Skip to content

cooling_heating

Modules:

Functions:

air_cooling_wenzel2025

air_cooling_wenzel2025(
    placements: DataFrame,
    era5_path: str,
    temperatureCoolant: int | float,
    designTemperature: int | float,
    heatTransferDelta: int | float = 5,
    efficiencyFan: int | float = 0.7,
    pressureDropAir: int | float = 261,
    efficiencyPump: int | float = 0.7,
    pressureDropWater: int | float = 200000,
    output_netcdf_path: str = None,
    output_variables: List[str] = None,
)

Simulate an air-cooling system based on ERA5 weather data.

This function calculates the fan and pump power requirements, capacity factor, and total electricity demand for air-cooling systems at varying ambient temperatures. Results can be saved to a NetCDF file.

Parameters:

  • placements

    (DataFrame) –

    DataFrame specifying the plant locations and their capacities.

  • era5_path

    (str) –

    Path to the ERA5 weather data source.

  • temperatureCoolant

    (float) –

    Temperature of the heat load to be cooled [°C].

  • designTemperature

    (float) –

    Temperature for the nominal design point of the air cooling system [°C].

  • heatTransferDelta

    (float, default: 5 ) –

    Temperature difference required for heat transfer from air to coolant [K]. Default is 5.

  • efficiencyFan

    (float, default: 0.7 ) –

    Efficiency of the fan system [0, 1]. Default is 0.7.

  • pressureDropAir

    (float, default: 261 ) –

    Pressure drop of air through the cooling frame channels [Pa]. Default is 261.

  • efficiencyPump

    (float, default: 0.7 ) –

    Efficiency of the pump system [0, 1]. Default is 0.7.

  • pressureDropWater

    (float, default: 200000 ) –

    Pressure drop of water through the circuit [Pa]. Default is 200000.

  • output_netcdf_path

    (str, default: None ) –

    Path to save the output NetCDF file. Default is None.

  • output_variables

    (list of str, default: None ) –

    List of simulation variables to save to the NetCDF file. If None, all variables are saved.

Returns:

  • Dataset

    Simulation results, including capacity factor, fan/pump/electricity inputs, and cooling output. Can be limited to output_variables if specified.

Notes
  • Calculates fan and pump power using calculate_fan_power_air_cooling and calculate_pump_power_air_cooling.
  • Computes the system capacity factor relative to the design temperature using calculate_capacity_factor_air_cooling.
  • Total electricity input includes contributions from both fan and pump.
  • Stores all relevant units in wf.units for reference.

Raises:

  • AssertionError

    If input parameters are not of expected type or if efficiency values are not within (0, 1].

