Skip to content

thermal

CableTemperatureResultsMixin

CableTemperatureResultsMixin(
    cable_is_bimetallic: NDArray[bool],
)
Source code in src/mechaphlowers/core/models/cable/thermal.py
112
113
def __init__(self, cable_is_bimetallic: npt.NDArray[np.bool]):
    self.cable_is_bimetallic = cable_is_bimetallic

cable_temperature

cable_temperature() -> ndarray

Relevant cable temperature for each span.

This means core temperature for bimetallic cables and average temperature for homogeneous cables.

Source code in src/mechaphlowers/core/models/cable/thermal.py
115
116
117
118
119
120
121
122
123
124
125
def cable_temperature(self) -> np.ndarray:
    """Relevant cable temperature for each span.

    This means core temperature for bimetallic cables and average temperature
    for homogeneous cables.
    """
    return np.where(
        self.cable_is_bimetallic,
        self.data["core_temperature"],  # type: ignore
        self.data["average_temperature"],  # type: ignore
    )

NebulosityResults

NebulosityResults(input_data: ndarray)

Bases: ThermalResults

Nebulosity results.

.data is a DataFrame with a single column: nebulosity.

Source code in src/mechaphlowers/core/models/cable/thermal.py
246
247
def __init__(self, input_data: np.ndarray):
    self.data = self.parse_results(input_data)

SolarRadiationResults

SolarRadiationResults(input_data: dict | DataFrame)

Bases: ThermalResults

Diffuse and beam radiations with their sum.

Source code in src/mechaphlowers/core/models/cable/thermal.py
34
35
def __init__(self, input_data: dict | pd.DataFrame):
    self.data = self.parse_results(input_data)

SteadyIntensityResults

SteadyIntensityResults(
    input_data: dict | DataFrame,
    cable_is_bimetallic: NDArray[bool],
    return_inputs=True,
)

Bases: ThermalSteadyResults

Parser for thermal steady-state intensity computation.

Source code in src/mechaphlowers/core/models/cable/thermal.py
182
183
184
185
186
187
188
189
def __init__(
    self,
    input_data: dict | pd.DataFrame,
    cable_is_bimetallic: npt.NDArray[np.bool],
    return_inputs=True,
):
    super().__init__(input_data, return_inputs)
    CableTemperatureResultsMixin.__init__(self, cable_is_bimetallic)

cable_temperature

cable_temperature() -> ndarray

Relevant cable temperature for each span.

This means core temperature for bimetallic cables and average temperature for homogeneous cables.

Source code in src/mechaphlowers/core/models/cable/thermal.py
115
116
117
118
119
120
121
122
123
124
125
def cable_temperature(self) -> np.ndarray:
    """Relevant cable temperature for each span.

    This means core temperature for bimetallic cables and average temperature
    for homogeneous cables.
    """
    return np.where(
        self.cable_is_bimetallic,
        self.data["core_temperature"],  # type: ignore
        self.data["average_temperature"],  # type: ignore
    )

parse_results staticmethod

parse_results(data: dict | DataFrame) -> DataFrame

Parse steady-state thermal results into a DataFrame.

Converts raw steady-state thermal output into standardized DataFrame format. If input is already a DataFrame, returns it as-is. Otherwise converts dict to DataFrame.

Parameters:

Name Type Description Default

data

dict | DataFrame

Raw steady-state results as dictionary or DataFrame.

required

Returns:

Type Description
DataFrame

Parsed results as a pandas DataFrame.

Source code in src/mechaphlowers/core/models/cable/thermal.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
@staticmethod
def parse_results(
    data: dict | pd.DataFrame,
) -> pd.DataFrame:
    """Parse steady-state thermal results into a DataFrame.

    Converts raw steady-state thermal output into standardized DataFrame format.
    If input is already a DataFrame, returns it as-is. Otherwise converts dict to DataFrame.

    Args:
        data: Raw steady-state results as dictionary or DataFrame.

    Returns:
        Parsed results as a pandas DataFrame.
    """
    if isinstance(data, pd.DataFrame):
        return data.copy()
    return pd.DataFrame(data)

SteadyTemperatureResults

SteadyTemperatureResults(
    input_data: dict | DataFrame,
    cable_is_bimetallic: NDArray[bool],
    return_inputs=True,
)

Bases: ThermalSteadyResults

