Skip to content

Model

A thermal model to calculate transformer temperatures under specified load and ambient temperature profiles.

Initialising a transformer model with a temperature simulation profile
>>> from datetime import datetime
>>> from transformer_thermal_model.cooler import CoolerType
>>> from transformer_thermal_model.schemas import InputProfile, UserTransformerSpecifications
>>> from transformer_thermal_model.transformer import PowerTransformer
>>> from transformer_thermal_model.model import Model

>>> # First, we create the input profile
>>> datetime_index = [
...     datetime(2023, 1, 1, 0, 0),
...     datetime(2023, 1, 1, 1, 0),
...     datetime(2023, 1, 1, 2, 0),
... ]
>>> load_profile = [0.8, 0.9, 1.0]
>>> ambient_temperature_profile = [25.0, 24.5, 24.0]
>>> input_profile = InputProfile.create(
...     datetime_index=datetime_index,
...     load_profile=load_profile,
...     ambient_temperature_profile=ambient_temperature_profile,
... )
>>> # Then, we create the transformer with some basic specifications
>>> tr_specs = UserTransformerSpecifications(
...     load_loss=1000,  # Transformer load loss [W]
...     nom_load_sec_side=1500,  # Transformer nominal current secondary side [A]
...     no_load_loss=200,  # Transformer no-load loss [W]
...     amb_temp_surcharge=20,  # Ambient temperature surcharge [K]
... )
>>> tr = PowerTransformer(
...     user_specs=tr_specs,
...     cooling_type=CoolerType.ONAN
... )
>>> # Finally, we can use the input profile in the transformer model
>>> model = Model(temperature_profile=input_profile, transformer=tr)

Attributes:

Name Type Description
transformer Transformer

The transformer that the model will use to calculate the temperatures.

data BaseInputProfile

The input profile that the model will use to calculate temperatures.

top_oil_temp_profile Series

The modeled top-oil temperature profile.

initial_condition InitialState

The initial condition for the model.

Parameters:

Name Type Description Default
temperature_profile BaseInputProfile

The temperature profile for the model.

required
transformer Transformer

The transformer object.

required
initial_condition InitialState | None

The initial condition for the model.

None
Source code in transformer_thermal_model/model/thermal_model.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def __init__(
    self,
    temperature_profile: BaseInputProfile,
    transformer: Transformer,
    initial_condition: InitialState | None = None,
) -> None:
    """Initialize the thermal model.

    Args:
        temperature_profile (BaseInputProfile): The temperature profile for the model.
        transformer (Transformer): The transformer object.
        initial_condition (InitialState | None): The initial condition for the model.
    """
    logger.info("Initializing the thermal model.")
    logger.info(f"First timestamp: {temperature_profile.datetime_index[0]}")
    logger.info(f"Last timestamp: {temperature_profile.datetime_index[-1]}")
    logger.info(f"Amount of data points: {len(temperature_profile)}")
    logger.info(f"Max load: {np.max(temperature_profile.load_profile_array)}")
    self.transformer = transformer
    self.data = temperature_profile

    self.initial_condition = initial_condition or ColdStart()

    self.check_config()

check_config

check_config() -> None

Check if the combination of the transformer and input profile are valid.

Source code in transformer_thermal_model/model/thermal_model.py
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def check_config(self) -> None:
    """Check if the combination of the transformer and input profile are valid."""
    if isinstance(self.transformer, ThreeWindingTransformer) and not isinstance(
        self.data, ThreeWindingInputProfile
    ):
        raise ValueError("A ThreeWindingTransformer requires a ThreeWindingInputProfile.")
    elif isinstance(self.transformer, PowerTransformer) and not isinstance(self.data, InputProfile):
        raise ValueError("A PowerTransformer requires an InputProfile.")
    elif isinstance(self.transformer, DistributionTransformer) and not isinstance(self.data, InputProfile):
        raise ValueError("A DistributionTransformer requires an InputProfile.")
    if (
        self.transformer.cooling_controller
        and self.transformer.cooling_controller.onaf_switch.fan_on is not None
        and len(self.transformer.cooling_controller.onaf_switch.fan_on) != len(self.data)
    ):
        raise ValueError(
            "The length of the fan_on list in the cooling_switch_settings must be equal to the length of the "
            "temperature profile."
        )

get_initial_top_oil_temp

get_initial_top_oil_temp(
    first_surrounding_temp: float,
) -> float

Function that returns the top oil temp for the first timestep.

