1 #ifndef TABULAR_BACKENDS_H
2 #define TABULAR_BACKENDS_H
6 #include <msgpack/fbuffer.hpp>
18 #define LIST_OF_MATRICES \
62 #define LIST_OF_SATURATION_VECTORS \
104 #define X(name) name = PED.name;
108 #define X(name) name = PED.name;
113 std::map<std::string, std::vector<double>>
vectors;
114 std::map<std::string, std::vector<std::vector<double>>>
matrices;
121 #define X(name) vectors.insert(std::pair<std::string, std::vector<double>>(#name, name));
125 #define X(name) matrices.insert(std::pair<std::string, std::vector<std::vector<double>>>(#name, name));
130 std::map<std::string, std::vector<double>>::iterator it =
vectors.find(name);
136 std::map<std::string, std::vector<std::vector<double>>>::iterator
get_matrix_iterator(
const std::string& name) {
137 std::map<std::string, std::vector<std::vector<double>>>::iterator it =
matrices.find(name);
148 #define X(name) name = get_vector_iterator(#name)->second;
154 #define X(name) name = get_matrix_iterator(#name)->second;
158 iTsat_max = std::distance(T.begin(), std::max_element(T.begin(), T.end()));
160 ipsat_max = std::distance(p.begin(), std::max_element(p.begin(), p.end()));
164 deserialized.convert(temp);
169 std::swap(*
this, temp);
175 conversion_factor = 1.0;
178 conversion_factor = molar_mass;
182 conversion_factor /= molar_mass;
186 conversion_factor /= molar_mass;
190 conversion_factor /= molar_mass;
194 conversion_factor /= molar_mass;
198 conversion_factor /= molar_mass;
216 throw ValueError(
"TabularBackends::mass_to_molar - I don't know how to convert this parameter");
228 shared_ptr<CoolProp::AbstractState>
AS;
236 void build(shared_ptr<CoolProp::AbstractState>&
AS);
239 #define X(name) std::vector<double> name;
244 std::map<std::string, std::vector<double>>
vectors;
263 std::vector<double>*yvecL = NULL, *yvecV = NULL;
290 throw ValueError(
"invalid input for other in is_inside");
296 double pmax = this->pV[pV.size() - 1], pmin = this->pV[0];
297 if (mainval > pmax || mainval < pmin) {
302 double Tmax = this->TV[TV.size() - 1], Tmin = this->TV[0];
303 if (mainval > Tmax || mainval < Tmin) {
307 throw ValueError(
"invalid input for other in is_inside");
311 std::size_t iLplus, iVplus;
322 throw ValueError(
format(
"For now, main input in is_inside must be T or p"));
325 iVplus = std::min(iV + 1,
N - 1);
326 iLplus = std::min(iL + 1,
N - 1);
336 double logp = log(mainval);
338 yV =
CubicInterp(logpV, TV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, logp);
339 yL =
CubicInterp(logpL, TL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, logp);
342 yV = exp(
CubicInterp(TV, logpV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, mainval));
343 yL = exp(
CubicInterp(TL, logpL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, mainval));
348 double ymin =
min4((*yvecL)[iL], (*yvecL)[iLplus], (*yvecV)[iV], (*yvecV)[iVplus]);
349 double ymax =
max4((*yvecL)[iL], (*yvecL)[iLplus], (*yvecV)[iV], (*yvecV)[iVplus]);
350 if (val < ymin || val > ymax) {
361 double logp = log(mainval);
362 yV =
CubicInterp(logpV, *yvecV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, logp);
363 yL =
CubicInterp(logpL, *yvecL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, logp);
365 yV =
CubicInterp(TV, *yvecV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, mainval);
366 yL =
CubicInterp(TL, *yvecL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, mainval);
382 std::fill(name.begin(), name.end(), _HUGE);
389 #define X(name) vectors.insert(std::pair<std::string, std::vector<double>>(#name, name));
394 std::map<std::string, std::vector<double>>::iterator it =
vectors.find(name);
403 #define X(name) name = get_vector_iterator(#name)->second;
410 deserialized.convert(temp);
417 std::swap(*
this, temp);
423 }
else if (iL + 1 ==
N) {
428 }
else if (iV + 1 ==
N) {
431 double logp = log(p_or_T);
434 double _logpV =
CubicInterp(this->TV, logpV, iV - 2, iV - 1, iV, iV + 1, p_or_T);
435 double _logpL =
CubicInterp(this->TL, logpL, iL - 2, iL - 1, iL, iL + 1, p_or_T);
436 return Q * exp(_logpV) + (1 - Q) * exp(_logpL);
439 double TV =
CubicInterp(logpV, this->TV, iV - 2, iV - 1, iV, iV + 1, logp);
440 double TL =
CubicInterp(logpL, this->TL, iL - 2, iL - 1, iL, iL + 1, logp);
441 return Q * TV + (1 - Q) * TL;
444 double sV =
CubicInterp(logpV, smolarV, iV - 2, iV - 1, iV, iV + 1, logp);
445 double sL =
CubicInterp(logpL, smolarL, iL - 2, iL - 1, iL, iL + 1, logp);
446 return Q * sV + (1 - Q) * sL;
449 double hV =
CubicInterp(logpV, hmolarV, iV - 2, iV - 1, iV, iV + 1, logp);
450 double hL =
CubicInterp(logpL, hmolarL, iL - 2, iL - 1, iL, iL + 1, logp);
451 return Q * hV + (1 - Q) * hL;
454 double uV =
CubicInterp(logpV, umolarV, iV - 2, iV - 1, iV, iV + 1, logp);
455 double uL =
CubicInterp(logpL, umolarL, iL - 2, iL - 1, iL, iL + 1, logp);
456 return Q * uV + (1 - Q) * uL;
459 double rhoV = exp(
CubicInterp(logpV, logrhomolarV, iV - 2, iV - 1, iV, iV + 1, logp));
460 double rhoL = exp(
CubicInterp(logpL, logrhomolarL, iL - 2, iL - 1, iL, iL + 1, logp));
467 return 1 / (Q / rhoV + (1 - Q) / rhoL);
470 double kV =
CubicInterp(logpV, condV, iV - 2, iV - 1, iV, iV + 1, logp);
471 double kL =
CubicInterp(logpL, condL, iL - 2, iL - 1, iL, iL + 1, logp);
478 return Q * kV + (1 - Q) * kL;
481 double muV = exp(
CubicInterp(logpV, logviscV, iV - 2, iV - 1, iV, iV + 1, logp));
482 double muL = exp(
CubicInterp(logpL, logviscL, iL - 2, iL - 1, iL, iL + 1, logp));
489 return 1 / (Q / muV + (1 - Q) / muL);
492 double cpV =
CubicInterp(logpV, cpmolarV, iV - 2, iV - 1, iV, iV + 1, logp);
493 double cpL =
CubicInterp(logpL, cpmolarL, iL - 2, iL - 1, iL, iL + 1, logp);
500 return Q * cpV + (1 - Q) * cpL;
503 double cvV =
CubicInterp(logpV, cvmolarV, iV - 2, iV - 1, iV, iV + 1, logp);
504 double cvL =
CubicInterp(logpL, cvmolarL, iL - 2, iL - 1, iL, iL + 1, logp);
511 return Q * cvV + (1 - Q) * cvL;
514 double wV =
CubicInterp(logpV, speed_soundV, iV - 2, iV - 1, iV, iV + 1, logp);
515 double wL =
CubicInterp(logpL, speed_soundL, iL - 2, iL - 1, iL, iL + 1, logp);
522 return Q * wV + (1 - Q) * wL;
525 throw ValueError(
"Output variable for evaluate is invalid");
537 if (i < 2 || i > TL.size() - 2) {
538 throw ValueError(
format(
"Invalid index (%d) to calc_first_saturation_deriv in TabularBackends", i));
540 std::vector<double>*x, *y;
544 x = (Q == 0) ? &TL : &TV;
547 x = (Q == 0) ? &pL : &pV;
550 throw ValueError(
format(
"Key for Wrt1 is invalid in calc_first_saturation_deriv"));
555 y = (Q == 0) ? &TL : &TV;
558 y = (Q == 0) ? &pL : &pV;
561 y = (Q == 0) ? &rhomolarL : &rhomolarV;
564 y = (Q == 0) ? &hmolarL : &hmolarV;
567 y = (Q == 0) ? &smolarL : &smolarV;
570 y = (Q == 0) ? &umolarL : &umolarV;
573 y = (Q == 0) ? &rhomolarL : &rhomolarV;
574 factor =
AS->molar_mass();
577 y = (Q == 0) ? &hmolarL : &hmolarV;
578 factor = 1 /
AS->molar_mass();
581 y = (Q == 0) ? &smolarL : &smolarV;
582 factor = 1 /
AS->molar_mass();
585 y = (Q == 0) ? &umolarL : &umolarV;
586 factor = 1 /
AS->molar_mass();
589 throw ValueError(
format(
"Key for Of1 is invalid in calc_first_saturation_deriv"));
591 return CubicInterpFirstDeriv((*x)[i - 2], (*x)[i - 1], (*x)[i], (*x)[i + 1], (*y)[i - 2], (*y)[i - 1], (*y)[i], (*y)[i + 1], val) * factor;
606 shared_ptr<CoolProp::AbstractState>
AS;
629 #define X(name) std::vector<std::vector<double>> name;
633 std::map<std::string, std::vector<std::vector<double>>>
matrices;
635 void build(shared_ptr<CoolProp::AbstractState>&
AS);
641 #define X(name) name.resize(Nx, std::vector<double>(Ny, _HUGE));
663 for (std::size_t i = 0; i <
xvec.size(); ++i) {
664 for (std::size_t j = 0; j <
yvec.size(); ++j) {
668 int xoffsets[] = {-1, 1, 0, 0, -1, 1, 1, -1};
669 int yoffsets[] = {0, 0, 1, -1, -1, -1, 1, 1};
671 std::size_t N =
sizeof(xoffsets) /
sizeof(xoffsets[0]);
672 for (std::size_t k = 0; k < N; ++k) {
673 std::size_t iplus = i + xoffsets[k];
674 std::size_t jplus = j + yoffsets[k];
675 if (0 < iplus && iplus <
Nx - 1 && 0 < jplus && jplus <
Ny - 1 &&
ValidNumber(T[iplus][jplus])) {
688 #define X(name) matrices.insert(std::pair<std::string, std::vector<std::vector<double>>>(#name, name));
693 std::map<std::string, std::vector<std::vector<double>>>::iterator it =
matrices.find(name);
702 #define X(name) name = get_matrices_iterator(#name)->second;
713 return x >=
xmin - e && x <= xmax + e && y >=
ymin - e && y <=
ymax + e;
722 if (x > (
xvec[i] +
xvec[i + 1]) / 2.0) {
726 if (x > sqrt(
xvec[i] *
xvec[i + 1])) {
734 if (y > (
yvec[j] +
yvec[j + 1]) / 2.0) {
738 if (y > sqrt(
yvec[j] *
yvec[j + 1])) {
746 if (givenkey ==
ykey) {
754 const std::vector<std::vector<double>>&
mat =
get(otherkey);
755 double closest_diff = 1e20;
756 std::size_t closest_i = 0;
757 for (std::size_t index = 0; index <
mat.size(); ++index) {
758 double diff = std::abs(
mat[index][j] - otherval);
759 if (diff < closest_diff) {
766 }
else if (givenkey ==
xkey) {
769 const std::vector<std::vector<double>>& v =
get(otherkey);
829 if (this->
AS.get() == NULL) {
843 xmax = std::max(xmax1, xmax2);
849 deserialized.convert(temp);
851 if (
Nx != temp.
Nx ||
Ny != temp.
Ny) {
855 }
else if ((std::abs(
xmin) > 1e-10 && std::abs(
xmax) > 1e-10)
858 }
else if ((std::abs(
ymin) > 1e-10 && std::abs(
ymax) > 1e-10)
862 std::swap(*
this, temp);
881 if (this->
AS.get() == NULL) {
889 xmax =
AS->Tmax() * 1.499;
894 deserialized.convert(temp);
896 if (
Nx != temp.
Nx ||
Ny != temp.
Ny) {
900 }
else if ((std::abs(
xmin) > 1e-10 && std::abs(
xmax) > 1e-10)
903 }
else if ((std::abs(
ymin) > 1e-10 && std::abs(
ymax) > 1e-10)
907 std::swap(*
this, temp);
917 std::size_t alt_i, alt_j;
918 bool _valid, _has_valid_neighbor;
924 _has_valid_neighbor =
false;
947 throw KeyError(
format(
"Invalid key to get() function of CellCoeffs"));
972 throw KeyError(
format(
"Invalid key to set() function of CellCoeffs"));
991 _has_valid_neighbor =
true;
995 if (_has_valid_neighbor) {
1004 return _has_valid_neighbor;
1025 void load_tables(
const std::string& path_to_tables, shared_ptr<CoolProp::AbstractState>& AS);
1027 void build_tables(shared_ptr<CoolProp::AbstractState>& AS);
1035 std::map<std::string, TabularDataSet> data;
1040 std::vector<std::string> fluids = AS->fluid_names();
1041 std::vector<CoolPropDbl> fractions = AS->get_mole_fractions();
1042 std::vector<std::string> components;
1043 for (std::size_t i = 0; i < fluids.size(); ++i) {
1044 components.push_back(
format(
"%s[%0.10Lf]", fluids[i].c_str(), fractions[i]));
1046 std::string table_directory =
get_home_dir() +
"/.CoolProp/Tables/";
1047 std::string alt_table_directory =
get_config_string(ALTERNATIVE_TABLES_DIRECTORY);
1048 if (!alt_table_directory.empty()) {
1049 table_directory = alt_table_directory;
1051 return table_directory + AS->backend_name() +
"(" +
strjoin(components,
"&") +
")";
1077 std::vector<std::vector<double>>
const*
z;
1078 std::vector<std::vector<double>>
const*
dzdx;
1079 std::vector<std::vector<double>>
const*
dzdy;
1080 std::vector<std::vector<double>>
const*
d2zdx2;
1082 std::vector<std::vector<double>>
const*
d2zdy2;
1086 shared_ptr<CoolProp::AbstractState>
AS;
1113 return AS->fluid_names();
1128 z = &table.rhomolar;
1129 dzdx = &table.drhomolardx;
1130 dzdy = &table.drhomolardy;
1131 d2zdxdy = &table.d2rhomolardxdy;
1132 d2zdx2 = &table.d2rhomolardx2;
1133 d2zdy2 = &table.d2rhomolardy2;
1137 dzdx = &table.dsmolardx;
1138 dzdy = &table.dsmolardy;
1139 d2zdxdy = &table.d2smolardxdy;
1140 d2zdx2 = &table.d2smolardx2;
1141 d2zdy2 = &table.d2smolardy2;
1145 dzdx = &table.dhmolardx;
1146 dzdy = &table.dhmolardy;
1147 d2zdxdy = &table.d2hmolardxdy;
1148 d2zdx2 = &table.d2hmolardx2;
1149 d2zdy2 = &table.d2hmolardy2;
1153 dzdx = &table.dumolardx;
1154 dzdy = &table.dumolardy;
1155 d2zdxdy = &table.d2umolardxdy;
1156 d2zdx2 = &table.d2umolardx2;
1157 d2zdy2 = &table.d2umolardy2;
1214 double y, std::size_t& i, std::size_t& j) = 0;
1217 const parameters variable1,
const double value1,
const parameters other,
const double otherval, std::size_t& i,
1218 std::size_t& j) = 0;
1221 parameters output,
double x,
double y, std::size_t i, std::size_t j) = 0;
1224 parameters output,
double x,
double y, std::size_t i, std::size_t j) = 0;
1230 return this->AS->T_critical();
1233 return this->AS->Ttriple();
1236 return this->AS->p_triple();
1239 return this->AS->pmax();
1242 return this->AS->Tmax();
1245 return this->AS->Tmin();
1248 return this->AS->p_critical();
1251 return this->AS->rhomolar_critical();
1270 return AS->get_mole_fractions();
1273 return AS->get_mass_fractions();
1277 return AS->molar_mass();
1292 single_phase_logph.
pack();
1293 single_phase_logpT.
pack();
1294 pure_saturation.
pack();
1295 phase_envelope.
pack();
1304 return _Q * yV + (1 -
_Q) * yL;
1307 this->AS->set_T(
_T);
1308 return this->AS->cp0molar();
1312 this->AS->set_T(
_T);
1313 return this->AS->surface_tension();
1314 this->AS->set_T(_HUGE);
1346 std::cout <<
format(
"Table loading failed with error: %s\n", e.
what());
1350 #if defined(__ISWINDOWS__)
1351 double directory_size_in_GB =
CalculateDirSize(std::wstring(table_path.begin(), table_path.end())) /
POW3(1024.0);
1355 double allowed_size_in_GB =
get_config_double(MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB);
1357 std::cout <<
"Tabular directory size is " << directory_size_in_GB <<
" GB\n";
1359 if (directory_size_in_GB > 1.5 * allowed_size_in_GB) {
1361 format(
"Maximum allowed tabular directory size is %g GB, you have exceeded 1.5 times this limit", allowed_size_in_GB));
1362 }
else if (directory_size_in_GB > allowed_size_in_GB) {
1363 set_warning_string(
format(
"Maximum allowed tabular directory size is %g GB, you have exceeded this limit", allowed_size_in_GB));