Source code in reskit/cooling_heating/workflows/workflows.py
def air_cooling_wenzel2025(
    placements: pd.DataFrame,
    era5_path: str,
    temperatureCoolant: int | float,
    designTemperature: int | float,
    heatTransferDelta: int | float = 5,
    efficiencyFan: int | float = 0.7,
    pressureDropAir: int | float = 261,
    efficiencyPump: int | float = 0.7,
    pressureDropWater: int | float = 200000,
    output_netcdf_path: str = None,
    output_variables: List[str] = None,
):
    """
    Simulate an air-cooling system based on ERA5 weather data.

    This function calculates the fan and pump power requirements, capacity factor,
    and total electricity demand for air-cooling systems at varying ambient temperatures.
    Results can be saved to a NetCDF file.

    Parameters
    ----------
    placements : pd.DataFrame
        DataFrame specifying the plant locations and their capacities.
    era5_path : str
        Path to the ERA5 weather data source.
    temperatureCoolant : float
        Temperature of the heat load to be cooled [°C].
    designTemperature : float
        Temperature for the nominal design point of the air cooling system [°C].
    heatTransferDelta : float, optional
        Temperature difference required for heat transfer from air to coolant [K]. Default is 5.
    efficiencyFan : float, optional
        Efficiency of the fan system [0, 1]. Default is 0.7.
    pressureDropAir : float, optional
        Pressure drop of air through the cooling frame channels [Pa]. Default is 261.
    efficiencyPump : float, optional
        Efficiency of the pump system [0, 1]. Default is 0.7.
    pressureDropWater : float, optional
        Pressure drop of water through the circuit [Pa]. Default is 200000.
    output_netcdf_path : str, optional
        Path to save the output NetCDF file. Default is None.
    output_variables : list of str, optional
        List of simulation variables to save to the NetCDF file. If None, all variables are saved.

    Returns
    -------
    xarray.Dataset
        Simulation results, including capacity factor, fan/pump/electricity inputs, and cooling output.
        Can be limited to `output_variables` if specified.

    Notes
    -----
    - Calculates fan and pump power using `calculate_fan_power_air_cooling` and `calculate_pump_power_air_cooling`.
    - Computes the system capacity factor relative to the design temperature using `calculate_capacity_factor_air_cooling`.
    - Total electricity input includes contributions from both fan and pump.
    - Stores all relevant units in `wf.units` for reference.

    Raises
    ------
    AssertionError
        If input parameters are not of expected type or if efficiency values are not within (0, 1].
    """
    assert isinstance(temperatureCoolant, (int, float))
    assert isinstance(designTemperature, (int, float))
    assert isinstance(heatTransferDelta, (int, float))
    assert isinstance(efficiencyFan, (int, float))
    assert isinstance(pressureDropAir, (int, float))
    assert isinstance(efficiencyPump, (int, float))
    assert isinstance(pressureDropWater, (int, float))
    assert 0 < efficiencyFan <= 1, "efficiencyFan must be between 0 and 1"
    assert 0 < efficiencyPump <= 1, "efficiencyPump must be between 0 and 1"

    wf = CoolingHeatingWorkflowManager(placements)

    wf.read(
        variables=[
            "surface_air_temperature",
        ],
        source_type="ERA5",
        source=era5_path,
        set_time_index=True,
        verbose=False,
    )

    wf.calculate_fan_power_air_cooling(
        temperatureCoolant,
        heatTransferDelta=heatTransferDelta,
        efficiencyFan=efficiencyFan,
        pressureDropAir=pressureDropAir,
        designTemperature=None,
    )
    wf.calculate_pump_power_air_cooling(
        temperatureCoolant,
        heatTransferDelta=heatTransferDelta,
        efficiencyPump=efficiencyPump,
        pressureDropWater=pressureDropWater,
        designTemperature=None,
    )
    wf.calculate_relative_cost_factor_air_cooling(
        designTemperature,
        temperatureCoolant,
        heatTransferDelta=heatTransferDelta,
        efficiencyFan=efficiencyFan,
        efficiencyPump=efficiencyPump,
        pressureDropAir=pressureDropAir,
        pressureDropWater=pressureDropWater,
    )

    wf.calculate_capacity_factor_air_cooling(
        designTemperature=designTemperature,
        temperatureCoolant=temperatureCoolant,
        heatTransferDelta=heatTransferDelta,
        efficiencyFan=efficiencyFan,
        efficiencyPump=efficiencyPump,
        pressureDropAir=pressureDropAir,
        pressureDropWater=pressureDropWater,
    )

    # calculate total conversion factor electricity:
    wf.sim_data["conversion_factor_electricity"] = (
        wf.sim_data["conversion_factor_fan_electricity"] + wf.sim_data["conversion_factor_pump_electricity"]
    )  # kWh_el/kWh_th

    # Calculate needed electricity in each time step for design capacity:
    wf.sim_data["cooling_output"] = wf.sim_data["capacity_factor"] * np.array(wf.placements["capacity"])  # kWh_th/h
    wf.sim_data["electricity_input"] = (
        -wf.sim_data["conversion_factor_electricity"]
        * wf.sim_data["capacity_factor"]
        * np.array(wf.placements["capacity"])
    )  # kWh_el/h
    wf.sim_data["electricity_input_fan"] = (
        -wf.sim_data["conversion_factor_fan_electricity"]
        * wf.sim_data["capacity_factor"]
        * np.array(wf.placements["capacity"])
    )  # kWh_el/h
    wf.sim_data["electricity_input_pump"] = (
        -wf.sim_data["conversion_factor_pump_electricity"]
        * wf.sim_data["capacity_factor"]
        * np.array(wf.placements["capacity"])
    )  # kWh_el/h

    return wf.to_xarray(
        output_netcdf_path=output_netcdf_path,
        output_variables=output_variables,
        custom_attributes=wf.units,
    )

air_source_heat_pump

air_source_heat_pump(
    placements: DataFrame,
    era5_path: str,
    targetTemperature: int | float = 100,
    secondLawEfficiency: int | float = 0.5,
    output_netcdf_path: str = None,
    output_variables: List[str] = None,
)

