teqp 0.22.0
Loading...
Searching...
No Matches
ideal_eosterms.hpp
Go to the documentation of this file.
1#pragma once
2#include <variant>
3#include <filesystem>
4
5#include "teqp/types.hpp"
6#include "teqp/exceptions.hpp"
7#include "teqp/json_tools.hpp"
8
9namespace teqp {
10
15 public:
16 const double a, R;
17 IdealHelmholtzConstant(double a, double R) : a(a), R(R) {};
18
19 template<typename TType, typename RhoType>
20 auto alphaig(const TType& /*T*/, const RhoType& /*rho*/) const {
21 using otype = std::common_type_t <TType, RhoType>;
22 return forceeval(static_cast<otype>(a));
23 }
24 };
25
36 public:
37 const double a, R;
38 IdealHelmholtzLogT(double a, double R) : a(a), R(R) {};
39
40 template<typename TType, typename RhoType>
41 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
42 using otype = std::common_type_t <TType, RhoType>;
43 return forceeval(static_cast<otype>(a * log(T)));
44 }
45 };
46
59 public:
60 const double a_1, a_2, R;
61 IdealHelmholtzLead(double a_1, double a_2, double R) : a_1(a_1), a_2(a_2), R(R) {};
62
63 template<typename TType, typename RhoType>
64 auto alphaig(const TType& T, const RhoType& rho) const {
65 using otype = std::common_type_t <TType, RhoType>;
66 return forceeval(static_cast<otype>(log(rho) + a_1 + a_2 / T));
67 }
68 };
69
74 public:
75 const std::valarray<double> n, t;
76 const double R;
77 IdealHelmholtzPowerT(const std::valarray<double>& n, const std::valarray<double>& t, double R) : n(n), t(t), R(R) {};
78
79 template<typename TType, typename RhoType>
80 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
81 std::common_type_t <TType, RhoType> summer = 0.0;
82 for (auto i = 0U; i < n.size(); ++i) {
83 summer += n[i] * pow(T, t[i]);
84 }
85 return forceeval(summer);
86 }
87 };
88
93 public:
94 const std::valarray<double> n, theta;
95 const double R;
96 IdealHelmholtzPlanckEinstein(const std::valarray<double>& n, const std::valarray<double>& theta, double R) : n(n), theta(theta), R(R) {};
97
98 template<typename TType, typename RhoType>
99 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
100 std::common_type_t <TType, RhoType> summer = 0.0;
101 for (auto i = 0U; i < n.size(); ++i) {
102 summer += n[i] * log(1.0 - exp(-theta[i] / T));
103 }
104 return forceeval(summer);
105 }
106 };
107
112 public:
113 const std::valarray<double> n, c, d, theta;
114 const double R;
116 const std::valarray<double>& n,
117 const std::valarray<double>& c,
118 const std::valarray<double>& d,
119 const std::valarray<double>& theta,
120 double R
121 ) : n(n), c(c), d(d), theta(theta), R(R) {};
122
123 template<typename TType, typename RhoType>
124 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
125 std::common_type_t <TType, RhoType> summer = 0.0;
126 for (auto i = 0U; i < n.size(); ++i) {
127 summer += n[i] * log(c[i] + d[i]*exp(theta[i] / T));
128 }
129 return forceeval(summer);
130 }
131 };
132
139 public:
140 const std::valarray<double> n, theta;
141 const double R;
142 IdealHelmholtzGERG2004Cosh(const std::valarray<double>& n, const std::valarray<double>& theta, double R) : n(n), theta(theta), R(R) {};
143
144 template<typename TType, typename RhoType>
145 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
146 std::common_type_t <TType, RhoType> summer = 0.0;
147 for (auto i = 0U; i < n.size(); ++i) {
148 using std::abs;
149 TType cosh_theta_over_T = cosh(theta[i] / T);
150 summer += n[i] * log(abs(cosh_theta_over_T));
151 }
152 return forceeval(summer);
153 }
154 };
155
162 public:
163 const std::valarray<double> n, theta;
164 const double R;
165 IdealHelmholtzGERG2004Sinh(const std::valarray<double>& n, const std::valarray<double>& theta, double R) : n(n), theta(theta), R(R) {};
166
167 template<typename TType, typename RhoType>
168 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
169 std::common_type_t <TType, RhoType> summer = 0.0;
170 for (auto i = 0U; i < n.size(); ++i) {
171 using std::abs;
172 TType sinh_theta_over_T = sinh(theta[i] / T);
173 summer += n[i] * log(abs(sinh_theta_over_T));
174 }
175 return forceeval(summer);
176 }
177 };
178
187 public:
188 const double c, T_0;
189 const double R;
191 const double c, const double T_0, const double R
192 ) : c(c), T_0(T_0), R(R) {};
193
194 template<typename TType, typename RhoType>
195 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
196 using otype = std::common_type_t <TType, RhoType>;
197 return forceeval(static_cast<otype>(
198 c*((T-T_0)/T-log(T/T_0))
199 ));
200 }
201 };
202
211 public:
212 const double c, t, T_0;
213 const double R;
215 const double c, const double t, const double T_0, const double R
216 ) : c(c), t(t), T_0(T_0), R(R) {};
217
218 template<typename TType, typename RhoType>
219 auto alphaig(const TType& T, const RhoType& /*rho*/) const {
220 using otype = std::common_type_t <TType, RhoType>;
221 return forceeval(static_cast<otype>(
222 c*(pow(T,t)*(1/(t+1)-1/t) - pow(T_0,t+1)/(T*(t+1)) + pow(T_0,t)/t)
223 ));
224 }
225 };
226
227 // The collection of possible terms that could be part of the summation
228 using IdealHelmholtzTerms = std::variant <
239 > ;
240
242 public:
243 std::vector<IdealHelmholtzTerms> contributions;
244 PureIdealHelmholtz(const nlohmann::json& jpure) {
245 //std::string s = jpure.dump(1);
246 if (jpure.is_array()) {
247 throw teqp::InvalidArgument("JSON data passed to PureIdealHelmholtz must be an object and contain the fields \"R\" and \"terms\"");
248 }
249 double R = jpure.at("R");
250 for (auto& term : jpure.at("terms")) {
251 if (!term.is_object()) {
252 throw teqp::InvalidArgument("JSON data for pure fluid must be an object");
253 }
254 //std::string s = term.dump(1);
255 if (term.at("type") == "Constant") { // a
256 contributions.emplace_back(IdealHelmholtzConstant(term.at("a"), R));
257 }
258 else if (term.at("type") == "Lead") { // ln(rho) + a_1 + a_2/T
259 contributions.emplace_back(IdealHelmholtzLead(term.at("a_1"), term.at("a_2"), R));
260 }
261 else if (term.at("type") == "LogT") { // a*ln(T)
262 contributions.emplace_back(IdealHelmholtzLogT(term.at("a"), R));
263 }
264 else if (term.at("type") == "PowerT") { // sum_i n_i * T^i
265 contributions.emplace_back(IdealHelmholtzPowerT(term.at("n"), term.at("t"), R));
266 }
267 else if (term.at("type") == "PlanckEinstein") {
268 contributions.emplace_back(IdealHelmholtzPlanckEinstein(term.at("n"), term.at("theta"), R));
269 }
270 else if (term.at("type") == "PlanckEinsteinGeneralized") {
271 contributions.emplace_back(IdealHelmholtzPlanckEinsteinGeneralized(term.at("n"), term.at("c"), term.at("d"), term.at("theta"), R));
272 }
273 else if (term.at("type") == "GERG2004Cosh") {
274 contributions.emplace_back(IdealHelmholtzGERG2004Cosh(term.at("n"), term.at("theta"), R));
275 }
276 else if (term.at("type") == "GERG2004Sinh") {
277 contributions.emplace_back(IdealHelmholtzGERG2004Sinh(term.at("n"), term.at("theta"), R));
278 }
279 else if (term.at("type") == "Cp0Constant") {
280 contributions.emplace_back(IdealHelmholtzCp0Constant(term.at("c"), term.at("T_0"), R));
281 }
282 else if (term.at("type") == "Cp0PowerT") {
283 contributions.emplace_back(IdealHelmholtzCp0PowerT(term.at("c"), term.at("t"), term.at("T_0"), R));
284 }
285 else {
286 throw InvalidArgument("Don't understand this type: " + term.at("type").get<std::string>());
287 }
288 }
289 }
290
291 template<typename TType, typename RhoType>
292 auto alphaig(const TType& T, const RhoType &rho) const{
293 std::common_type_t <TType, RhoType> ig = 0.0;
294 for (const auto& term : contributions) {
295 auto contrib = std::visit([&](auto& t) { return t.alphaig(T, rho); }, term);
296 ig = ig + contrib;
297 }
298 return ig;
299 }
300 };
301
311
312 public:
313
314 std::vector<PureIdealHelmholtz> pures;
315
316 IdealHelmholtz(const nlohmann::json &jpures){
317 if (!jpures.is_array()) {
318 throw teqp::InvalidArgument("JSON data passed to IdealHelmholtz must be an array");
319 }
320 for (auto &jpure : jpures){
321 pures.emplace_back(jpure);
322 }
323 }
324
325 template<typename TType, typename RhoType, typename MoleFrac>
326 auto alphaig(const TType& T, const RhoType &rho, const MoleFrac &molefrac) const {
327 std::common_type_t <TType, RhoType, decltype(molefrac[0])> ig = 0.0;
328 if (static_cast<std::size_t>(molefrac.size()) != pures.size()){
329 throw teqp::InvalidArgument("molefrac and pures are not the same length");
330 }
331 std::size_t i = 0;
332 for (auto &pure : pures){
333 if (getbaseval(molefrac[i]) != 0){
334 ig += molefrac[i]*(pure.alphaig(T, rho) + log(molefrac[i]));
335 }
336 else{
337 // lim_{x\to 0} x*ln(x) => 0
338 }
339 i++;
340 }
341 return ig;
342 }
343
346 template<typename TType, typename RhoType, typename MoleFrac>
347 auto alphar(const TType& T, const RhoType &rho, const MoleFrac &molefrac) const {
348 return alphaig(T, rho, molefrac);
349 }
350
352 template<typename MoleFrac>
353 auto R(const MoleFrac &/*molefrac*/) const{
354 return 8.31446261815324; // J/mol/K
355 }
356
357 };
358
359 inline nlohmann::json CoolProp2teqp_alphaig_term_reformatter(const nlohmann::json &term, double Tri, double rhori, double R){
360 //std::string s = term.dump(1);
361
362 if (term.at("type") == "IdealGasHelmholtzLead") {
363 // Was ln(delta) + a_1 + a_2*tau ==> ln(rho) + a_1 + a_2/T
364 // new a_1 is old a_1 - ln(rho_ri)
365 // new a_2 is old a_2 * Tri
366 return {{{"type", "Lead"}, {"a_1", term.at("a1").get<double>() - log(rhori)}, {"a_2", term.at("a2").get<double>() * Tri}, {"R", R}}};
367 }
368 else if (term.at("type") == "IdealGasHelmholtzEnthalpyEntropyOffset") {
369 // Was a_1 + a_2*tau ==> a_1 + a_2/T
370 std::valarray<double> n = {term.at("a1").get<double>(), term.at("a2").get<double>()*Tri};
371 std::valarray<double> t = {0, -1};
372 return {{{"type", "PowerT"}, {"n", n}, {"t", t}, {"R", R}}};
373 }
374 else if (term.at("type") == "IdealGasHelmholtzLogTau") { // a*ln(tau)
375 // Was a*ln(tau) = a*ln(Tri) - a*ln(T) ==> a*ln(T)
376 // Breaks into two pieces, first is a constant term a*ln(Tri), next is a*ln(T) piece
377 double a = term.at("a").get<double>();
378 nlohmann::json term1 = {{"type", "Constant"}, {"a", a*log(Tri)}, {"R", R}};
379 nlohmann::json term2 = {{"type", "LogT"}, {"a", -a}, {"R", R}};
380 return {term1, term2};
381 }
382 else if (term.at("type") == "IdealGasHelmholtzPlanckEinstein") {
383 // Was
384 std::valarray<double> n = term.at("n");
385 std::valarray<double> theta = term.at("t").get<std::valarray<double>>()*Tri;
386 return {{{"type", "PlanckEinstein"}, {"n", n}, {"theta", theta}, {"R", R}}};
387 }
388 else if (term.at("type") == "IdealGasHelmholtzPlanckEinsteinFunctionT") {
389 // Was
390 std::valarray<double> n = term.at("n");
391 std::valarray<double> theta = term.at("v");
392 return {{{"type", "PlanckEinstein"}, {"n", n}, {"theta", theta}, {"R", R}}};
393 }
394 else if (term.at("type") == "IdealGasHelmholtzPlanckEinsteinGeneralized") {
395 // Was
396 std::valarray<double> n = term.at("n");
397 std::valarray<double> c = term.at("c");
398 std::valarray<double> d = term.at("d");
399 std::valarray<double> theta = term.at("t").get<std::valarray<double>>()*Tri;
400// std::cout << term.dump() << std::endl;
401 return {{{"type", "PlanckEinsteinGeneralized"}, {"n", n}, {"c", c}, {"d", d}, {"theta", theta}, {"R", R}}};
402 }
403 else if (term.at("type") == "IdealGasHelmholtzPower") {
404 // Was
405 std::valarray<double> n = term.at("n").get<std::valarray<double>>();
406 std::valarray<double> t = term.at("t").get<std::valarray<double>>();
407 for (auto i = 0U; i < n.size(); ++i){
408 n[i] *= pow(Tri, t[i]);
409 t[i] *= -1; // T is in the denominator in CoolProp terms, in the numerator in teqp
410 }
411 return {{{"type", "PowerT"}, {"n", n}, {"t", t}, {"R", R}}};
412 }
413 else if (term.at("type") == "IdealGasHelmholtzCP0PolyT") {
414 // Was
415 nlohmann::json newterms = nlohmann::json::array();
416// std::cout << term.dump() << std::endl;
417 std::valarray<double> t = term.at("t"), c = term.at("c");
418 double T_0 = term.at("T0");
419 for (auto i = 0U; i < t.size(); ++i){
420 if (t[i] == 0){
421 newterms.push_back({{"type", "Cp0Constant"}, {"c", c[i]}, {"T_0", T_0}, {"R", R}});
422 }
423 else{
424 newterms.push_back({{"type", "Cp0PowerT"}, {"c", c[i]}, {"t", t[i]}, {"T_0", T_0}, {"R", R}});
425 }
426 }
427 return newterms;
428 }
429 else if (term.at("type") == "IdealGasHelmholtzCP0Constant") {
430// std::cout << term.dump() << std::endl;
431 double T_0 = term.at("T0");
432 return {{{"type", "Cp0Constant"}, {"c", term.at("cp_over_R")}, {"T_0", T_0}, {"R", R}}};
433 }
434 else if (term.at("type") == "IdealGasHelmholtzCP0AlyLee") {
435 // Was
436 nlohmann::json newterms = nlohmann::json::array();
437// std::cout << term.dump() << std::endl;
438 std::valarray<double> constants = term.at("c");
439 double T_0 = term.at("T0");
440
441 // Take the constant term if nonzero
442 if (std::abs(constants[0]) > 1e-14) {
443 newterms.push_back({{"type", "Cp0Constant"}, {"c", constants[0]}, {"T_0", T_0}, {"R", R}});
444 }
445
446 std::vector<double> n, c, d, t;
447 if (std::abs(constants[1]) > 1e-14) {
448 // sinh term can be converted by setting a_k = C, b_k = 2*D, c_k = -1, d_k = 1
449 n.push_back(constants[1]);
450 t.push_back(-2 * constants[2]);
451 c.push_back(1);
452 d.push_back(-1);
453 }
454 if (std::abs(constants[3]) > 1e-14) {
455 // cosh term can be converted by setting a_k = C, b_k = 2*D, c_k = 1, d_k = 1
456 n.push_back(-constants[3]);
457 t.push_back(-2 * constants[4]);
458 c.push_back(1);
459 d.push_back(1);
460 }
461 newterms.push_back(
462 {{"type", "PlanckEinsteinGeneralized"}, {"n", n}, {"c", c}, {"d", d}, {"theta", t}, {"R", R}}
463 );
464 return newterms;
465 }
466// else if (term.at("type") == "GERG2004Cosh") {
467// //contributions.emplace_back(IdealHelmholtzGERG2004Cosh(term.at("n"), term.at("theta")));
468// }
469// else if (term.at("type") == "GERG2004Sinh") {
470// //contributions.emplace_back(IdealHelmholtzGERG2004Sinh(term.at("n"), term.at("theta")));
471// }
472 else {
473 throw InvalidArgument("Don't understand this type of CoolProp ideal-gas Helmholtz energy term: " + term.at("type").get<std::string>());
474 }
475 }
476
489 inline nlohmann::json convert_CoolProp_idealgas(const std::string &s, int index){
490
491 nlohmann::json j;
492
493 // Get the JSON structure to be parsed
494 try{
495 // First assume that the input argument is a path
496 std::filesystem::path p = s;
497 j = load_a_JSON_file(s);
498 }
499 catch(std::exception &){
500 j = nlohmann::json::parse(s);
501 }
502
503 // Extract the things from the CoolProp-formatted data structure
504 auto jEOS = j.at("EOS")[index];
505 auto jCP = jEOS.at("alpha0");
506 double Tri = jEOS.at("STATES").at("reducing").at("T");
507 double rhori = jEOS.at("STATES").at("reducing").at("rhomolar");
508 double R = jEOS.at("gas_constant");
509
510 // Now we transform the inputs to teqp-formatted terms
511 nlohmann::json newterms = nlohmann::json::array();
512 for (const auto& term : jCP){
513 // Converted can be a two-element array, so all terms are returned as array
514 // and then put into newterms
515 auto converted = CoolProp2teqp_alphaig_term_reformatter(term, Tri, rhori, R);
516 for (auto newterm : converted){
517 newterms.push_back(newterm);
518 if (!newterms.back().is_object()){
519 std::cout << newterm.dump() << std::endl;
520 }
521 }
522 }
523
524 // And return our new data structure for this fluid
525 return {{"terms", newterms}, {"R", R}};
526 }
527}
IdealHelmholtzConstant(double a, double R)
auto alphaig(const TType &, const RhoType &) const
auto alphaig(const TType &T, const RhoType &) const
IdealHelmholtzCp0Constant(const double c, const double T_0, const double R)
IdealHelmholtzCp0PowerT(const double c, const double t, const double T_0, const double R)
auto alphaig(const TType &T, const RhoType &) const
auto alphaig(const TType &T, const RhoType &) const
const std::valarray< double > n
IdealHelmholtzGERG2004Cosh(const std::valarray< double > &n, const std::valarray< double > &theta, double R)
const std::valarray< double > theta
const std::valarray< double > theta
const std::valarray< double > n
auto alphaig(const TType &T, const RhoType &) const
IdealHelmholtzGERG2004Sinh(const std::valarray< double > &n, const std::valarray< double > &theta, double R)
auto alphaig(const TType &T, const RhoType &rho) const
IdealHelmholtzLead(double a_1, double a_2, double R)
auto alphaig(const TType &T, const RhoType &) const
IdealHelmholtzLogT(double a, double R)
auto alphaig(const TType &T, const RhoType &) const
IdealHelmholtzPlanckEinsteinGeneralized(const std::valarray< double > &n, const std::valarray< double > &c, const std::valarray< double > &d, const std::valarray< double > &theta, double R)
IdealHelmholtzPlanckEinstein(const std::valarray< double > &n, const std::valarray< double > &theta, double R)
auto alphaig(const TType &T, const RhoType &) const
const std::valarray< double > theta
const std::valarray< double > n
auto alphaig(const TType &T, const RhoType &) const
const std::valarray< double > t
IdealHelmholtzPowerT(const std::valarray< double > &n, const std::valarray< double > &t, double R)
const std::valarray< double > n
Ideal-gas Helmholtz energy container.
auto alphaig(const TType &T, const RhoType &rho, const MoleFrac &molefrac) const
auto alphar(const TType &T, const RhoType &rho, const MoleFrac &molefrac) const
IdealHelmholtz(const nlohmann::json &jpures)
std::vector< PureIdealHelmholtz > pures
auto R(const MoleFrac &) const
PureIdealHelmholtz(const nlohmann::json &jpure)
auto alphaig(const TType &T, const RhoType &rho) const
std::vector< IdealHelmholtzTerms > contributions
std::variant< IdealHelmholtzConstant, IdealHelmholtzLead, IdealHelmholtzLogT, IdealHelmholtzPowerT, IdealHelmholtzPlanckEinstein, IdealHelmholtzPlanckEinsteinGeneralized, IdealHelmholtzGERG2004Cosh, IdealHelmholtzGERG2004Sinh, IdealHelmholtzCp0Constant, IdealHelmholtzCp0PowerT > IdealHelmholtzTerms
nlohmann::json load_a_JSON_file(const std::string &path)
Load a JSON file from a specified file.
auto getbaseval(const T &expr)
Definition types.hpp:90
nlohmann::json CoolProp2teqp_alphaig_term_reformatter(const nlohmann::json &term, double Tri, double rhori, double R)
nlohmann::json convert_CoolProp_idealgas(const std::string &s, int index)
Convert the ideal-gas term for a term from CoolProp-formatted JSON structure.
auto pow(const double &x, const double &e)
Definition types.hpp:195
auto forceeval(T &&expr)
Definition types.hpp:52