CoolProp  6.6.0
An open-source fluid property and humid air property database
UNIFACLibrary.cpp
Go to the documentation of this file.
1 #include "UNIFACLibrary.h"
3 #include "Configuration.h"
4 
5 namespace UNIFACLibrary {
6 
7 void UNIFACParameterLibrary::jsonize(std::string& s, rapidjson::Document& d) {
8  d.Parse<0>(s.c_str());
9  if (d.HasParseError()) {
10  throw -1;
11  } else {
12  return;
13  }
14 }
15 void UNIFACParameterLibrary::populate(rapidjson::Value& group_data, rapidjson::Value& interaction_data, rapidjson::Value& comp_data) {
16  if (CoolProp::get_config_bool(VTPR_ALWAYS_RELOAD_LIBRARY)) {
17  groups.clear();
18  interaction_parameters.clear();
19  components.clear();
20  }
21  // Schema should have been used to validate the data already, so by this point we are can safely consume the data without checking ...
22  for (rapidjson::Value::ValueIterator itr = group_data.Begin(); itr != group_data.End(); ++itr) {
23  Group g;
24  g.sgi = (*itr)["sgi"].GetInt();
25  g.mgi = (*itr)["mgi"].GetInt();
26  g.R_k = (*itr)["R_k"].GetDouble();
27  g.Q_k = (*itr)["Q_k"].GetDouble();
28  groups.push_back(g);
29  }
30  for (rapidjson::Value::ValueIterator itr = interaction_data.Begin(); itr != interaction_data.End(); ++itr) {
32  ip.mgi1 = (*itr)["mgi1"].GetInt();
33  ip.mgi2 = (*itr)["mgi2"].GetInt();
34  ip.a_ij = (*itr)["a_ij"].GetDouble();
35  ip.a_ji = (*itr)["a_ji"].GetDouble();
36  ip.b_ij = (*itr)["b_ij"].GetDouble();
37  ip.b_ji = (*itr)["b_ji"].GetDouble();
38  ip.c_ij = (*itr)["c_ij"].GetDouble();
39  ip.c_ji = (*itr)["c_ji"].GetDouble();
40  interaction_parameters.push_back(ip);
41  }
42  for (rapidjson::Value::ValueIterator itr = comp_data.Begin(); itr != comp_data.End(); ++itr) {
43  Component c;
44  c.inchikey = (*itr)["inchikey"].GetString();
45  c.registry_number = (*itr)["registry_number"].GetString();
46  c.name = (*itr)["name"].GetString();
47  c.Tc = (*itr)["Tc"].GetDouble();
48  c.pc = (*itr)["pc"].GetDouble();
49  c.acentric = (*itr)["acentric"].GetDouble();
50  c.molemass = (*itr)["molemass"].GetDouble();
51  // userid is an optional user identifier
52  if ((*itr).HasMember("userid")) {
53  c.userid = (*itr)["userid"].GetString();
54  }
55  // If provided, store information about the alpha function in use
56  if ((*itr).HasMember("alpha") && (*itr)["alpha"].IsObject()) {
57  rapidjson::Value& alpha = (*itr)["alpha"];
58  c.alpha_type = cpjson::get_string(alpha, "type");
59  c.alpha_coeffs = cpjson::get_double_array(alpha, "c");
60  } else {
61  c.alpha_type = "default";
62  }
63  if ((*itr).HasMember("alpha0") && (*itr)["alpha0"].IsArray()) {
65  }
66  rapidjson::Value& groups = (*itr)["groups"];
67  for (rapidjson::Value::ValueIterator itrg = groups.Begin(); itrg != groups.End(); ++itrg) {
68  int count = (*itrg)["count"].GetInt();
69  int sgi = (*itrg)["sgi"].GetInt();
70  if (has_group(sgi)) {
71  ComponentGroup cg(count, get_group(sgi));
72  c.groups.push_back(cg);
73  }
74  }
75  components.push_back(c);
76  }
77 }
78 void UNIFACParameterLibrary::populate(std::string& group_data, std::string& interaction_data, std::string& decomp_data) {
79  rapidjson::Document group_JSON;
80  jsonize(group_data, group_JSON);
81  rapidjson::Document interaction_JSON;
82  jsonize(interaction_data, interaction_JSON);
83  rapidjson::Document decomp_JSON;
84  jsonize(decomp_data, decomp_JSON);
85  populate(group_JSON, interaction_JSON, decomp_JSON);
86  m_populated = true;
87 }
89  for (std::vector<Group>::const_iterator it = groups.begin(); it != groups.end(); ++it) {
90  if (it->sgi == sgi) {
91  return *it;
92  }
93  }
94  throw CoolProp::ValueError("Could not find group");
95 }
96 bool UNIFACParameterLibrary::has_group(int sgi) const {
97  for (std::vector<Group>::const_iterator it = groups.begin(); it != groups.end(); ++it) {
98  if (it->sgi == sgi) {
99  return true;
100  }
101  }
102  return false;
103 }
104 
106 
107  // If both mgi are the same, yield all zeros for the interaction parameters
108  if (mgi1 == mgi2) {
110  ip.mgi1 = mgi1;
111  ip.mgi2 = mgi2;
112  ip.zero_out();
113  return ip;
114  }
115  for (std::vector<InteractionParameters>::const_iterator it = interaction_parameters.begin(); it != interaction_parameters.end(); ++it) {
116  if (it->mgi1 == mgi1 && it->mgi2 == mgi2) {
117  // Correct order, return it
118  return *it;
119  }
120  if (it->mgi2 == mgi1 && it->mgi1 == mgi2) {
121  // Backwards, swap the parameters
122  InteractionParameters ip = *it;
123  ip.swap();
124  return ip;
125  }
126  }
127  throw CoolProp::ValueError(format("Could not find interaction between pair mgi[%d]-mgi[%d]", static_cast<int>(mgi1), static_cast<int>(mgi2)));
128 }
129 
130 Component UNIFACParameterLibrary::get_component(const std::string& identifier, const std::string& value) const {
131  if (identifier == "name") {
132  for (std::vector<Component>::const_iterator it = components.begin(); it != components.end(); ++it) {
133  if (it->name == value) {
134  return *it;
135  }
136  }
137  }
138  throw CoolProp::ValueError(format("Could not find component: %s with identifier: %s", value.c_str(), identifier.c_str()));
139 }
140 
141 }; /* namespace UNIFACLibrary */
142 
143 #if defined(ENABLE_CATCH)
144 # include <catch2/catch_all.hpp>
145 
146 # include "UNIFAC.h"
147 
148 TEST_CASE("Check Poling example for UNIFAC", "[UNIFAC]") {
149  std::string acetone_pentane_groups =
150  "[{ \"Tc\": 508.1, \"acentric\": 0.3071, \"groups\": [ { \"count\": 1, \"sgi\": 1 }, {\"count\": 1, \"sgi\": 18 } ], \"molemass\": 0.44, "
151  "\"inchikey\": \"?????????????\", \"name\": \"Acetone\", \"pc\": 4700000.0, \"registry_number\": \"67-64-1\", \"userid\": \"\" }, { \"Tc\": "
152  "469.7000000000001, \"acentric\": 0.251, \"molemass\": 0.44, \"groups\": [ { \"count\": 2, \"sgi\": 1 }, { \"count\": 3, \"sgi\": 2 } ], "
153  "\"inchikey\": \"?????????????\", \"name\": \"n-Pentane\", \"pc\": 3370000.0, \"registry_number\": \"109-66-0\", \"userid\": \"\" } ]";
154  std::string groups = "[{\"Q_k\": 0.848, \"R_k\": 0.9011, \"maingroup_name\": \"CH2\", \"mgi\": 1, \"sgi\": 1, \"subgroup_name\": \"CH3\"},"
155  "{\"Q_k\": 0.540, \"R_k\": 0.6744, \"maingroup_name\": \"CH2\", \"mgi\": 1, \"sgi\": 2, \"subgroup_name\": \"CH2\"},"
156  "{\"Q_k\": 1.488, \"R_k\": 1.6724, \"maingroup_name\": \"CH2CO\", \"mgi\": 9, \"sgi\": 18, \"subgroup_name\": \"CH3CO\"}]";
157  std::string interactions =
158  "[{\"a_ij\": 476.4, \"a_ji\": 26.76, \"b_ij\": 0.0, \"b_ji\": 0.0, \"c_ij\": 0.0, \"c_ji\": 0.0, \"mgi1\": 1, \"mgi2\": 9}]";
159 
160  SECTION("Validate AC for acetone + n-pentane") {
162  CHECK_NOTHROW(lib.populate(groups, interactions, acetone_pentane_groups));
163  UNIFAC::UNIFACMixture mix(lib, 1.0);
164  std::vector<std::string> names;
165  names.push_back("Acetone");
166  names.push_back("n-Pentane");
167  mix.set_components("name", names);
168  mix.set_interaction_parameters();
169 
170  std::vector<double> z(2, 0.047);
171  z[1] = 1 - z[0];
172  mix.set_mole_fractions(z);
173  CHECK_NOTHROW(mix.set_temperature(307));
174 
175  double lngammaR0 = mix.ln_gamma_R(1.0 / 307, 0, 0);
176  double lngammaR1 = mix.ln_gamma_R(1.0 / 307, 1, 0);
177  CAPTURE(lngammaR0);
178  CAPTURE(lngammaR1);
179  CHECK(std::abs(lngammaR0 - 1.66) < 1e-2);
180  CHECK(std::abs(lngammaR1 - 5.68e-3) < 1e-3);
181 
182  std::vector<double> gamma(2);
183  mix.activity_coefficients(1.0 / 307, z, gamma);
184  CAPTURE(gamma[0]);
185  CAPTURE(gamma[1]);
186  CHECK(std::abs(gamma[0] - 4.99) < 1e-2);
187  CHECK(std::abs(gamma[1] - 1.005) < 1e-3);
188  };
189 };
190 
191 #endif