Files
CoolProp/src
Ian Bell 09a265c907 perf(humid_air): cache virial/alpha0 coefficients to eliminate redundant EOS calls (26× speedup) (#2716)
* perf(humid_air): cache virial coefficients per temperature to eliminate redundant EOS calls

Adds `calc_all_virials()` to `HelmholtzEOSMixtureBackend` which computes B,
dB/dT, C, dC/dT in a single `residual_helmholtz->all()` call instead of four
separate `keyed_output()` calls (each of which invoked `all()` independently).

Adds a T-keyed static cache in `HumidAirProp.cpp` so that Air and Water virials
are computed once per unique temperature across all callers in the same
HAPropsSI evaluation. This eliminates ~12 redundant full EOS evaluations per
T+W→H call (6 Air + 6 Water: B_m and C_m each called twice across
MolarVolume+MolarEnthalpy, plus dB_m_dT and dC_m_dT).

Benchmark results on Apple M-series (ns/call, warm cache):
  T+W→H:    23 µs → 5.2 µs (4.5×)
  T+R→H:    32 µs → 7.6 µs (4.0×)
  T+Twb→W:  3.8 ms → 0.9 ms (4.2×)
  T+V→W:    33 µs → 1.6 µs (21× — dominated by cache warmth)

Adds [virial_cache] Catch2 tests verifying calc_all_virials() matches the
original keyed_output() path for Air and Water across 10 temperatures, and
that the HAPropsSI cache invalidates correctly across temperature changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* perf(humid_air): eliminate all update() calls from ideal-gas enthalpy/entropy functions

Adds two new per-temperature caches to HumidAirProp and two direct EOS methods
to HelmholtzEOSMixtureBackend, removing every backend update() call from the hot
path of HAPropsSI property evaluations.

Changes
-------
HelmholtzEOSMixtureBackend::calc_all_virials (previous commit):
  Single residual_helmholtz->all() call yields B, dB/dT, C, dC/dT at once.

HelmholtzEOSMixtureBackend::calc_alpha0_and_dTau (new):
  Single alpha0.all() call yields f(tau) and dalpha0/dtau at delta=1 without
  any update() call. Pure/pseudopure path (Air, Water) uses tau directly since
  Tc = Tr for these fluids; mixture fallback uses calc_alpha0_deriv_nocache.

HumidAirProp — two independent T-keyed caches:
  s_virial_cache: B, dB/dT, C, dC/dT for Air and Water (filled only when
    FlagUseVirialCorrelations=0, matching the original access pattern).
  s_alpha0_cache: f(tau) and dalpha0/dtau for Air and Water (always filled;
    separated from virial cache so virial EOS calls are not triggered when
    FlagUseVirialCorrelations=1).
  s_ref: one-time reference-state offsets (hoffset, soffset, T_red, rho_red,
    ln_delta_air) computed via update() with specify_phase(iphase_gas) guards.

IdealGasMolarEnthalpy_Water/Air and IdealGasMolarEntropy_Water/Air all rewritten
to use s_alpha0_cache + s_ref — zero update() calls on the hot path.

Benchmark (Apple M-series, warm cache):
  T+W→H:   23 µs → 5.2 µs (virial cache) → 0.88 µs (alpha0 cache)  26×
  T+R→H:   32 µs → 7.6 µs → 3.2 µs                                  10×
  T+R→S:   N/A   →  N/A   → 3.4 µs

Tests
-----
Adds [virial_cache] and [alpha0_cache] Catch2 test cases that verify the new
direct-EOS methods are bit-identical to the original update()+keyed_output()
paths for Air and Water across 10 temperatures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(humid_air): move virial/alpha0 helpers out of HEMB class

Address reviewer comments on PR #2716:

- calc_all_virials and calc_alpha0_and_dTau are removed from
  HelmholtzEOSMixtureBackend.  They are evaluated at delta→0 and
  delta=1 respectively, assumptions that only make sense in the
  humid-air context, so they now live as static free functions in
  HumidAirProp.cpp with clearer names and explicit doc comments
  explaining the delta choice.
- fill_virial_cache and fill_alpha0_cache updated to call the new
  static helpers (calc_all_virials, calc_ideal_gas_alpha0).
- Tests that previously called the class methods directly are replaced
  with end-to-end HAPropsSI checks that exercise the same code paths
  through the public API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(humid_air): three test failures from alpha0 refactor

- CMakeLists: use local _MY_MAIN_SOURCES so COOLPROP_MY_MAIN doesn't
  pollute APP_SOURCES and override Catch2's main in CatchTestRunner
- HumidAirProp: calc_ideal_gas_alpha0 incorrectly rejected Air
  (pseudo_pure=true); guard now only blocks true multi-component fluids
- CoolProp-Tests: fix Z tolerance (1e-3 → margin 2e-3); fix h-s
  round-trip to use (H,W=0)→T instead of unsupported (H,S)→T

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 11:50:37 -04:00
..
2023-09-18 21:03:52 -04:00
2016-02-21 22:00:48 -07:00