CoolProp 7.2.0
An open-source fluid property and humid air property database
Configuration.h
Go to the documentation of this file.
1#ifndef COOLPROP_CONFIGURATION
2#define COOLPROP_CONFIGURATION
3
4#include "Exceptions.h"
5#include "CoolPropTools.h"
6#include <cstdlib>
7#include <unordered_map>
8
9#if !defined(SWIG) // Hide this for swig - Swig gets confused
10# include "rapidjson_include.h"
11#endif
12
13/* See http://stackoverflow.com/a/148610
14 * See http://stackoverflow.com/questions/147267/easy-way-to-use-variables-of-enum-types-as-string-in-c#202511
15 * This will be used to generate an enum like:
16 * enum configuration_keys {NORMALIZE_GAS_CONSTANTS, CRITICAL_SPLINES_ENABLED};
17 *
18 * The values in this list are given by:
19 * enum, string representation of enum, default value, description
20 *
21 * The type of the default value specifies the only type that will be accepted for this parameter
22 */
23#define CONFIGURATION_KEYS_ENUM \
24 X(NORMALIZE_GAS_CONSTANTS, "NORMALIZE_GAS_CONSTANTS", true, "If true, for mixtures, the molar gas constant (R) will be set to the CODATA value") \
25 X(CRITICAL_WITHIN_1UK, "CRITICAL_WITHIN_1UK", true, \
26 "If true, any temperature within 1 uK of the critical temperature will be considered to be AT the critical point") \
27 X(CRITICAL_SPLINES_ENABLED, "CRITICAL_SPLINES_ENABLED", true, \
28 "If true, the critical splines will be used in the near-vicinity of the critical point") \
29 X(SAVE_RAW_TABLES, "SAVE_RAW_TABLES", false, "If true, the raw, uncompressed tables will also be written to file") \
30 X(ALTERNATIVE_TABLES_DIRECTORY, "ALTERNATIVE_TABLES_DIRECTORY", "", \
31 "If provided, this path will be the root directory for the tabular data. Otherwise, ${HOME}/.CoolProp/Tables is used") \
32 X(ALTERNATIVE_REFPROP_PATH, "ALTERNATIVE_REFPROP_PATH", "", \
33 "An alternative path to be provided to the directory that contains REFPROP's fluids and mixtures directories. If provided, the SETPATH " \
34 "function will be called with this directory prior to calling any REFPROP functions.") \
35 X(ALTERNATIVE_REFPROP_HMX_BNC_PATH, "ALTERNATIVE_REFPROP_HMX_BNC_PATH", "", \
36 "An alternative path to the HMX.BNC file. If provided, it will be passed into REFPROP's SETUP or SETMIX routines") \
37 X(ALTERNATIVE_REFPROP_LIBRARY_PATH, "ALTERNATIVE_REFPROP_LIBRARY_PATH", "", \
38 "An alternative path to the shared library file. If provided, it will be used to load REFPROP") \
39 X(REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS, "REFPROP_DONT_ESTIMATE_INTERACTION_PARAMETERS", false, \
40 "If true, if the binary interaction parameters in REFPROP are estimated, throw an error rather than silently continuing") \
41 X(REFPROP_IGNORE_ERROR_ESTIMATED_INTERACTION_PARAMETERS, "REFPROP_IGNORE_ERROR_ESTIMATED_INTERACTION_PARAMETERS", false, \
42 "If true, if the binary interaction parameters in REFPROP are unable to be estimated, silently continue rather than failing") \
43 X(REFPROP_USE_GERG, "REFPROP_USE_GERG", false, \
44 "If true, rather than using the highly-accurate pure fluid equations of state, use the pure-fluid EOS from GERG-2008") \
45 X(REFPROP_ERROR_THRESHOLD, "REFPROP_ERROR_THRESHOLD", static_cast<int>(0), "The highest acceptable error code without throwing an exception") \
46 X(REFPROP_USE_PENGROBINSON, "REFPROP_USE_PENGROBINSON", false, \
47 "If true, rather than using the highly-accurate pure fluid equations of state, use the Peng-Robinson EOS") \
48 X(MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB, "MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB", 1.0, \
49 "The maximum allowed size of the directory that is used to store tabular data") \
50 X(DONT_CHECK_PROPERTY_LIMITS, "DONT_CHECK_PROPERTY_LIMITS", false, \
51 "If true, when possible, CoolProp will skip checking whether values are inside the property limits") \
52 X(HENRYS_LAW_TO_GENERATE_VLE_GUESSES, "HENRYS_LAW_TO_GENERATE_VLE_GUESSES", false, \
53 "If true, when doing water-based mixture dewpoint calculations, use Henry's Law to generate guesses for liquid-phase composition") \
54 X(PHASE_ENVELOPE_STARTING_PRESSURE_PA, "PHASE_ENVELOPE_STARTING_PRESSURE_PA", 100.0, "Starting pressure [Pa] for phase envelope construction") \
55 X(R_U_CODATA, "R_U_CODATA", 8.31446261815324, \
56 "The value for the ideal gas constant in J/mol/K according to CODATA 2022. This value is used to harmonize all the ideal gas constants. " \
57 "This is especially important in the critical region.") \
58 X(VTPR_UNIFAC_PATH, "VTPR_UNIFAC_PATH", "", "The path to the directory containing the UNIFAC JSON files. Should be slash terminated") \
59 X(SPINODAL_MINIMUM_DELTA, "SPINODAL_MINIMUM_DELTA", 0.5, \
60 "The minimal delta to be used in tracing out the spinodal; make sure that the EOS has a spinodal at this value of delta=rho/rho_r") \
61 X(OVERWRITE_FLUIDS, "OVERWRITE_FLUIDS", false, \
62 "If true, and a fluid is added to the fluids library that is already there, rather than not adding the fluid (and probably throwing an " \
63 "exception), overwrite it") \
64 X(OVERWRITE_DEPARTURE_FUNCTION, "OVERWRITE_DEPARTURE_FUNCTION", false, \
65 "If true, and a departure function to be added is already there, rather than not adding the departure function (and probably throwing an " \
66 "exception), overwrite it") \
67 X(OVERWRITE_BINARY_INTERACTION, "OVERWRITE_BINARY_INTERACTION", false, \
68 "If true, and a pair of binary interaction pairs to be added is already there, rather than not adding the binary interaction pair (and " \
69 "probably throwing an exception), overwrite it") \
70 X(USE_GUESSES_IN_PROPSSI, "USE_GUESSES_IN_PROPSSI", false, \
71 "If true, calls to the vectorized versions of PropsSI use the previous state as guess value while looping over the input vectors, only makes " \
72 "sense when working with a single fluid and with points that are not too far from each other.") \
73 X(ASSUME_CRITICAL_POINT_STABLE, "ASSUME_CRITICAL_POINT_STABLE", false, \
74 "If true, evaluation of the stability of critical point will be skipped and point will be assumed to be stable") \
75 X(VTPR_ALWAYS_RELOAD_LIBRARY, "VTPR_ALWAYS_RELOAD_LIBRARY", false, \
76 "If true, the library will always be reloaded, no matter what is currently loaded") \
77 X(FLOAT_PUNCTUATION, "FLOAT_PUNCTUATION", ".", "The first character of this string will be used as the separator between the number fraction.") \
78 X(ENABLE_SUPERANCILLARIES, "ENABLE_SUPERANCILLARIES", true, "If true, the superancillary functions will be used for VLE of pure fluids") \
79 X(LIST_STRING_DELIMITER, "LIST_STRING_DELIMITER", ",", "The delimiter to be used when converting a list of strings to a string")
80
81// Use preprocessor to create the Enum
83{
84#define X(Enum, String, Default, Desc) Enum,
86#undef X
87};
88
89// Evidently SWIG+MATLAB cannot properly wrap enums within classes
91{
98};
99
100namespace CoolProp {
101
104
106configuration_keys config_string_to_key(const std::string& s);
107
110
112std::string config_key_description(const std::string& key);
113
117{
118 public:
120 return type;
121 }
122
124 operator bool() const {
125 check_data_type(CONFIGURATION_BOOL_TYPE);
126 return v_bool;
127 };
129 operator double() const {
130 check_data_type(CONFIGURATION_DOUBLE_TYPE);
131 return v_double;
132 };
134 operator std::string() const {
135 check_data_type(CONFIGURATION_STRING_TYPE);
136 return v_string;
137 };
139 operator int() const {
140 check_data_type(CONFIGURATION_INTEGER_TYPE);
141 return v_integer;
142 };
143 // Initializer for bool
145 this->key = key;
147 v_bool = val;
148 };
149 // Initializer for integer
151 this->key = key;
153 v_integer = val;
154 };
155 // Initializer for double
157 this->key = key;
159 v_double = val;
160 };
161 // Initializer for const char *
162 ConfigurationItem(configuration_keys key, const char* val) {
163 this->key = key;
165 v_string = val;
166 };
167 // Initializer for string
168 ConfigurationItem(configuration_keys key, const std::string& val) {
169 this->key = key;
171 v_string = val;
172 };
173 void set_bool(bool val) {
174 check_data_type(CONFIGURATION_BOOL_TYPE);
175 v_bool = val;
176 }
177 void set_integer(int val) {
178 check_data_type(CONFIGURATION_INTEGER_TYPE);
179 v_integer = val;
180 }
181 void set_double(double val) {
182 check_data_type(CONFIGURATION_DOUBLE_TYPE);
183 v_double = val;
184 }
185 void set_string(const std::string& val) {
186 check_data_type(CONFIGURATION_STRING_TYPE);
187 v_string = val;
188 }
189
191 return this->key;
192 }
193#if !defined(SWIG)
195 void add_to_json(rapidjson::Value& val, rapidjson::Document& d) const {
196 std::string name_string = config_key_to_string(key);
197 rapidjson::Value name(name_string.c_str(), d.GetAllocator());
198 switch (type) {
200 rapidjson::Value v(v_bool);
201 val.AddMember(name, v, d.GetAllocator());
202 break;
203 }
205 rapidjson::Value v(v_integer);
206 val.AddMember(name, v, d.GetAllocator());
207 break;
208 }
210 rapidjson::Value v(v_double); // Try to upcast
211 val.AddMember(name, v, d.GetAllocator());
212 break;
213 }
215 rapidjson::Value v(v_string.c_str(), d.GetAllocator());
216 val.AddMember(name, v, d.GetAllocator());
217 break;
218 }
221 throw ValueError();
222 }
223 }
224 void set_from_json(rapidjson::Value& val) {
225 switch (type) {
227 if (!val.IsBool()) {
228 throw ValueError(format("Input is not boolean"));
229 };
230 v_bool = val.GetBool();
231 break;
233 if (!val.IsInt()) {
234 throw ValueError(format("Input is not integer"));
235 };
236 v_integer = val.GetInt();
237 break;
239 if (!val.IsDouble() && !val.IsInt()) {
240 throw ValueError(format("Input [%s] is not double (or something that can be cast to double)", cpjson::to_string(val).c_str()));
241 };
242 if (val.IsDouble()) {
243 v_double = val.GetDouble();
244 } else {
245 v_double = static_cast<double>(val.GetInt());
246 }
247 break;
248 }
250 if (!val.IsString()) {
251 throw ValueError(format("Input is not string"));
252 };
253 v_string = val.GetString();
254 break;
257 throw ValueError();
258 }
259 }
260#endif // !defined(SWIG)
261
262 private:
263 void check_data_type(ConfigurationDataTypes type) const {
264 if (type != this->type) {
265 throw ValueError(format("type does not match"));
266 }
267 };
269 union
270 {
271 double v_double;
272 bool v_bool;
274 };
275 std::string v_string;
277};
278
280{
281 protected:
282 std::unordered_map<configuration_keys, ConfigurationItem> items;
283
284 public:
286 set_defaults();
287 };
289
292 // Try to find it
293 std::unordered_map<configuration_keys, ConfigurationItem>::iterator it = items.find(key);
294 // If equal to end, not found
295 if (it != items.end()) {
296 // Found, return it
297 return it->second;
298 } else {
299 throw ValueError(format("invalid item"));
300 }
301 }
304 std::pair<configuration_keys, ConfigurationItem> pair(item.get_key(), item);
305 items.insert(pair);
306 };
307
309 std::unordered_map<configuration_keys, ConfigurationItem>& get_items(void) {
310 return items;
311 };
312
315 std::string envkey = "COOLPROP_" + config_key_to_string(key);
316 const char* envval = std::getenv(envkey.c_str());
317 if (envval) {
318 auto tobool = [](const std::string x) {
319 if (x == "True" || x == "true") {
320 return true;
321 }
322 if (x == "False" || x == "false") {
323 return false;
324 }
325 throw ValueError(x);
326 };
327 switch (get_item(key).get_type()) {
329 items.erase(key);
330 items.emplace(key, ConfigurationItem(key, std::string(envval)));
331 break;
333 int i;
334 try {
335 i = std::stoi(envval);
336 } catch (...) {
337 auto skey = config_key_to_string(key);
338 std::string msg = "Unable to convert \"" + std::string(envval) + "\" to int for key [" + skey + "]";
339 std::cerr << msg << std::endl;
340 throw ValueError(msg);
341 }
342 items.erase(key);
343 items.emplace(key, ConfigurationItem(key, i));
344 break;
346 double d;
347 try {
348 d = std::stod(envval);
349 } catch (...) {
350 auto skey = config_key_to_string(key);
351 std::string msg = "Unable to convert \"" + std::string(envval) + "\" to double for key [" + skey + "]";
352 std::cerr << msg << std::endl;
353 throw ValueError(msg);
354 }
355 items.erase(key);
356 items.emplace(key, ConfigurationItem(key, d));
357 break;
359 bool b;
360 try {
361 b = tobool(envval);
362 } catch (...) {
363 auto skey = config_key_to_string(key);
364 std::string msg = "Unable to convert \"" + std::string(envval) + "\" to bool for key [" + skey + "]";
365 std::cerr << msg << std::endl;
366 throw ValueError(msg);
367 }
368 items.erase(key);
369 items.emplace(key, ConfigurationItem(key, b));
370 break;
371 default:
372 auto skey = config_key_to_string(key);
373 throw ValueError("This key [" + skey + "] has the wrong type; value was " + std::string(envval) + " ");
374 }
375 return true;
376 }
377 return false;
378 }
379
381 void set_defaults(void) {
382/* ***MAGIC WARNING**!!
383 * See http://stackoverflow.com/a/148610
384 * See http://stackoverflow.com/questions/147267/easy-way-to-use-variables-of-enum-types-as-string-in-c#202511
385 */
386#define X(Enum, String, Default, Desc) add_item(ConfigurationItem(Enum, Default));
388#undef X
389
390 // See if the variable is already present as environment variable
391#define X(Enum, String, Default, Desc) possibly_set_from_env(Enum);
393#undef X
394
395 };
396};
397
401
410#if !defined(SWIG) // Hide this for swig - Swig gets confused
411void get_config_as_json(rapidjson::Document& doc);
412#endif
414std::string get_config_as_json_string();
415
419
421void set_config_bool(configuration_keys key, bool val);
423void set_config_int(configuration_keys key, int val);
425void set_config_double(configuration_keys key, double val);
427void set_config_string(configuration_keys key, const std::string& val);
429#if !defined(SWIG) // Hide this for swig - Swig gets confused
430void set_config_json(rapidjson::Document& doc);
431#endif
433void set_config_as_json_string(const std::string& s);
434} // namespace CoolProp
435
436#endif // COOLPROP_CONFIGURATION