1#ifndef TABULAR_BACKENDS_H
2#define TABULAR_BACKENDS_H
19#define LIST_OF_MATRICES \
63#define LIST_OF_SATURATION_VECTORS \
105#define X(name) name = PED.name;
109#define X(name) name = PED.name;
114 std::map<std::string, std::vector<double>>
vectors;
115 std::map<std::string, std::vector<std::vector<double>>>
matrices;
122#define X(name) vectors.insert(std::pair<std::string, std::vector<double>>(#name, name));
126#define X(name) matrices.insert(std::pair<std::string, std::vector<std::vector<double>>>(#name, name));
137 std::map<std::string, std::vector<std::vector<double>>>::iterator
get_matrix_iterator(
const std::string& name) {
149#define X(name) name = get_vector_iterator(#name)->second;
155#define X(name) name = get_matrix_iterator(#name)->second;
159 iTsat_max = std::distance(
T.begin(), std::max_element(
T.begin(),
T.end()));
161 ipsat_max = std::distance(p.begin(), std::max_element(p.begin(), p.end()));
165 deserialized.convert(temp);
170 std::swap(*
this, temp);
176 conversion_factor = 1.0;
179 conversion_factor = molar_mass;
183 conversion_factor /= molar_mass;
187 conversion_factor /= molar_mass;
191 conversion_factor /= molar_mass;
195 conversion_factor /= molar_mass;
199 conversion_factor /= molar_mass;
217 throw ValueError(
"TabularBackends::mass_to_molar - I don't know how to convert this parameter");
229 shared_ptr<CoolProp::AbstractState>
AS;
234 void build(shared_ptr<CoolProp::AbstractState>&
AS);
237#define X(name) std::vector<double> name;
242 std::map<std::string, std::vector<double>>
vectors;
261 auto [yvecL, yvecV] = [&]() -> std::pair<std::vector<double>*, std::vector<double>*> {
266 return {&hmolarL, &hmolarV};
270 return {&smolarL, &smolarV};
272 return {&umolarL, &umolarV};
274 return {&rhomolarL, &rhomolarV};
276 throw ValueError(
"invalid input for other in is_inside");
283 double pmax = this->pV[pV.size() - 1], pmin = this->pV[0];
284 if (mainval > pmax || mainval < pmin) {
289 double Tmax = this->TV[TV.size() - 1], Tmin = this->TV[0];
290 if (mainval > Tmax || mainval < Tmin) {
294 throw ValueError(
"invalid input for other in is_inside");
298 std::size_t iLplus, iVplus;
309 throw ValueError(
format(
"For now, main input in is_inside must be T or p"));
312 iVplus = std::min(iV + 1,
N - 1);
313 iLplus = std::min(iL + 1,
N - 1);
323 double logp = log(mainval);
325 yV =
CubicInterp(logpV, TV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, logp);
326 yL =
CubicInterp(logpL, TL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, logp);
329 yV = exp(
CubicInterp(TV, logpV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, mainval));
330 yL = exp(
CubicInterp(TL, logpL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, mainval));
335 double ymin =
min4((*yvecL)[iL], (*yvecL)[iLplus], (*yvecV)[iV], (*yvecV)[iVplus]);
336 double ymax =
max4((*yvecL)[iL], (*yvecL)[iLplus], (*yvecV)[iV], (*yvecV)[iVplus]);
337 if (val < ymin || val > ymax) {
348 double logp = log(mainval);
349 yV =
CubicInterp(logpV, *yvecV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, logp);
350 yL =
CubicInterp(logpL, *yvecL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, logp);
352 yV =
CubicInterp(TV, *yvecV, iVplus - 3, iVplus - 2, iVplus - 1, iVplus, mainval);
353 yL =
CubicInterp(TL, *yvecL, iLplus - 3, iLplus - 2, iLplus - 1, iLplus, mainval);
369 std::fill(name.begin(), name.end(), _HUGE);
376#define X(name) vectors.insert(std::pair<std::string, std::vector<double>>(#name, name));
390#define X(name) name = get_vector_iterator(#name)->second;
397 deserialized.convert(temp);
404 std::swap(*
this, temp);
410 }
else if (iL + 1 ==
N) {
415 }
else if (iV + 1 ==
N) {
418 double logp = log(p_or_T);
421 double _logpV =
CubicInterp(this->TV, logpV, iV - 2, iV - 1, iV, iV + 1, p_or_T);
422 double _logpL =
CubicInterp(this->TL, logpL, iL - 2, iL - 1, iL, iL + 1, p_or_T);
423 return Q * exp(_logpV) + (1 - Q) * exp(_logpL);
426 double TV =
CubicInterp(logpV, this->TV, iV - 2, iV - 1, iV, iV + 1, logp);
427 double TL =
CubicInterp(logpL, this->TL, iL - 2, iL - 1, iL, iL + 1, logp);
428 return Q * TV + (1 - Q) * TL;
431 double sV =
CubicInterp(logpV, smolarV, iV - 2, iV - 1, iV, iV + 1, logp);
432 double sL =
CubicInterp(logpL, smolarL, iL - 2, iL - 1, iL, iL + 1, logp);
433 return Q * sV + (1 - Q) * sL;
436 double hV =
CubicInterp(logpV, hmolarV, iV - 2, iV - 1, iV, iV + 1, logp);
437 double hL =
CubicInterp(logpL, hmolarL, iL - 2, iL - 1, iL, iL + 1, logp);
438 return Q * hV + (1 - Q) * hL;
441 double uV =
CubicInterp(logpV, umolarV, iV - 2, iV - 1, iV, iV + 1, logp);
442 double uL =
CubicInterp(logpL, umolarL, iL - 2, iL - 1, iL, iL + 1, logp);
443 return Q * uV + (1 - Q) * uL;
446 double rhoV = exp(
CubicInterp(logpV, logrhomolarV, iV - 2, iV - 1, iV, iV + 1, logp));
447 double rhoL = exp(
CubicInterp(logpL, logrhomolarL, iL - 2, iL - 1, iL, iL + 1, logp));
454 return 1 / (Q / rhoV + (1 - Q) / rhoL);
457 double kV =
CubicInterp(logpV, condV, iV - 2, iV - 1, iV, iV + 1, logp);
458 double kL =
CubicInterp(logpL, condL, iL - 2, iL - 1, iL, iL + 1, logp);
465 return Q * kV + (1 - Q) * kL;
468 double muV = exp(
CubicInterp(logpV, logviscV, iV - 2, iV - 1, iV, iV + 1, logp));
469 double muL = exp(
CubicInterp(logpL, logviscL, iL - 2, iL - 1, iL, iL + 1, logp));
476 return 1 / (Q / muV + (1 - Q) / muL);
479 double cpV =
CubicInterp(logpV, cpmolarV, iV - 2, iV - 1, iV, iV + 1, logp);
480 double cpL =
CubicInterp(logpL, cpmolarL, iL - 2, iL - 1, iL, iL + 1, logp);
487 return Q * cpV + (1 - Q) * cpL;
490 double cvV =
CubicInterp(logpV, cvmolarV, iV - 2, iV - 1, iV, iV + 1, logp);
491 double cvL =
CubicInterp(logpL, cvmolarL, iL - 2, iL - 1, iL, iL + 1, logp);
498 return Q * cvV + (1 - Q) * cvL;
501 double wV =
CubicInterp(logpV, speed_soundV, iV - 2, iV - 1, iV, iV + 1, logp);
502 double wL =
CubicInterp(logpL, speed_soundL, iL - 2, iL - 1, iL, iL + 1, logp);
509 return Q * wV + (1 - Q) * wL;
512 throw ValueError(
"Output variable for evaluate is invalid");
524 if (i < 2 || i > TL.size() - 2) {
525 throw ValueError(
format(
"Invalid index (%d) to calc_first_saturation_deriv in TabularBackends", i));
527 std::vector<double>*x, *y;
531 x = (Q == 0) ? &TL : &TV;
534 x = (Q == 0) ? &pL : &pV;
537 throw ValueError(
format(
"Key for Wrt1 is invalid in calc_first_saturation_deriv"));
542 y = (Q == 0) ? &TL : &TV;
545 y = (Q == 0) ? &pL : &pV;
548 y = (Q == 0) ? &rhomolarL : &rhomolarV;
551 y = (Q == 0) ? &hmolarL : &hmolarV;
554 y = (Q == 0) ? &smolarL : &smolarV;
557 y = (Q == 0) ? &umolarL : &umolarV;
560 y = (Q == 0) ? &rhomolarL : &rhomolarV;
561 factor =
AS->molar_mass();
564 y = (Q == 0) ? &hmolarL : &hmolarV;
565 factor = 1 /
AS->molar_mass();
568 y = (Q == 0) ? &smolarL : &smolarV;
569 factor = 1 /
AS->molar_mass();
572 y = (Q == 0) ? &umolarL : &umolarV;
573 factor = 1 /
AS->molar_mass();
576 throw ValueError(
format(
"Key for Of1 is invalid in calc_first_saturation_deriv"));
578 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;
593 shared_ptr<CoolProp::AbstractState>
AS;
605 Nx = (nx_cfg > 1) ?
static_cast<std::size_t
>(nx_cfg) : 200;
606 Ny = (ny_cfg > 1) ?
static_cast<std::size_t
>(ny_cfg) : 200;
610#define X(name) std::vector<std::vector<double>> name;
614 std::map<std::string, std::vector<std::vector<double>>>
matrices;
616 void build(shared_ptr<CoolProp::AbstractState>&
AS);
622#define X(name) name.resize(Nx, std::vector<double>(Ny, _HUGE));
644 for (std::size_t i = 0; i <
xvec.size(); ++i) {
645 for (std::size_t j = 0; j <
yvec.size(); ++j) {
649 int xoffsets[] = {-1, 1, 0, 0, -1, 1, 1, -1};
650 int yoffsets[] = {0, 0, 1, -1, -1, -1, 1, 1};
652 std::size_t N =
sizeof(xoffsets) /
sizeof(xoffsets[0]);
653 for (std::size_t k = 0; k < N; ++k) {
654 std::size_t iplus = i + xoffsets[k];
655 std::size_t jplus = j + yoffsets[k];
656 if (0 < iplus && iplus <
Nx - 1 && 0 < jplus && jplus <
Ny - 1 &&
ValidNumber(
T[iplus][jplus])) {
669#define X(name) matrices.insert(std::pair<std::string, std::vector<std::vector<double>>>(#name, name));
683#define X(name) name = get_matrices_iterator(#name)->second;
694 return x >=
xmin - e && x <= xmax + e && y >=
ymin - e && y <=
ymax + e;
703 if (x > (
xvec[i] +
xvec[i + 1]) / 2.0) {
707 if (x > sqrt(
xvec[i] *
xvec[i + 1])) {
715 if (y > (
yvec[j] +
yvec[j + 1]) / 2.0) {
719 if (y > sqrt(
yvec[j] *
yvec[j + 1])) {
727 if (givenkey ==
ykey) {
735 const std::vector<std::vector<double>>&
mat =
get(otherkey);
736 double closest_diff = 1e20;
737 std::size_t closest_i = 0;
738 for (std::size_t index = 0; index <
mat.size(); ++index) {
739 double diff = std::abs(
mat[index][j] - otherval);
740 if (diff < closest_diff) {
747 }
else if (givenkey ==
xkey) {
750 const std::vector<std::vector<double>>& v =
get(otherkey);
810 if (this->
AS.get() ==
nullptr) {
824 xmax = std::max(xmax1, xmax2);
830 deserialized.convert(temp);
832 if (
Nx != temp.
Nx ||
Ny != temp.
Ny) {
838 }
else if ((std::abs(
xmin) > 1e-10 && std::abs(
xmax) > 1e-10)
841 }
else if ((std::abs(
ymin) > 1e-10 && std::abs(
ymax) > 1e-10)
845 std::swap(*
this, temp);
864 if (this->
AS.get() ==
nullptr) {
872 xmax =
AS->Tmax() * 1.499;
877 deserialized.convert(temp);
879 if (
Nx != temp.
Nx ||
Ny != temp.
Ny) {
885 }
else if ((std::abs(
xmin) > 1e-10 && std::abs(
xmax) > 1e-10)
888 }
else if ((std::abs(
ymin) > 1e-10 && std::abs(
ymax) > 1e-10)
892 std::swap(*
this, temp);
902 std::size_t alt_i, alt_j;
903 bool _valid, _has_valid_neighbor;
925 throw KeyError(
format(
"Invalid key to get() function of CellCoeffs"));
950 throw KeyError(
format(
"Invalid key to set() function of CellCoeffs"));
969 _has_valid_neighbor =
true;
972 [[nodiscard]] std::optional<std::pair<std::size_t, std::size_t>>
get_alternate()
const {
973 if (_has_valid_neighbor) {
974 return std::make_pair(alt_i, alt_j);
995 void load_tables(
const std::string& path_to_tables, shared_ptr<CoolProp::AbstractState>& AS);
997 void build_tables(shared_ptr<CoolProp::AbstractState>& AS);
1005 std::map<std::string, TabularDataSet> data;
1010 std::vector<std::string> fluids = AS->fluid_names();
1011 std::vector<CoolPropDbl> fractions = AS->get_mole_fractions();
1012 std::vector<std::string> components;
1013 components.reserve(fluids.size());
1014 for (std::size_t i = 0; i < fluids.size(); ++i) {
1015 components.push_back(
format(
"%s[%0.10Lf]", fluids[i].c_str(), fractions[i]));
1017 std::string table_directory =
get_home_dir() +
"/.CoolProp/Tables/";
1018 std::string alt_table_directory =
get_config_string(ALTERNATIVE_TABLES_DIRECTORY);
1019 if (!alt_table_directory.empty()) {
1020 table_directory = alt_table_directory;
1022 return table_directory + AS->backend_name() +
"(" +
strjoin(components,
"&") +
")";
1025 std::pair<TabularDataSet*, bool>
get_set_of_tables(shared_ptr<AbstractState>& AS);
1048 std::vector<std::vector<double>>
const*
z;
1049 std::vector<std::vector<double>>
const*
dzdx;
1050 std::vector<std::vector<double>>
const*
dzdy;
1051 std::vector<std::vector<double>>
const*
d2zdx2;
1053 std::vector<std::vector<double>>
const*
d2zdy2;
1057 shared_ptr<CoolProp::AbstractState>
AS;
1086 return AS->fluid_names();
1101 z = &table.rhomolar;
1102 dzdx = &table.drhomolardx;
1103 dzdy = &table.drhomolardy;
1104 d2zdxdy = &table.d2rhomolardxdy;
1105 d2zdx2 = &table.d2rhomolardx2;
1106 d2zdy2 = &table.d2rhomolardy2;
1110 dzdx = &table.dsmolardx;
1111 dzdy = &table.dsmolardy;
1112 d2zdxdy = &table.d2smolardxdy;
1113 d2zdx2 = &table.d2smolardx2;
1114 d2zdy2 = &table.d2smolardy2;
1118 dzdx = &table.dhmolardx;
1119 dzdy = &table.dhmolardy;
1120 d2zdxdy = &table.d2hmolardxdy;
1121 d2zdx2 = &table.d2hmolardx2;
1122 d2zdy2 = &table.d2hmolardy2;
1126 dzdx = &table.dumolardx;
1127 dzdy = &table.dumolardy;
1128 d2zdxdy = &table.d2umolardxdy;
1129 d2zdx2 = &table.d2umolardx2;
1130 d2zdy2 = &table.d2umolardy2;
1185 const CoolProp::parameters* outputs, std::size_t N_outputs,
double* out_buffer, std::size_t out_buffer_size,
int* status_flags,
1192 double y, std::size_t& i, std::size_t& j) = 0;
1195 const parameters variable1,
const double value1,
const parameters other,
const double otherval, std::size_t& i,
1196 std::size_t& j) = 0;
1199 parameters output,
double x,
double y, std::size_t i, std::size_t j) = 0;
1202 parameters output,
double x,
double y, std::size_t i, std::size_t j) = 0;
1208 return this->AS->T_critical();
1211 return this->AS->Ttriple();
1214 return this->AS->p_triple();
1217 return this->AS->pmax();
1220 return this->AS->Tmax();
1223 return this->AS->Tmin();
1226 return this->AS->p_critical();
1229 return this->AS->rhomolar_critical();
1248 return AS->get_mole_fractions();
1251 return AS->get_mass_fractions();
1255 return AS->molar_mass();
1270 single_phase_logph.
pack();
1271 single_phase_logpT.
pack();
1272 pure_saturation.
pack();
1273 phase_envelope.
pack();
1282 return _Q * yV + (1 -
_Q) * yL;
1285 this->AS->set_T(
_T);
1286 return this->AS->cp0molar();
1290 this->AS->set_T(
_T);
1291 return this->AS->surface_tension();
1292 this->AS->set_T(_HUGE);
1324 std::cout <<
format(
"Table loading failed with error: %s\n", e.
what());
1329 double allowed_size_in_GB =
get_config_double(MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB);
1331 std::cout <<
"Tabular directory size is " << directory_size_in_GB <<
" GB\n";
1333 if (directory_size_in_GB > 1.5 * allowed_size_in_GB) {
1335 format(
"Maximum allowed tabular directory size is %g GB, you have exceeded 1.5 times this limit", allowed_size_in_GB));
1336 }
else if (directory_size_in_GB > allowed_size_in_GB) {
1337 set_warning_string(
format(
"Maximum allowed tabular directory size is %g GB, you have exceeded this limit", allowed_size_in_GB));