13# include <nanobind/nanobind.h>
14# include <nanobind/stl/string.h>
15# include <nanobind/stl/string_view.h>
16# include <nanobind/stl/vector.h>
17# include <nanobind/stl/tuple.h>
18# include <nanobind/stl/pair.h>
19# include <nanobind/stl/map.h>
20# include <nanobind/ndarray.h>
23namespace nb = nanobind;
31static std::vector<std::string> _split_str(
const std::string& s,
char delim) {
32 std::vector<std::string> out;
45 if (!cur.empty() || !s.empty()) {
59static std::vector<double> _to_vec(nb::handle o,
bool& is_seq) {
60 if (nb::hasattr(o,
"ndim")) {
61 long ndim = nb::cast<long>(nb::getattr(o,
"ndim"));
64 PyErr_SetString(PyExc_ValueError,
"vectorized PropsSI/HAPropsSI input is not one-dimensional");
65 throw nb::python_error();
69 return {nb::cast<double>(nb::float_(o))};
72 return nb::cast<std::vector<double>>(o);
74 if (nb::isinstance<nb::list>(o) || nb::isinstance<nb::tuple>(o)) {
76 return nb::cast<std::vector<double>>(o);
81 return {nb::cast<double>(nb::float_(o))};
91static std::vector<std::string> _to_str_vec(nb::handle o) {
92 if (nb::isinstance<nb::str>(o)) {
93 return {nb::cast<std::string>(o)};
97 std::vector<std::string> out;
98 for (nb::handle item : o) {
99 out.push_back(nb::cast<std::string>(item));
104static void _raise_if_invalid(
double x) {
109 throw nb::python_error();
114static void _broadcast_to(std::vector<double>& v, std::size_t n,
const char* which) {
124 PyErr_SetString(PyExc_TypeError, (std::string(
"vectorized input ") + which +
" has an incompatible length").c_str());
125 throw nb::python_error();
131using _CAPI_SP = std::shared_ptr<CoolProp::AbstractState>;
132thread_local std::string g_capi_error;
137void capi_set_error(
const char* msg)
noexcept {
139 g_capi_error = (msg !=
nullptr) ? msg :
"unknown C++ exception";
141 g_capi_error.clear();
144void* capi_make(
const char* backend,
const char* fluids) {
147 g_capi_error.clear();
149 }
catch (
const std::exception& e) {
150 capi_set_error(e.what());
153 capi_set_error(
nullptr);
157void capi_destroy(
void* h) {
159 delete static_cast<_CAPI_SP*
>(h);
163void capi_update(
void* h,
long input_pair,
double v1,
double v2) {
165 capi_set_error(
"update: null handle");
170 g_capi_error.clear();
171 }
catch (
const std::exception& e) {
172 capi_set_error(e.what());
174 capi_set_error(
nullptr);
177double capi_keyed_output(
void* h,
long key) {
179 capi_set_error(
"keyed_output: null handle");
184 g_capi_error.clear();
186 }
catch (
const std::exception& e) {
187 capi_set_error(e.what());
190 capi_set_error(
nullptr);
194double capi_first_partial_deriv(
void* h,
long Of,
long Wrt,
long Constant) {
196 capi_set_error(
"first_partial_deriv: null handle");
200 double v = (*
static_cast<_CAPI_SP*
>(h))
203 g_capi_error.clear();
205 }
catch (
const std::exception& e) {
206 capi_set_error(e.what());
209 capi_set_error(
nullptr);
213const char* capi_last_error() {
214 return g_capi_error.empty() ? nullptr : g_capi_error.c_str();
216void capi_set_mole_fractions(
void* h,
const double* z,
long n) {
220 capi_set_error(
"set_mole_fractions: null handle");
224 capi_set_error(
"set_mole_fractions: negative length");
227 if (n > 0 && z ==
nullptr) {
228 capi_set_error(
"set_mole_fractions: null fractions pointer");
232 std::vector<double> fractions(z, z + n);
233 (*
static_cast<_CAPI_SP*
>(h))->set_mole_fractions(fractions);
234 g_capi_error.clear();
235 }
catch (
const std::exception& e) {
236 capi_set_error(e.what());
238 capi_set_error(
nullptr);
241void capi_specify_phase(
void* h,
long phase) {
243 capi_set_error(
"specify_phase: null handle");
247 (*
static_cast<_CAPI_SP*
>(h))->specify_phase(
static_cast<CoolProp::phases>(phase));
248 g_capi_error.clear();
249 }
catch (
const std::exception& e) {
250 capi_set_error(e.what());
252 capi_set_error(
nullptr);
255void capi_unspecify_phase(
void* h) {
257 capi_set_error(
"unspecify_phase: null handle");
261 (*
static_cast<_CAPI_SP*
>(h))->unspecify_phase();
262 g_capi_error.clear();
263 }
catch (
const std::exception& e) {
264 capi_set_error(e.what());
266 capi_set_error(
nullptr);
270 capi_make, capi_destroy, capi_update, capi_keyed_output, capi_first_partial_deriv, capi_last_error, capi_set_mole_fractions,
271 capi_specify_phase, capi_unspecify_phase};
279static void init_superancillary(nb::module_& m) {
281 using SAArray = std::vector<double>;
282 using ChebExp = sa::ChebyshevExpansion<SAArray>;
283 using ChebApprox1D = sa::ChebyshevApproximation1D<SAArray>;
284 using SuperAnc = sa::SuperAncillary<SAArray>;
285 using ArrD = nb::ndarray<double, nb::ndim<1>, nb::c_contig>;
286 using ArrSz = nb::ndarray<std::size_t, nb::ndim<1>, nb::c_contig>;
289 nb::class_<sa::MonotonicExpansionMatch>(m,
"MonotonicExpansionMatch")
290 .def_ro(
"idx", &sa::MonotonicExpansionMatch::idx)
291 .def_ro(
"ymin", &sa::MonotonicExpansionMatch::ymin)
292 .def_ro(
"ymax", &sa::MonotonicExpansionMatch::ymax)
293 .def_ro(
"xmin", &sa::MonotonicExpansionMatch::xmin)
294 .def_ro(
"xmax", &sa::MonotonicExpansionMatch::xmax);
296 nb::class_<sa::IntervalMatch>(m,
"IntervalMatch")
297 .def_ro(
"expansioninfo", &sa::IntervalMatch::expansioninfo)
298 .def_ro(
"xmin", &sa::IntervalMatch::xmin)
299 .def_ro(
"xmax", &sa::IntervalMatch::xmax)
300 .def_ro(
"ymin", &sa::IntervalMatch::ymin)
301 .def_ro(
"ymax", &sa::IntervalMatch::ymax);
303 nb::class_<ChebExp>(m,
"ChebyshevExpansion")
304 .def(nb::init<double, double, SAArray>(), nb::arg(
"xmin"), nb::arg(
"xmax"), nb::arg(
"coef"))
305 .def(
"xmin", &ChebExp::xmin)
306 .def(
"xmax", &ChebExp::xmax)
307 .def(
"coeff", [](
const ChebExp& e) {
return e.coeff(); })
310 [](
const ChebExp& e, ArrD x, ArrD y) {
311 if (x.shape(0) != y.shape(0)) {
312 throw nb::value_error(
"x and y are not the same size");
314 e.eval_manyC<
double>(x.data(), y.data(), x.shape(0));
316 nb::arg(
"x"), nb::arg(
"y"))
317 .def(
"solve_for_x", &ChebExp::solve_for_x, nb::arg(
"y"), nb::arg(
"a"), nb::arg(
"b"), nb::arg(
"bits"), nb::arg(
"max_iter"),
318 nb::arg(
"boundstytol"))
321 [](
const ChebExp& e, ArrD y,
double a,
double b,
unsigned int bits, std::size_t max_iter,
double boundstytol, ArrD x, ArrSz counts) {
322 if (y.shape(0) != x.shape(0) || y.shape(0) != counts.shape(0)) {
323 throw nb::value_error(
"y, x and counts are not the same size");
325 e.solve_for_x_manyC<double, std::size_t>(y.data(), y.shape(0), a, b, bits, max_iter, boundstytol, x.data(), counts.data());
327 nb::arg(
"y"), nb::arg(
"a"), nb::arg(
"b"), nb::arg(
"bits"), nb::arg(
"max_iter"), nb::arg(
"boundstytol"), nb::arg(
"x"), nb::arg(
"counts"));
329 nb::class_<ChebApprox1D>(m,
"ChebyshevApproximation1D")
333 .def(nb::init<std::vector<ChebExp>>(), nb::arg(
"expansions"))
334 .def(
"xmin", &ChebApprox1D::xmin)
335 .def(
"xmax", &ChebApprox1D::xmax)
336 .def(
"is_monotonic", &ChebApprox1D::is_monotonic)
339 [](
const ChebApprox1D& a, ArrD x, ArrD y) {
340 if (x.shape(0) != y.shape(0)) {
341 throw nb::value_error(
"x and y are not the same size");
343 a.eval_manyC<
double>(x.data(), y.data(), x.shape(0));
345 nb::arg(
"x"), nb::arg(
"y"))
346 .def(
"get_x_for_y", &ChebApprox1D::get_x_for_y, nb::arg(
"y"), nb::arg(
"bits"), nb::arg(
"max_iter"), nb::arg(
"boundstytol"))
348 "count_x_for_y_many",
349 [](
const ChebApprox1D& a, ArrD y,
unsigned int bits, std::size_t max_iter,
double boundstytol, ArrSz counts) {
350 if (y.shape(0) != counts.shape(0)) {
351 throw nb::value_error(
"y and counts are not the same size");
353 a.count_x_for_y_manyC<double, std::size_t>(y.data(), y.shape(0), bits, max_iter, boundstytol, counts.data());
355 nb::arg(
"y"), nb::arg(
"bits"), nb::arg(
"max_iter"), nb::arg(
"boundstytol"), nb::arg(
"counts"))
356 .def(
"monotonic_intervals", [](
const ChebApprox1D& a) {
return a.get_monotonic_intervals(); });
358 nb::class_<SuperAnc>(m,
"SuperAncillary")
359 .def(nb::init<const std::string&>(), nb::arg(
"json_as_string"))
362 [](
const SuperAnc& s,
double T,
const std::string& prop,
short Q) {
364 throw nb::value_error(
"prop must be a non-empty string");
366 return s.eval_sat(
T, prop[0], Q);
368 nb::arg(
"T"), nb::arg(
"prop"), nb::arg(
"Q"))
371 [](
const SuperAnc& s, ArrD
T,
const std::string& prop,
short Q, ArrD y) {
373 throw nb::value_error(
"prop must be a non-empty string");
375 if (
T.shape(0) != y.shape(0)) {
376 throw nb::value_error(
"T and y are not the same size");
378 s.eval_sat_manyC<
double>(
T.data(),
T.shape(0), prop[0], Q, y.data());
380 nb::arg(
"T"), nb::arg(
"prop"), nb::arg(
"Q"), nb::arg(
"y"));
383void init_CoolProp(nb::module_& m) {
394 nb::register_exception_translator([](
const std::exception_ptr& p,
void* ) {
396 std::rethrow_exception(p);
398 PyErr_SetString(PyExc_ValueError, e.
what());
402 nb::class_<SimpleState>(m,
"SimpleState")
405 .def_rw(
"p", &SimpleState::p)
406 .def_rw(
"rhomolar", &SimpleState::rhomolar);
408 nb::class_<GuessesStructure>(m,
"GuessesStructure")
411 .def_rw(
"p", &GuessesStructure::p)
412 .def_rw(
"rhomolar", &GuessesStructure::rhomolar)
413 .def_rw(
"hmolar", &GuessesStructure::hmolar)
414 .def_rw(
"smolar", &GuessesStructure::smolar)
415 .def_rw(
"rhomolar_liq", &GuessesStructure::rhomolar_liq)
416 .def_rw(
"rhomolar_vap", &GuessesStructure::rhomolar_vap)
417 .def_rw(
"x", &GuessesStructure::x)
418 .def_rw(
"y", &GuessesStructure::y)
419 .def(
"clear", &GuessesStructure::clear);
421 nb::class_<CriticalState, SimpleState>(m,
"CriticalState").def(nb::init<>()).def_rw(
"stable", &CriticalState::stable);
423 nb::class_<PhaseEnvelopeData>(m,
"PhaseEnvelopeData")
425 .def_rw(
"K", &PhaseEnvelopeData::K)
426 .def_rw(
"lnK", &PhaseEnvelopeData::lnK)
427 .def_rw(
"x", &PhaseEnvelopeData::x)
428 .def_rw(
"y", &PhaseEnvelopeData::y)
430 .def_rw(
"p", &PhaseEnvelopeData::p)
431 .def_rw(
"lnT", &PhaseEnvelopeData::lnT)
432 .def_rw(
"lnp", &PhaseEnvelopeData::lnp)
433 .def_rw(
"rhomolar_liq", &PhaseEnvelopeData::rhomolar_liq)
434 .def_rw(
"rhomolar_vap", &PhaseEnvelopeData::rhomolar_vap)
435 .def_rw(
"lnrhomolar_liq", &PhaseEnvelopeData::lnrhomolar_liq)
436 .def_rw(
"lnrhomolar_vap", &PhaseEnvelopeData::lnrhomolar_vap)
437 .def_rw(
"hmolar_liq", &PhaseEnvelopeData::hmolar_liq)
438 .def_rw(
"hmolar_vap", &PhaseEnvelopeData::hmolar_vap)
439 .def_rw(
"smolar_liq", &PhaseEnvelopeData::smolar_liq)
440 .def_rw(
"smolar_vap", &PhaseEnvelopeData::smolar_vap)
441 .def_rw(
"Q", &PhaseEnvelopeData::Q)
442 .def_rw(
"cpmolar_liq", &PhaseEnvelopeData::cpmolar_liq)
443 .def_rw(
"cpmolar_vap", &PhaseEnvelopeData::cpmolar_vap)
444 .def_rw(
"cvmolar_liq", &PhaseEnvelopeData::cvmolar_liq)
445 .def_rw(
"cvmolar_vap", &PhaseEnvelopeData::cvmolar_vap)
446 .def_rw(
"viscosity_liq", &PhaseEnvelopeData::viscosity_liq)
447 .def_rw(
"viscosity_vap", &PhaseEnvelopeData::viscosity_vap)
448 .def_rw(
"conductivity_liq", &PhaseEnvelopeData::conductivity_liq)
449 .def_rw(
"conductivity_vap", &PhaseEnvelopeData::conductivity_vap)
450 .def_rw(
"speed_sound_vap", &PhaseEnvelopeData::speed_sound_vap);
453 nb::enum_<configuration_keys>(m,
"configuration_keys", nb::is_arithmetic())
454# define X(Enum, String, Default, Desc) .value(String, configuration_keys::Enum)
459 nb::enum_<parameters>(m,
"parameters", nb::is_arithmetic())
552 nb::enum_<input_pairs>(m,
"input_pairs", nb::is_arithmetic())
601 nb::enum_<phases>(m,
"phases", nb::is_arithmetic())
615 nb::enum_<fluid_types>(m,
"fluid_types", nb::is_arithmetic())
624 nb::enum_<fast_evaluate_status>(m,
"fast_evaluate_status", nb::is_arithmetic())
635 nb::class_<SpinodalData>(m,
"SpinodalData")
637 .def_ro(
"tau", &SpinodalData::tau)
638 .def_ro(
"delta", &SpinodalData::delta)
639 .def_ro(
"M1", &SpinodalData::M1);
646 m.attr(
"PyCriticalState") = m.attr(
"CriticalState");
647 m.attr(
"PyGuessesStructure") = m.attr(
"GuessesStructure");
648 m.attr(
"PyPhaseEnvelopeData") = m.attr(
"PhaseEnvelopeData");
649 m.attr(
"PySpinodalData") = m.attr(
"SpinodalData");
657 nb::class_<AbstractState>(m,
"AbstractState")
658 .def(nb::new_(&factory))
659 .def(
"set_T", &AbstractState::set_T)
660 .def(
"backend_name", &AbstractState::backend_name)
661 .def(
"using_mole_fractions", &AbstractState::using_mole_fractions)
662 .def(
"using_mass_fractions", &AbstractState::using_mass_fractions)
663 .def(
"using_volu_fractions", &AbstractState::using_volu_fractions)
664 .def(
"set_mole_fractions", &AbstractState::set_mole_fractions)
665 .def(
"set_mass_fractions", &AbstractState::set_mass_fractions)
666 .def(
"set_volu_fractions", &AbstractState::set_volu_fractions)
667 .def(
"mole_fractions_liquid", &AbstractState::mole_fractions_liquid)
668 .def(
"mole_fractions_liquid_double", &AbstractState::mole_fractions_liquid_double)
669 .def(
"mole_fractions_vapor", &AbstractState::mole_fractions_vapor)
670 .def(
"mole_fractions_vapor_double", &AbstractState::mole_fractions_vapor_double)
671 .def(
"get_mole_fractions", &AbstractState::get_mole_fractions)
672 .def(
"get_mass_fractions", &AbstractState::get_mass_fractions)
673 .def(
"update", &AbstractState::update)
674 .def(
"update_with_guesses", &AbstractState::update_with_guesses)
675 .def(
"available_in_high_level", &AbstractState::available_in_high_level)
676 .def(
"build_options_json", &AbstractState::build_options_json)
677 .def(
"fluid_param_string", &AbstractState::fluid_param_string)
678 .def(
"fluid_names", &AbstractState::fluid_names)
679 .def(
"set_binary_interaction_double", (
void(
AbstractState::*)(
const std::string&,
const std::string&,
const std::string&,
const double))
680 & AbstractState::set_binary_interaction_double)
681 .def(
"set_binary_interaction_double", (
void(
AbstractState::*)(
const std::size_t,
const std::size_t,
const std::string&,
const double))
682 & AbstractState::set_binary_interaction_double)
683 .def(
"set_binary_interaction_string", (
void(
AbstractState::*)(
const std::string&,
const std::string&,
const std::string&,
const std::string&))
684 & AbstractState::set_binary_interaction_string)
685 .def(
"set_binary_interaction_string", (
void(
AbstractState::*)(
const std::size_t,
const std::size_t,
const std::string&,
const std::string&))
686 & AbstractState::set_binary_interaction_string)
687 .def(
"get_binary_interaction_double",
688 (
double(
AbstractState::*)(
const std::string&,
const std::string&,
const std::string&)) & AbstractState::get_binary_interaction_double)
689 .def(
"get_binary_interaction_double",
690 (
double(
AbstractState::*)(
const std::size_t,
const std::size_t,
const std::string&)) & AbstractState::get_binary_interaction_double)
691 .def(
"get_binary_interaction_string", &AbstractState::get_binary_interaction_string)
693 .def(
"set_fluid_parameter_double", &AbstractState::set_fluid_parameter_double)
694 .def(
"clear", &AbstractState::clear)
695 .def(
"get_reducing_state", &AbstractState::get_reducing_state)
696 .def(
"get_state", &AbstractState::get_state)
697 .def(
"Tmin", &AbstractState::Tmin)
698 .def(
"Tmax", &AbstractState::Tmax)
699 .def(
"pmax", &AbstractState::pmax)
700 .def(
"Ttriple", &AbstractState::Ttriple)
701 .def(
"phase", &AbstractState::phase)
702 .def(
"specify_phase", &AbstractState::specify_phase)
703 .def(
"unspecify_phase", &AbstractState::unspecify_phase)
704 .def(
"T_critical", &AbstractState::T_critical)
705 .def(
"p_critical", &AbstractState::p_critical)
706 .def(
"rhomolar_critical", &AbstractState::rhomolar_critical)
707 .def(
"rhomass_critical", &AbstractState::rhomass_critical)
708 .def(
"all_critical_points", &AbstractState::all_critical_points)
709 .def(
"build_spinodal", &AbstractState::build_spinodal)
710 .def(
"get_spinodal_data", &AbstractState::get_spinodal_data)
711 .def(
"criticality_contour_values",
715 return nb::make_tuple(L, M);
717 .def(
"tangent_plane_distance", &AbstractState::tangent_plane_distance)
718 .def(
"T_reducing", &AbstractState::T_reducing)
719 .def(
"rhomolar_reducing", &AbstractState::rhomolar_reducing)
720 .def(
"rhomass_reducing", &AbstractState::rhomass_reducing)
721 .def(
"p_triple", &AbstractState::p_triple)
722 .def(
"name", &AbstractState::name)
723 .def(
"dipole_moment", &AbstractState::dipole_moment)
724 .def(
"keyed_output", &AbstractState::keyed_output)
725 .def(
"trivial_keyed_output", &AbstractState::trivial_keyed_output)
732 nb::ndarray<
const double, nb::ndim<1>, nb::c_contig> val2, nb::ndarray<
const int, nb::ndim<1>, nb::c_contig> outputs,
733 nb::ndarray<
double, nb::ndim<2>, nb::c_contig> out, nb::ndarray<
int, nb::ndim<1>, nb::c_contig> status,
phases imposed_phase) {
734 std::size_t N = val1.shape(0);
735 std::size_t M = outputs.shape(0);
736 if (val2.shape(0) != N) {
737 throw nb::value_error(
"val1 and val2 must have the same length");
739 if (out.shape(0) != N || out.shape(1) != M) {
740 throw nb::value_error(
"out must have shape (N_inputs, N_outputs)");
742 if (status.shape(0) != N) {
743 throw nb::value_error(
"status must have length N_inputs");
749 for (std::size_t k = 0; k < N; ++k) {
750 status.data()[k] = 0;
754 AS.
fast_evaluate(input_pair, val1.data(), val2.data(), N,
reinterpret_cast<const parameters*
>(outputs.data()), M, out.data(), N * M,
755 status.data(), N, imposed_phase);
757 nb::arg(
"input_pair"), nb::arg(
"val1"), nb::arg(
"val2"), nb::arg(
"outputs"), nb::arg(
"out"), nb::arg(
"status"),
759 .def(
"saturated_liquid_keyed_output", &AbstractState::saturated_liquid_keyed_output)
760 .def(
"saturated_vapor_keyed_output", &AbstractState::saturated_vapor_keyed_output)
762 .def(
"rhomolar", &AbstractState::rhomolar)
763 .def(
"rhomass", &AbstractState::rhomass)
764 .def(
"p", &AbstractState::p)
765 .def(
"Q", &AbstractState::Q)
766 .def(
"Qmass", &AbstractState::Qmass)
767 .def(
"tau", &AbstractState::tau)
768 .def(
"delta", &AbstractState::delta)
769 .def(
"molar_mass", &AbstractState::molar_mass)
770 .def(
"acentric_factor", &AbstractState::acentric_factor)
771 .def(
"gas_constant", &AbstractState::gas_constant)
772 .def(
"Bvirial", &AbstractState::Bvirial)
773 .def(
"dBvirial_dT", &AbstractState::dBvirial_dT)
774 .def(
"Cvirial", &AbstractState::Cvirial)
775 .def(
"dCvirial_dT", &AbstractState::dCvirial_dT)
776 .def(
"compressibility_factor", &AbstractState::compressibility_factor)
777 .def(
"hmolar", &AbstractState::hmolar)
778 .def(
"hmass", &AbstractState::hmass)
779 .def(
"hmolar_excess", &AbstractState::hmolar_excess)
780 .def(
"hmass_excess", &AbstractState::hmass_excess)
781 .def(
"smolar", &AbstractState::smolar)
782 .def(
"smass", &AbstractState::smass)
783 .def(
"smolar_excess", &AbstractState::smolar_excess)
784 .def(
"smass_excess", &AbstractState::smass_excess)
785 .def(
"umolar", &AbstractState::umolar)
786 .def(
"umass", &AbstractState::umass)
787 .def(
"umolar_excess", &AbstractState::umolar_excess)
788 .def(
"umass_excess", &AbstractState::umass_excess)
789 .def(
"cpmolar", &AbstractState::cpmolar)
790 .def(
"cpmass", &AbstractState::cpmass)
791 .def(
"cp0molar", &AbstractState::cp0molar)
792 .def(
"cp0mass", &AbstractState::cp0mass)
793 .def(
"cvmolar", &AbstractState::cvmolar)
794 .def(
"cvmass", &AbstractState::cvmass)
795 .def(
"gibbsmolar", &AbstractState::gibbsmolar)
796 .def(
"gibbsmass", &AbstractState::gibbsmass)
797 .def(
"gibbsmolar_excess", &AbstractState::gibbsmolar_excess)
798 .def(
"gibbsmass_excess", &AbstractState::gibbsmass_excess)
799 .def(
"helmholtzmolar", &AbstractState::helmholtzmolar)
800 .def(
"helmholtzmass", &AbstractState::helmholtzmass)
801 .def(
"helmholtzmolar_excess", &AbstractState::helmholtzmolar_excess)
802 .def(
"helmholtzmass_excess", &AbstractState::helmholtzmass_excess)
803 .def(
"volumemolar_excess", &AbstractState::volumemolar_excess)
804 .def(
"volumemass_excess", &AbstractState::volumemass_excess)
806 .def(
"hmolar_idealgas", &AbstractState::hmolar_idealgas)
807 .def(
"hmass_idealgas", &AbstractState::hmass_idealgas)
808 .def(
"hmolar_residual", &AbstractState::hmolar_residual)
809 .def(
"smolar_idealgas", &AbstractState::smolar_idealgas)
810 .def(
"smass_idealgas", &AbstractState::smass_idealgas)
811 .def(
"smolar_residual", &AbstractState::smolar_residual)
812 .def(
"umolar_idealgas", &AbstractState::umolar_idealgas)
813 .def(
"umass_idealgas", &AbstractState::umass_idealgas)
814 .def(
"gibbsmolar_residual", &AbstractState::gibbsmolar_residual)
815 .def(
"neff", &AbstractState::neff)
817 .def(
"get_fluid_constant", &AbstractState::get_fluid_constant)
818 .def(
"get_fluid_parameter_double", &AbstractState::get_fluid_parameter_double)
819 .def(
"set_cubic_alpha_C", &AbstractState::set_cubic_alpha_C)
820 .def(
"update_QT_pure_superanc", &AbstractState::update_QT_pure_superanc)
821 .def(
"speed_sound", &AbstractState::speed_sound)
823 .def(
"isobaric_expansion_coefficient", &AbstractState::isobaric_expansion_coefficient)
824 .def(
"fugacity_coefficient", &AbstractState::fugacity_coefficient)
825 .def(
"fugacity", &AbstractState::fugacity)
826 .def(
"chemical_potential", &AbstractState::chemical_potential)
827 .def(
"fundamental_derivative_of_gas_dynamics", &AbstractState::fundamental_derivative_of_gas_dynamics)
828 .def(
"PIP", &AbstractState::PIP)
830 .def(
"true_critical_point",
832 double T = 0, rho = 0;
834 return nb::make_tuple(
T, rho);
838 std::vector<double>
T, p;
840 return nb::make_tuple(
T, p);
842 .def(
"first_partial_deriv", &AbstractState::first_partial_deriv)
843 .def(
"second_partial_deriv", &AbstractState::second_partial_deriv)
844 .def(
"first_saturation_deriv", &AbstractState::first_saturation_deriv)
845 .def(
"second_saturation_deriv", &AbstractState::second_saturation_deriv)
846 .def(
"first_two_phase_deriv", &AbstractState::first_two_phase_deriv)
847 .def(
"second_two_phase_deriv", &AbstractState::second_two_phase_deriv)
848 .def(
"first_two_phase_deriv_splined", &AbstractState::first_two_phase_deriv_splined)
849 .def(
"build_phase_envelope", &AbstractState::build_phase_envelope)
850 .def(
"get_phase_envelope_data", &AbstractState::get_phase_envelope_data)
851 .def(
"has_melting_line", &AbstractState::has_melting_line)
852 .def(
"melting_line", &AbstractState::melting_line)
854 .def(
"viscosity", &AbstractState::viscosity)
856 .def(
"viscosity_contributions",
858 CoolPropDbl dilute = 0, initial_density = 0, residual = 0, critical = 0;
861 d[
"dilute"] =
static_cast<double>(dilute);
862 d[
"initial_density"] =
static_cast<double>(initial_density);
863 d[
"residual"] =
static_cast<double>(residual);
864 d[
"critical"] =
static_cast<double>(critical);
867 .def(
"conductivity", &AbstractState::conductivity)
868 .def(
"conductivity_contributions",
870 CoolPropDbl dilute = 0, initial_density = 0, residual = 0, critical = 0;
873 d[
"dilute"] =
static_cast<double>(dilute);
874 d[
"initial_density"] =
static_cast<double>(initial_density);
875 d[
"residual"] =
static_cast<double>(residual);
876 d[
"critical"] =
static_cast<double>(critical);
879 .def(
"surface_tension", &AbstractState::surface_tension)
880 .def(
"Prandtl", &AbstractState::Prandtl)
882 .def(
"conformal_state",
883 [](
AbstractState& AS,
const std::string& reference_fluid,
double T,
double rho) {
887 d[
"T"] =
static_cast<double>(T0);
888 d[
"rhomolar"] =
static_cast<double>(rho0);
891 .def(
"change_EOS", &AbstractState::change_EOS)
892 .def(
"alpha0", &AbstractState::alpha0)
893 .def(
"dalpha0_dDelta", &AbstractState::dalpha0_dDelta)
894 .def(
"dalpha0_dTau", &AbstractState::dalpha0_dTau)
895 .def(
"d2alpha0_dDelta2", &AbstractState::d2alpha0_dDelta2)
896 .def(
"d2alpha0_dDelta_dTau", &AbstractState::d2alpha0_dDelta_dTau)
897 .def(
"d2alpha0_dTau2", &AbstractState::d2alpha0_dTau2)
898 .def(
"d3alpha0_dTau3", &AbstractState::d3alpha0_dTau3)
899 .def(
"d3alpha0_dDelta_dTau2", &AbstractState::d3alpha0_dDelta_dTau2)
900 .def(
"d3alpha0_dDelta2_dTau", &AbstractState::d3alpha0_dDelta2_dTau)
901 .def(
"d3alpha0_dDelta3", &AbstractState::d3alpha0_dDelta3)
902 .def(
"alphar", &AbstractState::alphar)
903 .def(
"dalphar_dDelta", &AbstractState::dalphar_dDelta)
904 .def(
"dalphar_dTau", &AbstractState::dalphar_dTau)
905 .def(
"d2alphar_dDelta2", &AbstractState::d2alphar_dDelta2)
906 .def(
"d2alphar_dDelta_dTau", &AbstractState::d2alphar_dDelta_dTau)
907 .def(
"d2alphar_dTau2", &AbstractState::d2alphar_dTau2)
908 .def(
"d3alphar_dDelta3", &AbstractState::d3alphar_dDelta3)
909 .def(
"d3alphar_dDelta2_dTau", &AbstractState::d3alphar_dDelta2_dTau)
910 .def(
"d3alphar_dDelta_dTau2", &AbstractState::d3alphar_dDelta_dTau2)
911 .def(
"d3alphar_dTau3", &AbstractState::d3alphar_dTau3)
912 .def(
"d4alphar_dDelta4", &AbstractState::d4alphar_dDelta4)
913 .def(
"d4alphar_dDelta3_dTau", &AbstractState::d4alphar_dDelta3_dTau)
914 .def(
"d4alphar_dDelta2_dTau2", &AbstractState::d4alphar_dDelta2_dTau2)
915 .def(
"d4alphar_dDelta_dTau3", &AbstractState::d4alphar_dDelta_dTau3)
916 .def(
"d4alphar_dTau4", &AbstractState::d4alphar_dTau4);
942 m.def(
"generate_update_pair", [](
parameters key1,
double value1,
parameters key2,
double value2) {
943 double out1 = 0.0, out2 = 0.0;
944 input_pairs pair = generate_update_pair<double>(key1, value1, key2, value2, out1, out2);
945 return nb::make_tuple(pair, out1, out2);
951 m.def(
"PropsSI", [](
const std::string& Output,
const std::string& Name1,
double Prop1,
const std::string& Name2,
double Prop2,
952 const std::string& FluidName) {
953 double val =
PropsSI(Output, Name1, Prop1, Name2, Prop2, FluidName);
954 _raise_if_invalid(val);
964 [](
const std::string& Output,
const std::string& Name1, nb::object Prop1,
const std::string& Name2, nb::object Prop2,
965 const std::string& FluidName) -> nb::object {
966 bool s1 =
false, s2 =
false;
967 std::vector<double> v1 = _to_vec(Prop1, s1);
968 std::vector<double> v2 = _to_vec(Prop2, s2);
969 bool any_seq = s1 || s2;
971 if ((s1 && v1.empty()) || (s2 && v2.empty())) {
972 auto* empty =
new double[1];
973 nb::capsule owner(empty, [](
void* p)
noexcept {
delete[]
static_cast<double*
>(p); });
974 return nb::cast(nb::ndarray<nb::numpy, double>(empty, {
static_cast<std::size_t
>(0)}, owner));
976 std::size_t n = std::max(v1.size(), v2.size());
977 _broadcast_to(v1, n,
"Prop1");
978 _broadcast_to(v2, n,
"Prop2");
979 std::string backend, fluid;
981 std::vector<double> fractions{1.0};
983 std::vector<std::string> fluids = _split_str(delimited,
'&');
984 std::vector<std::vector<double>> out =
PropsSImulti({Output}, Name1, v1, Name2, v2, backend, fluids, fractions);
985 if (out.empty() || out[0].empty()) {
988 throw nb::python_error();
993 _raise_if_invalid(out[0][0]);
994 return nb::float_(out[0][0]);
998 std::size_t n_out = out.size();
999 auto* data =
new double[n_out];
1000 for (std::size_t i = 0; i < n_out; ++i) {
1001 data[i] = out[i][0];
1003 nb::capsule owner(data, [](
void* p)
noexcept {
delete[]
static_cast<double*
>(p); });
1004 return nb::cast(nb::ndarray<nb::numpy, double>(data, {n_out}, owner));
1014 [](nb::object Output,
const std::string& Name1, nb::object Prop1,
const std::string& Name2, nb::object Prop2,
1015 const std::string& FluidName) -> nb::object {
1016 std::vector<std::string> outputs = _to_str_vec(Output);
1017 bool s1 =
false, s2 =
false;
1018 std::vector<double> v1 = _to_vec(Prop1, s1);
1019 std::vector<double> v2 = _to_vec(Prop2, s2);
1021 if ((s1 && v1.empty()) || (s2 && v2.empty())) {
1022 auto* empty =
new double[1];
1023 nb::capsule owner(empty, [](
void* p)
noexcept {
delete[]
static_cast<double*
>(p); });
1024 return nb::cast(nb::ndarray<nb::numpy, double>(empty, {
static_cast<std::size_t
>(0)}, owner));
1026 std::size_t n = std::max(v1.size(), v2.size());
1027 _broadcast_to(v1, n,
"Prop1");
1028 _broadcast_to(v2, n,
"Prop2");
1029 std::string backend, fluid;
1031 std::vector<double> fractions{1.0};
1033 std::vector<std::string> fluids = _split_str(delimited,
'&');
1034 std::vector<std::vector<double>> out =
PropsSImulti(outputs, Name1, v1, Name2, v2, backend, fluids, fractions);
1035 if (out.empty() || out[0].empty()) {
1038 throw nb::python_error();
1047 std::size_t nrows = out.size();
1048 std::size_t m_out = out[0].size();
1049 auto* data =
new double[std::max<std::size_t>(1, nrows * m_out)];
1050 nb::capsule owner(data, [](
void* p)
noexcept {
delete[]
static_cast<double*
>(p); });
1051 for (std::size_t i = 0; i < nrows; ++i) {
1052 for (std::size_t j = 0; j < m_out; ++j) {
1053 data[i * m_out + j] = out[i][j];
1056 std::vector<std::size_t> shape;
1058 shape.push_back(nrows);
1061 shape.push_back(m_out);
1063 if (shape.empty()) {
1066 return nb::cast(nb::ndarray<nb::numpy, double>(data, shape.size(), shape.data(), owner));
1071 m.def(
"PropsSI", [](
const std::string& Output,
const std::string& FluidName) {
1072 double val =
Props1SI(Output, FluidName);
1073 _raise_if_invalid(val);
1085 m.def(
"extract_backend", [](
const std::string& in_str) {
1086 std::string backend, fluid;
1088 return nb::make_tuple(backend, fluid);
1090 m.def(
"extract_fractions", [](
const std::string& in_str) {
1091 std::vector<double> fractions;
1093 return nb::make_tuple(_split_str(delimited,
'&'), fractions);
1102 [](
const std::string& Output,
const std::string& N1,
double V1,
const std::string& N2,
double V2,
const std::string& N3,
double V3) {
1104 _raise_if_invalid(val);
1113 [](
const std::string& Output,
const std::string& N1, nb::object V1,
const std::string& N2, nb::object V2,
const std::string& N3,
1114 nb::object V3) -> nb::object {
1115 bool s1 =
false, s2 =
false, s3 =
false;
1116 std::vector<double> v1 = _to_vec(V1, s1), v2 = _to_vec(V2, s2), v3 = _to_vec(V3, s3);
1117 bool any_seq = s1 || s2 || s3;
1118 bool any_ndarray = (s1 && nb::hasattr(V1,
"ndim")) || (s2 && nb::hasattr(V2,
"ndim")) || (s3 && nb::hasattr(V3,
"ndim"));
1119 std::size_t n = std::max({v1.size(), v2.size(), v3.size()});
1120 _broadcast_to(v1, n,
"Input1");
1121 _broadcast_to(v2, n,
"Input2");
1122 _broadcast_to(v3, n,
"Input3");
1123 std::vector<double> out(n);
1124 for (std::size_t i = 0; i < n; ++i) {
1130 _raise_if_invalid(out[i]);
1133 return nb::float_(out[0]);
1136 auto* data =
new double[n != 0u ? n : 1u];
1137 for (std::size_t i = 0; i < n; ++i) {
1140 nb::capsule owner(data, [](
void* p)
noexcept {
delete[]
static_cast<double*
>(p); });
1141 return nb::cast(nb::ndarray<nb::numpy, double>(data, {n}, owner));
1143 return nb::cast(out);
1146 m.def(
"HAProps_Aux", [](std::string out_string,
double T,
double p,
double psi_w) {
1147 std::array<char, 1000> units{};
1149 return nb::make_tuple(out, std::string(units.data()));
1165 m.def(
"get_aliases", [](
const std::string& Fluid) {
return _split_str(
get_fluid_param_string(Fluid,
"aliases_bar"),
'|'); });
1166 m.def(
"get_REFPROPname", [](
const std::string& Fluid) {
return get_fluid_param_string(Fluid,
"REFPROP_name"); });
1167 m.def(
"get_BibTeXKey", [](
const std::string& Fluid,
const std::string& key) {
return get_fluid_param_string(Fluid,
"BibTeX-" + key); });
1171 m.def(
"set_reference_state", [](
const std::string& FluidName, nb::args args) {
1172 if (args.size() == 1) {
1174 }
else if (args.size() == 4) {
1181 auto _as_double = [](nb::handle h) {
return nb::cast<double>(nb::float_(h)); };
1182 set_reference_stateD(FluidName, _as_double(args[0]), _as_double(args[1]), _as_double(args[2]), _as_double(args[3]));
1184 throw std::invalid_argument(
"Invalid number of inputs to set_reference_state");
1189 init_superancillary(m);
1192# if defined(COOLPROP_NANOBIND_MODULE)
1197 m.attr(
"_capi") = nb::capsule(&g_state_capi,
"CoolProp._capi");