CoolProp 8.0.0
An open-source fluid property and humid air property database
IncompressibleLibrary.cpp
Go to the documentation of this file.
4//#include "crossplatform_shared_ptr.h"
6#include "all_incompressibles_JSON.h" // Makes a std::string variable called all_incompressibles_JSON
7
8#include <mutex>
9
10namespace CoolProp {
11
14// * to bridge the gap between the solution functions
15// * used in the paper by Pátek and Klomfar:
16// * http://dx.doi.org/10.1016/j.ijrefrig.2005.10.007
17// *
18// * We owe gratitude to the authors for providing
19// * both access to the paper as well as the equations
20// * in the form of C source code. */
21//
22//double const LiBrSolution::M_H2O = 0.018015268; /* kg/mol, molar mass of H2O */
23//double const LiBrSolution::M_LiBr = 0.08685; /* kg/mol, molar mass of LiBr */
24//double const LiBrSolution::T0 = 221; /* K, constant */
25//
27//double const LiBrSolution::Tc_H2O = 647.096; /* K, temperature */
28//double const LiBrSolution::pc_H2O = 22.064; /* MPa, pressure */
29//double const LiBrSolution::rhoc_H2O = 17873; /* mol/m^3 (322 kg/m^3), molar density */
30//double const LiBrSolution::hc_H2O = 37548.5; /* J/mol, molar enthalpy */
31//double const LiBrSolution::sc_H2O = 79.3933; /* J/(mol.K) molar entropy*/
32//
34//double const LiBrSolution::Tt_H2O = 273.16; /* K, temperature */
35//double const LiBrSolution::cpt_H2O = 76.0226; /* J/(mol.K), molar isobaric heat capacity*/
36//
37//double LiBrSolution::ps_mix(double T, double x)
39//{
40// static double m[8] = { 3.0, 4.0, 4.0, 8.0, 1.0, 1.0, 4.0, 6.0 };
41// static double n[8] = { 0.0, 5.0, 6.0, 3.0, 0.0, 2.0, 6.0, 0.0 };
42// static double t[8] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 };
43// static double a[8] = { -2.41303e2, 1.91750e7, -1.75521e8, 3.25430e7,
44// 3.92571e2, -2.12626e3, 1.85127e8, 1.91216e3 };
45// double tau, suma = 0.0;
46// int i;
47//
48// tau = T / Tc_H2O;
49// for (i = 0; i <= 7; i++)
50// suma += a[i] * pow(x, m[i]) * pow(0.4 - x, n[i]) * pow(tau, t[i]);
51// return (ps_H2O(T - suma));
52//
53//} /* end function ps_mix */
54//
55//double LiBrSolution::rho_mix(double T, double x)
57//{
58// static double m[2] = { 1.0, 1.0 };
59// static double n[2] = { 0.0, 6.0 };
60// static double a[2] = { 1.746, 4.709 };
61//
62// double tau, suma = 0.0;
63// int i;
64//
65// tau = T / Tc_H2O;
66// for (i = 0; i <= 1; i++)
67// suma += a[i] * pow(x, m[i]) * pow(tau, n[i]);
68//
69// return ((1.0 - x) * rho_H2O(T) + rhoc_H2O * suma);
70//
71//} /* end function rho_mix */
72//
73//double LiBrSolution::cp_mix(double T, double x)
75//{
76// static double m[8] = { 2.0, 3.0, 3.0, 3.0, 3.0, 2.0, 1.0, 1.0 };
77// static double n[8] = { 0.0, 0.0, 1.0, 2.0, 3.0, 0.0, 3.0, 2.0 };
78// static double t[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 3.0, 4.0 };
79// static double a[8] = { -1.42094e1, 4.04943e1, 1.11135e2, 2.29980e2,
80// 1.34526e3, -1.41010e-2, 1.24977e-2, -6.83209e-4 };
81//
82// double tau, suma = 0.0;
83// int i;
84//
85// tau = Tc_H2O / (T - T0);
86// for (i = 0; i <= 7; i++)
87// suma += a[i] * pow(x, m[i]) * pow(0.4 - x, n[i]) * pow(tau, t[i]);
88//
89// return ((1.0 - x) * cp_H2O(T) + cpt_H2O * suma);
90//
91//} /* end function cp_mix */
92//
93//double LiBrSolution::h_mix(double T, double x)
95//{
96// static double m[30] = { 1.0, 1.0, 2.0, 3.0, 6.0, 1.0, 3.0, 5.0, 4.0,
97// 5.0, 5.0, 6.0, 6.0, 1.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 1.0, 1.0,
98// 2.0, 2.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0 };
99//
100// static double n[30] = { 0.0, 1.0, 6.0, 6.0, 2.0, 0.0, 0.0, 4.0, 0.0,
101// 4.0, 5.0, 5.0, 6.0, 0.0, 3.0, 5.0, 7.0, 0.0, 3.0, 1.0, 0.0, 4.0,
102// 2.0, 6.0, 7.0, 0.0, 0.0, 1.0, 2.0, 3.0 };
103//
104// static double t[30] = { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0,
105// 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0,
106// 4.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 5.0 };
107//
108// static double a[30] = { 2.27431, -7.99511, 3.85239e2, -1.63940e4,
109// -4.22562e2, 1.13314e-1, -8.33474, -1.73833e4, 6.49763,
110// 3.24552e3, -1.34643e4, 3.99322e4, -2.58877e5, -1.93046e-3,
111// 2.80616, -4.04479e1, 1.45342e2, -2.74873, -4.49743e2,
112// -1.21794e1, -5.83739e-3, 2.33910e-1, 3.41888e-1, 8.85259,
113// -1.78731e1, 7.35179e-2, -1.79430e-4, 1.84261e-3, -6.24282e-3,
114// 6.84765e-3 };
115//
116// double tau, suma = 0.0;
117// int i;
118//
119// tau = Tc_H2O / (T - T0);
120// for (i = 0; i <= 29; i++)
121// suma += a[i] * pow(x, m[i]) * pow(0.4 - x, n[i]) * pow(tau, t[i]);
122//
123// return ((1.0 - x) * h_H2O(T) + hc_H2O * suma);
124//
125//} /* end function h_mix */
126//
127//double LiBrSolution::s_mix(double T, double x)
129//{
130// static double m[29] = { 1.0, 1.0, 2.0, 3.0, 6.0, 1.0, 3.0, 5.0, 1.0,
131// 2.0, 2.0, 4.0, 5.0, 5.0, 6.0, 6.0, 1.0, 3.0, 5.0, 7.0, 1.0, 1.0,
132// 1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0 };
133//
134// static double n[29] = { 0.0, 1.0, 6.0, 6.0, 2.0, 0.0, 0.0, 4.0, 0.0,
135// 0.0, 4.0, 0.0, 4.0, 5.0, 2.0, 5.0, 0.0, 4.0, 0.0, 1.0, 0.0, 2.0,
136// 4.0, 7.0, 1.0, 0.0, 1.0, 2.0, 3.0 };
137//
138// static double t[29] = { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0,
139// 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0,
140// 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 5.0 };
141//
142// static double a[29] = { 1.53091, -4.52564, 6.98302e+2, -2.16664e+4,
143// -1.47533e+3, 8.47012e-2, -6.59523, -2.95331e+4, 9.56314e-3,
144// -1.88679e-1, 9.31752, 5.78104, 1.38931e+4, -1.71762e+4,
145// 4.15108e+2, -5.55647e+4, -4.23409e-3, 3.05242e+1, -1.67620,
146// 1.48283e+1, 3.03055e-3, -4.01810e-2, 1.49252e-1, 2.59240,
147// -1.77421e-1, -6.99650e-5, 6.05007e-4, -1.65228e-3, 1.22966e-3 };
148//
149// double tau, suma = 0.0;
150// int i;
151//
152// tau = Tc_H2O / (T - T0);
153// for (i = 0; i <= 28; i++)
154// suma += a[i] * pow(x, m[i]) * pow(0.4 - x, n[i]) * pow(tau, t[i]);
155//
156// return ((1.0 - x) * s_H2O(T) + sc_H2O * suma);
157//
158//} /* end function s_mix */
159//
160//double LiBrSolution::ps_H2O(double T)
162//{
163// static double a[7] = { 0.0, -7.85951783, 1.84408259, -11.7866497,
164// 22.6807411, -15.9618719, 1.80122502 };
165//
166// double tau, ps;
167//
168// tau = 1 - T / Tc_H2O;
169//
170// ps = pc_H2O
171// * exp(
172// Tc_H2O / T
173// * (a[1] * tau + a[2] * pow(tau, 1.5)
174// + a[3] * pow(tau, 3.0)
175// + a[4] * pow(tau, 3.5)
176// + a[5] * pow(tau, 4.0)
177// + a[6] * pow(tau, 7.5)));
178//
179// return (ps * 1.0e6);
180//
181//} /* end function ps_H2O */
182//
183//double LiBrSolution::rho_H2O(double T)
185//{
186// static double b[7] = { 0.0, 1.99274064, 1.09965342, -0.510839303,
187// -1.75493479, -45.5170352, -6.7469445e5 };
188// double theta, rho;
189//
190// theta = 1.0 - T / Tc_H2O;
191//
192// rho = rhoc_H2O
193// * (1.0 + b[1] * pow(theta, 1.0 / 3.0)
194// + b[2] * pow(theta, 2.0 / 3.0)
195// + b[3] * pow(theta, 5.0 / 3.0)
196// + b[4] * pow(theta, 16.0 / 3.0)
197// + b[5] * pow(theta, 43.0 / 3.0)
198// + b[6] * pow(theta, 110.0 / 3.0));
199//
200// return (rho);
201//} /* end function rho_H2O */
202//
203//double LiBrSolution::cp_H2O(double T)
205//{
206// static double a[5] =
207// { 1.38801, -2.95318, 3.18721, -0.645473, 9.18946e5 };
208// static double b[5] = { 0.0, 2.0, 3.0, 6.0, 34.0 };
209// static double c[5] = { 0.0, 2.0, 3.0, 5.0, 0.0 };
210//
211// double suma = 0.0;
212// int i;
213//
214// for (i = 0; i <= 4; i++)
215// suma += a[i] * exp(b[i] * log(1.0 - T / Tc_H2O))
216// * exp(c[i] * log(T / Tt_H2O));
217//
218// return (cpt_H2O * suma);
219//
220//} /* end function cp_H2O */
221//
222//double LiBrSolution::h_H2O(double T)
224//{
225// static double a[4] = { -4.37196e-1, 3.03440e-1, -1.29582, -1.76410e-1 };
226// static double alpha[4] = { 1.0 / 3.0, 2.0 / 3.0, 5.0 / 6.0, 21.0 / 6.0 };
227//
228// double suma = 0.0;
229// int i;
230//
231// for (i = 0; i <= 3; i++)
232// suma += a[i] * exp(alpha[i] * log(1.0 - T / Tc_H2O));
233//
234// return (hc_H2O * (1.0 + suma));
235//
236//} /* end function h_H2O */
237//
238//double LiBrSolution::s_H2O(double T)
240//{
241// static double a[4] = { -3.34112e-1, -8.47987e-1, -9.11980e-1, -1.64046 };
242// static double alpha[4] = { 1.0 / 3.0, 3.0 / 3.0, 8.0 / 3.0, 24.0 / 3.0 };
243//
244// double suma = 0.0;
245// int i;
246//
247// for (i = 0; i <= 3; i++)
248// suma += a[i] * exp(alpha[i] * log(1.0 - T / Tc_H2O));
249//
250// return (sc_H2O * (1.0 + suma));
251//
252//} /* end function s_H2O */
253//
254//
256// * convert the molar values to mass-based units. */
257//double LiBrSolution::massToMole(double w)
259//{
260// return (w/M_LiBr)/(w/M_LiBr+(1.-w)/M_H2O);
261// //return (w*M_LiBr)/(w*M_LiBr+(1.-w)*M_H2O);
262//}
263//
264//double LiBrSolution::molarToSpecific(double w, double value)
266//{
267// double x = massToMole(w);
268// //return w/(x*M_LiBr) * value;
269// return 1. / ( x*M_LiBr + (1.-x)*M_H2O ) * value;
270//}
271//
272//bool const LiBrSolution::debug = false;
273//
274//
275//
276//LiBrSolution::LiBrSolution():IncompressibleFluid(){
277// name = std::string("LiBr");
278// description = std::string("Lithium-Bromide solution from Patek2006");
279// reference = std::string("Patek2006");
280//
281// Tmin = 273.00;
282// Tmax = 500.00;
283// TminPsat = Tmin;
284//
285// xmin = 0.0;
286// xmax = 1.0;
287//
288// xbase = 0.0;
289// Tbase = 0.0;
290//
291//};
292//
293//double LiBrSolution::rho(double T, double p, double x){
294// checkTPX(T, p, x);
295// return 1./molarToSpecific(x, 1./rho_mix(T,massToMole(x)));
296//}
297//double LiBrSolution::c(double T, double p, double x){
298// checkTPX(T, p, x);
299// return molarToSpecific(x, cp_mix(T,massToMole(x)));
300//}
304//double LiBrSolution::s(double T, double p, double x){
305// checkTPX(T, p, x);
306// return molarToSpecific(x, s_mix(T,massToMole(x)));
307//}
308//double LiBrSolution::visc(double T, double p, double x){
309// throw ValueError("Viscosity is not defined for LiBr-solutions.");
310//}
311//double LiBrSolution::cond(double T, double p, double x){
312// throw ValueError("Thermal conductivity is not defined for LiBr-solutions.");
313//}
314//double LiBrSolution::u(double T, double p, double x){
315// checkTPX(T, p, x);
316// return molarToSpecific(x, h_mix(T,massToMole(x)));
317//}
318//double LiBrSolution::psat(double T, double x){
319// //checkT(T,p,x);
320// if (debug) throw ValueError(format("Your concentration is %f in kg/kg and %f in mol/mol.",x,massToMole(x)));
321// return ps_mix(T,massToMole(x));
322//};
323//double LiBrSolution::Tfreeze(double p, double x){
324// if (debug) throw ValueError(format("No freezing point data available for Lithium-Bromide: p=%f, x=%f",p,x));
325// return Tmin;
326//}
327
330 : _is_empty(true) {
331
332 // fluid_map.clear();
333 // name_vector.clear();
334 // string_to_index_map.clear();
335 //
336 // //shared_ptr<double> array (new double [256], ArrayDeleter<double> ());
337 };
338
341 // freeClear(fluid_map);
342 // fluid_map.clear();
343 // name_vector.clear();
344 // string_to_index_map.clear();
345};
346
348IncompressibleData JSONIncompressibleLibrary::parse_coefficients(const nlohmann::json& obj, const std::string& id, bool vital) {
349 IncompressibleData fluidData;
350 if (obj.contains(id)) {
351 const nlohmann::json& entry = obj.at(id);
352 if (entry.contains("type")) {
353 if (entry.contains("coeffs")) {
354 std::string type = cpjson::get_string(entry, "type");
355 if (!type.compare("polynomial")) {
357 fluidData.coeffs = vec_to_eigen(cpjson::get_double_array2D(entry.at("coeffs")));
358 return fluidData;
359 } else if (!type.compare("exponential")) {
361 fluidData.coeffs = vec_to_eigen(cpjson::get_double_array(entry.at("coeffs")));
362 return fluidData;
363 } else if (!type.compare("logexponential")) {
365 fluidData.coeffs = vec_to_eigen(cpjson::get_double_array(entry.at("coeffs")));
366 return fluidData;
367 } else if (!type.compare("exppolynomial")) {
369 fluidData.coeffs = vec_to_eigen(cpjson::get_double_array2D(entry.at("coeffs")));
370 return fluidData;
371 } else if (!type.compare("polyoffset")) {
373 fluidData.coeffs = vec_to_eigen(cpjson::get_double_array(entry.at("coeffs")));
374 return fluidData;
375 } else if (vital) {
376 throw ValueError(format("The type [%s] is not understood for [%s] of incompressible fluids. Please check your JSON file.",
377 type.c_str(), id.c_str()));
378 }
379 } else {
380 throw ValueError(format("Your file does not have an entry for \"coeffs\" in [%s], which is vital for this function.", id.c_str()));
381 }
382 } else {
383 throw ValueError(format("Your file does not have an entry for \"type\" in [%s], which is vital for this function.", id.c_str()));
384 }
385 } else {
386 if (vital) {
387 throw ValueError(format("Your file does not have information for [%s], which is vital for an incompressible fluid.", id.c_str()));
388 }
389 }
390 return fluidData;
391}
392
394double JSONIncompressibleLibrary::parse_value(const nlohmann::json& obj, const std::string& id, bool vital, double def = 0.0) {
395 if (obj.contains(id)) {
396 return cpjson::get_double(obj, id);
397 } else {
398 if (vital) {
399 throw ValueError(format("Your file does not have information for [%s], which is vital for an incompressible fluid.", id.c_str()));
400 } else {
401 return def;
402 }
403 }
404}
405
407composition_types JSONIncompressibleLibrary::parse_ifrac(const nlohmann::json& obj, const std::string& id) {
408 std::string res = cpjson::get_string(obj, id);
409 if (!res.compare("mass")) return IFRAC_MASS;
410 if (!res.compare("mole")) return IFRAC_MOLE;
411 if (!res.compare("volume")) return IFRAC_VOLUME;
412 if (!res.compare("not defined")) return IFRAC_UNDEFINED;
413 if (!res.compare("pure")) return IFRAC_PURE;
414
415 throw ValueError(format("Cannot recognise the entry for [%s], [%s] is unknown for incompressible fluids.", id.c_str(), res.c_str()));
416 return IFRAC_UNDEFINED;
417}
418
420void JSONIncompressibleLibrary::add_many(const nlohmann::json& listing) {
421 for (const auto& fluid_json : listing) {
422 add_one(fluid_json);
423 }
424};
425
426void JSONIncompressibleLibrary::add_one(const nlohmann::json& fluid_json) {
427 _is_empty = false;
428
429 // Get the next index for this fluid
430 std::size_t index = fluid_map.size();
431
432 // Add index->fluid mapping
433 fluid_map[index] = IncompressibleFluid();
434 //fluid_map[index].reset(new IncompressibleFluid());
435 //fluid_map[index].reset(new IncompressibleFluid());
436
437 // Create an instance of the fluid
438 IncompressibleFluid& fluid = fluid_map[index];
439 fluid.setName("unloaded");
440 try {
441 fluid.setName(cpjson::get_string(fluid_json, "name"));
442 if (get_debug_level() >= 20) std::cout << format("Incompressible library: Loading base values for %s ", fluid.getName().c_str()) << '\n';
443 fluid.setDescription(cpjson::get_string(fluid_json, "description"));
444 fluid.setReference(cpjson::get_string(fluid_json, "reference"));
445 fluid.setTmax(parse_value(fluid_json, "Tmax", true, 0.0));
446 fluid.setTmin(parse_value(fluid_json, "Tmin", true, 0.0));
447 fluid.setxmax(parse_value(fluid_json, "xmax", false, 1.0));
448 fluid.setxmin(parse_value(fluid_json, "xmin", false, 0.0));
449 fluid.setxid(parse_ifrac(fluid_json, "xid"));
450 fluid.setTminPsat(parse_value(fluid_json, "TminPsat", false, 0.0));
451
452 fluid.setTbase(parse_value(fluid_json, "Tbase", false, 0.0));
453 fluid.setxbase(parse_value(fluid_json, "xbase", false, 0.0));
454
456 if (get_debug_level() >= 20) std::cout << format("Incompressible library: Loading coefficients for %s ", fluid.getName().c_str()) << '\n';
457 fluid.setDensity(parse_coefficients(fluid_json, "density", true));
458 fluid.setSpecificHeat(parse_coefficients(fluid_json, "specific_heat", true));
459 fluid.setViscosity(parse_coefficients(fluid_json, "viscosity", false));
460 fluid.setConductivity(parse_coefficients(fluid_json, "conductivity", false));
461 fluid.setPsat(parse_coefficients(fluid_json, "saturation_pressure", false));
462 fluid.setTfreeze(parse_coefficients(fluid_json, "T_freeze", false));
463 fluid.setMass2input(parse_coefficients(fluid_json, "mass2input", false));
464 fluid.setVolume2input(parse_coefficients(fluid_json, "volume2input", false));
465 fluid.setMole2input(parse_coefficients(fluid_json, "mole2input", false));
466
467 //if (get_debug_level()>=20) std::cout << format("Incompressible library: Loading reference state for %s ",fluid.getName().c_str()) << std::endl;
468 //fluid.set_reference_state(
469 // parse_value(fluid_json, "Tref", false, 20+273.15) ,
470 // parse_value(fluid_json, "pref", false, 1.01325e5) ,
471 // parse_value(fluid_json, "xref", false, 0.0) ,
472 // parse_value(fluid_json, "href", false, 0.0) ,
473 // parse_value(fluid_json, "sref", false, 0.0)
474 // );
475
477 fluid.validate();
478
479 // Add name->index mapping
480 string_to_index_map[fluid.getName()] = index;
481
482 // Add name to vector of names
483 if (fluid.is_pure()) {
484 this->name_vector_pure.push_back(fluid.getName());
485 } else {
486 this->name_vector_solution.push_back(fluid.getName());
487 }
488 } catch (std::exception& e) {
489 std::cout << format("Unable to load fluid: %s; error was %s\n", fluid.getName().c_str(), e.what());
490 throw;
491 }
492};
493
495 _is_empty = false;
496
497 // Get the next index for this fluid
498 std::size_t index = fluid_map.size();
499
500 // Add index->fluid mapping
501 fluid_map[index] = fluid_obj;
502
503 // Create an instance of the fluid
504 IncompressibleFluid& fluid = fluid_map[index];
505
507 fluid.validate();
508
509 // Add name->index mapping
510 string_to_index_map[fluid.getName()] = index;
511}
512
513// Get an IncompressibleFluid instance stored in this library
515 // Try to find it
516 auto it = string_to_index_map.find(key);
517 // If it is found
518 if (it != string_to_index_map.end()) {
519 return get(it->second);
520 } else {
521 throw ValueError(format("key [%s] was not found in string_to_index_map in JSONIncompressibleLibrary", key.c_str()));
522 }
523};
524
526
530 // Try to find it
531 auto it = fluid_map.find(key);
532 // If it is found
533 if (it != fluid_map.end()) {
534 return it->second;
535 } else {
536 throw ValueError(format("key [%d] was not found in JSONIncompressibleLibrary", key));
537 }
538};
539
540static JSONIncompressibleLibrary library;
541
543
544// Thread-safe lazy initialization — see FluidLibrary.cpp for the same pattern
545// and rationale (gh-2787).
546static std::once_flag library_load_flag;
547
548static void ensure_library_loaded() {
549 std::call_once(library_load_flag, &load_incompressible_library);
550}
551
553 // This json formatted string comes from the all_incompressibles_JSON.h header
554 nlohmann::json dd = cpjson::parse(all_incompressibles_JSON);
555 try {
556 library.add_many(dd);
557 } catch (std::exception& e) {
558 std::cout << e.what() << '\n';
559 }
560 // TODO: Implement LiBr in the source code!
561 //library.add_obj(LiBrSolution());
562}
563
565 ensure_library_loaded();
566 return library;
567}
568
569IncompressibleFluid& get_incompressible_fluid(const std::string& fluid_string) {
570 ensure_library_loaded();
571 return library.get(fluid_string);
572}
573
575 ensure_library_loaded();
576 return library.get_incompressible_list_pure();
577};
579 ensure_library_loaded();
580 return library.get_incompressible_list_solution();
581};
582
583} /* namespace CoolProp */