Simulate an air-source heat pump based on ERA5 weather data.

This function calculates the coefficient of performance (COP) and electricity demand of an air-source heat pump at varying ambient temperatures. Results can be saved to a NetCDF file.

Parameters:

  • placements

    (DataFrame) –

    DataFrame specifying plant locations and capacities.

  • era5_path

    (str) –

    Path to the ERA5 weather data source.

  • targetTemperature

    (float, default: 100 ) –

    Temperature at which the heat pump should supply the heat [°C]. Default is 100.

  • secondLawEfficiency

    (float, default: 0.5 ) –

    Second law efficiency of the heat pump [0,1]. Default is 0.5.

  • output_netcdf_path

    (str, default: None ) –

    Path to save the output NetCDF file. Default is None.

  • output_variables

    (list of str, default: None ) –

    List of simulation variables to save to the NetCDF file. If None, all variables are saved.

Returns:

  • Dataset

    Simulation results including COP, electricity conversion factor, and electricity input. Can be limited to output_variables if specified.

Raises:

  • AssertionError

    If targetTemperature or secondLawEfficiency are not numeric or if secondLawEfficiency is not within (0, 1].

Notes
  • The electricity conversion factor is calculated as -1/COP [kWh_el/kWh_th].
  • Electricity input is computed for each plant based on its capacity and the COP.
  • Units are stored in wf.units for reference.
Source code in reskit/cooling_heating/workflows/workflows.py
def air_source_heat_pump(
    placements: pd.DataFrame,
    era5_path: str,
    targetTemperature: int | float = 100,
    secondLawEfficiency: int | float = 0.5,
    output_netcdf_path: str = None,
    output_variables: List[str] = None,
):
    """
    Simulate an air-source heat pump based on ERA5 weather data.

    This function calculates the coefficient of performance (COP) and electricity
    demand of an air-source heat pump at varying ambient temperatures. Results
    can be saved to a NetCDF file.

    Parameters
    ----------
    placements : pd.DataFrame
        DataFrame specifying plant locations and capacities.
    era5_path : str
        Path to the ERA5 weather data source.
    targetTemperature : float, optional
        Temperature at which the heat pump should supply the heat [°C]. Default is 100.
    secondLawEfficiency : float, optional
        Second law efficiency of the heat pump [0,1]. Default is 0.5.
    output_netcdf_path : str, optional
        Path to save the output NetCDF file. Default is None.
    output_variables : list of str, optional
        List of simulation variables to save to the NetCDF file. If None, all variables are saved.

    Returns
    -------
    xarray.Dataset
        Simulation results including COP, electricity conversion factor, and electricity input.
        Can be limited to `output_variables` if specified.

    Raises
    ------
    AssertionError
        If `targetTemperature` or `secondLawEfficiency` are not numeric or if
        `secondLawEfficiency` is not within (0, 1].

    Notes
    -----
    - The electricity conversion factor is calculated as -1/COP [kWh_el/kWh_th].
    - Electricity input is computed for each plant based on its capacity and the COP.
    - Units are stored in `wf.units` for reference.
    """
    assert isinstance(targetTemperature, (int, float))
    assert isinstance(secondLawEfficiency, (int, float))
    assert 0 < secondLawEfficiency <= 1, "efficiency must be between 0 and 1"

    wf = CoolingHeatingWorkflowManager(placements)
    wf.read(
        variables=[
            "surface_air_temperature",
        ],
        source_type="ERA5",
        source=era5_path,
        set_time_index=True,
        verbose=False,
    )
    wf.simulate_air_source_heat_pump(targetTemperature=targetTemperature, secondLawEfficiency=secondLawEfficiency)

    wf.sim_data["electricity_input"] = -wf.sim_data["conversion_factor_electricity"] * np.array(
        wf.placements["capacity"]
    )  # kWh_el/h

    wf.sim_data["heat_output"] = np.ones(wf.sim_data["electricity_input"].shape) * np.array(wf.placements["capacity"])

    return wf.to_xarray(
        output_netcdf_path=output_netcdf_path,
        output_variables=output_variables,
        custom_attributes=wf.units,
    )

calculate_relative_humidity

calculate_relative_humidity(
    dewpoint_temperature, air_temperature
)

Function to calculate the relative humidity from dewpoint temperature and air temperature using the Sonntag formula.

Parameters:

  • dewpoint_temperature

    dewpoint temperature in °C

  • air_temperature

    air temperature in °C

