Skip to content

Compatibility with CoolProp v8 (nanobind) + numpy 2.x #104

@ibell

Description

@ibell

Summary

CoolProp v8.0.0 (a nanobind-based rewrite of the Python interface, abi3 wheels, link-free State shim) is heading to a beta. I tested PDSim against the v8 wheel and the good news first:

PDSim builds and runs full simulations on CoolProp v8 with zero source changes. It compiles cleanly against v8's frozen cimport surface (CoolProp.State / CoolProp.constants_header), and complete quasi-steady-state cycles converge with correct physics:

Example Result on v8
examples/recip_compressor.py mdot 8.139 g/s, vol-eff 65.2%, adiabatic-eff 90.7%
examples/simple_example.py mdot 0.504 g/s, vol-eff 88.7%, adiabatic-eff 100.6%

CoolProp.State (the v8 capsule shim) drives the entire ODE inner loop. So the CoolProp coupling itself is fine. The only blockers were on the PDSim side:

1. The coolprop==7.1.0 pin blocks v8

pyproject.toml pins coolprop==7.1.0 in both [build-system].requires and [project].dependencies. That means:

  • pip install pdsim will downgrade a user already on v8, and
  • building PDSim resolves CoolProp 7.1.0 under build isolation regardless of what's installed.

To test v8 I had to build --no-build-isolation and force-reinstall v8 afterward.

Suggested fix: loosen the pin to a range that admits v8, e.g. coolprop>=7.1 (or coolprop>=8.0.0b1 to opt into the beta with pip install --pre). v8's cimport surface (State.pxd, constants_header.pxd) and get_include_directory() are all present, so the build needs no other change.

2. numpy 2.x incompatibilities (independent of CoolProp)

PDSim uses several numpy-1 APIs removed in numpy 2.0, which break the examples on a modern numpy:

  • np.trapz — removed in numpy 2.0 (renamed np.trapezoid). Hit in PDSim/core/core.py _postprocess_flows (~L415: np.trapz(mdot, self.t[0:self.Ntheta])). Breaks recip_compressor.py in post-processing.
  • size-1 array → Python scalar — numpy 2 no longer auto-converts a 1-element array to a scalar. Assigning to a cdef double geoVals attribute raises TypeError: only 0-dimensional arrays can be converted to Python scalars. Hit in PDSim/scroll/common_scroll_geo.pxd (geoVals setter, e.g. xa_arc2.__set__) via symm_scroll_geo.setDiscGeo. This kills scroll_compressor.py in geometry setup, before CoolProp is involved.

Suggested fix: np.trapznp.trapezoid (with a fallback shim for numpy<2 if you still support it), and ensure scalars (float(x) / x.item()) are passed into the cdef double geoVals setters. (As a stopgap, pinning numpy<2 also works.)

Why this matters now

CoolProp v8 is recruiting beta testers, and PDSim is the flagship downstream consumer. With the pin loosened and the numpy-2 fixes in, testers could pip install --pre both and run these examples directly. Happy to send PRs for either fix.

(Tested 2026-06-09 against a local CoolProp v8 nanobind wheel; PDSim @ main 2.15.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions