CoolProp 6.8.0
An open-source fluid property and humid air property database
FluidLibrary.h
Go to the documentation of this file.
1
2#ifndef FLUIDLIBRARY_H
3#define FLUIDLIBRARY_H
4
5#include "CoolPropFluid.h"
6
7#include "rapidjson_include.h"
9
10#include <map>
11#include <algorithm>
12#include "Configuration.h"
14#include "Helmholtz.h"
15
16namespace CoolProp {
17
18// Forward declaration of the necessary debug function to avoid including the whole header
19extern int get_debug_level();
20
22
28{
30 std::map<std::size_t, CoolPropFluid> fluid_map;
32 std::map<std::size_t, std::string> JSONstring_map;
33 std::vector<std::string> name_vector;
34 std::map<std::string, std::size_t> string_to_index_map;
35 bool _is_empty;
36
37 public:
39 static ResidualHelmholtzContainer parse_alphar(rapidjson::Value& jsonalphar) {
41
42 for (rapidjson::Value::ValueIterator itr = jsonalphar.Begin(); itr != jsonalphar.End(); ++itr) {
43 // A reference for code cleanness
44 rapidjson::Value& contribution = *itr;
45
46 // Get the type (required!)
47 std::string type = contribution["type"].GetString();
48
49 if (!type.compare("ResidualHelmholtzPower")) {
50 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
51 std::vector<CoolPropDbl> d = cpjson::get_long_double_array(contribution["d"]);
52 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
53 std::vector<CoolPropDbl> l = cpjson::get_long_double_array(contribution["l"]);
54 assert(n.size() == d.size());
55 assert(n.size() == t.size());
56 assert(n.size() == l.size());
57
58 alphar.GenExp.add_Power(n, d, t, l);
59 } else if (!type.compare("ResidualHelmholtzGaussian")) {
60 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
61 std::vector<CoolPropDbl> d = cpjson::get_long_double_array(contribution["d"]);
62 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
63 std::vector<CoolPropDbl> eta = cpjson::get_long_double_array(contribution["eta"]);
64 std::vector<CoolPropDbl> epsilon = cpjson::get_long_double_array(contribution["epsilon"]);
65 std::vector<CoolPropDbl> beta = cpjson::get_long_double_array(contribution["beta"]);
66 std::vector<CoolPropDbl> gamma = cpjson::get_long_double_array(contribution["gamma"]);
67 assert(n.size() == d.size());
68 assert(n.size() == t.size());
69 assert(n.size() == eta.size());
70 assert(n.size() == epsilon.size());
71 assert(n.size() == beta.size());
72 assert(n.size() == gamma.size());
73 alphar.GenExp.add_Gaussian(n, d, t, eta, epsilon, beta, gamma);
74 } else if (!type.compare("ResidualHelmholtzGaoB")) {
75 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
76 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
77 std::vector<CoolPropDbl> d = cpjson::get_long_double_array(contribution["d"]);
78 std::vector<CoolPropDbl> eta = cpjson::get_long_double_array(contribution["eta"]);
79 std::vector<CoolPropDbl> beta = cpjson::get_long_double_array(contribution["beta"]);
80 std::vector<CoolPropDbl> gamma = cpjson::get_long_double_array(contribution["gamma"]);
81 std::vector<CoolPropDbl> epsilon = cpjson::get_long_double_array(contribution["epsilon"]);
82 std::vector<CoolPropDbl> b = cpjson::get_long_double_array(contribution["b"]);
83 assert(n.size() == t.size());
84 assert(n.size() == d.size());
85 assert(n.size() == eta.size());
86 assert(n.size() == epsilon.size());
87 assert(n.size() == beta.size());
88 assert(n.size() == gamma.size());
89 assert(n.size() == b.size());
90 alphar.GaoB = ResidualHelmholtzGaoB(n, t, d, eta, beta, gamma, epsilon, b);
91 } else if (!type.compare("ResidualHelmholtzNonAnalytic")) {
92 if (alphar.NonAnalytic.N > 0) {
93 throw ValueError("Cannot add ");
94 }
95 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
96 std::vector<CoolPropDbl> a = cpjson::get_long_double_array(contribution["a"]);
97 std::vector<CoolPropDbl> b = cpjson::get_long_double_array(contribution["b"]);
98 std::vector<CoolPropDbl> beta = cpjson::get_long_double_array(contribution["beta"]);
99 std::vector<CoolPropDbl> A = cpjson::get_long_double_array(contribution["A"]);
100 std::vector<CoolPropDbl> B = cpjson::get_long_double_array(contribution["B"]);
101 std::vector<CoolPropDbl> C = cpjson::get_long_double_array(contribution["C"]);
102 std::vector<CoolPropDbl> D = cpjson::get_long_double_array(contribution["D"]);
103 assert(n.size() == a.size());
104 assert(n.size() == b.size());
105 assert(n.size() == beta.size());
106 assert(n.size() == A.size());
107 assert(n.size() == B.size());
108 assert(n.size() == C.size());
109 assert(n.size() == D.size());
110 alphar.NonAnalytic = ResidualHelmholtzNonAnalytic(n, a, b, beta, A, B, C, D);
111 } else if (!type.compare("ResidualHelmholtzLemmon2005")) {
112 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
113 std::vector<CoolPropDbl> d = cpjson::get_long_double_array(contribution["d"]);
114 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
115 std::vector<CoolPropDbl> l = cpjson::get_long_double_array(contribution["l"]);
116 std::vector<CoolPropDbl> m = cpjson::get_long_double_array(contribution["m"]);
117 assert(n.size() == d.size());
118 assert(n.size() == t.size());
119 assert(n.size() == l.size());
120 assert(n.size() == m.size());
121 alphar.GenExp.add_Lemmon2005(n, d, t, l, m);
122 } else if (!type.compare("ResidualHelmholtzExponential")) {
123 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
124 std::vector<CoolPropDbl> d = cpjson::get_long_double_array(contribution["d"]);
125 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
126 std::vector<CoolPropDbl> g = cpjson::get_long_double_array(contribution["g"]);
127 std::vector<CoolPropDbl> l = cpjson::get_long_double_array(contribution["l"]);
128 assert(n.size() == d.size());
129 assert(n.size() == t.size());
130 assert(n.size() == g.size());
131 assert(n.size() == l.size());
132 alphar.GenExp.add_Exponential(n, d, t, g, l);
133 } else if (!type.compare("ResidualHelmholtzAssociating")) {
134 if (alphar.SAFT.disabled == false) {
135 throw ValueError("Cannot add ");
136 }
137 CoolPropDbl a = cpjson::get_double(contribution, "a");
138 CoolPropDbl m = cpjson::get_double(contribution, "m");
139 CoolPropDbl epsilonbar = cpjson::get_double(contribution, "epsilonbar");
140 CoolPropDbl vbarn = cpjson::get_double(contribution, "vbarn");
141 CoolPropDbl kappabar = cpjson::get_double(contribution, "kappabar");
142 alphar.SAFT = ResidualHelmholtzSAFTAssociating(a, m, epsilonbar, vbarn, kappabar);
143 } else {
144 throw ValueError(format("Unsupported Residual helmholtz type: %s", type.c_str()));
145 }
146 }
147
148 // Finish adding parts to the Generalized Exponential term, build other vectors
149 alphar.GenExp.finish();
150
151 return alphar;
152 };
153
155 static IdealHelmholtzContainer parse_alpha0(rapidjson::Value& jsonalpha0) {
156 if (!jsonalpha0.IsArray()) {
157 throw ValueError();
158 }
159
161
162 for (rapidjson::Value::ConstValueIterator itr = jsonalpha0.Begin(); itr != jsonalpha0.End(); ++itr) {
163 // A reference for code cleanness
164 const rapidjson::Value& contribution = *itr;
165
166 // Get the type (required!)
167 std::string type = contribution["type"].GetString();
168
169 if (!type.compare("IdealGasHelmholtzLead")) {
170 if (alpha0.Lead.is_enabled() == true) {
171 throw ValueError("Cannot add ");
172 }
173 CoolPropDbl a1 = cpjson::get_double(contribution, "a1");
174 CoolPropDbl a2 = cpjson::get_double(contribution, "a2");
175
176 alpha0.Lead = IdealHelmholtzLead(a1, a2);
177 } else if (!type.compare("IdealGasHelmholtzPower")) {
178 if (alpha0.Power.is_enabled() == true) {
179 throw ValueError("Cannot add ");
180 }
181 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
182 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
183
184 alpha0.Power = IdealHelmholtzPower(n, t);
185 } else if (!type.compare("IdealGasHelmholtzLogTau")) {
186 if (alpha0.LogTau.is_enabled() == true) {
187 throw ValueError("Cannot add ");
188 }
189 CoolPropDbl a = cpjson::get_double(contribution, "a");
190
191 alpha0.LogTau = IdealHelmholtzLogTau(a);
192 } else if (!type.compare("IdealGasHelmholtzPlanckEinsteinGeneralized")) {
193 // Retrieve the values
194 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
195 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
196
197 std::vector<CoolPropDbl> c = cpjson::get_long_double_array(contribution["c"]);
198 std::vector<CoolPropDbl> d = cpjson::get_long_double_array(contribution["d"]);
199
200 if (alpha0.PlanckEinstein.is_enabled() == true) {
201 alpha0.PlanckEinstein.extend(n, t, c, d);
202 } else {
204 }
205 } else if (!type.compare("IdealGasHelmholtzPlanckEinstein")) {
206 // Retrieve the values
207 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
208 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
209 // Flip the sign of theta
210 for (std::size_t i = 0; i < t.size(); ++i) {
211 t[i] *= -1;
212 }
213 std::vector<CoolPropDbl> c(n.size(), 1);
214 std::vector<CoolPropDbl> d(c.size(), -1);
215
216 if (alpha0.PlanckEinstein.is_enabled() == true) {
217 alpha0.PlanckEinstein.extend(n, t, c, d);
218 } else {
220 }
221 } else if (!type.compare("IdealGasHelmholtzPlanckEinsteinFunctionT")) {
222 // Retrieve the values
223 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
224 std::vector<CoolPropDbl> v = cpjson::get_long_double_array(contribution["v"]), theta(n.size(), 0.0);
225 // Calculate theta
226 double Tc = cpjson::get_double(contribution, "Tcrit");
227 for (std::size_t i = 0; i < v.size(); ++i) {
228 theta[i] = -v[i] / Tc;
229 }
230 std::vector<CoolPropDbl> c(n.size(), 1);
231 std::vector<CoolPropDbl> d(c.size(), -1);
232
233 if (alpha0.PlanckEinstein.is_enabled() == true) {
234 alpha0.PlanckEinstein.extend(n, theta, c, d);
235 } else {
237 }
238 } else if (!type.compare("IdealGasHelmholtzGERG2004Cosh")) {
239 // Retrieve the values
240 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
241 std::vector<CoolPropDbl> theta = cpjson::get_long_double_array(contribution["theta"]);
242 double Tc = cpjson::get_double(contribution, "Tcrit");
243 if (alpha0.GERG2004Cosh.is_enabled() == true) {
244 alpha0.GERG2004Cosh.extend(n, theta);
245 } else {
246 alpha0.GERG2004Cosh = IdealHelmholtzGERG2004Cosh(n, theta, Tc);
247 }
248 } else if (!type.compare("IdealGasHelmholtzGERG2004Sinh")) {
249 // Retrieve the values
250 std::vector<CoolPropDbl> n = cpjson::get_long_double_array(contribution["n"]);
251 std::vector<CoolPropDbl> theta = cpjson::get_long_double_array(contribution["theta"]);
252 double Tc = cpjson::get_double(contribution, "Tcrit");
253 if (alpha0.GERG2004Sinh.is_enabled() == true) {
254 alpha0.GERG2004Sinh.extend(n, theta);
255 } else {
256 alpha0.GERG2004Sinh = IdealHelmholtzGERG2004Sinh(n, theta, Tc);
257 }
258 } else if (!type.compare("IdealGasHelmholtzCP0Constant")) {
259 if (alpha0.CP0Constant.is_enabled() == true) {
260 throw ValueError("Cannot add another IdealGasHelmholtzCP0Constant term; join them together");
261 }
262 CoolPropDbl cp_over_R = cpjson::get_double(contribution, "cp_over_R");
263 CoolPropDbl Tc = cpjson::get_double(contribution, "Tc");
264 CoolPropDbl T0 = cpjson::get_double(contribution, "T0");
265 alpha0.CP0Constant = IdealHelmholtzCP0Constant(cp_over_R, Tc, T0);
266 } else if (!type.compare("IdealGasHelmholtzCP0PolyT")) {
267 if (alpha0.CP0PolyT.is_enabled() == true) {
268 throw ValueError("Cannot add another CP0PolyT term; join them together");
269 }
270 std::vector<CoolPropDbl> c = cpjson::get_long_double_array(contribution["c"]);
271 std::vector<CoolPropDbl> t = cpjson::get_long_double_array(contribution["t"]);
272 CoolPropDbl Tc = cpjson::get_double(contribution, "Tc");
273 CoolPropDbl T0 = cpjson::get_double(contribution, "T0");
274 alpha0.CP0PolyT = IdealHelmholtzCP0PolyT(c, t, Tc, T0);
275 } else if (!type.compare("IdealGasHelmholtzCP0AlyLee")) {
276
277 std::vector<CoolPropDbl> constants = cpjson::get_long_double_array(contribution["c"]);
278 CoolPropDbl Tc = cpjson::get_double(contribution, "Tc");
279 CoolPropDbl T0 = cpjson::get_double(contribution, "T0");
280
281 // Take the constant term if nonzero and set it as a polyT term
282 if (std::abs(constants[0]) > 1e-14) {
283 std::vector<CoolPropDbl> c(1, constants[0]), t(1, 0);
284 if (alpha0.CP0PolyT.is_enabled() == true) {
285 alpha0.CP0PolyT.extend(c, t);
286 } else {
287 alpha0.CP0PolyT = IdealHelmholtzCP0PolyT(c, t, Tc, T0);
288 }
289 }
290 std::vector<CoolPropDbl> n, c, d, t;
291 if (std::abs(constants[1]) > 1e-14) {
292 // sinh term can be converted by setting a_k = C, b_k = 2*D, c_k = -1, d_k = 1
293 n.push_back(constants[1]);
294 t.push_back(-2 * constants[2] / Tc);
295 c.push_back(1);
296 d.push_back(-1);
297 }
298 if (std::abs(constants[3]) > 1e-14) {
299 // cosh term can be converted by setting a_k = C, b_k = 2*D, c_k = 1, d_k = 1
300 n.push_back(-constants[3]);
301 t.push_back(-2 * constants[4] / Tc);
302 c.push_back(1);
303 d.push_back(1);
304 }
305 if (alpha0.PlanckEinstein.is_enabled() == true) {
306 alpha0.PlanckEinstein.extend(n, t, c, d);
307 } else {
309 }
310 } else if (!type.compare("IdealGasHelmholtzEnthalpyEntropyOffset")) {
311 CoolPropDbl a1 = cpjson::get_double(contribution, "a1");
312 CoolPropDbl a2 = cpjson::get_double(contribution, "a2");
313 std::string reference = cpjson::get_string(contribution, "reference");
315 } else {
316 std::cout << format("Unsupported ideal-gas Helmholtz type: %s\n", type.c_str());
317 //throw ValueError(format("Unsupported ideal-gas Helmholtz type: %s",type.c_str()));
318 }
319 }
320 return alpha0;
321 };
322
323 protected:
325 void parse_environmental(rapidjson::Value& json, CoolPropFluid& fluid) {
326 fluid.environment.ASHRAE34 = cpjson::get_string(json, "ASHRAE34");
327 fluid.environment.GWP20 = cpjson::get_double(json, "GWP20");
328 fluid.environment.GWP100 = cpjson::get_double(json, "GWP100");
329 fluid.environment.GWP500 = cpjson::get_double(json, "GWP500");
330 fluid.environment.HH = cpjson::get_double(json, "HH");
331 fluid.environment.FH = cpjson::get_double(json, "FH");
332 fluid.environment.PH = cpjson::get_double(json, "PH");
333 fluid.environment.ODP = cpjson::get_double(json, "ODP");
334 }
335
337 void parse_EOS(rapidjson::Value& EOS_json, CoolPropFluid& fluid) {
339 fluid.EOSVector.push_back(E);
340
341 EquationOfState& EOS = fluid.EOSVector.at(fluid.EOSVector.size() - 1);
342
343 // Universal gas constant [J/mol/K]
344 EOS.R_u = cpjson::get_double(EOS_json, "gas_constant");
345 EOS.molar_mass = cpjson::get_double(EOS_json, "molar_mass");
346 EOS.acentric = cpjson::get_double(EOS_json, "acentric");
347
348 EOS.pseudo_pure = cpjson::get_bool(EOS_json, "pseudo_pure");
349 EOS.limits.Tmax = cpjson::get_double(EOS_json, "T_max");
350 EOS.limits.pmax = cpjson::get_double(EOS_json, "p_max");
351
352 rapidjson::Value& reducing_state = EOS_json["STATES"]["reducing"];
353 rapidjson::Value& satminL_state = EOS_json["STATES"]["sat_min_liquid"];
354 rapidjson::Value& satminV_state = EOS_json["STATES"]["sat_min_vapor"];
355
356 // Reducing state
357 EOS.reduce.T = cpjson::get_double(reducing_state, "T");
358 EOS.reduce.rhomolar = cpjson::get_double(reducing_state, "rhomolar");
359 EOS.reduce.p = cpjson::get_double(reducing_state, "p");
360 EOS.reduce.hmolar = cpjson::get_double(reducing_state, "hmolar");
361 EOS.reduce.smolar = cpjson::get_double(reducing_state, "smolar");
362
363 EOS.sat_min_liquid.T = cpjson::get_double(satminL_state, "T");
364 EOS.sat_min_liquid.p = cpjson::get_double(satminL_state, "p");
365 EOS.sat_min_liquid.rhomolar = cpjson::get_double(satminL_state, "rhomolar");
366 EOS.sat_min_vapor.T = cpjson::get_double(satminV_state, "T");
367 EOS.sat_min_vapor.p = cpjson::get_double(satminV_state, "p");
368 EOS.sat_min_vapor.rhomolar = cpjson::get_double(satminV_state, "rhomolar");
369
371 EOS.limits.Tmin = cpjson::get_double(satminL_state, "T");
372 EOS.ptriple = cpjson::get_double(satminL_state, "p");
373 EOS.Ttriple = EOS.limits.Tmin;
374
375 // BibTex keys
376 EOS.BibTeX_EOS = cpjson::get_string(EOS_json, "BibTeX_EOS");
377 EOS.BibTeX_CP0 = cpjson::get_string(EOS_json, "BibTeX_CP0");
378
379 EOS.alphar = parse_alphar(EOS_json["alphar"]);
380 EOS.alpha0 = parse_alpha0(EOS_json["alpha0"]);
381
382 // Store the prefactor multipliying alpha0 if present
383 if (EOS_json.HasMember("alpha0_prefactor")) {
384 EOS.alpha0.set_prefactor(cpjson::get_double(EOS_json, "alpha0_prefactor"));
385 }
386 if (EOS_json["STATES"].HasMember("hs_anchor")) {
387 rapidjson::Value& hs_anchor = EOS_json["STATES"]["hs_anchor"];
388 EOS.hs_anchor.T = cpjson::get_double(hs_anchor, "T");
389 EOS.hs_anchor.p = cpjson::get_double(hs_anchor, "p");
390 EOS.hs_anchor.rhomolar = cpjson::get_double(hs_anchor, "rhomolar");
391 EOS.hs_anchor.hmolar = cpjson::get_double(hs_anchor, "hmolar");
392 EOS.hs_anchor.smolar = cpjson::get_double(hs_anchor, "smolar");
393 }
394
395 if (EOS_json["STATES"].HasMember("pressure_max_sat")) {
396 rapidjson::Value& s = EOS_json["STATES"]["pressure_max_sat"];
397 EOS.max_sat_p.T = cpjson::get_double(s, "T");
398 EOS.max_sat_p.p = cpjson::get_double(s, "p");
399 EOS.max_sat_p.rhomolar = cpjson::get_double(s, "rhomolar");
400 if (s.HasMember("hmolar")) {
401 EOS.max_sat_p.hmolar = cpjson::get_double(s, "hmolar");
402 EOS.max_sat_p.smolar = cpjson::get_double(s, "smolar");
403 }
404 }
405
406 if (EOS_json["STATES"].HasMember("temperature_max_sat")) {
407 rapidjson::Value& s = EOS_json["STATES"]["temperature_max_sat"];
408 EOS.max_sat_T.T = cpjson::get_double(s, "T");
409 EOS.max_sat_T.p = cpjson::get_double(s, "p");
410 EOS.max_sat_T.rhomolar = cpjson::get_double(s, "rhomolar");
411 if (s.HasMember("hmolar")) {
412 EOS.max_sat_T.hmolar = cpjson::get_double(s, "hmolar");
413 EOS.max_sat_T.smolar = cpjson::get_double(s, "smolar");
414 }
415 }
416
417 if (EOS_json.HasMember("critical_region_splines")) {
418 rapidjson::Value& spline = EOS_json["critical_region_splines"];
419 EOS.critical_region_splines.T_min = cpjson::get_double(spline, "T_min");
420 EOS.critical_region_splines.T_max = cpjson::get_double(spline, "T_max");
421 EOS.critical_region_splines.rhomolar_min = cpjson::get_double(spline, "rhomolar_min");
422 EOS.critical_region_splines.rhomolar_max = cpjson::get_double(spline, "rhomolar_max");
426 }
427
428 // Validate the equation of state that was just created
429 EOS.validate();
430 }
431
433 void parse_EOS_listing(rapidjson::Value& EOS_array, CoolPropFluid& fluid) {
434 for (rapidjson::Value::ValueIterator itr = EOS_array.Begin(); itr != EOS_array.End(); ++itr) {
435 parse_EOS(*itr, fluid);
436 }
437 };
438
440 void parse_dilute_viscosity(rapidjson::Value& dilute, CoolPropFluid& fluid) {
441 if (dilute.HasMember("hardcoded")) {
442 std::string target = cpjson::get_string(dilute, "hardcoded");
443 if (!target.compare("Ethane")) {
445 return;
446 } else if (!target.compare("Cyclohexane")) {
448 return;
449 } else if (!target.compare("CarbonDioxideLaeseckeJPCRD2017")) {
451 return;
452 } else {
453 throw ValueError(format("hardcoded dilute viscosity [%s] is not understood for fluid %s", target.c_str(), fluid.name.c_str()));
454 }
455 }
456 std::string type = cpjson::get_string(dilute, "type");
457 if (!type.compare("collision_integral")) {
458 // Get a reference to the entry in the fluid instance
460
461 // Set the type flag
463
464 // Load up the values
465 CI.a = cpjson::get_long_double_array(dilute["a"]);
466 CI.t = cpjson::get_long_double_array(dilute["t"]);
467 CI.molar_mass = cpjson::get_double(dilute, "molar_mass");
468 CI.C = cpjson::get_double(dilute, "C");
469 } else if (!type.compare("kinetic_theory")) {
471 } else if (!type.compare("powers_of_T")) {
472 // Get a reference to the entry in the fluid instance
474
475 // Load up the values
476 CI.a = cpjson::get_long_double_array(dilute["a"]);
477 CI.t = cpjson::get_long_double_array(dilute["t"]);
478
480 } else if (!type.compare("powers_of_Tr")) {
481 // Get a reference to the entry in the fluid instance
483 // Load up the values
484 CI.a = cpjson::get_long_double_array(dilute["a"]);
485 CI.t = cpjson::get_long_double_array(dilute["t"]);
486 CI.T_reducing = cpjson::get_double(dilute, "T_reducing");
488 } else if (!type.compare("collision_integral_powers_of_Tstar")) {
489 // Get a reference to the entry in the fluid instance
491
492 // Load up the values
493 CI.a = cpjson::get_long_double_array(dilute["a"]);
494 CI.t = cpjson::get_long_double_array(dilute["t"]);
495 CI.T_reducing = cpjson::get_double(dilute, "T_reducing");
496 CI.C = cpjson::get_double(dilute, "C");
497
499 } else {
500 throw ValueError(format("type [%s] is not understood for fluid %s", type.c_str(), fluid.name.c_str()));
501 }
502 };
503
505 void parse_initial_density_viscosity(rapidjson::Value& initial_density, CoolPropFluid& fluid) {
506 std::string type = cpjson::get_string(initial_density, "type");
507 if (!type.compare("Rainwater-Friend")) {
508 // Get a reference to the entry in the fluid instance
510
511 // Load up the values
512 RF.b = cpjson::get_long_double_array(initial_density["b"]);
513 RF.t = cpjson::get_long_double_array(initial_density["t"]);
514
515 // Set the type flag
517 } else if (!type.compare("empirical")) {
518 // Get a reference to the entry in the fluid instance
520
521 // Load up the values
522 EM.n = cpjson::get_long_double_array(initial_density["n"]);
523 EM.d = cpjson::get_long_double_array(initial_density["d"]);
524 EM.t = cpjson::get_long_double_array(initial_density["t"]);
525 EM.T_reducing = cpjson::get_double(initial_density, "T_reducing");
526 EM.rhomolar_reducing = cpjson::get_double(initial_density, "rhomolar_reducing");
527
528 // Set the type flag
530 } else {
531 throw ValueError(format("type [%s] is not understood for fluid %s", type.c_str(), fluid.name.c_str()));
532 }
533 };
534
536 void parse_higher_order_viscosity(rapidjson::Value& higher, CoolPropFluid& fluid) {
537 // First check for hardcoded higher-order term
538 if (higher.HasMember("hardcoded")) {
539 std::string target = cpjson::get_string(higher, "hardcoded");
540 if (!target.compare("Hydrogen")) {
542 return;
543 } else if (!target.compare("n-Hexane")) {
545 return;
546 } else if (!target.compare("n-Heptane")) {
548 return;
549 } else if (!target.compare("Toluene")) {
551 return;
552 } else if (!target.compare("Ethane")) {
554 return;
555 } else if (!target.compare("Benzene")) {
557 return;
558 } else if (!target.compare("CarbonDioxideLaeseckeJPCRD2017")) {
560 return;
561 } else {
562 throw ValueError(
563 format("hardcoded higher order viscosity term [%s] is not understood for fluid %s", target.c_str(), fluid.name.c_str()));
564 }
565 }
566
567 std::string type = cpjson::get_string(higher, "type");
568 if (!type.compare("modified_Batschinski_Hildebrand")) {
569 // Get a reference to the entry in the fluid instance to simplify the code that follows
571
572 // Set the flag for the type of this model
574
575 BH.T_reduce = cpjson::get_double(higher, "T_reduce");
576 BH.rhomolar_reduce = cpjson::get_double(higher, "rhomolar_reduce");
577 // Load up the values
578 BH.a = cpjson::get_long_double_array(higher["a"]);
579 BH.t1 = cpjson::get_long_double_array(higher["t1"]);
580 BH.d1 = cpjson::get_long_double_array(higher["d1"]);
581 BH.gamma = cpjson::get_long_double_array(higher["gamma"]);
582 BH.l = cpjson::get_long_double_array(higher["l"]);
583 assert(BH.a.size() == BH.t1.size());
584 assert(BH.a.size() == BH.d1.size());
585 assert(BH.a.size() == BH.gamma.size());
586 assert(BH.a.size() == BH.l.size());
587 BH.f = cpjson::get_long_double_array(higher["f"]);
588 BH.t2 = cpjson::get_long_double_array(higher["t2"]);
589 BH.d2 = cpjson::get_long_double_array(higher["d2"]);
590 assert(BH.f.size() == BH.t2.size());
591 assert(BH.f.size() == BH.d2.size());
592 BH.g = cpjson::get_long_double_array(higher["g"]);
593 BH.h = cpjson::get_long_double_array(higher["h"]);
594 assert(BH.g.size() == BH.h.size());
595 BH.p = cpjson::get_long_double_array(higher["p"]);
596 BH.q = cpjson::get_long_double_array(higher["q"]);
597 assert(BH.p.size() == BH.q.size());
598 } else if (!type.compare("friction_theory")) {
599 // Get a reference to the entry in the fluid instance to simplify the code that follows
601
602 // Set the flag for the type of this model
604
605 // Always need these terms
606 F.Ai = cpjson::get_long_double_array(higher["Ai"]);
607 F.Aa = cpjson::get_long_double_array(higher["Aa"]);
608 F.Aaa = cpjson::get_long_double_array(higher["Aaa"]);
609 F.Ar = cpjson::get_long_double_array(higher["Ar"]);
610
611 F.Na = cpjson::get_integer(higher, "Na");
612 F.Naa = cpjson::get_integer(higher, "Naa");
613 F.Nr = cpjson::get_integer(higher, "Nr");
614 F.Nrr = cpjson::get_integer(higher, "Nrr");
615 F.c1 = cpjson::get_double(higher, "c1");
616 F.c2 = cpjson::get_double(higher, "c2");
617 assert(F.Aa.size() == 3);
618 assert(F.Aaa.size() == 3);
619 assert(F.Ar.size() == 3);
620
621 F.T_reduce = cpjson::get_double(higher, "T_reduce");
622
623 if (higher.HasMember("Arr") && !higher.HasMember("Adrdr")) {
624 F.Arr = cpjson::get_long_double_array(higher["Arr"]);
625 assert(F.Arr.size() == 3);
626 } else if (higher.HasMember("Adrdr") && !higher.HasMember("Arr")) {
627 F.Adrdr = cpjson::get_long_double_array(higher["Adrdr"]);
628 assert(F.Adrdr.size() == 3);
629 } else {
630 throw ValueError(format("can only provide one of Arr or Adrdr for fluid %s", fluid.name.c_str()));
631 }
632 if (higher.HasMember("Aii")) {
633 F.Aii = cpjson::get_long_double_array(higher["Aii"]);
634 F.Nii = cpjson::get_integer(higher, "Nii");
635 }
636 if (higher.HasMember("Aaaa") && higher.HasMember("Arrr")) {
637 F.Aaaa = cpjson::get_long_double_array(higher["Aaaa"]);
638 F.Arrr = cpjson::get_long_double_array(higher["Arrr"]);
639 F.Naaa = cpjson::get_integer(higher, "Naaa");
640 F.Nrrr = cpjson::get_integer(higher, "Nrrr");
641 }
642
643 } else {
644 throw ValueError(format("type [%s] is not understood for fluid %s", type.c_str(), fluid.name.c_str()));
645 }
646 };
647
648 void parse_ECS_conductivity(rapidjson::Value& conductivity, CoolPropFluid& fluid) {
649 fluid.transport.conductivity_ecs.reference_fluid = cpjson::get_string(conductivity, "reference_fluid");
650
651 // Parameters for correction polynomials
652 fluid.transport.conductivity_ecs.psi_a = cpjson::get_long_double_array(conductivity["psi"]["a"]);
653 fluid.transport.conductivity_ecs.psi_t = cpjson::get_long_double_array(conductivity["psi"]["t"]);
654 fluid.transport.conductivity_ecs.psi_rhomolar_reducing = cpjson::get_double(conductivity["psi"], "rhomolar_reducing");
655 fluid.transport.conductivity_ecs.f_int_a = cpjson::get_long_double_array(conductivity["f_int"]["a"]);
656 fluid.transport.conductivity_ecs.f_int_t = cpjson::get_long_double_array(conductivity["f_int"]["t"]);
657 fluid.transport.conductivity_ecs.f_int_T_reducing = cpjson::get_double(conductivity["f_int"], "T_reducing");
658
660 }
661
662 void parse_ECS_viscosity(rapidjson::Value& viscosity, CoolPropFluid& fluid) {
663 fluid.transport.viscosity_ecs.reference_fluid = cpjson::get_string(viscosity, "reference_fluid");
664
665 // Parameters for correction polynomial
666 fluid.transport.viscosity_ecs.psi_a = cpjson::get_long_double_array(viscosity["psi"]["a"]);
667 fluid.transport.viscosity_ecs.psi_t = cpjson::get_long_double_array(viscosity["psi"]["t"]);
668 fluid.transport.viscosity_ecs.psi_rhomolar_reducing = cpjson::get_double(viscosity["psi"], "rhomolar_reducing");
669
670 fluid.transport.viscosity_using_ECS = true;
671 }
672
673 void parse_Chung_viscosity(rapidjson::Value& viscosity, CoolPropFluid& fluid) {
674 // These in base SI units
675 fluid.transport.viscosity_Chung.rhomolar_critical = cpjson::get_double(viscosity, "rhomolar_critical");
676 fluid.transport.viscosity_Chung.T_critical = cpjson::get_double(viscosity, "T_critical");
677 fluid.transport.viscosity_Chung.molar_mass = cpjson::get_double(viscosity, "molar_mass");
678 fluid.transport.viscosity_Chung.dipole_moment_D = cpjson::get_double(viscosity, "dipole_moment_D");
679 fluid.transport.viscosity_Chung.acentric = cpjson::get_double(viscosity, "acentric");
680 fluid.transport.viscosity_using_Chung = true;
681 }
682
683 void parse_rhosr_viscosity(rapidjson::Value& viscosity, CoolPropFluid& fluid) {
684 fluid.transport.viscosity_rhosr.C = cpjson::get_double(viscosity, "C");
685 fluid.transport.viscosity_rhosr.c_liq = cpjson::get_double_array(viscosity, "c_liq");
686 fluid.transport.viscosity_rhosr.c_vap = cpjson::get_double_array(viscosity, "c_vap");
687 fluid.transport.viscosity_rhosr.rhosr_critical = cpjson::get_double(viscosity, "rhosr_critical");
688 fluid.transport.viscosity_rhosr.x_crossover = cpjson::get_double(viscosity, "x_crossover");
689 fluid.transport.viscosity_using_rhosr = true;
690 }
691
693 void parse_viscosity(rapidjson::Value& viscosity, CoolPropFluid& fluid) {
694 // If an array, use the first one, and then stop;
695 if (viscosity.IsArray()) {
696 rapidjson::Value::ValueIterator itr = viscosity.Begin();
697 parse_viscosity(*itr, fluid);
698 return;
699 }
700
701 // Load the BibTeX key
702 fluid.transport.BibTeX_viscosity = cpjson::get_string(viscosity, "BibTeX");
703
704 // Set the Lennard-Jones 12-6 potential variables, or approximate them from method of Chung
705 if (!viscosity.HasMember("sigma_eta") || !viscosity.HasMember("epsilon_over_k")) {
706 default_transport(fluid);
707 } else {
708 fluid.transport.sigma_eta = cpjson::get_double(viscosity, "sigma_eta");
709 fluid.transport.epsilon_over_k = cpjson::get_double(viscosity, "epsilon_over_k");
710 }
711
712 // If it is using ECS, set ECS parameters and quit
713 if (viscosity.HasMember("type") && !cpjson::get_string(viscosity, "type").compare("ECS")) {
714 parse_ECS_viscosity(viscosity, fluid);
715 return;
716 }
717
718 // If it is using rho*sr CS, set parameters and quit
719 if (viscosity.HasMember("type") && !cpjson::get_string(viscosity, "type").compare("rhosr-CS")) {
720 parse_rhosr_viscosity(viscosity, fluid);
721 return;
722 }
723
724 // Use the method of Chung
725 // If it is using ECS, set ECS parameters and quit
726 if (viscosity.HasMember("type") && !cpjson::get_string(viscosity, "type").compare("Chung")) {
727 parse_Chung_viscosity(viscosity, fluid);
728 return;
729 }
730
731 if (viscosity.HasMember("hardcoded")) {
732 std::string target = cpjson::get_string(viscosity, "hardcoded");
733 if (!target.compare("Water")) {
735 return;
736 } else if (!target.compare("HeavyWater")) {
738 return;
739 } else if (!target.compare("Helium")) {
741 return;
742 } else if (!target.compare("R23")) {
744 return;
745 } else if (!target.compare("Methanol")) {
747 return;
748 } else if (!target.compare("m-Xylene")) {
750 return;
751 } else if (!target.compare("o-Xylene")) {
753 return;
754 } else if (!target.compare("p-Xylene")) {
756 return;
757 } else {
758 throw ValueError(format("hardcoded viscosity [%s] is not understood for fluid %s", target.c_str(), fluid.name.c_str()));
759 }
760 }
761
762 // Load dilute viscosity term
763 if (viscosity.HasMember("dilute")) {
764 parse_dilute_viscosity(viscosity["dilute"], fluid);
765 }
766 // Load initial density term
767 if (viscosity.HasMember("initial_density")) {
768 parse_initial_density_viscosity(viscosity["initial_density"], fluid);
769 }
770 // Load higher_order term
771 if (viscosity.HasMember("higher_order")) {
772 parse_higher_order_viscosity(viscosity["higher_order"], fluid);
773 }
774 };
775
777 void parse_dilute_conductivity(rapidjson::Value& dilute, CoolPropFluid& fluid) {
778 if (dilute.HasMember("hardcoded")) {
779 std::string target = cpjson::get_string(dilute, "hardcoded");
780 if (!target.compare("CO2")) {
782 return;
783 }
784 else if (!target.compare("CarbonDioxideHuberJPCRD2016")) {
786 return;
787 } else if (!target.compare("Ethane")) {
789 return;
790 } else if (!target.compare("none")) {
792 return;
793 } else {
794 throw ValueError(
795 format("hardcoded dilute conductivity term [%s] is not understood for fluid %s", target.c_str(), fluid.name.c_str()));
796 }
797 }
798 std::string type = cpjson::get_string(dilute, "type");
799 if (!type.compare("ratio_of_polynomials")) {
800 // Get a reference to the entry in the fluid instance
802
803 // Set the type flag
805
806 // Load up the values
807 data.A = cpjson::get_long_double_array(dilute["A"]);
808 data.B = cpjson::get_long_double_array(dilute["B"]);
809 data.n = cpjson::get_long_double_array(dilute["n"]);
810 data.m = cpjson::get_long_double_array(dilute["m"]);
811 data.T_reducing = cpjson::get_double(dilute, "T_reducing");
812 } else if (!type.compare("eta0_and_poly")) {
813 // Get a reference to the entry in the fluid instance
815
816 // Set the type flag
818
819 // Load up the values
820 data.A = cpjson::get_long_double_array(dilute["A"]);
821 data.t = cpjson::get_long_double_array(dilute["t"]);
822 } else {
823 throw ValueError(format("type [%s] is not understood for fluid %s", type.c_str(), fluid.name.c_str()));
824 }
825 };
826
828 void parse_residual_conductivity(rapidjson::Value& dilute, CoolPropFluid& fluid) {
829 if (dilute.HasMember("hardcoded")) {
830 std::string target = cpjson::get_string(dilute, "hardcoded");
831 if (!target.compare("CO2")) {
833 return;
834 } else {
835 throw ValueError(
836 format("hardcoded residual conductivity term [%s] is not understood for fluid %s", target.c_str(), fluid.name.c_str()));
837 }
838 }
839 std::string type = cpjson::get_string(dilute, "type");
840 if (!type.compare("polynomial")) {
841 // Get a reference to the entry in the fluid instance
843
844 // Set the type flag
846
847 // Load up the values
848 data.B = cpjson::get_long_double_array(dilute["B"]);
849 data.d = cpjson::get_long_double_array(dilute["d"]);
850 data.t = cpjson::get_long_double_array(dilute["t"]);
851 data.T_reducing = cpjson::get_double(dilute, "T_reducing");
852 data.rhomass_reducing = cpjson::get_double(dilute, "rhomass_reducing");
853 } else if (!type.compare("polynomial_and_exponential")) {
854 // Get a reference to the entry in the fluid instance
856
857 // Set the type flag
859
860 // Load up the values
861 data.A = cpjson::get_long_double_array(dilute["A"]);
862 data.d = cpjson::get_long_double_array(dilute["d"]);
863 data.t = cpjson::get_long_double_array(dilute["t"]);
864 data.gamma = cpjson::get_long_double_array(dilute["gamma"]);
865 data.l = cpjson::get_long_double_array(dilute["l"]);
866 } else {
867 throw ValueError(format("type [%s] is not understood for fluid %s", type.c_str(), fluid.name.c_str()));
868 }
869 };
870
871 void parse_critical_conductivity(rapidjson::Value& critical, CoolPropFluid& fluid) {
872 if (critical.HasMember("hardcoded")) {
873 std::string target = cpjson::get_string(critical, "hardcoded");
874 if (!target.compare("R123")) {
876 return;
877 } else if (!target.compare("Ammonia")) {
879 return;
880 } else if (!target.compare("CarbonDioxideScalabrinJPCRD2006")) {
883 return;
884 } else if (!target.compare("None")) {
886 return;
887 } else {
888 throw ValueError(format("critical conductivity term [%s] is not understood for fluid %s", target.c_str(), fluid.name.c_str()));
889 }
890 }
891 std::string type = cpjson::get_string(critical, "type");
892 if (!type.compare("simplified_Olchowy_Sengers")) {
895
896 // Set the type flag
898
899 // Set values if they are found - otherwise fall back to default values
900 if (critical.HasMember("qD")) {
901 data.qD = cpjson::get_double(critical, "qD");
902 }
903 if (critical.HasMember("zeta0")) {
904 data.zeta0 = cpjson::get_double(critical, "zeta0");
905 }
906 if (critical.HasMember("GAMMA")) {
907 data.GAMMA = cpjson::get_double(critical, "GAMMA");
908 }
909 if (critical.HasMember("gamma")) {
910 data.gamma = cpjson::get_double(critical, "gamma");
911 }
912 if (critical.HasMember("R0")) {
913 data.R0 = cpjson::get_double(critical, "R0");
914 }
915 if (critical.HasMember("T_ref")) {
916 data.T_ref = cpjson::get_double(critical, "T_ref");
917 }
918 } else {
919 throw ValueError(format("type [%s] is not understood for fluid %s", type.c_str(), fluid.name.c_str()));
920 }
921 };
922
924 void parse_thermal_conductivity(rapidjson::Value& conductivity, CoolPropFluid& fluid) {
925 // Load the BibTeX key
926 fluid.transport.BibTeX_conductivity = cpjson::get_string(conductivity, "BibTeX");
927
928 // If it is using ECS, set ECS parameters and quit
929 if (conductivity.HasMember("type") && !cpjson::get_string(conductivity, "type").compare("ECS")) {
930 parse_ECS_conductivity(conductivity, fluid);
931 return;
932 }
933
934 if (conductivity.HasMember("hardcoded")) {
935 std::string target = cpjson::get_string(conductivity, "hardcoded");
936 if (!target.compare("Water")) {
938 return;
939 } else if (!target.compare("HeavyWater")) {
941 return;
942 } else if (!target.compare("Methane")) {
944 return;
945 } else if (!target.compare("R23")) {
947 return;
948 } else if (!target.compare("Helium")) {
950 return;
951 } else {
952 throw ValueError(
953 format("hardcoded residual conductivity term [%s] is not understood for fluid %s", target.c_str(), fluid.name.c_str()));
954 }
955 }
956
957 // Load dilute conductivity term
958 if (conductivity.HasMember("dilute")) {
959 parse_dilute_conductivity(conductivity["dilute"], fluid);
960 }
961 // Load residual conductivity term
962 if (conductivity.HasMember("residual")) {
963 parse_residual_conductivity(conductivity["residual"], fluid);
964 }
965 // Load critical conductivity term
966 if (conductivity.HasMember("critical")) {
967 parse_critical_conductivity(conductivity["critical"], fluid);
968 }
969 };
970
972 void parse_transport(rapidjson::Value& transport, CoolPropFluid& fluid) {
973
974 // Parse viscosity
975 if (transport.HasMember("viscosity")) {
976 parse_viscosity(transport["viscosity"], fluid);
978 }
979
980 // Parse thermal conductivity
981 if (transport.HasMember("conductivity")) {
982 parse_thermal_conductivity(transport["conductivity"], fluid);
984 }
985 };
986
988 // Use the method of Chung to approximate the values for epsilon_over_k and sigma_eta
989 // Chung, T.-H.; Ajlan, M.; Lee, L. L.; Starling, K. E. Generalized Multiparameter Correlation for Nonpolar and Polar Fluid Transport Properties. Ind. Eng. Chem. Res. 1988, 27, 671-679.
990 // rhoc needs to be in mol/L to yield a sigma in nm,
991 CoolPropDbl rho_crit_molar = fluid.EOS().reduce.rhomolar / 1000.0; // [mol/m3 to mol/L]
992 CoolPropDbl Tc = fluid.EOS().reduce.T;
993 fluid.transport.sigma_eta = 0.809 / pow(rho_crit_molar, static_cast<CoolPropDbl>(1.0 / 3.0)) / 1e9; // 1e9 is to convert from nm to m
994 fluid.transport.epsilon_over_k = Tc / 1.2593; // [K]
995 }
996
997 void parse_melting_line(rapidjson::Value& melting_line, CoolPropFluid& fluid) {
998 fluid.ancillaries.melting_line.T_m = cpjson::get_double(melting_line, "T_m");
999 fluid.ancillaries.melting_line.BibTeX = cpjson::get_string(melting_line, "BibTeX");
1000
1001 if (melting_line.HasMember("type")) {
1002 std::string type = cpjson::get_string(melting_line, "type");
1003 if (!type.compare("Simon")) {
1004 rapidjson::Value& parts = melting_line["parts"];
1006 for (rapidjson::Value::ValueIterator itr = parts.Begin(); itr != parts.End(); ++itr) {
1008 data.a = cpjson::get_double((*itr), "a");
1009 data.c = cpjson::get_double((*itr), "c");
1010 data.T_min = cpjson::get_double((*itr), "T_min");
1011 data.T_max = cpjson::get_double((*itr), "T_max");
1012 data.T_0 = cpjson::get_double((*itr), "T_0");
1013 data.p_0 = cpjson::get_double((*itr), "p_0");
1014 fluid.ancillaries.melting_line.simon.parts.push_back(data);
1015 }
1016 } else if (!type.compare("polynomial_in_Tr")) {
1017 rapidjson::Value& parts = melting_line["parts"];
1019 for (rapidjson::Value::ValueIterator itr = parts.Begin(); itr != parts.End(); ++itr) {
1021 data.a = cpjson::get_long_double_array((*itr), "a");
1022 data.t = cpjson::get_long_double_array((*itr), "t");
1023 data.T_min = cpjson::get_double((*itr), "T_min");
1024 data.T_max = cpjson::get_double((*itr), "T_max");
1025 data.T_0 = cpjson::get_double((*itr), "T_0");
1026 data.p_0 = cpjson::get_double((*itr), "p_0");
1027 fluid.ancillaries.melting_line.polynomial_in_Tr.parts.push_back(data);
1028 }
1029 } else if (!type.compare("polynomial_in_Theta")) {
1030 rapidjson::Value& parts = melting_line["parts"];
1032 for (rapidjson::Value::ValueIterator itr = parts.Begin(); itr != parts.End(); ++itr) {
1034 data.a = cpjson::get_long_double_array((*itr), "a");
1035 data.t = cpjson::get_long_double_array((*itr), "t");
1036 data.T_min = cpjson::get_double((*itr), "T_min");
1037 data.T_max = cpjson::get_double((*itr), "T_max");
1038 data.T_0 = cpjson::get_double((*itr), "T_0");
1039 data.p_0 = cpjson::get_double((*itr), "p_0");
1040 fluid.ancillaries.melting_line.polynomial_in_Theta.parts.push_back(data);
1041 }
1042 } else {
1043 throw ValueError(format("melting line type [%s] is not understood for fluid %s", type.c_str(), fluid.name.c_str()));
1044 }
1045 // Set the limits for the melting line curve
1047 } else {
1048 throw ValueError(format("melting line does not have \"type\" for fluid %s", fluid.name.c_str()));
1049 }
1050 };
1051
1053 void parse_states(rapidjson::Value& states, CoolPropFluid& fluid) {
1054 if (!states.HasMember("critical")) {
1055 throw ValueError(format("fluid[\"STATES\"] [%s] does not have \"critical\" member", fluid.name.c_str()));
1056 }
1057 rapidjson::Value& crit = states["critical"];
1058 fluid.crit.T = cpjson::get_double(crit, "T");
1059 fluid.crit.p = cpjson::get_double(crit, "p");
1060 fluid.crit.rhomolar = cpjson::get_double(crit, "rhomolar");
1061 fluid.crit.hmolar = cpjson::get_double(crit, "hmolar");
1062 fluid.crit.smolar = cpjson::get_double(crit, "smolar");
1063
1064 if (!states.HasMember("triple_liquid")) {
1065 throw ValueError(format("fluid[\"STATES\"] [%s] does not have \"triple_liquid\" member", fluid.name.c_str()));
1066 }
1067 rapidjson::Value& triple_liquid = states["triple_liquid"];
1068 if (triple_liquid.ObjectEmpty()) {
1069 // State is empty - probably because the triple point temperature is below the minimum saturation temperature
1070 fluid.triple_liquid.T = -1;
1071 fluid.triple_liquid.p = -1;
1072 fluid.triple_liquid.rhomolar = -1;
1073 fluid.triple_liquid.hmolar = _HUGE;
1074 fluid.triple_liquid.smolar = _HUGE;
1075 } else {
1076 fluid.triple_liquid.T = cpjson::get_double(triple_liquid, "T");
1077 fluid.triple_liquid.p = cpjson::get_double(triple_liquid, "p");
1078 fluid.triple_liquid.rhomolar = cpjson::get_double(triple_liquid, "rhomolar");
1079 fluid.triple_liquid.hmolar = cpjson::get_double(triple_liquid, "hmolar");
1080 fluid.triple_liquid.smolar = cpjson::get_double(triple_liquid, "smolar");
1081 }
1082
1083 if (!states.HasMember("triple_vapor")) {
1084 throw ValueError(format("fluid[\"STATES\"] [%s] does not have \"triple_vapor\" member", fluid.name.c_str()));
1085 }
1086 rapidjson::Value& triple_vapor = states["triple_vapor"];
1087 if (triple_vapor.ObjectEmpty()) {
1088 // State is empty - probably because the triple point temperature is below the minimum saturation temperature
1089 fluid.triple_vapor.T = -1;
1090 fluid.triple_vapor.p = -1;
1091 fluid.triple_vapor.rhomolar = -1;
1092 fluid.triple_vapor.hmolar = _HUGE;
1093 fluid.triple_vapor.smolar = _HUGE;
1094 } else {
1095 fluid.triple_vapor.T = cpjson::get_double(triple_vapor, "T");
1096 fluid.triple_vapor.p = cpjson::get_double(triple_vapor, "p");
1097 fluid.triple_vapor.rhomolar = cpjson::get_double(triple_vapor, "rhomolar");
1098 fluid.triple_vapor.hmolar = cpjson::get_double(triple_vapor, "hmolar");
1099 fluid.triple_vapor.smolar = cpjson::get_double(triple_vapor, "smolar");
1100 }
1101 };
1102
1104 void parse_ancillaries(rapidjson::Value& ancillaries, CoolPropFluid& fluid) {
1105 if (!ancillaries.HasMember("rhoL") || !ancillaries.HasMember("rhoV")) {
1106 throw ValueError("Ancillary curves for either rhoL or rhoV are missing");
1107 }
1108 fluid.ancillaries.rhoL = SaturationAncillaryFunction(ancillaries["rhoL"]);
1109 fluid.ancillaries.rhoV = SaturationAncillaryFunction(ancillaries["rhoV"]);
1110
1111 // If a pseudo-pure fluid, has pL and pV curves
1112 if (ancillaries.HasMember("pL") && ancillaries.HasMember("pV")) {
1113 fluid.ancillaries.pL = SaturationAncillaryFunction(ancillaries["pL"]);
1114 fluid.ancillaries.pV = SaturationAncillaryFunction(ancillaries["pV"]);
1115 }
1116 // Otherwise has a single pS curve and not pL and not pV
1117 else if (!ancillaries.HasMember("pL") && !ancillaries.HasMember("pV") && ancillaries.HasMember("pS")) {
1118 fluid.ancillaries.pL = SaturationAncillaryFunction(ancillaries["pS"]);
1119 fluid.ancillaries.pV = SaturationAncillaryFunction(ancillaries["pS"]);
1120 } else {
1121 throw ValueError("Pressure ancillary curves are missing or invalid");
1122 }
1123
1124 if (ancillaries.HasMember("hL")) {
1125 fluid.ancillaries.hL = SaturationAncillaryFunction(ancillaries["hL"]);
1126 } else {
1127 if (get_debug_level() > 0) {
1128 std::cout << "Missing hL ancillary for fluid " << fluid.name;
1129 }
1130 }
1131 if (ancillaries.HasMember("hLV")) {
1132 fluid.ancillaries.hLV = SaturationAncillaryFunction(ancillaries["hLV"]);
1133 } else {
1134 if (get_debug_level() > 0) {
1135 std::cout << "Missing hLV ancillary for fluid " << fluid.name;
1136 }
1137 }
1138
1139 if (ancillaries.HasMember("sL")) {
1140 fluid.ancillaries.sL = SaturationAncillaryFunction(ancillaries["sL"]);
1141 } else {
1142 if (get_debug_level() > 0) {
1143 std::cout << "Missing sL ancillary for fluid " << fluid.name;
1144 }
1145 }
1146 if (ancillaries.HasMember("sLV")) {
1147 fluid.ancillaries.sLV = SaturationAncillaryFunction(ancillaries["sLV"]);
1148 } else {
1149 if (get_debug_level() > 0) {
1150 std::cout << "Missing sLV ancillary for fluid " << fluid.name;
1151 }
1152 }
1153 if (!ValidNumber(fluid.ancillaries.sL.get_Tmin()) && get_debug_level() > 0) {
1154 std::cout << "Tmin invalid for sL for " << fluid.name << std::endl;
1155 }
1156 };
1157
1159 void parse_surface_tension(rapidjson::Value& surface_tension, CoolPropFluid& fluid) {
1160 fluid.ancillaries.surface_tension = SurfaceTensionCorrelation(surface_tension);
1161 };
1162
1165 assert(fluid.EOSVector.size() > 0);
1166 assert(fluid.CAS.length() > 0);
1167 assert(fluid.name.length() > 0);
1168 }
1169
1170 public:
1171 // Default constructor;
1173 _is_empty = true;
1174 };
1175 bool is_empty(void) {
1176 return _is_empty;
1177 };
1178
1180 static void add_many(const std::string& JSON_string);
1181
1183 void add_many(rapidjson::Value& listing);
1184
1185 void add_one(rapidjson::Value& fluid_json);
1186
1187 std::string get_JSONstring(const std::string& key) {
1188 // Try to find it
1189 std::map<std::string, std::size_t>::const_iterator it = string_to_index_map.find(key);
1190 if (it != string_to_index_map.end()) {
1191
1192 std::map<std::size_t, std::string>::const_iterator it2 = JSONstring_map.find(it->second);
1193 if (it2 != JSONstring_map.end()) {
1194 // Then, load the fluids we would like to add
1195 rapidjson::Document doc;
1196 cpjson::JSON_string_to_rapidjson(it2->second, doc);
1197 rapidjson::Document doc2;
1198 doc2.SetArray();
1199 doc2.PushBack(doc, doc.GetAllocator());
1200 return cpjson::json2string(doc2);
1201 } else {
1202 throw ValueError(format("Unable to obtain JSON string for this identifier [%d]", it->second));
1203 }
1204 } else {
1205 throw ValueError(format("Unable to obtain index for this identifier [%s]", key.c_str()));
1206 }
1207 }
1208
1210
1213 CoolPropFluid get(const std::string& key) {
1214 // Try to find it
1215 std::map<std::string, std::size_t>::const_iterator it = string_to_index_map.find(key);
1216 // If it is found
1217 if (it != string_to_index_map.end()) {
1218 return get(it->second);
1219 } else {
1220 // Here we check for the use of a cubic Helmholtz energy transformation for a multi-fluid model
1221 std::vector<std::string> endings;
1222 endings.push_back("-SRK");
1223 endings.push_back("-PengRobinson");
1224 for (std::vector<std::string>::const_iterator end = endings.begin(); end != endings.end(); ++end) {
1225 if (endswith(key, *end)) {
1226 std::string used_name = key.substr(0, key.size() - (*end).size());
1227 it = string_to_index_map.find(used_name);
1228 if (it != string_to_index_map.end()) {
1229 // We found the name of the fluid within the library of multiparameter
1230 // Helmholtz-explicit models. We will load its parameters from the
1231 // multiparameter EOS
1232 //
1233 CoolPropFluid fluid = get(it->second);
1234 // Remove all the residual contributions to the Helmholtz energy
1235 fluid.EOSVector[0].alphar.empty_the_EOS();
1236 // Get the parameters for the cubic EOS
1237 CoolPropDbl Tc = fluid.EOSVector[0].reduce.T;
1238 CoolPropDbl pc = fluid.EOSVector[0].reduce.p;
1239 CoolPropDbl rhomolarc = fluid.EOSVector[0].reduce.rhomolar;
1240 CoolPropDbl acentric = fluid.EOSVector[0].acentric;
1241 CoolPropDbl R = 8.3144598; // fluid.EOSVector[0].R_u;
1242 // Set the cubic contribution to the residual Helmholtz energy
1243 shared_ptr<AbstractCubic> ac;
1244 if (*end == "-SRK") {
1245 ac.reset(new SRK(Tc, pc, acentric, R));
1246 } else if (*end == "-PengRobinson") {
1247 ac.reset(new PengRobinson(Tc, pc, acentric, R));
1248 } else {
1249 throw CoolProp::ValueError(format("Unable to match this ending [%s]", (*end).c_str()));
1250 }
1251 ac->set_Tr(Tc);
1252 ac->set_rhor(rhomolarc);
1253 fluid.EOSVector[0].alphar.cubic = ResidualHelmholtzGeneralizedCubic(ac);
1254 return fluid;
1255 } else {
1256 // Let's look in the library of cubic EOS
1258 // Set the cubic contribution to the residual Helmholtz energy
1259 shared_ptr<AbstractCubic> ac;
1260 if (*end == "-SRK") {
1261 ac.reset(new SRK(vals.Tc, vals.pc, vals.acentric, get_config_double(R_U_CODATA)));
1262 } else if (*end == "-PengRobinson") {
1263 ac.reset(new PengRobinson(vals.Tc, vals.pc, vals.acentric, get_config_double(R_U_CODATA)));
1264 } else {
1265 throw CoolProp::ValueError(format("Unable to match this ending [%s]", (*end).c_str()));
1266 }
1267 ac->set_Tr(vals.Tc);
1268 if (vals.rhomolarc > 0) {
1269 ac->set_rhor(vals.rhomolarc);
1270 } else {
1271 // Curve fit from all the pure fluids in CoolProp (thanks to recommendation of A. Kazakov)
1272 double v_c_Lmol = 2.14107171795 * (vals.Tc / vals.pc * 1000) + 0.00773144012514; // [L/mol]
1273 ac->set_rhor(1 / (v_c_Lmol / 1000.0));
1274 }
1275 if (vals.alpha_type == "Twu") {
1276 std::vector<double>& c = vals.alpha_coeffs;
1277 ac->set_C_Twu(0, c[0], c[1], c[2]);
1278 }
1279 CoolPropFluid fluid;
1280 fluid.CAS = vals.CAS;
1282 E.acentric = vals.acentric;
1283 E.sat_min_liquid.T = _HUGE;
1284 E.sat_min_liquid.p = _HUGE;
1285 E.reduce.T = vals.Tc;
1286 E.reduce.p = vals.pc;
1287 E.reduce.rhomolar = ac->get_rhor();
1288 fluid.EOSVector.push_back(E);
1290 fluid.EOS().alpha0 = vals.alpha0;
1291 fluid.crit.T = vals.Tc;
1292 fluid.crit.p = vals.pc;
1293 fluid.crit.rhomolar = ac->get_rhor();
1294
1295 return fluid;
1296 }
1297 }
1298 }
1299 throw ValueError(format("key [%s] was not found in string_to_index_map in JSONFluidLibrary", key.c_str()));
1300 }
1301 };
1302
1304
1307 CoolPropFluid get(std::size_t key) {
1308 // Try to find it
1309 std::map<std::size_t, CoolPropFluid>::iterator it = fluid_map.find(key);
1310 // If it is found
1311 if (it != fluid_map.end()) {
1312 return it->second;
1313 } else {
1314 throw ValueError(format("key [%d] was not found in JSONFluidLibrary", key));
1315 }
1316 };
1317 void set_fluid_enthalpy_entropy_offset(const std::string& fluid, double delta_a1, double delta_a2, const std::string& ref);
1319 std::string get_fluid_list(void) {
1320 return strjoin(name_vector, get_config_string(LIST_STRING_DELIMITER));
1321 };
1322};
1323
1325JSONFluidLibrary& get_library(void);
1326
1328std::string get_fluid_list(void);
1329
1331CoolPropFluid get_fluid(const std::string& fluid_string);
1332
1334std::string get_fluid_as_JSONstring(const std::string& indentifier);
1335
1337void set_fluid_enthalpy_entropy_offset(const std::string& fluid, double delta_a1, double delta_a2, const std::string& ref);
1338
1339} /* namespace CoolProp */
1340#endif