References

[1] https://www.npl.co.uk/resources/q-a/dew-point-and-relative-humidity

Source code in reskit/util/relative_humidity.py
def calculate_relative_humidity(dewpoint_temperature, air_temperature):
    """
    Function to calculate the relative humidity from dewpoint temperature and air temperature using the Sonntag formula.

    Parameters
    ----------
    dewpoint_temperature: float | int
        dewpoint temperature in °C
    air_temperature: float | int
        air temperature in °C

    References
    ----------
    [1] https://www.npl.co.uk/resources/q-a/dew-point-and-relative-humidity
    """

    def calculate_vapor_pressure(temperature):
        """
        Function to calculate the vapor pressure from the temperature

        temperature: temperature in °C
        """
        temperature_Kelvin = temperature + 273.15
        vapor_pressure = np.exp(
            -6096.9385 / temperature_Kelvin
            + 21.2409642
            - 2.711193 * 10**-2 * temperature_Kelvin
            + 1.673952 * 10**-5 * temperature_Kelvin**2
            + 2.433502 * np.log(temperature_Kelvin)
        )  # vapor pressure [1]
        return vapor_pressure

    relative_humidity = (
        calculate_vapor_pressure(dewpoint_temperature) / calculate_vapor_pressure(air_temperature) * 100
    )  # [1]

    return relative_humidity

calculate_wet_bulb_temperature

calculate_wet_bulb_temperature(
    air_temperature, relative_humidity
)

Function to calculate the wet bulb temperature from air temperature and relative humidity.

Parameters:

  • air_temperature

    air temperature in °C

  • relative_humidity

    relative humidity in %

References

[1] Roland Stull. Wet-bulb temperature from relative humidity and air temperature. Journal of Applied Meteorology and Climatology, 50:2267–2269, 11 2011.

Source code in reskit/util/wet_bulb_temperature.py
def calculate_wet_bulb_temperature(air_temperature, relative_humidity):
    """
    Function to calculate the wet bulb temperature from air temperature and relative humidity.

    Parameters
    ----------
    air_temperature: float | int
        air temperature in °C
    relative_humidity: float | int
        relative humidity in %

    References
    ----------
    [1] Roland Stull. Wet-bulb temperature from relative humidity and air temperature. Journal of Applied Meteorology and Climatology, 50:2267–2269, 11 2011.
    """
    wet_bulb_temperature = (
        air_temperature * np.arctan(0.151977 * (relative_humidity + 8.313659) ** (0.5))
        + np.arctan(air_temperature + relative_humidity)
        - np.arctan(relative_humidity - 1.676331)
        + 0.00391838 * (relative_humidity**1.5) * np.arctan(0.023101 * relative_humidity)
        - 4.686035
    )

    return wet_bulb_temperature

evaporative_cooling_wortmann2025

evaporative_cooling_wortmann2025(
    placements: DataFrame,
    era5_path: str,
    temperatureCoolant: int | float,
    heatTransferDelta: int | float,
    efficiencyCoolingTower: int | float,
    factorDriftLosses: float | int = 0.001,
    typical_cycles_blowdown: int = 5,
    output_netcdf_path: str = None,
    output_variables: List[str] = None,
)

Simulate an evaporative-cooling system based on ERA5 weather data.

This function calculates the water losses of an evaporative-cooling systems at varying ambient conditions (temperature, humidity). Results can be saved to a NetCDF file.

Parameters:

  • placements

    (DataFrame) –

    DataFrame specifying the plant locations and their capacities.

  • era5_path

    (str) –

    Path to the ERA5 weather data source.

  • temperatureCoolant

    (float | int) –

    Temperature of the cooling load (lower temperature if sensible heat transfer) in °C.

  • heatTransferDelta

    (float | int) –

    Temperature difference required for heat transfer from air to coolant [K]

  • efficiencyCoolingTower

    (float | int) –

    Efficiency of the cooling tower system [0, 1]

  • factorDriftLosses

    (float | int, default: 0.001 ) –

    Drift losses by small water droplets carried away by the exhaust air. Defaults to 0.001.

  • typical_cycles_blowdown

    (int, default: 5 ) –

    after how many cycles the blowdown occurs to prevent accumulation of impurities. Defaults to 5.

  • output_netcdf_path

    (str, default: None ) –

    Path to save the output NetCDF file. Default is None.

  • output_variables

    (list of str, default: None ) –

    List of simulation variables to save to the NetCDF file. If None, all variables are saved.

