CoolProp 8.0.0
An open-source fluid property and humid air property database
state_capi.h
Go to the documentation of this file.
1#ifndef COOLPROP_DETAIL_STATE_CAPI_H
2#define COOLPROP_DETAIL_STATE_CAPI_H
3
4// C-ABI bridge for the frozen Cython `State` compat shim (the PDSim cimport
5// surface). A non-Cython core (here, the nanobind module) exports a pointer to
6// this table as the `CoolProp._capi` PyCapsule; the thin `State` Cython shim
7// grabs it at import and forwards every call through it -- so PDSim keeps
8// cimporting `State` while the Cython AbstractState wrapper goes away.
9//
10// extern "C": only long/double/void* cross the boundary -- no C++ name
11// mangling or std layout leaks, so the table is a stable ABI. The opaque
12// handle carries a `std::shared_ptr<AbstractState>` directly (no long-handle
13// registry lookup). See dev/state_capsule/ for the shim + contract harness.
14//
15// Why this indirection (measured, not assumed): the consuming shim is ~200 KB
16// and contains NO CoolProp C++ -- it forwards to the single copy compiled into
17// the core, so the wheel is not doubled. A `State` that wrapped the C++
18// AbstractState directly would be ~5 ns/read faster (~1-2% on PDSim's
19// read-heavy ODE loop) but would embed its own ~7 MB of CoolProp, ~doubling the
20// wheel. The capsule trades that ~2% for no duplication + link-free
21// decoupling; a consumer that can link CoolProp may instead wrap AbstractState
22// directly against this same C-ABI.
23
24#ifdef __cplusplus
25extern "C"
26{
27#endif
28
29 typedef struct // NOLINT(modernize-use-using) -- C-ABI table; typedef kept C-compatible
30 {
31 void* (*make)(const char* backend, const char* fluids);
32 void (*destroy)(void* handle);
33 void (*update)(void* handle, long input_pair, double value1, double value2);
34 double (*keyed_output)(void* handle, long key);
35 double (*first_partial_deriv)(void* handle, long Of, long Wrt, long Constant);
36 // CoolProp throws C++ exceptions; they cannot cross this extern "C" boundary.
37 // Each call above catches them and stashes the message; last_error() returns
38 // it (or NULL) so the Cython shim can re-raise a Python exception -- matching
39 // the legacy State's `except *` behaviour. Cleared on the next successful call.
40 const char* (*last_error)();
41 // Set the composition (mole fractions) of a mixture handle, so the shim's
42 // set_Fluid can honour bracketed strings like "R32[0.5]&R134a[0.5]".
43 // Appended after last_error to keep the existing field offsets stable.
44 void (*set_mole_fractions)(void* handle, const double* fractions, long n);
45 // Impose a phase (a `phases` enum value) on the handle, so the shim's
46 // ``State(..., phase=...)`` can force the gas/liquid root like legacy.
47 void (*specify_phase)(void* handle, long phase);
48 // Lift a previously-imposed phase so the backend resumes auto-detecting it.
49 // (specify_phase(iphase_not_imposed) is NOT a substitute: it also clobbers
50 // the cached _phase, breaking lazy property evaluation.) copy() uses this
51 // to reproduce a mixture state under an imposed phase, then restore
52 // auto-detect on the returned handle. Appended last to keep field offsets
53 // stable.
54 void (*unspecify_phase)(void* handle);
56
57#ifdef __cplusplus
58}
59#endif
60
61#endif // COOLPROP_DETAIL_STATE_CAPI_H