22#define REFPROP_IMPLEMENTATION
23#define REFPROP_CSTYLE_REFERENCES
24#include "externals/REFPROP-headers/REFPROP_lib.h"
25#undef REFPROP_IMPLEMENTATION
26#undef REFPROP_CSTYLE_REFERENCES
50# define _CRTDBG_MAP_ALLOC
51# ifndef _CRT_SECURE_NO_WARNINGS
52# define _CRT_SECURE_NO_WARNINGS
62static bool dbg_refprop =
false;
63static const unsigned int number_of_endings = 5;
64std::string
endings[number_of_endings] = {
"",
".FLD",
".fld",
".PPF",
".ppf"};
66static char default_reference_state[] =
"DEF";
69#if defined(__powerpc__) || defined(__ISLINUX__) || defined(__ISAPPLE__)
70char refpropPath[] =
"/opt/refprop";
71#elif defined(__ISWINDOWS__)
72char refpropPath[] =
"";
79 char* valptr = getenv(var);
80 if (valptr ==
nullptr) {
83 return std::string(valptr);
92 std::string joined =
join_path(root,
"fluids");
96 std::string ucase_joined =
join_path(root,
"FLUIDS");
100 throw CoolProp::ValueError(
format(
"fluid directories \"FLUIDS\" or \"fluids\" could not be found in the directory [%s]", root));
108 std::string rpPath = refpropPath;
111 if (!alt_refprop_path.empty()) {
121#if defined(__ISWINDOWS__)
123#elif defined(__ISLINUX__) || defined(__ISAPPLE__)
134 std::string rpPath = refpropPath;
138 if (!alt_refprop_path.empty()) {
146 return join_path(alt_refprop_path,
"mixtures");
148#if defined(__ISWINDOWS__)
150#elif defined(__ISLINUX__) || defined(__ISAPPLE__)
162 if (!alt_hmx_bnc_path.empty()) {
163 return alt_hmx_bnc_path;
177 if (fluid_names.size() == 1) {
228 if (RefpropdllInstance != NULL)
return true;
233 std::string rpv(STRINGIFY(RPVersion));
234 if (rpv.compare(
"NOTAVAILABLE") != 0) {
239 bool loaded_REFPROP =
false;
241 auto root =
get_envvar(
"COOLPROP_REFPROP_ROOT");
243 const std::string alt_rp_name =
get_config_string(ALTERNATIVE_REFPROP_LIBRARY_PATH);
246 loaded_REFPROP = ::load_REFPROP(err, root.value().c_str(),
"");
247 SETPATHdll(
const_cast<char*
>(root.value().c_str()), 400);
249 if (!loaded_REFPROP) {
250 if (!alt_rp_name.empty()) {
251 loaded_REFPROP = ::load_REFPROP(err,
"", alt_rp_name);
253 if (alt_rp_path.empty()) {
254 loaded_REFPROP = ::load_REFPROP(err, refpropPath,
"");
256 loaded_REFPROP = ::load_REFPROP(err, alt_rp_path,
"");
261 if (loaded_REFPROP) {
264 printf(
"Good news: It is possible to use REFPROP on your system! However, the library \n");
265 printf(
"could not be loaded. Please make sure that REFPROP is available on your system.\n\n");
266 printf(
"Neither found in current location nor found in system PATH.\n");
267 printf(
"If you already obtained a copy of REFPROP from http://www.nist.gov/srd/, \n");
268 printf(
"add location of REFPROP to the PATH environment variable or your library path.\n\n");
269 printf(
"In case you do not use Windows, have a look at https://github.com/jowr/librefprop.so \n");
270 printf(
"to find instructions on how to compile your own version of the REFPROP library.\n\n");
271 printf(
"COOLPROP_REFPROP_ROOT: %s\n", (root) ? root.value().c_str() :
"?");
272 printf(
"ALTERNATIVE_REFPROP_PATH: %s\n", alt_rp_path.c_str());
273 printf(
"ERROR: %s\n", err.c_str());
291 char fluids[10000] =
"", hmx[] =
"HMX.BNC", default_reference_state[] =
"DEF", herr[255] =
"";
296 for (
int i = 0; i < 255; ++i) {
299 SETUPdll(&N, fluids, hmx, default_reference_state, &ierr, herr,
305 if (strlen(herr) == 0) {
306 return format(
"%g", ((
double)ierr) / 10000.0);
308 std::string s(herr, herr + 254);
316 if (!cached_component_string.empty() &&
LoadedREFPROPRef == cached_component_string) {
318 std::cout <<
format(
"%s:%d: The current fluid can be reused; %s and %s match \n", __FILE__, __LINE__, cached_component_string.c_str(),
322 std::cout <<
format(
"%s:%d: The current fluid can be reused; %s and %s match \n", __FILE__, __LINE__, cached_component_string.c_str(),
324 int N =
static_cast<int>(this->fluid_names.size());
326 throw ValueError(
format(
"Size of fluid vector [%d] is larger than the maximum defined by REFPROP [%d]",
fluid_names.size(), ncmax));
336 char component_string[10000], herr[errormessagelength];
345 const char* _HMX_path = HMX_path.c_str();
346 if (strlen(_HMX_path) > refpropcharlength) {
347 throw ValueError(
format(
"Full HMX path (%s) is too long; max length is 255 characters", _HMX_path));
349 strcpy(hmx_bnc, _HMX_path);
355 GERG04dll(&N, &iflag, &ierr, herr, 255);
363 if (N == 1 &&
upper(components_joined_raw).find(
".MIX") != std::string::npos) {
366 std::vector<double> x(ncmax);
367 char mix[255], reference_state[4] =
"DEF";
370 const char* _components_joined_raw = path_to_MIX_file.c_str();
371 if (strlen(_components_joined_raw) > 255) {
372 throw ValueError(
format(
"components (%s) is too long", components_joined_raw.c_str()));
374 strcpy(mix, _components_joined_raw);
376 SETMIXdll(mix, hmx_bnc, reference_state, &N, component_string, &(x[0]), &ierr, herr, 255, 255, 3, 10000, 255);
377 if (
static_cast<int>(ierr) <= 0) {
383 cached_component_string = mix;
384 this->fluid_names.clear();
385 this->fluid_names.push_back(components_joined_raw);
387 std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
389 if (dbg_refprop) std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
390 if (
get_config_bool(REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS) && ierr == -117) {
391 throw ValueError(
format(
"Interaction parameter estimation has been disabled: %s", herr));
404 std::cout <<
format(
"%s:%d Unable to load predefined mixture [%s] with ierr: [%d] and herr: [%s]\n", __FILE__, __LINE__, mix,
407 throw ValueError(
format(
"Unable to load mixture: %s", components_joined_raw.c_str()));
412 for (
unsigned int k = 0; k < number_of_endings; k++) {
414 for (
unsigned int j = 0; j < (
unsigned int)N; j++) {
423 std::cout <<
format(
"%s:%d: The fluid %s has not been loaded before, current value is %s \n", __FILE__, __LINE__,
427 const char* _components_joined = components_joined.c_str();
428 if (strlen(_components_joined) > 10000) {
429 throw ValueError(
format(
"components_joined (%s) is too long", _components_joined));
431 strcpy(component_string, _components_joined);
433 for (
int i =
static_cast<int>(components_joined.size()); i < 10000; ++i) {
434 component_string[i] =
' ';
439 SETUPdll(&N, component_string, hmx_bnc, default_reference_state, &ierr, herr,
445 if (
get_config_bool(REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS) && ierr == -117) {
446 throw ValueError(
format(
"Interaction parameter estimation has been disabled: %s", herr));
448 if (
get_config_bool(REFPROP_IGNORE_ERROR_ESTIMATED_INTERACTION_PARAMETERS) && ierr == 117) {
451 if (
static_cast<int>(ierr) <= 0)
458 cached_component_string = _components_joined;
460 std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
462 if (dbg_refprop) std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
472 }
else if (k < number_of_endings - 1) {
474 std::cout <<
format(
"REFPROP error/warning [ierr: %d]: %s", ierr, herr) << std::endl;
479 std::cout <<
format(
"k: %d #endings: %d", k, number_of_endings) << std::endl;
481 throw ValueError(
format(
"Could not load these fluids: %s", components_joined_raw.c_str()));
487 if (ParamName ==
"CAS") {
498 std::vector<std::string> CASvec;
499 for (
int icomp = 1L; icomp <= static_cast<int>(
fluid_names.size()); ++icomp) {
500 char hnam[13], hn80[81], hcasn[13];
501 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
503 std::string casn = hcasn;
505 CASvec.push_back(casn);
508 }
else if (ParamName ==
"name") {
510 char hnam[13], hn80[81], hcasn[13];
511 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
513 std::string
name = hnam;
516 }
else if (ParamName ==
"long_name") {
518 char hnam[13], hn80[81], hcasn[13];
519 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
521 std::string n80 = hn80;
525 throw ValueError(
format(
"parameter to fluid_param_string is invalid: %s", ParamName.c_str()));
529 for (
int icomp = 1L; icomp <= static_cast<int>(
fluid_names.size()); ++icomp) {
530 char hnam[13], hn80[81], hcasn[13];
531 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
533 std::string casn = hcasn;
543 const double value) {
556 char hmodij[3], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
563 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
565 std::string shmodij(hmodij);
568 if (parameter ==
"model") {
571 throw ValueError(
format(
" I don't know what to do with your parameter [%s]", parameter.c_str()));
581 const std::string& value) {
583 if (i < 0 || i >=
Ncomp) {
584 if (j < 0 || j >=
Ncomp) {
585 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
Ncomp - 1));
589 }
else if (j < 0 || j >=
Ncomp) {
592 int icomp =
static_cast<int>(i) + 1, jcomp =
static_cast<int>(j) + 1, ierr = 0L;
593 char hmodij[3], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
598 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
600 if (parameter ==
"model") {
601 if (value.length() > 4) {
602 throw ValueError(
format(
"Model parameter (%s) is longer than 4 characters.", value));
604 strcpy(hmodij, value.c_str());
607 throw ValueError(
format(
"I don't know what to do with your parameter [%s]", parameter.c_str()));
609 SETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, &ierr, herr, 3, 255, 255);
611 throw ValueError(
format(
"Unable to set parameter[%s] to value[%s]: %s", parameter.c_str(), value.c_str(), herr));
616 const double value) {
618 if (i < 0 || i >=
Ncomp) {
619 if (j < 0 || j >=
Ncomp) {
620 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
Ncomp - 1));
624 }
else if (j < 0 || j >=
Ncomp) {
627 int icomp =
static_cast<int>(i) + 1, jcomp =
static_cast<int>(j) + 1, ierr = 0L;
628 char hmodij[3], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
633 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
635 std::string shmodij(hmodij);
638 if (parameter ==
"betaT") {
640 }
else if (parameter ==
"gammaT") {
642 }
else if (parameter ==
"betaV") {
644 }
else if (parameter ==
"gammaV") {
646 }
else if (parameter ==
"Fij") {
649 throw ValueError(
format(
"I don't know what to do with your parameter [%s]", parameter.c_str()));
651 SETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, &ierr, herr, 3, 255, 255);
653 throw ValueError(
format(
"Unable to set parameter[%s] to value[%g]: %s", parameter.c_str(), value, herr));
663 if (i < 0 || i >=
Ncomp) {
664 if (j < 0 || j >=
Ncomp) {
665 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
Ncomp - 1));
669 }
else if (j < 0 || j >=
Ncomp) {
672 int icomp =
static_cast<int>(i) + 1, jcomp =
static_cast<int>(j) + 1;
673 char hmodij[3], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
677 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
679 std::string shmodij(hmodij);
683 if (parameter ==
"betaT") {
685 }
else if (parameter ==
"gammaT") {
687 }
else if (parameter ==
"betaV") {
689 }
else if (parameter ==
"gammaV") {
691 }
else if (parameter ==
"Fij") {
694 throw ValueError(
format(
" I don't know what to do with your parameter [%s]", parameter.c_str()));
706 format(
"Size of mole fraction vector [%d] does not equal that of component vector [%d]",
mole_fractions.size(), this->Ncomp));
708 this->mole_fractions = std::vector<CoolPropDbl>(ncmax, 0.0);
719 format(
"size of mass fraction vector [%d] does not equal that of component vector [%d]",
mass_fractions.size(), this->Ncomp));
721 std::vector<double> moles(this->
Ncomp);
722 double sum_moles = 0.0;
723 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
724 for (
int i = 1L; i <= static_cast<int>(this->
Ncomp); ++i) {
725 INFOdll(&i, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
726 moles[i - 1] =
static_cast<double>(
mass_fractions[i - 1]) / (wmm / 1000.0);
727 sum_moles += moles[i - 1];
729 for (std::size_t i = 0; i < this->
Ncomp; ++i) {
730 moles[i] = moles[i] / sum_moles;
736 throw ValueError(
"Mole fractions not yet set");
765 double Dmax_mol_L, pmax_kPa;
768 pmax = pmax_kPa * 1000;
769 rhomolarmax = Dmax_mol_L * 1000;
790 double Tcrit, pcrit_kPa, dcrit_mol_L;
791 CRITPdll(&(
mole_fractions[0]), &Tcrit, &pcrit_kPa, &dcrit_mol_L, &ierr, herr, 255);
792 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
801 double Tcrit, pcrit_kPa, dcrit_mol_L;
802 CRITPdll(&(
mole_fractions[0]), &Tcrit, &pcrit_kPa, &dcrit_mol_L, &ierr, herr, 255);
803 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
811 double Tcrit, pcrit_kPa, dcrit_mol_L;
812 CRITPdll(&(
mole_fractions[0]), &Tcrit, &pcrit_kPa, &dcrit_mol_L, &ierr, herr, 255);
813 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
816 return static_cast<CoolPropDbl>(dcrit_mol_L * 1000);
820 double rhored_mol_L = 0, Tr = 0;
827 double rhored_mol_L = 0, Tr = 0;
833 double rhored_mol_L = 0, Tr = 0;
835 return static_cast<CoolPropDbl>(rhored_mol_L * 1000);
840 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
845 INFOdll(&icomp, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
848 throw CoolProp::ValueError(
"acentric factor only available for pure components in REFPROP backend");
870 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
875 INFOdll(&icomp, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
885 double p_kPa = _HUGE;
886 double rho_mol_L = _HUGE, rhoLmol_L = _HUGE, rhoVmol_L = _HUGE, hmol = _HUGE, emol = _HUGE, smol = _HUGE, cvmol = _HUGE, cpmol = _HUGE, w = _HUGE;
888 char herr[errormessagelength + 1];
890 double __T =
Ttriple(), __Q = 0;
893 &emol, &hmol, &smol, &cvmol, &cpmol, &w,
894 &ierr, herr, errormessagelength);
895 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
919 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
924 INFOdll(&icomp, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
925 return static_cast<CoolPropDbl>(dip * 3.33564e-30);
927 throw ValueError(
format(
"dipole moment is only available for pure fluids"));
962 double tmin, tmax, Dmax_mol_L, pmax_kPa, Tmax_melt;
964 LIMITSdll(htyp, &(
mole_fractions[0]), &tmin, &tmax, &Dmax_mol_L, &pmax_kPa, 3);
966 MELTPdll(&pmax_kPa, &(
mole_fractions[0]), &Tmax_melt, &ierr, herr, errormessagelength);
967 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
978 if (param ==
iP && given ==
iT) {
979 double _T =
static_cast<double>(value), p_kPa;
980 MELTTdll(&
_T, &(
mole_fractions[0]), &p_kPa, &ierr, herr, errormessagelength);
981 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
985 }
else if (param ==
iT && given ==
iP) {
986 double p_kPa =
static_cast<double>(value) / 1000.0,
_T;
987 MELTPdll(&p_kPa, &(
mole_fractions[0]), &
_T, &ierr, herr, errormessagelength);
988 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1002 double _T = 300, p_kPa;
1003 MELTTdll(&
_T, &(
mole_fractions[0]), &p_kPa, &ierr, herr, errormessagelength);
1004 if (
static_cast<int>(ierr) == 1) {
1016 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
1020 INFOdll(&i, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
1031 p = 0, e = 0, h = 0, s = 0, cv = 0, cp = 0, w = 0, Z = 0, hjt = 0, A = 0, G = 0, xkappa = 0, beta = 0, dPdrho = 0, d2PdD2 = 0, dPT = 0,
1032 drhodT = 0, drhodP = 0, d2PT2 = 0, d2PdTD = 0, spare3 = 0, spare4 = 0;
1036 THERM2dll(&t, &rho, &(
mole_fractions[0]), &
p, &e, &h, &s, &cv, &cp, &w, &Z, &hjt, &A, &G, &xkappa, &beta, &dPdrho, &d2PdD2, &dPT, &drhodT,
1037 &drhodP, &d2PT2, &d2PdTD, &spare3, &spare4);
1038 return 2 - rho * (d2PdTD / dPT - d2PdD2 / dPdrho);
1043 double eta, tcx, rhomol_L = 0.001 *
_rhomolar;
1048 &ierr, herr, errormessagelength);
1049 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1064 double sigma, rho_mol_L = 0.001 *
_rhomolar;
1069 &ierr, herr, errormessagelength);
1070 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1081 std::vector<double> fug_cof;
1086 &ierr, herr, errormessagelength);
1087 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1101 &ierr, herr, errormessagelength);
1102 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1116 &ierr, herr, errormessagelength);
1117 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1126 double rhoymin, rhoymax, c = 0;
1130 &ierr, herr, errormessagelength);
1131 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1156 int isp = 0, iderv = -1;
1157 if (SPLNVALdll == NULL) {
1160 format(
"Your version of REFFPROP(%s) does not have the SPLNVALdll function; cannot extract phase envelope values", rpv.c_str()));
1162 SPLNVALdll(&isp, &iderv, &c, &rhoymin, &ierr, herr, errormessagelength);
1164 SPLNVALdll(&isp, &iderv, &c, &rhoymax, &ierr, herr, errormessagelength);
1165 int nc =
static_cast<int>(this->
Ncomp);
1166 double ratio = pow(rhoymax / rhoymin, 1 /
double(N));
1167 for (
double rho_molL = rhoymin; rho_molL < rhoymax; rho_molL *= ratio) {
1173 for (isp = 1; isp <= nc; ++isp) {
1174 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1180 PhaseEnvelope.lnrhomolar_vap.push_back(log(rho_molL * 1000));
1182 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1187 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1191 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1194 PhaseEnvelope.Q.push_back(
static_cast<double>(y > rho_molL));
1196 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1199 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1205 double p_kPa, emol, hmol, smol, cvmol, cpmol, w, hjt, eta, tcx;
1207 THERMdll(&
T, &rho_molL, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1213 &ierr, herr, errormessagelength);
1221 double p0, e0, h0, s0, cv0, cp0, w0, A0, G0;
1222 THERM0dll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p0, &e0, &h0, &s0, &cv0, &cp0, &w0, &A0, &G0);
1229 if ((
_Q >= 0.00) && (
_Q <= 1.00)) {
1231 }
else if (
_Q > 1.00) {
1236 }
else if (
_Q < 0.00) {
1245 if ((
_Q == 999) || (
_Q == -997)) {
1260 double rho_mol_L = _HUGE, rhoLmol_L = _HUGE, rhoVmol_L = _HUGE, hmol = _HUGE, emol = _HUGE, smol = _HUGE, cvmol = _HUGE, cpmol = _HUGE, w = _HUGE,
1261 q = _HUGE, mm = _HUGE, p_kPa = _HUGE, hjt = _HUGE;
1263 char herr[errormessagelength + 1] =
" ";
1274 switch (input_pair) {
1277 p_kPa = 0.001 * value1;
1284 &q, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1285 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1311 int kph = -10, kguess = 0;
1317 throw ValueError(
format(
"PT: cannot use this imposed phase for PT inputs"));
1320 TPRHOdll(&
_T, &p_kPa, &(
mole_fractions[0]), &kph, &kguess, &rho_mol_L, &ierr, herr, errormessagelength);
1323 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1336 rho_mol_L = 0.001 * value1;
1343 &q, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1344 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1350 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1367 rho_mol_L = 0.001 * value1;
1368 p_kPa = 0.001 * value2;
1374 &q, &emol, &hmol, &smol, &cvmol, &cpmol, &w,
1375 &ierr, herr, errormessagelength);
1376 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1396 rho_mol_L = 0.001 * value1;
1403 &q, &emol, &smol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1404 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1424 rho_mol_L = 0.001 * value1;
1431 &q, &emol, &hmol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1432 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1452 rho_mol_L = 0.001 * value1;
1459 &q, &hmol, &smol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1460 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1480 p_kPa = 0.001 * value2;
1485 &q, &emol, &smol, &cvmol, &cpmol, &w,
1486 &ierr, herr, errormessagelength);
1487 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1506 p_kPa = 0.001 * value1;
1512 &q, &emol, &hmol, &cvmol, &cpmol, &w,
1513 &ierr, herr, errormessagelength);
1515 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1534 p_kPa = 0.001 * value1;
1541 &q, &hmol, &smol, &cvmol, &cpmol, &w,
1542 &ierr, herr, errormessagelength);
1544 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1568 &q, &emol, &cvmol, &cpmol, &w,
1569 &ierr, herr, errormessagelength);
1571 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1597 &q, &smol, &cvmol, &cpmol, &w,
1598 &ierr, herr, errormessagelength);
1600 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1634 &q, &emol, &hmol, &cvmol, &cpmol, &w,
1635 &ierr, herr, errormessagelength);
1637 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1670 &q, &emol, &smol, &cvmol, &cpmol, &w,
1671 &ierr, herr, errormessagelength);
1673 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1706 &q, &hmol, &smol, &cvmol, &cpmol, &w,
1707 &ierr, herr, errormessagelength);
1709 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1754 p_kPa = 0.001 * value1;
1757 int iFlsh = 0, iGuess = 0, ierr = 0;
1758 if (std::abs(q) < 1e-10) {
1760 }
else if (std::abs(q - 1) < 1e-10) {
1778 herr, errormessagelength);
1779 rho_mol_L = (iFlsh == 1) ? rhoLmol_L : rhoVmol_L;
1783 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1786 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD) || iFlsh == 0) {
1797 &emol, &hmol, &smol, &cvmol, &cpmol, &w,
1798 &ierr, herr, errormessagelength);
1801 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1818 int iFlsh = 0, iGuess = 0;
1819 if (std::abs(q) < 1e-10) {
1821 }
else if (std::abs(q - 1) < 1e-10) {
1840 &ierr, herr, errormessagelength);
1841 rho_mol_L = (iFlsh == 1) ? rhoLmol_L : rhoVmol_L;
1845 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1848 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD) || iFlsh == 0) {
1859 &emol, &hmol, &smol, &cvmol, &cpmol, &w,
1860 &ierr, herr, errormessagelength);
1863 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1898 double rho_mol_L = _HUGE, hmol = _HUGE, emol = _HUGE, smol = _HUGE, cvmol = _HUGE, cpmol = _HUGE, w = _HUGE, q = _HUGE, p_kPa = _HUGE,
1901 char herr[errormessagelength + 1];
1908 switch (input_pair) {
1911 p_kPa = 0.001 * value1;
1923 rho_mol_L = guesses.
rhomolar / 1000.0;
1924 TPRHOdll(&
_T, &p_kPa, &(
mole_fractions[0]), &kph, &kguess, &rho_mol_L, &ierr, herr, errormessagelength);
1925 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1936 p_kPa = 0.001 * value1;
1938 double rhoLmol_L = -1, rhoVmol_L = -1;
1943 if (std::abs(value2) < 1e-10) {
1945 if (!guesses.
x.empty()) {
1953 }
else if (std::abs(value2 - 1) < 1e-10) {
1955 if (!guesses.
y.empty()) {
1967 std::cout <<
format(
"guesses.T: %g\n", guesses.
T);
1979 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1994 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
2010 if (PHIXdll == NULL) {
2011 throw ValueError(
"PHIXdll function is not available in your version of REFPROP. Please upgrade");
2019 if (PHI0dll == NULL) {
2020 throw ValueError(
"PHI0dll function is not available in your version of REFPROP. Please upgrade");
2030 double T_K =
_T, p_kPa =
_p / 1000.0, rho = 1, vE = -1, eE = -1, hE = -1, sE = -1, aE = -1, gE = -1;
2056 EXCESSdll(&T_K, &p_kPa, &(
mole_fractions[0]), &kph, &rho, &vE, &eE, &hE, &sE, &aE, &gE, &ierr, herr, errormessagelength);
2057 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
2073 const std::vector<double> z;
2074 wrapper(
const std::vector<double>& z) : z(z) {};
2075 std::vector<double> call(
const std::vector<double>& x) {
2076 std::vector<double> r(2);
2077 double dpdrho__constT = _HUGE, d2pdrho2__constT = _HUGE;
2078 DPDDdll(
const_cast<double*
>(&(x[0])),
const_cast<double*
>(&(x[1])),
const_cast<double*
>(&(z[0])), &dpdrho__constT);
2079 DPDD2dll(
const_cast<double*
>(&(x[0])),
const_cast<double*
>(&(x[1])),
const_cast<double*
>(&(z[0])), &d2pdrho2__constT);
2080 r[0] = dpdrho__constT;
2081 r[1] = d2pdrho2__constT;
2089 std::vector<double> x(2,
T);
2093 rho = xfinal[1] * 1000.0;
2100 }
else if (key ==
iDmass) {
2103 double wmm_kg_kmol = 0;
2105 return wmm_kg_kmol / 1000;
2107 throw ValueError(
"Invalid parameter. Only mass and molar density are available with RefProp");
2111 throw ValueError(
"The saturated liquid state has not been set.");
2118 }
else if (key ==
iDmass) {
2121 double wmm_kg_kmol = 0;
2123 return wmm_kg_kmol / 1000;
2129 throw ValueError(
"The saturated vapor state has not been set.");
2134 if (type ==
"Joule-Thomson") {
2137 }
else if (type ==
"Joule-Inversion") {
2140 }
else if (type ==
"Ideal") {
2143 }
else if (type ==
"Boyle") {
2174 throw ValueError(
"mole fractions must be of size 20");
2178 THERM0dll(&
T, &rho_mol_dm3, &(mf[0]), &o.
p_kPa, &o.
umol_Jmol, &o.
hmol_Jmol, &o.
smol_JmolK, &o.
cvmol_JmolK, &o.
cpmol_JmolK, &o.
w_ms, &o.
amol_Jmol,
2185 if (!load_REFPROP(err)) {
2187 std::cout <<
format(
"Error while loading REFPROP: %s", err) << std::endl;
2198 if (!unload_REFPROP(err)) {
2200 std::cout <<
format(
"Error while unloading REFPROP: %s", err) << std::endl;
2210void REFPROP_SETREF(
char hrf[3],
int ixflag,
double x0[1],
double& h0,
double& s0,
double& T0,
double& p0,
int& ierr,
char herr[255],
int l1,
2213 bool loaded_REFPROP = ::load_REFPROP(err);
2214 if (!loaded_REFPROP) {
2215 throw ValueError(
format(
"Not able to load REFPROP; err is: %s", err.c_str()));
2217 SETREFdll(hrf, &ixflag, x0, &h0, &s0, &T0, &p0, &ierr, herr, l1, l2);
2224# include <catch2/catch_all.hpp>
2226TEST_CASE(
"Check REFPROP and CoolProp values agree",
"[REFPROP]") {
2227 SECTION(
"Saturation densities agree within 0.5% at T/Tc = 0.9") {
2230 for (std::vector<std::string>::iterator it = ss.begin(); it != ss.end(); ++it) {
2231 std::string Name = (*it);
2235 if (RPName.find(
"N/A") == 0) {
2240 double Tr = S1->T_critical();
2242 double rho_CP = S1->rhomolar();
2246 double rho_RP = S2->rhomolar();
2253 double DH = (rho_RP - rho_CP) / rho_RP;
2254 CHECK(std::abs(DH) < 0.05);
2257 SECTION(
"Saturation specific heats agree within 0.5% at T/Tc = 0.9") {
2260 for (std::vector<std::string>::iterator it = ss.begin(); it != ss.end(); ++it) {
2261 std::string Name = (*it);
2265 if (RPName.find(
"N/A") == 0) {
2270 double Tr = S1->T_critical();
2272 double cp_CP = S1->cpmolar();
2276 double cp_RP = S2->cpmolar();
2284 double Dcp = (cp_RP - cp_CP) / cp_RP;
2285 CHECK(std::abs(Dcp) < 0.05);
2288 SECTION(
"Enthalpy and entropy reference state") {
2291 for (std::vector<std::string>::iterator it = ss.begin(); it != ss.end(); ++it) {
2292 std::string Name = (*it);
2296 if (RPName.find(
"N/A") == 0) {
2301 double Tr = S1->T_critical();
2302 double RCP = S1->gas_constant();
2304 double h_CP = S1->hmass();
2305 double s_CP = S1->smass();
2306 auto j = S1->fluid_param_string(
"JSON");
2307 rapidjson::Document doc;
2308 doc.Parse<0>(j.c_str());
2309 auto& v = doc[0][
"EOS"][0][
"alpha0"];
2315 double RRP = S2->gas_constant();
2316 double h_RP = S2->hmass();
2317 double s_RP = S2->smass();
2319 double delta_a1 = (s_CP - s_RP) / (S1->gas_constant() / S1->molar_mass());
2320 double delta_a2 = -(h_CP - h_RP) / (S1->gas_constant() / S1->molar_mass() * S1->get_reducing_state().T);
2321 CAPTURE(
format(
"%0.16f", delta_a1));
2322 CAPTURE(
format(
"%0.16f", delta_a2));
2332 double DH = (S1->hmass() - S2->hmass());
2333 double DS = (S1->smass() - S2->smass());
2335 CHECK(std::abs(DH / h_RP) < 0.01);
2336 CHECK(std::abs(DS / s_RP) < 0.01);
2341TEST_CASE(
"Check trivial inputs for REFPROP work",
"[REFPROP_trivial]") {
2342 const int num_inputs = 6;
2343 std::string inputs[num_inputs] = {
"T_triple",
"T_critical",
"p_critical",
"molar_mass",
"rhomolar_critical",
"rhomass_critical"};
2344 for (
int i = 0; i < num_inputs; ++i) {
2345 std::ostringstream ss;
2346 ss <<
"Check " << inputs[i];
2347 SECTION(ss.str(),
"") {
2353 double err = (cp_val - rp_val) / cp_val;
2359TEST_CASE(
"Check PHI0 derivatives",
"[REFPROP_PHI0]") {
2361 const int num_inputs = 3;
2362 std::string inputs[num_inputs] = {
"DALPHA0_DDELTA_CONSTTAU",
"D2ALPHA0_DDELTA2_CONSTTAU",
"D3ALPHA0_DDELTA3_CONSTTAU"};
2363 for (
int i = 0; i < num_inputs; ++i) {
2364 std::ostringstream ss;
2365 ss <<
"Check " << inputs[i];
2366 SECTION(ss.str(),
"") {
2367 double cp_val =
CoolProp::PropsSI(inputs[i],
"P", 101325,
"T", 298,
"HEOS::Water");
2368 double rp_val =
CoolProp::PropsSI(inputs[i],
"P", 101325,
"T", 298,
"REFPROP::Water");
2372 double err = std::abs((cp_val - rp_val) / cp_val);