Parser for thermal steady-state temperature computation.

Source code in src/mechaphlowers/core/models/cable/thermal.py
182
183
184
185
186
187
188
189
def __init__(
    self,
    input_data: dict | pd.DataFrame,
    cable_is_bimetallic: npt.NDArray[np.bool],
    return_inputs=True,
):
    super().__init__(input_data, return_inputs)
    CableTemperatureResultsMixin.__init__(self, cable_is_bimetallic)

cable_temperature

cable_temperature() -> ndarray

Relevant cable temperature for each span.

This means core temperature for bimetallic cables and average temperature for homogeneous cables.

Source code in src/mechaphlowers/core/models/cable/thermal.py
115
116
117
118
119
120
121
122
123
124
125
def cable_temperature(self) -> np.ndarray:
    """Relevant cable temperature for each span.

    This means core temperature for bimetallic cables and average temperature
    for homogeneous cables.
    """
    return np.where(
        self.cable_is_bimetallic,
        self.data["core_temperature"],  # type: ignore
        self.data["average_temperature"],  # type: ignore
    )

parse_results staticmethod

parse_results(data: dict | DataFrame) -> DataFrame

Parse steady-state thermal results into a DataFrame.

Converts raw steady-state thermal output into standardized DataFrame format. If input is already a DataFrame, returns it as-is. Otherwise converts dict to DataFrame.

Parameters:

Name Type Description Default

data

dict | DataFrame

Raw steady-state results as dictionary or DataFrame.

required

Returns:

Type Description
DataFrame

Parsed results as a pandas DataFrame.

Source code in src/mechaphlowers/core/models/cable/thermal.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
@staticmethod
def parse_results(
    data: dict | pd.DataFrame,
) -> pd.DataFrame:
    """Parse steady-state thermal results into a DataFrame.

    Converts raw steady-state thermal output into standardized DataFrame format.
    If input is already a DataFrame, returns it as-is. Otherwise converts dict to DataFrame.

    Args:
        data: Raw steady-state results as dictionary or DataFrame.

    Returns:
        Parsed results as a pandas DataFrame.
    """
    if isinstance(data, pd.DataFrame):
        return data.copy()
    return pd.DataFrame(data)

ThermalEngine

ThermalEngine()

Thermal engine is a wrapper for cable thermal modeling.

Attributes:

Name Type Description
power_model

The power model used for thermal calculations.

heateq

The heat equation model used.

dict_input

Dictionary to store input parameters.

forecast

An instance of ThermalForecastArray for time series data.

target_temperature

Target temperature for steady-state calculations in celsius.

Source code in src/mechaphlowers/core/models/cable/thermal.py
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
def __init__(self):
    """Initialize ThermalEngine.

    Attributes:
        power_model: The power model used for thermal calculations.
        heateq: The heat equation model used.
        dict_input: Dictionary to store input parameters.
        forecast: An instance of ThermalForecastArray for time series data.
        target_temperature: Target temperature for steady-state calculations in celsius.
    """
    self.power_model = self.available_power_model.get("rte", ValueError)
    self.heateq = self.available_heat_equation.get("3tl", ValueError)
    self.dict_input = {}
    self.forecast = ThermalForecastArray()
    self.target_temperature = 65

normal_wind_mode property writable

normal_wind_mode

Get normal wind mode status.

Triggers normal_wind mode in models. Not implemented yet.

Raises:

Type Description
NotImplementedError

This feature is not yet implemented.

wind_cable_angle property

wind_cable_angle: ndarray

Compute the angle between wind and cable direction.

Triggers ambient_wind_speed mode in models.

Returns:

Type Description
ndarray

Angle in degrees between wind direction and cable azimuth.

compute_wind_attack_angle staticmethod

compute_wind_attack_angle(
    cable_azimuth: ndarray, wind_azimuth: ndarray
) -> ndarray

Compute the angle between wind and cable.

Parameters:

Name Type Description Default

cable_azimuth

ndarray

azimuth of the cable, in degrees

required

wind_azimuth

ndarray

azimuth of the wind, in degrees

required

Returns:

Type Description
ndarray

Angle in degrees between wind direction and cable azimuth.

