psychrometrics#
Moist-air thermodynamics behind the Mollier h,x-diagram: saturation
pressure, dew point, wet-bulb temperature, enthalpy and density, the
state() constructor for a complete moist-air
state, and air-handling processes (heating, cooling, isothermal and
adiabatic humidification, mixing, heat recovery) that can be chained and
summarised.
The public module is pyedautils.psychrometrics:
from pyedautils.psychrometrics import state, heat, mix, pressure_from_altitude
p = pressure_from_altitude(450) # ISA barometric formula: 96 035 Pa at 450 m
pressure_from_altitude is also what plot_mollier_hx(),
plot_mollier_hx_fast() and state(altitude=...) use
when only an altitude is given, so passing altitude=450 is enough there.
Note
The implementation lives in the private module pyedautils._mollier. Imports
from there keep working, but only the names exported by
pyedautils.psychrometrics are public API.
See Mollier h,x-Diagram for usage examples.
Tip
New to the h,x diagram? The h,x diagram in five minutes explains how to read it correctly (relative vs. absolute humidity, pressure, mould at cold surfaces), comfort and saving energy, with worked examples computed with these functions.
API Reference#
Moist-air thermodynamics (psychrometrics) behind the Mollier h,x-diagram.
Public entry point for the psychrometric functions: saturation pressure,
dew point, wet-bulb temperature, enthalpy and density, pressure from
altitude, the state() constructor for a complete moist-air state, and
air-handling processes (heating, cooling, isothermal and adiabatic
humidification, mixing, heat recovery) that can be chained and summarised:
from pyedautils.psychrometrics import pressure_from_altitude, state, heat
p = pressure_from_altitude(450) # 96 035 Pa (ISA)
room = state(t=21, phi=0.5, p=p)
The implementation lives in the private module pyedautils._mollier;
importing from there keeps working, but only the names re-exported here
are public API.
- pyedautils.psychrometrics.pressure_from_altitude(altitude_m) float[source]#
Atmospheric pressure [Pa] at given altitude [m above sea level].
International Standard Atmosphere (ISA) barometric formula, valid in the troposphere (0–11 km). Reference state: p₀ = 101325 Pa, T₀ = 288.15 K, L = 0.0065 K/m.
Public import:
from pyedautils.psychrometrics import pressure_from_altitude. The Mollier plots (pyedautils.plots.plot_mollier_hx(),plot_mollier_hx_fast) andstate()apply it when onlyaltitudeis given.- Parameters:
altitude_m – Altitude in metres above sea level (scalar or array).
- Returns:
Pressure in Pa, e.g. 101325 at 0 m and about 96 035 at 450 m.
- Return type:
float
- pyedautils.psychrometrics.p_sat(t)[source]#
Saturation vapour pressure [Pa] for temperature t [°C].
Works with scalars and numpy arrays. Convention-independent.
- pyedautils.psychrometrics.temperature_p_sat(p_s) float[source]#
Inverse of p_sat: temperature [°C] from saturation pressure [Pa].
Convention-independent. Uses Newton’s method on log(p_sat) for better convergence.
- pyedautils.psychrometrics.vapor_pressure(x, p) float[source]#
Water-vapour partial pressure [Pa] from absolute humidity and pressure.
- Parameters:
x – Absolute humidity [kg/kg dry air].
p – Total pressure [Pa].
- pyedautils.psychrometrics.dew_point(x, p) float[source]#
Dew-point temperature [°C] from absolute humidity and pressure.
The dew point is the temperature at which the current water-vapour partial pressure equals the saturation pressure (φ = 1). Inverts
temperature_p_satfor the vapour-pressure of the given (x, p).
- pyedautils.psychrometrics.specific_volume(t, x, p) float[source]#
Specific volume [m³/kg dry air] from temperature, abs. humidity, pressure.
- Parameters:
t – Dry-bulb temperature [°C].
x – Absolute humidity [kg/kg dry air].
p – Total pressure [Pa].
- pyedautils.psychrometrics.wet_bulb(t, x, p) float[source]#
Wet-bulb temperature [°C] from dry-bulb T, abs. humidity x, pressure p.
Solves the adiabatic-saturation energy balance:
h(T_db, x) = h(T_wb, x_sat(T_wb)) − (x_sat(T_wb) − x)·c_W_fl·T_wb
iteratively (Newton with numerical derivative). Returns T_wb such that air at T_db, x is in equilibrium with water adiabatically evaporated to saturation at T_wb.
Notes
At saturation (x = x_sat(T_db)), T_wb = T_db.
Convention-independent (T_wb is a physical thermodynamic quantity).
- pyedautils.psychrometrics.enthalpy(x, y) float[source]#
Enthalpy [kJ/kg] from diagram coordinates (x, y).
Convention-independent: h = R_0*x + C_PL*y holds by the y-axis definition in both conventions.
- pyedautils.psychrometrics.x_hy(h, y) float[source]#
Absolute humidity from enthalpy [kJ/kg] and y-coordinate.
Convention-independent.
- pyedautils.psychrometrics.y_hx(h, x) float[source]#
y-coordinate from enthalpy [kJ/kg] and absolute humidity.
Convention-independent.
- pyedautils.psychrometrics.temperature(x, y, convention=None) float[source]#
Temperature [°C] from diagram coordinates (x, y).
- pyedautils.psychrometrics.rel_humidity(x, y, p, convention=None) float[source]#
Relative humidity [0–1] from diagram coordinates and pressure [Pa].
- pyedautils.psychrometrics.density(x, y, p, convention=None) float[source]#
Air density [kg/m³] from diagram coordinates and pressure [Pa].
- pyedautils.psychrometrics.get_x_y(t, phi, p, convention=None)[source]#
(x, y) from temperature [°C], relative humidity [0–1], pressure [Pa].
Works with scalars and numpy arrays.
- pyedautils.psychrometrics.get_x_y_tx(t, x, p, convention=None)[source]#
(x, y) from temperature [°C] and absolute humidity [kg/kg].
- pyedautils.psychrometrics.y_phix(phi, x, p, convention=None) float[source]#
y-coordinate from relative humidity, absolute humidity, pressure.
- pyedautils.psychrometrics.x_phiy(phi, y, p, convention=None) float[source]#
Absolute humidity from relative humidity and y-coordinate (Newton).
- pyedautils.psychrometrics.y_rhox(rho, x, p, convention=None) float[source]#
y-coordinate from density [kg/m³], absolute humidity, pressure [Pa].
- pyedautils.psychrometrics.create_comfort(range_t, range_phi, range_x, p, convention=None)[source]#
Create the comfort-zone polygon as a list of (x, y) tuples.
- Parameters:
range_t – (min, max) temperature [°C].
range_phi – (min, max) relative humidity [0–1].
range_x – (min, max) absolute humidity [kg/kg].
p – Pressure [Pa].
convention – Mollier convention (‘classical’ default, or ‘glueck’).
- Returns:
List of (x, y) coordinate pairs forming a closed polygon.
- class pyedautils.psychrometrics.MoistAirState(t: float, phi: float, x: float, h: float, t_wb: float, t_dp: float, p_v: float, rho: float, v: float, y: float, m_dot_dry: float | None = None, volume_flow: float | None = None, p: float = 101325.0, convention: str = 'classical')[source]#
Bases:
objectImmutable moist-air state with all derived psychrometric properties.
Construct via
state(), never call this constructor directly.- Intensive properties (always populated):
t: dry-bulb temperature [°C] phi: relative humidity [0..1] x: absolute humidity [kg/kg dry air] h: specific enthalpy [kJ/kg dry air] t_wb: wet-bulb temperature [°C] t_dp: dew-point temperature [°C] p_v: water-vapour partial pressure [Pa] rho: moist-air density [kg/m³] v: specific volume [m³/kg dry air] y: diagram y-coordinate (depends on
convention)- Extensive properties (optional,
Nonewhen not specified): m_dot_dry: dry-air mass flow [kg/s] volume_flow: volumetric flow rate [m³/h], evaluated at
v- Context:
p: total pressure [Pa] convention: Mollier coordinate convention (‘classical’ | ‘glueck’)
- t: float#
- phi: float#
- x: float#
- h: float#
- t_wb: float#
- t_dp: float#
- p_v: float#
- rho: float#
- v: float#
- y: float#
- m_dot_dry: float | None = None#
- volume_flow: float | None = None#
- p: float = 101325.0#
- convention: str = 'classical'#
- pyedautils.psychrometrics.state(*, t=None, t_wb=None, t_dp=None, phi=None, x=None, h=None, p=None, altitude=None, m_dot_dry=None, volume_flow=None, convention=None) MoistAirState[source]#
Construct a
MoistAirStatefrom any two psychrometric properties.Exactly two of
{t, t_wb, t_dp, phi, x, h}must be given. All other properties are computed and returned.- Parameters:
t – dry-bulb, wet-bulb, dew-point temperatures [°C]
t_wb – dry-bulb, wet-bulb, dew-point temperatures [°C]
t_dp – dry-bulb, wet-bulb, dew-point temperatures [°C]
phi – relative humidity [0..1]
x – absolute humidity [kg/kg dry air]
h – enthalpy [kJ/kg dry air]
p – total pressure [Pa] (defaults to sea-level standard when neither
pnoraltitudeis given)altitude – altitude in metres a.s.l.; mutually exclusive with
pm_dot_dry – dry-air mass flow [kg/s] (mutually exclusive with
volume_flow)volume_flow – volumetric flow [m³/h] at the state’s specific volume; converted internally to
m_dot_dryconvention – ‘classical’ (default) or ‘glueck’
- Raises:
ValueError – on invalid argument combinations (e.g. wrong number of psychrometric properties, both
pandaltitude, degenerate pair like(x, t_dp)).
- class pyedautils.psychrometrics.ProcessBalance(name: str, dh: float, dx: float, power_kw: float | None = None, condensate_kgh: float | None = None, water_kgh: float | None = None, epsilon: float | None = None)[source]#
Bases:
objectEnergy and water balance for one psychrometric process step.
- name#
process identifier (‘heat’, ‘cool’, …)
- Type:
str
- dh#
specific enthalpy change [kJ/kg dry air] (positive = heating, negative = cooling). 0 by convention for
mix.- Type:
float
- dx#
humidity-ratio change [kg/kg dry air] (positive = humidification, negative = drying). 0 by convention for
mix.- Type:
float
- power_kw#
m_dot_dry × dh [kW]; None when m_dot_dry unset
- Type:
float | None
- condensate_kgh#
m_dot_dry × |dx| × 3600 [kg/h] for cooling that crosses the dew point; None otherwise
- Type:
float | None
- water_kgh#
m_dot_dry × dx × 3600 [kg/h] for humidification; None otherwise
- Type:
float | None
- epsilon#
efficiency for heat_recovery; None otherwise
- Type:
float | None
- name: str#
- dh: float#
- dx: float#
- power_kw: float | None = None#
- condensate_kgh: float | None = None#
- water_kgh: float | None = None#
- epsilon: float | None = None#
- pyedautils.psychrometrics.heat(s, t_out=None, dt=None, power_kw=None)[source]#
Sensible heating at constant absolute humidity x.
- Parameters:
s – input MoistAirState
t_out – target dry-bulb temperature [°C]
dt – temperature change [K]; positive = heating
power_kw – heating power [kW]; requires
s.m_dot_dryto be set
- Returns:
(new_state, ProcessBalance)
- pyedautils.psychrometrics.cool(s, t_out=None, dt=None)[source]#
Cooling. Sensible while T_out ≥ dew point; latent below (output state saturated at the coil temperature, BF = 0).
- Parameters:
s – input MoistAirState
t_out – target dry-bulb temperature [°C] (= coil temperature in the latent regime)
dt – temperature change [K]; should be negative
- Returns:
(new_state, ProcessBalance)
- pyedautils.psychrometrics.humidify_isothermal(s, x_out=None, phi_out=None)[source]#
Steam humidifier: T stays constant, water vapour added.
- Parameters:
s – input MoistAirState
x_out – target humidity ratio [kg/kg]
phi_out – target relative humidity [0..1]
- Returns:
(new_state, ProcessBalance)
- pyedautils.psychrometrics.humidify_adiabatic(s, x_out=None, phi_out=None)[source]#
Adiabatic humidifier (evaporative): h stays constant, water added, T drops.
- Parameters:
s – input MoistAirState
x_out – target humidity ratio [kg/kg]
phi_out – target relative humidity [0..1]
- Returns:
(new_state, ProcessBalance)
- pyedautils.psychrometrics.mix(s_a, s_b)[source]#
Adiabatic mixing of two moist-air streams.
Both inputs must have
m_dot_dryset and matching pressure. The output hasm_dot_dry = s_a.m_dot_dry + s_b.m_dot_dryand the mass-weighted x and h.- Returns:
(mixed_state, ProcessBalance with dh=dx=0)
- pyedautils.psychrometrics.heat_recovery(supply, extract, eps_sensible, eps_latent=0.0)[source]#
Two-stream heat (and optionally moisture) recovery exchanger.
Returns the new state of the SUPPLY side after recovery. The extract side is treated as an input boundary condition; compute it separately if you need the exhaust state.
- Parameters:
supply – inlet state of the supply stream
extract – inlet state of the extract (return) stream
eps_sensible – temperature effectiveness [0..1]
eps_latent – humidity effectiveness [0..1]; default 0 (sensible-only HX)
- Returns:
(new_supply_state, ProcessBalance)