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
49 # define _CRTDBG_MAP_ALLOC
50 # ifndef _CRT_SECURE_NO_WARNINGS
51 # define _CRT_SECURE_NO_WARNINGS
54 # include <sys/stat.h>
56 # include <sys/stat.h>
61 static bool dbg_refprop =
false;
62 static const unsigned int number_of_endings = 5;
63 std::string
endings[number_of_endings] = {
"",
".FLD",
".fld",
".PPF",
".ppf"};
65 static char default_reference_state[] =
"DEF";
68 #if defined(__powerpc__) || defined(__ISLINUX__) || defined(__ISAPPLE__)
69 char refpropPath[] =
"/opt/refprop";
70 #elif defined(__ISWINDOWS__)
71 char refpropPath[] =
"";
78 std::string joined =
join_path(root,
"fluids");
82 std::string ucase_joined =
join_path(root,
"FLUIDS");
86 throw CoolProp::ValueError(
format(
"fluid directories \"FLUIDS\" or \"fluids\" could not be found in the directory [%s]", root));
91 std::string rpPath = refpropPath;
94 if (!alt_refprop_path.empty()) {
104 #if defined(__ISWINDOWS__)
106 #elif defined(__ISLINUX__) || defined(__ISAPPLE__)
114 std::string rpPath = refpropPath;
118 if (!alt_refprop_path.empty()) {
126 return join_path(alt_refprop_path,
"mixtures");
128 #if defined(__ISWINDOWS__)
130 #elif defined(__ISLINUX__) || defined(__ISAPPLE__)
142 if (!alt_hmx_bnc_path.empty()) {
143 return alt_hmx_bnc_path;
157 if (fluid_names.size() == 1) {
208 if (RefpropdllInstance != NULL)
return true;
213 std::string rpv(STRINGIFY(RPVersion));
214 if (rpv.compare(
"NOTAVAILABLE") != 0) {
219 const std::string alt_rp_name =
get_config_string(ALTERNATIVE_REFPROP_LIBRARY_PATH);
220 bool loaded_REFPROP =
false;
221 if (!alt_rp_name.empty()) {
222 loaded_REFPROP = ::load_REFPROP(err,
"", alt_rp_name);
224 if (alt_rp_path.empty()) {
225 loaded_REFPROP = ::load_REFPROP(err, refpropPath,
"");
227 loaded_REFPROP = ::load_REFPROP(err, alt_rp_path,
"");
231 if (loaded_REFPROP) {
234 printf(
"Good news: It is possible to use REFPROP on your system! However, the library \n");
235 printf(
"could not be loaded. Please make sure that REFPROP is available on your system.\n\n");
236 printf(
"Neither found in current location nor found in system PATH.\n");
237 printf(
"If you already obtained a copy of REFPROP from http://www.nist.gov/srd/, \n");
238 printf(
"add location of REFPROP to the PATH environment variable or your library path.\n\n");
239 printf(
"In case you do not use Windows, have a look at https://github.com/jowr/librefprop.so \n");
240 printf(
"to find instructions on how to compile your own version of the REFPROP library.\n\n");
241 printf(
"ALTERNATIVE_REFPROP_PATH: %s\n", alt_rp_path.c_str());
242 printf(
"ERROR: %s\n", err.c_str());
260 char fluids[10000] =
"", hmx[] =
"HMX.BNC", default_reference_state[] =
"DEF", herr[255] =
"";
265 for (
int i = 0; i < 255; ++i) {
268 SETUPdll(&N, fluids, hmx, default_reference_state, &ierr, herr,
274 if (strlen(herr) == 0) {
275 return format(
"%g", ((
double)ierr) / 10000.0);
277 std::string s(herr, herr + 254);
285 if (!cached_component_string.empty() &&
LoadedREFPROPRef == cached_component_string) {
287 std::cout <<
format(
"%s:%d: The current fluid can be reused; %s and %s match \n", __FILE__, __LINE__, cached_component_string.c_str(),
291 std::cout <<
format(
"%s:%d: The current fluid can be reused; %s and %s match \n", __FILE__, __LINE__, cached_component_string.c_str(),
293 int N =
static_cast<int>(this->fluid_names.size());
295 throw ValueError(
format(
"Size of fluid vector [%d] is larger than the maximum defined by REFPROP [%d]",
fluid_names.size(), ncmax));
305 char component_string[10000], herr[errormessagelength];
314 const char* _HMX_path = HMX_path.c_str();
315 if (strlen(_HMX_path) > refpropcharlength) {
316 throw ValueError(
format(
"Full HMX path (%s) is too long; max length is 255 characters", _HMX_path));
318 strcpy(hmx_bnc, _HMX_path);
324 GERG04dll(&N, &iflag, &ierr, herr, 255);
332 if (N == 1 &&
upper(components_joined_raw).find(
".MIX") != std::string::npos) {
335 std::vector<double> x(ncmax);
336 char mix[255], reference_state[4] =
"DEF";
339 const char* _components_joined_raw = path_to_MIX_file.c_str();
340 if (strlen(_components_joined_raw) > 255) {
341 throw ValueError(
format(
"components (%s) is too long", components_joined_raw.c_str()));
343 strcpy(mix, _components_joined_raw);
345 SETMIXdll(mix, hmx_bnc, reference_state, &N, component_string, &(x[0]), &ierr, herr, 255, 255, 3, 10000, 255);
346 if (
static_cast<int>(ierr) <= 0) {
352 cached_component_string = mix;
353 this->fluid_names.clear();
354 this->fluid_names.push_back(components_joined_raw);
356 std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
358 if (dbg_refprop) std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
359 if (
get_config_bool(REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS) && ierr == -117) {
360 throw ValueError(
format(
"Interaction parameter estimation has been disabled: %s", herr));
373 std::cout <<
format(
"%s:%d Unable to load predefined mixture [%s] with ierr: [%d] and herr: [%s]\n", __FILE__, __LINE__, mix,
376 throw ValueError(
format(
"Unable to load mixture: %s", components_joined_raw.c_str()));
381 for (
unsigned int k = 0; k < number_of_endings; k++) {
383 for (
unsigned int j = 0; j < (
unsigned int)N; j++) {
392 std::cout <<
format(
"%s:%d: The fluid %s has not been loaded before, current value is %s \n", __FILE__, __LINE__,
396 const char* _components_joined = components_joined.c_str();
397 if (strlen(_components_joined) > 10000) {
398 throw ValueError(
format(
"components_joined (%s) is too long", _components_joined));
400 strcpy(component_string, _components_joined);
402 for (
int i =
static_cast<int>(components_joined.size()); i < 10000; ++i) {
403 component_string[i] =
' ';
408 SETUPdll(&N, component_string, hmx_bnc, default_reference_state, &ierr, herr,
414 if (
get_config_bool(REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS) && ierr == -117) {
415 throw ValueError(
format(
"Interaction parameter estimation has been disabled: %s", herr));
417 if (
get_config_bool(REFPROP_IGNORE_ERROR_ESTIMATED_INTERACTION_PARAMETERS) && ierr == 117) {
420 if (
static_cast<int>(ierr) <= 0)
427 cached_component_string = _components_joined;
429 std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
431 if (dbg_refprop) std::cout <<
format(
"%s:%d: Successfully loaded REFPROP fluid: %s\n", __FILE__, __LINE__, components_joined.c_str());
441 }
else if (k < number_of_endings - 1) {
443 std::cout <<
format(
"REFPROP error/warning [ierr: %d]: %s", ierr, herr) << std::endl;
448 std::cout <<
format(
"k: %d #endings: %d", k, number_of_endings) << std::endl;
450 throw ValueError(
format(
"Could not load these fluids: %s", components_joined_raw.c_str()));
456 if (ParamName ==
"CAS") {
467 std::vector<std::string> CASvec;
468 for (
int icomp = 1L; icomp <= static_cast<int>(
fluid_names.size()); ++icomp) {
469 char hnam[13], hn80[81], hcasn[13];
470 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
472 std::string casn = hcasn;
474 CASvec.push_back(casn);
477 }
else if (ParamName ==
"name") {
479 char hnam[13], hn80[81], hcasn[13];
480 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
482 std::string
name = hnam;
485 }
else if (ParamName ==
"long_name") {
487 char hnam[13], hn80[81], hcasn[13];
488 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
490 std::string n80 = hn80;
494 throw ValueError(
format(
"parameter to fluid_param_string is invalid: %s", ParamName.c_str()));
498 for (
int icomp = 1L; icomp <= static_cast<int>(
fluid_names.size()); ++icomp) {
499 char hnam[13], hn80[81], hcasn[13];
500 NAMEdll(&icomp, hnam, hn80, hcasn, 12, 80, 12);
502 std::string casn = hcasn;
512 const double value) {
525 char hmodij[4], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
532 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
534 std::string shmodij(hmodij);
535 if (shmodij.find(
"KW") == 0 || shmodij.find(
"GE") == 0)
537 if (parameter ==
"model") {
540 throw ValueError(
format(
" I don't know what to do with your parameter [%s]", parameter.c_str()));
550 const std::string& value) {
552 if (i < 0 || i >=
Ncomp) {
553 if (j < 0 || j >=
Ncomp) {
554 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
Ncomp-1));
558 }
else if (j < 0 || j >=
Ncomp) {
561 int icomp =
static_cast<int>(i) + 1, jcomp =
static_cast<int>(j) + 1, ierr = 0L;
562 char hmodij[4], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
567 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
569 if (parameter ==
"model") {
570 if (value.length() > 4) {
571 throw ValueError(
format(
"Model parameter (%s) is longer than 4 characters.", value));
573 strcpy(hmodij, value.c_str());
576 throw ValueError(
format(
"I don't know what to do with your parameter [%s]", parameter.c_str()));
578 SETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, &ierr, herr, 3, 255, 255);
580 throw ValueError(
format(
"Unable to set parameter[%s] to value[%s]: %s", parameter.c_str(), value.c_str(), herr));
585 const double value) {
587 if (i < 0 || i >=
Ncomp) {
588 if (j < 0 || j >=
Ncomp) {
589 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
Ncomp-1));
593 }
else if (j < 0 || j >=
Ncomp) {
596 int icomp =
static_cast<int>(i) + 1, jcomp =
static_cast<int>(j) + 1, ierr = 0L;
597 char hmodij[4], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
602 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
604 std::string shmodij(hmodij);
605 if (shmodij.find(
"KW") == 0 || shmodij.find(
"GE") == 0)
607 if (parameter ==
"betaT") {
609 }
else if (parameter ==
"gammaT") {
611 }
else if (parameter ==
"betaV") {
613 }
else if (parameter ==
"gammaV") {
615 }
else if (parameter ==
"Fij") {
618 throw ValueError(
format(
"I don't know what to do with your parameter [%s]", parameter.c_str()));
620 SETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, &ierr, herr, 3, 255, 255);
622 throw ValueError(
format(
"Unable to set parameter[%s] to value[%g]: %s", parameter.c_str(), value, herr));
625 throw ValueError(
format(
"For now, model [%s] must start with KW or GE", hmodij));
632 if (i < 0 || i >=
Ncomp) {
633 if (j < 0 || j >=
Ncomp) {
634 throw ValueError(
format(
"Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j,
Ncomp-1));
638 }
else if (j < 0 || j >=
Ncomp) {
641 int icomp =
static_cast<int>(i) + 1, jcomp =
static_cast<int>(j) + 1;
642 char hmodij[4], hfmix[255], hbinp[255], hfij[255], hmxrul[255];
646 GETKTVdll(&icomp, &jcomp, hmodij, fij, hfmix, hfij, hbinp, hmxrul, 3, 255, 255, 255, 255);
648 std::string shmodij(hmodij);
649 if (shmodij.find(
"KW") == 0 || shmodij.find(
"GE") == 0)
652 if (parameter ==
"betaT") {
654 }
else if (parameter ==
"gammaT") {
656 }
else if (parameter ==
"betaV") {
658 }
else if (parameter ==
"gammaV") {
660 }
else if (parameter ==
"Fij") {
663 throw ValueError(
format(
" I don't know what to do with your parameter [%s]", parameter.c_str()));
675 format(
"Size of mole fraction vector [%d] does not equal that of component vector [%d]",
mole_fractions.size(), this->Ncomp));
677 this->mole_fractions = std::vector<CoolPropDbl>(ncmax, 0.0);
688 format(
"size of mass fraction vector [%d] does not equal that of component vector [%d]",
mass_fractions.size(), this->Ncomp));
690 std::vector<double> moles(this->
Ncomp);
691 double sum_moles = 0.0;
692 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
693 for (
int i = 1L; i <= static_cast<int>(this->
Ncomp); ++i) {
694 INFOdll(&i, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
695 moles[i - 1] =
static_cast<double>(
mass_fractions[i - 1]) / (wmm / 1000.0);
696 sum_moles += moles[i - 1];
698 for (std::size_t i = 0; i < this->
Ncomp; ++i) {
699 moles[i] = moles[i] / sum_moles;
705 throw ValueError(
"Mole fractions not yet set");
734 double Dmax_mol_L, pmax_kPa;
737 pmax = pmax_kPa * 1000;
738 rhomolarmax = Dmax_mol_L * 1000;
759 double Tcrit, pcrit_kPa, dcrit_mol_L;
760 CRITPdll(&(
mole_fractions[0]), &Tcrit, &pcrit_kPa, &dcrit_mol_L, &ierr, herr, 255);
761 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
770 double Tcrit, pcrit_kPa, dcrit_mol_L;
771 CRITPdll(&(
mole_fractions[0]), &Tcrit, &pcrit_kPa, &dcrit_mol_L, &ierr, herr, 255);
772 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
780 double Tcrit, pcrit_kPa, dcrit_mol_L;
781 CRITPdll(&(
mole_fractions[0]), &Tcrit, &pcrit_kPa, &dcrit_mol_L, &ierr, herr, 255);
782 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
785 return static_cast<CoolPropDbl>(dcrit_mol_L * 1000);
789 double rhored_mol_L = 0, Tr = 0;
796 double rhored_mol_L = 0, Tr = 0;
802 double rhored_mol_L = 0, Tr = 0;
804 return static_cast<CoolPropDbl>(rhored_mol_L * 1000);
809 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
814 INFOdll(&icomp, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
817 throw CoolProp::ValueError(
"acentric factor only available for pure components in REFPROP backend");
839 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
844 INFOdll(&icomp, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
854 double p_kPa = _HUGE;
855 double rho_mol_L = _HUGE, rhoLmol_L = _HUGE, rhoVmol_L = _HUGE, hmol = _HUGE, emol = _HUGE, smol = _HUGE, cvmol = _HUGE, cpmol = _HUGE, w = _HUGE;
857 char herr[errormessagelength + 1];
859 double __T =
Ttriple(), __Q = 0;
862 &emol, &hmol, &smol, &cvmol, &cpmol, &w,
863 &ierr, herr, errormessagelength);
864 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
888 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
893 INFOdll(&icomp, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
894 return static_cast<CoolPropDbl>(dip * 3.33564e-30);
896 throw ValueError(
format(
"dipole moment is only available for pure fluids"));
931 double tmin, tmax, Dmax_mol_L, pmax_kPa, Tmax_melt;
933 LIMITSdll(htyp, &(
mole_fractions[0]), &tmin, &tmax, &Dmax_mol_L, &pmax_kPa, 3);
935 MELTPdll(&pmax_kPa, &(
mole_fractions[0]), &Tmax_melt, &ierr, herr, errormessagelength);
936 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
947 if (param ==
iP && given ==
iT) {
948 double _T =
static_cast<double>(value), p_kPa;
949 MELTTdll(&
_T, &(
mole_fractions[0]), &p_kPa, &ierr, herr, errormessagelength);
950 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
954 }
else if (param ==
iT && given ==
iP) {
955 double p_kPa =
static_cast<double>(value) / 1000.0,
_T;
956 MELTPdll(&p_kPa, &(
mole_fractions[0]), &
_T, &ierr, herr, errormessagelength);
957 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
971 double _T = 300, p_kPa;
972 MELTTdll(&
_T, &(
mole_fractions[0]), &p_kPa, &ierr, herr, errormessagelength);
973 if (
static_cast<int>(ierr) == 1) {
985 double wmm, ttrp, tnbpt, tc, pc, Dc, Zc, acf, dip, Rgas;
989 INFOdll(&i, &wmm, &ttrp, &tnbpt, &tc, &pc, &Dc, &Zc, &acf, &dip, &Rgas);
1000 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,
1001 drhodT = 0, drhodP = 0, d2PT2 = 0, d2PdTD = 0, spare3 = 0, spare4 = 0;
1005 THERM2dll(&t, &rho, &(
mole_fractions[0]), &
p, &e, &h, &s, &cv, &cp, &w, &Z, &hjt, &A, &G, &xkappa, &beta, &dPdrho, &d2PdD2, &dPT, &drhodT,
1006 &drhodP, &d2PT2, &d2PdTD, &spare3, &spare4);
1007 return 2 - rho * (d2PdTD / dPT - d2PdD2 / dPdrho);
1012 double eta, tcx, rhomol_L = 0.001 *
_rhomolar;
1017 &ierr, herr, errormessagelength);
1018 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1033 double sigma, rho_mol_L = 0.001 *
_rhomolar;
1038 &ierr, herr, errormessagelength);
1039 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1050 std::vector<double> fug_cof;
1055 &ierr, herr, errormessagelength);
1056 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1070 &ierr, herr, errormessagelength);
1071 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1085 &ierr, herr, errormessagelength);
1086 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1095 double rhoymin, rhoymax, c = 0;
1099 &ierr, herr, errormessagelength);
1100 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1125 int isp = 0, iderv = -1;
1126 if (SPLNVALdll == NULL) {
1129 format(
"Your version of REFFPROP(%s) does not have the SPLNVALdll function; cannot extract phase envelope values", rpv.c_str()));
1131 SPLNVALdll(&isp, &iderv, &c, &rhoymin, &ierr, herr, errormessagelength);
1133 SPLNVALdll(&isp, &iderv, &c, &rhoymax, &ierr, herr, errormessagelength);
1134 int nc = this->
Ncomp;
1135 double ratio = pow(rhoymax / rhoymin, 1 /
double(N));
1136 for (
double rho_molL = rhoymin; rho_molL < rhoymax; rho_molL *= ratio) {
1142 for (isp = 1; isp <= nc; ++isp) {
1143 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1149 PhaseEnvelope.lnrhomolar_vap.push_back(log(rho_molL * 1000));
1151 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1156 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1160 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1163 PhaseEnvelope.Q.push_back(
static_cast<double>(y > rho_molL));
1165 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1168 SPLNVALdll(&isp, &iderv, &rho_molL, &y, &ierr, herr, errormessagelength);
1174 double p_kPa, emol, hmol, smol, cvmol, cpmol, w, hjt, eta, tcx;
1176 THERMdll(&
T, &rho_molL, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1182 &ierr, herr, errormessagelength);
1190 double p0, e0, h0, s0, cv0, cp0, w0, A0, G0;
1191 THERM0dll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p0, &e0, &h0, &s0, &cv0, &cp0, &w0, &A0, &G0);
1198 if ((
_Q >= 0.00) && (
_Q <= 1.00)) {
1200 }
else if (
_Q > 1.00) {
1205 }
else if (
_Q < 0.00) {
1214 if ((
_Q == 999) || (
_Q == -997)) {
1229 double rho_mol_L = _HUGE, rhoLmol_L = _HUGE, rhoVmol_L = _HUGE, hmol = _HUGE, emol = _HUGE, smol = _HUGE, cvmol = _HUGE, cpmol = _HUGE, w = _HUGE,
1230 q = _HUGE, mm = _HUGE, p_kPa = _HUGE, hjt = _HUGE;
1232 char herr[errormessagelength + 1] =
" ";
1243 switch (input_pair) {
1246 p_kPa = 0.001 * value1;
1253 &q, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1254 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1280 int kph = -10, kguess = 0;
1286 throw ValueError(
format(
"PT: cannot use this imposed phase for PT inputs"));
1289 TPRHOdll(&
_T, &p_kPa, &(
mole_fractions[0]), &kph, &kguess, &rho_mol_L, &ierr, herr, errormessagelength);
1292 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1305 rho_mol_L = 0.001 * value1;
1312 &q, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1313 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1319 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1336 rho_mol_L = 0.001 * value1;
1337 p_kPa = 0.001 * value2;
1343 &q, &emol, &hmol, &smol, &cvmol, &cpmol, &w,
1344 &ierr, herr, errormessagelength);
1345 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1365 rho_mol_L = 0.001 * value1;
1372 &q, &emol, &smol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1373 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1393 rho_mol_L = 0.001 * value1;
1400 &q, &emol, &hmol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1401 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1421 rho_mol_L = 0.001 * value1;
1428 &q, &hmol, &hmol, &cvmol, &cpmol, &w, &ierr, herr, errormessagelength);
1429 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1449 p_kPa = 0.001 * value2;
1454 &q, &emol, &smol, &cvmol, &cpmol, &w,
1455 &ierr, herr, errormessagelength);
1456 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1475 p_kPa = 0.001 * value1;
1481 &q, &emol, &hmol, &cvmol, &cpmol, &w,
1482 &ierr, herr, errormessagelength);
1484 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1503 p_kPa = 0.001 * value1;
1510 &q, &hmol, &smol, &cvmol, &cpmol, &w,
1511 &ierr, herr, errormessagelength);
1513 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1537 &q, &emol, &cvmol, &cpmol, &w,
1538 &ierr, herr, errormessagelength);
1540 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1566 &q, &smol, &cvmol, &cpmol, &w,
1567 &ierr, herr, errormessagelength);
1569 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1603 &q, &emol, &hmol, &cvmol, &cpmol, &w,
1604 &ierr, herr, errormessagelength);
1606 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1639 &q, &emol, &smol, &cvmol, &cpmol, &w,
1640 &ierr, herr, errormessagelength);
1642 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1675 &q, &hmol, &smol, &cvmol, &cpmol, &w,
1676 &ierr, herr, errormessagelength);
1678 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1723 p_kPa = 0.001 * value1;
1726 int iFlsh = 0, iGuess = 0, ierr = 0;
1727 if (std::abs(q) < 1e-10) {
1729 }
else if (std::abs(q - 1) < 1e-10) {
1747 herr, errormessagelength);
1748 rho_mol_L = (iFlsh == 1) ? rhoLmol_L : rhoVmol_L;
1752 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1755 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD) || iFlsh == 0) {
1766 &emol, &hmol, &smol, &cvmol, &cpmol, &w,
1767 &ierr, herr, errormessagelength);
1770 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1787 int iFlsh = 0, iGuess = 0;
1788 if (std::abs(q) < 1e-10) {
1790 }
else if (std::abs(q - 1) < 1e-10) {
1809 &ierr, herr, errormessagelength);
1810 rho_mol_L = (iFlsh == 1) ? rhoLmol_L : rhoVmol_L;
1814 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1817 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD) || iFlsh == 0) {
1828 &emol, &hmol, &smol, &cvmol, &cpmol, &w,
1829 &ierr, herr, errormessagelength);
1832 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1867 double rho_mol_L = _HUGE, hmol = _HUGE, emol = _HUGE, smol = _HUGE, cvmol = _HUGE, cpmol = _HUGE, w = _HUGE, q = _HUGE, p_kPa = _HUGE,
1870 char herr[errormessagelength + 1];
1877 switch (input_pair) {
1880 p_kPa = 0.001 * value1;
1892 rho_mol_L = guesses.
rhomolar / 1000.0;
1893 TPRHOdll(&
_T, &p_kPa, &(
mole_fractions[0]), &kph, &kguess, &rho_mol_L, &ierr, herr, errormessagelength);
1894 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1905 p_kPa = 0.001 * value1;
1907 double rhoLmol_L = -1, rhoVmol_L = -1;
1912 if (std::abs(value2) < 1e-10) {
1914 if (!guesses.
x.empty()) {
1922 }
else if (std::abs(value2 - 1) < 1e-10) {
1924 if (!guesses.
y.empty()) {
1936 std::cout <<
format(
"guesses.T: %g\n", guesses.
T);
1948 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
1963 THERMdll(&
_T, &rho_mol_L, &(
mole_fractions[0]), &p_kPa, &emol, &hmol, &smol, &cvmol, &cpmol, &w, &hjt);
1979 if (PHIXdll == NULL) {
1980 throw ValueError(
"PHIXdll function is not available in your version of REFPROP. Please upgrade");
1988 if (PHI0dll == NULL) {
1989 throw ValueError(
"PHI0dll function is not available in your version of REFPROP. Please upgrade");
1999 double T_K =
_T, p_kPa =
_p / 1000.0, rho = 1, vE = -1, eE = -1, hE = -1, sE = -1, aE = -1, gE = -1;
2025 EXCESSdll(&T_K, &p_kPa, &(
mole_fractions[0]), &kph, &rho, &vE, &eE, &hE, &sE, &aE, &gE, &ierr, herr, errormessagelength);
2026 if (
static_cast<int>(ierr) >
get_config_int(REFPROP_ERROR_THRESHOLD)) {
2042 const std::vector<double> z;
2043 wrapper(
const std::vector<double>& z) : z(z){};
2044 std::vector<double> call(
const std::vector<double>& x) {
2045 std::vector<double> r(2);
2046 double dpdrho__constT = _HUGE, d2pdrho2__constT = _HUGE;
2047 DPDDdll(
const_cast<double*
>(&(x[0])),
const_cast<double*
>(&(x[1])),
const_cast<double*
>(&(z[0])), &dpdrho__constT);
2048 DPDD2dll(
const_cast<double*
>(&(x[0])),
const_cast<double*
>(&(x[1])),
const_cast<double*
>(&(z[0])), &d2pdrho2__constT);
2049 r[0] = dpdrho__constT;
2050 r[1] = d2pdrho2__constT;
2058 std::vector<double> x(2,
T);
2062 rho = xfinal[1] * 1000.0;
2069 }
else if (key ==
iDmass) {
2072 double wmm_kg_kmol = 0;
2074 return wmm_kg_kmol / 1000;
2076 throw ValueError(
"Invalid parameter. Only mass and molar density are available with RefProp");
2080 throw ValueError(
"The saturated liquid state has not been set.");
2087 }
else if (key ==
iDmass) {
2090 double wmm_kg_kmol = 0;
2092 return wmm_kg_kmol / 1000;
2098 throw ValueError(
"The saturated vapor state has not been set.");
2103 if (type ==
"Joule-Thomson") {
2106 }
else if (type ==
"Joule-Inversion") {
2109 }
else if (type ==
"Ideal") {
2112 }
else if (type ==
"Boyle") {
2122 if (!load_REFPROP(err)) {
2124 std::cout <<
format(
"Error while loading REFPROP: %s", err) << std::endl;
2135 if (!unload_REFPROP(err)) {
2137 std::cout <<
format(
"Error while unloading REFPROP: %s", err) << std::endl;
2147 void 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,
2150 bool loaded_REFPROP = ::load_REFPROP(err);
2151 if (!loaded_REFPROP) {
2152 throw ValueError(
format(
"Not able to load REFPROP; err is: %s", err.c_str()));
2154 SETREFdll(hrf, &ixflag, x0, &h0, &s0, &T0, &p0, &ierr, herr, l1, l2);
2161 # include <catch2/catch_all.hpp>
2163 TEST_CASE(
"Check REFPROP and CoolProp values agree",
"[REFPROP]") {
2164 SECTION(
"Saturation densities agree within 0.5% at T/Tc = 0.9") {
2167 for (std::vector<std::string>::iterator it = ss.begin(); it != ss.end(); ++it) {
2168 std::string Name = (*it);
2172 if (RPName.find(
"N/A") == 0) {
2177 double Tr = S1->T_critical();
2179 double rho_CP = S1->rhomolar();
2183 double rho_RP = S2->rhomolar();
2190 double DH = (rho_RP - rho_CP) / rho_RP;
2191 CHECK(std::abs(DH) < 0.05);
2194 SECTION(
"Saturation specific heats agree within 0.5% at T/Tc = 0.9") {
2197 for (std::vector<std::string>::iterator it = ss.begin(); it != ss.end(); ++it) {
2198 std::string Name = (*it);
2202 if (RPName.find(
"N/A") == 0) {
2207 double Tr = S1->T_critical();
2209 double cp_CP = S1->cpmolar();
2213 double cp_RP = S2->cpmolar();
2221 double Dcp = (cp_RP - cp_CP) / cp_RP;
2222 CHECK(std::abs(Dcp) < 0.05);
2225 SECTION(
"Enthalpy and entropy reference state") {
2228 for (std::vector<std::string>::iterator it = ss.begin(); it != ss.end(); ++it) {
2229 std::string Name = (*it);
2233 if (RPName.find(
"N/A") == 0) {
2238 double Tr = S1->T_critical();
2240 double h_CP = S1->hmass();
2241 double s_CP = S1->smass();
2245 double h_RP = S2->hmass();
2246 double s_RP = S2->smass();
2248 double delta_a1 = (s_CP - s_RP) / (S1->gas_constant() / S1->molar_mass());
2249 double delta_a2 = -(h_CP - h_RP) / (S1->gas_constant() / S1->molar_mass() * S1->get_reducing_state().T);
2250 CAPTURE(
format(
"%0.16f", delta_a1));
2251 CAPTURE(
format(
"%0.16f", delta_a2));
2259 double DH = (S1->hmass() - S2->hmass());
2260 double DS = (S1->smass() - S2->smass());
2262 CHECK(std::abs(DH / h_RP) < 0.01);
2263 CHECK(std::abs(DS / s_RP) < 0.01);
2268 TEST_CASE(
"Check trivial inputs for REFPROP work",
"[REFPROP_trivial]") {
2269 const int num_inputs = 6;
2270 std::string inputs[num_inputs] = {
"T_triple",
"T_critical",
"p_critical",
"molar_mass",
"rhomolar_critical",
"rhomass_critical"};
2271 for (
int i = 0; i < num_inputs; ++i) {
2272 std::ostringstream ss;
2273 ss <<
"Check " << inputs[i];
2274 SECTION(ss.str(),
"") {
2280 double err = (cp_val - rp_val) / cp_val;
2286 TEST_CASE(
"Check PHI0 derivatives",
"[REFPROP_PHI0]") {
2288 const int num_inputs = 3;
2289 std::string inputs[num_inputs] = {
"DALPHA0_DDELTA_CONSTTAU",
"D2ALPHA0_DDELTA2_CONSTTAU",
"D3ALPHA0_DDELTA3_CONSTTAU"};
2290 for (
int i = 0; i < num_inputs; ++i) {
2291 std::ostringstream ss;
2292 ss <<
"Check " << inputs[i];
2293 SECTION(ss.str(),
"") {
2294 double cp_val =
CoolProp::PropsSI(inputs[i],
"P", 101325,
"T", 298,
"HEOS::Water");
2295 double rp_val =
CoolProp::PropsSI(inputs[i],
"P", 101325,
"T", 298,
"REFPROP::Water");
2299 double err = std::abs((cp_val - rp_val) / cp_val);