Source code in src/mechaphlowers/core/models/cable/thermal.py
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
@staticmethod
def compute_wind_attack_angle(
    cable_azimuth: np.ndarray, wind_azimuth: np.ndarray
) -> np.ndarray:
    """Compute the angle between wind and cable.

    Args:
        cable_azimuth (np.ndarray): azimuth of the cable, in degrees
        wind_azimuth (np.ndarray): azimuth of the wind, in degrees

    Returns:
        Angle in degrees between wind direction and cable azimuth.
    """
    return np.rad2deg(
        thermohl_compute_wind_angle(cable_azimuth, wind_azimuth),
    )

diffuse_and_beam_solar_radiations staticmethod

diffuse_and_beam_solar_radiations(
    datetime_utc: NDArray[datetime64],
    latitude: ndarray,
    longitude: ndarray,
    nebulosity: ndarray,
) -> SolarRadiationResults

Compute diffuse radiation, beam radiation and their sum.

Returns:

Name Type Description
SolarRadiationResults SolarRadiationResults

An instance containing the results.

Source code in src/mechaphlowers/core/models/cable/thermal.py
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
@staticmethod
def diffuse_and_beam_solar_radiations(
    datetime_utc: npt.NDArray[np.datetime64],
    latitude: np.ndarray,
    longitude: np.ndarray,
    nebulosity: np.ndarray,
) -> SolarRadiationResults:
    """Compute diffuse radiation, beam radiation and their sum.

    Returns:
        SolarRadiationResults: An instance containing the results.
    """
    inputs, _ = check_inputs(
        nebulosity=nebulosity,
        datetime_utc=datetime_utc,
        latitude=latitude,
        longitude=longitude,
    )
    diffuse_radiation, beam_radiation = diffuse_and_beam_radiations(
        inputs["datetime_utc"],
        inputs["latitude"],
        inputs["longitude"],
        inputs["nebulosity"],
    )
    df = pd.DataFrame(
        {
            "diffuse_radiation": diffuse_radiation,
            "beam_radiation": beam_radiation,
            "diffuse_plus_beam_radiation": diffuse_radiation
            + beam_radiation,
        }
    )
    return SolarRadiationResults(df)

load

load()

Load or reload the thermal model, and checks the shape of the input parameters. Can be used if the input parameters are modified without using set().

Source code in src/mechaphlowers/core/models/cable/thermal.py
471
472
473
474
475
def load(self):
    """Load or reload the thermal model, and checks the shape of the input parameters.
    Can be used if the input parameters are modified without using set()."""
    check_inputs(**self.dict_input)
    self._load()

nebulosity staticmethod

nebulosity(
    diffuse_plus_beam_radiation: ndarray,
    datetime_utc: NDArray[datetime64],
    latitude: ndarray,
    longitude: ndarray,
) -> NebulosityResults

Compute the nebulosity which gives the closest diffuse + beam radiation to the one given as argument.

Nebulosities are integers between 0 and 8.

Returns:

Name Type Description
NebulosityResults NebulosityResults

an instance containing the results.

Source code in src/mechaphlowers/core/models/cable/thermal.py
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
@staticmethod
def nebulosity(
    diffuse_plus_beam_radiation: np.ndarray,
    datetime_utc: npt.NDArray[np.datetime64],
    latitude: np.ndarray,
    longitude: np.ndarray,
) -> NebulosityResults:
    """Compute the nebulosity which gives the closest diffuse + beam radiation
    to the one given as argument.

    Nebulosities are integers between 0 and 8.

    Returns:
        NebulosityResults: an instance containing the results.
    """
    result = estimate_nebulosity(
        diffuse_plus_beam_radiation, datetime_utc, latitude, longitude
    )
    return NebulosityResults(result)

set

set(
    cable_array: CableArray,
    latitude: ndarray,
    longitude: ndarray,
    altitude: ndarray,
    azimuth: ndarray,
    datetime_utc: NDArray[datetime64],
    intensity: ndarray,
    ambient_temp: ndarray,
    wind_speed: ndarray,
    wind_angle: ndarray,
    nebulosity: ndarray,
    solar_irradiance: ndarray | None = None,
)

Set input parameters for thermal calculations.

Parameters:

Name Type Description Default

cable_array

CableArray

An instance of CableArray containing cable properties.

required

latitude

ndarray

Latitude values.

required

longitude

ndarray

Longitude values.

required

altitude

ndarray

Altitude values.

required

azimuth

ndarray

Azimuth values.

required

datetime_utc

ndarray

