CoolProp  6.6.0
An open-source fluid property and humid air property database
VTPRBackend.cpp
Go to the documentation of this file.
1 
2 #include <string>
3 #include <fstream>
4 #include <sstream>
5 #include <iostream>
6 #include <cmath>
7 
8 #include "VTPRBackend.h"
9 #include "Configuration.h"
10 #include "Exceptions.h"
11 
13 
14 void CoolProp::VTPRBackend::setup(const std::vector<std::string>& names, bool generate_SatL_and_SatV) {
15 
16  R = get_config_double(R_U_CODATA);
17 
18  // Set the pure fluid flag
19  is_pure_or_pseudopure = (N == 1);
20 
21  // Reset the residual Helmholtz energy class
23 
24  // If pure, set the mole fractions to be unity
26  mole_fractions = std::vector<CoolPropDbl>(1, 1.0);
27  }
28 
29  // Now set the reducing function for the mixture
30  Reducing.reset(new ConstantReducingFunction(cubic->get_Tr(), cubic->get_rhor()));
31 
32  VTPRCubic* _cubic = static_cast<VTPRCubic*>(cubic.get());
33  _cubic->get_unifaq().set_components("name", names);
35 
36  // Store the fluid names
37  m_fluid_names = names;
38 
39  // Set the alpha function for the backend
41 
42  // Set the ideal-gas helmholtz energy based on the components in use;
44 
45  // Top-level class can hold copies of the base saturation classes,
46  // saturation classes cannot hold copies of the saturation classes
47  if (generate_SatL_and_SatV) {
48  bool SatLSatV = false;
49  SatL.reset(this->get_copy(SatLSatV));
50  SatL->specify_phase(iphase_liquid);
51  linked_states.push_back(SatL);
52  SatV.reset(this->get_copy(SatLSatV));
53  SatV->specify_phase(iphase_gas);
54  linked_states.push_back(SatV);
55 
57  std::vector<CoolPropDbl> z(1, 1.0);
59  SatL->set_mole_fractions(z);
60  SatV->set_mole_fractions(z);
61  }
62  }
63 
64  // Resize the vectors (including linked states)
65  resize(names.size());
66 }
67 
69 
70  VTPRCubic* _cubic = static_cast<VTPRCubic*>(cubic.get());
71  const std::vector<UNIFACLibrary::Component>& components = _cubic->get_unifaq().get_components();
72 
74  if (components.empty()) {
75  return;
76  }
77 
78  for (std::size_t i = 0; i < N; ++i) {
79  const std::string& alpha_type = components[i].alpha_type;
80  if (alpha_type != "default") {
81  const std::vector<double>& c = components[i].alpha_coeffs;
82  shared_ptr<AbstractCubicAlphaFunction> acaf;
83  if (alpha_type == "Twu") {
84  acaf.reset(new TwuAlphaFunction(get_cubic()->a0_ii(i), c[0], c[1], c[2], get_cubic()->get_Tr() / get_cubic()->get_Tc()[i]));
85  } else if (alpha_type == "MathiasCopeman" || alpha_type == "Mathias-Copeman") {
86  acaf.reset(
87  new MathiasCopemanAlphaFunction(get_cubic()->a0_ii(i), c[0], c[1], c[2], get_cubic()->get_Tr() / get_cubic()->get_Tc()[i]));
88  } else {
89  throw ValueError("alpha function is not understood");
90  }
91  cubic->set_alpha_function(i, acaf);
92  }
93  }
94 }
95 
97  double summer = 0;
98  for (unsigned int i = 0; i < N; ++i) {
99  summer += mole_fractions[i] * molemass[i];
100  }
101  return summer;
102 }
103 
104 void CoolProp::VTPRBackend::set_binary_interaction_double(const std::size_t i, const std::size_t j, const std::string& parameter,
105  const double value) {
106  // bound-check indices
107  if (i < 0 || i >= N) {
108  if (j < 0 || j >= N) {
109  throw ValueError(format("Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j, N-1));
110  } else {
111  throw ValueError(format("Index i [%d] is out of bounds. Must be between 0 and %d.", i, N-1));
112  }
113  } else if (j < 0 || j >= N) {
114  throw ValueError(format("Index j [%d] is out of bounds. Must be between 0 and %d.", j, N-1));
115  }
116  cubic->set_interaction_parameter(i, j, parameter, value);
117  for (std::vector<shared_ptr<HelmholtzEOSMixtureBackend>>::iterator it = linked_states.begin(); it != linked_states.end(); ++it) {
118  (*it)->set_binary_interaction_double(i, j, parameter, value);
119  }
120 };
121 
122 void CoolProp::VTPRBackend::set_Q_k(const size_t sgi, const double value) {
123  cubic->set_Q_k(sgi, value);
124 };
125 
126 double CoolProp::VTPRBackend::get_binary_interaction_double(const std::size_t i, const std::size_t j, const std::string& parameter) {
127  // bound-check indices
128  if (i < 0 || i >= N) {
129  if (j < 0 || j >= N) {
130  throw ValueError(format("Both indices i [%d] and j [%d] are out of bounds. Must be between 0 and %d.", i, j, N-1));
131  } else {
132  throw ValueError(format("Index i [%d] is out of bounds. Must be between 0 and %d.", i, N-1));
133  }
134  } else if (j < 0 || j >= N) {
135  throw ValueError(format("Index j [%d] is out of bounds. Must be between 0 and %d.", j, N-1));
136  }
137  return cubic->get_interaction_parameter(i, j, parameter);
138 };
139 
141  if (!lib.is_populated() || get_config_bool(VTPR_ALWAYS_RELOAD_LIBRARY)) {
142  std::string UNIFAC_path = get_config_string(VTPR_UNIFAC_PATH);
143  if (UNIFAC_path.empty()) {
144  throw ValueError("You must provide the path to the UNIFAC library files as VTPR_UNIFAC_PATH");
145  }
146  if (!(UNIFAC_path[UNIFAC_path.size() - 1] == '\\' || UNIFAC_path[UNIFAC_path.size() - 1] == '/')) {
147  throw ValueError("VTPR_UNIFAC_PATH must end with / or \\ character");
148  }
149  std::string group_path = UNIFAC_path + "group_data.json";
150  std::string groups = get_file_contents(group_path.c_str());
151  std::string interaction_path = UNIFAC_path + "interaction_parameters.json";
152  std::string interaction = get_file_contents(interaction_path.c_str());
153  std::string decomps_path = UNIFAC_path + "decompositions.json";
154  std::string decomps = get_file_contents(decomps_path.c_str());
155  lib.populate(groups, interaction, decomps);
156  }
157  return lib;
158 }
159 
161  //double slower = log(HelmholtzEOSMixtureBackend::calc_fugacity_coefficient(i));
162  VTPRCubic* _cubic = static_cast<VTPRCubic*>(cubic.get());
163  std::vector<double> here = _cubic->ln_fugacity_coefficient(mole_fractions, rhomolar(), p(), T());
164  return exp(here[i]);
165 }
166 
167 #ifdef ENABLE_CATCH
168 # include <catch2/catch_all.hpp>
169 
171 
172 using namespace CoolProp;
173 
174 TEST_CASE("VTPR test", "[VTPR]") {
175  shared_ptr<VTPRBackend> VTPR(new VTPRBackend(strsplit("Ethane&n-Propane&n-Butane", '&')));
176  std::vector<double> z(3);
177  z[0] = 0.1;
178  z[1] = 0.2;
179  z[2] = 0.7;
180  VTPR->set_mole_fractions(z);
181 
182  SECTION("dam_dxi") {
183  shared_ptr<AbstractCubic> cubic = VTPR->get_cubic();
184  double tau = 0.001, dz = 1e-6;
185  std::vector<double> zp = z, zm = z;
186  zp[0] += dz;
187  zm[0] -= dz;
188  if (!XN_INDEPENDENT) {
189  zp[2] -= dz;
190  zm[2] += dz;
191  }
192 
193  double dam_dxi_num = (cubic->am_term(tau, zp, 0) - cubic->am_term(tau, zm, 0)) / (2 * dz);
194  double dam_dxi_ana = cubic->d_am_term_dxi(tau, z, 0, 0, XN_INDEPENDENT);
195  double diff = dam_dxi_num - dam_dxi_ana;
196  CHECK(std::abs(diff) < 1e-6);
197  }
198 }
199 
200 #endif