Dry Cooler

Note

A dry cooler consists of an element and a controller. The element defines it’s physical parameters, while the controller governs the operational logic.

The create_controlled function creates both and connects them.

Create Controlled Function

pandaprosumer.create_controlled_dry_cooler(prosumer, n_nom_rpm, p_fan_nom_kw, qair_nom_m3_per_h, t_air_in_nom_c=15, t_air_out_nom_c=35, t_fluid_in_nom_c=65, t_fluid_out_nom_c=40, fans_number=1, adiabatic_mode=False, phi_adiabatic_sat_percent=99, min_delta_t_air_c=0, name=None, index=None, in_service=True, period=0, level=0, order=0, **kwargs)[source]

Creates a dry cooler element in prosumer[“dry_cooler”] and a dry cooler controller

INPUT:

prosumer - The prosumer within this dry_cooler should be created

n_nom_rpm (float) - Nominal rotational speed of the fans [rpm]

p_fan_nom_kw (float) - Nominal electric power of each fan [kW]

qair_nom_m3_per_h (float) - Nominal air flow [m3/h]

t_air_in_nom_c (float, default 15) - Air nominal input temperature [C]

t_air_out_nom_c (float, default 35) - Air nominal output temperature [C]

t_fluid_in_nom_c (float, default 60) - Water nominal input temperature [C]

t_fluid_out_nom_c (float, default 40) - Water nominal output temperature [C]

OPTIONAL:

fans_number (integer, default 1) - Number of fans in the dry cooler

adiabatic_mode (boolean, default False) - Whether to use the air adiabatic pre-cooling mode.

If False, apply dry cooling only

phi_adiabatic_sat_percent (float, default 99) - Adiabatic Pre-Cooling saturation level [%]

min_delta_t_air_c (float, default 0) - Minimum air temperature difference [C]

name (string, default None) - The name for this dry cooler

index (int, default None) - Force a specified ID if it is available. If None, the index one higher than the highest already existing index is selected.

in_service (boolean, default True) - True for in_service or False for out of service

level (int, default 0) - The level of the controller

order (int, default 0) - The order of the controller

period (int, default 0) - Index of the period, default is 0

OUTPUT:

index (int) - The unique ID of the created dry cooler

EXAMPLE:

create_controlled_dry_cooler(prosumer, “dry_cooler_1”)

Controller

Dry Cooler Controller logic

Input Static Data

Parameter

Description

Unit

name

A custom name for this heat pump

N/A

n_nom_rpm

Nominal rotational speed of the fans

rpm

p_fan_nom_kw

Nominal electric power of each fan

kw

qair_nom_m3_per_h

Nominal air flow

m3/h

t_air_in_nom_c

Air nominal input temperature

Degree Celsius

t_air_out_nom_c

Air nominal output temperature

Degree Celsius

t_fluid_in_nom_c

Water nominal input temperature

Degree Celsius

t_fluid_out_nom_c

Water nominal output temperature

Degree Celsius

fans_number

Number of fans in the dry cooler

int

adiabatic_mode

Whether to use the air adiabatic pre-cooling

boolean

phi_adiabatic_sat_percent

Adiabatic Pre-Cooling saturation level

%

min_delta_t_air_c

Minimum air temperature difference

Degree Celsius

Input Time Series

Parameter

Description

Unit

mdot_fluid_kg_per_s

Water required mass flow rate

kg/s

t_in_c

Water input required temperature

Degree Celsius

t_out_c

Water output expected temperature

Degree Celsius

t_air_in_c

Input dry bulb temperature of the ambient air

Degree Celsius

phi_air_in_percent

Input relative humidity of the ambient air.

Degree Celsius

Output Time Series

Parameter

Description

Unit

q_exchanged_kw

Extracted heat power

kW

p_fans_kw

Electrical power consumed by the fans

kW

n_rpm

Fans rotational speed

rpm

mdot_air_m3_per_h

Air mass flow through the cooler

m3/h

Mapping

The Dry Cooler Controller can be mapped using FluidMixMapping.

  • The dry cooler can be used as responder for a FluidMix mapping, taking the output from another controller as its input

  • No output are mapped, as the dry cooler does not act as an initiator.

Model

class pandaprosumer.controller.models.DryCoolerController(prosumer, dry_cooler_object, order=-1, level=-1, in_service=True, index=None, name=None, **kwargs)[source]

Controller for dry coolers.

First implementation of the dry cooler that do not model the heat exchange between the water the air

Parameters:
  • prosumer – The prosumer object

  • dry_cooler_object – The heat pump object

  • order – The order of the controller

  • level – The level of the controller

  • in_service – The in-service status of the controller

  • index – The index of the controller

  • kwargs – Additional keyword arguments