Datetime (year is indifferent).

required

intensity

ndarray

Current intensity values.

required

ambient_temp

ndarray

Ambient temperature values.

required

wind_speed

ndarray

Wind speed values in m/s

required

wind_angle

ndarray

Wind angle values in degrees, clockwise from North.

required

nebulosity

ndarray

Nebulosity level (ints from 0 to 8). 8 is the most clouded.

required

solar_irradiance

ndarray | None

Solar irradiance values (optional). Defaults to None.

None
Source code in src/mechaphlowers/core/models/cable/thermal.py
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
def set(
    self,
    cable_array: CableArray,
    latitude: np.ndarray,
    longitude: np.ndarray,
    altitude: np.ndarray,
    azimuth: np.ndarray,
    datetime_utc: npt.NDArray[np.datetime64],
    intensity: np.ndarray,
    ambient_temp: np.ndarray,
    wind_speed: np.ndarray,
    wind_angle: np.ndarray,
    nebulosity: np.ndarray,
    solar_irradiance: np.ndarray | None = None,
):
    """Set input parameters for thermal calculations.

    Args:
        cable_array (CableArray): An instance of CableArray containing cable properties.
        latitude (np.ndarray): Latitude values.
        longitude (np.ndarray): Longitude values.
        altitude (np.ndarray): Altitude values.
        azimuth (np.ndarray): Azimuth values.
        datetime_utc (np.ndarray): Datetime (year is indifferent).
        intensity (np.ndarray): Current intensity values.
        ambient_temp (np.ndarray): Ambient temperature values.
        wind_speed (np.ndarray): Wind speed values in m/s
        wind_angle (np.ndarray): Wind angle values in degrees, clockwise from North.
        nebulosity (np.ndarray): Nebulosity level (ints from 0 to 8). 8 is the most clouded.
        solar_irradiance (np.ndarray | None): Solar irradiance values (optional). Defaults to None.
    """
    # Handle optional solar_irradiance - create NaN array if not provided
    if solar_irradiance is None:
        solar_irradiance = np.full_like(latitude, np.nan, dtype=np.float64)

    # Normalize and validate all input parameters
    inputs, self._len = check_inputs(
        latitude=latitude,
        longitude=longitude,
        altitude=altitude,
        azimuth=azimuth,
        datetime_utc=datetime_utc,
        intensity=intensity,
        ambient_temp=ambient_temp,
        wind_speed=wind_speed,
        wind_angle=wind_angle,
        nebulosity=nebulosity,
        solar_irradiance=solar_irradiance,
    )

    self.dict_input = {
        "measured_global_radiation": inputs["solar_irradiance"],
        "latitude": inputs["latitude"],
        "longitude": inputs["longitude"],
        "altitude": inputs["altitude"],
        "cable_azimuth": inputs["azimuth"],
        "datetime_utc": inputs["datetime_utc"],
        "ambient_temperature": inputs["ambient_temp"],
        "wind_speed": inputs["wind_speed"],  # wind speed (m.s**-1)
        "wind_azimuth": inputs[
            "wind_angle"
        ],  # wind angle (deg, 0 means north)
        "nebulosity": inputs["nebulosity"],
        "transit": inputs["intensity"],
        "linear_mass": np.full(
            self._len, cable_array.data.linear_mass.iloc[0]
        ),
        "core_diameter": np.full(
            self._len, cable_array.data.diameter_heart.iloc[0]
        ),
        "outer_diameter": np.full(
            self._len, cable_array.data.diameter.iloc[0]
        ),
        "core_area": np.full(
            self._len, cable_array.data.section_heart.iloc[0]
        ),
        "outer_area": np.full(
            self._len, cable_array.data.section_conductor.iloc[0]
        ),
        "radial_thermal_conductivity": np.full(
            self._len, cable_array.data.radial_thermal_conductivity.iloc[0]
        ),
        "solar_absorptivity": np.full(
            self._len, cable_array.data.solar_absorption.iloc[0]
        ),
        "emissivity": np.full(
            self._len, cable_array.data.emissivity.iloc[0]
        ),
        "linear_resistance_dc_20c": np.full(
            self._len, cable_array.data.electric_resistance_20.iloc[0]
        ),
        "temperature_coeff_linear": np.full(
            self._len,
            cable_array.data.linear_resistance_temperature_coef.iloc[0],
        ),
        "magnetic_coeff": np.full(
            self._len,
            1.006 if cable_array.data.has_magnetic_heart.iloc[0] else 1.0,
        ),
        "magnetic_coeff_per_a": np.full(
            self._len,
            0.016 if cable_array.data.has_magnetic_heart.iloc[0] else 0.0,
        ),
    }
    self.bimetallic_cable = cable_array.is_bimetallic
    self._load()
    logger.debug("Thermal attribute set")

