Humid Air Connection

This tutorial introduces the HAConnection class, which models moist (humid) air streams. It wraps CoolProp’s HumidAir backend and exposes physical quantities for psychrometric calculations. It is an experimental feature for now and might be reworked in near future!

Parameter

Description

m

mass flow rate of dry air (system variable)

p

absolute pressure

h

dry-air-specific enthalpy (system variable)

T

temperature

w

humidity ratio - kg water per kg dry air

r

relative humidity (0 … 1)

mHA

mass flow rate of the humid-air mixture (result)

mH2O

mass flow rate of liquid/solid water that condenses out (result)

The fluid vector of an HAConnection always contains exactly two components: air and water (mass fractions). Setting w is a shortcut that derives the corresponding mass fractions automatically.

Physical scenario

We simulate a simple air-cooling coil found in HVAC systems. Humid air enters at 15 °C, is cooled to 5 °C (below the dew point), and the heat is absorbed by an evaporating NH₃ refrigerant. If the outlet temperature is below the dew point, some moisture condenses and leaves as liquid water (mH2O > 0).

The network contains:

  • Air side - two HAConnection objects around a MovingBoundaryHeatExchanger

  • Refrigerant side - two regular Connection objects carrying NH₃

from tespy.components import MovingBoundaryHeatExchanger, Sink, Source
from tespy.connections import Connection, HAConnection
from tespy.networks import Network

Network and component setup

nw = Network()
nw.units.set_defaults(
    temperature="°C", pressure="bar", pressure_difference="bar", heat="kW"
)

# air-side components
air_source = Source("air source")
air_sink = Sink("air sink")

# refrigerant-side components
ref_source = Source("refrigerant source")
ref_sink = Sink("refrigerant sink")

hex = MovingBoundaryHeatExchanger("heat exchanger")

# air-side connections use HAConnection
c1 = HAConnection(air_source, "out1", hex, "in1", label="c1")
c2 = HAConnection(hex, "out1", air_sink, "in1", label="c2")

# refrigerant-side connections use regular Connection
a1 = Connection(ref_source, "out1", hex, "in2", label="a1")
a2 = Connection(hex, "out2", ref_sink, "in1", label="a2")

nw.add_conns(c1, c2, a1, a2)

Case 1: Specifying the humidity ratio w

The most direct way to fix the inlet humidity is to set w, the ratio of water mass to dry-air mass. A value of w = 0.004 kg/kg corresponds to roughly 40 % relative humidity at 15 °C. TESPy translates this into mass fractions internally, so there is no need to also set fluid or fluid_balance.

# air inlet: 15 °C, 1 bar, w = 0.004 kg_water/kg_dry_air
c1.set_attr(p=1, T=15, w=0.004)
# air outlet: cooled to 5 °C
c2.set_attr(T=5)

# NH3 refrigerant: 2 kg/s, 30 % quality at inlet; 5 K superheat above dew point at -20 °C outlet
a1.set_attr(fluid={"NH3": 1}, m=2, x=0.3)
a2.set_attr(td_dew=5, T_dew=-20)

hex.set_attr(dp1=0, dp2=0)
nw.solve("design")
nw.assert_convergence()
 iter  | residual   | progress   | massflow   | pressure   | enthalpy   | fluid      | component  
-------+------------+------------+------------+------------+------------+------------+------------
 1     | 1.88e+06   | 0 %        | 1.86e+02   | 0.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 2     | 2.09e-04   | 100 %      | 2.06e-08   | 0.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 3     | 2.33e-10   | 100 %      | 2.30e-14   | 0.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
 4     | 0.00e+00   | 100 %      | 0.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   | 0.00e+00   
Total iterations: 4, Calculation time: 0.00 s, Iterations per second: 1353.44
nw.results["HAConnection"][["T", "w", "r", "m", "mHA", "mH2O"]].style
  T w r m mHA mH2O
c1 15.000000 0.004000 0.373121 185.960364 186.704206 0.000000
c2 5.000000 0.004000 0.729421 185.960364 186.704206 0.000000

Interpreting the results

  • m – mass flow of dry air (the conserved quantity inside a humid-air loop; it does not change even if moisture condenses)

  • mHA – mass flow of the humid-air mixture

  • mH2O – mass flow of liquid water that condenses out

  • w – humidity ratio at each connection. It drops if moisture is removed

  • r – relative humidity

Case 2: Specifying relative humidity r with fluid_balance

When the inlet state is described by relative humidity rather than humidity ratio, we use the r parameter. Because the fluid composition (the ratio of air to water mass fractions) is now an unknown that is determined by the r equation, we must tell TESPy to close the fluid balance automatically with fluid_balance=True.

If no previous result is available fluid0 should be specified as initial guess for the solver.

# remove the w specification and switch to relative humidity
c1.set_attr(
    w=None,
    r=0.9,
    fluid_balance=True,
)
nw.solve("design")
nw.assert_convergence()
 iter  | residual   | progress   | massflow   | pressure   | enthalpy   | fluid      | component  
-------+------------+------------+------------+------------+------------+------------+------------
 1     | 1.88e+06   | 0 %        | 1.93e+06   | 0.00e+00   | 3.55e+04   | 5.66e-03   | 0.00e+00   
 2     | 2.93e+10   | 0 %        | 2.92e+06   | 0.00e+00   | 1.04e+04   | 5.14e-05   | 0.00e+00   
 3     | 2.26e+10   | 0 %        | 9.01e+05   | 0.00e+00   | 1.96e+03   | 6.25e-10   | 0.00e+00   
 4     | 1.81e+09   | 0 %        | 8.66e+04   | 0.00e+00   | 4.59e-02   | 5.92e-14   | 0.00e+00   
 5     | 2.17e+03   | 29 %       | 1.04e-01   | 0.00e+00   | 1.51e-07   | 6.04e-18   | 0.00e+00   
 6     | 1.70e-08   | 100 %      | 7.42e-14   | 0.00e+00   | 1.27e-10   | 1.21e-18   | 0.00e+00   
 7     | 1.63e-09   | 100 %      | 8.18e-13   | 0.00e+00   | 1.27e-10   | 0.00e+00   | 0.00e+00   
Total iterations: 7, Calculation time: 0.11 s, Iterations per second: 61.71
nw.results["HAConnection"][["T", "w", "r", "m", "mHA", "mH2O"]].style
  T w r m mHA mH2O
c1 15.000000 0.009737 0.900000 90.265760 91.144656 0.000000
c2 5.000000 0.005497 1.000000 90.265760 90.761944 0.382713

At 90 % relative humidity and 15 °C the humidity ratio is noticeably higher than in Case 1. When the air is cooled to 5 °C 390 g/s of the water condenses.

When to use fluid_balance

Specification

fluid_balance needed?

w (humidity ratio)

No - composition is fully determined by w

r (relative humidity)

Yes - r imposes one equation on the two unknown mass fractions; fluid_balance provides the second (sum = 1)

fluid={"air": ..., "water": ...} directly

No - both fractions are fixed