CMake does not have a LIST cache type; it was silently coercing to STRING
and emitting a warning on every configure. Fixes the longstanding CMake
warning reported in PR #2728.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The vendored file was fetched from CPM master rather than the v0.40.7
release tag, causing a CMake warning about an unstable development
version on every configure.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* 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>
* build: replace git submodules with CPM.cmake
All 11 submodules (Eigen, fmtlib, msgpack-c, rapidjson, IF97,
REFPROP-headers, multicomplex, Catch2, pybind11, ExcelAddinInstaller,
FindMathematica) are now fetched by CPM.cmake at configure time.
Set CPM_SOURCE_CACHE (e.g. ~/.cache/CPM) to share the download cache
across git worktrees and build directories — no more per-worktree
`git submodule update --init --recursive`.
Vendored deps that have no upstream release cycle (miniz, nlohmann-json,
incbin) remain in externals/ as before.
Source-level changes: angle-bracket includes for rapidjson, IF97, and
REFPROP-headers now that their directories are on the include path via
CPM-provided source dirs rather than relative paths from the repo root.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(python): wire up CPM.cmake in Python wrapper, fix include paths
The Python wrapper CMakeLists.txt was still referencing submodule paths
(externals/Eigen, externals/fmtlib, externals/msgpack-c) removed by the
CPM migration. Include CPM.cmake + dependencies.cmake from the root and
use the ${Pkg_SOURCE_DIR} variables instead. Also adds missing
rapidjson, IF97, and REFPROP_headers include dirs required by CoolProp
sources.
CI workflows drop the now-meaningless `submodules: recursive` checkout
option and add a CPM source-cache step to avoid re-downloading on each
macOS/Windows runner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: remove git submodule references after CPM.cmake migration
Dependencies are now managed by CPM.cmake (fetched automatically at
CMake configure time), so git submodules no longer exist.
- Drop `--recursive` from all `git clone` commands in Web docs and
wrapper READMEs (26 .rst/.md files)
- Remove `submodules: recursive` from all CI workflow checkout steps
(13 workflow files)
- Remove `git submodule foreach/update` calls from release.bsh and
delete the now-dead pybind11 security-workaround lines
- Drop `--recursive` from build_swigged_matlab.sh and gitMirror.bsh
- Update CONTRIBUTING.md: drop "and its submodules" phrasing
Changelog entries referencing old submodule PRs are left intact as
historical records. The --recursive in buildbot.rst is for the
Dockerfiles repo (unrelated) and is also left unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): remove empty 'with:' blocks after submodule removal, apply clang-format
After removing 'submodules: recursive' from checkout steps, some workflow
files were left with dangling empty 'with:' blocks that GitHub Actions
rejects as workflow file errors. Remove the empty 'with:' in 9 workflows.
Also apply clang-format to fix spacing in REFPROPMixtureBackend.cpp,
HumidAirProp.cpp, and Helmholtz.cpp.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add Chlorine (Cl2) fundamental equation of state
Implements the EOS from Thol, Herrig, Span, Lemmon (AIChE J. 67, e17326,
2021, DOI: 10.1002/aic.17326) for chlorine (CAS 7782-50-5).
- 10-term polynomial/exponential residual + 5-term Gaussian bell-shaped
- Ideal gas: diatomic (2.5) + 3 Planck-Einstein terms (800/3000/8200 K)
- NBP reference state (h=0, s=0 at saturated liquid, 101325 Pa)
- Saturation ancillaries: pS, rhoL, rhoV from REFPROP coefficients
- Valid range: 172.17 K to 525 K, up to 20 MPa
- Adds BibTeX entry Thol-AICHE-2021
Closes#2714
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add superancillary equations to Chlorine EOS
Builds Chebyshev superancillary for Cl2 covering the full saturation
curve from Ttriple (172.17 K) to near-critical (416.865 K, 61
intervals). Errors away from the critical region are at machine-
precision level (~1e-13 %).
The fastchebpure builder was also patched to prune near-critical
intervals where the pressure Chebyshev expansion becomes non-monotone
due to ill-conditioned VLE convergence at very small Theta; 3 such
intervals were removed for Chlorine (Theta ~ 2.3e-7).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Bump fastchebpure release to 2026.04.16 to fix docs CI failures
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces urllib with requests + HTTPAdapter/Retry to get automatic
retries (up to 3) with exponential backoff on 429/5xx and network
errors; 404 is treated as a definitive miss and skips to 2D without
retrying.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Try loading REFPROP backend and only warn on failure
* Skip REFPROP related tests when not available using a single helper routine in CoolProp:: namespace
* docs: add predefined mixtures table to Mixtures documentation
Adds a new section "Predefined mixtures" to Web/fluid_properties/Mixtures.rst
listing all 154 predefined mixtures with their components and mole fractions.
Each mixture is tested at build time; those that fail (missing binary interaction
parameters or not present in the compiled library) are flagged in a Notes column.
Also updates the code examples in the new section to use the required .mix suffix,
and registers the generation script in the doc build task list.
Closes#2711
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: improve predefined mixtures table error messages and auto-count
- Replace CAS numbers with fluid names in binary interaction parameter errors
- Detect and report missing pure fluids by name
- Distinguish 'not registered as predefined mixture' from missing BIP
- Write PredefinedMixturesCount.rst so the mixture count in Mixtures.rst
is generated automatically rather than hardcoded
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix superancillary performance: store as shared_ptr instead of optional
Every call to AbstractState::factory("HEOS", fluid) was deep-copying the
SuperAncillary_t object (multiple large Chebyshev coefficient vectors) as
part of the CoolPropFluid value copy from the fluid library. Since the
superancillary is immutable once built, switch storage from
std::optional<SuperAncillary_t> to std::shared_ptr<SuperAncillary_t>.
All copies of CoolPropFluid for the same fluid now share a single
SuperAncillary_t in memory; copying the shared_ptr is O(1) (atomic
ref-count increment only).
Also fix a latent bug in get_fluid_parameter_double where optsuperanc.value()
was called before the if(optsuperanc) guard (would have crashed on fluids
without superancillaries when SUPERANC:: parameters were queried).
Changes:
- CoolPropFluid.h: storage type optional -> shared_ptr; rename internal
accessor get_superanc_optional -> get_superanc
- HelmholtzEOSMixtureBackend.h: update declaration (return shared_ptr)
- HelmholtzEOSMixtureBackend.cpp: update impl + 6 call sites (.value() -> *)
- FlashRoutines.cpp: update 4 call sites (.value() -> *)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* PR review fixes: rename get_superanc, simplify melting line logic, test cleanup
- Rename HelmholtzEOSMixtureBackend::get_superanc_optional() to get_superanc()
to match EquationOfState::get_superanc() and reflect the shared_ptr return type
- Remove redundant `if (other == iT &&` guard inside case iT: (always true)
- Simplify melting line if/else in subcritical superanc branch: collapse redundant
has_melting_line()/else branches into a single _phase assignment
- Fix get_fluid_parameter_double: note that .value() before null check was a
pre-existing bug that the optional->shared_ptr migration implicitly fixed
- Use std::shared_ptr in [2639] test case for consistency
- Add comment explaining [2608] CO2 temperature change (218.048->218.050)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(docs): add interactive 3D molecule viewers to fluid pages
Use py3Dmol + PubChem SDF data to embed a rotate-and-drag 3D (or 2D
fallback) molecule viewer on each pure fluid documentation page.
- fetch_pubchem_sdf(): downloads 3D conformer SDF from PubChem REST API
(falls back to 2D), caching results in molecule_sdf/ to avoid repeated
network calls on doc rebuilds
- generate_3dmol_rst(): inlines the SDF as a JS template literal inside a
.. raw:: html block — no extra static files needed at Sphinx build time
- FluidGenerator.write(): validates InChIKey with regex before fetching;
pseudo-pure fluids (Air, R404A, etc.) without InChIKeys are silently skipped
- conf.py: loads 3Dmol.js from CDN via html_js_files
- .gitignore: excludes the generated molecule_sdf/ cache directory
Restores molecule visualisation that was removed in April 2025 (the old
approach tried to embed an image directive inside a CSV table, which is
invalid RST; this implementation places the viewer in the RST template).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docs): serve 3Dmol.js locally to eliminate CORS errors
Download 3Dmol-min.js to _static/ at Sphinx build time (same pattern
as MathJax) instead of loading it from the CDN via html_js_files.
Serving the script same-origin removes the cross-origin restriction
that caused CORS errors when docs were opened from file:// or a local
dev server.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docs): correct 3Dmol viewer positioning and initialization timing
3Dmol.js sets its canvas to position:absolute;top:0;left:0 and only
auto-sets the container to position:relative when the container's
inline style.position === "static". An unstyled div has style.position
=== "" so the check fails, and the canvas escapes the container and
anchors to the nearest positioned ancestor in the Sphinx page layout.
Fix: add position:relative explicitly to the viewer container div.
Also defer viewer init via DOMContentLoaded so layout is finalized
before createViewer reads the container dimensions, and call v.resize()
before v.render() to sync the WebGL canvas to the container size.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docs): disable MathJax SRE to prevent CORS errors on file:// URLs
MathJax 4.0's Speech Rule Engine fetches sre/mathmaps/base.json at
runtime via fetch(). Chrome blocks this when docs are opened from a
local file:// URL (null origin). Disabling enableExplorer and
enableAssistiveMml prevents SRE from initialising entirely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docs): load 3Dmol before require.js to fix AMD conflict
sphinx.ext.mathjax injects require.js at priority 500. When 3Dmol
loads after it, AMD detection fires and calls define([], factory)
instead of setting window.$3Dmol directly. Since nothing ever calls
require(['3Dmol-min']), the factory never runs and the viewer silently
fails (infinite setTimeout retry, no console errors).
Setting priority 450 ensures 3Dmol loads before require.js.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docs): add retry logic to downloads in conf.py using requests
Replace urllib.request.urlretrieve with a requests-based _download()
helper that retries up to 5 times (exponential backoff, factor=2) on
transient HTTP errors and timeouts. Fixes CI build failures when
the MathJax or 3Dmol.js downloads time out.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers ASHRAE RP-1485 scenarios from HAValidation.py as C++ Catch2
tests so they run in CI instead of only during Python doc builds:
- [ashrae_a61]: saturated air T=-60..0°C (ice regime, R=1)
- [ashrae_a62]: saturated air T=0..90°C (liquid regime, R=1)
- [ashrae_a8/a9]: hot humid air T=200/320°C across multiple pressures
- [humid_air_physics]: T_dp <= T_wb <= T_db ordering, W/R invariants
- [humid_air_roundtrip]: W, H, T_dp, T_wb round-trips
- [humid_air_aux]: f_factor, p_ws, beta_H, kT, vbar_ws, virial checks
Also documents two current behaviors as known baselines:
- W_sat > 1 kg/kg is physically correct above ~60 degC (not a bug)
- beta_H returns inf below 273.16 K (no liquid water)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(deps): update miniz from 3.0.2 to 3.1.1
Adds the miniz-3.1.1 source directory and updates all CMakeLists.txt
references. Notable fixes in 3.1.0/3.1.1: integer promotion warnings,
tinfl_decompress bug that broke mem-to-heap decompression, MinGW Unicode
path support, and inline static wrappers to silence warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(deps): remove old miniz-3.0.2 source tree
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Three fixes to src/HumidAirProp.cpp:
1. WetbulbTemperature inner Brent upper bound: changed Brent(WBS, Tmax+1, 100)
to Brent(WBS, Tmax, 100). The old Tmax+1 evaluated WBS at T_sat(P) where
P_s == P, causing division-by-zero (W_s_wb infinite) and an exception that
cascaded into the outer solver returning _HUGE for certain pressures.
2. _HAPropsSI_inputs T_max extension for T_wb / enthalpy secondary inputs: when
MainInput is RelHum (>= 1e-10) and the secondary input is T_wb or enthalpy,
use T_max = 640 K instead of T_sat(P) - 1. For very dry air at sub-atmospheric
pressures the solution T_db can legitimately exceed T_sat(P); WetbulbTemperature
already handles T_db > T_sat correctly via its fallback solver.
3. Replace CoolProp::PropsSI("T","P",p,"Q",0,"Water") with the already-instantiated
Water singleton (Water->update(PQ_INPUTS,...); T_max = Water->T() - 1), consistent
with the rest of HumidAirProp.cpp.
Also added a Catch regression test [humid_air][2690] covering 10 pressures
(including the previously-failing 90190–91160 Pa band) with round-trip
verification to < 1e-6 K.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Remove unused heavy headers to improve compile times
- Exceptions.h: replace unused <iostream> with <string> (needed for std::string)
- CPnumerics.h: add explicit <iostream> (was relying on transitive include via Exceptions.h for std::cerr)
- superancillary/superancillary.h: replace <iostream> with <cstdio>; use fprintf for debug output
- TabularBackends.h: remove unused <sstream>
<iostream> is one of the heaviest stdlib headers; removing it from widely-included
headers (Exceptions.h: ~32 dependents, superancillary.h: pulled in by AbstractState.h,
CoolPropFluid.h, Configuration.h) reduces cold build times.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add missing <iostream> to ODEIntegrators.cpp
ODEIntegrators.cpp uses std::cout but was relying on transitive inclusion
via Exceptions.h. After removing <iostream> from Exceptions.h, this broke
compilation. Add the include directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* make _binary arrays constexpr and use string_view instead of string
By making _binary arrays constexpr and using string_view instead of string, startup speed of the library is improved.
* fixed interfaces for string_view
added /bigobj /MP to MSVC CXX-flags
* empty commit to trigger CI
* empty commit to force CI build
---------
Co-authored-by: Löw, Tobias <Tobias.Loew@iqony.energy>
GitHub does not pass repository secrets to workflows triggered by PRs
from forks, causing the gpg decrypt step to fail. Add a condition so
the Build REFPROP step is skipped for fork PRs; the rest of the build
and non-REFPROP tests still run.
Fixes#2694
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Only the REFPROP checks not passing because of permissions but ran fine locally. All regression testing passed and limited to the single Mathcad wrapper file.
Both combinations uniquely determine dry-bulb temperature: T_dp and W
each fix psi_w independently of T, while relative humidity R provides
the T-dependent equation R = psi_w*P / (f(T,P)*p_ws(T)) to solve.
Changes:
- Reorder priority chain to prefer T_dp over R as main key when both
are present (T_dp gives psi_w directly, yielding correct T_min bound)
- Relax the two-water-content guard to allow T_dp+R and W+R combinations
while still rejecting W+T_dp (both fix psi_w; T remains unconstrained)
- Add Catch2 test covering all three cases, including the W+T_dp invalid
case which correctly returns _HUGE
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Use ninja for the examples
Should help a little bit with doc building
* FIx some templates
* Fix template deduction error in count_x_for_y_many functions
The count_x_for_y_many and count_x_for_y_manyC functions were using
a single template parameter for both input (double) and output (size_t)
arrays, causing template deduction failures in Cython bindings.
Changed to use separate template parameters YContainer and CountContainer
to properly support different types for input y values and output counts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix types in PXD header too
* Docs should get ninja too
* Changes from clang-format
* Fix git diff argument order in clang-format script
The script was comparing PR_BRANCH to TARGET_BRANCH, which shows changes from the PR branch to the target (what's in target that's NOT in PR). For PR validation, we need the opposite: changes from target to PR (what's in PR that's NOT in target).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix Cython template deduction errors in solve_for_x_manyC and count_x_for_y_manyC
Add explicit template parameters [double, size_t] to both function calls
to resolve template type deduction errors when compiling with Cython.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix wheel building by removing return from void Cython template calls
The functions solve_for_x_manyC and count_x_for_y_manyC return void in C++.
When Cython sees a return statement with a void function call containing
template arguments with commas (e.g., [double, size_t]), it wraps the call
in the __Pyx_void_to_None macro. This macro is a simple preprocessor macro
that cannot handle the commas in template arguments, treating them as macro
argument separators instead.
The fix is to remove the return statements, making these simple void function
calls. This prevents the __Pyx_void_to_None wrapping and allows the wheel to
build successfully.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix header gen on windows
* Add missing dependencies for constants generation
The generate_constants_target was defined but nothing depended on it,
so CMake never invoked the constants generation script on Windows.
Changes:
- CoolProp_module now depends on generate_constants_target (not just
generate_headers_target)
- CoolProp.pyx Cythonization now depends on constants_header.pxd and
generate_constants_target (since CoolProp.pyx imports constants_header)
This ensures the constants generation script runs before building,
creating the required files:
- constants_header.pxd
- _constants.pyx
- constants.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>