steady_intensity

steady_intensity(
    target_temperature: ndarray | None = None,
    return_inputs: bool = True,
) -> SteadyIntensityResults

Compute steady-state intensity results.

If return_inputs=True, input data are returned in result.inputs as a DataFrame.

Returns:

Name Type Description
SteadyIntensityResults SteadyIntensityResults

An instance containing steady-state intensity data.

Source code in src/mechaphlowers/core/models/cable/thermal.py
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
def steady_intensity(
    self,
    target_temperature: np.ndarray | None = None,
    return_inputs: bool = True,
) -> SteadyIntensityResults:
    """Compute steady-state intensity results.

    If return_inputs=True, input data are returned in
    result.inputs as a DataFrame.

    Returns:
        SteadyIntensityResults: An instance containing steady-state intensity data.
    """
    if target_temperature is not None:
        self.target_temperature = target_temperature

    return SteadyIntensityResults(
        self.thermal_model.steady_intensity(
            self.target_temperature,
        ),
        cable_is_bimetallic=self.bimetallic_cable,
        return_inputs=return_inputs,
    )

steady_temperature

steady_temperature(
    intensity: ndarray | None = None,
    return_uncertainty: bool = False,
    return_inputs: bool = True,
) -> SteadyTemperatureResults

Compute steady-state temperature results.

If return_inputs=True, input data are returned in result.inputs as a DataFrame.

Returns:

Name Type Description
SteadyTemperatureResults SteadyTemperatureResults

An instance containing steady-state temperature data.

Source code in src/mechaphlowers/core/models/cable/thermal.py
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
def steady_temperature(
    self,
    intensity: np.ndarray | None = None,
    return_uncertainty: bool = False,
    return_inputs: bool = True,
) -> SteadyTemperatureResults:
    """Compute steady-state temperature results.

    If return_inputs=True, input data are returned in
    result.inputs as a DataFrame.

    Returns:
        SteadyTemperatureResults: An instance containing steady-state temperature data.
    """
    logger.debug("Get steady_temperature()")
    if intensity is not None:
        self.dict_input["transit"] = intensity
        self.load()
    return SteadyTemperatureResults(
        self.thermal_model.steady_temperature(
            return_uncertainty=return_uncertainty,
        ),
        cable_is_bimetallic=self.bimetallic_cable,
        return_inputs=return_inputs,
    )

transient_temperature

transient_temperature(
    forecast_control: ThermalForecastArray | None = None,
    return_inputs: bool = True,
) -> ThermalTransientResults

Compute transient temperature results.

If return_inputs=True, input data are returned in result.inputs as a DataFrame.

Returns:

Name Type Description
ThermalTransientResults ThermalTransientResults

An instance containing time-varying temperature data.

Source code in src/mechaphlowers/core/models/cable/thermal.py
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
def transient_temperature(
    self,
    forecast_control: ThermalForecastArray | None = None,
    return_inputs: bool = True,
) -> ThermalTransientResults:
    """Compute transient temperature results.

    If return_inputs=True, input data are returned in
    result.inputs as a DataFrame.

    Returns:
        ThermalTransientResults: An instance containing time-varying temperature data.
    """
    if forecast_control is not None:
        self.forecast = forecast_control

    return ThermalTransientResults(
        self.thermal_model.transient_temperature(
            offset=self.forecast.time
        ),
        cable_is_bimetallic=self.bimetallic_cable,
        return_inputs=return_inputs,
    )

ThermalForecastArray

Array for input thermal forecast parameters.

ThermalResults

ThermalResults(input_data: dict | DataFrame)

Bases: ABC

Thermal results base class.

Source code in src/mechaphlowers/core/models/cable/thermal.py
34
35
def __init__(self, input_data: dict | pd.DataFrame):
    self.data = self.parse_results(input_data)

parse_results abstractmethod staticmethod