Returns:

  • Dataset

    Simulation results, including water losses. Can be limited to output_variables if specified.

Notes
  • Stores all relevant units in wf.units for reference.

Raises:

  • AssertionError

    If input parameters are not of expected type or if efficiency values are not within (0, 1].

Source code in reskit/cooling_heating/workflows/workflows.py
def evaporative_cooling_wortmann2025(
    placements: pd.DataFrame,
    era5_path: str,
    temperatureCoolant: int | float,
    heatTransferDelta: int | float,
    efficiencyCoolingTower: int | float,
    factorDriftLosses: float | int = 0.001,
    typical_cycles_blowdown: int = 5,
    output_netcdf_path: str = None,
    output_variables: List[str] = None,
):
    """
    Simulate an evaporative-cooling system based on ERA5 weather data.

    This function calculates the water losses of an evaporative-cooling systems at varying ambient conditions (temperature, humidity).
    Results can be saved to a NetCDF file.

    Parameters
    ----------
    placements : pd.DataFrame
        DataFrame specifying the plant locations and their capacities.
    era5_path : str
        Path to the ERA5 weather data source.
    temperatureCoolant : float | int
        Temperature of the cooling load (lower temperature if sensible heat transfer) in °C.
    heatTransferDelta : float | int
        Temperature difference required for heat transfer from air to coolant [K]
    efficiencyCoolingTower : float | int
        Efficiency of the cooling tower system [0, 1]
    factorDriftLosses : float | int
        Drift losses by small water droplets carried away by the exhaust air. Defaults to 0.001.
    typical_cycles_blowdown: int
        after how many cycles the blowdown occurs to prevent accumulation of impurities. Defaults to 5.
    output_netcdf_path : str, optional
        Path to save the output NetCDF file. Default is None.
    output_variables : list of str, optional
        List of simulation variables to save to the NetCDF file. If None, all variables are saved.

    Returns
    -------
    xarray.Dataset
        Simulation results, including water losses.
        Can be limited to `output_variables` if specified.

    Notes
    -----
    - Stores all relevant units in `wf.units` for reference.

    Raises
    ------
    AssertionError
        If input parameters are not of expected type or if efficiency values are not within (0, 1].
    """
    assert isinstance(temperatureCoolant, (int, float))
    assert isinstance(heatTransferDelta, (int, float))
    assert isinstance(efficiencyCoolingTower, (int, float))
    assert isinstance(factorDriftLosses, (int, float))
    assert isinstance(typical_cycles_blowdown, (int, float))
    assert 0 < efficiencyCoolingTower <= 1, "efficiencyCoolingTower must be between 0 and 1"
    assert 0 < factorDriftLosses <= 1, "factorDriftLosses must be between 0 and 1"

    wf = CoolingHeatingWorkflowManager(placements)

    wf.read(
        variables=["surface_air_temperature", "surface_dew_temperature"],
        source_type="ERA5",
        source=era5_path,
        set_time_index=True,
        verbose=False,
    )

    wf.sim_data["relative_humidity"] = calculate_relative_humidity(
        dewpoint_temperature=wf.sim_data["surface_dew_temperature"],
        air_temperature=wf.sim_data["surface_air_temperature"],
    )

    wf.sim_data["wet_bulb_temperature"] = calculate_wet_bulb_temperature(
        air_temperature=wf.sim_data["surface_air_temperature"], relative_humidity=wf.sim_data["relative_humidity"]
    )

    wf.calculate_approach_evaporative_cooling(
        temperatureCoolant=temperatureCoolant,
        heatTransferDelta=heatTransferDelta,
        efficiencyCoolingTower=efficiencyCoolingTower,
    )

    wf.calculate_water_losses_evaporative_cooling(
        temperatureCoolant=temperatureCoolant,
        heatTransferDelta=heatTransferDelta,
        efficiencyCoolingTower=efficiencyCoolingTower,
        factorDriftLosses=factorDriftLosses,
        typical_cycles_blowdown=typical_cycles_blowdown,
    )

    # calculate total water demand for the plant
    wf.sim_data["total_water_losses"] = -wf.sim_data["conversion_factor_water"] * np.array(wf.placements["capacity"])

    return wf.to_xarray(
        output_netcdf_path=output_netcdf_path,
        output_variables=output_variables,
        custom_attributes=wf.units,
    )