control_step(prosumer)[source]

Executes the control step for the controller.

Parameters:

prosumer – The prosumer object

The dry cooler model is based on a combination of the heat demand controller and of the heat_exchanger_element.

The dry cooler is a heat exchanger that uses air to cool down a fluid.

On the secondary side, the cooling demand is given from the input \(Q\), \(\dot{m}\), \(T_\text{feed}\) and \(T_\text{return}\) that may come from a timeseries data through a ConstProfile controller.

The ambient air temperature on the primary side is also an input that may be mapped from timeseries data.

Schematic representation of a dry cooler

Schematic representation of an air-cooled heat exchanger (source: [RTH23])

The heat exchanger will then calculate the air flow rate needed to cool down the fluid to the desired temperature. This air flow rate will be used to calculate the power consumption of the fans of the dry cooler, who are needed to apply a forced convection on the air and ensure cooling. The power consumption of the fans is assumed to be proportional to the air flow rate.

The air mass flow rate is calculated similarly to the heat exchanger model based on the logarithmic mean temperature difference (LMTD) calculation. However as known temperature is the cold input air temperature, the model is adapted.

The equation to solve is in this case:

\begin{align*} a * X - \ln{(1+X)} &= 0 \\ \end{align*}

With

\begin{align*} a &= \Delta T_\text{cold} * \frac{Q_{r_n}}{Q_r} * \frac{1}{LMTD_n} \\ X &= \frac{\Delta T_\text{hot}}{\Delta T_\text{cold}} - 1 \end{align*}

This equation is solved by dichotomy to find \(X\), then \(\Delta T_\text{hot}\), then \(T_{\text{air}_\text{out}}\).

Assuming no heat losses, we then derive \(\dot{m}_\text{air}\) given that

\begin{align*} Q_r = Q_\text{air} = Q_\text{water} = \dot{m}_\text{air} * Cp_\text{air} * \Delta T_\text{air} = \dot{m}_\text{water} * Cp_\text{water} * \Delta T_\text{water} \end{align*}

Note

\(a = 1\) means that \(X = 0\) so \(\Delta T_\text{hot} = \Delta T_\text{cold}\)

\(0 < a < 1\) means that \(X > 0\) so \(\Delta T_\text{hot} > \Delta T_\text{cold}\)

\(a > 1\) means that \(-1 < X < 0\) so \(\Delta T_\text{hot} < \Delta T_\text{cold}\)

Note

\(X < -1\) would mean \(\Delta T_\text{hot} < 0\), so \(T_{2_\text{out}} > T_{1_\text{in}}\), which is not possible for the heat exchange

\(a << 1\) would mean \(\Delta T_\text{hot} >> \Delta T_\text{cold}\), so \(T_{2_\text{out}} < T_{2_\text{in}}\) which is not possible for a countercurrent flows

The power consumption of the fans is then calculated from the “Fan Affinity Laws”:

With impeller diameter \(D\) constant, the power consumption of the fans is proportional to the cube of the air flow rate, which is proportional to the shaft speed:

\begin{align*} \frac{Q_{\text{fan}_n}}{Q_{\text{fan}}} &= \left(\frac{\dot{m}_\text{air}}{\dot{m}_{\text{air}_n}}\right) \\ \frac{P_{\text{fan}_n}}{P_{\text{fan}}} &= \left(\frac{\dot{m}_\text{air}}{\dot{m}_{\text{air}_n}}\right)^3 \\ P_\text{fan} &= \frac{P_{\text{fan}_n} * \dot{m}_\text{air}^3}{\dot{m}_{\text{air}_n}^3} \\ \end{align*}
Schematic representation of an adiabatic cooler

Schematic representation of an adiabatic cooler system and process (source: [RTH23])

The adiabatic feature consists in spraying water on the air to cool it down and increase the efficiency of the dry cooler.

For a given input air dry bulb temperature \(T_{db}\) and relative humidity \(\phi\), the wet bulb temperature \(T_{wb}\) can be calculated using the formula from [RTH23]:

\begin{align*} T_\text{wb} &= T_\text{db} * \arctan{(0.151977 * (\phi + 8.313659)^{0.5})} \\ &+ \arctan{(T_{db} + \phi)} - \arctan{(\phi - 1.676331)} \\ &+ 0.00391838 * \phi^{3/2} * \arctan{(0.023101 \phi)} - 4.686035 \\ \end{align*}

with temperature in °C and in % as input arguments.

We assume that the air is saturated with water at the wet bulb temperature after going through the adiabatic pre-cooling system when it is activated, and that the air is then cooled down to this temperature.