parse_results(data: dict | DataFrame) -> DataFrame

Parse raw thermal results into a standardized DataFrame format.

Parameters:

Name Type Description Default

data

dict | DataFrame

Raw thermal results as dictionary or DataFrame.

required

Returns:

Type Description
DataFrame

pd.DataFrame: Parsed results as a pandas DataFrame.

Source code in src/mechaphlowers/core/models/cable/thermal.py
37
38
39
40
41
42
43
44
45
46
47
48
@staticmethod
@abstractmethod
def parse_results(data: dict | pd.DataFrame) -> pd.DataFrame:
    """Parse raw thermal results into a standardized DataFrame format.

    Args:
        data (dict | pd.DataFrame): Raw thermal results as dictionary or DataFrame.

    Returns:
        pd.DataFrame: Parsed results as a pandas DataFrame.
    """
    raise NotImplementedError

ThermalSteadyResults

ThermalSteadyResults(
    input_data: dict | DataFrame,
    cable_is_bimetallic: NDArray[bool],
    return_inputs=True,
)

Bases: ThermalResultsWithInputs, CableTemperatureResultsMixin

Thermal steady-state results parser.

Source code in src/mechaphlowers/core/models/cable/thermal.py
182
183
184
185
186
187
188
189
def __init__(
    self,
    input_data: dict | pd.DataFrame,
    cable_is_bimetallic: npt.NDArray[np.bool],
    return_inputs=True,
):
    super().__init__(input_data, return_inputs)
    CableTemperatureResultsMixin.__init__(self, cable_is_bimetallic)

cable_temperature

cable_temperature() -> ndarray

Relevant cable temperature for each span.

This means core temperature for bimetallic cables and average temperature for homogeneous cables.

Source code in src/mechaphlowers/core/models/cable/thermal.py
115
116
117
118
119
120
121
122
123
124
125
def cable_temperature(self) -> np.ndarray:
    """Relevant cable temperature for each span.

    This means core temperature for bimetallic cables and average temperature
    for homogeneous cables.
    """
    return np.where(
        self.cable_is_bimetallic,
        self.data["core_temperature"],  # type: ignore
        self.data["average_temperature"],  # type: ignore
    )

parse_results staticmethod

parse_results(data: dict | DataFrame) -> DataFrame

Parse steady-state thermal results into a DataFrame.

Converts raw steady-state thermal output into standardized DataFrame format. If input is already a DataFrame, returns it as-is. Otherwise converts dict to DataFrame.

Parameters:

Name Type Description Default

data

dict | DataFrame

Raw steady-state results as dictionary or DataFrame.

required

Returns:

Type Description
DataFrame

Parsed results as a pandas DataFrame.

Source code in src/mechaphlowers/core/models/cable/thermal.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
@staticmethod
def parse_results(
    data: dict | pd.DataFrame,
) -> pd.DataFrame:
    """Parse steady-state thermal results into a DataFrame.

    Converts raw steady-state thermal output into standardized DataFrame format.
    If input is already a DataFrame, returns it as-is. Otherwise converts dict to DataFrame.

    Args:
        data: Raw steady-state results as dictionary or DataFrame.

    Returns:
        Parsed results as a pandas DataFrame.
    """
    if isinstance(data, pd.DataFrame):
        return data.copy()
    return pd.DataFrame(data)

ThermalTransientResults

ThermalTransientResults(
    input_data: dict | DataFrame,
    cable_is_bimetallic: NDArray[bool],
    return_inputs=True,
)

Bases: ThermalResultsWithInputs, CableTemperatureResultsMixin

Thermal transient results class for transient temperature calculations.

Source code in src/mechaphlowers/core/models/cable/thermal.py
133
134
135
136
137
138
139
140
def __init__(
    self,
    input_data: dict | pd.DataFrame,
    cable_is_bimetallic: npt.NDArray[np.bool],
    return_inputs=True,
):
    super().__init__(input_data, return_inputs)
    CableTemperatureResultsMixin.__init__(self, cable_is_bimetallic)

cable_temperature

cable_temperature() -> ndarray

Relevant cable temperature for each span.

This means core temperature for bimetallic cables and average temperature for homogeneous cables.

