CoolProp  4.2.5
An open-source fluid property and humid air property database
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Mixtures.cpp
Go to the documentation of this file.
1 
2 #define _CRT_SECURE_NO_WARNINGS
3 
4 #include "rapidjson_CoolProp.h"
5 
6 #include "Mixtures.h"
7 #include "Solvers.h"
8 #include "CPExceptions.h"
9 #include "MatrixMath.h"
10 #include "mixture_excess_JSON.h" // Loads the JSON code for the excess parameters, and makes a variable "std::string mixture_excess_JSON"
11 #include "mixture_reducing_JSON.h" // Loads the JSON code for the reducing parameters, and makes a variable "std::string mixture_reducing_JSON"
12 #include <numeric>
13 #include "CoolProp.h"
14 #include "Spline.h"
15 
16 #ifdef MPLSUPPORTED
17 #include "MPLPlot.h"
18 #endif
19 
20 static const bool use_cache = true;
21 
22 bool has_string_array_member(const rapidjson::Value& a, const char * member)
23 {
24  if(a.HasMember(member) && a[member].IsArray())
25  {
26  for (rapidjson::Value::ConstValueIterator itrC = a[member].Begin(); itrC != a[member].End(); ++itrC)
27  {
28  if (!itrC->IsString())
29  {
30  return false;
31  }
32  }
33  return true;
34  }
35  else
36  {
37  return false;
38  }
39 }
40 
41 std::vector<double> JSON_double_array(const rapidjson::Value& a)
42 {
43  std::vector<double> v;
44  for (rapidjson::Value::ConstValueIterator itrC = a.Begin(); itrC != a.End(); ++itrC)
45  {
46  if (itrC->IsInt())
47  {
48  v.push_back((double)itrC->GetInt());
49  }
50  else
51  {
52  v.push_back(itrC->GetDouble());
53  }
54  }
55  return v;
56 }
57 std::vector<std::string> JSON_string_array(const rapidjson::Value& a)
58 {
59  std::vector<std::string> v;
60  for (rapidjson::Value::ConstValueIterator itrC = a.Begin(); itrC != a.End(); ++itrC)
61  {
62  v.push_back(itrC->GetString());
63  }
64  return v;
65 }
66 bool match_CAS_entry(std::vector<std::string> CAS1, std::vector<std::string> CAS2, std::string FluidiCAS, std::string FluidjCAS)
67 {
68  for (unsigned int k = 0; k < CAS1.size(); k++)
69  {
70  if (
71  (!FluidiCAS.compare(CAS1[k]) && !FluidjCAS.compare(CAS2[k]))
72  ||
73  (!FluidjCAS.compare(CAS1[k]) && !FluidiCAS.compare(CAS2[k]))
74  ){ return true; }
75  }
76  return false;
77 }
78 std::map<std::string, double> Mixture::load_reducing_values(int i, int j)
79 {
80  // Make an output map that maps the necessary keys to the arrays of values
81  std::map<std::string, double > outputmap;
82 
83  std::string Model;
85 
86  JSON.Parse<0>(mixture_reducing_JSON.c_str());
87 
88  // Iterate over the entries for the excess term
89  for (rapidjson::Value::ConstValueIterator itr = JSON.Begin(); itr != JSON.End(); ++itr)
90  {
91  // Get the Model
92  if (itr->HasMember("Model") && (*itr)["Model"].IsString())
93  {
94  Model = (*itr)["Model"].GetString();
95  }
96  else
97  {
98  throw ValueError("Model not included for reducing term");
99  }
100 
101  // Get the coefficients
102  if (itr->HasMember("Coeffs") && (*itr)["Coeffs"].IsArray())
103  {
104  const rapidjson::Value& Coeffs = (*itr)["Coeffs"];
105 
106  // Get the coeffs
107  for (rapidjson::Value::ConstValueIterator itrC = Coeffs.Begin(); itrC != Coeffs.End(); ++itrC)
108  {
109  std::string Name1,Name2,CAS1,CAS2;
110  std::vector<std::string> Names1, Names2, CASs1, CASs2;
111 
112  if (itrC->HasMember("Name1") && (*itrC)["Name1"].IsString() && itrC->HasMember("Name2") && (*itrC)["Name2"].IsString())
113  {
114  Name1 = (*itrC)["Name1"].GetString();
115  Name2 = (*itrC)["Name2"].GetString();
116  CAS1 = (*itrC)["CAS1"].GetString();
117  CAS2 = (*itrC)["CAS2"].GetString();
118  }
119  else if (itrC->HasMember("Names1") && (*itrC)["Names1"].IsArray() && itrC->HasMember("Names2") && (*itrC)["Names2"].IsArray())
120  {
121  std::cout << format("Not currently supporting lists of components in excess terms\n").c_str();
122  continue;
123  }
124  std::string FluidiCAS = pFluids[i]->params.CAS, FluidjCAS = pFluids[j]->params.CAS;
125 
126  // Check if CAS codes match with either the i,j or j,i fluids
127  if (
128  (!(FluidiCAS.compare(CAS1)) && !(FluidjCAS.compare(CAS2)))
129  ||
130  (!(FluidjCAS.compare(CAS1)) && !(FluidiCAS.compare(CAS2)))
131  )
132  {
133  // See if it is the GERG-2008 formulation
134  if (!Model.compare("Kunz-JCED-2012"))
135  {
136  if (!pReducing)
137  {
138  // One reducing function for the entire mixture
140  }
141  if (!(FluidiCAS.compare(CAS1)) && !(FluidjCAS.compare(CAS2)))
142  {
143  outputmap.insert(std::pair<std::string, double >("betaT",(*itrC)["betaT"].GetDouble()));
144  outputmap.insert(std::pair<std::string, double >("betaV",(*itrC)["betaV"].GetDouble()));
145  }
146  else
147  {
148  outputmap.insert(std::pair<std::string, double >("betaT",1/(*itrC)["betaT"].GetDouble()));
149  outputmap.insert(std::pair<std::string, double >("betaV",1/(*itrC)["betaV"].GetDouble()));
150  }
151  outputmap.insert(std::pair<std::string, double >("gammaT",(*itrC)["gammaT"].GetDouble()));
152  outputmap.insert(std::pair<std::string, double >("gammaV",(*itrC)["gammaV"].GetDouble()));
153  outputmap.insert(std::pair<std::string, double >("F",(*itrC)["F"].GetDouble()));
154 
155  return outputmap;
156  }
157  else if (!Model.compare("Lemmon-JPCRD-2000") || !Model.compare("Lemmon-JPCRD-2004"))
158  {
159  if (!pReducing)
160  {
161  // One reducing function for the entire mixture
163  }
164  outputmap.insert(std::pair<std::string,double>("xi",(*itrC)["xi"].GetDouble()));
165  outputmap.insert(std::pair<std::string,double>("zeta",(*itrC)["zeta"].GetDouble()));
166  outputmap.insert(std::pair<std::string,double>("F",(*itrC)["F"].GetDouble()));
167  return outputmap;
168  }
169  else
170  {
171  throw ValueError(format("This model [%s] is not currently supported\n",Model.c_str()).c_str());
172  }
173  }
174  }
175  }
176  else
177  {
178  throw ValueError("Coeffs not included for reducing term");
179  }
180  }
181  return outputmap;
182 };
183 
184 void Mixture::load_excess_values(int i, int j)
185 {
186  // Make an output map that maps the necessary keys to the arrays of values
187  std::map<std::string,std::vector<double> > outputmap;
188 
189  std::string FluidiCAS = pFluids[i]->params.CAS,
190  FluidjCAS = pFluids[j]->params.CAS;
191 
192  std::string Model;
193  rapidjson::Document JSON;
194 
195  JSON.Parse<0>(mixture_excess_JSON.c_str());
196 
197  // Iterate over the entries for the excess term
198  for (rapidjson::Value::ConstValueIterator itr = JSON.Begin(); itr != JSON.End(); ++itr)
199  {
200  // Get the Model
201  if (itr->HasMember("Model") && (*itr)["Model"].IsString())
202  {
203  Model = (*itr)["Model"].GetString();
204  }
205  else
206  {
207  // It doesn't have the term Model
208  throw ValueError("Model not included for excess term");
209  }
210 
211  // Get the coefficients
212  if (itr->HasMember("Coeffs") && (*itr)["Coeffs"].IsArray())
213  {
214  const rapidjson::Value& Coeffs = (*itr)["Coeffs"];
215 
216  // Get the coeffs
217  for (rapidjson::Value::ConstValueIterator itrC = Coeffs.Begin(); itrC != Coeffs.End(); ++itrC)
218  {
219  std::vector<std::string> Names1, Names2, CASs1, CASs2;
220 
221  if (itrC->HasMember("Name1") && (*itrC)["Name1"].IsString() && itrC->HasMember("Name2") && (*itrC)["Name2"].IsString())
222  {
223  Names1 = std::vector<std::string>(1, (*itrC)["Name1"].GetString());
224  Names2 = std::vector<std::string>(1, (*itrC)["Name2"].GetString());
225  CASs1 = std::vector<std::string>(1, (*itrC)["CAS1"].GetString());
226  CASs2 = std::vector<std::string>(1, (*itrC)["CAS2"].GetString());
227  }
228  else if (has_string_array_member((*itrC), "Name1") && has_string_array_member((*itrC), "Name2")
229  && has_string_array_member((*itrC), "CAS1") && has_string_array_member((*itrC), "CAS2"))
230  {
231  Names1 = JSON_string_array((*itrC)["Name1"]);
232  Names2 = JSON_string_array((*itrC)["Name2"]);
233  CASs1 = JSON_string_array((*itrC)["CAS1"]);
234  CASs2 = JSON_string_array((*itrC)["CAS2"]);
235  }
236 
237  // Check if CAS codes match with either the i,j or j,i fluids
238  if (match_CAS_entry(CASs1,CASs2,FluidiCAS,FluidjCAS))
239  {
240  // See if it is the GERG-2008 formulation
241  if (!Model.compare("Kunz-JCED-2012"))
242  {
243  // Create an instance for the departure function for GERG formulation
245 
246  const rapidjson::Value& _n = (*itrC)["n"];
247  outputmap.insert(std::pair<std::string,std::vector<double> >("n",JSON_double_array(_n)));
248  const rapidjson::Value& _t = (*itrC)["t"];
249  outputmap.insert(std::pair<std::string,std::vector<double> >("t",JSON_double_array(_t)));
250  const rapidjson::Value& _d = (*itrC)["d"];
251  outputmap.insert(std::pair<std::string,std::vector<double> >("d",JSON_double_array(_d)));
252  const rapidjson::Value& _eta = (*itrC)["eta"];
253  outputmap.insert(std::pair<std::string,std::vector<double> >("eta",JSON_double_array(_eta)));
254  const rapidjson::Value& _epsilon = (*itrC)["epsilon"];
255  outputmap.insert(std::pair<std::string,std::vector<double> >("epsilon",JSON_double_array(_epsilon)));
256  const rapidjson::Value& _beta = (*itrC)["beta"];
257  outputmap.insert(std::pair<std::string,std::vector<double> >("beta",JSON_double_array(_beta)));
258  const rapidjson::Value& _gamma = (*itrC)["gamma"];
259  outputmap.insert(std::pair<std::string,std::vector<double> >("gamma",JSON_double_array(_gamma)));
260 
261  // Set the variables in the class
262  pExcess->DepartureFunctionMatrix[i][j]->set_coeffs_from_map(outputmap);
263  return;
264  }
265  else if (!Model.compare("Lemmon-JPCRD-2004"))
266  {
267  // Create an instance for the departure function for the HFC mixtures
269 
270  const rapidjson::Value& _n = (*itrC)["n"];
271  outputmap.insert(std::pair<std::string,std::vector<double> >("n",JSON_double_array(_n)));
272  const rapidjson::Value& _t = (*itrC)["t"];
273  outputmap.insert(std::pair<std::string,std::vector<double> >("t",JSON_double_array(_t)));
274  const rapidjson::Value& _d = (*itrC)["d"];
275  outputmap.insert(std::pair<std::string,std::vector<double> >("d",JSON_double_array(_d)));
276  const rapidjson::Value& _l = (*itrC)["l"];
277  outputmap.insert(std::pair<std::string,std::vector<double> >("l",JSON_double_array(_l)));
278 
279  // Set the variables in the class
280  pExcess->DepartureFunctionMatrix[i][j]->set_coeffs_from_map(outputmap);
281  return;
282  }
283  else
284  {
285  throw ValueError(format("This model [%s] is not currently supported\n",Model.c_str()).c_str());
286  }
287  }
288  }
289  }
290  else
291  {
292  throw ValueError("Coeffs not included for excess term");
293  }
294  }
295  throw ValueError("No excess parameters loaded for this binary pair");
296 };
297 
298 void normalize_vector(std::vector<double> &x)
299 {
300  double sumx = std::accumulate( x.begin(), x.end(), (double)0 );
301  // Normalize the components
302  for (unsigned int i = 0; i < x.size(); i++)
303  {
304  x[i] /= sumx;
305  }
306 };
307 
309 
310 double Mixture::Rbar(const std::vector<double> &x)
311 {
312  double R = 0;
313  for (unsigned int i = 0; i < N; i++)
314  {
315  R += x[i]*pFluids[i]->params.R_u;
316  }
317  return R;
318 }
319 Mixture::Mixture(std::vector<Fluid *> pFluids)
320 {
321  // Make a copy of the list of pointers to fluids that compose this mixture
322  this->pFluids = pFluids;
323  this->N = pFluids.size();
324 
325  // Finish the initalization
326  this->initialize();
327 
328 }
329 Mixture::Mixture(std::string FluidsString)
330 {
331  // Split at the '|'
332  std::vector<std::string> fluids = strsplit(FluidsString,'|');
333 
334  // Number of components
335  this->N = fluids.size();
336 
337  // Resize the pointers
338  pFluids.resize(this->N);
339 
340  // Get all the pointers to the components
341  for (unsigned int i = 0; i < fluids.size(); i++)
342  {
343  pFluids[i] = get_fluid(get_Fluid_index(fluids[i]));
344  }
345 
346  // Finish the initalization
347  this->initialize();
348 }
349 
351 {
352  // Give child classes a pointer to this class
353  SS.Mix = this;
354  NRVLE.Mix = this;
355  Envelope.Mix = this;
356 
357  STLMatrix F;
358  F.resize(pFluids.size(),std::vector<double>(pFluids.size(),1.0));
359 
360  NRVLE.resize(this->N);
361 
362  // Reset the reducing parameter pointer
363  pReducing = NULL;
364 
365  // One Residual Ideal Mixture term
367 
368  // A matrix of departure functions for each binary pair
369  pExcess = new ExcessTerm(pFluids.size());
370 
371  for (unsigned int i = 0; i < pFluids.size(); i++)
372  {
373  for (unsigned int j = 0; j < pFluids.size(); j++)
374  {
375  if (i != j)
376  {
377  std::map<std::string, double > reducing_map = load_reducing_values(i, j);
378  load_excess_values(i, j);
379  pReducing->set_coeffs_from_map(i, j, reducing_map);
380  pExcess->F[i][j] = reducing_map.find("F")->second;
381  }
382  }
383  }
384 
389 }
390 
392 {
393  std::vector<double> x,y,z(2, 0.5);
394 
395  //Envelope.build(100000,z);
396 
397  z[0] = 0.3;
398  z[1] = 1-z[0];
399 
400  double _Tsat = saturation_p(0, 440000, z, x, y);
401 
402  double Tr = pReducing->Tr(z); //[K]
403  double rhorbar = pReducing->rhorbar(z); //[mol/m^3]
404 
405  double T = 145; // [K]
406  double rhobar = 4; // [mol/m^3]; to convert from mol/L, multiply by 1000
407  double tau = Tr/T;
408  double delta = rhobar/rhorbar;
409  //double dtau_dT = -Tr/T/T;
410 
411  //double _dphir_dDelta = dphir_dDelta(tau, delta, &z);
412  //double p = Rbar(&z)*rhobar*T*(1 + delta*_dphir_dDelta)/1000; //[kPa]
413 
414 
415  //check();
416  //time_t t1,t2;
417  //unsigned int N = 100;
418  //double TTE = 0;
419  //t1 = clock();
420  //for (unsigned int i = 0; i < N; i++)
421  //{
422  // TTE += saturation_p(TYPE_BUBBLEPOINT,10000,z,x,y);
423  // //TTE += Props("T",'P',10,'Q',0,"REFPROP-MIX:Methane[0.5]&Ethane[0.5]");
424  //}
425  //t2 = clock();
426  //printf("val %g elapsed time/call %g us\n", TTE/(double)N, (double)(t2-t1)/(double)CLOCKS_PER_SEC/N*1e6);
427 // return;
428  //p = 595.61824;
429 
430  //TpzFlash(T, p, z, &rhobar, &x, &y);
431 
432  //double rhor = pReducing->rhorbar(&z);
433 
434  double Tsat;
435 
436  for (double psat = 1e6; psat < 6.9e6; psat += 1e6)
437  {
438  std::cout << "psat: " << psat << " Pa" << std::endl;
439  for (double x0 = 0; x0 <= 1.000000000000001; x0 += 0.01)
440  {
441  z[0] = x0; z[1] = 1-x0;
442  Tsat = saturation_p(0, psat, z, x, y);
443  std::cout << format("%g %g %0.9g %0.9g",x0,Tsat,y[0],y[1]).c_str();
444  Tsat = saturation_p(1, psat, z, x, y);
445  std::cout << format(" %g %0.9g %0.9g",Tsat,x[0],x[1]).c_str() ;
446  std::cout << std::endl;
447  }
448  }
449 
450  /*double x0 = 0.5;
451  z[0] = x0; z[1] = 1-x0;
452  double TL, TV;
453  for (double p = 100; p <= 1e9; p *= 1.5)
454  {
455  TL = saturation_p(TYPE_BUBBLEPOINT, p, z, x, y);
456  TV = saturation_p(TYPE_DEWPOINT, p, z, x, y);
457  if (!ValidNumber(Tsat)){break;}
458  std::cout << format("%g %g %g\n",TL,TV,p).c_str();
459  }*/
460 }
461 
463 {
464  std::vector<double> z(2, 0.5);
465 
466  double tol = 1e-10; // relative tolerance
467  z[0] = 0.4;
468  z[1] = 1-z[0];
469 
470  double Tr = pReducing->Tr(z);
471  double Tr_RP91 = 574.10640748981632; // [K]
472  if (fabs(Tr/Tr_RP91-1) > tol){throw ValueError();}
473 
474  double rhorbar = pReducing->rhorbar(z);
475  double rhorbar_RP91 = 11090.627577544581; //[mol/m^3]
476  if (fabs(rhorbar/rhorbar_RP91-1) > tol){throw ValueError();}
477 
478  double T = 500; // [K]
479  double rhobar = 868.40163264165199; // [mol/m^3]; to convert from mol/L, multiply by 1000
480 
481  double tau = Tr/T;
482  double delta = rhobar/rhorbar;
483 
484  double RT = Rbar(z)*T;
485  double p = rhobar*RT*(1+delta*dphir_dDelta(tau, delta,z));
486  double p_RP91 = 3011336.2097271665;
487  if (fabs(p/p_RP91-1) > tol){throw ValueError();}
488 
489  double dtdn0 = pReducing->ndTrdni__constnj(z,0);
490  double dtdn0_RP91 = -80.606224987885071;
491  if (fabs(dtdn0/dtdn0_RP91-1) > tol){throw ValueError();}
492 
493  double dtdn1 = pReducing->ndTrdni__constnj(z,1);
494  double dtdn1_RP91 = 53.737483325256562;
495  if (fabs(dtdn1/dtdn1_RP91-1) > tol){throw ValueError();}
496 
497  double drhodn0 = pReducing->ndrhorbardni__constnj(z,0);
498  double drhodn0_RP91 = -7259.8385028178765;
499  if (fabs(drhodn0/drhodn0_RP91-1) > tol){throw ValueError();}
500 
501  double drhodn1 = pReducing->ndrhorbardni__constnj(z,1);
502  double drhodn1_RP91 = 4839.8923352119168;
503  if (fabs(drhodn1/drhodn1_RP91-1) > tol){throw ValueError();}
504 
505  double ddrdxn00 = pReducing->d_ndrhorbardni_dxj__constxi(z,0,0);
506  double ddrdxn00_RP91 = 57050.801427407002;
507  if (fabs(ddrdxn00/ddrdxn00_RP91-1) > tol){throw ValueError();}
508 
509  double ddrdxn01 = pReducing->d_ndrhorbardni_dxj__constxi(z,0,1);
510  double ddrdxn01_RP91 = 35234.083487633299;
511  if (fabs(ddrdxn01/ddrdxn01_RP91-1) > tol){throw ValueError();}
512 
513  double ddrdxn10 = pReducing->d_ndrhorbardni_dxj__constxi(z,1,0);
514  double ddrdxn10_RP91 = 11034.621811573714;
515  if (fabs(ddrdxn10/ddrdxn10_RP91-1) > tol){throw ValueError();}
516 
517  double ddrdxn11 = pReducing->d_ndrhorbardni_dxj__constxi(z,1,1);
518  double ddrdxn11_RP91 = 5412.8823747065340;
519  if (fabs(ddrdxn11/ddrdxn11_RP91-1) > tol){throw ValueError();}
520 
521  double dtrdxn00 = pReducing->d_ndTrdni_dxj__constxi(z,0,0);
522  double dtrdxn00_RP91 = -1078.6599487910798;
523  if (fabs(dtrdxn00/dtrdxn00_RP91-1) > tol){throw ValueError();}
524 
525  double dtrdxn01 = pReducing->d_ndTrdni_dxj__constxi(z,0,1);
526  double dtrdxn01_RP91 = -1328.9251007518092;
527  if (fabs(dtrdxn01/dtrdxn01_RP91-1) > tol){throw ValueError();}
528 
529  double dtrdxn10 = pReducing->d_ndTrdni_dxj__constxi(z,1,0);
530  double dtrdxn10_RP91 = -1060.2376841255259;
531  if (fabs(dtrdxn10/dtrdxn10_RP91-1) > tol){throw ValueError();}
532 
533  double dtrdxn11 = pReducing->d_ndTrdni_dxj__constxi(z,1,1);
534  double dtrdxn11_RP91 = -1117.3004300069424;
535  if (fabs(dtrdxn11/dtrdxn11_RP91-1) > tol){throw ValueError();}
536 
537  /*double dadxi0 = this->dphir_dxi(tau, delta, z, 0);
538  double dadxi0_RP91 = -1.66733159546361936E-003;
539  if (fabs(dadxi0/dadxi0_RP91-1) > tol){throw ValueError();}
540 
541  double dadxi1 = this->dphir_dxi(tau, delta, z, 1);
542  double dadxi1_RP91 = -1.82138497681156902E-003;
543  if (fabs(dadxi1/dadxi1_RP91-1) > tol){throw ValueError();}*/
544 
545  double daddx0 = this->d2phir_dxi_dDelta(tau,delta,z,0);
546  double daddx0_RP91 = -1.9898117177651518;
547  if (fabs(daddx0/daddx0_RP91-1) > tol){throw ValueError();}
548 
549  double daddx1 = this->d2phir_dxi_dDelta(tau,delta,z,1);
550  double daddx1_RP91 = -2.1704856931980134;
551  if (fabs(daddx1/daddx1_RP91-1) > tol){throw ValueError();}
552 
553  double dadtx0 = this->d2phir_dxi_dTau(tau,delta,z,0);
554  double dadtx0_RP91 = -0.54706966169729132;
555  if (fabs(dadtx0/dadtx0_RP91-1) > tol){throw ValueError();}
556 
557  double dadtx1 = this->d2phir_dxi_dTau(tau,delta,z,1);
558  double dadtx1_RP91 = -0.45648092575441646;
559  if (fabs(dadtx1/dadtx1_RP91-1) > tol){throw ValueError();}
560 
561  double dadn0 = this->ndphir_dni__constT_V_nj(tau, delta, z, 0);
562  double dadn0_RP91 = -0.18827619536857490;
563  if (fabs(dadn0/dadn0_RP91-1) > tol){throw ValueError();}
564 
565  double dadn1 = this->ndphir_dni__constT_V_nj(tau, delta, z, 1);
566  double dadn1_RP91 = -0.15092181712014577;
567  if (fabs(dadn1/dadn1_RP91-1) > tol){throw ValueError();}
568 
569  double dpdn0 = ndpdni__constT_V_nj(tau, delta, z, 0);
570  double dpdn0_RP91 = 2359472.7345531628;
571  if (fabs(dpdn0/dpdn0_RP91-1) > tol){throw ValueError();}
572 
573  double dpdn1 = ndpdni__constT_V_nj(tau, delta, z, 1);
574  double dpdn1_RP91 = 2459536.5646813584;
575  if (fabs(dpdn1/dpdn1_RP91-1) > tol){throw ValueError();}
576 
577  double vhat0 = partial_molar_volume(tau, delta, z, 0);
578  double vhat0_RP91 = 1.1229663043954532/1000;
579  if (fabs(vhat0/vhat0_RP91-1) > tol){throw ValueError();}
580 
581  double vhat1 = partial_molar_volume(tau, delta, z, 1);
582  double vhat1_RP91 = 1.1705906349830217/1000;
583  if (fabs(vhat1/vhat1_RP91-1) > tol){throw ValueError();}
584 
585  /*double d2adbn0 = d2nphir_dni_dT(tau, delta, z, 0);
586  double d2adbn0_RP91 = 2.91400791470335643E-005;
587  if (fabs(d2adbn0/d2adbn0_RP91-1) > tol){throw ValueError();}
588 
589  double d2adbn1 = d2nphir_dni_dT(tau, delta, z, 1);
590  double d2adbn1_RP91 = 6.58714026367381391E-005;
591  if (fabs(d2adbn1/d2adbn1_RP91-1) > tol){throw ValueError();}*/
592 
593  double dphidT0 = dln_fugacity_coefficient_dT__constp_n(tau,delta,z,0);
594  double dphidT0_RP91 = 1.80275151505261211E-003;
595  if (fabs(dphidT0/dphidT0_RP91-1) > tol){throw ValueError();}
596 
597  double dphidT1 = dln_fugacity_coefficient_dT__constp_n(tau,delta,z,1);
598  double dphidT1_RP91 = 1.24216502708919410E-003;
599  if (fabs(dphidT1/dphidT1_RP91-1) > tol){throw ValueError();}
600 
601  double dphidP0 = dln_fugacity_coefficient_dp__constT_n(tau,delta,z,0);
602  double dphidP0_RP91 = -6.19532350116346726E-005/1000;
603  if (fabs(dphidP0/dphidP0_RP91-1) > tol){throw ValueError();}
604 
605  double dphidP1 = dln_fugacity_coefficient_dp__constT_n(tau,delta,z,1);
606  double dphidP1_RP91 = -5.04973839435411730E-005/1000;
607  if (fabs(dphidP1/dphidP1_RP91-1) > tol){throw ValueError();}
608 
609  double dadxij00 = d2phirdxidxj(tau, delta, z, 0, 0);
610  double dadxij00_RP91 = 0.0;
611  if (fabs(dadxij00-dadxij00_RP91) > tol){throw ValueError();}
612 
613  double dadxij01 = d2phirdxidxj(tau, delta, z, 0, 1);
614  double dadxij01_RP91 = 2.95156019175951646E-003;
615  if (fabs(dadxij01/dadxij01_RP91-1) > tol){throw ValueError();}
616 
617  double dadxij10 = d2phirdxidxj(tau, delta, z, 1, 0);
618  double dadxij10_RP91 = 2.95156019175951646E-003;
619  if (fabs(dadxij10/dadxij10_RP91-1) > tol){throw ValueError();}
620 
621  double dadxij11 = d2phirdxidxj(tau, delta, z, 1, 1);
622  double dadxij11_RP91 = 0.0;
623  if (fabs(dadxij11-dadxij11_RP91) > tol){throw ValueError();}
624 
625  double d2adxn00 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,0,0);
626  double d2adxn00_RP91 = 1.4701046408163372;
627  if (fabs(d2adxn00-d2adxn00_RP91) > tol){throw ValueError();}
628 
629  double d2adxn01 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,0,1);
630  double d2adxn01_RP91 = 1.4673267962070480;
631  if (fabs(d2adxn01/d2adxn01_RP91-1) > tol){throw ValueError();}
632 
633  double d2adxn10 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,1,0);
634  double d2adxn10_RP91 = 1.5168952199179448;
635  if (fabs(d2adxn10/d2adxn10_RP91-1) > tol){throw ValueError();}
636 
637  double d2adxn11 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,1,1);
638  double d2adxn11_RP91 = 1.4329117162994811;
639  if (fabs(d2adxn11/d2adxn11_RP91-1) > tol){throw ValueError();}
640 
641  double d2addn0 = d_ndphirdni_dDelta(tau,delta,z,0);
642  double d2addn0_RP91 = -2.3060567022876386;
643  if (fabs(d2addn0/d2addn0_RP91-1) > tol){throw ValueError();}
644 
645  double d2addn1 = d_ndphirdni_dDelta(tau,delta,z,1);
646  double d2addn1_RP91 = -1.9520671401909093;
647  if (fabs(d2addn1/d2addn1_RP91-1) > tol){throw ValueError();}
648 
649  double d2adtn0 = d_ndphirdni_dTau(tau,delta,z,0);
650  double d2adtn0_RP91 = -0.62562519155517959;
651  if (fabs(d2adtn0/d2adtn0_RP91-1) > tol){throw ValueError();}
652 
653  double d2adtn1 = d_ndphirdni_dTau(tau,delta,z,1);
654  double d2adtn1_RP91 = -0.43264230263327769;
655  if (fabs(d2adtn1/d2adtn1_RP91-1) > tol){throw ValueError();}
656 
657  double d2ann00 = nd2nphirdnidnj__constT_V(tau, delta, z, 0, 0);
658  double d2dnn00_RP91 = -0.38451299457845400;
659  if (fabs(d2ann00/d2dnn00_RP91-1) > tol){throw ValueError();}
660 
661  double d2ann01 = nd2nphirdnidnj__constT_V(tau, delta, z, 0, 1);
662  double d2dnn01_RP91 = -0.32103958765767326;
663  if (fabs(d2ann01/d2dnn01_RP91-1) > tol){throw ValueError();}
664 
665  double d2ann10 = nd2nphirdnidnj__constT_V(tau, delta, z, 1, 0);
666  double d2dnn10_RP91 = -0.32103958765767304;
667  if (fabs(d2ann10/d2dnn10_RP91-1) > tol){throw ValueError();}
668 
669  double d2ann11 = nd2nphirdnidnj__constT_V(tau, delta, z, 1, 1);
670  double d2dnn11_RP91 = -0.31715926219249480;
671  if (fabs(d2ann11/d2dnn11_RP91-1) > tol){throw ValueError();}
672 
673  double dphidnj00 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,0,0);
674  double dphidnj00_RP91 = -2.18661832047073457E-002;
675  if (fabs(dphidnj00/dphidnj00_RP91-1) > tol){throw ValueError();}
676 
677  double dphidnj01 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,0,1);
678  double dphidnj01_RP91 = 1.45774554698049341E-002;
679  if (fabs(dphidnj01/dphidnj01_RP91-1) > tol){throw ValueError();}
680 
681  double dphidnj10 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,1,0);
682  double dphidnj10_RP91 = 1.45774554698051562E-002;
683  if (fabs(dphidnj10/dphidnj10_RP91-1) > tol){throw ValueError();}
684 
685  double dphidnj11 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,1,1);
686  double dphidnj11_RP91 = -9.71830364653669676E-003;
687  if (fabs(dphidnj11/dphidnj11_RP91-1) > tol){throw ValueError();}
688 
689 }
690 
692 {
693  std::vector<double> z(2, 0.5);
694 
695  double tol = 1e-10; // relative tolerance
696  z[0] = 0.5;
697  z[1] = 1-z[0];
698 
699  double Tr = pReducing->Tr(z);
700  double Tr_RP91 = 250.57185990876351; // [K]
701  if (fabs(Tr/Tr_RP91-1) > tol){throw ValueError();}
702 
703  double rhorbar = pReducing->rhorbar(z);
704  double rhorbar_RP91 = 8205.7858837320694; //[mol/m^3]
705  if (fabs(rhorbar/rhorbar_RP91-1) > tol){throw ValueError();}
706 
707  double T = 145; // [K]
708  double rhobar = 4; // [mol/m^3]; to convert from mol/L, multiply by 1000
709 
710  double tau = Tr/T;
711  double delta = rhobar/rhorbar;
712 
713  double RT = Rbar(z)*T;
714  double p = rhobar*RT*(1+delta*dphir_dDelta(tau, delta,z));
715  double p_RP91 = 4814.1558068139991;
716  if (fabs(p/p_RP91-1) > tol){throw ValueError();}
717 
718  double dtdn0 = pReducing->ndTrdni__constnj(z,0);
719  double dtdn0_RP91 = -56.914351037292874;
720  if (fabs(dtdn0/dtdn0_RP91-1) > tol){throw ValueError();}
721 
722  double dtdn1 = pReducing->ndTrdni__constnj(z,1);
723  double dtdn1_RP91 = 56.914351037292874;
724  if (fabs(dtdn1/dtdn1_RP91-1) > tol){throw ValueError();}
725 
726  double drhodn0 = pReducing->ndrhorbardni__constnj(z,0);
727  double drhodn0_RP91 = 1579.4307575322835;
728  if (fabs(drhodn0/drhodn0_RP91-1) > tol){throw ValueError();}
729 
730  double drhodn1 = pReducing->ndrhorbardni__constnj(z,1);
731  double drhodn1_RP91 = -1579.4307575322843;
732  if (fabs(drhodn1/drhodn1_RP91-1) > tol){throw ValueError();}
733 
734  double ddrdxn00 = pReducing->d_ndrhorbardni_dxj__constxi(z,0,0);
735  double ddrdxn00_RP91 = 10652.242638037194;
736  if (fabs(ddrdxn00/ddrdxn00_RP91-1) > tol){throw ValueError();}
737 
738  double ddrdxn01 = pReducing->d_ndrhorbardni_dxj__constxi(z,0,1);
739  double ddrdxn01_RP91 = 12694.316351697381;
740  if (fabs(ddrdxn01/ddrdxn01_RP91-1) > tol){throw ValueError();}
741 
742  double ddrdxn10 = pReducing->d_ndrhorbardni_dxj__constxi(z,1,0);
743  double ddrdxn10_RP91 = 19012.039381826526;
744  if (fabs(ddrdxn10/ddrdxn10_RP91-1) > tol){throw ValueError();}
745 
746  double ddrdxn11 = pReducing->d_ndrhorbardni_dxj__constxi(z,1,1);
747  double ddrdxn11_RP91 = 23287.688698295469;
748  if (fabs(ddrdxn11/ddrdxn11_RP91-1) > tol){throw ValueError();}
749 
750  double dtrdxn00 = pReducing->d_ndTrdni_dxj__constxi(z,0,0);
751  double dtrdxn00_RP91 = -506.39802892344619;
752  if (fabs(dtrdxn00/dtrdxn00_RP91-1) > tol){throw ValueError();}
753 
754  double dtrdxn01 = pReducing->d_ndTrdni_dxj__constxi(z,0,1);
755  double dtrdxn01_RP91 = -609.71811278619361;
756  if (fabs(dtrdxn01/dtrdxn01_RP91-1) > tol){throw ValueError();}
757 
758  double dtrdxn10 = pReducing->d_ndTrdni_dxj__constxi(z,1,0);
759  double dtrdxn10_RP91 = -382.06070863702217;
760  if (fabs(dtrdxn10/dtrdxn10_RP91-1) > tol){throw ValueError();}
761 
762  double dtrdxn11 = pReducing->d_ndTrdni_dxj__constxi(z,1,1);
763  double dtrdxn11_RP91 = -506.39802892344630;
764  if (fabs(dtrdxn11/dtrdxn11_RP91-1) > tol){throw ValueError();}
765 
766  double dadxi0 = this->dphir_dxi(tau, delta, z, 0);
767  double dadxi0_RP91 = -1.66733159546361936E-003;
768  if (fabs(dadxi0/dadxi0_RP91-1) > tol){throw ValueError();}
769 
770  double dadxi1 = this->dphir_dxi(tau, delta, z, 1);
771  double dadxi1_RP91 = -1.82138497681156902E-003;
772  if (fabs(dadxi1/dadxi1_RP91-1) > tol){throw ValueError();}
773 
774  double daddx0 = this->d2phir_dxi_dDelta(tau,delta,z,0);
775  double daddx0_RP91 = -3.4250061506157587;
776  if (fabs(daddx0/daddx0_RP91-1) > tol){throw ValueError();}
777 
778  double dadtx0 = this->d2phir_dxi_dTau(tau,delta,z,0);
779  double dadtx0_RP91 = -1.94597122635832131E-003;
780  if (fabs(dadtx0/dadtx0_RP91-1) > tol){throw ValueError();}
781 
782  double daddx1 = this->d2phir_dxi_dDelta(tau,delta,z,1);
783  double daddx1_RP91 = -3.7448162669516916;
784  if (fabs(daddx1/daddx1_RP91-1) > tol){throw ValueError();}
785 
786  double dadtx1 = this->d2phir_dxi_dTau(tau,delta,z,1);
787  double dadtx1_RP91 = -2.15974774776696646E-003;
788  if (fabs(dadtx1/dadtx1_RP91-1) > tol){throw ValueError();}
789 
790  double dadn0 = this->ndphir_dni__constT_V_nj(tau, delta, z, 0);
791  double dadn0_RP91 = -5.24342982584834368E-004;
792  if (fabs(dadn0/dadn0_RP91-1) > tol){throw ValueError();}
793 
794  double dadn1 = this->ndphir_dni__constT_V_nj(tau, delta, z, 1);
795  double dadn1_RP91 = -2.89676062124885614E-003;
796  if (fabs(dadn1/dadn1_RP91-1) > tol){throw ValueError();}
797 
798  double dpdn0 = ndpdni__constT_V_nj(tau, delta, z, 0);
799  double dpdn0_RP91 = 4811.6359520642318;
800  if (fabs(dpdn0/dpdn0_RP91-1) > tol){throw ValueError();}
801 
802  double dpdn1 = ndpdni__constT_V_nj(tau, delta, z, 1);
803  double dpdn1_RP91 = 4800.1319544625067;
804  if (fabs(dpdn1/dpdn1_RP91-1) > tol){throw ValueError();}
805 
806  double vhat0 = partial_molar_volume(tau, delta, z, 0);
807  double vhat0_RP91 = 0.25029921648425145;
808  if (fabs(vhat0/vhat0_RP91-1) > tol){throw ValueError();}
809 
810  double vhat1 = partial_molar_volume(tau, delta, z, 1);
811  double vhat1_RP91 = 0.24970078351574867;
812  if (fabs(vhat1/vhat1_RP91-1) > tol){throw ValueError();}
813 
814  double d2adbn0 = d2nphir_dni_dT(tau, delta, z, 0);
815  double d2adbn0_RP91 = 2.91400791470335643E-005;
816  if (fabs(d2adbn0/d2adbn0_RP91-1) > tol){throw ValueError();}
817 
818  double d2adbn1 = d2nphir_dni_dT(tau, delta, z, 1);
819  double d2adbn1_RP91 = 6.58714026367381391E-005;
820  if (fabs(d2adbn1/d2adbn1_RP91-1) > tol){throw ValueError();}
821 
822  double dphidT0 = dln_fugacity_coefficient_dT__constp_n(tau,delta,z,0);
823  double dphidT0_RP91 = 8.84377505112714235E-006;
824  if (fabs(dphidT0/dphidT0_RP91-1) > tol){throw ValueError();}
825 
826  double dphidT1 = dln_fugacity_coefficient_dT__constp_n(tau,delta,z,1);
827  double dphidT1_RP91 = 6.21123852185909847E-005;
828  if (fabs(dphidT1/dphidT1_RP91-1) > tol){throw ValueError();}
829 
830  double dphidP0 = dln_fugacity_coefficient_dp__constT_n(tau,delta,z,0);
831  double dphidP0_RP91 = -1.07128474189810419E-007;
832  if (fabs(dphidP0/dphidP0_RP91-1) > tol){throw ValueError();}
833 
834  double dphidP1 = dln_fugacity_coefficient_dp__constT_n(tau,delta,z,1);
835  double dphidP1_RP91 = -6.03505693277411881E-007;
836  if (fabs(dphidP1/dphidP1_RP91-1) > tol){throw ValueError();}
837 
838  double dadxij00 = d2phirdxidxj(tau, delta, z, 0, 0);
839  double dadxij00_RP91 = 0.0;
840  if (fabs(dadxij00-dadxij00_RP91) > tol){throw ValueError();}
841 
842  double dadxij01 = d2phirdxidxj(tau, delta, z, 0, 1);
843  double dadxij01_RP91 = -1.44900341276804124E-004;
844  if (fabs(dadxij01/dadxij01_RP91-1) > tol){throw ValueError();}
845 
846  double dadxij10 = d2phirdxidxj(tau, delta, z, 1, 0);
847  double dadxij10_RP91 = -1.44900341276804124E-004;
848  if (fabs(dadxij10/dadxij10_RP91-1) > tol){throw ValueError();}
849 
850  double dadxij11 = d2phirdxidxj(tau, delta, z, 1, 1);
851  double dadxij11_RP91 = 0.0;
852  if (fabs(dadxij11-dadxij11_RP91) > tol){throw ValueError();}
853 
854  double d2adxn00 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,0,0);
855  double d2adxn00_RP91 = 9.52786141739760811E-003;
856  if (fabs(d2adxn00-d2adxn00_RP91) > tol){throw ValueError();}
857 
858  double d2adxn01 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,0,1);
859  double d2adxn01_RP91 = 1.11090273394917772E-002;
860  if (fabs(d2adxn01/d2adxn01_RP91-1) > tol){throw ValueError();}
861 
862  double d2adxn10 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,1,0);
863  double d2adxn10_RP91 = 8.82661064281056729E-003;
864  if (fabs(d2adxn10/d2adxn10_RP91-1) > tol){throw ValueError();}
865 
866  double d2adxn11 = d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,z,1,1);
867  double d2adxn11_RP91 = 1.16784901260031035E-002;
868  if (fabs(d2adxn11/d2adxn11_RP91-1) > tol){throw ValueError();}
869 
870  double d2addn0 = d_ndphirdni_dDelta(tau,delta,z,0);
871  double d2addn0_RP91 = -1.0719438474166139;
872  if (fabs(d2addn0/d2addn0_RP91-1) > tol){throw ValueError();}
873 
874  double d2addn1 = d_ndphirdni_dDelta(tau,delta,z,1);
875  double d2addn1_RP91 = -5.9657336386754745;
876  if (fabs(d2addn1/d2addn1_RP91-1) > tol){throw ValueError();}
877 
878  double d2adtn0 = d_ndphirdni_dTau(tau,delta,z,0);
879  double d2adtn0_RP91 = -4.58046408525892678E-004;
880  if (fabs(d2adtn0/d2adtn0_RP91-1) > tol){throw ValueError();}
881 
882  double d2adtn1 = d_ndphirdni_dTau(tau,delta,z,1);
883  double d2adtn1_RP91 = -3.54010070086436396E-003;
884  if (fabs(d2adtn1/d2adtn1_RP91-1) > tol){throw ValueError();}
885 
886  double d2ann00 = nd2nphirdnidnj__constT_V(tau, delta, z, 0, 0);
887  double d2dnn00_RP91 = -1.55709211017489475E-003;
888  if (fabs(d2ann00/d2dnn00_RP91-1) > tol){throw ValueError();}
889 
890  double d2ann01 = nd2nphirdnidnj__constT_V(tau, delta, z, 0, 1);
891  double d2dnn01_RP91 = -2.90907297842576788E-003;
892  if (fabs(d2ann01/d2dnn01_RP91-1) > tol){throw ValueError();}
893 
894  double d2ann10 = nd2nphirdnidnj__constT_V(tau, delta, z, 1, 0);
895  double d2dnn10_RP91 = -2.90907297842577049E-003;
896  if (fabs(d2ann10/d2dnn10_RP91-1) > tol){throw ValueError();}
897 
898  double d2ann11 = nd2nphirdnidnj__constT_V(tau, delta, z, 1, 1);
899  double d2dnn11_RP91 = -6.32815473413224101E-003;
900  if (fabs(d2ann11/d2dnn11_RP91-1) > tol){throw ValueError();}
901 
902  double dphidnj00 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,0,0);
903  double dphidnj00_RP91 = -5.18202802448741728E-004;
904  if (fabs(dphidnj00/dphidnj00_RP91-1) > tol){throw ValueError();}
905 
906  double dphidnj01 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,0,1);
907  double dphidnj01_RP91 = 5.18202802448741728E-004;
908  if (fabs(dphidnj01/dphidnj01_RP91-1) > tol){throw ValueError();}
909 
910  double dphidnj10 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,1,0);
911  double dphidnj10_RP91 = 5.18202802448741728E-004;
912  if (fabs(dphidnj10/dphidnj10_RP91-1) > tol){throw ValueError();}
913 
914  double dphidnj11 = ndln_fugacity_coefficient_dnj__constT_p(tau,delta,z,1,1);
915  double dphidnj11_RP91 = -5.18202802448741728E-004;
916  if (fabs(dphidnj11/dphidnj11_RP91-1) > tol){throw ValueError();}
917 
918 }
920 {
921  if (pReducing != NULL){
922  delete pReducing; pReducing = NULL;
923  }
924  if (pExcess != NULL){
925  delete pExcess; pExcess = NULL;
926  }
927  if (pResidualIdealMix != NULL){
928  delete pResidualIdealMix; pResidualIdealMix = NULL;
929  }
930 }
931 double Mixture::Wilson_lnK_factor(double T, double p, int i)
932 {
933  double pci = pFluids[i]->reduce.p.Pa;
934  double wi = pFluids[i]->params.accentricfactor;
935  double Tci = pFluids[i]->reduce.T;
936  return log(pci/p)+5.373*(1 + wi)*(1-Tci/T);
937 }
938 double Mixture::fugacity(double tau, double delta, const std::vector<double> &x, int i)
939 {
940  double Tr = pReducing->Tr(x);
941  double rhorbar = pReducing->rhorbar(x);
942  double T = Tr/tau, rhobar = rhorbar*delta, Rbar = 8.314472;
943 
944  double dnphir_dni = phir(tau,delta,x) + ndphir_dni__constT_V_nj(tau,delta,x,i);
945 
946  double f_i = x[i]*rhobar*Rbar*T*exp(dnphir_dni);
947  return f_i;
948 }
949 double Mixture::ln_fugacity_coefficient(double tau, double delta, const std::vector<double> &x, int i)
950 {
951  return phir(tau,delta,x) + ndphir_dni__constT_V_nj(tau,delta,x,i)-log(1+delta*dphir_dDelta(tau,delta,x));
952 }
953 double Mixture::dln_fugacity_coefficient_dT__constrho(double tau, double delta, const std::vector<double> &x, int i)
954 {
955  double Tr = pReducing->Tr(x); // [K]
956  double T = Tr/tau;
957  double dtau_dT = -tau/T;
958  return (dphir_dTau(tau,delta,x) + d_ndphirdni_dTau(tau,delta,x,i)-1/(1+delta*dphir_dDelta(tau,delta,x))*(delta*d2phir_dDelta_dTau(tau,delta,x)))*dtau_dT;
959 }
960 double Mixture::dnphir_dni__constT_V_nj(double tau, double delta, const std::vector<double> &x, int i)
961 {
962  // GERG Equation 7.42
963  return phir(tau,delta,x) + ndphir_dni__constT_V_nj(tau, delta, x, i);
964 }
965 double Mixture::d2nphir_dni_dT(double tau, double delta, const std::vector<double> &x, int i)
966 {
967  double Tr = pReducing->Tr(x); // [K]
968  double T = Tr/tau;
969  return -tau/T*(dphir_dTau(tau,delta,x) + d_ndphirdni_dTau(tau,delta,x,i));
970 }
971 double Mixture::dln_fugacity_coefficient_dT__constp_n(double tau, double delta, const std::vector<double> &x, int i)
972 {
973  double Tr = pReducing->Tr(x); // [K]
974  double T = Tr/tau;
975  return d2nphir_dni_dT(tau, delta, x, i) + 1/T-this->partial_molar_volume(tau,delta,x,i)/(Rbar(x)*T)*dpdT__constV_n(tau,delta,x,i);
976 }
977 double Mixture::partial_molar_volume(double tau, double delta, const std::vector<double> &x, int i)
978 {
979  return -ndpdni__constT_V_nj(tau,delta,x,i)/ndpdV__constT_n(tau,delta,x,i);
980 }
981 
982 double Mixture::dln_fugacity_coefficient_dp__constT_n(double tau, double delta, const std::vector<double> &x, int i)
983 {
984  // GERG equation 7.30
985  double Tr = pReducing->Tr(x); // [K]
986  double T = Tr/tau;
987  double rhorbar = pReducing->rhorbar(x);
988  double rhobar = rhorbar*delta;
989  double RT = Rbar(x)*T; // J/mol/K*K = J/mol = N*m/mol
990  double p = rhobar*RT*(1.0+delta*dphir_dDelta(tau, delta, x)); // [Pa]
991  double partial_molar_volume = this->partial_molar_volume(tau,delta,x,i); // [m^3/mol]
992  double term1 = partial_molar_volume/RT; // m^3/mol/(N*m)*mol = m^2/N = 1/Pa
993  double term2 = 1.0/p;
994  return term1 - term2;
995 }
996 
997 
998 
999 double Mixture::dln_fugacity_coefficient_dxj__constT_p_xi(double tau, double delta, const std::vector<double> &x, int i, int j)
1000 {
1001  // Gernert 3.115
1002  double Tr = pReducing->Tr(x); //[K]
1003  double T = Tr/tau;
1004  double term1 = d2nphir_dni_dxj__constT_V(tau, delta, x, i, j);
1005  double term2 = - this->partial_molar_volume(tau,delta,x,i)/(Rbar(x)*T)*dpdxj__constT_V_xi(tau,delta,x,j);
1006  // partial molar volume is -dpdn/dpdV, so need to flip the sign here
1007  return d2nphir_dni_dxj__constT_V(tau, delta, x, i, j) - this->partial_molar_volume(tau,delta,x,i)/(Rbar(x)*T)*dpdxj__constT_V_xi(tau,delta,x,j);
1008 }
1009 double Mixture::dpdxj__constT_V_xi(double tau, double delta, const std::vector<double> &x, int j)
1010 {
1011  // Gernert 3.130
1012  double rhorbar = pReducing->rhorbar(x);
1013  double rhobar = rhorbar*delta;
1014  double Tr = pReducing->Tr(x); //[K]
1015  double T = Tr/tau;
1016 
1017  return rhobar*Rbar(x)*T*(ddelta_dxj__constT_V_xi(tau,delta,x,j)*dphir_dDelta(tau, delta, x)+delta*d_dphirddelta_dxj__constT_V_xi(tau,delta,x,j));
1018 }
1019 
1020 double Mixture::d_dphirddelta_dxj__constT_V_xi(double tau, double delta, const std::vector<double> &x, int j)
1021 {
1022  // Gernert Equation 3.134 (Catch test provided)
1023  return d2phir_dDelta2(tau, delta, x)*ddelta_dxj__constT_V_xi(tau, delta, x, j)
1024  + d2phir_dDelta_dTau(tau, delta, x)*dtau_dxj__constT_V_xi(tau, delta, x, j)
1025  + d2phir_dxi_dDelta(tau, delta, x, j);
1026 }
1027 double Mixture::d2nphir_dni_dxj__constT_V(double tau, double delta, const std::vector<double> &x, int i, int j)
1028 {
1029  // Gernert 3.117
1030  return d_ndphirdni_dxj__constT_V_xi(tau, delta, x, i, j) + dphir_dxj__constT_V_xi(tau, delta, x, j);
1031 }
1032 double Mixture::dphir_dxj__constT_V_xi(double tau, double delta, const std::vector<double> &x, int j)
1033 {
1034  //Gernert 3.119 (Catch test provided)
1035  return dphir_dDelta(tau, delta, x)*ddelta_dxj__constT_V_xi(tau, delta, x, j)+dphir_dTau(tau, delta, x)*dtau_dxj__constT_V_xi(tau, delta, x, j)+dphir_dxi(tau, delta, x, j);
1036 }
1037 double Mixture::d_ndphirdni_dxj__constT_V_xi(double tau, double delta, const std::vector<double> &x, int i, int j)
1038 {
1039  // Gernert 3.118
1040  return d_ndphirdni_dxj__constdelta_tau_xi(tau,delta,x,i,j)
1041  + ddelta_dxj__constT_V_xi(tau,delta,x,j)*d_ndphirdni_dDelta(tau,delta,x,i)
1042  + dtau_dxj__constT_V_xi(tau,delta,x,j)*d_ndphirdni_dTau(tau,delta,x,i);
1043 }
1044 double Mixture::ddelta_dxj__constT_V_xi(double tau, double delta, const std::vector<double> &x, int j)
1045 {
1046  // Gernert 3.121 (Catch test provided)
1047  double rhorbar = pReducing->rhorbar(x);
1048  return -delta/rhorbar*pReducing->drhorbardxi__constxj(x,j);
1049 }
1050 double Mixture::dtau_dxj__constT_V_xi(double tau, double delta, const std::vector<double> &x, int j)
1051 {
1052  // Gernert 3.122 (Catch test provided)
1053  double Tr = pReducing->Tr(x); //[K]
1054  double T = Tr/tau;
1055  return 1/T*pReducing->dTrdxi__constxj(x,j);
1056 }
1057 
1058 
1059 
1060 double Mixture::dpdT__constV_n(double tau, double delta, const std::vector<double> &x, int i)
1061 {
1062  double rhorbar = pReducing->rhorbar(x);
1063  double rhobar = rhorbar*delta;
1064  return rhobar*Rbar(x)*(1+delta*dphir_dDelta(tau, delta, x)-delta*tau*d2phir_dDelta_dTau(tau, delta, x));
1065 }
1066 double Mixture::ndpdV__constT_n(double tau, double delta, const std::vector<double> &x, int i)
1067 {
1068  double rhorbar = pReducing->rhorbar(x);
1069  double rhobar = rhorbar*delta;
1070  double Tr = pReducing->Tr(x); // [K]
1071  double T = Tr/tau;
1072  return -rhobar*rhobar*Rbar(x)*T*(1+2*delta*dphir_dDelta(tau,delta,x)+delta*delta*d2phir_dDelta2(tau, delta, x));
1073 }
1074 double Mixture::ndpdni__constT_V_nj(double tau, double delta, const std::vector<double> &x, int i)
1075 {
1076  // Eqn 7.64 and 7.63
1077  double rhorbar = pReducing->rhorbar(x);
1078  double rhobar = rhorbar*delta;
1079  double Tr = pReducing->Tr(x); // [K]
1080  double T = Tr/tau;
1081  double ndrhorbar_dni__constnj = pReducing->ndrhorbardni__constnj(x,i);
1082  double ndTr_dni__constnj = pReducing->ndTrdni__constnj(x,i);
1083  double summer = 0;
1084  for (unsigned int k = 0; k < x.size(); k++)
1085  {
1086  summer += x[k]*d2phir_dxi_dDelta(tau,delta,x,k);
1087  }
1088  double nd2phir_dni_dDelta = delta*d2phir_dDelta2(tau,delta,x)*(1-1/rhorbar*ndrhorbar_dni__constnj)+tau*d2phir_dDelta_dTau(tau,delta,x)/Tr*ndTr_dni__constnj+d2phir_dxi_dDelta(tau,delta,x,i)-summer;
1089  return rhobar*Rbar(x)*T*(1+delta*dphir_dDelta(tau,delta,x)*(2-1/rhorbar*ndrhorbar_dni__constnj)+delta*nd2phir_dni_dDelta);
1090 }
1091 
1092 double Mixture::ndphir_dni__constT_V_nj(double tau, double delta, const std::vector<double> &x, int i)
1093 {
1094  double Tr = pReducing->Tr(x);
1095  double rhorbar = pReducing->rhorbar(x);
1096 
1097  double term1 = delta*dphir_dDelta(tau,delta,x)*(1-1/rhorbar*pReducing->ndrhorbardni__constnj(x,i));
1098  double term2 = tau*dphir_dTau(tau,delta,x)*(1/Tr)*pReducing->ndTrdni__constnj(x,i);
1099 
1100  double s = 0;
1101  for (unsigned int k = 0; k < x.size(); k++)
1102  {
1103  s += x[k]*dphir_dxi(tau,delta,x,k);
1104  }
1105  double term3 = dphir_dxi(tau,delta,x,i);
1106  return term1 + term2 + term3 - s;
1107 }
1108 double Mixture::ndln_fugacity_coefficient_dnj__constT_p(double tau, double delta, const std::vector<double> &x, int i, int j)
1109 {
1110  double Tr = pReducing->Tr(x);
1111  double T = Tr/tau;
1112  return nd2nphirdnidnj__constT_V(tau, delta, x, j, i) + 1 - partial_molar_volume(tau,delta,x,i)/(Rbar(x)*T)*ndpdni__constT_V_nj(tau,delta,x,j);
1113 }
1114 double Mixture::nddeltadni__constT_V_nj(double tau, double delta, const std::vector<double> &x, int i)
1115 {
1116  double rhorbar = pReducing->rhorbar(x);
1117  return delta-delta/rhorbar*pReducing->ndrhorbardni__constnj(x,i);
1118 }
1119 double Mixture::ndtaudni__constT_V_nj(double tau, double delta, const std::vector<double> &x, int i)
1120 {
1121  double Tr = pReducing->Tr(x);
1122  return tau/Tr*pReducing->ndTrdni__constnj(x,i);
1123 }
1124 double Mixture::d_ndphirdni_dxj__constdelta_tau_xi(double tau, double delta, const std::vector<double> &x, int i, int j)
1125 {
1126  double rhorbar = pReducing->rhorbar(x);
1127  double Tr = pReducing->Tr(x); // [K]
1128 
1129  double line1 = delta*d2phir_dxi_dDelta(tau,delta,x,j)*(1-1/rhorbar*pReducing->ndrhorbardni__constnj(x,i));
1130  double line2 = -delta*dphir_dDelta(tau,delta,x)*(1/rhorbar)*(pReducing->d_ndrhorbardni_dxj__constxi(x,i,j)-1/rhorbar*pReducing->drhorbardxi__constxj(x,j)*pReducing->ndrhorbardni__constnj(x,i));
1131  double line3 = tau*d2phir_dxi_dTau(tau,delta,x,j)*(1/Tr)*pReducing->ndTrdni__constnj(x,i);
1132  double line4 = tau*dphir_dTau(tau,delta,x)*(1/Tr)*(pReducing->d_ndTrdni_dxj__constxi(x,i,j)-1/Tr*pReducing->dTrdxi__constxj(x,j)*pReducing->ndTrdni__constnj(x,i));
1133  double s = 0;
1134  for (unsigned int m = 0; m < x.size(); m++)
1135  {
1136  s += x[m]*d2phirdxidxj(tau,delta,x,j,m);
1137  }
1138  double line5 = d2phirdxidxj(tau,delta,x,i,j)-dphir_dxi(tau,delta,x,j)-s;
1139  return line1+line2+line3+line4+line5;
1140 }
1141 double Mixture::nd2nphirdnidnj__constT_V(double tau, double delta, const std::vector<double> &x, int i, int j)
1142 {
1143  double line0 = ndphir_dni__constT_V_nj(tau, delta, x, j); // First term from 7.46
1144  double line1 = this->d_ndphirdni_dDelta(tau, delta, x, i)*this->nddeltadni__constT_V_nj(tau,delta,x,j);
1145  double line2 = this->d_ndphirdni_dTau(tau, delta, x, i)*this->ndtaudni__constT_V_nj(tau,delta,x,j);
1146  double summer = 0;
1147  for (unsigned int k = 0; k < x.size(); k++)
1148  {
1149  summer += x[k]*this->d_ndphirdni_dxj__constdelta_tau_xi(tau, delta, x, i, k);
1150  }
1151  double line3 = this->d_ndphirdni_dxj__constdelta_tau_xi(tau, delta, x, i, j)-summer;
1152  return line0 + line1 + line2 + line3;
1153 }
1154 double Mixture::d_ndphirdni_dDelta(double tau, double delta, const std::vector<double> &x, int i)
1155 {
1156  double Tr = pReducing->Tr(x);
1157  double rhorbar = pReducing->rhorbar(x);
1158 
1159  // The first line
1160  double term1 = (delta*d2phir_dDelta2(tau,delta,x)+dphir_dDelta(tau,delta,x))*(1-1/rhorbar*pReducing->ndrhorbardni__constnj(x,i));
1161 
1162  // The second line
1163  double term2 = tau*d2phir_dDelta_dTau(tau,delta,x)*(1/Tr)*pReducing->ndTrdni__constnj(x,i);
1164 
1165  // The third line
1166  double term3 = d2phir_dxi_dDelta(tau,delta,x,i);
1167  for (unsigned int k = 0; k < x.size(); k++)
1168  {
1169  term3 -= x[k]*d2phir_dxi_dDelta(tau,delta,x,k);
1170  }
1171  return term1 + term2 + term3;
1172 }
1173 
1174 double Mixture::d_ndphirdni_dTau(double tau, double delta, const std::vector<double> &x, int i)
1175 {
1176  double Tr = pReducing->Tr(x);
1177  double rhorbar = pReducing->rhorbar(x);
1178 
1179  // The first line
1180  double term1 = delta*d2phir_dDelta_dTau(tau,delta,x)*(1-1/rhorbar*pReducing->ndrhorbardni__constnj(x,i));
1181 
1182  // The second line
1183  double term2 = (tau*d2phir_dTau2(tau,delta,x)+dphir_dTau(tau,delta,x))*(1/Tr)*pReducing->ndTrdni__constnj(x,i);
1184 
1185  // The third line
1186  double term3 = d2phir_dxi_dTau(tau,delta,x,i);
1187  for (unsigned int k = 0; k < x.size(); k++)
1188  {
1189  term3 -= x[k]*d2phir_dxi_dTau(tau,delta,x,k);
1190  }
1191  return term1 + term2 + term3;
1192 }
1193 
1194 double Mixture::phir(double tau, double delta, const std::vector<double> &x)
1195 {
1196  return pResidualIdealMix->phir(tau,delta,x) + pExcess->phir(tau,delta,x);
1197 }
1198 double Mixture::dphir_dxi(double tau, double delta, const std::vector<double> &x, int i)
1199 {
1200  return pFluids[i]->phir(tau,delta) + pExcess->dphir_dxi(tau,delta,x,i);
1201 }
1202 double Mixture::d2phirdxidxj(double tau, double delta, const std::vector<double> &x, int i, int j)
1203 {
1204  return 0 + pExcess->d2phirdxidxj(tau,delta,x,i,j);
1205 }
1206 double Mixture::d2phir_dxi_dTau(double tau, double delta, const std::vector<double> &x, int i)
1207 {
1208  return pFluids[i]->dphir_dTau(tau,delta) + pExcess->d2phir_dxi_dTau(tau,delta,x,i);
1209 }
1210 double Mixture::d2phir_dxi_dDelta(double tau, double delta, const std::vector<double> &x, int i)
1211 {
1212  return pFluids[i]->dphir_dDelta(tau,delta) + pExcess->d2phir_dxi_dDelta(tau,delta,x,i);
1213 }
1214 double Mixture::dphir_dDelta(double tau, double delta, const std::vector<double> &x)
1215 {
1216  return pResidualIdealMix->dphir_dDelta(tau,delta,x) + pExcess->dphir_dDelta(tau,delta,x);
1217 }
1218 double Mixture::d2phir_dDelta2(double tau, double delta, const std::vector<double> &x)
1219 {
1220  return pResidualIdealMix->d2phir_dDelta2(tau,delta,x) + pExcess->d2phir_dDelta2(tau,delta,x);
1221 }
1222 double Mixture::d2phir_dDelta_dTau(double tau, double delta, const std::vector<double> &x)
1223 {
1224  return pResidualIdealMix->d2phir_dDelta_dTau(tau,delta,x) + pExcess->d2phir_dDelta_dTau(tau,delta,x);
1225 }
1226 double Mixture::d2phir_dTau2(double tau, double delta, const std::vector<double> &x)
1227 {
1228  return pResidualIdealMix->d2phir_dTau2(tau,delta,x) + pExcess->d2phir_dTau2(tau,delta,x);
1229 }
1230 double Mixture::dphir_dTau(double tau, double delta, const std::vector<double> &x)
1231 {
1232  return pResidualIdealMix->dphir_dTau(tau,delta,x) + pExcess->dphir_dTau(tau,delta,x);
1233 }
1234 
1236 class gRR_resid : public FuncWrapper1D
1237 {
1238 public:
1239  const std::vector<double> * z;
1240  const std::vector<double> * lnK;
1242 
1243  gRR_resid(Mixture *Mix, std::vector<double> const &z, std::vector<double> const& lnK){ this->z = &z; this->lnK = &lnK; this->Mix = Mix; };
1244  double call(double beta){return Mix->g_RachfordRice(*z, *lnK, beta); };
1245  double deriv(double beta){return Mix->dgdbeta_RachfordRice(*z, *lnK, beta); };
1246 };
1247 
1250 {
1251 protected:
1253 public:
1254  const std::vector<double> *x;
1256 
1257  rho_Tpz_resid(Mixture *Mix, double T, double p, const std::vector<double> &x){
1258  this->x = &x; this->T = T; this->p = p; this->Mix = Mix;
1259 
1260  Tr = Mix->pReducing->Tr(x);
1261  rhorbar = Mix->pReducing->rhorbar(x);
1262  tau = Tr/T;
1263  Rbar = Mix->Rbar(x); // J/mol/K
1264  };
1265  double call(double rhobar){
1266  double delta = rhobar/rhorbar;
1267  dphir_dDelta = Mix->dphir_dDelta(tau, delta, *x);
1268  double resid = Rbar*rhobar*T*(1 + delta*dphir_dDelta)-p;
1269  return resid;
1270  }
1271  double deriv(double rhobar){
1272  double delta = rhobar/rhorbar;
1273  double val = Rbar*T*(1 + 2*delta*Mix->dphir_dDelta(tau, delta, *x)+delta*delta*Mix->d2phir_dDelta2(tau, delta, *x));
1274  return val;
1275  }
1276 };
1277 double Mixture::rhobar_Tpz(double T, double p, const std::vector<double> &x, double rhobar0)
1278 {
1279  rho_Tpz_resid Resid(this,T,p,x);
1280  double rhobar;
1281  std::string errstr;
1282  //FILE *fp;
1283  //fp = fopen("rhobar_resid.csv","w");
1284  //for (double rhobar = 0; rhobar < 20000; rhobar += 1)
1285  //{
1286  // fprintf(fp,"%g, %g\n",rhobar, Resid.call(rhobar));
1287  //}
1288  //fclose(fp);
1289 
1290  rhobar = Newton(&Resid, rhobar0, 1e-16, 100, &errstr);
1291  if (!ValidNumber(rhobar))
1292  {
1293  rhobar = Secant(&Resid, rhobar0, 1.001*rhobar0, 1e-16, 100, &errstr);
1294  if (!ValidNumber(rhobar))
1295  {
1296  throw ValueError("Density solver failed");
1297  }
1298  }
1299  return rhobar;
1300 }
1301 
1302 
1309 {
1310 public:
1311  double p, beta;
1312  const std::vector<double> *z;
1313  std::vector<double> K;
1315 
1316  WilsonK_resid(Mixture *Mix, double beta, double p, std::vector<double> const& z){
1317  this->z = &z; this->p = p; this->Mix = Mix, this->beta = beta;
1318  K = std::vector<double>(z.size(),_HUGE);
1319  };
1320  double call(double T){
1321  double summer = 0;
1322  for (unsigned int i = 0; i< (*z).size(); i++) {
1323  K[i] = exp(Mix->Wilson_lnK_factor(T,p,i));
1324  summer += (*z)[i]*(K[i]-1)/(1-beta+beta*K[i]);
1325  }
1326  return summer;
1327  };
1328 };
1329 double Mixture::saturation_p_preconditioner(double p, const std::vector<double> &z)
1330 {
1331  double pseudo_ptriple = 0;
1332  double pseudo_pcrit = 0;
1333  double pseudo_Ttriple = 0;
1334  double pseudo_Tcrit = 0;
1335 
1336  // Check if a pure fluid, if so, mole fractions and saturation temperatures are equal to bulk composition
1337  for (unsigned int i = 0; i < N; i++)
1338  {
1339  pseudo_ptriple += pFluids[i]->params.ptriple*z[i];
1340  pseudo_pcrit += pFluids[i]->crit.p.Pa*z[i];
1341  pseudo_Ttriple += pFluids[i]->params.Ttriple*z[i];
1342  pseudo_Tcrit += pFluids[i]->crit.T*z[i];
1343  }
1344 
1345  // Preliminary guess based on interpolation of log(p) v. T
1346  return (pseudo_Tcrit-pseudo_Ttriple)/(pseudo_pcrit/pseudo_ptriple)*(p/pseudo_ptriple)+pseudo_Ttriple;
1347 }
1348 double Mixture::saturation_p_Wilson(double beta, double p, const std::vector<double> &z, double T_guess, std::vector<double> &K)
1349 {
1350  double T;
1351 
1352  std::string errstr;
1353 
1354  // Find first guess for T using Wilson K-factors
1355  WilsonK_resid Resid(this, beta, p, z);
1356  T = Secant(&Resid, T_guess, 0.001, 1e-10, 100, &errstr);
1357  // Get the K factors from the residual wrapper
1358  K = Resid.K;
1359 
1360  if (!ValidNumber(T)){throw ValueError("saturation_p_Wilson failed to get good T");}
1361  return T;
1362 }
1363 double Mixture::saturation_p(double beta, double p, std::vector<double> const& z, std::vector<double> &x, std::vector<double> &y)
1364 {
1365  double T;
1366  unsigned int N = z.size();
1367  std::vector<double> K(N), ln_phi_liq(N), ln_phi_vap(N);
1368 
1369  // Check if a pure fluid, if so, mole fractions and saturation temperatures are equal to bulk composition
1370  for (unsigned int i = 0; i < N; i++)
1371  {
1372  if (fabs(z[i]-1) < 10*DBL_EPSILON)
1373  {
1374  // Mole fractions are equal to bulk composition
1375  x = z;
1376  y = z;
1377  // Get temperature from pure-fluid saturation call
1378  double TL=0, TV=0, rhoL=0, rhoV=0;
1379  pFluids[i]->saturation_p(p,false, TL, TV, rhoL, rhoV);
1380  return TL; // Also equal to TV for pure fluid
1381  }
1382  }
1383 
1384  // Preliminary guess based on interpolation of log(p) v. T
1385  double T_guess = saturation_p_preconditioner(p, z);
1386 
1387  // Initialize the call using Wilson to get K-factors and temperature
1388  T = saturation_p_Wilson(beta, p, z, T_guess, K);
1389 
1390  // Call the successive substitution routine with the guess values provided above from Wilson
1391  // It will call the Newton-Raphson routine after a few steps of successive-substitution
1392  SS.useNR = true;
1393  T = SS.call(beta, T, p, z, K);
1394 
1395  x = SS.x;
1396  y = SS.y;
1397 
1398  return T;
1399 }
1400 void Mixture::TpzFlash(double T, double p, const std::vector<double> &z, double &rhobar, std::vector<double> &x, std::vector<double> &y)
1401 {
1402  unsigned int N = z.size();
1403  double beta, change = 0;
1404  std::vector<double> lnK(N);
1405 
1406  x.resize(N);
1407  y.resize(N);
1408 
1409  // Wilson k-factors for each component
1410  for (unsigned int i = 0; i < N; i++)
1411  {
1412  lnK[i] = Wilson_lnK_factor(T, p, i);
1413  }
1414 
1415  // Check which phase we are in using Wilson estimations
1416  double g_RR_0 = g_RachfordRice(z, lnK, 0);
1417  if (g_RR_0 < 0)
1418  {
1419  // Subcooled liquid - done
1420  rhobar = rhobar_Tpz(T,p,z,rhobar_pengrobinson(T,p,z,PR_SATL));
1421  return;
1422  }
1423  else
1424  {
1425  double g_RR_1 = g_RachfordRice(z, lnK, 1);
1426  if (g_RR_1 > 0)
1427  {
1428  // Superheated vapor - done
1429  rhobar = rhobar_Tpz(T,p,z,rhobar_pengrobinson(T,p,z,PR_SATV));
1430  return;
1431  }
1432  }
1433  // TODO: How can you be sure that you aren't in the two-phase region? Safety factor needed?
1434  // TODO: Calculate the dewpoint density
1435  do
1436  {
1437  // Now find the value of beta that satisfies Rachford-Rice using Brent's method
1438 
1439  gRR_resid Resid(this,z,lnK);
1440  std::string errstr;
1441  beta = Newton(&Resid,0,1e-10,300,&errstr);
1442 
1443  // Evaluate mole fractions in liquid and vapor
1444  for (unsigned int i = 0; i < N; i++)
1445  {
1446  double Ki = exp(lnK[i]);
1447  double den = (1 - beta + beta*Ki); // Common denominator
1448  // Liquid mole fraction of component i
1449  x[i] = z[i]/den;
1450  // Vapor mole fraction of component i
1451  y[i] = Ki*z[i]/den;
1452  }
1453 
1454  // Reducing parameters for each phase
1455  double tau_liq = pReducing->Tr(x)/T;
1456  double tau_vap = pReducing->Tr(y)/T;
1457 
1458  double rhobar_liq = rhobar_Tpz(T, p, x, rhobar_pengrobinson(T,p,x,PR_SATL));
1459  double rhobar_vap = rhobar_Tpz(T, p, y, rhobar_pengrobinson(T,p,y,PR_SATV));
1460  double rhorbar_liq = pReducing->rhorbar(x);
1461  double rhorbar_vap = pReducing->rhorbar(y);
1462  double delta_liq = rhobar_liq/rhorbar_liq;
1463  double delta_vap = rhobar_vap/rhorbar_vap;
1464 
1465  // Evaluate fugacity coefficients in liquid and vapor
1466  for (unsigned int i = 0; i < N; i++)
1467  {
1468  double ln_phi_liq = ln_fugacity_coefficient(tau_liq, delta_vap, x, i);
1469  double ln_phi_vap = ln_fugacity_coefficient(tau_vap, delta_liq, x, i);
1470 
1471  double lnKold = lnK[i];
1472  // Recalculate the K-factor (log(exp(ln_phi_liq)/exp(ln_phi_vap)))
1473  lnK[i] = ln_phi_liq - ln_phi_vap;
1474 
1475  change = lnK[i] - lnKold;
1476  }
1477  }
1478  while( fabs(change) > 1e-7);
1479 
1480  return;
1481 }
1482 void Mixture::x_and_y_from_K(double beta, const std::vector<double> &K, const std::vector<double> &z, std::vector<double> &x, std::vector<double> &y)
1483 {
1484  for (unsigned int i=0; i < N; i++)
1485  {
1486  double denominator = (1-beta+beta*K[i]); // Common denominator
1487  x[i] = z[i]/denominator;
1488  y[i] = K[i]*z[i]/denominator;
1489  }
1490  normalize_vector(x);
1491  normalize_vector(y);
1492 }
1493 double Mixture::rhobar_pengrobinson(double T, double p, const std::vector<double> &x, int solution)
1494 {
1495  double A = 0, B = 0, a = 0, b = 0, m_i, m_j, a_i, a_j, b_i, R = Rbar(x), k_ij;
1496 
1497  for (unsigned int i = 0; i < N; i++)
1498  {
1499 
1500  b_i = 0.077796074*(R*pFluids[i]->reduce.T)/(pFluids[i]->reduce.p.Pa);
1501  b += x[i]*b_i;
1502 
1503  double omega_i = pFluids[i]->params.accentricfactor;
1504  //m_i = 0.480 + 1.574*omega_i-0.176*pow(omega_i,(int)2);
1505  m_i = 0.37464 + 1.54226*omega_i-0.26992*pow(omega_i,(int)2);
1506 
1507  for (unsigned int j = 0; j < N; j++)
1508  {
1509  double omega_j = pFluids[j]->params.accentricfactor;
1510  m_j = 0.37464 + 1.54226*omega_j-0.26992*pow(omega_j,(int)2);
1511  //m_j = 0.480 + 1.574*omega_j - 0.176*pow(omega_j,(int)2);
1512  a_i = 0.45724*pow(R*pFluids[i]->reduce.T,2)/pFluids[i]->reduce.p.Pa*pow(1+m_i*(1-sqrt(T/pFluids[i]->reduce.T)),2);
1513 
1514 
1515  a_j = 0.45724*pow(R*pFluids[j]->reduce.T,2)/pFluids[j]->reduce.p.Pa*pow(1+m_j*(1-sqrt(T/pFluids[j]->reduce.T)),2);
1516  if (i!=j)
1517  {
1518  k_ij = -0.3; // Hard coded for Ethanol-Water
1519  }
1520  else
1521  {
1522  k_ij = 0;
1523  }
1524  a += x[i]*x[j]*sqrt(a_i*a_j)*(1-k_ij);
1525  }
1526  }
1527  A = a*p/(R*R*T*T);
1528  B = b*p/(R*T);
1529 
1530  double Z0, Z1, Z2;
1531  solve_cubic(1, -1+B, A-3*B*B-2*B, -A*B+B*B+B*B*B, &Z0, &Z1, &Z2);
1532 
1533  if (solution == PR_SATL)
1534  {
1535  return p/(min3(Z0,Z1,Z2)*R*T);
1536  }
1537  else if (solution == PR_SATV)
1538  {
1539  return p/(max3(Z0,Z1,Z2)*R*T);
1540  }
1541  else
1542  {
1543  throw ValueError("Solution should be one of PR_SATL, PR_SATV");
1544  }
1545 }
1546 
1547 double Mixture::g_RachfordRice(const std::vector<double> &z, const std::vector<double> &lnK, double beta)
1548 {
1549  // g function from Rachford-Rice
1550  double summer = 0;
1551  for (unsigned int i = 0; i < z.size(); i++)
1552  {
1553  double Ki = exp(lnK[i]);
1554  summer += z[i]*(Ki-1)/(1-beta+beta*Ki);
1555  }
1556  return summer;
1557 }
1558 double Mixture::dgdbeta_RachfordRice(const std::vector<double> &z, const std::vector<double> &lnK, double beta)
1559 {
1560  // derivative of g function from Rachford-Rice with respect to beta
1561  double summer = 0;
1562  for (unsigned int i = 0; i < z.size(); i++)
1563  {
1564  double Ki = exp(lnK[i]);
1565  summer += -z[i]*pow((Ki-1)/(1-beta+beta*Ki),2);
1566  }
1567  return summer;
1568 }
1569 
1570 double GERG2008ReducingFunction::Tr(const std::vector<double> &x)
1571 {
1572  double Tr = 0;
1573  for (unsigned int i = 0; i < N; i++)
1574  {
1575  double xi = x[i], Tci = pFluids[i]->reduce.T;
1576  Tr += xi*xi*Tci;
1577 
1578  // The last term is only used for the pure component, as it is sum_{i=1}^{N-1}sum_{j=1}^{N}
1579  if (i==N-1){ break; }
1580 
1581  for (unsigned int j = i+1; j < N; j++)
1582  {
1583  Tr += c_Y_ij(i, j, &beta_T, &gamma_T, &T_c)*f_Y_ij(x, i, j, &beta_T);
1584  }
1585  }
1586  return Tr;
1587 }
1588 double GERG2008ReducingFunction::dTrdxi__constxj(const std::vector<double> &x, int i)
1589 {
1590  // See Table B9 from Kunz Wagner 2012 (GERG 2008)
1591  double xi = x[i];
1592  double dTr_dxi = 2*xi*pFluids[i]->reduce.T;
1593  for (int k = 0; k < i; k++)
1594  {
1595  dTr_dxi += c_Y_ji(k,i,&beta_T,&gamma_T,&T_c)*dfYkidxi__constxk(x,k,i,&beta_T);
1596  }
1597  for (unsigned int k = i+1; k < N; k++)
1598  {
1599  dTr_dxi += c_Y_ij(i,k,&beta_T,&gamma_T,&T_c)*dfYikdxi__constxk(x,i,k,&beta_T);
1600  }
1601  return dTr_dxi;
1602 }
1603 double GERG2008ReducingFunction::d2Trdxi2__constxj(const std::vector<double> &x, int i)
1604 {
1605  // See Table B9 from Kunz Wagner 2012 (GERG 2008)
1606  double d2Tr_dxi2 = 2*pFluids[i]->reduce.T;
1607  for (int k = 0; k < i; k++)
1608  {
1609  d2Tr_dxi2 += c_Y_ij(k,i,&beta_T,&gamma_T,&T_c)*d2fYkidxi2__constxk(x,k,i,&beta_T);
1610  }
1611  for (unsigned int k = i+1; k < N; k++)
1612  {
1613  d2Tr_dxi2 += c_Y_ij(i,k,&beta_T,&gamma_T,&T_c)*d2fYikdxi2__constxk(x,i,k,&beta_T);
1614  }
1615  return d2Tr_dxi2;
1616 }
1617 double GERG2008ReducingFunction::d2Trdxidxj(const std::vector<double> &x, int i, int j)
1618 {
1619  if (i == j)
1620  {
1621  return d2Trdxi2__constxj(x,i);
1622  }
1623  else
1624  {
1625  // See Table B9 from Kunz Wagner 2012 (GERG 2008)
1626  return c_Y_ij(i,j,&beta_T,&gamma_T,&T_c)*d2fYijdxidxj(x,i,j,&beta_T);
1627  }
1628 }
1629 double GERG2008ReducingFunction::dvrbardxi__constxj(const std::vector<double> &x, int i)
1630 {
1631  // See Table B9 from Kunz Wagner 2012 (GERG 2008)
1632  double xi = x[i];
1633  double dvrbar_dxi = 2*xi/pFluids[i]->reduce.rhobar;
1634 
1635  for (int k = 0; k < i; k++)
1636  {
1637  dvrbar_dxi += c_Y_ij(k, i, &beta_v, &gamma_v, &v_c)*dfYkidxi__constxk(x, k, i, &beta_v);
1638  }
1639  for (unsigned int k = i+1; k < N; k++)
1640  {
1641  dvrbar_dxi += c_Y_ij(i, k, &beta_v, &gamma_v, &v_c)*dfYikdxi__constxk(x, i, k, &beta_v);
1642  }
1643  return dvrbar_dxi;
1644 }
1645 double GERG2008ReducingFunction::d2vrbardxidxj(const std::vector<double> &x, int i, int j)
1646 {
1647  if (i == j)
1648  {
1649  return d2vrbardxi2__constxj(x, i);
1650  }
1651  else
1652  {
1653  return c_Y_ij(i, j, &beta_v, &gamma_v, &v_c)*d2fYijdxidxj(x, i, j, &beta_v);
1654  }
1655 }
1656 double GERG2008ReducingFunction::drhorbardxi__constxj(const std::vector<double> &x, int i)
1657 {
1658  return -pow(rhorbar(x),2)*dvrbardxi__constxj(x,i);
1659 }
1660 double GERG2008ReducingFunction::d2vrbardxi2__constxj(const std::vector<double> &x, int i)
1661 {
1662  // See Table B9 from Kunz Wagner 2012 (GERG 2008)
1663  double d2vrbardxi2 = 2/pFluids[i]->reduce.rhobar;
1664 
1665  for (int k = 0; k < i; k++)
1666  {
1667  d2vrbardxi2 += c_Y_ij(k, i, &beta_v, &gamma_v, &v_c)*d2fYkidxi2__constxk(x, k, i, &beta_v);
1668  }
1669  for (unsigned int k = i+1; k < N; k++)
1670  {
1671  d2vrbardxi2 += c_Y_ij(i, k, &beta_v, &gamma_v, &v_c)*d2fYikdxi2__constxk(x, i, k, &beta_v);
1672  }
1673  return d2vrbardxi2;
1674 }
1675 double GERG2008ReducingFunction::d2rhorbardxi2__constxj(const std::vector<double> &x, int i)
1676 {
1677  double rhor = this->rhorbar(x);
1678  double dvrbardxi = this->dvrbardxi__constxj(x,i);
1679  return 2*pow(rhor,(int)3)*pow(dvrbardxi,(int)2)-pow(rhor,(int)2)*this->d2vrbardxi2__constxj(x,i);
1680 }
1681 double GERG2008ReducingFunction::d2rhorbardxidxj(const std::vector<double> &x, int i, int j)
1682 {
1683  double rhor = this->rhorbar(x);
1684  double dvrbardxi = this->dvrbardxi__constxj(x,i);
1685  double dvrbardxj = this->dvrbardxi__constxj(x,j);
1686  return 2*pow(rhor,(int)3)*dvrbardxi*dvrbardxj-pow(rhor,(int)2)*this->d2vrbardxidxj(x,i,j);
1687 }
1688 
1689 double GERG2008ReducingFunction::rhorbar(const std::vector<double> &x)
1690 {
1691  double vrbar = 0;
1692  for (unsigned int i = 0; i < N; i++)
1693  {
1694  double xi = x[i];
1695  vrbar += xi*xi/pFluids[i]->reduce.rhobar;
1696 
1697  if (i == N-1){ break; }
1698 
1699  for (unsigned int j = i+1; j < N; j++)
1700  {
1701  vrbar += c_Y_ij(i, j, &beta_v, &gamma_v, &v_c)*f_Y_ij(x,i,j,&beta_v);
1702  }
1703  }
1704  return 1/vrbar;
1705 }
1706 double GERG2008ReducingFunction::dfYkidxi__constxk(const std::vector<double> &x, int k, int i, std::vector< std::vector< double> > * beta)
1707 {
1708  double xk = x[k], xi = x[i], beta_Y = (*beta)[k][i];
1709  return xk*(xk+xi)/(beta_Y*beta_Y*xk+xi)+xk*xi/(beta_Y*beta_Y*xk+xi)*(1-(xk+xi)/(beta_Y*beta_Y*xk+xi));
1710 }
1711 double GERG2008ReducingFunction::dfYikdxi__constxk(const std::vector<double> &x, int i, int k, std::vector< std::vector< double> > * beta)
1712 {
1713  double xk = x[k], xi = x[i], beta_Y = (*beta)[i][k];
1714  return xk*(xi+xk)/(beta_Y*beta_Y*xi+xk)+xi*xk/(beta_Y*beta_Y*xi+xk)*(1-beta_Y*beta_Y*(xi+xk)/(beta_Y*beta_Y*xi+xk));
1715 }
1716 double GERG2008ReducingFunction::c_Y_ij(int i, int j, std::vector< std::vector< double> > * beta, std::vector< std::vector< double> > *gamma, std::vector< std::vector< double> > *Y_c)
1717 {
1718  return 2*((*beta)[i][j])*((*gamma)[i][j])*((*Y_c)[i][j]);
1719 }
1720 double GERG2008ReducingFunction::c_Y_ji(int j, int i, std::vector< std::vector< double> > * beta, std::vector< std::vector< double> > *gamma, std::vector< std::vector< double> > *Y_c)
1721 {
1722  return 2/((*beta)[i][j])*((*gamma)[i][j])*((*Y_c)[i][j]);
1723 }
1724 double GERG2008ReducingFunction::f_Y_ij(const std::vector<double> &x, int i, int j, std::vector< std::vector< double> > * beta)
1725 {
1726  double xi = x[i], xj = x[j], beta_Y = (*beta)[i][j];
1727  return xi*xj*(xi+xj)/(beta_Y*beta_Y*xi+xj);
1728 }
1729 double GERG2008ReducingFunction::d2fYikdxi2__constxk(const std::vector<double> &x, int i, int k, std::vector< std::vector< double> > * beta)
1730 {
1731  double xi = x[i], xk = x[k], beta_Y = (*beta)[i][k];
1732  return 1/(beta_Y*beta_Y*xi+xk)*(1-beta_Y*beta_Y*(xi+xk)/(beta_Y*beta_Y*xi+xk))*(2*xk-xi*xk*2*beta_Y*beta_Y/(beta_Y*beta_Y*xi+xk));
1733 }
1734 double GERG2008ReducingFunction::d2fYkidxi2__constxk(const std::vector<double> &x, int k, int i, std::vector< std::vector< double> > * beta)
1735 {
1736  double xi = x[i], xk = x[k], beta_Y = (*beta)[k][i];
1737  return 1/(beta_Y*beta_Y*xk+xi)*(1-(xk+xi)/(beta_Y*beta_Y*xk+xi))*(2*xk-xk*xi*2/(beta_Y*beta_Y*xk+xi));
1738 }
1739 double GERG2008ReducingFunction::d2fYijdxidxj(const std::vector<double> &x, int i, int j, std::vector< std::vector< double> > * beta)
1740 {
1741  double xi = x[i], xj = x[j], beta_Y = (*beta)[i][j], beta_Y2 = beta_Y*beta_Y;
1742  return (xi+xj)/(beta_Y2*xi+xj) + xj/(beta_Y2*xi+xj)*(1-(xi+xj)/(beta_Y2*xi+xj))
1743  +xi/(beta_Y2*xi+xj)*(1-beta_Y2*(xi+xj)/(beta_Y2*xi+xj))
1744  -xi*xj/pow(beta_Y2*xi+xj,(int)2)*(1+beta_Y2-2*beta_Y2*(xi+xj)/(beta_Y2*xi+xj));
1745 }
1746 void GERG2008ReducingFunction::set_coeffs_from_map(int i, int j, std::map<std::string,double > m)
1747 {
1748  beta_v[i][j] = m.find("betaV")->second;
1749  beta_T[i][j] = m.find("betaT")->second;
1750 
1751  gamma_v[i][j] = m.find("gammaV")->second;
1752  gamma_T[i][j] = m.find("gammaT")->second;
1753 
1754  //std::map<std::string,std::vector<double> >::iterator it;
1756  //it = m.find("t")->second;
1758  //if (it != param_map.end() )
1759  //{
1760 
1761  //}
1763  //it = m.find("n");
1765  //if (it != param_map.end() )
1766  //{
1767 
1768  //}
1769 }
1770 
1771 //GERG2008DepartureFunction::GERG2008DepartureFunction()
1772 //{
1773 // if (phi1 != NULL){
1774 // delete phi1; phi1 = NULL;
1775 // }
1776 // if (phi2 != NULL){
1777 // delete phi2; phi2 = NULL;
1778 // }
1779 //}
1780 double GERG2008DepartureFunction::phir(double tau, double delta)
1781 {
1782  if (double_equal(tau,cache.phir.tau) && double_equal(delta,cache.phir.delta))
1783  {
1784  return cache.phir.cached_val;
1785  }
1786  else
1787  {
1788  double sum;
1789  if (using_gaussian){
1790  sum = phi1.base(tau, delta) + phi2.base(tau, delta);
1791  }
1792  else{
1793  sum = phi1.base(tau, delta);
1794  }
1795  cache.phir.tau = tau;
1796  cache.phir.delta = delta;
1797  cache.phir.cached_val = sum;
1798  return sum;
1799  }
1800 }
1801 double GERG2008DepartureFunction::dphir_dDelta(double tau, double delta)
1802 {
1804  {
1805  return cache.dphir_dDelta.cached_val;
1806  }
1807  else
1808  {
1809  double sum;
1810  if (using_gaussian){
1811  sum = phi1.dDelta(tau, delta) + phi2.dDelta(tau, delta);
1812  }
1813  else{
1814  sum = phi1.dDelta(tau, delta);
1815  }
1816  cache.dphir_dDelta.tau = tau;
1817  cache.dphir_dDelta.delta = delta;
1819  return sum;
1820  }
1821 }
1822 double GERG2008DepartureFunction::d2phir_dDelta2(double tau, double delta)
1823 {
1825  {
1827  }
1828  else
1829  {
1830  double sum;
1831  if (using_gaussian){
1832  sum = phi1.dDelta2(tau, delta) + phi2.dDelta2(tau, delta);
1833  }
1834  else{
1835  sum = phi1.dDelta2(tau, delta);
1836  }
1837  cache.d2phir_dDelta2.tau = tau;
1838  cache.d2phir_dDelta2.delta = delta;
1840  return sum;
1841  }
1842 }
1843 double GERG2008DepartureFunction::d2phir_dDelta_dTau(double tau, double delta)
1844 {
1845 
1847  {
1849  }
1850  else
1851  {
1852  double sum;
1853  if (using_gaussian){
1854  sum = phi1.dDelta_dTau(tau, delta) + phi2.dDelta_dTau(tau, delta);
1855  }
1856  else{
1857  sum = phi1.dDelta_dTau(tau, delta);
1858  }
1860  cache.d2phir_dDelta_dTau.delta = delta;
1862  return sum;
1863  }
1864 }
1865 double GERG2008DepartureFunction::dphir_dTau(double tau, double delta)
1866 {
1867 
1869  {
1870  return cache.dphir_dTau.cached_val;
1871  }
1872  else
1873  {
1874  double sum;
1875  if (using_gaussian){
1876  sum = phi1.dTau(tau, delta) + phi2.dTau(tau, delta);
1877  }
1878  else{
1879  sum = phi1.dTau(tau, delta);
1880  }
1881  cache.dphir_dTau.tau = tau;
1882  cache.dphir_dTau.delta = delta;
1883  cache.dphir_dTau.cached_val = sum;
1884  return sum;
1885  }
1886 }
1887 double GERG2008DepartureFunction::d2phir_dTau2(double tau, double delta)
1888 {
1889 
1891  {
1892  return cache.d2phir_dTau2.cached_val;
1893  }
1894  else
1895  {
1896  double sum;
1897  if (using_gaussian){
1898  sum = phi1.dTau2(tau, delta) + phi2.dTau2(tau, delta);
1899  }
1900  else{
1901  sum = phi1.dTau2(tau, delta);
1902  }
1903  cache.d2phir_dTau2.tau = tau;
1904  cache.d2phir_dTau2.delta = delta;
1906  return sum;
1907  }
1908 }
1909 
1910 void GERG2008DepartureFunction::set_coeffs_from_map(std::map<std::string,std::vector<double> > m)
1911 {
1912  std::vector<double> n = m.find("n")->second;
1913  std::vector<double> t = m.find("t")->second;
1914  std::vector<double> d = m.find("d")->second;
1915  std::vector<double> eta = m.find("eta")->second;
1916  std::vector<double> epsilon = m.find("epsilon")->second;
1917  std::vector<double> beta = m.find("beta")->second;
1918  std::vector<double> gamma = m.find("gamma")->second;
1919 
1920  unsigned int iStart;
1921  // If sum of entries in eta are zero, there is no gaussian term
1922  // All terms are power-like
1923  if (double_equal(std::accumulate(eta.begin(), eta.end(), 0.0),0.0))
1924  {
1925  using_gaussian = false;
1926  iStart = eta.size()-1;
1927  }
1928  else
1929  {
1930  using_gaussian = true;
1931  iStart = 0;
1932  while (eta[iStart+1] < 0.25)
1933  {
1934  iStart++;
1935  }
1936  }
1937 
1938  phi1 = phir_power(n,d,t,1,iStart);
1939  if (using_gaussian) { phi2 = phir_GERG2008_gaussian(n,d,t,eta,epsilon,beta,gamma,iStart+1,eta.size()-1); }
1940 
1941  //std::map<std::string,std::vector<double> >::iterator it;
1943  //it = m.find("t")->second;
1945  //if (it != param_map.end() )
1946  //{
1947 
1948  //}
1950  //it = m.find("n");
1952  //if (it != param_map.end() )
1953  //{
1954 
1955  //}
1956 }
1957 
1958 double LemmonHFCDepartureFunction::phir(double tau, double delta)
1959 {
1960  if (use_cache && double_equal(tau,cache.phir.tau) && double_equal(delta,cache.phir.delta))
1961  {
1962  return cache.phir.cached_val;
1963  }
1964  else
1965  {
1966  double sum = phi1.base(tau, delta);
1967  cache.phir.tau = tau;
1968  cache.phir.delta = delta;
1969  cache.phir.cached_val = sum;
1970  return sum;
1971  }
1972 }
1973 double LemmonHFCDepartureFunction::dphir_dDelta(double tau, double delta)
1974 {
1975  if (use_cache && double_equal(tau,cache.dphir_dDelta.tau) && double_equal(delta,cache.dphir_dDelta.delta))
1976  {
1977  return cache.dphir_dDelta.cached_val;
1978  }
1979  else
1980  {
1981  double sum = phi1.dDelta(tau, delta);
1982  cache.dphir_dDelta.tau = tau;
1983  cache.dphir_dDelta.delta = delta;
1985  return sum;
1986  }
1987 }
1988 double LemmonHFCDepartureFunction::d2phir_dDelta2(double tau, double delta)
1989 {
1990  if (use_cache && double_equal(tau,cache.d2phir_dDelta2.tau) && double_equal(delta,cache.d2phir_dDelta2.delta))
1991  {
1993  }
1994  else
1995  {
1996  double sum = phi1.dDelta2(tau, delta);
1997  cache.d2phir_dDelta2.tau = tau;
1998  cache.d2phir_dDelta2.delta = delta;
2000  return sum;
2001  }
2002 }
2003 double LemmonHFCDepartureFunction::d2phir_dDelta_dTau(double tau, double delta)
2004 {
2005 
2007  {
2009  }
2010  else
2011  {
2012  double sum = phi1.dDelta_dTau(tau, delta);
2014  cache.d2phir_dDelta_dTau.delta = delta;
2016  return sum;
2017  }
2018 }
2019 double LemmonHFCDepartureFunction::dphir_dTau(double tau, double delta)
2020 {
2021  if (use_cache && double_equal(tau,cache.dphir_dTau.tau) && double_equal(delta,cache.dphir_dTau.delta))
2022  {
2023  return cache.dphir_dTau.cached_val;
2024  }
2025  else
2026  {
2027  double sum = phi1.dTau(tau, delta);
2028  cache.dphir_dTau.tau = tau;
2029  cache.dphir_dTau.delta = delta;
2030  cache.dphir_dTau.cached_val = sum;
2031  return sum;
2032  }
2033 }
2034 double LemmonHFCDepartureFunction::d2phir_dTau2(double tau, double delta)
2035 {
2036 
2037  if (use_cache && double_equal(tau,cache.d2phir_dTau2.tau) && double_equal(delta,cache.d2phir_dTau2.delta))
2038  {
2039  return cache.d2phir_dTau2.cached_val;
2040  }
2041  else
2042  {
2043  double sum = phi1.dTau2(tau, delta);
2044  cache.d2phir_dTau2.tau = tau;
2045  cache.d2phir_dTau2.delta = delta;
2047  return sum;
2048  }
2049 }
2050 
2051 void LemmonHFCDepartureFunction::set_coeffs_from_map(std::map<std::string,std::vector<double> > m)
2052 {
2053  std::vector<double> n = m.find("n")->second;
2054  std::vector<double> t = m.find("t")->second;
2055  std::vector<double> d = m.find("d")->second;
2056  std::vector<double> l = m.find("l")->second;
2057 
2058  // All terms are power-like
2059  phi1 = phir_power(n,d,t,l,1,n.size()-1);
2060 }
2061 
2062 void LemmonAirHFCReducingFunction::set_coeffs_from_map(int i, int j, std::map<std::string,double > m)
2063 {
2064  double xi_ij = m.find("xi")->second;
2065  double zeta_ij = m.find("zeta")->second;
2066  beta_T[i][j] = 1;
2067  beta_v[i][j] = 1;
2068  gamma_T[i][j] = (pFluids[i]->reduce.T + pFluids[j]->reduce.T + xi_ij)/(2*sqrt(pFluids[i]->reduce.T*pFluids[j]->reduce.T));
2069  double v_i = 1/pFluids[i]->reduce.rhobar;
2070  double v_j = 1/pFluids[j]->reduce.rhobar;
2071  double one_third = 0.33333333333333333;
2072  gamma_v[i][j] = (v_i + v_j + zeta_ij)/(0.25*pow(pow(v_i, one_third)+pow(v_j, one_third),(int)3));
2073 }
2074 
2076 {
2077  F.resize(N,std::vector<double>(N,1.0));
2078  DepartureFunctionMatrix.resize(N,std::vector<DepartureFunction*>(N));
2079  this->N = N;
2080 }
2082 {
2083  for (unsigned int i = 0; i < N; i++)
2084  {
2085  for (unsigned int j = 0; j < N; j++)
2086  {
2087  if (DepartureFunctionMatrix[i][j] != NULL)
2088  {
2089  delete DepartureFunctionMatrix[i][j]; DepartureFunctionMatrix[i][j] = NULL;
2090  }
2091  }
2092  }
2093 }
2094 
2095 double ExcessTerm::phir(double tau, double delta, const std::vector<double> &x)
2096 {
2097  double summer = 0;
2098  for (unsigned int i = 0; i < N-1; i++)
2099  {
2100  for (unsigned int j = i + 1; j < N; j++)
2101  {
2102  summer += x[i]*x[j]*F[i][j]*DepartureFunctionMatrix[i][j]->phir(tau,delta);
2103  }
2104  }
2105  return summer;
2106 }
2107 double ExcessTerm::dphir_dTau(double tau, double delta, const std::vector<double> &x)
2108 {
2109  double summer = 0;
2110  for (unsigned int i = 0; i < N-1; i++)
2111  {
2112  for (unsigned int j = i + 1; j < N; j++)
2113  {
2114  summer += x[i]*x[j]*F[i][j]*DepartureFunctionMatrix[i][j]->dphir_dTau(tau,delta);
2115  }
2116  }
2117  return summer;
2118 }
2119 double ExcessTerm::dphir_dDelta(double tau, double delta, const std::vector<double> &x)
2120 {
2121  double summer = 0;
2122  for (unsigned int i = 0; i < N-1; i++)
2123  {
2124  for (unsigned int j = i + 1; j < N; j++)
2125  {
2126  summer += x[i]*x[j]*F[i][j]*DepartureFunctionMatrix[i][j]->dphir_dDelta(tau,delta);
2127  }
2128  }
2129  return summer;
2130 }
2131 double ExcessTerm::d2phir_dDelta2(double tau, double delta, const std::vector<double> &x)
2132 {
2133  double summer = 0;
2134  for (unsigned int i = 0; i < N-1; i++)
2135  {
2136  for (unsigned int j = i + 1; j < N; j++)
2137  {
2138  summer += x[i]*x[j]*F[i][j]*DepartureFunctionMatrix[i][j]->d2phir_dDelta2(tau,delta);
2139  }
2140  }
2141  return summer;
2142 }
2143 double ExcessTerm::d2phir_dTau2(double tau, double delta, const std::vector<double> &x)
2144 {
2145  double summer = 0;
2146  for (unsigned int i = 0; i < N-1; i++)
2147  {
2148  for (unsigned int j = i + 1; j < N; j++)
2149  {
2150  summer += x[i]*x[j]*F[i][j]*DepartureFunctionMatrix[i][j]->d2phir_dTau2(tau,delta);
2151  }
2152  }
2153  return summer;
2154 }
2155 double ExcessTerm::d2phir_dDelta_dTau(double tau, double delta, const std::vector<double> &x)
2156 {
2157  double summer = 0;
2158  for (unsigned int i = 0; i < N-1; i++)
2159  {
2160  for (unsigned int j = i + 1; j < N; j++)
2161  {
2162  summer += x[i]*x[j]*F[i][j]*DepartureFunctionMatrix[i][j]->d2phir_dDelta_dTau(tau,delta);
2163  }
2164  }
2165  return summer;
2166 }
2167 double ExcessTerm::dphir_dxi(double tau, double delta, const std::vector<double> &x, unsigned int i)
2168 {
2169  double summer = 0;
2170  for (unsigned int k = 0; k < N; k++)
2171  {
2172  if (i != k)
2173  {
2174  summer += x[k]*F[i][k]*DepartureFunctionMatrix[i][k]->phir(tau,delta);
2175  }
2176  }
2177  return summer;
2178 }
2179 double ExcessTerm::d2phirdxidxj(double tau, double delta, const std::vector<double> &x, unsigned int i, unsigned int j)
2180 {
2181  if (i != j)
2182  {
2183  return F[i][j]*DepartureFunctionMatrix[i][j]->phir(tau,delta);
2184  }
2185  else
2186  {
2187  return 0;
2188  }
2189 }
2190 double ExcessTerm::d2phir_dxi_dTau(double tau, double delta, const std::vector<double> &x, unsigned int i)
2191 {
2192  double summer = 0;
2193  for (unsigned int k = 0; k < N; k++)
2194  {
2195  if (i != k)
2196  {
2197  summer += x[k]*F[i][k]*DepartureFunctionMatrix[i][k]->dphir_dTau(tau,delta);
2198  }
2199  }
2200  return summer;
2201 }
2202 double ExcessTerm::d2phir_dxi_dDelta(double tau, double delta, const std::vector<double> &x, unsigned int i)
2203 {
2204  double summer = 0;
2205  for (unsigned int k = 0; k < N; k++)
2206  {
2207  if (i != k)
2208  {
2209  summer += x[k]*F[i][k]*DepartureFunctionMatrix[i][k]->dphir_dDelta(tau,delta);
2210  }
2211  }
2212  return summer;
2213 }
2214 void ExcessTerm::set_coeffs_from_map(int i, int j, std::map<std::string, std::vector<double> > m)
2215 {
2216  DepartureFunctionMatrix[i][j]->set_coeffs_from_map(m);
2217 }
2218 
2220 {
2221  this->pFluids = pFluids;
2222  this->N = pFluids.size();
2223 }
2224 double ResidualIdealMixture::phir(double tau, double delta, const std::vector<double> &x)
2225 {
2226  double summer = 0;
2227  for (unsigned int i = 0; i < N; i++)
2228  {
2229  summer += x[i]*pFluids[i]->phir(tau,delta);
2230  }
2231  return summer;
2232 }
2233 double ResidualIdealMixture::dphir_dDelta(double tau, double delta, const std::vector<double> &x)
2234 {
2235  double summer = 0;
2236  for (unsigned int i = 0; i < N; i++)
2237  {
2238  summer += x[i]*pFluids[i]->dphir_dDelta(tau,delta);
2239  }
2240  return summer;
2241 }
2242 double ResidualIdealMixture::d2phir_dDelta2(double tau, double delta, const std::vector<double> &x)
2243 {
2244  double summer = 0;
2245  for (unsigned int i = 0; i < N; i++)
2246  {
2247  summer += x[i]*pFluids[i]->d2phir_dDelta2(tau,delta);
2248  }
2249  return summer;
2250 }
2251 double ResidualIdealMixture::d2phir_dDelta_dTau(double tau, double delta, const std::vector<double> &x)
2252 {
2253  double summer = 0;
2254  for (unsigned int i = 0; i < N; i++)
2255  {
2256  summer += x[i]*pFluids[i]->d2phir_dDelta_dTau(tau,delta);
2257  }
2258  return summer;
2259 }
2260 double ResidualIdealMixture::dphir_dTau(double tau, double delta, const std::vector<double> &x)
2261 {
2262  double summer = 0;
2263  for (unsigned int i = 0; i < N; i++)
2264  {
2265  summer += x[i]*pFluids[i]->dphir_dTau(tau,delta);
2266  }
2267  return summer;
2268 }
2269 double ResidualIdealMixture::d2phir_dTau2(double tau, double delta, const std::vector<double> &x)
2270 {
2271  double summer = 0;
2272  for (unsigned int i = 0; i < N; i++)
2273  {
2274  summer += x[i]*pFluids[i]->d2phir_dTau2(tau,delta);
2275  }
2276  return summer;
2277 }
2278 double ReducingFunction::d_ndTrdni_dxj__constxi(const std::vector<double> &x, int i, int j)
2279 {
2280  double s = 0;
2281  for (unsigned int k = 0; k < N; k++)
2282  {
2283  s += x[k]*d2Trdxidxj(x,j,k);
2284  }
2285  return d2Trdxidxj(x,i,j)-dTrdxi__constxj(x,j)-s;
2286 }
2287 double ReducingFunction::d_ndrhorbardni_dxj__constxi(const std::vector<double> &x, int i, int j)
2288 {
2289  double s = 0;
2290  for (unsigned int k = 0; k < N; k++)
2291  {
2292  s += x[k]*d2rhorbardxidxj(x,j,k);
2293  }
2294  return d2rhorbardxidxj(x,j,i)-drhorbardxi__constxj(x,j)-s;
2295 }
2296 double ReducingFunction::ndrhorbardni__constnj(const std::vector<double> &x, int i)
2297 {
2298  double summer_term1 = 0;
2299  for (unsigned int j = 0; j < N; j++)
2300  {
2301  summer_term1 += x[j]*drhorbardxi__constxj(x,j);
2302  }
2303  return drhorbardxi__constxj(x,i)-summer_term1;
2304 }
2305 double ReducingFunction::ndTrdni__constnj(const std::vector<double> &x, int i)
2306 {
2307  // GERG Equation 7.54
2308  double summer_term1 = 0;
2309  for (unsigned int j = 0; j < N; j++)
2310  {
2311  summer_term1 += x[j]*dTrdxi__constxj(x,j);
2312  }
2313  return dTrdxi__constxj(x,i)-summer_term1;
2314 }
2315 
2316 double SuccessiveSubstitutionVLE::call(double beta, double T, double p, const std::vector<double> &z, std::vector<double> &K)
2317 {
2318  int iter = 1;
2319  double change, f, dfdT, rhobar_liq_new, rhobar_vap_new;
2320  unsigned int N = z.size();
2321  K.resize(N); ln_phi_liq.resize(N); ln_phi_vap.resize(N); x.resize(N); y.resize(N);
2322 
2323  Mix->x_and_y_from_K(beta, K, z, x, y);
2324 
2325  rhobar_liq = 1.3 * Mix->rhobar_pengrobinson(T, p, x, PR_SATL); // [kg/m^3]
2326  rhobar_vap = Mix->rhobar_pengrobinson(T, p, y, PR_SATV); // [kg/m^3]
2327 
2328  do
2329  {
2330  rhobar_liq_new = Mix->rhobar_Tpz(T, p, x, rhobar_liq); // [kg/m^3]
2331  rhobar_vap_new = Mix->rhobar_Tpz(T, p, y, rhobar_vap); // [kg/m^3]
2332  rhobar_liq = rhobar_liq_new;
2333  rhobar_vap = rhobar_vap_new;
2334 
2335  double Tr_liq = Mix->pReducing->Tr(x); // [K]
2336  double Tr_vap = Mix->pReducing->Tr(y); // [K]
2337  double tau_liq = Tr_liq/T; // [-]
2338  double tau_vap = Tr_vap/T; // [-]
2339 
2340  double rhorbar_liq = Mix->pReducing->rhorbar(x); //[kg/m^3]
2341  double rhorbar_vap = Mix->pReducing->rhorbar(y); //[kg/m^3]
2342  double delta_liq = rhobar_liq/rhorbar_liq; //[-]
2343  double delta_vap = rhobar_vap/rhorbar_vap; //[-]
2344 
2345  f = 0;
2346  dfdT = 0;
2347 
2348  for (unsigned int i=0; i < N; i++)
2349  {
2350  // Loop over the liquids to take advantage of caching since cached derivatives
2351  // will be used as long as tau and delta don't change
2352  ln_phi_liq[i] = Mix->ln_fugacity_coefficient(tau_liq, delta_liq, x, i);
2353  double dln_phi_liq_dT = Mix->dln_fugacity_coefficient_dT__constp_n(tau_liq, delta_liq, x, i);
2354 
2355  // And then loop over the vapors
2356  ln_phi_vap[i] = Mix->ln_fugacity_coefficient(tau_vap, delta_vap, y, i);
2357  double dln_phi_vap_dT = Mix->dln_fugacity_coefficient_dT__constp_n(tau_vap, delta_vap, y, i);
2358 
2359  K[i] = exp(ln_phi_liq[i]-ln_phi_vap[i]);
2360 
2361  f += z[i]*(K[i]-1)/(1-beta+beta*K[i]);
2362 
2363  double dfdK = K[i]*z[i]/pow(1-beta+beta*K[i],(int)2);
2364  dfdT += dfdK*(dln_phi_liq_dT-dln_phi_vap_dT);
2365  }
2366 
2367  change = -f/dfdT;
2368 
2369  //double Tnew_over_Told = (T + change)/T;
2370  T += change;
2371 
2372  Mix->x_and_y_from_K(beta,K,z,x,y);
2373 
2374  iter += 1;
2375  if (iter > 50)
2376  {
2377  return _HUGE;
2378  //throw ValueError(format("saturation_p was unable to reach a solution within 50 iterations"));
2379  }
2380  // If SS takes a large step, help by re-guessing using Peng-Robinson
2381  if (fabs(change) > 3)
2382  {
2383  rhobar_liq = 1.3 * Mix->rhobar_pengrobinson(T, p, x, PR_SATL); // [kg/m^3]
2384  rhobar_vap = Mix->rhobar_pengrobinson(T, p, y, PR_SATV); // [kg/m^3]
2385  }
2386  }
2387  while(fabs(f) > 1e-3 && iter < Nstep_max);
2388 
2389  if (!useNR)
2390  {
2391  this->rhobar_liq = rhobar_liq;
2392  this->rhobar_vap = rhobar_vap;
2393  return T;
2394  }
2395  else
2396  {
2397  // Pass off to Newton-Raphson to polish the solution
2398  double Treturn = Mix->NRVLE.call(beta, T, p, rhobar_liq, rhobar_vap, z, K, N+1, log(p));
2399  this->rhobar_liq = Mix->NRVLE.rhobar_liq;
2400  this->rhobar_vap = Mix->NRVLE.rhobar_vap;
2401  return Treturn;
2402  }
2403 }
2404 
2405 void NewtonRaphsonVLE::resize(unsigned int N)
2406 {
2407  this->N = N;
2408  x.resize(N);
2409  y.resize(N);
2410  phi_ij_liq.resize(N);
2411  phi_ij_vap.resize(N);
2412 
2413  r.resize(N+2);
2414  J.resize(N+2, std::vector<double>(N+2, 0));
2415 
2416  neg_dFdS.resize(N+2);
2417  dXdS.resize(N+2);
2418 
2419  // Fill the vector -dFdS with zeros (Gerg Eqn. 7.132)
2420  std::fill(neg_dFdS.begin(), neg_dFdS.end(), (double)0.0);
2421  // Last entry is 1
2422  neg_dFdS[N+1] = 1.0;
2423 }
2424 double NewtonRaphsonVLE::call(double beta, double T, double p, double rhobar_liq, double rhobar_vap, const std::vector<double> &z, std::vector<double> & K, int spec_index, double spec_value)
2425 {
2426  int iter = 0;
2427 
2428  // Reset all the variables and resize
2429  pre_call();
2430  resize(K.size());
2431 
2432  //std::cout << format("NRVLE beta %g, T %g, p %g, rhobar_liq %g, rhobar_vap %g , z %s, K %s, index %d, val %g \n",beta,T,p,rhobar_liq,rhobar_vap,vec_to_string(z,"%4.3g").c_str(),vec_to_string(K,"%4.3g").c_str(),spec_index,spec_value);
2433 
2434  //~ double old_rhobar_liq = rhobar_liq,
2435  //~ old_rhobar_vap = rhobar_vap,
2436  //~ old_T = T,
2437  //~ old_p = p;
2438  std::vector<double> old_K = K;
2439 
2440  this->rhobar_liq = rhobar_liq;
2441  this->rhobar_vap = rhobar_vap;
2442  do
2443  {
2444  // Build the Jacobian and residual vectors for given inputs of K_i,T,p
2445  build_arrays(beta,T,p,z,K,spec_index,spec_value);
2446 
2447  // Solve for the step; v is the step with the contents
2448  // [delta(lnK0), delta(lnK1), ..., delta(lnT), delta(lnp)]
2449  std::vector<double> v = linsolve(J, r);
2450 
2451  // Set the variables again, the same structure independent of the specified variable
2452  for (unsigned int i = 0; i < N; i++)
2453  {
2454  K[i] = exp(log(K[i]) + v[i]);
2455  if (!ValidNumber(K[i]))
2456  {
2457  throw ValueError(format("K[i] (%g) is invalid",K[i]).c_str());
2458  }
2459  }
2460  T = exp(log(T) + v[N]);
2461  p = exp(log(p) + v[N+1]);
2462 
2463  if (fabs(T) > 1e6 || fabs(p) > 1e10)
2464  {
2465  /*std::cout << "J = " << vec_to_string(J,"%16.15g");
2466  std::cout << "nr = " << vec_to_string(r,"%16.15g");*/
2467  throw ValueError("Temperature or p has bad value");
2468  }
2469 
2470  //std::cout << iter << " " << T << " " << p << " " << error_rms << std::endl;
2471  iter++;
2472  }
2473  while(this->error_rms > 1e-11 && iter < Nsteps_max);
2474  // Store new values since they were passed by value
2475  this->T = T;
2476  this->p = p;
2477  this->K = K;
2478  this->Nsteps = iter;
2479 
2480  //std::cout << format("NRVLE beta %g, T %g, p %g, rhobar_liq %g, rhobar_vap %g , z %s, K %s, index %d, val %g \n",beta,T,p,rhobar_liq,rhobar_vap,vec_to_string(z,"%4.3g").c_str(),vec_to_string(K,"%4.3g").c_str(),spec_index,exp(spec_value));
2481  //std::cout << format("liq_change %g vap_change %g\n", this->rhobar_liq/old_rhobar_liq-1, this->rhobar_vap/old_rhobar_vap-1);
2482  return T;
2483 }
2484 
2485 void NewtonRaphsonVLE::build_arrays(double beta, double T, double p, const std::vector<double> &z, std::vector<double> &K, int spec_index, double spec_value)
2486 {
2487  // Step 0:
2488  // --------
2489  // Calculate the mole fractions in liquid and vapor phases
2490  Mix->x_and_y_from_K(beta, K, z, x, y);
2491 
2492  // Step 1:
2493  // -------
2494  // Calculate the new reducing and reduced parameters for each phase
2495  // based on the current values of the molar fractions
2496  double old_rhobar_liq = this->rhobar_liq;
2497  double old_rhobar_vap = this->rhobar_vap;
2498 
2499  this->rhobar_liq = Mix->rhobar_Tpz(T, p, x, this->rhobar_liq); // [kg/m^3] (Not exact due to solver convergence)
2500  this->rhobar_vap = Mix->rhobar_Tpz(T, p, y, this->rhobar_vap); // [kg/m^3] (Not exact due to solver convergence)
2501 
2502  if (this->rhobar_vap > this->rhobar_liq)
2503  {
2504  // Phases are inverted, swap x&y, recalculate densities
2505  std::swap(x, y);
2506  std::cout << format("Phase inversion");
2507  this->rhobar_liq = Mix->rhobar_Tpz(T, p, x, old_rhobar_liq); // [kg/m^3] (Not exact due to solver convergence)
2508  this->rhobar_vap = Mix->rhobar_Tpz(T, p, y, old_rhobar_vap); // [kg/m^3] (Not exact due to solver convergence)
2509  }
2510 
2511  //std::cout << format("rho liq: %g rho vap: %g k: %s T: %g P: %g x: %s\n", this->rhobar_liq, this->rhobar_vap, vec_to_string(K,"%6.5g").c_str(),T,p, vec_to_string(x,"%6.5g").c_str()).c_str();
2512 
2513  if (!ValidNumber(this->rhobar_liq)){ throw ValueError(format("Liquid density solver has failed with guess value %g",old_rhobar_liq).c_str()); }
2514  if (!ValidNumber(this->rhobar_vap)){ throw ValueError(format("Vapor density solver has failed with guess value %g",old_rhobar_vap).c_str()); }
2515 
2516  double Tr_liq = Mix->pReducing->Tr(x); // [K]
2517  double Tr_vap = Mix->pReducing->Tr(y); // [K]
2518  double tau_liq = Tr_liq/T; // [-]
2519  double tau_vap = Tr_vap/T; // [-]
2520 
2521  double rhorbar_liq = Mix->pReducing->rhorbar(x); //[kg/m^3]
2522  double rhorbar_vap = Mix->pReducing->rhorbar(y); //[kg/m^3]
2523  double delta_liq = this->rhobar_liq/rhorbar_liq; //[-]
2524  double delta_vap = this->rhobar_vap/rhorbar_vap; //[-]
2525 
2526  double p_liq = this->rhobar_liq*Mix->Rbar(x)*T*(1+delta_liq*Mix->dphir_dDelta(tau_liq,delta_liq,x));
2527  double p_vap = this->rhobar_vap*Mix->Rbar(y)*T*(1+delta_vap*Mix->dphir_dDelta(tau_vap,delta_vap,y));
2528 
2529  // Step 2:
2530  // -------
2531  // Build the residual vector and the Jacobian matrix
2532 
2533  // For the residuals F_i
2534  for (unsigned int i = 0; i < N; i++)
2535  {
2536  double ln_phi_liq = Mix->ln_fugacity_coefficient(tau_liq, delta_liq, x, i);
2537  double phi_iT_liq = Mix->dln_fugacity_coefficient_dT__constp_n(tau_liq, delta_liq, x, i);
2538  double phi_ip_liq = Mix->dln_fugacity_coefficient_dp__constT_n(tau_liq, delta_liq, x, i);
2539  for (unsigned int j = 0; j < N; j++)
2540  {
2541  phi_ij_liq[j] = Mix->ndln_fugacity_coefficient_dnj__constT_p(tau_liq,delta_liq,x,i,j); // 7.126 from GERG monograph
2542  }
2543 
2544  double ln_phi_vap = Mix->ln_fugacity_coefficient(tau_vap, delta_vap, y, i);
2545  double phi_iT_vap = Mix->dln_fugacity_coefficient_dT__constp_n(tau_vap, delta_vap, y, i);
2546  double phi_ip_vap = Mix->dln_fugacity_coefficient_dp__constT_n(tau_vap, delta_vap, y, i);
2547  for (unsigned int j = 0; j < N; j++)
2548  {
2549  phi_ij_vap[j] = Mix->ndln_fugacity_coefficient_dnj__constT_p(tau_vap,delta_vap,y,i,j); // 7.126 from GERG monograph
2550  }
2551 
2552  r[i] = ln_phi_vap - ln_phi_liq + log(K[i]);
2553  for (unsigned int j = 0; j < N; j++)
2554  {
2555  J[i][j] = K[j]*z[j]/pow(1-beta+beta*K[j],(int)2)*((1-beta)*phi_ij_vap[j]+beta*phi_ij_liq[j])+Kronecker_delta(i,j);
2556  }
2557  // dF_{i}/d(ln(T))
2558  J[i][N] = T*(phi_iT_vap-phi_iT_liq);
2559  // dF_{i}/d(ln(p))
2560  J[i][N+1] = p*(phi_ip_vap-phi_ip_liq);
2561  }
2562 
2563  double summer1 = 0;
2564  for (unsigned int i = 0; i < N; i++)
2565  {
2566  // Although the definition of this term is given by
2567  // y[i]-x[i], when x and y are normalized, you get
2568  // the wrong values. Why? No idea.
2569  summer1 += z[i]*(K[i]-1)/(1-beta+beta*K[i]);
2570  }
2571  r[N] = summer1;
2572 
2573  // For the residual term F_{N+1}, only non-zero derivatives are with respect
2574  // to ln(K[i])
2575  for (unsigned int j = 0; j < N; j++)
2576  {
2577  J[N][j] = K[j]*z[j]/pow(1-beta+beta*K[j],(int)2);
2578  }
2579 
2580  // For the specification term F_{N+2}, with index of N+1
2581  if (spec_index == N)
2582  {r[N+1] = log(T) - spec_value;}
2583  else if (spec_index == N+1)
2584  {r[N+1] = log(p) - spec_value;}
2585  else
2586  {r[N+1] = log(K[spec_index]) - spec_value;}
2587 
2588  // The row in the Jacobian for the specification
2589  for (unsigned int i = 0; i < N+2; i++)
2590  {
2591  J[N+1][i] = Kronecker_delta(i,spec_index);
2592  }
2593 
2594  // Flip all the signs of the entries in the residual vector since we are solving Jv = -r, not Jv=r
2595  // Also calculate the rms error of the residual vector at this step
2596  error_rms = 0;
2597  for (unsigned int i = 0; i < N+2; i++)
2598  {
2599  r[i] *= -1;
2600  error_rms += r[i]*r[i]; // Sum the squares
2601  }
2602  error_rms = sqrt(error_rms); // Square-root (The R in RMS)
2603 
2604  //std::cout << format("r: %s\n",vec_to_string(r,"%6.5g").c_str());
2605 
2606  // Step 3:
2607  // =======
2608  // Calculate the sensitivity vector dXdS
2609  dXdS = linsolve(J,neg_dFdS);
2610 }
2611 
2612 
2613 void PhaseEnvelope::build(double p0, const std::vector<double> &z, double beta_envelope)
2614 {
2615  double S, Sold, DELTAS, abs_Kdeviation;
2616  K.resize(Mix->N);
2617  bubble.K.resize(Mix->N);
2618  bubble.lnK.resize(Mix->N);
2619  bubble.x.resize(Mix->N);
2620  bubble.y.resize(Mix->N);
2621  dew.K.resize(Mix->N);
2622  dew.lnK.resize(Mix->N);
2623  dew.x.resize(Mix->N);
2624  dew.y.resize(Mix->N);
2625 
2626  for (unsigned int betaI = 0; betaI < 2; betaI++)
2627  {
2628  // If betaI is 0, use beta_envelope, otherwise use 1-beta_envelope
2629  double beta = (betaI==0) ? beta_envelope : 1-beta_envelope;
2630 
2631  // Reference for data points to either bubble or dew
2632  PhaseEnvelopeLog &data = (betaI==0) ? bubble : dew;
2633 
2634  // Use the preconditioner to get the very rough guess for saturation temperature
2635  // (interpolation based on pseudo-critical pressure)
2636  double T_guess = Mix->saturation_p_preconditioner(p0, z);
2637 
2638  // Initialize the call using Wilson to get K-factors and temperature
2639  double T = Mix->saturation_p_Wilson(beta, p0, z, T_guess, K);
2640 
2641  // Call successive substitution and Newton-Raphson to get updated guess for K-factors using imposed pressure
2642  T = Mix->SS.call(beta, T, p0, z, K);
2645 
2646  double p = p0;
2647  double lnT = log(T);
2648  double lnP = log(p0);
2649 
2650  // Find the most sensitive input (the one with the largest absolute value in dX/dS
2651  double max_abs_val = -1;
2652  int i_S = -1;
2653  for (unsigned int i = 0; i < Mix->N+1; i++) // N+1 because specification not allowed to be selected
2654  {
2655  if (fabs(Mix->NRVLE.dXdS[i])>max_abs_val)
2656  {
2657  max_abs_val = fabs(Mix->NRVLE.dXdS[i]);
2658  i_S = i;
2659  }
2660  }
2661  // Determine the value of the specified variable based on the index of the specified variable
2662  if (i_S >= (int)Mix->N)
2663  {
2664  if (i_S == Mix->N)
2665  {
2666  Sold = lnT;
2667  DELTAS = log(1.01); // Temperatures increase as we approach the critical point for both branches
2668  }
2669  else
2670  {
2671  Sold = lnP;
2672  DELTAS = log(1.01); // Pressures increase as we approach the critical point for both branches
2673  }
2674  }
2675  else
2676  {
2677  // K will go towards 1 as we move up on the envelope
2678  Sold = log(K[i_S]);
2679  if (Sold < 0) // K_i < 1
2680  {
2681  DELTAS = log(1.1); // K_i will increase
2682  }
2683  else
2684  {
2685  DELTAS = log(0.9); // K_i will decrease
2686  }
2687  }
2688 
2689  // Run once with the specified variable set
2690  Mix->NRVLE.call(beta, T, p, rhobar_liq, rhobar_vap, z, K, i_S, Sold);
2691 
2692  // Store the variables in the log if the step worked ok
2694 
2695  int iter = 1;
2696  do
2697  {
2698  bool step_accepted = false;
2699  std::vector<double> dXdSold = Mix->NRVLE.dXdS; //Copy from the last good run
2700  double Told = T; // Copy from the last good run
2701  double pold = p; // Copy from the last good run
2702  std::vector<double> Kold = K; // Copy from the last good run
2703 
2704  // Loop while the step size isn't small enough - usually only requires one downsizing of the step
2705  while (step_accepted == false)
2706  {
2707  // Make a copy of the stored values from the last iteration
2708  std::vector<double> DELTAX(dXdSold.size()), dXdS = dXdSold;
2709  T = Told;
2710  p = pold;
2711  K = Kold;
2712 
2713  for (unsigned int i = 0; i < Mix->N+2; i++)
2714  {
2715  DELTAX[i] = dXdS[i]*DELTAS;
2716  }
2717 
2718  // Update the temperature
2719  double DELTALNT = DELTAX[Mix->N];
2720  T = exp(log(Told)+DELTALNT);
2721  lnT = log(T);
2722 
2723  // Update the pressure
2724  double DELTALNP = DELTAX[Mix->N+1];
2725  p = exp(log(pold)+DELTALNP);
2726  lnP = log(p);
2727 
2728  // Update the K-factors
2729  for (unsigned int i = 0; i < Mix->N; i++)
2730  {
2731  K[i] = exp(log(Kold[i])+DELTAX[i]);
2732  }
2733 
2734  // Update the specified variable
2735  S = Sold + DELTAS;
2736 
2737  //std::cout << format("S: %g Sold %g DELTAS %g exp(S) %g exp(Sold) %g K %s\n",S,Sold,DELTAS, exp(S), exp(Sold),vec_to_string(K,"%0.5g").c_str());
2738 
2739  // UPDATE THE GUESSES
2740  // The specified variable is known directly. The others must be obtained either through the use of dXdS and/or extrapolation
2741  if (data.T.size() > 2)
2742  {
2743  int M = data.T.size();
2744  // Update the densities using quadratic extrapolation
2745  rhobar_liq = QuadInterp(data.lnK[1][M-3],data.lnK[1][M-2],data.lnK[1][M-1],data.rhobar_liq[M-3],data.rhobar_liq[M-2],data.rhobar_liq[M-1],log(K[1]));
2746  rhobar_vap = exp(QuadInterp(data.lnK[1][M-3],data.lnK[1][M-2],data.lnK[1][M-1],log(data.rhobar_vap[M-3]),log(data.rhobar_vap[M-2]),log(data.rhobar_vap[M-1]),log(K[1])));
2747  T = exp(QuadInterp(data.lnK[1][M-3],data.lnK[1][M-2],data.lnK[1][M-1],data.lnT[M-3],data.lnT[M-2],data.lnT[M-1],log(K[1])));
2748  p = exp(QuadInterp(data.lnK[1][M-3],data.lnK[1][M-2],data.lnK[1][M-1],data.lnp[M-3],data.lnp[M-2],data.lnp[M-1],log(K[1])));
2749  }
2750  else if (data.T.size() > 3)
2751  {
2752  int M = data.T.size();
2753  // First we use a cubic spline to find the next value for the vapor molar density
2754  SplineClass SC1;
2755  SC1.add_4value_constraints(data.lnK[0][M-4],data.lnK[0][M-3],data.lnK[0][M-2],data.lnK[0][M-1],
2756  data.lnrhobar_vap[M-4],data.lnrhobar_vap[M-3],data.lnrhobar_vap[M-2],data.lnrhobar_vap[M-1]);
2757  SC1.build();
2758  rhobar_vap = exp(SC1.evaluate(log(K[0])));
2759 
2760  SplineClass SC2;
2761  SC2.add_4value_constraints(log(data.rhobar_vap[M-4]), log(data.rhobar_vap[M-3]), log(data.rhobar_vap[M-2]), log(data.rhobar_vap[M-1]),
2762  data.lnT[M-4], data.lnT[M-3], data.lnT[M-2], data.lnT[M-1]);
2763  SC2.build();
2764  T = exp(SC2.evaluate(log(rhobar_vap)));
2765 
2766  SplineClass SC3;
2767  SC3.add_4value_constraints(log(data.rhobar_vap[M-4]), log(data.rhobar_vap[M-3]), log(data.rhobar_vap[M-2]), log(data.rhobar_vap[M-1]),
2768  data.lnp[M-4], data.lnp[M-3], data.lnp[M-2], data.lnp[M-1]);
2769  SC3.build();
2770  p = exp(SC3.evaluate(log(rhobar_vap)));
2771 
2772  SplineClass SC4;
2773  /*SC4.add_4value_constraints(log(data.rhobar_vap[M-4]), log(data.rhobar_vap[M-3]), log(data.rhobar_vap[M-2]), log(data.rhobar_vap[M-1]),
2774  log(data.rhobar_liq[M-4]), log(data.rhobar_liq[M-3]), log(data.rhobar_liq[M-2]), log(data.rhobar_liq[M-1]));
2775  SC4.build();
2776  rhobar_liq = exp(SC4.evaluate(log(rhobar_vap)));*/
2777  SC4.add_4value_constraints(data.rhobar_vap[M-4], data.rhobar_vap[M-3], data.rhobar_vap[M-2], data.rhobar_vap[M-1],
2778  data.rhobar_liq[M-4], data.rhobar_liq[M-3], data.rhobar_liq[M-2], data.rhobar_liq[M-1]);
2779  SC4.build();
2780  rhobar_liq = SC4.evaluate(rhobar_vap);
2781  }
2782  else
2783  {
2784  // Treat the liquid as being incompressible, don't update the guess
2785  // Treat the vapor as being ideal, use pressure ratio to update pressure
2786 
2787  // Start with T&p from the last specified state
2788  T = Mix->NRVLE.T;
2789  p = Mix->NRVLE.p;
2790 
2791  // Start with the densities from the last specified state
2794  }
2795 
2796  // Run with the selected specified variable
2797  try
2798  {
2799 
2800  Mix->NRVLE.call(beta, T, p, rhobar_liq, rhobar_vap, z, K, i_S, S);
2801  // Throw an exception if an invalid value returned but no exception was thrown
2802  if (!ValidNumber(Mix->NRVLE.T))
2803  {
2804  throw ValueError(format("T [%g] is not valid", Mix->NRVLE.T).c_str());
2805  }
2806 
2807  T = Mix->NRVLE.T;
2808  p = Mix->NRVLE.p;
2811 
2812  //std::vector<double> x(K.size()), y(K.size());
2813  //double T2 = Mix->NRVLE.T;
2814  //double T3 = Mix->saturation_p(beta_envelope,p,z,x,y);
2815  //std::cout << T2 << " " << T3;
2816  }
2817  catch (CoolPropBaseError &e)
2818  {
2819  printf("error: %s\n",e.what());
2820  // Decrease the step size by a factor of 10
2821  printf("Failure; step downsize\n");
2822 
2823  DELTAS *= 0.1;
2824 
2825  continue;
2826  }
2827 
2828  #ifdef MPLSUPPORTED
2829  if (K[0] < 1.01)
2830  {
2831  Dictionary d;
2832  d.add("lw", 1);
2833  d.add("color", "r");
2834  d.add("linestyle", "-");
2835  d.add("marker", "o");
2836 
2837  PyPlotter plt;
2838  plt.plot(data.lnK[0],data.lnrhobar_vap, &d);
2839  plt.show();
2840  }
2841  #endif
2842 
2843  // Store the variables in the log if the step worked ok
2844  data.store_variables(T, p, Mix->NRVLE.rhobar_liq, Mix->NRVLE.rhobar_vap, K, i_S, Mix->NRVLE.x, Mix->NRVLE.y, Mix->N);
2845 
2846  step_accepted = true;
2847 
2848  if (Mix->NRVLE.Nsteps > 4)
2849  {
2850  std::cout << "Downsizing, too many iterations\n";
2851  DELTAS *= 0.25;
2852  }
2853  else if (Mix->NRVLE.Nsteps < 4)
2854  {
2855  DELTAS *= 2;
2856  }
2857 
2858  double _max_abs_val = -1;
2859  int iii_S = -1;
2860  for (unsigned int i = 0; i < Mix->N+1; i++)
2861  {
2862  if (fabs(Mix->NRVLE.dXdS[i]) > _max_abs_val)
2863  {
2864  _max_abs_val = fabs(Mix->NRVLE.dXdS[i]);
2865  iii_S = i;
2866  }
2867  }
2868  //std::cout << format("T,P,Nstep,K : %g %g %d %g %g %d %d %s %s\n",T,p,Mix->NRVLE.Nsteps, rhobar_liq, rhobar_vap, iii_S, i_S, vec_to_string(Mix->NRVLE.x,"%6.5g").c_str(), vec_to_string(K,"%6.5g").c_str());
2869  }
2870 
2871  // Update step counter
2872  iter++;
2873 
2874  // Reset last specified value
2875  Sold = S;
2876 
2877  if (!ValidNumber(T))
2878  {
2879  double rr = 0;
2880  }
2881 
2882  std::vector<double> Kdeviation(K.size(),0);
2883  for (unsigned int i = 0; i < Mix->N; i++)
2884  {
2885  Kdeviation[i] = std::abs(K[i]-1);
2886  }
2887  abs_Kdeviation = *std::max_element(Kdeviation.begin(), Kdeviation.end());
2888  }
2889  while ((p > p0 && abs_Kdeviation > 0.01 && iter < 10000) || iter < 3);
2890  }
2891 }
2892 
2893 void PhaseEnvelope::to_python_files(std::string base_fname)
2894 {
2895  FILE *fp;
2896  for (unsigned int i = 0; i < 2; i++)
2897  {
2898  // reference for data points to bubble if i==0, otherwise dew
2899  PhaseEnvelopeLog &data = (i==0) ? bubble : dew;
2900  std::string fname;
2901  if (i==0){
2902  fname = base_fname+std::string("_bubble.py");
2903  }
2904  else{
2905  fname = base_fname+std::string("_dew.py");
2906  }
2907  fp = fopen(fname.c_str(), "w");
2908 
2909  fprintf(fp, "import matplotlib.pyplot as plt\n");
2910  fprintf(fp, "T = %s\n",vec_to_string(data.T,"%10.9g").c_str());
2911  fprintf(fp, "p = %s\n",vec_to_string(data.p,"%10.9g").c_str());
2912  fprintf(fp, "rhobar_liq = %s\n", vec_to_string(data.rhobar_liq,"%10.9g").c_str());
2913  fprintf(fp, "rhobar_vap = %s\n", vec_to_string(data.rhobar_vap,"%10.9g").c_str());
2914  fprintf(fp, "K0 = %s\n", vec_to_string(data.K[0],"%10.9g").c_str());
2915  fprintf(fp, "K1 = %s\n", vec_to_string(data.K[1],"%10.9g").c_str());
2916  fprintf(fp, "lnK0 = %s\n", vec_to_string(data.lnK[0],"%10.9g").c_str());
2917  fprintf(fp, "lnK1 = %s\n", vec_to_string(data.lnK[1],"%10.9g").c_str());
2918  fprintf(fp, "if __name__=='__main__':\n\tplt.plot(T,p,'o-')\n\tplt.show()");
2919  fprintf(fp, "\n\tplt.plot(K0,p,'o-')\n\tplt.show()");
2920  fclose(fp);
2921  }
2922 }
2923 
2924 
2925 
2927 
2928 #ifndef DISABLE_CATCH
2929 #include "Catch/catch.hpp"
2930 TEST_CASE("Mixture derivative checks", "")
2931  {
2932  Mixture Mix("Methane|Ethane");
2933  std::vector<double> z(2,0.5);
2934  double rhorbar = Mix.pReducing->rhorbar(z);
2935  double Tr = Mix.pReducing->Tr(z);
2936  int i = 0;
2937  double epsT = sqrt(DBL_EPSILON), epsp = 0.1, epsz = 1e-5;
2938  double T0 = 300, p0 = 100000;
2939  double rho0 = Mix.rhobar_Tpz(T0,p0, z, 5);
2940  double delta0 = rho0/rhorbar;
2941  double tau0 = Tr/T0;
2942 
2943  SECTION("check against RP9.1")
2944  {
2945  Mix.check_MethaneEthane();
2946  }
2947  SECTION("check p")
2948  {
2949  double p1 = rho0*Mix.Rbar(z)*T0*(1+delta0*Mix.dphir_dDelta(tau0, delta0, z));
2950  CAPTURE(p0);
2951  CAPTURE(p1);
2952  REQUIRE(fabs(p0/p1-1) < 1e-8);
2953  }
2954  SECTION("dlnphi_dT")
2955  {
2956  double ANA = Mix.dln_fugacity_coefficient_dT__constp_n(tau0, delta0, z, i);
2957 
2958  double T1 = T0+epsT;
2959  double delta1 = Mix.rhobar_Tpz(T1,p0,z, 5)/rhorbar;
2960  double tau1 = Tr/T1;
2961  double f1 = Mix.ln_fugacity_coefficient(tau1, delta1, z, i);
2962 
2963  double T2 = T0-epsT;
2964  double delta2 = Mix.rhobar_Tpz(T2,p0,z, 5)/rhorbar;
2965  double tau2 = Tr/T2;
2966  double f2 = Mix.ln_fugacity_coefficient(tau2, delta2, z, i);
2967 
2968  double NUM = (f1-f2)/(2*epsT);
2969 
2970  CAPTURE(NUM);
2971  CAPTURE(ANA);
2972  REQUIRE(fabs(NUM/ANA-1) < 1e-8);
2973  }
2974  SECTION("dlnphi_dp")
2975  {
2976  double ANA = Mix.dln_fugacity_coefficient_dp__constT_n(tau0, delta0, z, i);
2977 
2978  double p1 = p0+epsp;
2979  double delta1 = Mix.rhobar_Tpz(T0,p1,z, 5)/rhorbar;
2980  double tau1 = Tr/T0;
2981  double f1 = Mix.ln_fugacity_coefficient(tau1, delta1, z, i);
2982 
2983  double p2 = p0-epsp;
2984  double delta2 = Mix.rhobar_Tpz(T0,p2,z, 5)/rhorbar;
2985  double tau2 = Tr/T0;
2986  double f2 = Mix.ln_fugacity_coefficient(tau2, delta2, z, i);
2987 
2988  double NUM = (f1-f2)/(2*epsp);
2989 
2990  CAPTURE(NUM);
2991  CAPTURE(ANA);
2992  REQUIRE(fabs(NUM/ANA-1) < 1e-7);
2993  }
2994  SECTION("dln_fugacity_coefficient_dxj__constT_p_xi")
2995  {
2996  for (int i = 0; i < 2; i++)
2997  {
2998  for (int j = 0; j < 2; j++)
2999  {
3000  double ANA = Mix.dln_fugacity_coefficient_dxj__constT_p_xi(tau0, delta0, z, i, j);
3001 
3002  std::vector<double> z1 = z;
3003  z1[j] += epsz;
3004  double delta1 = Mix.rhobar_Tpz(T0, p0, z1, 5)/Mix.pReducing->rhorbar(z1);
3005  double tau1 = Mix.pReducing->Tr(z1)/T0;
3006  double f1 = Mix.ln_fugacity_coefficient(tau1, delta1, z1, i);
3007 
3008  std::vector<double> z2 = z;
3009  z2[j] -= epsz;
3010  double delta2 = Mix.rhobar_Tpz(T0, p0, z2, 5)/Mix.pReducing->rhorbar(z2);
3011  double tau2 = Mix.pReducing->Tr(z2)/T0;
3012  double f2 = Mix.ln_fugacity_coefficient(tau2, delta2, z2, i);
3013 
3014  double NUM = (f1-f2)/(2*epsz);
3015 
3016  CAPTURE(NUM);
3017  CAPTURE(ANA);
3018  CAPTURE(i);
3019  CAPTURE(j);
3020  CHECK(fabs(NUM-ANA) < 1e-7);
3021  }
3022  }
3023  }
3024  SECTION("d_ndphirdni_dxj__constdelta_tau_xi")
3025  {
3026  for (int i = 0; i < 2; i++)
3027  {
3028  for (int j = 0; j < 2; j++)
3029  {
3030  double ANA = Mix.d_ndphirdni_dxj__constdelta_tau_xi(tau0, delta0, z, i, j);
3031  std::vector<double> z1 = z, z2 = z;
3032 
3033  z1[j] += epsz;
3034  double f1 = Mix.ndphir_dni__constT_V_nj(tau0, delta0, z1, i);
3035 
3036  z2[j] -= epsz;
3037  double f2 = Mix.ndphir_dni__constT_V_nj(tau0, delta0, z2, i);
3038 
3039  double NUM = (f1-f2)/(2*epsz);
3040  CAPTURE(NUM);
3041  CAPTURE(ANA);
3042  CAPTURE(i);
3043  CAPTURE(j);
3044  CHECK(fabs(NUM/ANA-1) < 1e-10);
3045  }
3046  }
3047  }
3048  SECTION("dphir_dxj__constT_V_xi")
3049  {
3050  for (int j = 0; j < 2; j++)
3051  {
3052  double ANA = Mix.dphir_dxj__constT_V_xi(tau0, delta0, z, j);
3053 
3054  std::vector<double> z1 = z;
3055  z1[j] += epsz;
3056  double delta1 = rho0/Mix.pReducing->rhorbar(z1);
3057  double tau1 = Mix.pReducing->Tr(z1)/T0;
3058  double f1 = Mix.phir(tau1, delta1, z1);
3059 
3060  std::vector<double> z2 = z;
3061  z2[j] -= epsz;
3062  double delta2 = rho0/Mix.pReducing->rhorbar(z2);
3063  double tau2 = Mix.pReducing->Tr(z2)/T0;
3064  double f2 = Mix.phir(tau2, delta2, z2);
3065 
3066  double NUM = (f1-f2)/(2*epsz);
3067  CAPTURE(NUM);
3068  CAPTURE(ANA);
3069  CAPTURE(j);
3070  CHECK(fabs(NUM/ANA-1) < 1e-9);
3071  }
3072  }
3073  SECTION("d_dphirddelta_dxj__constT_V_xi")
3074  {
3075  for (int j = 0; j < 2; j++)
3076  {
3077  double ANA = Mix.d_dphirddelta_dxj__constT_V_xi(tau0, delta0, z, j);
3078 
3079  std::vector<double> z1 = z;
3080  z1[j] += epsz;
3081  double delta1 = rho0/Mix.pReducing->rhorbar(z1);
3082  double tau1 = Mix.pReducing->Tr(z1)/T0;
3083  double f1 = Mix.dphir_dDelta(tau1, delta1, z1);
3084 
3085  std::vector<double> z2 = z;
3086  z2[j] -= epsz;
3087  double delta2 = rho0/Mix.pReducing->rhorbar(z2);
3088  double tau2 = Mix.pReducing->Tr(z2)/T0;
3089  double f2 = Mix.dphir_dDelta(tau2, delta2, z2);
3090 
3091  double NUM = (f1-f2)/(2*epsz);
3092  CAPTURE(NUM);
3093  CAPTURE(ANA);
3094  CAPTURE(j);
3095  CHECK(fabs(NUM/ANA-1) < 1e-9);
3096  }
3097  }
3098  SECTION("d2nphir_dni_dxj__constT_V")
3099  {
3100  for (int i = 0; i < 2; i++)
3101  {
3102  for (int j = 0; j < 2; j++)
3103  {
3104  double ANA = Mix.d2nphir_dni_dxj__constT_V(tau0, delta0, z, i, j);
3105 
3106  std::vector<double> z1 = z;
3107  z1[j] += epsz;
3108  double delta1 = rho0/Mix.pReducing->rhorbar(z1);
3109  double tau1 = Mix.pReducing->Tr(z1)/T0;
3110  double f1 = Mix.dnphir_dni__constT_V_nj(tau1, delta1, z1, i);
3111 
3112  std::vector<double> z2 = z;
3113  z2[j] -= epsz;
3114  double delta2 = rho0/Mix.pReducing->rhorbar(z2);
3115  double tau2 = Mix.pReducing->Tr(z2)/T0;
3116  double f2 = Mix.dnphir_dni__constT_V_nj(tau2, delta2, z2, i);
3117 
3118  double NUM = (f1-f2)/(2*epsz);
3119  CAPTURE(NUM);
3120  CAPTURE(ANA);
3121  CAPTURE(j);
3122  CHECK(fabs(NUM/ANA-1) < 1e-8);
3123  }
3124  }
3125  }
3126  SECTION("dpdxj__constT_V_xi")
3127  {
3128  for (int j = 0; j < 2; j++)
3129  {
3130  double ANA = Mix.dpdxj__constT_V_xi(tau0, delta0, z, j);
3131 
3132  std::vector<double> z1 = z;
3133  z1[j] += epsz;
3134  double delta1 = rho0/Mix.pReducing->rhorbar(z1);
3135  double tau1 = Mix.pReducing->Tr(z1)/T0;
3136  double p1 = rho0*Mix.Rbar(z1)*T0*(1+delta1*Mix.dphir_dDelta(tau1,delta1,z1));
3137 
3138  std::vector<double> z2 = z;
3139  z2[j] -= epsz;
3140  double delta2 = rho0/Mix.pReducing->rhorbar(z2);
3141  double tau2 = Mix.pReducing->Tr(z2)/T0;
3142  double p2 = rho0*Mix.Rbar(z2)*T0*(1+delta2*Mix.dphir_dDelta(tau2,delta2,z2));
3143 
3144  double NUM = (p1-p2)/(2*epsz);
3145  CAPTURE(NUM);
3146  CAPTURE(ANA);
3147  CAPTURE(j);
3148  CHECK(fabs(NUM/ANA-1) < 1e-9);
3149  }
3150  }
3151  SECTION("ddelta_dxj__constT_V_xi")
3152  {
3153  for (int j = 0; j < 2; j++)
3154  {
3155  double ANA = Mix.ddelta_dxj__constT_V_xi(tau0, delta0, z, j);
3156 
3157  std::vector<double> z1 = z;
3158  z1[j] += epsz;
3159  double f1 = rho0/Mix.pReducing->rhorbar(z1);
3160 
3161  std::vector<double> z2 = z;
3162  z2[j] -= epsz;
3163  double f2 = rho0/Mix.pReducing->rhorbar(z2);
3164 
3165  double NUM = (f1-f2)/(2*epsz);
3166  CAPTURE(NUM);
3167  CAPTURE(ANA);
3168  CAPTURE(j);
3169  CHECK(fabs(NUM/ANA-1) < 1e-10);
3170  }
3171  }
3172  SECTION("ddtau_dxj__constT_V_xi")
3173  {
3174  for (int j = 0; j < 2; j++)
3175  {
3176  double ANA = Mix.dtau_dxj__constT_V_xi(tau0, delta0, z, j);
3177 
3178  std::vector<double> z1 = z;
3179  z1[j] += epsz;
3180  double f1 = Mix.pReducing->Tr(z1)/T0;
3181 
3182  std::vector<double> z2 = z;
3183  z2[j] -= epsz;
3184  double f2 = Mix.pReducing->Tr(z2)/T0;
3185 
3186  double NUM = (f1-f2)/(2*epsz);
3187  CAPTURE(NUM);
3188  CAPTURE(ANA);
3189  CAPTURE(j);
3190  CHECK(fabs(NUM/ANA-1) < 1e-10);
3191  }
3192  }
3193  }
3194 #endif
double d_ndphirdni_dxj__constdelta_tau_xi(double tau, double delta, const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1124
double ndtaudni__constT_V_nj(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1119
Fluid * get_fluid(long iFluid)
Definition: CoolProp.cpp:236
double rhobar_pengrobinson(double T, double p, const std::vector< double > &x, int solution)
Definition: Mixtures.cpp:1493
double f_Y_ij(const std::vector< double > &x, int i, int j, std::vector< std::vector< double > > *beta)
Definition: Mixtures.cpp:1724
double nd2nphirdnidnj__constT_V(double tau, double delta, const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1141
GenericDocument & Parse(const Ch *str)
Parse JSON text from a read-only string.
Definition: document.h:742
std::vector< double > phi_ij_vap
Definition: Mixtures.h:341
Mixture * Mix
Definition: Mixtures.h:339
double d2phir_dxi_dDelta(double tau, double delta, const std::vector< double > &x, unsigned int i)
Definition: Mixtures.cpp:2202
void build_arrays(double beta, double T, double p, const std::vector< double > &z, std::vector< double > &K, int spec_index, double spec_value)
Definition: Mixtures.cpp:2485
void set_coeffs_from_map(int i, int j, std::map< std::string, double >)
Set the coefficients based on reducing parameters loaded from JSON.
Definition: Mixtures.cpp:2062
double dphir_dxi(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1198
double dphir_dDelta(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2119
ValueIterator Begin()
Element iterator.
Definition: document.h:370
double dln_fugacity_coefficient_dxj__constT_p_xi(double tau, double delta, const std::vector< double > &x, int i, int j)
Gernert Equation 3.115.
Definition: Mixtures.cpp:999
double ddelta_dxj__constT_V_xi(double tau, double delta, const std::vector< double > &x, int j)
Definition: Mixtures.cpp:1044
DepartureFunctionCacheElement dphir_dDelta
Definition: Mixtures.h:206
double saturation_p_preconditioner(double p, const std::vector< double > &z)
Definition: Mixtures.cpp:1329
std::vector< Fluid * > pFluids
Definition: Mixtures.h:454
std::vector< std::vector< double > > K
Definition: Mixtures.h:395
double min3(double x1, double x2, double x3)
double rhobar_vap
The molar density of the vapor phase [mol/m^3].
Definition: Mixtures.h:312
double ndTrdni__constnj(const std::vector< double > &x, int i)
Definition: Mixtures.cpp:2305
std::vector< double > dXdS
Definition: Mixtures.h:341
std::string mixture_excess_JSON
double d2phir_dDelta_dTau(double tau, double delta)
Definition: Mixtures.cpp:2003
double dphir_dTau(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2107
double g_RachfordRice(const std::vector< double > &z, const std::vector< double > &lnK, double beta)
Definition: Mixtures.cpp:1547
long get_Fluid_index(std::string FluidName)
Definition: CoolProp.cpp:239
double dphir_dTau(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2260
double call(double rhobar)
Definition: Mixtures.cpp:1265
std::vector< double > lnp
Definition: Mixtures.h:396
void x_and_y_from_K(double beta, const std::vector< double > &K, const std::vector< double > &z, std::vector< double > &x, std::vector< double > &y)
Definition: Mixtures.cpp:1482
double d2rhorbardxi2__constxj(const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1675
const std::vector< double > * z
Definition: Mixtures.cpp:1239
double max3(double x1, double x2, double x3)
double d_ndphirdni_dDelta(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1154
double d2fYijdxidxj(const std::vector< double > &x, int i, int k, std::vector< std::vector< double > > *beta)
Definition: Mixtures.cpp:1739
double ndln_fugacity_coefficient_dnj__constT_p(double tau, double delta, const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1108
Set the coefficients based on reducing parameters loaded from JSON void set_coeffs_from_map(int i, int j, std::map< std::string, double >)
Set the coefficients based on reducing parameters loaded from JSON.
Definition: Mixtures.cpp:1746
ReducingFunction * pReducing
Definition: Mixtures.h:455
double saturation_p(double beta, double p, const std::vector< double > &z, std::vector< double > &x, std::vector< double > &y)
Definition: Mixtures.cpp:1363
unsigned int N
Definition: Mixtures.h:446
std::vector< double > rhobar_vap
Definition: Mixtures.h:396
double dDelta(double tau, double delta)
Definition: Helmholtz.cpp:1063
double dDelta_dTau(double tau, double delta)
Definition: Helmholtz.cpp:247
double d_ndphirdni_dxj__constT_V_xi(double tau, double delta, const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1037
double dvrbardxi__constxj(const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1629
virtual double d2rhorbardxidxj(const std::vector< double > &x, int i, int j)=0
Mixture * Mix
Definition: Mixtures.cpp:1314
NewtonRaphsonVLE NRVLE
Definition: Mixtures.h:462
double d2phir_dDelta2(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:1218
phir_GERG2008_gaussian phi2
Definition: Mixtures.h:215
double dtau_dxj__constT_V_xi(double tau, double delta, const std::vector< double > &x, int j)
Definition: Mixtures.cpp:1050
double d2phir_dDelta2(double tau, double delta)
Definition: Mixtures.cpp:1822
const std::vector< double > * lnK
Definition: Mixtures.cpp:1240
~Mixture()
Definition: Mixtures.cpp:919
double dDelta(double tau, double delta)
Definition: Helmholtz.cpp:199
double c_Y_ij(int i, int j, std::vector< std::vector< double > > *beta, std::vector< std::vector< double > > *gamma, std::vector< std::vector< double > > *Y_c)
Definition: Mixtures.cpp:1716
double d_ndTrdni_dxj__constxi(const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:2278
double dnphir_dni__constT_V_nj(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:960
double dTau(double tau, double delta)
Definition: Helmholtz.cpp:139
double ndrhorbardni__constnj(const std::vector< double > &x, int i)
Definition: Mixtures.cpp:2296
double d2phir_dTau2(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2143
SuccessiveSubstitutionVLE SS
Definition: Mixtures.h:461
std::vector< double > T
Definition: Mixtures.h:396
double dDelta_dTau(double tau, double delta)
Definition: Helmholtz.cpp:1103
virtual double rhorbar(const std::vector< double > &x)=0
The molar reducing density.
DepartureFunctionCacheElement dphir_dTau
Definition: Mixtures.h:206
double dDelta2(double tau, double delta)
Definition: Helmholtz.cpp:1073
double nddeltadni__constT_V_nj(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1114
double fugacity(double tau, double delta, const std::vector< double > &x, int i)
Returns the fugacity for the given component for the given total reduced density and reciprocal reduc...
Definition: Mixtures.cpp:938
double d2vrbardxi2__constxj(const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1660
double d2nphir_dni_dT(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:965
ValueIterator End()
Definition: document.h:371
std::vector< std::vector< double > > lnK
Definition: Mixtures.h:395
gRR_resid(Mixture *Mix, std::vector< double > const &z, std::vector< double > const &lnK)
Definition: Mixtures.cpp:1243
double d2nphir_dni_dxj__constT_V(double tau, double delta, const std::vector< double > &x, int i, int j)
Gernert Equation 3.117.
Definition: Mixtures.cpp:1027
double dgdbeta_RachfordRice(const std::vector< double > &z, const std::vector< double > &lnK, double beta)
Definition: Mixtures.cpp:1558
Mixture * Mix
Pointer to the Mixture class instance.
Definition: Mixtures.h:311
int Nstep_max
The maximum number of steps to take, can be changed as needed.
Definition: Mixtures.h:310
std::vector< std::string > strsplit(std::string s, char del)
double d2phir_dDelta2(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2131
std::vector< std::vector< double > > F
Definition: Mixtures.h:251
Mixture * Mix
Definition: Mixtures.cpp:1255
std::vector< std::vector< DepartureFunction * > > DepartureFunctionMatrix
Definition: Mixtures.h:250
bool double_equal(double a, double b)
std::vector< double > y
Definition: Mixtures.h:314
double rhobar_vap
Definition: Mixtures.h:334
ExcessTerm(int N)
Definition: Mixtures.cpp:2075
double phir(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2095
ResidualIdealMixture(std::vector< Fluid * > pFluids)
Definition: Mixtures.cpp:2219
#define DBL_EPSILON
Definition: Helmholtz.cpp:10
std::vector< std::vector< double > > y
Definition: Mixtures.h:395
double dphir_dTau(double tau, double delta)
Definition: Mixtures.cpp:2019
double d2phir_dTau2(double tau, double delta)
Definition: Mixtures.cpp:2034
void check_WaterEthanol()
Definition: Mixtures.cpp:462
The derivative of reduced temperature with respect to component i mole fraction double dTrdxi__constxj(const std::vector< double > &x, int i)
The derivative of reduced temperature with respect to component i mole fraction.
Definition: Mixtures.cpp:1588
double d2Trdxidxj(const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1617
void build(double p0, const std::vector< double > &z, double beta_envelope)
Definition: Mixtures.cpp:2613
double rhobar_liq
Definition: Mixtures.h:431
double dln_fugacity_coefficient_dp__constT_n(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:982
double d2phir_dTau2(double tau, double delta)
Definition: Mixtures.cpp:1887
void resize(unsigned int N)
Definition: Mixtures.cpp:2405
void add(std::string key, double value)
Add a floating point value to the dictionary.
Definition: MPLPlot.h:21
unsigned int N
Definition: Mixtures.h:249
double dphir_dDelta(double tau, double delta)
Definition: Mixtures.cpp:1973
std::string mixture_reducing_JSON
double deriv(double beta)
Definition: Mixtures.cpp:1245
std::vector< double > x
Definition: Mixtures.h:314
double dpdT__constV_n(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1060
std::string format(const char *fmt,...)
#define CAPTURE(msg)
Definition: catch.hpp:8074
double call(double T)
Definition: Mixtures.cpp:1320
double d2phir_dDelta_dTau(double tau, double delta)
Definition: Mixtures.cpp:1843
virtual void set_coeffs_from_map(int i, int j, std::map< std::string, double >)=0
Set the coefficients based on reducing parameters loaded from JSON.
DepartureFunctionCache cache
Definition: Mixtures.h:213
double rhobar_liq
The molar density of the liquid phase [mol/m^3].
Definition: Mixtures.h:312
std::vector< double > y
Definition: Mixtures.h:341
PengRobinsonOptions
Definition: Mixtures.cpp:308
double dfYikdxi__constxk(const std::vector< double > &x, int i, int k, std::vector< std::vector< double > > *beta)
Definition: Mixtures.cpp:1711
void pre_call()
Definition: Mixtures.h:349
bool IsArray() const
Definition: document.h:199
std::vector< std::vector< double > > STLMatrix
Definition: Mixtures.h:10
TEST_CASE("Mixture derivative checks","")
Definition: Mixtures.cpp:2930
STLMatrix gamma_T
from GERG-2008
Definition: Mixtures.h:70
double Wilson_lnK_factor(double T, double p, int i)
Definition: Mixtures.cpp:931
void TpzFlash(double T, double p, const std::vector< double > &z, double &rhobar, std::vector< double > &x, std::vector< double > &y)
Definition: Mixtures.cpp:1400
double QuadInterp(double x0, double x1, double x2, double f0, double f1, double f2, double x)
std::vector< double > ln_phi_liq
Definition: Mixtures.h:314
STLMatrix J
Definition: Mixtures.h:340
void store_variables(const double T, const double p, const double rhobar_liq, const double rhobar_vap, const std::vector< double > &K, const int iS, const std::vector< double > &x, const std::vector< double > &y, const unsigned int N)
Definition: Mixtures.h:399
std::map< std::string, double > load_reducing_values(int i, int j)
Definition: Mixtures.cpp:78
virtual double Tr(const std::vector< double > &x)=0
The reduced temperature.
double d2fYkidxi2__constxk(const std::vector< double > &x, int k, int i, std::vector< std::vector< double > > *beta)
Definition: Mixtures.cpp:1734
std::vector< double > x(ncmax, 0)
double dphir_dDelta(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:1214
const std::vector< double > * z
Definition: Mixtures.cpp:1312
double dphir_dDelta
Definition: Mixtures.cpp:1252
double dphir_dTau(double tau, double delta)
Definition: Mixtures.cpp:1865
double ndpdV__constT_n(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1066
ResidualIdealMixture * pResidualIdealMix
Definition: Mixtures.h:457
DepartureFunctionCache cache
Definition: Mixtures.h:232
std::vector< std::vector< double > > linsolve(std::vector< std::vector< double > > const &A, std::vector< std::vector< double > > const &B)
Definition: MatrixMath.cpp:185
double d2phir_dDelta2(double tau, double delta)
Definition: Mixtures.cpp:1988
double call(double beta)
Definition: Mixtures.cpp:1244
std::vector< Fluid * > pFluids
Definition: Mixtures.h:272
double d2phir_dDelta_dTau(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2155
double evaluate(double x)
Definition: Spline.cpp:62
Mixture * Mix
Definition: Mixtures.h:433
double dTau2(double tau, double delta)
Definition: Helmholtz.cpp:148
std::vector< double > lnT
Definition: Mixtures.h:396
double d2phir_dTau2(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:1226
double phir(double tau, double delta)
Definition: Mixtures.cpp:1780
double d_dphirddelta_dxj__constT_V_xi(double tau, double delta, const std::vector< double > &x, int j)
Definition: Mixtures.cpp:1020
DepartureFunctionCacheElement d2phir_dTau2
Definition: Mixtures.h:206
double rhobar_Tpz(double T, double p, const std::vector< double > &z, double rhobar0)
Definition: Mixtures.cpp:1277
A document for parsing JSON text as DOM.
Definition: document.h:691
double dDelta2(double tau, double delta)
Definition: Helmholtz.cpp:208
double dphir_dxi(double tau, double delta, const std::vector< double > &x, unsigned int i)
Definition: Mixtures.cpp:2167
void add_4value_constraints(double x1, double x2, double x3, double x4, double y1, double y2, double y3, double y4)
Definition: Spline.cpp:42
double Rbar(const std::vector< double > &x)
Definition: Mixtures.cpp:310
void initialize()
Definition: Mixtures.cpp:350
double ndpdni__constT_V_nj(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1074
std::vector< double > rhobar_liq
Definition: Mixtures.h:396
virtual double drhorbardxi__constxj(const std::vector< double > &x, int i)=0
Derivative of the molar reducing density with respect to component i mole fraction.
A wrapper function around the density(T,p,x) residual.
Definition: Mixtures.cpp:1249
double Newton(FuncWrapper1D *f, double x0, double ftol, int maxiter, std::string *errstring)
Definition: Solvers.cpp:85
double dln_fugacity_coefficient_dT__constp_n(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:971
std::vector< double > lnrhobar_vap
Definition: Mixtures.h:396
double d2phir_dDelta_dTau(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2251
unsigned int N
Definition: Mixtures.h:271
virtual double d2Trdxidxj(const std::vector< double > &x, int i, int j)=0
std::string vec_to_string(double const &a)
Definition: MatrixMath.cpp:359
void set_coeffs_from_map(std::map< std::string, std::vector< double > >)
Definition: Mixtures.cpp:1910
double d2vrbardxidxj(const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1645
double d2Trdxi2__constxj(const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1603
unsigned int N
Definition: Mixtures.h:335
void to_python_files(std::string fname)
Definition: Mixtures.cpp:2893
virtual double dTrdxi__constxj(const std::vector< double > &x, int i)=0
The derivative of reduced temperature with respect to component i mole fraction.
std::vector< double > K
Definition: Mixtures.cpp:1313
bool has_string_array_member(const rapidjson::Value &a, const char *member)
Definition: Mixtures.cpp:22
void show()
Definition: MPLPlot.h:126
double d2phir_dDelta2(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2242
std::vector< Fluid * > pFluids
List of pointers to fluids.
Definition: Mixtures.h:159
double dfYkidxi__constxk(const std::vector< double > &x, int k, int i, std::vector< std::vector< double > > *beta)
Definition: Mixtures.cpp:1706
DepartureFunctionCacheElement d2phir_dDelta2
Definition: Mixtures.h:206
double d_ndphirdni_dTau(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1174
double dpdxj__constT_V_xi(double tau, double delta, const std::vector< double > &x, int j)
Definition: Mixtures.cpp:1009
REQUIRE(fabs(CPWater.p()-RPWater.p())< 1e-4)
double dphir_dDelta(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2233
double dTau2(double tau, double delta)
Definition: Helmholtz.cpp:1093
void load_excess_values(int i, int j)
Definition: Mixtures.cpp:184
double d2phirdxidxj(double tau, double delta, const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1202
std::vector< double > neg_dFdS
Definition: Mixtures.h:341
double d2phir_dxi_dTau(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1206
void test()
Definition: Mixtures.cpp:391
A wrapper function around the Rachford-Rice residual.
Definition: Mixtures.cpp:1236
double dphir_dTau(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:1230
double error_rms
Definition: Mixtures.h:334
double partial_molar_volume(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:977
STLMatrix beta_T
from GERG-2008
Definition: Mixtures.h:69
double rhorbar
Definition: Mixtures.cpp:1252
double base(double tau, double delta)
Definition: Helmholtz.cpp:130
PhaseEnvelopeLog bubble
Definition: Mixtures.h:430
std::vector< double > x
Definition: Mixtures.h:341
double rhobar_liq
Definition: Mixtures.h:334
std::vector< double > phi_ij_liq
Definition: Mixtures.h:341
std::vector< double > JSON_double_array(const rapidjson::Value &a)
Definition: Mixtures.cpp:41
double Secant(FuncWrapper1D *f, double x0, double dx, double tol, int maxiter, std::string *errstring)
Definition: Solvers.cpp:123
The reduced temperature double Tr(const std::vector< double > &x)
The reduced temperature.
Definition: Mixtures.cpp:1570
bool HasMember(const Ch *name) const
Check whether a member exists in the object.
Definition: document.h:249
Mixture * Mix
Definition: Mixtures.cpp:1241
double dln_fugacity_coefficient_dT__constrho(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:953
const std::vector< double > * x
Definition: Mixtures.cpp:1254
int Kronecker_delta(int i, int j)
std::vector< double > p
Definition: Mixtures.h:396
void solve_cubic(double a, double b, double c, double d, double *x0, double *x1, double *x2)
double d2rhorbardxidxj(const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:1681
DepartureFunctionCacheElement phir
Definition: Mixtures.h:206
double d2phir_dDelta_dTau(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:1222
void set_coeffs_from_map(std::map< std::string, std::vector< double > >)
Definition: Mixtures.cpp:2051
double saturation_p_Wilson(double beta, double p, const std::vector< double > &z, double T_guess, std::vector< double > &K)
Definition: Mixtures.cpp:1348
double phir(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:1194
Mixture(std::vector< Fluid * > pFluids)
Definition: Mixtures.cpp:319
double d2fYikdxi2__constxk(const std::vector< double > &x, int i, int k, std::vector< std::vector< double > > *beta)
Definition: Mixtures.cpp:1729
PhaseEnvelopeLog dew
Definition: Mixtures.h:430
#define SECTION(name, description)
Definition: catch.hpp:8088
STLMatrix beta_v
from GERG-2008
Definition: Mixtures.h:67
void check_MethaneEthane()
Definition: Mixtures.cpp:691
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
Definition: document.h:30
void set_coeffs_from_map(int i, int j, std::map< std::string, std::vector< double > >)
Definition: Mixtures.cpp:2214
std::vector< Fluid * > pFluids
List of pointers to fluids.
Definition: Mixtures.h:71
double call(double beta, double T, double p, double rhobar_liq, double rhobar_vap, const std::vector< double > &z, std::vector< double > &K, int spec_index, double spec_value)
Definition: Mixtures.cpp:2424
STLMatrix gamma_v
from GERG-2008
Definition: Mixtures.h:68
double d_ndrhorbardni_dxj__constxi(const std::vector< double > &x, int i, int j)
Definition: Mixtures.cpp:2287
void normalize_vector(std::vector< double > &x)
Definition: Mixtures.cpp:298
std::vector< std::string > JSON_string_array(const rapidjson::Value &a)
Definition: Mixtures.cpp:57
PhaseEnvelope Envelope
Definition: Mixtures.h:459
double call(double beta, double T, double p, const std::vector< double > &z, std::vector< double > &K)
Definition: Mixtures.cpp:2316
bool match_CAS_entry(std::vector< std::string > CAS1, std::vector< std::string > CAS2, std::string FluidiCAS, std::string FluidjCAS)
Definition: Mixtures.cpp:66
double c_Y_ji(int j, int i, std::vector< std::vector< double > > *beta, std::vector< std::vector< double > > *gamma, std::vector< std::vector< double > > *Y_c)
Definition: Mixtures.cpp:1720
rho_Tpz_resid(Mixture *Mix, double T, double p, const std::vector< double > &x)
Definition: Mixtures.cpp:1257
double deriv(double rhobar)
Definition: Mixtures.cpp:1271
double d2phir_dTau2(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2269
double phir(double tau, double delta)
Definition: Mixtures.cpp:1958
const Ch * GetString() const
Definition: document.h:447
double phir(double tau, double delta, const std::vector< double > &x)
Definition: Mixtures.cpp:2224
std::vector< std::vector< double > > x
Definition: Mixtures.h:395
The molar reducing density double rhorbar(const std::vector< double > &x)
The molar reducing density.
Definition: Mixtures.cpp:1689
std::vector< double > r
Definition: Mixtures.h:341
Derivative of the molar reducing density with respect to component i mole fraction double drhorbardxi__constxj(const std::vector< double > &x, int i)
Derivative of the molar reducing density with respect to component i mole fraction.
Definition: Mixtures.cpp:1656
unsigned int N
Definition: Mixtures.h:20
double d2phirdxidxj(double tau, double delta, const std::vector< double > &x, unsigned int i, unsigned int j)
Definition: Mixtures.cpp:2179
double base(double tau, double delta)
Definition: Helmholtz.cpp:1053
bool build(void)
Definition: Spline.cpp:13
#define CHECK(expr)
Definition: catch.hpp:8058
double dphir_dxj__constT_V_xi(double tau, double delta, const std::vector< double > &x, int j)
Definition: Mixtures.cpp:1032
double d2phir_dxi_dDelta(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1210
double dphir_dDelta(double tau, double delta)
Definition: Mixtures.cpp:1801
double ln_fugacity_coefficient(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:949
bool useNR
If true (default is false), will call Newton-Raphson after either solving to tolerance, or taking Nmax steps.
Definition: Mixtures.h:307
bool ValidNumber(double x)
double ndphir_dni__constT_V_nj(double tau, double delta, const std::vector< double > &x, int i)
Definition: Mixtures.cpp:1092
double d2phir_dxi_dTau(double tau, double delta, const std::vector< double > &x, unsigned int i)
Definition: Mixtures.cpp:2190
std::vector< double > K
Definition: Mixtures.h:432
DepartureFunctionCacheElement d2phir_dDelta_dTau
Definition: Mixtures.h:206
std::vector< double > K
Definition: Mixtures.h:341
double rhobar_vap
Definition: Mixtures.h:431
WilsonK_resid(Mixture *Mix, double beta, double p, std::vector< double > const &z)
Definition: Mixtures.cpp:1316
std::vector< double > ln_phi_vap
Definition: Mixtures.h:314
double dTau(double tau, double delta)
Definition: Helmholtz.cpp:1083
virtual const char * what() const
Definition: CPExceptions.h:16
void plot(std::vector< double > x, std::vector< double > y, Dictionary *dict=NULL)
Definition: MPLPlot.h:111
ExcessTerm * pExcess
Definition: Mixtures.h:456