2 # ifndef _CRT_SECURE_NO_WARNINGS
3 # define _CRT_SECURE_NO_WARNINGS
27 #include "externals/IF97/IF97.h"
30 std::size_t
strcmp(
const std::string& s,
const std::string& e) {
33 std::size_t
strcmp(
const std::string& s,
const char* e) {
36 std::size_t
strcmp(
const char* e,
const std::string& s) {
41 void strcpy(std::string& s,
const std::string& e) {
45 shared_ptr<CoolProp::HelmholtzEOSBackend>
Water,
Air;
79 #if !defined(NO_FMTLIB) && FMT_VERSION >= 90000
80 int format_as(
givens given) {
81 return fmt::underlying(given);
85 void _HAPropsSI_inputs(
double p,
const std::vector<givens>& input_keys,
const std::vector<double>& input_vals,
double& T,
double& psi_w);
101 static double epsilon = 0.621945, R_bar = 8.314472;
102 static int FlagUseVirialCorrelations = 0, FlagUseIsothermCompressCorrelation = 0, FlagUseIdealGasEnthalpyCorrelations = 0;
103 double f_factor(
double T,
double p);
106 static inline bool check_bounds(
const givens prop,
const double& value,
double& min_val,
double& max_val) {
121 min_val = -143.15 + 273.15;
122 max_val = 350 + 273.15;
141 bool ret = !((value < min_val) || (value > max_val));
146 static double MM_Air(
void) {
150 static double MM_Water(
void) {
154 static double B_Air(
double T) {
157 Air->update_DmolarT_direct(1e-12, T);
158 Air->unspecify_phase();
161 static double dBdT_Air(
double T) {
164 Air->update_DmolarT_direct(1e-12, T);
165 Air->unspecify_phase();
168 static double B_Water(
double T) {
171 Water->update_DmolarT_direct(1e-12, T);
172 Water->unspecify_phase();
175 static double dBdT_Water(
double T) {
178 Water->update_DmolarT_direct(1e-12, T);
179 Water->unspecify_phase();
182 static double C_Air(
double T) {
185 Air->update_DmolarT_direct(1e-12, T);
186 Air->unspecify_phase();
189 static double dCdT_Air(
double T) {
192 Air->update_DmolarT_direct(1e-12, T);
193 Air->unspecify_phase();
196 static double C_Water(
double T) {
199 Water->update_DmolarT_direct(1e-12, T);
200 Water->unspecify_phase();
203 static double dCdT_Water(
double T) {
206 Water->update_DmolarT_direct(1e-12, T);
207 Water->unspecify_phase();
211 if (flag == 0 || flag == 1) {
212 FlagUseVirialCorrelations = flag;
214 printf(
"UseVirialCorrelations takes an integer, either 0 (no) or 1 (yes)\n");
218 if (flag == 0 || flag == 1) {
219 FlagUseIsothermCompressCorrelation = flag;
221 printf(
"UseIsothermCompressCorrelation takes an integer, either 0 (no) or 1 (yes)\n");
225 if (flag == 0 || flag == 1) {
226 FlagUseIdealGasEnthalpyCorrelations = flag;
228 printf(
"UseIdealGasEnthalpyCorrelations takes an integer, either 0 (no) or 1 (yes)\n");
231 static double Brent_HAProps_W(
givens OutputKey,
double p,
givens In1Name,
double Input1,
double TargetVal,
double W_min,
double W_max) {
240 double Input1, TargetVal;
241 std::vector<givens> input_keys;
242 std::vector<double> input_vals;
245 BrentSolverResids(
givens OutputKey,
double p,
givens In1Key,
double Input1,
double TargetVal)
246 : OutputKey(OutputKey), p(p), In1Key(In1Key), Input1(Input1), TargetVal(TargetVal) {
247 input_keys.resize(2);
248 input_keys[0] = In1Key;
250 input_vals.resize(2);
251 input_vals[0] = Input1;
254 double call(
double W) {
256 double T = _HUGE, psi_w = _HUGE;
259 std::cout <<
format(
"T: %g K, psi_w %g\n", T, psi_w);
265 BrentSolverResids BSR = BrentSolverResids(OutputKey, p, In1Name, Input1, TargetVal);
269 double r_min = BSR.call(W_min);
271 double r_max = BSR.call(W_max);
273 if (!W_min_valid && !W_max_valid) {
274 throw CoolProp::ValueError(
format(
"Both W_min [%g] and W_max [%g] yield invalid output values in Brent_HAProps_W", W_min, W_max).c_str());
275 }
else if (W_min_valid && !W_max_valid) {
276 while (!W_max_valid) {
278 W_max = 0.95 * W_max + 0.05 * W_min;
279 r_max = BSR.call(W_max);
282 }
else if (!W_min_valid && W_max_valid) {
283 while (!W_min_valid) {
285 W_min = 0.95 * W_min + 0.05 * W_max;
286 r_min = BSR.call(W_min);
291 if (r_min * r_max > 0) {
292 if (std::abs(r_min) < std::abs(r_max)) {
302 static double Brent_HAProps_T(
givens OutputKey,
double p,
givens In1Name,
double Input1,
double TargetVal,
double T_min,
double T_max) {
310 double Input1, TargetVal;
311 std::vector<givens> input_keys;
312 std::vector<double> input_vals;
315 BrentSolverResids(
givens OutputKey,
double p,
givens In1Key,
double Input1,
double TargetVal)
316 : OutputKey(OutputKey), p(p), In1Key(In1Key), Input1(Input1), TargetVal(TargetVal) {
317 input_keys.resize(2);
318 input_keys[0] = In1Key;
320 input_vals.resize(2);
321 input_vals[0] = Input1;
324 double call(
double T_drybulb) {
328 return val - TargetVal;
332 BrentSolverResids BSR = BrentSolverResids(OutputKey, p, In1Name, Input1, TargetVal);
336 double r_min = BSR.call(T_min);
338 double r_max = BSR.call(T_max);
340 if (!T_min_valid && !T_max_valid) {
341 throw CoolProp::ValueError(
format(
"Both T_min [%g] and T_max [%g] yield invalid output values in Brent_HAProps_T", T_min, T_max).c_str());
342 }
else if (T_min_valid && !T_max_valid) {
343 while (!T_max_valid) {
345 T_max = 0.95 * T_max + 0.05 * T_min;
346 r_max = BSR.call(T_max);
349 }
else if (!T_min_valid && T_max_valid) {
350 while (!T_min_valid) {
352 T_min = 0.95 * T_min + 0.05 * T_max;
353 r_min = BSR.call(T_min);
358 if (r_min * r_max > 0) {
359 if (std::abs(r_min) < std::abs(r_max)) {
365 double mach_eps = 1e-15, tol = 1e-10;
370 static double Secant_Tdb_at_saturated_W(
double psi_w,
double p,
double T_guess) {
375 double pp_water, psi_w, p;
378 BrentSolverResids(
double psi_w,
double p) : psi_w(psi_w), p(p) {
379 pp_water = psi_w * p;
381 ~BrentSolverResids(){};
383 double call(
double T) {
387 p_ws = IF97::psat97(T);
393 double pp_water_calc = f * p_ws;
394 double psi_w_calc = pp_water_calc / p;
395 return (psi_w_calc - psi_w) / psi_w;
399 BrentSolverResids Resids(psi_w, p);
406 }
catch (std::exception& e) {
477 static double _B_aw(
double T) {
480 double a[] = {0, 0.665687e2, -0.238834e3, -0.176755e3};
481 double b[] = {0, -0.237, -1.048, -3.183};
482 double rhobarstar = 1000, Tstar = 100;
483 return 1 / rhobarstar * (a[1] * pow(T / Tstar, b[1]) + a[2] * pow(T / Tstar, b[2]) + a[3] * pow(T / Tstar, b[3]))
487 static double _dB_aw_dT(
double T) {
490 double a[] = {0, 0.665687e2, -0.238834e3, -0.176755e3};
491 double b[] = {0, -0.237, -1.048, -3.183};
492 double rhobarstar = 1000, Tstar = 100;
493 return 1 / rhobarstar / Tstar
494 * (a[1] * b[1] * pow(T / Tstar, b[1] - 1) + a[2] * b[2] * pow(T / Tstar, b[2] - 1) + a[3] * b[3] * pow(T / Tstar, b[3] - 1))
498 static double _C_aaw(
double T) {
501 double c[] = {0, 0.482737e3, 0.105678e6, -0.656394e8, 0.294442e11, -0.319317e13};
502 double rhobarstar = 1000, Tstar = 1, summer = 0;
504 for (i = 1; i <= 5; i++) {
505 summer += c[i] * pow(T / Tstar, 1 - i);
507 return 1.0 / rhobarstar / rhobarstar * summer / 1e6;
510 static double _dC_aaw_dT(
double T) {
513 double c[] = {0, 0.482737e3, 0.105678e6, -0.656394e8, 0.294442e11, -0.319317e13};
514 double rhobarstar = 1000, Tstar = 1, summer = 0;
516 for (i = 2; i <= 5; i++) {
517 summer += c[i] * (1 - i) * pow(T / Tstar, -i);
519 return 1.0 / rhobarstar / rhobarstar / Tstar * summer / 1e6;
522 static double _C_aww(
double T) {
525 double d[] = {0, -0.1072887e2, 0.347804e4, -0.383383e6, 0.334060e8};
526 double rhobarstar = 1, Tstar = 1, summer = 0;
528 for (i = 1; i <= 4; i++) {
529 summer += d[i] * pow(T / Tstar, 1 - i);
531 return -1.0 / rhobarstar / rhobarstar * exp(summer) / 1e6;
534 static double _dC_aww_dT(
double T) {
537 double d[] = {0, -0.1072887e2, 0.347804e4, -0.383383e6, 0.334060e8};
538 double rhobarstar = 1, Tstar = 1, summer1 = 0, summer2 = 0;
540 for (i = 1; i <= 4; i++) {
541 summer1 += d[i] * pow(T / Tstar, 1 - i);
543 for (i = 2; i <= 4; i++) {
544 summer2 += d[i] * (1 - i) * pow(T / Tstar, -i);
546 return -1.0 / rhobarstar / rhobarstar / Tstar * exp(summer1) * summer2
550 static double B_m(
double T,
double psi_w) {
552 double B_aa, B_ww, B_aw;
553 if (FlagUseVirialCorrelations == 1) {
554 B_aa = -0.000721183853646 + 1.142682674467e-05 * T - 8.838228412173e-08 * pow(T, 2) + 4.104150642775e-10 * pow(T, 3)
555 - 1.192780880645e-12 * pow(T, 4) + 2.134201312070e-15 * pow(T, 5) - 2.157430412913e-18 * pow(T, 6) + 9.453830907795e-22 * pow(T, 7);
556 B_ww = -10.8963128394 + 2.439761625859e-01 * T - 2.353884845100e-03 * pow(T, 2) + 1.265864734412e-05 * pow(T, 3)
557 - 4.092175700300e-08 * pow(T, 4) + 7.943925411344e-11 * pow(T, 5) - 8.567808759123e-14 * pow(T, 6) + 3.958203548563e-17 * pow(T, 7);
564 return pow(1 - psi_w, 2) * B_aa + 2 * (1 - psi_w) * psi_w * B_aw + psi_w * psi_w * B_ww;
567 static double dB_m_dT(
double T,
double psi_w) {
569 double dB_dT_aa, dB_dT_ww, dB_dT_aw;
570 if (FlagUseVirialCorrelations) {
571 dB_dT_aa = 1.65159324353e-05 - 3.026130954749e-07 * T + 2.558323847166e-09 * pow(T, 2) - 1.250695660784e-11 * pow(T, 3)
572 + 3.759401946106e-14 * pow(T, 4) - 6.889086380822e-17 * pow(T, 5) + 7.089457032972e-20 * pow(T, 6)
573 - 3.149942145971e-23 * pow(T, 7);
574 dB_dT_ww = 0.65615868848 - 1.487953162679e-02 * T + 1.450134660689e-04 * pow(T, 2) - 7.863187630094e-07 * pow(T, 3)
575 + 2.559556607010e-09 * pow(T, 4) - 4.997942221914e-12 * pow(T, 5) + 5.417678681513e-15 * pow(T, 6)
576 - 2.513856275241e-18 * pow(T, 7);
578 dB_dT_aa = dBdT_Air(T);
579 dB_dT_ww = dBdT_Water(T);
581 dB_dT_aw = _dB_aw_dT(T);
582 return pow(1 - psi_w, 2) * dB_dT_aa + 2 * (1 - psi_w) * psi_w * dB_dT_aw + psi_w * psi_w * dB_dT_ww;
585 static double C_m(
double T,
double psi_w) {
587 double C_aaa, C_www, C_aww, C_aaw;
588 if (FlagUseVirialCorrelations) {
589 C_aaa = 1.29192158975e-08 - 1.776054020409e-10 * T + 1.359641176409e-12 * pow(T, 2) - 6.234878717893e-15 * pow(T, 3)
590 + 1.791668730770e-17 * pow(T, 4) - 3.175283581294e-20 * pow(T, 5) + 3.184306136120e-23 * pow(T, 6) - 1.386043640106e-26 * pow(T, 7);
591 C_www = -0.580595811134 + 1.365952762696e-02 * T - 1.375986293288e-04 * pow(T, 2) + 7.687692259692e-07 * pow(T, 3)
592 - 2.571440816920e-09 * pow(T, 4) + 5.147432221082e-12 * pow(T, 5) - 5.708156494894e-15 * pow(T, 6) + 2.704605721778e-18 * pow(T, 7);
599 return pow(1 - psi_w, 3) * C_aaa + 3 * pow(1 - psi_w, 2) * psi_w * C_aaw + 3 * (1 - psi_w) * psi_w * psi_w * C_aww + pow(psi_w, 3) * C_www;
602 static double dC_m_dT(
double T,
double psi_w) {
605 double dC_dT_aaa, dC_dT_www, dC_dT_aww, dC_dT_aaw;
607 if (FlagUseVirialCorrelations) {
608 dC_dT_aaa = -2.46582342273e-10 + 4.425401935447e-12 * T - 3.669987371644e-14 * pow(T, 2) + 1.765891183964e-16 * pow(T, 3)
609 - 5.240097805744e-19 * pow(T, 4) + 9.502177003614e-22 * pow(T, 5) - 9.694252610339e-25 * pow(T, 6)
610 + 4.276261986741e-28 * pow(T, 7);
611 dC_dT_www = 0.0984601196142 - 2.356713397262e-03 * T + 2.409113323685e-05 * pow(T, 2) - 1.363083778715e-07 * pow(T, 3)
612 + 4.609623799524e-10 * pow(T, 4) - 9.316416405390e-13 * pow(T, 5) + 1.041909136255e-15 * pow(T, 6)
613 - 4.973918480607e-19 * pow(T, 7);
615 dC_dT_aaa = dCdT_Air(T);
616 dC_dT_www = dCdT_Water(T);
618 dC_dT_aaw = _dC_aaw_dT(T);
619 dC_dT_aww = _dC_aww_dT(T);
620 return pow(1 - psi_w, 3) * dC_dT_aaa + 3 * pow(1 - psi_w, 2) * psi_w * dC_dT_aaw + 3 * (1 - psi_w) * psi_w * psi_w * dC_dT_aww
621 + pow(psi_w, 3) * dC_dT_www;
624 return psi_w * epsilon / (1 - psi_w);
627 static double HenryConstant(
double T) {
629 double p_ws, beta_N2, beta_O2, beta_Ar, beta_a, tau, Tr, Tc = 647.096;
632 p_ws = IF97::psat97(T);
633 beta_N2 = p_ws * exp(-9.67578 / Tr + 4.72162 * pow(tau, 0.355) / Tr + 11.70585 * pow(Tr, -0.41) * exp(tau));
634 beta_O2 = p_ws * exp(-9.44833 / Tr + 4.43822 * pow(tau, 0.355) / Tr + 11.42005 * pow(Tr, -0.41) * exp(tau));
635 beta_Ar = p_ws * exp(-8.40954 / Tr + 4.29587 * pow(tau, 0.355) / Tr + 10.52779 * pow(Tr, -0.41) * exp(tau));
636 beta_a = 1 / (0.7812 / beta_N2 + 0.2095 / beta_O2 + 0.0093 / beta_Ar);
637 return 1 / (1.01325 * beta_a);
643 if (FlagUseIsothermCompressCorrelation) {
644 k_T = 1.6261876614E-22 * pow(T, 6) - 3.3016385196E-19 * pow(T, 5) + 2.7978984577E-16 * pow(T, 4) - 1.2672392901E-13 * pow(T, 3)
645 + 3.2382864853E-11 * pow(T, 2) - 4.4318979503E-09 * T + 2.5455947289E-07;
658 double f = 0, Rbar = 8.314371, eps = 1e-8;
659 double x1 = 0, x2 = 0, x3, y1 = 0, y2, change = _HUGE;
661 double p_ws, B_aa, B_aw, B_ww, C_aaa, C_aaw, C_aww, C_www, line1, line2, line3, line4, line5, line6, line7, line8, k_T, beta_H, LHS, RHS, psi_ws,
670 beta_H = HenryConstant(T);
687 if (FlagUseVirialCorrelations) {
688 B_aa = -0.000721183853646 + 1.142682674467e-05 * T - 8.838228412173e-08 * pow(T, 2) + 4.104150642775e-10 * pow(T, 3)
689 - 1.192780880645e-12 * pow(T, 4) + 2.134201312070e-15 * pow(T, 5) - 2.157430412913e-18 * pow(T, 6) + 9.453830907795e-22 * pow(T, 7);
690 B_ww = -10.8963128394 + 2.439761625859e-01 * T - 2.353884845100e-03 * pow(T, 2) + 1.265864734412e-05 * pow(T, 3)
691 - 4.092175700300e-08 * pow(T, 4) + 7.943925411344e-11 * pow(T, 5) - 8.567808759123e-14 * pow(T, 6) + 3.958203548563e-17 * pow(T, 7);
692 C_aaa = 1.29192158975e-08 - 1.776054020409e-10 * T + 1.359641176409e-12 * pow(T, 2) - 6.234878717893e-15 * pow(T, 3)
693 + 1.791668730770e-17 * pow(T, 4) - 3.175283581294e-20 * pow(T, 5) + 3.184306136120e-23 * pow(T, 6) - 1.386043640106e-26 * pow(T, 7);
694 C_www = -0.580595811134 + 1.365952762696e-02 * T - 1.375986293288e-04 * pow(T, 2) + 7.687692259692e-07 * pow(T, 3)
695 - 2.571440816920e-09 * pow(T, 4) + 5.147432221082e-12 * pow(T, 5) - 5.708156494894e-15 * pow(T, 6) + 2.704605721778e-18 * pow(T, 7);
708 while ((iter <= 3 || change > eps) && iter < 100) {
714 x2 = 1.00 + 0.000001;
724 psi_ws = f * p_ws / p;
727 line1 = ((1 + k_T * p_ws) * (p - p_ws) - k_T * (p * p - p_ws * p_ws) / 2.0) / (Rbar * T) * vbar_ws + log(1 - beta_H * (1 - psi_ws) * p);
728 line2 = pow(1 - psi_ws, 2) * p / (Rbar * T) * B_aa - 2 * pow(1 - psi_ws, 2) * p / (Rbar * T) * B_aw
729 - (p - p_ws - pow(1 - psi_ws, 2) * p) / (Rbar * T) * B_ww;
730 line3 = pow(1 - psi_ws, 3) * p * p / pow(Rbar * T, 2) * C_aaa
731 + (3 * pow(1 - psi_ws, 2) * (1 - 2 * (1 - psi_ws)) * p * p) / (2 * pow(Rbar * T, 2)) * C_aaw;
732 line4 = -3 * pow(1 - psi_ws, 2) * psi_ws * p * p / pow(Rbar * T, 2) * C_aww
733 - ((3 - 2 * psi_ws) * psi_ws * psi_ws * p * p - p_ws * p_ws) / (2 * pow(Rbar * T, 2)) * C_www;
734 line5 = -(pow(1 - psi_ws, 2) * (-2 + 3 * psi_ws) * psi_ws * p * p) / pow(Rbar * T, 2) * B_aa * B_ww;
735 line6 = -(2 * pow(1 - psi_ws, 3) * (-1 + 3 * psi_ws) * p * p) / pow(Rbar * T, 2) * B_aa * B_aw;
736 line7 = (6 * pow(1 - psi_ws, 2) * psi_ws * psi_ws * p * p) / pow(Rbar * T, 2) * B_ww * B_aw
737 - (3 * pow(1 - psi_ws, 4) * p * p) / (2 * pow(Rbar * T, 2)) * B_aa * B_aa;
738 line8 = -(2 * pow(1 - psi_ws, 2) * psi_ws * (-2 + 3 * psi_ws) * p * p) / pow(Rbar * T, 2) * B_aw * B_aw
739 - (p_ws * p_ws - (4 - 3 * psi_ws) * pow(psi_ws, 3) * p * p) / (2 * pow(Rbar * T, 2)) * B_ww * B_ww;
740 RHS = line1 + line2 + line3 + line4 + line5 + line6 + line7 + line8;
747 x3 = x2 - y2 / (y2 - y1) * (x2 - x1);
748 change = std::abs(y2 / (y2 - y1) * (x2 - x1));
761 printf(
"Sorry, Need to update!");
764 if (!
strcmp(Code,
"GIVEN_TDP"))
766 else if (!
strcmp(Code,
"GIVEN_HUMRAT"))
768 else if (!
strcmp(Code,
"GIVEN_TWB"))
770 else if (!
strcmp(Code,
"GIVEN_RH"))
772 else if (!
strcmp(Code,
"GIVEN_ENTHALPY"))
775 fprintf(stderr,
"Code to returnHumAirCode in HumAir.c [%s] not understood", Code);
787 double mu_a, mu_w, Phi_av, Phi_va, Ma, Mw;
796 Phi_av = sqrt(2.0) / 4.0 * pow(1 + Ma / Mw, -0.5) * pow(1 + sqrt(mu_a / mu_w) * pow(Mw / Ma, 0.25), 2);
797 Phi_va = sqrt(2.0) / 4.0 * pow(1 + Mw / Ma, -0.5) * pow(1 + sqrt(mu_w / mu_a) * pow(Ma / Mw, 0.25), 2);
798 return (1 - psi_w) * mu_a / ((1 - psi_w) + psi_w * Phi_av) + psi_w * mu_w / (psi_w + (1 - psi_w) * Phi_va);
808 double mu_a, mu_w, k_a, k_w, Phi_av, Phi_va, Ma, Mw;
820 Phi_av = sqrt(2.0) / 4.0 * pow(1 + Ma / Mw, -0.5) * pow(1 + sqrt(mu_a / mu_w) * pow(Mw / Ma, 0.25), 2);
821 Phi_va = sqrt(2.0) / 4.0 * pow(1 + Mw / Ma, -0.5) * pow(1 + sqrt(mu_w / mu_a) * pow(Ma / Mw, 0.25), 2);
822 return (1 - psi_w) * k_a / ((1 - psi_w) + psi_w * Phi_av) + psi_w * k_w / (psi_w + (1 - psi_w) * Phi_va);
833 double v_bar0, v_bar = 0, R_bar = 8.314472, x1 = 0, x2 = 0, x3, y1 = 0, y2, resid, eps, Bm, Cm;
840 v_bar0 = R_bar * T / p;
849 while ((iter <= 3 || std::abs(resid) > eps) && iter < 100) {
855 x2 = v_bar0 + 0.000001;
863 resid = (p - (R_bar)*T / v_bar * (1 + Bm / v_bar + Cm / (v_bar * v_bar))) / p;
870 x3 = x2 - y2 / (y2 - y1) * (x2 - x1);
879 double Pressure(
double T,
double v_bar,
double psi_w) {
880 double R_bar = 8.314472;
881 double Bm = B_m(T, psi_w);
882 double Cm = C_m(T, psi_w);
883 return (R_bar)*T / v_bar * (1 + Bm / v_bar + Cm / (v_bar * v_bar));
886 double hbar_w_0, tau, hbar_w;
888 hbar_w_0 = -0.01102303806;
891 double Tref = 473.15, vmolarref = 0.038837428192186184, href = 51885.582451893446;
895 double hoffset = href - href_EOS;
899 Water->update_DmolarT_direct(p / (R_bar * T), T);
900 Water->unspecify_phase();
909 double sbar_w, tau, R_bar;
913 double Tref = 473.15, pref = 101325, sref = 141.18297895840303;
917 double soffset = sref - sref_EOS;
923 Water->unspecify_phase();
929 double hbar_a_0, tau, hbar_a, R_bar_Lemmon;
931 hbar_a_0 = -7914.149298;
933 R_bar_Lemmon = 8.314510;
935 double Tref = 473.15, vmolarref = 0.038837428192186184, href = 13782.240592933371;
937 double tauref = 132.6312 / Tref;
939 double hoffset = href - href_EOS;
945 Air->update_DmolarT_direct(p / (R_bar * T), T);
946 Air->unspecify_phase();
951 double sbar_0_Lem, tau, sbar_a, R_bar_Lemmon = 8.314510, T0 = 273.15, p0 = 101325, vmolar_a_0;
954 sbar_0_Lem = -196.1375815;
956 vmolar_a_0 = R_bar_Lemmon * T0 / p0;
959 double Tref = 473.15, vmolarref = 0.038837605637863169, sref = 212.22365283759311;
961 double tauref = 132.6312 / Tref;
963 + R_bar_Lemmon * log(vmolarref / vmolar_a_0);
964 double soffset = sref - sref_EOS;
970 Air->update_DmolarT_direct(1 / vmolar_a_0, T);
971 Air->unspecify_phase();
972 sbar_a = sbar_0_Lem + soffset
974 + R_bar_Lemmon * log(vmolar_a / vmolar_a_0);
991 double hbar_0, hbar_a, hbar_w, hbar, R_bar = 8.314472;
999 if (FlagUseIdealGasEnthalpyCorrelations) {
1000 hbar_w = 2.7030251618E-03 * T * T + 3.1994361015E+01 * T + 3.6123174929E+04;
1001 hbar_a = 9.2486716590E-04 * T * T + 2.8557221776E+01 * T - 7.8616129429E+03;
1011 hbar = hbar_0 + (1 - psi_w) * hbar_a + psi_w * hbar_w
1012 + R_bar * T * ((B_m(T, psi_w) - T * dB_m_dT(T, psi_w)) / vmolar + (C_m(T, psi_w) - T / 2.0 * dC_m_dT(T, psi_w)) / (vmolar * vmolar));
1021 double M_ha = MM_Water() * psi_w + (1 - psi_w) * 0.028966;
1022 return h_bar / M_ha;
1028 double M_ha = MM_Water() * psi_w + (1 - psi_w) * 0.028966;
1029 return h_bar * (1 + W) / M_ha;
1034 double M_ha = MM_Water() * psi_w + (1 - psi_w) * 0.028966;
1035 return h_bar / M_ha;
1041 double M_ha = MM_Water() * psi_w + (1 - psi_w) * 0.028966;
1042 return h_bar * (1 + W) / M_ha;
1055 double x1 = 0, x2 = 0, x3 = 0, y1 = 0, y2 = 0, eps = 1e-8, f = 999, R_bar_Lem = 8.314510;
1057 double sbar_0, sbar_a = 0, sbar_w = 0, sbar, R_bar = 8.314472, vbar_a_guess, Baa, Caaa, vbar_a = 0;
1058 double B, dBdT, C, dCdT;
1060 sbar_0 = 0.02366427495;
1066 dBdT = dB_m_dT(T, psi_w);
1069 dCdT = dC_m_dT(T, psi_w);
1071 vbar_a_guess = R_bar_Lem * T / p;
1073 while ((iter <= 3 || std::abs(f) > eps) && iter < 100) {
1079 x2 = vbar_a_guess + 0.001;
1085 f = R_bar_Lem * T / vbar_a * (1 + Baa / vbar_a + Caaa / pow(vbar_a, 2)) - p;
1091 x3 = x2 - y2 / (y2 - y1) * (x2 - x1);
1099 if (FlagUseIdealGasEnthalpyCorrelations) {
1100 std::cout <<
"Not implemented" << std::endl;
1106 sbar = sbar_0 + (1 - psi_w) * sbar_a + psi_w * sbar_w
1107 - R_bar * ((B + T * dBdT) / v_bar + (C + T * dCdT) / (2 * pow(v_bar, 2)) + (1 - psi_w) * log(1 - psi_w) + psi_w * log(psi_w));
1109 sbar = sbar_0 + sbar_a - R_bar * ((B + T * dBdT) / v_bar + (C + T * dCdT) / (2 * pow(v_bar, 2)));
1117 double M_ha = MM_Water() * psi_w + (1 - psi_w) * 0.028966;
1118 return s_bar / M_ha;
1123 double M_ha = MM_Water() * psi_w + (1 - psi_w) * 0.028966;
1125 return s_bar * (1 + W) / M_ha;
1130 double p_w, eps, resid, Tdp = 0, x1 = 0, x2 = 0, x3, y1 = 0, y2, T0;
1131 double p_ws_dp, f_dp;
1134 if ((1 - psi_w) < 1e-16) {
1147 if (p_w > 611.6547241637944) {
1148 T0 = IF97::Tsat97(p) - 1;
1158 while ((iter <= 3 || std::abs(resid) > eps) && iter < 100) {
1171 if (Tdp >= 273.16) {
1173 p_ws_dp = IF97::psat97(Tdp);
1181 resid = p_w - p_ws_dp * f_dp;
1188 x3 = x2 - y2 / (y2 - y1) * (x2 - x1);
1204 WetBulbSolver(
double T,
double p,
double psi_w) : _p(p), _W(epsilon * psi_w / (1 - psi_w)) {
1206 double v_bar_w =
MolarVolume(T, p, psi_w), M_ha = MM_Water() * psi_w + (1 - psi_w) * 0.028966;
1207 LHS =
MolarEnthalpy(T, p, psi_w, v_bar_w) * (1 + _W) / M_ha;
1210 double epsilon = 0.621945;
1211 double f_wb, p_ws_wb, p_s_wb, W_s_wb, h_w, M_ha_wb, psi_wb, v_bar_wb;
1217 p_ws_wb = IF97::psat97(Twb);
1224 p_s_wb = f_wb * p_ws_wb;
1226 W_s_wb = epsilon * p_s_wb / (_p - p_s_wb);
1228 psi_wb = W_s_wb / (epsilon + W_s_wb);
1237 h_w =
h_Ice(Twb, _p);
1241 M_ha_wb = MM_Water() * psi_wb + (1 - psi_wb) * 0.028966;
1243 double RHS = (
MolarEnthalpy(Twb, _p, psi_wb, v_bar_wb) * (1 + W_s_wb) / M_ha_wb + (_W - W_s_wb) * h_w);
1261 std::vector<givens> inp(2);
1265 std::vector<double> val(2);
1290 double Tsat = IF97::Tsat97(p);
1303 if (return_val > Tmax + 1) {
1315 double Tmin =
Brent(WBTS, 210, Tsat - 1, 1e-12, 1e-12, 50);
1317 return_val =
Brent(WBS, Tmin - 30, Tmax - 1, 1e-12, 1e-12, 50);
1324 static givens Name2Type(
const std::string& Name) {
1335 else if (!
strcmp(Name,
"Hha"))
1337 else if (!
strcmp(Name,
"InternalEnergy") || !
strcmp(Name,
"U") || !
strcmp(Name,
"Uda"))
1339 else if (!
strcmp(Name,
"Uha"))
1343 else if (!
strcmp(Name,
"Sha"))
1349 else if (!
strcmp(Name,
"P"))
1353 else if (!
strcmp(Name,
"Vha"))
1361 else if (!
strcmp(Name,
"Cha") || !
strcmp(Name,
"cp_ha"))
1363 else if (!
strcmp(Name,
"CV"))
1365 else if (!
strcmp(Name,
"CVha") || !
strcmp(Name,
"cv_ha"))
1367 else if (!
strcmp(Name,
"P_w"))
1369 else if (!
strcmp(Name,
"isentropic_exponent"))
1371 else if (!
strcmp(Name,
"speed_of_sound"))
1373 else if (!
strcmp(Name,
"Z"))
1377 "Sorry, your input [%s] was not understood to Name2Type. Acceptable values are T,P,R,W,D,B,H,S,M,K and aliases thereof\n", Name.c_str()));
1379 int TypeMatch(
int TypeCode,
const std::string& Input1Name,
const std::string& Input2Name,
const std::string& Input3Name) {
1381 if (TypeCode == Name2Type(Input1Name))
return 1;
1382 if (TypeCode == Name2Type(Input2Name))
return 2;
1383 if (TypeCode == Name2Type(Input3Name))
1389 double p_ws, f, W, epsilon = 0.621945, Tdp, p_ws_dp, f_dp, p_w_dp, p_s, RH;
1394 return W / (epsilon + W);
1398 p_ws = IF97::psat97(T);
1409 double psi_ws = p_s / p;
1415 if (Tdp >= 273.16) {
1416 p_ws_dp = IF97::psat97(Tdp);
1425 p_w_dp = f_dp * p_ws_dp;
1434 double p_ws, f, p_s;
1437 p_ws = IF97::psat97(T);
1449 return psi_w * p / p_s;
1453 switch (Name2Type(Name)) {
1487 switch (Name2Type(Name)) {
1520 double HAProps(
const std::string& OutputName,
const std::string& Input1Name,
double Input1,
const std::string& Input2Name,
double Input2,
1521 const std::string& Input3Name,
double Input3) {
1526 double out =
HAPropsSI(OutputName, Input1Name, Input1, Input2Name, Input2, Input3Name, Input3);
1533 if (input_keys.size() != 2) {
1537 if (input_keys[0] == key) {
1539 }
else if (input_keys[1] == key) {
1553 const double target;
1556 std::vector<double> input_vals;
1561 : p(p), target(target), output(output), _T(_HUGE), _psi_w(_HUGE) {
1562 input_vals.resize(2, T);
1579 const double target;
1582 std::vector<double> input_vals;
1587 : p(p), target(target), output(output), _T(_HUGE), _psi_w(_HUGE) {
1588 input_vals.resize(2, W);
1603 void _HAPropsSI_inputs(
double p,
const std::vector<givens>& input_keys,
const std::vector<double>& input_vals,
double& T,
double& psi_w) {
1605 std::cout <<
format(
"length of input_keys is %d\n", input_keys.size());
1607 if (input_keys.size() != input_vals.size()) {
1608 throw CoolProp::ValueError(
format(
"Length of input_keys (%d) does not equal that of input_vals (%d)", input_keys.size(), input_vals.size()));
1614 long other = 1 - key;
1615 T = input_vals[key];
1617 std::cout <<
format(
"One of the inputs is T: %g K\n", T);
1619 givens othergiven = input_keys[other];
1620 switch (othergiven) {
1625 std::cout <<
format(
"other input value is %g\n", input_vals[other]);
1626 std::cout <<
format(
"other input index is %d\n", othergiven);
1648 double MainInputValue = T;
1650 double SecondaryInputValue = input_vals[other];
1651 givens SecondaryInputKey = input_keys[other];
1652 W = Brent_HAProps_W(SecondaryInputKey, p, MainInputKey, MainInputValue, SecondaryInputValue, W_min, W_max);
1663 std::cout <<
format(
"The main input is not T\n", T);
1674 "Sorry, but currently at least one of the variables as an input to HAPropsSI() must be temperature, relative humidity, humidity ratio, "
1675 "or dewpoint\n Eventually will add a 2-D NR solver to find T and psi_w simultaneously, but not included now");
1678 int number_of_water_content_inputs =
1680 if (number_of_water_content_inputs > 1) {
1682 "Sorry, but cannot provide two inputs that are both water-content (humidity ratio, relative humidity, absolute humidity");
1685 long other = 1 - key;
1688 double MainInputValue = input_vals[key];
1689 givens MainInputKey = input_keys[key];
1691 double SecondaryInputValue = input_vals[other];
1692 givens SecondaryInputKey = input_keys[other];
1695 std::cout <<
format(
"Main input is %g\n", MainInputValue);
1696 std::cout <<
format(
"Secondary input is %g\n", SecondaryInputValue);
1701 check_bounds(
GIVEN_T, 273.15, T_min, T_max);
1704 if (MainInputValue < 1e-10) {
1720 if (MainInputValue < 1e-10) {
1725 double T_dummy = -1,
1728 double pp_water_sat = psi_w_sat * p;
1731 if (pp_water_sat >
Water->p_triple()) {
1732 T_min = IF97::Tsat97(pp_water_sat);
1737 T_min = Secant_Tdb_at_saturated_W(psi_w_sat, p, T_min);
1750 T = Brent_HAProps_T(SecondaryInputKey, p, MainInputKey, MainInputValue, SecondaryInputValue, T_min, T_max);
1751 }
catch (std::exception& e) {
1753 std::cout <<
"ERROR: " << e.what() << std::endl;
1762 std::vector<givens> input_keys(2,
GIVEN_T);
1763 input_keys[1] = MainInputKey;
1764 std::vector<double> input_vals(2, T);
1765 input_vals[1] = MainInputValue;
1771 std::cout <<
format(
"_HAPropsSI_outputs :: T: %g K, psi_w: %g\n", T, psi_w);
1774 double M_ha = (1 - psi_w) * 0.028966 + MM_Water() * psi_w;
1778 switch (OutputType) {
1786 return v_bar * (1 + W) / M_ha;
1790 return v_bar / M_ha;
1839 double v_bar1, v_bar2, h_bar1, h_bar2, cp_ha, dT = 1e-3;
1844 cp_ha = (h_bar2 - h_bar1) / (2 * dT);
1845 return cp_ha / M_ha;
1852 double v_bar, p_1, p_2, u_bar1, u_bar2, cv_bar, dT = 1e-3;
1854 p_1 =
Pressure(T - dT, v_bar, psi_w);
1856 p_2 =
Pressure(T + dT, v_bar, psi_w);
1858 cv_bar = (u_bar2 - u_bar1) / (2 * dT);
1859 return cv_bar / M_ha;
1866 p_1 =
Pressure(T, v_bar - dv, psi_w);
1867 p_2 =
Pressure(T, v_bar + dv, psi_w);
1868 CoolPropDbl dpdv__constT = (p_2 - p_1) / (2 * dv);
1869 return -cp / cv * dpdv__constT * v_bar / p;
1876 p_1 =
Pressure(T, v_bar - dv, psi_w);
1877 p_2 =
Pressure(T, v_bar + dv, psi_w);
1879 CoolPropDbl dpdrho__constT = (p_2 - p_1) / (2 * dv) * dvdrho;
1880 return sqrt(1 / M_ha * cp / cv * dpdrho__constT);
1884 double R_u_molar = 8.314472;
1885 return p * v_bar / (R_u_molar * T);
1891 double HAPropsSI(
const std::string& OutputName,
const std::string& Input1Name,
double Input1,
const std::string& Input2Name,
double Input2,
1892 const std::string& Input3Name,
double Input3) {
1900 std::cout <<
format(
"HAPropsSI(%s,%s,%g,%s,%g,%s,%g)\n", OutputName.c_str(), Input1Name.c_str(), Input1, Input2Name.c_str(), Input2,
1901 Input3Name.c_str(), Input3);
1904 std::vector<givens> input_keys(2);
1905 std::vector<double> input_vals(2);
1907 givens In1Type, In2Type, In3Type, OutputType;
1908 double p, T = _HUGE, psi_w = _HUGE;
1911 In1Type = Name2Type(Input1Name.c_str());
1912 In2Type = Name2Type(Input2Name.c_str());
1913 In3Type = Name2Type(Input3Name.c_str());
1916 OutputType = Name2Type(OutputName.c_str());
1919 if (OutputType == In1Type) {
1922 if (OutputType == In2Type) {
1925 if (OutputType == In3Type) {
1932 input_keys[0] = In2Type;
1933 input_keys[1] = In3Type;
1934 input_vals[0] = Input2;
1935 input_vals[1] = Input3;
1936 }
else if (In2Type ==
GIVEN_P) {
1938 input_keys[0] = In1Type;
1939 input_keys[1] = In3Type;
1940 input_vals[0] = Input1;
1941 input_vals[1] = Input3;
1942 }
else if (In3Type ==
GIVEN_P) {
1944 input_keys[0] = In1Type;
1945 input_keys[1] = In2Type;
1946 input_vals[0] = Input1;
1947 input_vals[1] = Input2;
1952 if (input_keys[0] == input_keys[1]) {
1953 throw CoolProp::ValueError(
"Other two inputs to HAPropsSI aside from pressure cannot be the same");
1957 double min_val = _HUGE, max_val = -_HUGE;
1958 for (std::size_t i = 0; i < input_keys.size(); i++) {
1959 if (!check_bounds(input_keys[i], input_vals[i], min_val, max_val)) {
1961 input_keys[i], input_vals[i], min_val, max_val));
1971 std::cout <<
format(
"HAPropsSI input conversion yields T: %g, psi_w: %g\n", T, psi_w);
1975 if (!check_bounds(
GIVEN_P, p, min_val, max_val)) {
1976 throw CoolProp::ValueError(
format(
"The pressure value (%g) is outside the range of validity: (%g) to (%g)", p, min_val, max_val));
1981 if (!check_bounds(
GIVEN_T, T, min_val, max_val)) {
1982 throw CoolProp::ValueError(
format(
"The temperature value (%g) is outside the range of validity: (%g) to (%g)", T, min_val, max_val));
1987 if (!check_bounds(
GIVEN_PSIW, psi_w, min_val, max_val)) {
1989 format(
"The water mole fraction value (%g) is outside the range of validity: (%g) to (%g)", psi_w, min_val, max_val));
1997 if (!check_bounds(OutputType, val, min_val, max_val)) {
1999 format(
"The output for key (%d) with value (%g) is outside the range of validity: (%g) to (%g)", OutputType, val, min_val, max_val));
2007 std::cout <<
format(
"HAPropsSI is about to return invalid number");
2013 std::cout <<
format(
"HAPropsSI is about to return %g\n", val);
2016 }
catch (std::exception& e) {
2024 double HAProps_Aux(
const char* Name,
double T,
double p,
double W,
char* units) {
2033 double psi_w, B_aa, C_aaa, B_ww, C_www, B_aw, C_aaw, C_aww, v_bar;
2036 if (!
strcmp(Name,
"Baa")) {
2038 strcpy(units,
"m^3/mol");
2040 }
else if (!
strcmp(Name,
"Caaa")) {
2042 strcpy(units,
"m^6/mol^2");
2044 }
else if (!
strcmp(Name,
"Bww")) {
2046 strcpy(units,
"m^3/mol");
2048 }
else if (!
strcmp(Name,
"Cwww")) {
2050 strcpy(units,
"m^6/mol^2");
2052 }
else if (!
strcmp(Name,
"dBaa")) {
2054 strcpy(units,
"m^3/mol");
2056 }
else if (!
strcmp(Name,
"dCaaa")) {
2057 C_aaa = dCdT_Air(T);
2058 strcpy(units,
"m^6/mol^2");
2060 }
else if (!
strcmp(Name,
"dBww")) {
2061 B_ww = dBdT_Water(T);
2062 strcpy(units,
"m^3/mol");
2064 }
else if (!
strcmp(Name,
"dCwww")) {
2065 C_www = dCdT_Water(T);
2066 strcpy(units,
"m^6/mol^2");
2068 }
else if (!
strcmp(Name,
"Baw")) {
2070 strcpy(units,
"m^3/mol");
2072 }
else if (!
strcmp(Name,
"Caww")) {
2074 strcpy(units,
"m^6/mol^2");
2076 }
else if (!
strcmp(Name,
"Caaw")) {
2078 strcpy(units,
"m^6/mol^2");
2080 }
else if (!
strcmp(Name,
"dBaw")) {
2081 double dB_aw = _dB_aw_dT(T);
2082 strcpy(units,
"m^3/mol");
2084 }
else if (!
strcmp(Name,
"dCaww")) {
2085 double dC_aww = _dC_aww_dT(T);
2086 strcpy(units,
"m^6/mol^2");
2088 }
else if (!
strcmp(Name,
"dCaaw")) {
2089 double dC_aaw = _dC_aaw_dT(T);
2090 strcpy(units,
"m^6/mol^2");
2092 }
else if (!
strcmp(Name,
"beta_H")) {
2094 return HenryConstant(T);
2095 }
else if (!
strcmp(Name,
"kT")) {
2104 }
else if (!
strcmp(Name,
"p_ws")) {
2107 return IF97::psat97(T);
2110 }
else if (!
strcmp(Name,
"vbar_ws")) {
2111 strcpy(units,
"m^3/mol");
2117 return dg_dp_Ice(T, p) * MM_Water() / 1000 / 1000;
2119 }
else if (!
strcmp(Name,
"f")) {
2125 if (!
strcmp(Name,
"Bm")) {
2126 strcpy(units,
"m^3/mol");
2127 return B_m(T, psi_w);
2128 }
else if (!
strcmp(Name,
"Cm")) {
2129 strcpy(units,
"m^6/mol^2");
2130 return C_m(T, psi_w);
2131 }
else if (!
strcmp(Name,
"hvirial")) {
2133 return 8.3145 * T * ((B_m(T, psi_w) - T * dB_m_dT(T, psi_w)) / v_bar + (C_m(T, psi_w) - T / 2.0 * dC_m_dT(T, psi_w)) / (v_bar * v_bar));
2147 else if (!
strcmp(Name,
"hbaro_w")) {
2149 }
else if (!
strcmp(Name,
"hbaro_a")) {
2151 }
else if (!
strcmp(Name,
"h_Ice")) {
2154 }
else if (!
strcmp(Name,
"s_Ice")) {
2157 }
else if (!
strcmp(Name,
"psub_Ice")) {
2160 }
else if (!
strcmp(Name,
"g_Ice")) {
2163 }
else if (!
strcmp(Name,
"rho_Ice")) {
2167 printf(
"Sorry I didn't understand your input [%s] to HAProps_Aux\n", Name);
2180 return 2.14627073E+03 - 3.28917768E+01 * T + 1.89471075E-01 * T * T - 4.86290986E-04 * T * T * T + 4.69540143E-07 * T * T * T * T;
2183 double IceProps(
const char* Name,
double T,
double p) {
2184 if (!
strcmp(Name,
"s")) {
2185 return s_Ice(T, p * 1000.0);
2186 }
else if (!
strcmp(Name,
"rho")) {
2187 return rho_Ice(T, p * 1000.0);
2188 }
else if (!
strcmp(Name,
"h")) {
2189 return h_Ice(T, p * 1000.0);
2199 # include <catch2/catch_all.hpp>
2201 TEST_CASE(
"Check HA Virials from Table A.2.1",
"[RP1485]") {
2203 CHECK(std::abs(HumidAir::B_Air(-60 + 273.15) / (-33.065 / 1e6) - 1) < 1e-3);
2204 CHECK(std::abs(HumidAir::B_Air(0 + 273.15) / (-13.562 / 1e6) - 1) < 1e-3);
2205 CHECK(std::abs(HumidAir::B_Air(200 + 273.15) / (11.905 / 1e6) - 1) < 1e-3);
2206 CHECK(std::abs(HumidAir::B_Air(350 + 273.15) / (18.949 / 1e6) - 1) < 1e-3);
2209 CHECK(std::abs(HumidAir::B_Water(-60 + 273.15) / (-11174 / 1e6) - 1) < 1e-3);
2210 CHECK(std::abs(HumidAir::B_Water(0 + 273.15) / (-2025.6 / 1e6) - 1) < 1e-3);
2211 CHECK(std::abs(HumidAir::B_Water(200 + 273.15) / (-200.52 / 1e6) - 1) < 1e-3);
2212 CHECK(std::abs(HumidAir::B_Water(350 + 273.15) / (-89.888 / 1e6) - 1) < 1e-3);
2215 CHECK(std::abs(HumidAir::_B_aw(-60 + 273.15) / (-68.306 / 1e6) - 1) < 1e-3);
2216 CHECK(std::abs(HumidAir::_B_aw(0 + 273.15) / (-38.074 / 1e6) - 1) < 1e-3);
2217 CHECK(std::abs(HumidAir::_B_aw(200 + 273.15) / (-2.0472 / 1e6) - 1) < 1e-3);
2218 CHECK(std::abs(HumidAir::_B_aw(350 + 273.15) / (7.5200 / 1e6) - 1) < 1e-3);
2222 CHECK(std::abs(HumidAir::C_Air(-60 + 273.15) / (2177.9 / 1e12) - 1) < 1e-3);
2223 CHECK(std::abs(HumidAir::C_Air(0 + 273.15) / (1893.1 / 1e12) - 1) < 1e-3);
2224 CHECK(std::abs(HumidAir::C_Air(200 + 273.15) / (1551.2 / 1e12) - 1) < 1e-3);
2225 CHECK(std::abs(HumidAir::C_Air(350 + 273.15) / (1464.7 / 1e12) - 1) < 1e-3);
2228 CHECK(std::abs(HumidAir::C_Water(-60 + 273.15) / (-1.5162999202e-04) - 1) < 1e-3);
2229 CHECK(std::abs(HumidAir::C_Water(0 + 273.15) / (-10981960 / 1e12) - 1) < 1e-3);
2230 CHECK(std::abs(HumidAir::C_Water(200 + 273.15) / (-0.00000003713759442) - 1) < 1e-3);
2231 CHECK(std::abs(HumidAir::C_Water(350 + 273.15) / (-0.000000001198914198) - 1) < 1e-3);
2234 CHECK(std::abs(HumidAir::_C_aaw(-60 + 273.15) / (1027.3 / 1e12) - 1) < 1e-3);
2235 CHECK(std::abs(HumidAir::_C_aaw(0 + 273.15) / (861.02 / 1e12) - 1) < 1e-3);
2236 CHECK(std::abs(HumidAir::_C_aaw(200 + 273.15) / (627.15 / 1e12) - 1) < 1e-3);
2237 CHECK(std::abs(HumidAir::_C_aaw(350 + 273.15) / (583.79 / 1e12) - 1) < 1e-3);
2240 CHECK(std::abs(HumidAir::_C_aww(-60 + 273.15) / (-1821432 / 1e12) - 1) < 1e-3);
2241 CHECK(std::abs(HumidAir::_C_aww(0 + 273.15) / (-224234 / 1e12) - 1) < 1e-3);
2242 CHECK(std::abs(HumidAir::_C_aww(200 + 273.15) / (-8436.5 / 1e12) - 1) < 1e-3);
2243 CHECK(std::abs(HumidAir::_C_aww(350 + 273.15) / (-2486.9 / 1e12) - 1) < 1e-3);
2246 TEST_CASE(
"Enhancement factor from Table A.3",
"[RP1485]") {
2252 TEST_CASE(
"Isothermal compressibility from Table A.5",
"[RP1485]") {
2259 TEST_CASE(
"Henry constant from Table A.6",
"[RP1485]") {
2260 CHECK(std::abs(HumidAir::HenryConstant(0.010001 + 273.15) / (0.22600e-9) - 1) < 1e-3);
2261 CHECK(std::abs(HumidAir::HenryConstant(300 + 273.15) / (0.58389e-9) - 1) < 1e-3);
2268 std::string in1, in2, in3, out;
2269 double v1, v2, v3, expected;
2270 hel(std::string in1,
double v1, std::string in2,
double v2, std::string in3,
double v3, std::string out,
double expected) {
2277 this->expected = expected;
2281 hel table_A11[] = {hel(
"T", 473.15,
"W", 0.00,
"P", 101325,
"B", 45.07 + 273.15), hel(
"T", 473.15,
"W", 0.00,
"P", 101325,
"V", 1.341),
2282 hel(
"T", 473.15,
"W", 0.00,
"P", 101325,
"H", 202520), hel(
"T", 473.15,
"W", 0.00,
"P", 101325,
"S", 555.8),
2283 hel(
"T", 473.15,
"W", 0.50,
"P", 101325,
"B", 81.12 + 273.15), hel(
"T", 473.15,
"W", 0.50,
"P", 101325,
"V", 2.416),
2284 hel(
"T", 473.15,
"W", 0.50,
"P", 101325,
"H", 1641400), hel(
"T", 473.15,
"W", 0.50,
"P", 101325,
"S", 4829.5),
2285 hel(
"T", 473.15,
"W", 1.00,
"P", 101325,
"B", 88.15 + 273.15), hel(
"T", 473.15,
"W", 1.00,
"P", 101325,
"V", 3.489),
2286 hel(
"T", 473.15,
"W", 1.00,
"P", 101325,
"H", 3079550), hel(
"T", 473.15,
"W", 1.00,
"P", 101325,
"S", 8889.0)};
2288 hel table_A12[] = {hel(
"T", 473.15,
"W", 0.00,
"P", 1e6,
"B", 90.47 + 273.15),
2289 hel(
"T", 473.15,
"W", 0.00,
"P", 1e6,
"V", 0.136),
2290 hel(
"T", 473.15,
"W", 0.00,
"P", 1e6,
"H", 201940),
2291 hel(
"T", 473.15,
"W", 0.00,
"P", 1e6,
"S", -101.1),
2292 hel(
"T", 473.15,
"W", 0.50,
"P", 1e6,
"B", 148.49 + 273.15),
2293 hel(
"T", 473.15,
"W", 0.50,
"P", 1e6,
"V", 0.243),
2294 hel(
"T", 473.15,
"W", 0.50,
"P", 1e6,
"H", 1630140),
2295 hel(
"T", 473.15,
"W", 0.50,
"P", 1e6,
"S", 3630.2),
2296 hel(
"T", 473.15,
"W", 1.00,
"P", 1e6,
"B", 159.92 + 273.15),
2297 hel(
"T", 473.15,
"W", 1.00,
"P", 1e6,
"V", 0.347),
2298 hel(
"T", 473.15,
"W", 1.00,
"P", 1e6,
"H", 3050210),
2299 hel(
"T", 473.15,
"W", 1.00,
"P", 1e6,
"S", 7141.3)};
2302 hel(
"T", 473.15,
"W", 0.10,
"P", 1e7,
"B", 188.92 + 273.15), hel(
"T", 473.15,
"W", 0.10,
"P", 1e7,
"V", 0.016),
2303 hel(
"T", 473.15,
"W", 0.10,
"P", 1e7,
"H", 473920), hel(
"T", 473.15,
"W", 0.10,
"P", 1e7,
"S", -90.1),
2304 hel(
"T", 473.15,
"W", 0.10,
"P", 1e7,
"R", 0.734594),
2307 class HAPropsConsistencyFixture
2310 std::vector<hel> inputs;
2311 std::string in1, in2, in3, out;
2312 double v1, v2, v3, expected, actual;
2313 void set_table(hel h[],
int nrow) {
2314 inputs = std::vector<hel>(h, h + nrow);
2316 void set_values(hel& h) {
2323 this->expected = h.expected;
2327 actual =
HumidAir::HAPropsSI(out.c_str(), in1.c_str(), v1, in2.c_str(), v2, in3.c_str(), v3);
2331 TEST_CASE_METHOD(HAPropsConsistencyFixture,
"ASHRAE RP1485 Tables",
"[RP1485]") {
2332 SECTION(
"Table A.15") {
2333 set_table(table_A15, 5);
2334 for (std::size_t i = 0; i < inputs.size(); ++i) {
2335 set_values(inputs[i]);
2337 CAPTURE(inputs[i].in1);
2338 CAPTURE(inputs[i].v1);
2339 CAPTURE(inputs[i].in2);
2340 CAPTURE(inputs[i].v2);
2341 CAPTURE(inputs[i].in3);
2342 CAPTURE(inputs[i].v3);
2348 CHECK(std::abs(actual / expected - 1) < 0.01);
2351 SECTION(
"Table A.11") {
2352 set_table(table_A11, 12);
2353 for (std::size_t i = 0; i < inputs.size(); ++i) {
2354 set_values(inputs[i]);
2356 CAPTURE(inputs[i].in1);
2357 CAPTURE(inputs[i].v1);
2358 CAPTURE(inputs[i].in2);
2359 CAPTURE(inputs[i].v2);
2360 CAPTURE(inputs[i].in3);
2361 CAPTURE(inputs[i].v3);
2367 CHECK(std::abs(actual / expected - 1) < 0.01);
2370 SECTION(
"Table A.12") {
2371 set_table(table_A12, 12);
2372 for (std::size_t i = 0; i < inputs.size(); ++i) {
2373 set_values(inputs[i]);
2375 CAPTURE(inputs[i].in1);
2376 CAPTURE(inputs[i].v1);
2377 CAPTURE(inputs[i].in2);
2378 CAPTURE(inputs[i].v2);
2379 CAPTURE(inputs[i].in3);
2380 CAPTURE(inputs[i].v3);
2386 CHECK(std::abs(actual / expected - 1) < 0.01);
2390 TEST_CASE(
"Assorted tests",
"[HAPropsSI]") {
2396 bool is_not_a_pair(
const std::set<std::size_t>& item) {
2397 return item.size() != 2;
2400 const int number_of_inputs = 6;
2401 std::string inputs[number_of_inputs] = {
"W",
"D",
"B",
"R",
"T",
"V"};
2403 class ConsistencyTestData
2407 std::vector<Dictionary> data;
2408 std::list<std::set<std::size_t>> inputs_list;
2409 ConsistencyTestData() {
2416 std::vector<std::size_t> indices(number_of_inputs);
2417 for (std::size_t i = 0; i < number_of_inputs; ++i) {
2421 std::set<std::size_t> indices_set(indices.begin(), indices.end());
2422 std::set<std::set<std::size_t>> inputs_powerset =
powerset(indices_set);
2423 inputs_list = std::list<std::set<std::size_t>>(inputs_powerset.begin(), inputs_powerset.end());
2424 inputs_list.remove_if(is_not_a_pair);
2426 const int NT = 10, NW = 5;
2428 for (
double T = 210; T < 350; T += (350 - 210) / (NT - 1)) {
2430 for (
double W = 1e-5; W < Wsat; W += (Wsat - 1e-5) / (NW - 1)) {
2433 for (
int i = 0; i < number_of_inputs; ++i) {
2437 data.push_back(vals);
2438 std::cout <<
format(
"T %g W %g\n", T, W);