Source code in transformer_thermal_model/model/thermal_model.py
177
178
179
180
181
182
183
184
185
186
187
188
189
def get_initial_top_oil_temp(self, first_surrounding_temp: float) -> float:
    """Function that returns the top oil temp for the first timestep."""
    match self.initial_condition:
        case InitialTopOilTemp():
            return self.initial_condition.initial_top_oil_temp
        case InitialLoad():
            top_k = self.transformer._end_temperature_top_oil(load=np.array([self.initial_condition.initial_load]))

            return top_k + first_surrounding_temp
        case ColdStart():
            return first_surrounding_temp
        case _:
            raise TypeError(f"Unsupported type: {type(self.initial_condition)}")

get_initial_hot_spot_increase

get_initial_hot_spot_increase() -> float

Function that returns the hot spot temp for the first timestep.

Source code in transformer_thermal_model/model/thermal_model.py
191
192
193
194
195
196
197
198
199
200
def get_initial_hot_spot_increase(self) -> float:
    """Function that returns the hot spot temp for the first timestep."""
    match self.initial_condition:
        case InitialLoad():
            static_hot_spot_incr = self._calculate_static_hot_spot_increase(
                np.array([self.initial_condition.initial_load])
            )[0]
            return static_hot_spot_incr
        case _:
            return 0.0

run

run(
    force_use_ambient_temperature: bool = False,
) -> OutputProfile

Calculate the top-oil and hot-spot temperatures for the provided Transformer object.

This method prepares the calculation inputs, calculates intermediate factors, and computes the top-oil and hot-spot temperature profiles for the transformer based on the provided load and internal parameters. If the top oil temperature is provided in the temperature_profile it gets priority over the ambient temperature. The ambient temperature is then ignored. You can change this behaviour using the force_use_ambient_temperature parameter.

Parameters:

Name Type Description Default
force_use_ambient_temperature bool

Use the ambient temperature to perform the calculation, even if the top oil temperature is given (optional, False by default)

False

Returns:

Name Type Description
OutputProfile OutputProfile

Object containing the top-oil and hot-spot temperature profiles.

Source code in transformer_thermal_model/model/thermal_model.py
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
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
def run(self, force_use_ambient_temperature: bool = False) -> OutputProfile:
    """Calculate the top-oil and hot-spot temperatures for the provided Transformer object.

    This method prepares the calculation inputs, calculates intermediate factors, and computes
    the top-oil and hot-spot temperature profiles for the transformer based on the provided
    load and internal parameters. If the top oil temperature is provided in the `temperature_profile` it gets
    priority over the ambient temperature. The ambient temperature is then ignored. You can change this behaviour
    using the `force_use_ambient_temperature` parameter.

    Args:
        force_use_ambient_temperature:
            Use the ambient temperature to perform the calculation,
            even if the top oil temperature is given (optional, False by default)

    Returns:
        OutputProfile: Object containing the top-oil and hot-spot temperature profiles.

    """
    logger.info("Running the thermal model.")

    # decide if we use the top oil or ambient temperature as input and perform basic validation
    use_top_oil = not force_use_ambient_temperature and self.data.top_oil_temperature_profile is not None

    dt = self.data.time_step
    load = self.data.load_profile_array
    t_internal = self._get_internal_temp()

    # Check if top oil temperature profile is provided and use it if available
    # If not, calculate it
    if use_top_oil and self.data.top_oil_temperature_profile is not None:
        top_oil_temp_profile = self.data.top_oil_temperature_profile
    else:
        top_oil_temp_profile = self._calculate_top_oil_temp_profile(t_internal, dt, load)

    # Calculate hot-spot temperature profile
    hot_spot_temp_profile = self._calculate_hot_spot_temp_profile(load, top_oil_temp_profile, dt)
    logger.info("The calculation with the Thermal model is completed.")
    logger.info(f"Max top-oil temperature: {np.max(top_oil_temp_profile)}")
    logger.info(f"Max hot-spot temperature: {np.max(hot_spot_temp_profile)}")

    if isinstance(self.transformer, ThreeWindingTransformer):
        return OutputProfile(
            top_oil_temp_profile=pd.Series(top_oil_temp_profile, index=self.data.datetime_index),
            hot_spot_temp_profile=pd.DataFrame(
                hot_spot_temp_profile.transpose(),
                columns=["low_voltage_side", "middle_voltage_side", "high_voltage_side"],
                index=self.data.datetime_index,
            ),
        )
    else:
        # For a two winding transformer, hot_spot_temp_profile is a Series
        return OutputProfile(
            top_oil_temp_profile=pd.Series(top_oil_temp_profile, index=self.data.datetime_index),
            hot_spot_temp_profile=pd.Series(hot_spot_temp_profile, index=self.data.datetime_index),
        )