11# define _CRTDBG_MAP_ALLOC
12# ifndef _CRT_SECURE_NO_WARNINGS
13# define _CRT_SECURE_NO_WARNINGS
40static int deriv_counter = 0;
48 if (fluid_names.size() == 1) {
67 std::vector<CoolPropFluid>
components(component_names.size());
68 for (
unsigned int i = 0; i <
components.size(); ++i) {
96 this->
N = components.size();
101 std::vector<std::vector<double>> ones(1, std::vector<double>(1, 1));
114 if (generate_SatL_and_SatV) {
126 if (mf.size() !=
N) {
127 throw ValueError(
format(
"size of mole fraction vector [%d] does not equal that of component vector [%d]", mf.size(),
N));
140 for (std::vector<shared_ptr<HelmholtzEOSMixtureBackend>>::iterator it =
linked_states.begin(); it !=
linked_states.end(); ++it) {
141 it->get()->sync_linked_states(source);
153 if (mass_fractions.size() !=
N) {
154 throw ValueError(
format(
"size of mass fraction vector [%d] does not equal that of component vector [%d]", mass_fractions.size(),
N));
156 std::vector<CoolPropDbl> moles;
159 for (
unsigned int i = 0; i <
components.size(); ++i) {
160 tmp = mass_fractions[i] /
components[i].molar_mass();
161 moles.push_back(tmp);
165 for (std::vector<CoolPropDbl>::iterator it = moles.begin(); it != moles.end(); ++it) {
174 for (std::vector<shared_ptr<HelmholtzEOSMixtureBackend>>::iterator it =
linked_states.begin(); it !=
linked_states.end(); ++it) {
176 it->get()->resize(
N);
201 if (!ParamName.compare(
"name")) {
203 }
else if (!ParamName.compare(
"aliases")) {
205 }
else if (!ParamName.compare(
"aliases_bar")) {
207 }
else if (!ParamName.compare(
"CAS") || !ParamName.compare(
"CAS_number")) {
209 }
else if (!ParamName.compare(
"formula")) {
211 }
else if (!ParamName.compare(
"ASHRAE34")) {
213 }
else if (!ParamName.compare(
"REFPROPName") || !ParamName.compare(
"REFPROP_name") || !ParamName.compare(
"REFPROPname")) {
215 }
else if (ParamName.find(
"BibTeX") == 0)
217 std::vector<std::string> parts =
strsplit(ParamName,
'-');
218 if (parts.size() != 2) {
219 throw ValueError(
format(
"Unable to parse BibTeX string %s", ParamName.c_str()));
221 std::string key = parts[1];
222 if (!key.compare(
"EOS")) {
224 }
else if (!key.compare(
"CP0")) {
226 }
else if (!key.compare(
"VISCOSITY")) {
228 }
else if (!key.compare(
"CONDUCTIVITY")) {
230 }
else if (!key.compare(
"ECS_LENNARD_JONES")) {
232 }
else if (!key.compare(
"ECS_VISCOSITY_FITS")) {
234 }
else if (!key.compare(
"ECS_CONDUCTIVITY_FITS")) {
236 }
else if (!key.compare(
"SURFACE_TENSION")) {
238 }
else if (!key.compare(
"MELTING_LINE")) {
243 }
else if (ParamName.find(
"pure") == 0) {
249 }
else if (ParamName ==
"INCHI" || ParamName ==
"InChI" || ParamName ==
"INCHI_STRING") {
250 return cpfluid.
InChI;
251 }
else if (ParamName ==
"INCHI_Key" || ParamName ==
"InChIKey" || ParamName ==
"INCHIKEY") {
253 }
else if (ParamName ==
"2DPNG_URL") {
255 }
else if (ParamName ==
"SMILES" || ParamName ==
"smiles") {
257 }
else if (ParamName ==
"CHEMSPIDER_ID") {
259 }
else if (ParamName ==
"JSON") {
262 throw ValueError(
format(
"fluid parameter [%s] is invalid", ParamName.c_str()));
270 return components[0].EOS().get_superanc_optional();
275 throw ValueError(
format(
"Index i [%d] is out of bounds. Must be between 0 and %d.", i,
N - 1));
278 if (parameter.find(
"SUPERANC::") == 0) {
279 auto& superanc = optsuperanc.value();
281 std::string key = parameter.substr(10);
283 return superanc.get_pmax();
284 }
else if (key ==
"pmin") {
285 return superanc.get_pmin();
286 }
else if (key ==
"Tmin") {
287 return superanc.get_Tmin();
288 }
else if (key ==
"Tcrit_num") {
289 return superanc.get_Tcrit_num();
291 throw ValueError(
format(
"Superancillary parameter [%s] is invalid", key.c_str()));
297 throw ValueError(
format(
"fluid parameter [%s] is invalid", parameter.c_str()));
303 if (i < 0 || i >=
N) {
304 if (j < 0 || j >=
N) {
305 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
N - 1));
307 throw ValueError(
format(
"Index i [%d] is out of bounds. Must be between 0 and %d.", i,
N - 1));
309 }
else if (j < 0 || j >=
N) {
310 throw ValueError(
format(
"Index j [%d] is out of bounds. Must be between 0 and %d.", j,
N - 1));
312 if (model ==
"linear") {
314 double gammaT = 0.5 * (Tc1 + Tc2) / sqrt(Tc1 * Tc2);
316 double gammaV = 4.0 * (1 / rhoc1 + 1 / rhoc2) / pow(pow(rhoc1, -1.0 / 3.0) + pow(rhoc2, -1.0 / 3.0), 3);
321 }
else if (model ==
"Lorentz-Berthelot") {
327 throw ValueError(
format(
"mixing rule [%s] is not understood", model.c_str()));
332 const double value) {
334 if (i < 0 || i >=
N) {
335 if (j < 0 || j >=
N) {
336 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
N - 1));
338 throw ValueError(
format(
"Index i [%d] is out of bounds. Must be between 0 and %d.", i,
N - 1));
340 }
else if (j < 0 || j >=
N) {
341 throw ValueError(
format(
"Index j [%d] is out of bounds. Must be between 0 and %d.", j,
N - 1));
343 if (parameter ==
"Fij") {
347 Reducing->set_binary_interaction_double(i, j, parameter, value);
350 for (std::vector<shared_ptr<HelmholtzEOSMixtureBackend>>::iterator it =
linked_states.begin(); it !=
linked_states.end(); ++it) {
351 it->get()->set_binary_interaction_double(i, j, parameter, value);
357 if (i < 0 || i >=
N) {
358 if (j < 0 || j >=
N) {
359 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
N - 1));
361 throw ValueError(
format(
"Index i [%d] is out of bounds. Must be between 0 and %d.", i,
N - 1));
363 }
else if (j < 0 || j >=
N) {
364 throw ValueError(
format(
"Index j [%d] is out of bounds. Must be between 0 and %d.", j,
N - 1));
366 if (parameter ==
"Fij") {
369 return Reducing->get_binary_interaction_double(i, j, parameter);
378 const std::string& value) {
380 if (i < 0 || i >=
N) {
381 if (j < 0 || j >=
N) {
382 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
N - 1));
384 throw ValueError(
format(
"Index i [%d] is out of bounds. Must be between 0 and %d.", i,
N - 1));
386 }
else if (j < 0 || j >=
N) {
387 throw ValueError(
format(
"Index j [%d] is out of bounds. Must be between 0 and %d.", j,
N - 1));
389 if (parameter ==
"function") {
393 throw ValueError(
format(
"Cannot process this string parameter [%s] in set_binary_interaction_string", parameter.c_str()));
396 for (std::vector<shared_ptr<HelmholtzEOSMixtureBackend>>::iterator it =
linked_states.begin(); it !=
linked_states.end(); ++it) {
397 it->get()->set_binary_interaction_string(i, j, parameter, value);
407 if (EOS_name ==
"SRK" || EOS_name ==
"Peng-Robinson") {
419 shared_ptr<AbstractCubic> ac;
420 if (EOS_name ==
"SRK") {
421 ac.reset(
new SRK(Tc, pc, acentric, R));
426 ac->set_rhor(rhomolarc);
428 }
else if (EOS_name ==
"XiangDeiters") {
446 if (this->
SatL)
SatL->change_EOS(i, EOS_name);
447 if (this->
SatV)
SatV->change_EOS(i, EOS_name);
483 if (!state.compare(
"hs_anchor")) {
485 }
else if (!state.compare(
"max_sat_T")) {
487 }
else if (!state.compare(
"max_sat_p")) {
489 }
else if (!state.compare(
"reducing")) {
491 }
else if (!state.compare(
"critical")) {
493 }
else if (!state.compare(
"triple_liquid")) {
495 }
else if (!state.compare(
"triple_vapor")) {
498 throw ValueError(
format(
"This state [%s] is invalid to calc_state", state.c_str()));
501 if (!state.compare(
"critical")) {
512 throw ValueError(
"acentric factor cannot be calculated for mixtures");
524 for (
unsigned int i = 0; i <
components.size(); ++i) {
533 for (
unsigned int i = 0; i <
components.size(); ++i) {
540 if (param ==
iP && given ==
iT) {
544 return components[0].ancillaries.pL.evaluate(value);
546 return components[0].ancillaries.pV.evaluate(value);
548 }
else if (param ==
iT && given ==
iP) {
552 return components[0].ancillaries.pL.invert(value);
554 return components[0].ancillaries.pV.invert(value);
556 }
else if (param ==
iDmolar && given ==
iT) {
560 return components[0].ancillaries.rhoL.evaluate(value);
562 return components[0].ancillaries.rhoV.evaluate(value);
564 }
else if (param ==
iT && given ==
iDmolar) {
568 return components[0].ancillaries.rhoL.invert(value);
570 return components[0].ancillaries.rhoV.invert(value);
573 return components[0].ancillaries.surface_tension.evaluate(value);
587 return components[0].ancillaries.melting_line.evaluate(param, given, value);
595 return components[0].ancillaries.surface_tension.evaluate(
T());
597 throw ValueError(
format(
"surface tension is only defined within the two-phase region; Try PQ or QT inputs"));
606 switch (
components[0].transport.viscosity_dilute.type) {
633 format(
"dilute viscosity type [%d] is invalid for fluid %s",
components[0].transport.viscosity_dilute.type,
name().c_str()));
646 switch (
components[0].transport.viscosity_initial.type) {
650 initial_density = eta_dilute * B_eta_initial * rho;
663 switch (
components[0].transport.viscosity_higher_order.type) {
668 residual = TransportRoutines::viscosity_higher_order_friction_theory(*
this);
693 format(
"higher order viscosity type [%d] is invalid for fluid %s",
components[0].transport.viscosity_dilute.type,
name().c_str()));
696 return initial_density + residual;
701 CoolPropDbl dilute = 0, initial_density = 0, residual = 0, critical = 0;
703 return dilute + initial_density + residual + critical;
728 throw ValueError(
format(
"Viscosity model is not available for this fluid"));
735 std::vector<std::string> names(1, fluid_name);
739 critical = TransportRoutines::viscosity_ECS(*
this, *ref_fluid);
746 critical = TransportRoutines::viscosity_Chung(*
this);
753 critical = TransportRoutines::viscosity_rhosr(*
this);
804 throw ValueError(
"calc_viscosity_contributions invalid for mixtures");
820 throw ValueError(
format(
"Thermal conductivity model is not available for this fluid"));
827 std::vector<std::string>
name(1, fluid_name);
831 initial_density = TransportRoutines::conductivity_ECS(*
this, *ref_fluid);
840 initial_density = TransportRoutines::conductivity_hardcoded_water(*
this);
843 initial_density = TransportRoutines::conductivity_hardcoded_heavywater(*
this);
846 initial_density = TransportRoutines::conductivity_hardcoded_R23(*
this);
849 initial_density = TransportRoutines::conductivity_hardcoded_helium(*
this);
852 initial_density = TransportRoutines::conductivity_hardcoded_methane(*
this);
855 throw ValueError(
format(
"hardcoded conductivity type [%d] is invalid for fluid %s",
868 dilute = TransportRoutines::conductivity_dilute_ratio_polynomials(*
this);
871 dilute = TransportRoutines::conductivity_dilute_eta0_and_poly(*
this);
874 dilute = TransportRoutines::conductivity_dilute_hardcoded_CO2(*
this);
877 dilute = TransportRoutines::conductivity_dilute_hardcoded_CO2_HuberJPCRD2016(*
this);
880 dilute = TransportRoutines::conductivity_dilute_hardcoded_ethane(*
this);
887 format(
"dilute conductivity type [%d] is invalid for fluid %s",
components[0].transport.conductivity_dilute.type,
name().c_str()));
896 critical = TransportRoutines::conductivity_critical_simplified_Olchowy_Sengers(*
this);
899 critical = TransportRoutines::conductivity_critical_hardcoded_R123(*
this);
902 critical = TransportRoutines::conductivity_critical_hardcoded_ammonia(*
this);
908 critical = TransportRoutines::conductivity_critical_hardcoded_CO2_ScalabrinJPCRD2006(*
this);
912 format(
"critical conductivity type [%d] is invalid for fluid %s",
components[0].transport.viscosity_dilute.type,
name().c_str()));
915 throw ValueError(
"calc_conductivity_contributions invalid for mixtures");
922 switch (
components[0].transport.conductivity_residual.type) {
924 lambda_residual = TransportRoutines::conductivity_residual_polynomial(*
this);
927 lambda_residual = TransportRoutines::conductivity_residual_polynomial_and_exponential(*
this);
931 format(
"residual conductivity type [%d] is invalid for fluid %s",
components[0].transport.conductivity_residual.type,
name().c_str()));
933 return lambda_residual;
937 CoolPropDbl dilute = 0, initial_density = 0, residual = 0, critical = 0;
939 return dilute + initial_density + residual + critical;
971 TransportRoutines::conformal_state_solver(*
this, *REF,
T,
rhomolar);
975 for (
unsigned int i = 0; i <
components.size(); ++i) {
982 for (
unsigned int i = 0; i <
components.size(); ++i) {
997 if (!
SatL)
throw ValueError(
"The saturated liquid state has not been set.");
998 return SatL->keyed_output(key);
1002 if (!
SatV)
throw ValueError(
"The saturated vapor state has not been set.");
1003 return SatV->keyed_output(key);
1007 if (type ==
"Joule-Thomson") {
1010 }
else if (type ==
"Joule-Inversion") {
1013 }
else if (type ==
"Ideal") {
1016 }
else if (type ==
"Boyle") {
1024 std::vector<std::string> out;
1025 for (std::size_t i = 0; i <
components.size(); ++i) {
1032 throw ValueError(
format(
"For now, calc_ODP is only valid for pure and pseudo-pure fluids, %d components",
components.size()));
1043 throw ValueError(
format(
"For now, calc_GWP20 is only valid for pure and pseudo-pure fluids, %d components",
components.size()));
1054 throw ValueError(
format(
"For now, calc_GWP100 is only valid for pure and pseudo-pure fluids, %d components",
components.size()));
1065 throw ValueError(
format(
"For now, calc_GWP500 is only valid for pure and pseudo-pure fluids, %d components",
components.size()));
1077 if (critpts.size() == 1) {
1079 return critpts[0].T;
1081 throw ValueError(
format(
"critical point finding routine found %d critical points", critpts.size()));
1087 return optsuperanc.value().get_Tcrit_num();
1096 if (critpts.size() == 1) {
1098 return critpts[0].p;
1100 throw ValueError(
format(
"critical point finding routine found %d critical points", critpts.size()));
1106 return optsuperanc.value().get_pmax();
1115 if (critpts.size() == 1) {
1117 return critpts[0].rhomolar;
1119 throw ValueError(
format(
"critical point finding routine found %d critical points", critpts.size()));
1125 return optsuperanc.value().get_rhocrit_num();
1139 throw ValueError(
"calc_pmax_sat not yet defined for mixtures");
1145 double Tmax_sat =
components[0].EOS().max_sat_T.T;
1155 throw ValueError(
"calc_Tmax_sat not yet defined for mixtures");
1161 Tmin_satL =
components[0].EOS().sat_min_liquid.T;
1162 Tmin_satV =
components[0].EOS().sat_min_vapor.T;
1165 throw ValueError(
"calc_Tmin_sat not yet defined for mixtures");
1171 pmin_satL =
components[0].EOS().sat_min_liquid.p;
1172 pmin_satV =
components[0].EOS().sat_min_vapor.p;
1175 throw ValueError(
"calc_pmin_sat not yet defined for mixtures");
1184 for (
unsigned int i = 0; i <
components.size(); ++i) {
1191 for (
unsigned int i = 0; i <
components.size(); ++i) {
1198 for (
unsigned int i = 0; i <
components.size(); ++i) {
1219 auto& superanc = optsuperanc.value();
1221 if (
T > Tcrit_num) {
1222 throw ValueError(
format(
"Temperature to QT_flash [%0.8Lg K] may not be above the numerical critical point of %0.15Lg K",
T, Tcrit_num));
1224 auto rhoL = superanc.eval_sat(
T,
'D', 0);
1225 auto rhoV = superanc.eval_sat(
T,
'D', 1);
1226 auto p = superanc.eval_sat(
T,
'P', 1);
1227 SatL->update_TDmolarP_unchecked(
T, rhoL,
p);
1228 SatV->update_TDmolarP_unchecked(
T, rhoV,
p);
1245 bool optional_checks =
false;
1255 throw ValueError(
format(
"The molar density of %f mol/m3 is below the minimum of %f mol/m3",
rhomolar, rhomolar_min));
1259 throw ValueError(
format(
"The temperature of %f K is below the minimum of %f K",
T, T_min));
1271 bool optional_checks =
false;
1290 this->
_T = HEOS.
T();
1292 this->
_p = HEOS.
p();
1294 this->
_Q = HEOS.
Q();
1318 throw ValueError(
"Mole fractions must be set");
1334 std::cout <<
format(
"%s (%d): update called with (%d: (%s), %g, %g)", __FILE__, __LINE__, input_pair,
1339 CoolPropDbl ld_value1 = value1, ld_value2 = value2;
1340 pre_update(input_pair, ld_value1, ld_value2);
1344 switch (input_pair) {
1449 return mass_fractions;
1455 std::cout <<
format(
"%s (%d): update called with (%d: (%s), %g, %g)", __FILE__, __LINE__, input_pair,
1460 CoolPropDbl ld_value1 = value1, ld_value2 = value2;
1461 pre_update(input_pair, ld_value1, ld_value2);
1465 switch (input_pair) {
1498 throw ValueError(
"rhomolar is less than zero");
1501 throw ValueError(
"rhomolar is not a valid number");
1504 if (optional_checks) {
1543 saturation_called =
false;
1552 auto smolar_critical = [
this, &T_crit_, &rhomolar_crit_]() {
return this->
calc_smolar_nocache(T_crit_, rhomolar_crit_); };
1553 auto hmolar_critical = [
this, &T_crit_, &rhomolar_crit_]() {
return this->
calc_hmolar_nocache(T_crit_, rhomolar_crit_); };
1554 auto umolar_critical = [
this, &T_crit_, &rhomolar_crit_]() {
return this->
calc_umolar_nocache(T_crit_, rhomolar_crit_); };
1557 if (
_p > psat_max) {
1606 throw ValueError(
"supercritical pressure but other invalid for now");
1611 else if (
_p >=
components[0].EOS().ptriple * 0.9999 &&
_p <= psat_max) {
1618 auto& superanc = optsuperanc.value();
1620 if (
_p > pmax_num) {
1622 format(
"Pressure to PQ_flash [%0.8Lg Pa] may not be above the numerical critical point of %0.15Lg Pa",
_p, pmax_num));
1624 auto Tsat = superanc.get_T_from_p(
_p);
1625 auto rhoL = superanc.eval_sat(Tsat,
'D', 0);
1626 auto rhoV = superanc.eval_sat(Tsat,
'D', 1);
1642 SatL->update_TDmolarP_unchecked(Tsat, rhoL, psat);
1643 SatV->update_TDmolarP_unchecked(Tsat, rhoV, psat);
1647 Q = (1 / value - 1 /
SatL->rhomolar()) / (1 /
SatV->rhomolar() - 1 /
SatL->rhomolar());
1650 Q = (value -
SatL->smolar()) / (
SatV->smolar() -
SatL->smolar());
1653 Q = (value -
SatL->hmolar()) / (
SatV->hmolar() -
SatL->hmolar());
1656 Q = (value -
SatL->umolar()) / (
SatV->umolar() -
SatL->umolar());
1668 }
else if (
Q > 1 + 1e-9) {
1689 bool definitely_two_phase =
false;
1700 if (
_T < Tm - 0.001) {
1701 throw ValueError(
format(
"For now, we don't support T [%g K] below Tmelt(p) [%g K]",
_T, Tm));
1708 if (
_T <
Tmin() - 0.001) {
1709 throw ValueError(
format(
"For now, we don't support T [%g K] below Tmin(saturation) [%g K]",
_T,
Tmin()));
1717 if (value > T_vap) {
1721 }
else if (value < T_liq) {
1745 if (value > h_vap + h_vap_error_band) {
1749 }
else if (value < h_liq - h_liq_error_band) {
1753 }
else if (value > h_liq + h_liq_error_band && value < h_vap - h_vap_error_band) {
1754 definitely_two_phase =
true;
1770 if (value > s_vap + s_vap_error_band) {
1774 }
else if (value < s_liq - s_liq_error_band) {
1778 }
else if (value > s_liq + s_liq_error_band && value < s_vap - s_vap_error_band) {
1779 definitely_two_phase =
true;
1798 CoolPropDbl u_liq_error_band = 1.5 * h_liq_error_band;
1799 CoolPropDbl u_vap_error_band = 1.5 * h_vap_error_band;
1802 if (value > u_vap + u_vap_error_band) {
1806 }
else if (value < u_liq - u_liq_error_band) {
1810 }
else if (value > u_liq + u_liq_error_band && value < u_vap - u_vap_error_band) {
1811 definitely_two_phase =
true;
1821 if (!definitely_two_phase) {
1828 if (value < rho_vap) {
1831 }
else if (value > rho_liq) {
1841 throw ValueError(
"possibly two-phase inputs not supported for mixtures for now");
1858 saturation_called =
true;
1877 Q = (1 / value - 1 / HEOS.
SatL->rhomolar()) / (1 / HEOS.
SatV->rhomolar() - 1 / HEOS.
SatL->rhomolar());
1880 Q = (value - HEOS.
SatL->smolar()) / (HEOS.
SatV->smolar() - HEOS.
SatL->smolar());
1883 Q = (value - HEOS.
SatL->hmolar()) / (HEOS.
SatV->hmolar() - HEOS.
SatL->hmolar());
1886 Q = (value - HEOS.
SatL->umolar()) / (HEOS.
SatV->umolar() - HEOS.
SatL->umolar());
1904 }
else if (Q > 1 + 1e-9) {
1918 }
else if (
_p <
components[0].EOS().ptriple * 0.9999) {
1926 throw NotImplementedError(
format(
"For now, we don't support p [%g Pa] below ptriple [%g Pa] when T [%g] is less than Tmin [%g]",
1934 throw ValueError(
format(
"The pressure [%g Pa] cannot be used in p_phase_determination",
_p));
1943 double call(
double T) {
1946 double dTdp_along_sat =
1947 HEOS->
T() * (1 / HEOS->
SatV->rhomolar() - 1 / HEOS->
SatL->rhomolar()) / (HEOS->
SatV->hmolar() - HEOS->
SatL->hmolar());
1954 Residual resid(*HEOS_copy);
1957 double v2 = resid.call(tripleV.
T);
1978 double call(
double T) {
1981 double dTdp_along_sat =
1982 HEOS->
T() * (1 / HEOS->
SatV->rhomolar() - 1 / HEOS->
SatL->rhomolar()) / (HEOS->
SatV->hmolar() - HEOS->
SatL->hmolar());
1989 Residualhmax residhmax(*HEOS_copy);
2000 throw ValueError(
format(
"value to T_phase_determination_pure_or_pseudopure is invalid"));
2004 auto smolar_critical = [
this, &T_crit_, &rhomolar_crit_]() {
return this->
calc_smolar_nocache(T_crit_, rhomolar_crit_); };
2005 auto hmolar_critical = [
this, &T_crit_, &rhomolar_crit_]() {
return this->
calc_hmolar_nocache(T_crit_, rhomolar_crit_); };
2006 auto umolar_critical = [
this, &T_crit_, &rhomolar_crit_]() {
return this->
calc_umolar_nocache(T_crit_, rhomolar_crit_); };
2009 if (_T < T_crit_ && _p > p_crit_) {
2019 }
else if (
_rhomolar > rhomolar_crit_) {
2030 }
else if (
_p > p_crit_) {
2039 throw ValueError(
format(
"T=Tcrit; invalid input for other to T_phase_determination_pure_or_pseudopure"));
2041 }
else if (
_T < T_crit_)
2047 auto& superanc = optsuperanc.value();
2048 auto rhoL = superanc.eval_sat(
_T,
'D', 0);
2049 auto rhoV = superanc.eval_sat(
_T,
'D', 1);
2050 auto psat = superanc.eval_sat(
_T,
'P', 1);
2057 if (std::abs(psat / value - 1) < 1e-6) {
2059 format(
"Saturation pressure [%g Pa] corresponding to T [%g K] is within 1e-4 %% of given p [%Lg Pa]", psat,
_T, value));
2060 }
else if (value < psat) {
2063 }
else if (value > psat) {
2072 Q = (1 / value - 1 / rhoL) / (1 / rhoV - 1 / rhoL);
2076 }
else if (
Q >= 1) {
2090 SatL->update_TDmolarP_unchecked(
_T, rhoL, psat);
2091 SatV->update_TDmolarP_unchecked(
_T, rhoV, psat);
2095 Q = (1 / value - 1 /
SatL->rhomolar()) / (1 /
SatV->rhomolar() - 1 /
SatL->rhomolar());
2098 Q = (value -
SatL->smolar()) / (
SatV->smolar() -
SatL->smolar());
2101 Q = (value -
SatL->hmolar()) / (
SatV->hmolar() -
SatL->hmolar());
2104 Q = (value -
SatL->umolar()) / (
SatV->umolar() -
SatL->umolar());
2141 if (value < p_vap) {
2145 }
else if (value > p_liq) {
2162 throw ValueError(
"Two-phase inputs not supported for pseudo-pure for now");
2175 if (value < rho_vap) {
2178 }
else if (value > rho_liq) {
2183 double Qanc = (1 / value - 1 /
static_cast<double>(
_rhoLanc))
2186 if (value > 0.95 * rho_liq || value < 1.05 * rho_vap) {
2197 }
else if (Qanc > 1.01) {
2209 throw ValueError(
format(
"The saturation properties are needed in T_phase_determination_pure_or_pseudopure"));
2218 if (value >
SatV->calc_smolar()) {
2229 if (value >
SatV->calc_hmolar()) {
2239 if (value >
SatV->calc_umolar()) {
2249 throw ValueError(
format(
"invalid input for other to T_phase_determination_pure_or_pseudopure"));
2266 if (value > HEOS.
SatL->p() * (1e-6 + 1)) {
2270 }
else if (value < HEOS.SatV->
p() * (1 - 1e-6)) {
2276 format(
"Saturation pressure [%g Pa] corresponding to T [%g K] is within 1e-4 %% of given p [%Lg Pa]", HEOS.
SatL->p(),
_T, value));
2282 Q = (1 / value - 1 / HEOS.
SatL->rhomolar()) / (1 / HEOS.
SatV->rhomolar() - 1 / HEOS.
SatL->rhomolar());
2285 Q = (value - HEOS.
SatL->smolar()) / (HEOS.
SatV->smolar() - HEOS.
SatL->smolar());
2288 Q = (value - HEOS.
SatL->hmolar()) / (HEOS.
SatV->hmolar() - HEOS.
SatL->hmolar());
2291 Q = (value - HEOS.
SatL->umolar()) / (HEOS.
SatV->umolar() - HEOS.
SatL->umolar());
2370 throw ValueError(
"supercritical temp but other invalid for now");
2379 dT_dtau = -pow(T, 2) / Tr, R = HEOS->
gas_constant(), delta = rho / rhor, tau = Tr / T;
2462 int nTau = 0, nDelta = 1;
2496 double second_deriv(
double rhomolar) {
2498 return R_u *
T /
POW2(rhor)
2502 dpdrho_resid resid(
this,
T,
p);
2506 light =
Halley(resid, 1e-6, 1e-8, 100);
2507 double d2pdrho2__constT = resid.deriv(light);
2508 if (d2pdrho2__constT > 0) {
2512 }
catch (std::exception& e) {
2514 std::cout << e.what() << std::endl;
2523 for (std::size_t counter = 0; counter <= 100; counter++) {
2525 double curvature = resid.deriv(rho);
2526 if (curvature > 0) {
2537 for (
double omega = 0.7; omega > 0; omega -= 0.2) {
2539 resid.options.add_number(
"omega", omega);
2540 heavy =
Halley(resid, rhomax, 1e-8, 100);
2541 double d2pdrho2__constT = resid.deriv(heavy);
2542 if (d2pdrho2__constT < 0) {
2547 }
catch (std::exception& e) {
2549 std::cout << e.what() << std::endl;
2558 double rho = rhomax;
2559 for (std::size_t counter = 0; counter <= 100; counter++) {
2561 double curvature = resid.deriv(rho);
2562 if (curvature < 0 || this->
p() < 0) {
2572 if (light > 0 && heavy > 0) {
2579 else if (light < 0 && heavy < 0) {
2580 double dpdrho_min = resid.call(1e-10);
2581 double dpdrho_max = resid.call(rhomax);
2582 if (dpdrho_max * dpdrho_min > 0) {
2603 rhor(
HEOS->get_reducing_state().rhomolar),
2610 return (peos -
p) /
p;
2655 double rho_liq = -1, rho_vap = -1;
2656 if (
p > p_at_rhomax_stationary) {
2658 for (; counter <= 10; counter++) {
2661 if (p_at_rhomax <
p) {
2662 rhomolar_max *= 1.05;
2671 if (
p < p_at_rhomin_stationary) {
2676 if (rho_vap > 0 && rho_liq > 0) {
2678 if (std::abs(rho_vap - rho_liq) < 1e-10) {
2685 if (gibbsmolar_liq < gibbsmolar_vap) {
2691 }
else if (rho_vap < 0 && rho_liq > 0) {
2694 }
else if (rho_vap > 0 && rho_liq < 0) {
2720 if (rhomolar_guess < 0)
2727 if (rhomolar_guess < 0 || !
ValidNumber(rhomolar_guess))
2741 throw ValueError(
"Liquid density is invalid");
2743 }
catch (std::exception&) {
2786 if (dpdrho < 0 || d2pdrho2 < 0) {
2794 if (dpdrho < 0 || d2pdrho2 > 0) {
2801 }
catch (std::exception& e) {
2815 throw ValueError(
format(
"solver_rho_Tp was unable to find a solution for T=%10Lg, p=%10Lg, with guess value %10Lg with error: %s",
T,
p,
2816 rhomolar_guess, e.what()));
2822 for (std::size_t i = 0; i <
components.size(); ++i) {
2824 CoolPropDbl m_i = 0.480 + 1.574 * acentric_i - 0.176 * pow(acentric_i, 2);
2828 CoolPropDbl a_i = 0.42747 * pow(R_u * Tci, 2) / pci * pow(1 + m_i * (1 - sqrt(
T / Tci)), 2);
2830 for (std::size_t j = 0; j <
components.size(); ++j) {
2832 CoolPropDbl m_j = 0.480 + 1.574 * acentric_j - 0.176 * pow(acentric_j, 2);
2834 CoolPropDbl a_j = 0.42747 * pow(R_u * Tcj, 2) / pcj * pow(1 + m_j * (1 - sqrt(
T / Tcj)), 2);
2854 solve_cubic(1, -1, A - B - B * B, -A * B, Nsolns, Z0, Z1, Z2);
2865 if (rhomolar0 > 0 && rhomolar1 <= 0 && rhomolar2 <= 0) {
2868 if (rhomolar0 <= 0 && rhomolar1 > 0 && rhomolar2 <= 0) {
2871 if (rhomolar0 <= 0 && rhomolar1 <= 0 && rhomolar2 > 0) {
2886 throw ValueError(
"Bad phase to solver_rho_Tp_SRK");
2924 return R_u *
T * (1 +
tau * (da0_dTau + dar_dTau) +
delta * dar_dDelta);
2928 std::cout <<
format(
"HelmholtzEOSMixtureBackend::calc_hmolar: 2phase: %d T: %g rhomomolar: %g",
isTwoPhase(),
_T,
_rhomolar) << std::endl;
2930 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for the two-phase properties"));
2972 return R_u * (
tau * (da0_dTau + dar_dTau) - a0 - ar);
2976 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for the two-phase properties"));
3001 _smolar = R_u * (
_tau.
pt() * (da0_dTau + dar_dTau) - a0 - ar);
3019 return R_u *
T *
tau * (da0_dTau + dar_dTau);
3023 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for the two-phase properties"));
3063 return static_cast<double>(
_cvmolar);
3080 * (-pow(
_tau.
pt(), 2) * (d2ar_dTau2 + d2a0_dTau2)
3082 / (1 + 2 *
_delta.
pt() * dar_dDelta + pow(
_delta.
pt(), 2) * d2ar_dDelta2));
3084 return static_cast<double>(
_cpmolar);
3096 return R_u * (1 + (-pow(
_tau.
pt(), 2)) * d2a0_dTau2);
3101 return SatL->speed_sound();
3103 return SatV->speed_sound();
3105 throw ValueError(
format(
"Speed of sound is not defined for two-phase states because it depends on the distribution of phases."));
3125 - pow(1 +
_delta.
pt() * dar_dDelta -
_delta.
pt() *
_tau.
pt() * d2ar_dDelta_dTau, 2) / (pow(
_tau.
pt(), 2) * (d2ar_dTau2 + d2a0_dTau2))));
3148 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for the two-phase properties"));
3174 for (std::size_t i = 0; i <
components.size(); ++i) {
3190 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for the two-phase properties"));
3224 double dna0_dni__const_T_V_nj =
3226 return gas_constant() *
T() * (dna0_dni__const_T_V_nj + dnar_dni__const_T_V_nj);
3247 throw ValueError(
"Mole fractions must be set before calling calc_reducing_state");
3256 bool cache_values =
true;
3277 bool cache_values =
false;
3279 return derivs.
get(nTau, nDelta);
3286 throw ValueError(
"No alpha0 derivatives are available");
3297 double taustar = Tc / Tr *
tau, deltastar = rhor / rhomolarc *
delta;
3298 if (nTau == 0 && nDelta == 0) {
3299 val = E.
base0(taustar, deltastar);
3300 }
else if (nTau == 0 && nDelta == 1) {
3302 }
else if (nTau == 1 && nDelta == 0) {
3304 }
else if (nTau == 0 && nDelta == 2) {
3306 }
else if (nTau == 1 && nDelta == 1) {
3308 }
else if (nTau == 2 && nDelta == 0) {
3310 }
else if (nTau == 0 && nDelta == 3) {
3312 }
else if (nTau == 1 && nDelta == 2) {
3314 }
else if (nTau == 2 && nDelta == 1) {
3316 }
else if (nTau == 3 && nDelta == 0) {
3321 val *= pow(rhor / rhomolarc, nDelta);
3322 val /= pow(Tr / Tc, nTau);
3325 throw ValueError(
format(
"calc_alpha0_deriv_nocache returned invalid number with inputs nTau: %d, nDelta: %d, tau: %Lg, delta: %Lg", nTau,
3336 for (
unsigned int i = 0; i <
N; ++i) {
3341 tau_i = T_ci *
tau / Tr;
3342 delta_i =
delta * rhor / rho_ci;
3348 if (nTau == 0 && nDelta == 0) {
3351 }
else if (nTau == 0 && nDelta == 1) {
3353 }
else if (nTau == 1 && nDelta == 0) {
3355 }
else if (nTau == 0 && nDelta == 2) {
3356 summer +=
mole_fractions[i] * Rratio * pow(rhor / rho_ci, 2) *
components[i].EOS().d2alpha0_dDelta2(tau_i, delta_i);
3357 }
else if (nTau == 1 && nDelta == 1) {
3358 summer +=
mole_fractions[i] * Rratio * rhor / rho_ci * T_ci / Tr *
components[i].EOS().d2alpha0_dDelta_dTau(tau_i, delta_i);
3359 }
else if (nTau == 2 && nDelta == 0) {
3373 throw ValueError(
"No alpha0 derivatives are available");
3384 double taustar = Tc / Tr *
tau, deltastar = rhor / rhomolarc *
delta;
3385 return E.
alpha0.
all(taustar, deltastar,
false);
3391 CoolPropDbl summer_00 = 0, summer_01 = 0, summer_10 = 0, summer_02 = 0, summer_11 = 0, summer_20 = 0;
3394 for (
unsigned int i = 0; i <
N; ++i) {
3399 tau_i = T_ci *
tau / Tr;
3400 delta_i =
delta * rhor / rho_ci;
3407 auto pure =
components[i].EOS().alpha0.all(tau_i, delta_i);
3412 summer_01 +=
mole_fractions[i] * Rratio * rhor / rho_ci * pure.dalphar_ddelta;
3413 summer_10 +=
mole_fractions[i] * Rratio * T_ci / Tr * pure.dalphar_dtau;
3414 summer_02 +=
mole_fractions[i] * Rratio * pow(rhor / rho_ci, 2) * pure.d2alphar_ddelta2;
3415 summer_11 +=
mole_fractions[i] * Rratio * rhor / rho_ci * T_ci / Tr * pure.d2alphar_ddelta_dtau;
3416 summer_20 +=
mole_fractions[i] * Rratio * pow(T_ci / Tr, 2) * pure.d2alphar_dtau2;
3420 ders.alphar = summer_00;
3421 ders.dalphar_ddelta = summer_01;
3422 ders.dalphar_dtau = summer_10;
3423 ders.d2alphar_ddelta2 = summer_02;
3424 ders.d2alphar_ddelta_dtau = summer_11;
3425 ders.d2alphar_dtau2 = summer_20;
3494 const int nTau = 0, nDelta = 0;
3498 const int nTau = 0, nDelta = 1;
3502 const int nTau = 1, nDelta = 0;
3506 const int nTau = 0, nDelta = 2;
3510 const int nTau = 1, nDelta = 1;
3514 const int nTau = 2, nDelta = 0;
3518 const int nTau = 0, nDelta = 3;
3522 const int nTau = 1, nDelta = 2;
3526 const int nTau = 2, nDelta = 1;
3530 const int nTau = 3, nDelta = 0;
3539 if (Of1 ==
iT && Wrt1 ==
iP) {
3541 }
else if (Of1 ==
iP && Wrt1 ==
iT) {
3542 return 1 / dTdP_sat;
3545 else if (Wrt1 ==
iT) {
3549 else if (Wrt1 ==
iP) {
3557 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for calc_first_saturation_deriv"));
3563 if (Of1 ==
iT && Wrt1 ==
iP) {
3565 }
else if (Of1 ==
iP && Wrt1 ==
iT) {
3566 return 1 / dTdP_sat;
3569 else if (Wrt1 ==
iT) {
3573 else if (Wrt1 ==
iP) {
3581 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for calc_second_saturation_deriv"));
3582 if (Wrt1 ==
iP && Wrt2 ==
iP) {
3597 CoolPropDbl ddT_dTdp_along_sat_constp = (DELTAh * (
_T * dDELTAv_dT_constp + DELTAv) -
_T * DELTAv * dDELTAh_dT_constp) /
POW2(DELTAh);
3598 CoolPropDbl ddp_dTdp_along_sat_constT = (DELTAh * (
_T * dDELTAv_dp_constT) -
_T * DELTAv * dDELTAh_dp_constT) /
POW2(DELTAh);
3600 double ddp_dydpsigma = d2ydp2_constT + dydT_constp * ddp_dTdp_along_sat_constT + d2ydTdp * dTdp_along_sat;
3601 double ddT_dydpsigma = d2ydTdp + dydT_constp * ddT_dTdp_along_sat_constp + d2ydT2_constp * dTdp_along_sat;
3602 return ddp_dydpsigma + ddT_dydpsigma * dTdp_along_sat;
3604 throw ValueError(
format(
"Currently, only possible to take second saturation derivative w.r.t. P (both times)"));
3610 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for calc_second_two_phase_deriv"));
3625 CoolPropDbl numerator = 1 /
SatV->keyed_output(rho_key) - 1 /
SatL->keyed_output(rho_key);
3627 CoolPropDbl dnumerator = -1 /
POW2(
SatV->keyed_output(rho_key)) * drhoV_dp_sat + 1 /
POW2(
SatL->keyed_output(rho_key)) * drhoL_dp_sat;
3628 CoolPropDbl ddenominator = dhV_dp_sat - dhL_dp_sat;
3629 CoolPropDbl d_dvdh_dp__consth = (denominator * dnumerator - numerator * ddenominator) /
POW2(denominator);
3630 return -
POW2(
rhomolar()) * d_dvdh_dp__consth + dv_dh_constp * (-2 *
rhomolar()) * drhomolar_dp__consth;
3632 && ((Wrt1 ==
iHmass && Constant1 ==
iP && Wrt2 ==
iP && Constant2 ==
iHmass)
3633 || (Wrt2 ==
iHmass && Constant2 ==
iP && Wrt1 ==
iP && Constant1 ==
iHmass))) {
3645 CoolPropDbl numerator = 1 /
SatV->keyed_output(rho_key) - 1 /
SatL->keyed_output(rho_key);
3647 CoolPropDbl dnumerator = -1 /
POW2(
SatV->keyed_output(rho_key)) * drhoV_dp_sat + 1 /
POW2(
SatL->keyed_output(rho_key)) * drhoL_dp_sat;
3648 CoolPropDbl ddenominator = dhV_dp_sat - dhL_dp_sat;
3649 CoolPropDbl d_dvdh_dp__consth = (denominator * dnumerator - numerator * ddenominator) /
POW2(denominator);
3650 return -
POW2(rho) * d_dvdh_dp__consth + dv_dh_constp * (-2 * rho) * drho_dp__consth;
3656 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for calc_first_two_phase_deriv"));
3670 CoolPropDbl dvdp_h = dvL_dp + dxdp_h * (1 /
SatV->rhomolar() - 1 /
SatL->rhomolar()) +
Q() * (dvV_dp - dvL_dp);
3681 CoolPropDbl dvdp_h = dvL_dp + dxdp_h * (1 /
SatV->rhomass() - 1 /
SatL->rhomass()) +
Q() * (dvV_dp - dvL_dp);
3684 throw ValueError(
"These inputs are not supported to calc_first_two_phase_deriv");
3691 bool drho_dh__p =
false;
3692 bool drho_dp__h =
false;
3693 bool rho_spline =
false;
3713 throw ValueError(
"These inputs are not supported to calc_first_two_phase_deriv");
3716 if (!this->
SatL || !this->
SatV)
throw ValueError(
format(
"The saturation properties are needed for calc_first_two_phase_deriv_splined"));
3729 Liq->update_DmolarT_direct(
SatL->rhomolar(),
SatL->T());
3744 CoolPropDbl Abracket = (2 * rho_liq - 2 * rho_end + Delta_end * (drho_dh_liq__constp + drho_dh_end));
3746 CoolPropDbl b = 3 /
POW2(Delta_end) * (-rho_liq + rho_end) - 1 / Delta_end * (drho_dh_end + 2 * drho_dh_liq__constp);
3780 CoolPropDbl d_Delta_end_dp__consth = x_end * (dhV_dp_sat - dhL_dp_sat);
3784 CoolPropDbl d_Abracket_dp_consth = (2 * drhoL_dp_sat - 2 * drho_dp_end + Delta_end * (d2rhodhdp_liq + d2rhodhdp_end)
3785 + d_Delta_end_dp__consth * (drho_dh_liq__constp + drho_dh_end));
3786 CoolPropDbl da_dp = 1 /
POW3(Delta_end) * d_Abracket_dp_consth + Abracket * (-3 /
POW4(Delta_end) * d_Delta_end_dp__consth);
3787 CoolPropDbl db_dp = -6 /
POW3(Delta_end) * d_Delta_end_dp__consth * (rho_end - rho_liq) + 3 /
POW2(Delta_end) * (drho_dp_end - drhoL_dp_sat)
3788 + (1 /
POW2(Delta_end) * d_Delta_end_dp__consth) * (drho_dh_end + 2 * drho_dh_liq__constp)
3789 - (1 / Delta_end) * (d2rhodhdp_end + 2 * d2rhodhdp_liq);
3794 (3 * a *
POW2(Delta) + 2 * b * Delta + c) * d_Delta_dp__consth +
POW3(Delta) * da_dp +
POW2(Delta) * db_dp + Delta * dc_dp + dd_dp;
3797 throw ValueError(
"Something went wrong in HelmholtzEOSMixtureBackend::calc_first_two_phase_deriv_splined");
3807 Eigen::MatrixXd Lstar, Mstar;
3809 std::vector<double> call(
const std::vector<double>& tau_delta) {
3815 std::vector<double> o(2);
3816 o[0] = Lstar.determinant();
3817 o[1] = Mstar.determinant();
3820 std::vector<std::vector<double>> Jacobian(
const std::vector<double>& x) {
3821 std::size_t
N = x.size();
3822 std::vector<std::vector<double>> J(
N, std::vector<double>(
N, 0));
3828 J[0][0] = (adjL * dLdTau).trace();
3829 J[0][1] = (adjL * dLdDelta).trace();
3830 J[1][0] = (adjM * dMdTau).trace();
3831 J[1][1] = (adjM * dMdDelta).trace();
3835 std::vector<std::vector<double>> numerical_Jacobian(
const std::vector<double>& x) {
3836 std::size_t
N = x.size();
3837 std::vector<double> rplus, rminus, xp;
3838 std::vector<std::vector<double>> J(
N, std::vector<double>(
N, 0));
3840 double epsilon = 0.0001;
3843 for (std::size_t i = 0; i <
N; ++i) {
3847 xp[i] -= 2 * epsilon;
3850 for (std::size_t j = 0; j <
N; ++j) {
3851 J[j][i] = (rplus[j] - rminus[j]) / (2 * epsilon);
3854 std::cout << J[0][0] <<
" " << J[0][1] << std::endl;
3855 std::cout << J[1][0] <<
" " << J[1][1] << std::endl;
3860 std::vector<double> x, tau_delta(2);
3906 _deriv = (adjL * dLdTau).trace();
3913 dadjLstardTau = adjugate_derivative(Lstar, dLstardTau);
3914 _second_deriv = (dLstardTau * dadjLstardTau + adjL * d2LstardTau2).trace();
3954 tau_new =
tau +
R_tau * cos(theta);
3962 double tau_new, delta_new;
3970 double L1 =
Lstar.determinant();
3979 return -
R_tau * sin(theta) * dL1_dtau +
R_delta * cos(theta) * dL1_ddelta;
3985 for (
int i = 0; i < 300; ++i) {
4027 double p_MPa =
HEOS.
p() / 1e6;
4030 double tau_new, delta_new;
4053 this->tau = tau_new;
4054 this->delta = delta_new;
4058 this->spinodal_values.
tau.push_back(tau_new);
4059 this->spinodal_values.
delta.push_back(delta_new);
4060 this->spinodal_values.
M1.push_back(M1);
4068 L1star = Lstar.determinant();
4069 M1star = Mstar.determinant();
4080 rapidjson::Document doc;
4082 rapidjson::Value& val = doc;
4083 std::vector<std::vector<DepartureFunctionPointer>>&
mat =
critical_state->residual_helmholtz->Excess.DepartureFunctionMatrix;
4084 if (
mat.size() > 0) {
4085 mat[0][1]->phi.to_json(val, doc);
4094 double delta0 = _HUGE, tau0 = _HUGE;
4095 critical_state->get_critical_point_starting_values(delta0, tau0);
4102 resid_L0.
call(tau0);
4104 while (resid_L0.
deriv(tau0) > 0 && bump_count < 3) {
4108 double tau_L0 =
Halley(resid_L0, tau0, 1e-10, 100);
4115 double R_delta = 0, R_tau = 0;
4127 const double rhomolar_guess) {
4130 if (w.size() != z.size()) {
4131 throw ValueError(
format(
"Trial composition vector size [%d] is not the same as bulk composition [%d]", w.size(), z.size()));
4140 for (std::size_t i = 0; i < w.size(); ++i) {
4149 bool find_critical_points =
false;
4154 for (std::size_t i = 0; i <
components.size(); ++i) {
4156 if (!reference_state.compare(
"IIR")) {
4157 if (HEOS.
Ttriple() > 273.15) {
4158 throw ValueError(
format(
"Cannot use IIR reference state; Ttriple [%Lg] is greater than 273.15 K", HEOS.
Ttriple()));
4163 double deltah = HEOS.
hmass() - 200000;
4164 double deltas = HEOS.
smass() - 1000;
4170 std::cout <<
format(
"set offsets to %0.15g and %0.15g\n", delta_a1, delta_a2);
4172 }
else if (!reference_state.compare(
"ASHRAE")) {
4173 if (HEOS.
Ttriple() > 233.15) {
4174 throw ValueError(
format(
"Cannot use ASHRAE reference state; Ttriple [%Lg] is greater than than 233.15 K", HEOS.
Ttriple()));
4179 double deltah = HEOS.
hmass() - 0;
4180 double deltas = HEOS.
smass() - 0;
4186 std::cout <<
format(
"set offsets to %0.15g and %0.15g\n", delta_a1, delta_a2);
4188 }
else if (!reference_state.compare(
"NBP")) {
4190 throw ValueError(
format(
"Cannot use NBP reference state; p_triple [%Lg Pa] is greater than than 101325 Pa", HEOS.
p_triple()));
4195 double deltah = HEOS.
hmass() - 0;
4196 double deltas = HEOS.
smass() - 0;
4202 std::cout <<
format(
"set offsets to %0.15g and %0.15g\n", delta_a1, delta_a2);
4204 }
else if (!reference_state.compare(
"DEF")) {
4206 }
else if (!reference_state.compare(
"RESET")) {
4209 throw ValueError(
format(
"reference state string is invalid: [%s]", reference_state.c_str()));
4220 for (std::size_t i = 0; i <
components.size(); ++i) {
4229 double deltah =
hmolar - hmolar0;
4230 double deltas =
smolar - smolar0;
4238 const std::string& ref) {
4248 double f = (HEOS->name() ==
"Water" || HEOS->name() ==
"CarbonDioxide") ? 1.00001 : 1.0;
4270 if (!HEOS->is_pure()) {