@verifyhash/psychrometrics
v0.1.1
Published
Zero-dependency humidity & moist-air math: saturation vapour pressure, dew point, relative & absolute humidity, NOAA heat index, and Stull wet-bulb temperature.
Maintainers
Readme
psychrometrics
A tiny, zero-dependency Node library for humidity and moist-air math: saturation vapour pressure, dew point, relative and absolute humidity, the NOAA heat index, and Stull's wet-bulb temperature.
Every export is a pure function: no I/O, no network, no daemon, no dependencies, and no mutation of its arguments. The same inputs always give the same output. Everything is in SI-friendly units — degrees Celsius, percent RH, hectopascals (hPa == millibars), and grams per cubic metre.
Who it's for
Developers building HVAC, weather, or agriculture tools who need reliable moist-air numbers without pulling in a large scientific package or hitting an API:
- an HVAC/indoor-climate app converting between temperature, RH, and dew point;
- a weather dashboard showing "feels like" (heat index) and wet-bulb stress;
- an agriculture / greenhouse model tracking condensation risk (dew point) and vapour density (absolute humidity).
Install / use
Copy the folder in, or require it directly — there is nothing to install.
const psy = require('./psychrometrics'); // path to this folder
psy.dewPoint(30, 50); // → 18.45 (°C)
psy.saturationVaporPressure(20); // → 23.33 (hPa)
psy.heatIndex(32, 70); // → 40.4 (°C, "feels like")
psy.absoluteHumidity(20, 50); // → 8.62 (g/m³)
psy.wetBulb(20, 50); // → 13.70 (°C)Run the tests
One command, offline, no framework:
node test/psychrometrics.test.jsIt exits 0 on success and prints N passed, 0 failed. (Or npm test.)
API
All temperatures are °C, all relative humidity is percent (0..100), vapour pressure is hPa, absolute humidity is g/m³.
saturationVaporPressure(tempC) → hPa
Saturation vapour pressure of water over a flat liquid surface.
- Formula: Magnus/Tetens form,
es = 6.1094 · exp(17.625·T / (243.04 + T)), using the Alduchov & Eskridge (1996) "AERK" coefficients (J. Appl. Meteorol. 35, 601–609). - Accuracy: better than 0.4 % over roughly −40 °C … +50 °C.
- Caveats: over ice (below 0 °C) the true saturation pressure is slightly lower than this over-liquid value; if you need frost-point work, use an over-ice coefficient set. Not valid far outside the fitted range.
- Reference:
es(0 °C) = 6.1094 hPa,es(20 °C) ≈ 23.3 hPa.
dewPoint(tempC, rhPct) → °C
Temperature to which the air must cool (at constant pressure and water content) to reach saturation.
- Formula: analytic Magnus inverse of
saturationVaporPressure, with the same AERK coefficients, sodewPointandrelativeHumidityare mutually consistent. - Domain:
rhPctin[0, 100]. At100 %the dew point equals the air temperature; at0 %it is-Infinity(dry air never saturates on cooling). - Accuracy: inherits the < 0.4 % vapour-pressure fit; dew-point error is typically a few hundredths of a degree versus an exact inversion.
- Reference:
dewPoint(30, 50) ≈ 18.4 °C.
relativeHumidity(tempC, dewPointC) → %
Relative humidity from air temperature and dew point, as the ratio of saturation vapour pressure at the dew point to that at the air temperature.
- Formula:
100 · es(dewPointC) / es(tempC). - Round-trip:
relativeHumidity(T, dewPoint(T, rh)) ≈ rhto machine precision (verified in the tests). - Caveat: returns > 100 when
dewPointC > tempC(supersaturation); that is intentional, not clamped, so callers can detect bad/edge inputs.
absoluteHumidity(tempC, rhPct) → g/m³
Mass of water vapour per cubic metre of air (vapour density).
- Formula: ideal-gas law on the vapour partial pressure,
AH = e / (Rv · T_K)withe = es(T)·RH/100in Pa,Rv = 461.5 J/(kg·K),T_K = T + 273.15, result converted to g/m³. - Domain:
rhPctin[0, 100]. Linear in RH at fixed temperature. - Caveat: treats vapour as an ideal gas (excellent at ambient conditions; small errors near boiling). Independent of barometric pressure, since it is a density, not a mixing ratio.
- Reference:
absoluteHumidity(20, 100) ≈ 17.3 g/m³(saturated 20 °C air).
heatIndex(tempC, rhPct) → °C
Apparent "feels-like" temperature from heat and humidity.
- Formula: NOAA/NWS Rothfusz regression. Computed internally in °F and returned in °C. Matching the NWS reference implementation, it first tries the simpler Steadman average; if that stays below 80 °F (≈ 27 °C) the heat index is essentially the air temperature and that value is returned. Otherwise the full 9-term polynomial is applied, followed by the two documented corrections — a low-RH subtraction (RH < 13 %, 80–112 °F) and a high-RH addition (RH > 85 %, 80–87 °F).
- Valid range: the regression is fit for hot, humid conditions, roughly T ≳ 27 °C and RH ≳ 40 %. Outside that the returned value approaches the air temperature and should be read as "no meaningful heat stress," not as a precise apparent temperature. Heat index also assumes shade and light wind; direct sun can add up to ~8 °C.
- Reference:
heatIndex(32, 70) ≈ 40 °C(well above the 32 °C air temperature).
wetBulb(tempC, rhPct) → °C
Wet-bulb temperature: the lowest temperature reachable by evaporative cooling at the given humidity — a key metric for heat stress and cooling-tower design.
- Formula: Stull (2011), "Wet-Bulb Temperature from Relative Humidity and Air Temperature", J. Appl. Meteorol. Climatol. 50, 2267–2269, an empirical closed-form fit (no iteration).
- Valid range: standard sea-level pressure (1013.25 hPa), roughly −20 °C ≤ T ≤ 50 °C and 5 % ≤ RH ≤ 99 %, where it agrees with an exact psychrometric solver to about ±1 °C. Error grows at very low RH / very low temperature.
- Caveat: not altitude-corrected — at high elevation (lower pressure) the true wet bulb is lower than this returns.
- Reference:
wetBulb(20, 50) ≈ 13.7 °C(Stull's worked example).
Domain guards
Inputs are validated so unit mistakes fail loudly instead of silently producing garbage:
- Every numeric argument must be a finite number or a
TypeErroris thrown. rhPctmust be within[0, 100]percent or aRangeErroris thrown. The library throws rather than clamps — a caller who accidentally passes a0..1fraction (or a percentage over 100) finds out immediately. The test suite covers this behaviour.
Honest limits
- These are standard engineering approximations, not a full equation-of-state psychrometric solver. For most HVAC/weather/agriculture work they are well within measurement noise; for research-grade work near the edges of the stated ranges, use a dedicated reference implementation.
- Saturation is computed over liquid water; sub-freezing frost-point work needs an over-ice variant.
heatIndexandwetBulbare empirical regressions valid in the ranges noted above; outside them they degrade gracefully but are not authoritative.
License
MIT.
Install
npm install @verifyhash/psychrometricsconst psy = require('@verifyhash/psychrometrics');
psy.dewPoint(30, 50); // 18.45 (°C)
psy.heatIndex(32, 70); // 40.4 (°C, "feels like")
psy.wetBulb(20, 50); // 13.70 (°C)