CoolProp  6.6.0
An open-source fluid property and humid air property database
PCSAFTLibrary.cpp
Go to the documentation of this file.
1 #include <string>
2 #include <map>
3 #include "PCSAFTLibrary.h"
4 #include "all_pcsaft_JSON.h" // Makes a std::string variable called all_pcsaft_JSON
5 #include "pcsaft_fluids_schema_JSON.h" // Makes a std::string variable called pcsaft_fluids_schema_JSON
6 #include "mixture_binary_pairs_pcsaft_JSON.h" // Makes a std::string variable called mixture_binary_pairs_pcsaft_JSON
7 #include "rapidjson_include.h"
8 #include "CPstrings.h"
9 #include "CoolProp.h"
10 #include "Configuration.h"
12 #include "CoolPropTools.h"
13 
14 namespace CoolProp {
15 
16 std::string get_mixture_binary_pair_pcsaft(const std::string& CAS1, const std::string& CAS2, const std::string& key) {
18 }
19 
20 void set_mixture_binary_pair_pcsaft(const std::string& CAS1, const std::string& CAS2, const std::string& key, const double value) {
22 }
23 
24 namespace PCSAFTLibrary {
25 
26 static PCSAFTLibraryClass library;
27 
29  return library;
30 }
31 
33  // This JSON formatted string comes from the all_pcsaft_JSON.h header which is a C++-escaped version of the JSON file
35 
36  // Then we add the library of binary interaction parameters
37  if (m_binary_pair_map.size() == 0) {
38  PCSAFTLibraryClass::load_from_string(mixture_binary_pairs_pcsaft_JSON);
39  }
40 }
41 
42 // Get a PCSAFTFluid instance stored in this library
43 PCSAFTFluid& PCSAFTLibraryClass::get(const std::string& key) {
44  // Try to find it
45  std::map<std::string, std::size_t>::iterator it = string_to_index_map.find(key);
46  // If it is found
47  if (it != string_to_index_map.end()) {
48  return get(it->second);
49  } else {
50  throw ValueError(format("key [%s] was not found in string_to_index_map in PCSAFTLibraryClass", key.c_str()));
51  }
52 }
53 
55 
59  // Try to find it
60  std::map<std::size_t, PCSAFTFluid>::iterator it = fluid_map.find(key);
61  // If it is found
62  if (it != fluid_map.end()) {
63  return it->second;
64  } else {
65  throw ValueError(format("key [%d] was not found in PCSAFTLibraryClass", key));
66  }
67 };
68 
69 void add_fluids_as_JSON(const std::string& JSON) {
70  // First we validate the json string against the schema;
71  std::string errstr;
73  // Then we check the validation code
74 
75  if (val_code == cpjson::SCHEMA_VALIDATION_OK) {
76  rapidjson::Document dd;
77 
78  dd.Parse<0>(JSON.c_str());
79  if (dd.HasParseError()) {
80  throw ValueError("Unable to load all_pcsaft_JSON.json");
81  } else {
82  try {
83  library.add_many(dd);
84  } catch (std::exception& e) {
85  std::cout << e.what() << std::endl;
86  }
87  }
88  } else {
89  if (get_debug_level() > 0) {
90  throw ValueError(format("Unable to load PC-SAFT library with error: %s", errstr.c_str()));
91  }
92  }
93 }
94 
95 int PCSAFTLibraryClass::add_many(rapidjson::Value& listing) {
96  int counter = 0;
97  std::string fluid_name;
98  for (rapidjson::Value::ValueIterator itr = listing.Begin(); itr != listing.End(); ++itr) {
99  try {
100  PCSAFTFluid fluid(itr);
101  fluid_name = fluid.getName();
102 
103  // If the fluid is ok...
104 
105  // First check that none of the identifiers are already present
106  bool already_present = false;
107 
108  if (string_to_index_map.find(fluid.getCAS()) != string_to_index_map.end()
109  || string_to_index_map.find(fluid_name) != string_to_index_map.end()
110  || string_to_index_map.find(upper(fluid_name)) != string_to_index_map.end()) {
111  already_present = true;
112  } else {
113  // Check the aliases
114  for (std::size_t i = 0; i < fluid.getAliases().size(); ++i) {
115  if (string_to_index_map.find(fluid.getAliases()[i]) != string_to_index_map.end()) {
116  already_present = true;
117  break;
118  }
119  if (string_to_index_map.find(upper(fluid.getAliases()[i])) != string_to_index_map.end()) {
120  already_present = true;
121  break;
122  }
123  }
124  }
125 
126  if (already_present) {
127  if (!get_config_bool(OVERWRITE_FLUIDS)) {
128  throw ValueError(format(
129  "Cannot load fluid [%s:%s] because it is already in library; consider enabling the config boolean variable OVERWRITE_FLUIDS",
130  fluid.getName().c_str(), fluid.getCAS().c_str()));
131  } else {
132  // Remove the one(s) that are already there
133 
134  // Remove the actual fluid instance
135  std::size_t index = string_to_index_map.find(fluid_name)->second;
136 
137  if (fluid_map.find(index) != fluid_map.end()) {
138  fluid_map.erase(fluid_map.find(index));
139  }
140 
141  if (string_to_index_map.find(fluid_name) != string_to_index_map.end()) {
142  fluid_map.erase(fluid_map.find(index));
143  }
144 
145  // Remove the identifiers pointing to that instance
146  if (string_to_index_map.find(fluid.getCAS()) != string_to_index_map.end()) {
147  string_to_index_map.erase(string_to_index_map.find(fluid.getCAS()));
148  }
149  if (string_to_index_map.find(fluid_name) != string_to_index_map.end()) {
150  string_to_index_map.erase(string_to_index_map.find(fluid_name));
151  }
152  // Check the aliases
153  for (std::size_t i = 0; i < fluid.getAliases().size(); ++i) {
154  if (string_to_index_map.find(fluid.getAliases()[i]) != string_to_index_map.end()) {
155  string_to_index_map.erase(string_to_index_map.find(fluid.getAliases()[i]));
156  }
157  if (string_to_index_map.find(upper(fluid.getAliases()[i])) != string_to_index_map.end()) {
158  string_to_index_map.erase(string_to_index_map.find(upper(fluid.getAliases()[i])));
159  }
160  }
161  }
162  }
163 
164  // By now, the library has been cleared of remnants of this fluid; safe to add the fluid now.
165 
166  // Get the next index for this fluid
167  std::size_t index = fluid_map.size();
168 
169  // Add index->fluid mapping
170  fluid_map[index] = fluid;
171 
172  // fluid_map[index] = cpjson::json2string(fluid_json);
173 
174  // Add CAS->index mapping
175  string_to_index_map[fluid.getCAS()] = index;
176 
177  // Add name->index mapping
178  string_to_index_map[fluid_name] = index;
179 
180  // Add the aliases
181  for (std::size_t i = 0; i < fluid.getAliases().size(); ++i) {
182  string_to_index_map[fluid.getAliases()[i]] = index;
183 
184  // Add uppercase alias for EES compatibility
185  string_to_index_map[upper(fluid.getAliases()[i])] = index;
186  }
187 
188  counter++;
189  if (get_debug_level() > 5) {
190  std::cout << format("Loaded.\n");
191  }
192  } catch (const std::exception& e) {
193  throw ValueError(format("Unable to load fluid [%s] due to error: %s", fluid_name.c_str(), e.what()));
194  }
195  }
196  return counter;
197 };
198 
201 }
202 
203 std::string PCSAFTLibraryClass::get_binary_interaction_pcsaft(const std::string& CAS1, const std::string& CAS2, const std::string& key) {
204  // Find pair
205  std::vector<std::string> CAS;
206  CAS.push_back(CAS1);
207  CAS.push_back(CAS2);
208 
209  std::vector<std::string> CASrev;
210  CASrev.push_back(CAS2);
211  CASrev.push_back(CAS1);
212 
213  if (m_binary_pair_map.find(CAS) != m_binary_pair_map.end()) {
214  std::vector<Dictionary>& v = m_binary_pair_map[CAS];
215  try {
216  if (key == "name1") {
217  return v[0].get_string("name1");
218  } else if (key == "name2") {
219  return v[0].get_string("name2");
220  } else if (key == "BibTeX") {
221  return v[0].get_string("BibTeX");
222  } else if (key == "kij") {
223  return format("%0.16g", v[0].get_double("kij"));
224  } else if (key == "kijT") {
225  try {
226  return format("%0.16g", v[0].get_double("kijT"));
227  } catch (ValueError) {
228  return format("%0.16g", 0.0);
229  }
230  } else {
231  }
232  } catch (...) {
233  }
234  throw ValueError(format("Could not match the parameter [%s] for the binary pair [%s,%s] - for now this is an error.", key.c_str(),
235  CAS1.c_str(), CAS2.c_str()));
236  } else if (m_binary_pair_map.find(CASrev) != m_binary_pair_map.end()) {
237  std::vector<Dictionary>& v = m_binary_pair_map[CASrev];
238  try {
239  if (key == "name1") {
240  return v[0].get_string("name1");
241  } else if (key == "name2") {
242  return v[0].get_string("name2");
243  } else if (key == "BibTeX") {
244  return v[0].get_string("BibTeX");
245  } else if (key == "kij") {
246  return format("%0.16g", v[0].get_double("kij"));
247  } else if (key == "kijT") {
248  try {
249  return format("%0.16g", v[0].get_double("kijT"));
250  } catch (ValueError) {
251  return format("%0.16g", 0.0);
252  }
253  } else {
254  }
255  } catch (...) {
256  }
257  throw ValueError(format("Could not match the parameter [%s] for the binary pair [%s,%s] - for now this is an error.", key.c_str(),
258  CAS1.c_str(), CAS2.c_str()));
259  } else {
260  // Sort, see if other order works properly
261  std::sort(CAS.begin(), CAS.end());
262  if (m_binary_pair_map.find(CAS) != m_binary_pair_map.end()) {
263  throw ValueError(format("Could not match the binary pair [%s,%s] - order of CAS numbers is backwards; found the swapped CAS numbers.",
264  CAS1.c_str(), CAS2.c_str()));
265  } else {
266  throw ValueError(format("Could not match the binary pair [%s,%s] - for now this is an error.", CAS1.c_str(), CAS2.c_str()));
267  }
268  }
269 }
270 
271 void PCSAFTLibraryClass::set_binary_interaction_pcsaft(const std::string& CAS1, const std::string& CAS2, const std::string& key, const double value) {
272  // Find pair
273  std::vector<std::string> CAS;
274  CAS.push_back(CAS1);
275  CAS.push_back(CAS2);
276 
277  std::vector<std::string> CASrev;
278  CASrev.push_back(CAS2);
279  CASrev.push_back(CAS1);
280 
281  if (m_binary_pair_map.find(CAS) != m_binary_pair_map.end()) {
282  if (get_config_bool(OVERWRITE_BINARY_INTERACTION)) {
283  std::vector<Dictionary>& v = m_binary_pair_map[CAS];
284  if (v[0].has_number(key)) {
285  v[0].add_number(key, value);
286  } else {
287  throw ValueError(format("Could not set the parameter [%s] for the binary pair [%s,%s] - for now this is an error", key.c_str(),
288  CAS1.c_str(), CAS2.c_str()));
289  }
290  } else {
291  throw ValueError(
292  format("CAS pair(%s,%s) already in binary interaction map; considering enabling configuration key OVERWRITE_BINARY_INTERACTION",
293  CAS1.c_str(), CAS2.c_str()));
294  }
295  } else if (m_binary_pair_map.find(CASrev) != m_binary_pair_map.end()) {
296  if (get_config_bool(OVERWRITE_BINARY_INTERACTION)) {
297  std::vector<Dictionary>& v = m_binary_pair_map[CASrev];
298  if (v[0].has_number(key)) {
299  v[0].add_number(key, value);
300  } else {
301  throw ValueError(format("Could not set the parameter [%s] for the binary pair [%s,%s] - for now this is an error", key.c_str(),
302  CAS1.c_str(), CAS2.c_str()));
303  }
304  } else {
305  throw ValueError(
306  format("CAS pair(%s,%s) already in binary interaction map; considering enabling configuration key OVERWRITE_BINARY_INTERACTION",
307  CAS1.c_str(), CAS2.c_str()));
308  }
309  } else {
310  Dictionary dict;
311  std::vector<std::string> CAS;
312  CAS.push_back(CAS1);
313  CAS.push_back(CAS2);
314  dict.add_number(key, value);
315 
316  m_binary_pair_map.insert(std::pair<std::vector<std::string>, std::vector<Dictionary>>(CAS, std::vector<Dictionary>(1, dict)));
317  }
318 }
319 
320 void PCSAFTLibraryClass::load_from_JSON(rapidjson::Document& doc) {
321  for (rapidjson::Value::ValueIterator itr = doc.Begin(); itr != doc.End(); ++itr) {
322  // Get the empty dictionary to be filled by the appropriate interaction parameter
323  Dictionary dict;
324 
325  // Get the vector of CAS numbers
326  std::vector<std::string> CAS;
327  CAS.push_back(cpjson::get_string(*itr, "CAS1"));
328  CAS.push_back(cpjson::get_string(*itr, "CAS2"));
329  std::string name1 = cpjson::get_string(*itr, "Name1");
330  std::string name2 = cpjson::get_string(*itr, "Name2");
331 
332  // Sort the CAS number vector
333  std::sort(CAS.begin(), CAS.end());
334 
335  // A sort was carried out, names/CAS were swapped
336  bool swapped = CAS[0].compare(cpjson::get_string(*itr, "CAS1")) != 0;
337 
338  if (swapped) {
339  std::swap(name1, name2);
340  }
341 
342  // Populate the dictionary with common terms
343  dict.add_string("name1", name1);
344  dict.add_string("name2", name2);
345  dict.add_string("BibTeX", cpjson::get_string(*itr, "BibTeX"));
346  if (itr->HasMember("kij")) {
347  dict.add_number("kij", cpjson::get_double(*itr, "kij"));
348  } else {
349  std::cout << "Loading error: binary pair of " << name1 << " & " << name2 << "does not provide kij" << std::endl;
350  }
351  if (itr->HasMember("kijT")) {
352  dict.add_number("kijT", cpjson::get_double(*itr, "kijT"));
353  }
354 
355  std::map<std::vector<std::string>, std::vector<Dictionary>>::iterator it = m_binary_pair_map.find(CAS);
356  if (it == m_binary_pair_map.end()) {
357  // Add to binary pair map by creating one-element vector
358  m_binary_pair_map.insert(std::pair<std::vector<std::string>, std::vector<Dictionary>>(CAS, std::vector<Dictionary>(1, dict)));
359  } else {
360  if (get_config_bool(OVERWRITE_BINARY_INTERACTION)) {
361  // Already there, see http://www.cplusplus.com/reference/map/map/insert/, so we are going to pop it and overwrite it
362  m_binary_pair_map.erase(it);
363  std::pair<std::map<std::vector<std::string>, std::vector<Dictionary>>::iterator, bool> ret;
364  ret = m_binary_pair_map.insert(std::pair<std::vector<std::string>, std::vector<Dictionary>>(CAS, std::vector<Dictionary>(1, dict)));
365  assert(ret.second == true);
366  } else {
367  // Error if already in map!
368  throw ValueError(
369  format("CAS pair(%s,%s) already in binary interaction map; considering enabling configuration key OVERWRITE_BINARY_INTERACTION",
370  CAS[0].c_str(), CAS[1].c_str()));
371  }
372  }
373  }
374 }
375 
376 void PCSAFTLibraryClass::load_from_string(const std::string& str) {
377  rapidjson::Document doc;
378  doc.Parse<0>(str.c_str());
379  if (doc.HasParseError()) {
380  throw ValueError("Unable to parse PC-SAFT binary interaction parameter string");
381  }
382  load_from_JSON(doc);
383 }
384 
385 } // namespace PCSAFTLibrary
386 } // namespace CoolProp