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 |
|---|---|
|
mass flow rate of dry air (system variable) |
|
absolute pressure |
|
dry-air-specific enthalpy (system variable) |
|
temperature |
|
humidity ratio - kg water per kg dry air |
|
relative humidity (0 … 1) |
|
mass flow rate of the humid-air mixture (result) |
|
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
HAConnectionobjects around aMovingBoundaryHeatExchangerRefrigerant side - two regular
Connectionobjects 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 mixturemH2O– mass flow of liquid water that condenses outw– humidity ratio at each connection. It drops if moisture is removedr– 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 |
|
|---|---|
|
No - composition is fully determined by |
|
Yes - |
|
No - both fractions are fixed |