Source code in src/mechaphlowers/core/models/cable/thermal.py
115
116
117
118
119
120
121
122
123
124
125
def cable_temperature(self) -> np.ndarray:
    """Relevant cable temperature for each span.

    This means core temperature for bimetallic cables and average temperature
    for homogeneous cables.
    """
    return np.where(
        self.cable_is_bimetallic,
        self.data["core_temperature"],  # type: ignore
        self.data["average_temperature"],  # type: ignore
    )

parse_results staticmethod

parse_results(data: dict | DataFrame) -> DataFrame

Parse transient thermal results into a time-series DataFrame.

Converts raw transient thermal output into a DataFrame with columns for time, cable ID, average temperature, surface temperature, and core temperature.

Parameters:

Name Type Description Default

data

dict | DataFrame

Raw transient results dictionary or DataFrame.

required

Returns:

Type Description
DataFrame

pd.DataFrame: DataFrame with columns: time, id, average_temperature, surface_temperature, core_temperature.

Raises:

Type Description
TypeError

If input is a DataFrame (only dict format is supported).

Source code in src/mechaphlowers/core/models/cable/thermal.py
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
@staticmethod
def parse_results(data: dict | pd.DataFrame) -> pd.DataFrame:
    """Parse transient thermal results into a time-series DataFrame.

    Converts raw transient thermal output into a DataFrame with columns for
    time, cable ID, average temperature, surface temperature, and core temperature.

    Args:
        data (dict | pd.DataFrame): Raw transient results dictionary or DataFrame.

    Returns:
        pd.DataFrame: DataFrame with columns: time, id, average_temperature,
            surface_temperature, core_temperature.

    Raises:
        TypeError: If input is a DataFrame (only dict format is supported).
    """
    if isinstance(data, pd.DataFrame):
        raise TypeError(
            "DataFrame input not supported for transient results parsing."
        )
    input_size = data["average_temperature"].shape
    return pd.DataFrame(
        {
            "time": np.tile(data["time"], input_size[1]),
            "id": np.tile(
                np.arange(input_size[1]), (input_size[0], 1)
            ).T.flatten(),
            "average_temperature": data["average_temperature"].T.flatten(),
            "surface_temperature": data["surface_temperature"].T.flatten(),
            "core_temperature": data["core_temperature"].T.flatten(),
        }
    )

check_inputs

check_inputs(
    **kwargs: NDArray[integer | floating | datetime64],
) -> tuple[
    dict[str, NDArray[integer | floating | datetime64]], int
]

Validate input parameters.

Ensures all inputs are numpy arrays with the same size. Also ensures that nebulosities (if given) are in the right range.

Parameters:

Name Type Description Default

**kwargs

NDArray[integer | floating | datetime64]

Input parameters as numpy arrays.

{}

Returns:

Name Type Description
tuple tuple[dict[str, NDArray[integer | floating | datetime64]], int]

A tuple containing: - dict: Dictionary with the input numpy arrays. - int: The common length of all arrays.

Raises:

Type Description
ValueError

If array inputs have incompatible sizes.

TypeError

If any input is not a numpy array.

Source code in src/mechaphlowers/core/models/cable/thermal.py
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
def check_inputs(
    **kwargs: npt.NDArray[np.integer | np.floating | np.datetime64],
) -> tuple[
    dict[str, npt.NDArray[np.integer | np.floating | np.datetime64]], int
]:
    """Validate input parameters.

    Ensures all inputs are numpy arrays with the same size. Also ensures that
    nebulosities (if given) are in the right range.

    Args:
        **kwargs: Input parameters as numpy arrays.

    Returns:
        tuple: A tuple containing:
            - dict: Dictionary with the input numpy arrays.
            - int: The common length of all arrays.

    Raises:
        ValueError: If array inputs have incompatible sizes.
        TypeError: If any input is not a numpy array.
    """
    if len(kwargs) == 0:
        return kwargs, 0

    array_length: int | None = None

    for key, value in kwargs.items():
        if not isinstance(value, np.ndarray):
            raise TypeError(
                f"Expected numpy array for '{key}', got {type(value).__name__}."
            )

        # Track and validate the length of array inputs
        if array_length is None:
            array_length = value.size
        elif value.size != array_length:
            raise ValueError(
                f"All array inputs must have the same length. "
                f"Expected {array_length}, got {value.size} for {key}."
            )

    if "nebulosity" in kwargs:
        check_nebulosity_range(kwargs["nebulosity"])

    return kwargs, array_length  # type: ignore