Cantera  2.1.2
IdealMolalSoln.cpp
Go to the documentation of this file.
1 /**
2  * @file IdealMolalSoln.cpp
3  * ThermoPhase object for the ideal molal equation of
4  * state (see \ref thermoprops
5  * and class \link Cantera::IdealMolalSoln IdealMolalSoln\endlink).
6  *
7  * Definition file for a derived class of ThermoPhase that handles
8  * variable pressure standard state methods for calculating
9  * thermodynamic properties that are further based upon
10  * activities on the molality scale. The Ideal molal
11  * solution assumes that all molality-based activity
12  * coefficients are equal to one. This turns out, actually, to be
13  * highly nonlinear when the solvent densities get low.
14  */
15 /*
16  * Copyright (2006) Sandia Corporation. Under the terms of
17  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
18  * U.S. Government retains certain rights in this software.
19  */
22 
23 using namespace ctml;
24 
25 namespace Cantera
26 {
27 
28 IdealMolalSoln::IdealMolalSoln() :
30  m_formGC(2),
31  IMS_typeCutoff_(0),
32  IMS_X_o_cutoff_(0.20),
33  IMS_gamma_o_min_(0.00001),
34  IMS_gamma_k_min_(10.0),
35  IMS_slopefCut_(0.6),
36  IMS_slopegCut_(0.0),
37  IMS_cCut_(.05),
38  IMS_dfCut_(0.0),
39  IMS_efCut_(0.0),
40  IMS_afCut_(0.0),
41  IMS_bfCut_(0.0),
42  IMS_dgCut_(0.0),
43  IMS_egCut_(0.0),
44  IMS_agCut_(0.0),
45  IMS_bgCut_(0.0)
46 {
47 }
48 
51 {
52  /*
53  * Use the assignment operator to do the brunt
54  * of the work for the copy constructor.
55  */
56  *this = b;
57 }
58 
61 {
62  if (&b != this) {
65  m_formGC = b.m_formGC;
70  IMS_cCut_ = b.IMS_cCut_;
72  IMS_dfCut_ = b.IMS_dfCut_;
73  IMS_efCut_ = b.IMS_efCut_;
74  IMS_afCut_ = b.IMS_afCut_;
75  IMS_bfCut_ = b.IMS_bfCut_;
77  IMS_dgCut_ = b.IMS_dgCut_;
78  IMS_egCut_ = b.IMS_egCut_;
79  IMS_agCut_ = b.IMS_agCut_;
80  IMS_bgCut_ = b.IMS_bgCut_;
81  m_pp = b.m_pp;
82  m_tmpV = b.m_tmpV;
84  }
85  return *this;
86 }
87 
88 IdealMolalSoln::IdealMolalSoln(const std::string& inputFile,
89  const std::string& id_) :
91  m_formGC(2),
92  IMS_typeCutoff_(0),
93  IMS_X_o_cutoff_(0.2),
94  IMS_gamma_o_min_(0.00001),
95  IMS_gamma_k_min_(10.0),
96  IMS_slopefCut_(0.6),
97  IMS_slopegCut_(0.0),
98  IMS_cCut_(.05),
99  IMS_dfCut_(0.0),
100  IMS_efCut_(0.0),
101  IMS_afCut_(0.0),
102  IMS_bfCut_(0.0),
103  IMS_dgCut_(0.0),
104  IMS_egCut_(0.0),
105  IMS_agCut_(0.0),
106  IMS_bgCut_(0.0)
107 {
108  initThermoFile(inputFile, id_);
109 }
110 
111 IdealMolalSoln::IdealMolalSoln(XML_Node& root, const std::string& id_) :
112  MolalityVPSSTP(),
113  m_formGC(2),
114  IMS_typeCutoff_(0),
115  IMS_X_o_cutoff_(0.2),
116  IMS_gamma_o_min_(0.00001),
117  IMS_gamma_k_min_(10.0),
118  IMS_slopefCut_(0.6),
119  IMS_slopegCut_(0.0),
120  IMS_cCut_(.05),
121  IMS_dfCut_(0.0),
122  IMS_efCut_(0.0),
123  IMS_afCut_(0.0),
124  IMS_bfCut_(0.0),
125  IMS_dgCut_(0.0),
126  IMS_egCut_(0.0),
127  IMS_agCut_(0.0),
128  IMS_bgCut_(0.0)
129 {
130  importPhase(*findXMLPhase(&root, id_), this);
131 }
132 
134 {
135  return new IdealMolalSoln(*this);
136 }
137 
139 {
142  return mean_X(DATA_PTR(m_tmpV));
143 }
144 
146 {
148  return mean_X(DATA_PTR(m_tmpV));
149 }
150 
152 {
154  return mean_X(DATA_PTR(m_tmpV));
155 }
156 
157 doublereal IdealMolalSoln::gibbs_mole() const
158 {
160  return mean_X(DATA_PTR(m_tmpV));
161 }
162 
163 doublereal IdealMolalSoln::cp_mole() const
164 {
166  return mean_X(DATA_PTR(m_tmpV));
167 }
168 
169 doublereal IdealMolalSoln::cv_mole() const
170 {
171  return err("not implemented");
172 }
173 
174 //
175 // ------- Mechanical Equation of State Properties ------------------------
176 //
177 
178 void IdealMolalSoln::setPressure(doublereal p)
179 {
180  setState_TP(temperature(), p);
181 }
182 
184 {
185  double* vbar = &m_pp[0];
187  double* x = &m_tmpV[0];
188  getMoleFractions(x);
189  doublereal vtotal = 0.0;
190  for (size_t i = 0; i < m_kk; i++) {
191  vtotal += vbar[i] * x[i];
192  }
193  doublereal dd = meanMolecularWeight() / vtotal;
194  Phase::setDensity(dd);
195 }
196 
198 {
199  return 0.0;
200 }
201 
203 {
204  return 0.0;
205 }
206 
207 void IdealMolalSoln::setDensity(const doublereal rho)
208 {
209  double dens = density();
210  if (rho != dens) {
211  throw CanteraError("Idea;MolalSoln::setDensity",
212  "Density is not an independent variable");
213  }
214 }
215 
216 void IdealMolalSoln::setMolarDensity(const doublereal conc)
217 {
218  double concI = Phase::molarDensity();
219  if (conc != concI) {
220  throw CanteraError("IdealMolalSoln::setMolarDensity",
221  "molarDensity/denisty is not an independent variable");
222  }
223 }
224 
225 void IdealMolalSoln::setState_TP(doublereal temp, doublereal pres)
226 {
227  Phase::setTemperature(temp);
228  m_Pcurrent = pres;
230  //m_densWaterSS = m_waterSS->density();
231  calcDensity();
232 }
233 
234 //
235 // ------- Activities and Activity Concentrations
236 //
237 
239 {
240  if (m_formGC != 1) {
241  double c_solvent = standardConcentration();
242  getActivities(c);
243  for (size_t k = 0; k < m_kk; k++) {
244  c[k] *= c_solvent;
245  }
246  } else {
247  getActivities(c);
248  for (size_t k = 0; k < m_kk; k++) {
249  double c0 = standardConcentration(k);
250  c[k] *= c0;
251  }
252  }
253 }
254 
255 doublereal IdealMolalSoln::standardConcentration(size_t k) const
256 {
257  double c0 = 1.0, mvSolvent;
258  switch (m_formGC) {
259  case 0:
260  break;
261  case 1:
263  break;
264  case 2:
266  c0 = 1.0 / mvSolvent;
267  break;
268  }
269  return c0;
270 }
271 
272 doublereal IdealMolalSoln::logStandardConc(size_t k) const
273 {
274  double c0 = standardConcentration(k);
275  return log(c0);
276 }
277 
278 void IdealMolalSoln::getUnitsStandardConc(double* uA, int k, int sizeUA) const
279 {
280  int eos = eosType();
281  if (eos == 0) {
282  for (int i = 0; i < sizeUA; i++) {
283  uA[i] = 0.0;
284  }
285  } else {
286  for (int i = 0; i < sizeUA; i++) {
287  if (i == 0) {
288  uA[0] = 1.0;
289  }
290  if (i == 1) {
291  uA[1] = -int(nDim());
292  }
293  if (i == 2) {
294  uA[2] = 0.0;
295  }
296  if (i == 3) {
297  uA[3] = 0.0;
298  }
299  if (i == 4) {
300  uA[4] = 0.0;
301  }
302  if (i == 5) {
303  uA[5] = 0.0;
304  }
305  }
306  }
307 }
308 
309 void IdealMolalSoln::getActivities(doublereal* ac) const
310 {
312  /*
313  * Update the molality array, m_molalities()
314  * This requires an update due to mole fractions
315  */
316  if (IMS_typeCutoff_ == 0) {
317  calcMolalities();
318  for (size_t k = 0; k < m_kk; k++) {
319  ac[k] = m_molalities[k];
320  }
321  double xmolSolvent = moleFraction(m_indexSolvent);
322  // Limit the activity coefficient to be finite as the solvent mole
323  // fraction goes to zero.
324  xmolSolvent = std::max(m_xmolSolventMIN, xmolSolvent);
325  ac[m_indexSolvent] =
326  exp((xmolSolvent - 1.0)/xmolSolvent);
327  } else {
328 
330  /*
331  * Now calculate the array of activities.
332  */
333  for (size_t k = 1; k < m_kk; k++) {
334  ac[k] = m_molalities[k] * exp(IMS_lnActCoeffMolal_[k]);
335  }
336  double xmolSolvent = moleFraction(m_indexSolvent);
337  ac[m_indexSolvent] =
338  exp(IMS_lnActCoeffMolal_[m_indexSolvent]) * xmolSolvent;
339 
340  }
341 }
342 
343 void IdealMolalSoln::
344 getMolalityActivityCoefficients(doublereal* acMolality) const
345 {
346  if (IMS_typeCutoff_ == 0) {
347  for (size_t k = 0; k < m_kk; k++) {
348  acMolality[k] = 1.0;
349  }
350  double xmolSolvent = moleFraction(m_indexSolvent);
351  // Limit the activity coefficient to be finite as the solvent mole
352  // fraction goes to zero.
353  xmolSolvent = std::max(m_xmolSolventMIN, xmolSolvent);
354  acMolality[m_indexSolvent] =
355  exp((xmolSolvent - 1.0)/xmolSolvent) / xmolSolvent;
356  } else {
358  std::copy(IMS_lnActCoeffMolal_.begin(), IMS_lnActCoeffMolal_.end(), acMolality);
359  for (size_t k = 0; k < m_kk; k++) {
360  acMolality[k] = exp(acMolality[k]);
361  }
362  }
363 }
364 
365 //
366 // ------ Partial Molar Properties of the Solution -----------------
367 //
368 
369 void IdealMolalSoln::getChemPotentials(doublereal* mu) const
370 {
371  double xx;
372 
373  // Assertion is made for speed
374  AssertThrow(m_indexSolvent == 0, "solvent not the first species");
375 
376  /*
377  * First get the standard chemical potentials
378  * -> this requires updates of standard state as a function
379  * of T and P
380  * These are defined at unit molality.
381  */
383  /*
384  * Update the molality array, m_molalities()
385  * This requires an update due to mole fractions
386  */
387  calcMolalities();
388  /*
389  * get the solvent mole fraction
390  */
391  double xmolSolvent = moleFraction(m_indexSolvent);
392  doublereal RT = GasConstant * temperature();
393 
394  if (IMS_typeCutoff_ == 0 || xmolSolvent > 3.* IMS_X_o_cutoff_/2.0) {
395 
396  for (size_t k = 1; k < m_kk; k++) {
397  xx = std::max(m_molalities[k], SmallNumber);
398  mu[k] += RT * log(xx);
399  }
400  /*
401  * Do the solvent
402  * -> see my notes
403  */
404 
405  xx = std::max(xmolSolvent, SmallNumber);
406  mu[m_indexSolvent] +=
407  (RT * (xmolSolvent - 1.0) / xx);
408  } else {
409  /*
410  * Update the activity coefficients
411  * This also updates the internal molality array.
412  */
414 
415 
416  for (size_t k = 1; k < m_kk; k++) {
417  xx = std::max(m_molalities[k], SmallNumber);
418  mu[k] += RT * (log(xx) + IMS_lnActCoeffMolal_[k]);
419  }
420  xx = std::max(xmolSolvent, SmallNumber);
421  mu[m_indexSolvent] +=
422  RT * (log(xx) + IMS_lnActCoeffMolal_[m_indexSolvent]);
423  }
424 
425 }
426 
427 void IdealMolalSoln::getPartialMolarEnthalpies(doublereal* hbar) const
428 {
429  getEnthalpy_RT(hbar);
430  doublereal RT = _RT();
431  for (size_t k = 0; k < m_kk; k++) {
432  hbar[k] *= RT;
433  }
434 }
435 
436 void IdealMolalSoln::getPartialMolarEntropies(doublereal* sbar) const
437 {
438  getEntropy_R(sbar);
439  doublereal R = GasConstant;
440  calcMolalities();
441  if (IMS_typeCutoff_ == 0) {
442  for (size_t k = 0; k < m_kk; k++) {
443  if (k != m_indexSolvent) {
444  doublereal mm = std::max(SmallNumber, m_molalities[k]);
445  sbar[k] -= R * log(mm);
446  }
447  }
448  double xmolSolvent = moleFraction(m_indexSolvent);
449  sbar[m_indexSolvent] -= (R * (xmolSolvent - 1.0) / xmolSolvent);
450  } else {
451  /*
452  * Update the activity coefficients, This also update the
453  * internally stored molalities.
454  */
456  /*
457  * First we will add in the obvious dependence on the T
458  * term out front of the log activity term
459  */
460  doublereal mm;
461  for (size_t k = 0; k < m_kk; k++) {
462  if (k != m_indexSolvent) {
463  mm = std::max(SmallNumber, m_molalities[k]);
464  sbar[k] -= R * (log(mm) + IMS_lnActCoeffMolal_[k]);
465  }
466  }
467  double xmolSolvent = moleFraction(m_indexSolvent);
468  mm = std::max(SmallNumber, xmolSolvent);
469  sbar[m_indexSolvent] -= R *(log(mm) + IMS_lnActCoeffMolal_[m_indexSolvent]);
470 
471  }
472 }
473 
474 void IdealMolalSoln::getPartialMolarVolumes(doublereal* vbar) const
475 {
476  getStandardVolumes(vbar);
477 }
478 
479 void IdealMolalSoln::getPartialMolarCp(doublereal* cpbar) const
480 {
481  /*
482  * Get the nondimensional gibbs standard state of the
483  * species at the T and P of the solution.
484  */
485  getCp_R(cpbar);
486 
487  for (size_t k = 0; k < m_kk; k++) {
488  cpbar[k] *= GasConstant;
489  }
490 }
491 
492 /*
493  * -------------- Utilities -------------------------------
494  */
495 
497 {
498  initLengths();
500 }
501 
502 void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, const std::string& id_)
503 {
504  /*
505  * Find the Thermo XML node
506  */
507  if (!phaseNode.hasChild("thermo")) {
508  throw CanteraError("IdealMolalSoln::initThermoXML",
509  "no thermo XML node");
510  }
511 
512  /*
513  * Initialize the whole thermo object, using a virtual function.
514  */
515  initThermo();
516 
517  if (id_.size() > 0) {
518  std::string idp = phaseNode.id();
519  if (idp != id_) {
520  throw CanteraError("IdealMolalSoln::initThermo",
521  "phasenode and Id are incompatible");
522  }
523  }
524 
525  /*
526  * Find the Thermo XML node
527  */
528  if (!phaseNode.hasChild("thermo")) {
529  throw CanteraError("IdealMolalSoln::initThermo",
530  "no thermo XML node");
531  }
532  XML_Node& thermoNode = phaseNode.child("thermo");
533 
534  /*
535  * Possible change the form of the standard concentrations
536  */
537  if (thermoNode.hasChild("standardConc")) {
538  XML_Node& scNode = thermoNode.child("standardConc");
539  m_formGC = 2;
540  std::string formString = scNode.attrib("model");
541  if (formString != "") {
542  if (formString == "unity") {
543  m_formGC = 0;
544  } else if (formString == "molar_volume") {
545  m_formGC = 1;
546  } else if (formString == "solvent_volume") {
547  m_formGC = 2;
548  } else {
549  throw CanteraError("IdealMolalSoln::initThermo",
550  "Unknown standardConc model: " + formString);
551  }
552  }
553  }
554 
555  /*
556  * Get the Name of the Solvent:
557  * <solvent> solventName </solvent>
558  */
559  std::string solventName = "";
560  if (thermoNode.hasChild("solvent")) {
561  XML_Node& scNode = thermoNode.child("solvent");
562  std::vector<std::string> nameSolventa;
563  getStringArray(scNode, nameSolventa);
564  int nsp = static_cast<int>(nameSolventa.size());
565  if (nsp != 1) {
566  throw CanteraError("IdealMolalSoln::initThermoXML",
567  "badly formed solvent XML node");
568  }
569  solventName = nameSolventa[0];
570  }
571 
572  if (thermoNode.hasChild("activityCoefficients")) {
573  XML_Node& acNode = thermoNode.child("activityCoefficients");
574  std::string modelString = acNode.attrib("model");
575  IMS_typeCutoff_ = 0;
576  if (modelString != "IdealMolalSoln") {
577  throw CanteraError("IdealMolalSoln::initThermoXML",
578  "unknown ActivityCoefficient model: " + modelString);
579  }
580  if (acNode.hasChild("idealMolalSolnCutoff")) {
581  XML_Node& ccNode = acNode.child("idealMolalSolnCutoff");
582  modelString = ccNode.attrib("model");
583  if (modelString != "") {
584  if (modelString == "polyExp") {
585  IMS_typeCutoff_ = 2;
586  } else if (modelString == "poly") {
587  IMS_typeCutoff_ = 1;
588  } else {
589  throw CanteraError("IdealMolalSoln::initThermoXML",
590  "Unknown idealMolalSolnCutoff form: " + modelString);
591  }
592 
593  if (ccNode.hasChild("gamma_o_limit")) {
594  IMS_gamma_o_min_ = getFloat(ccNode, "gamma_o_limit");
595  }
596  if (ccNode.hasChild("gamma_k_limit")) {
597  IMS_gamma_k_min_ = getFloat(ccNode, "gamma_k_limit");
598  }
599  if (ccNode.hasChild("X_o_cutoff")) {
600  IMS_X_o_cutoff_ = getFloat(ccNode, "X_o_cutoff");
601  }
602  if (ccNode.hasChild("c_0_param")) {
603  IMS_cCut_ = getFloat(ccNode, "c_0_param");
604  }
605  if (ccNode.hasChild("slope_f_limit")) {
606  IMS_slopefCut_ = getFloat(ccNode, "slope_f_limit");
607  }
608  if (ccNode.hasChild("slope_g_limit")) {
609  IMS_slopegCut_ = getFloat(ccNode, "slope_g_limit");
610  }
611 
612  }
613  }
614  }
615 
616 
617  /*
618  * Reconcile the solvent name and index.
619  */
620  for (size_t k = 0; k < m_kk; k++) {
621  std::string sname = speciesName(k);
622  if (solventName == sname) {
623  m_indexSolvent = k;
624  break;
625  }
626  }
627  if (m_indexSolvent == npos) {
628  std::cout << "IdealMolalSoln::initThermo: Solvent Name not found"
629  << std::endl;
630  throw CanteraError("IdealMolalSoln::initThermo",
631  "Solvent name not found");
632  }
633  if (m_indexSolvent != 0) {
634  throw CanteraError("IdealMolalSoln::initThermo",
635  "Solvent " + solventName +
636  " should be first species");
637  }
638 
639 
640  /*
641  * Now go get the molar volumes
642  */
643  XML_Node& speciesList = phaseNode.child("speciesArray");
644  XML_Node* speciesDB =
645  get_XML_NameID("speciesData", speciesList["datasrc"],
646  &phaseNode.root());
647  const std::vector<std::string> &sss = speciesNames();
648 
649  for (size_t k = 0; k < m_kk; k++) {
650  XML_Node* s = speciesDB->findByAttr("name", sss[k]);
651  XML_Node* ss = s->findByName("standardState");
652  m_speciesMolarVolume[k] = getFloat(*ss, "molarVolume", "toSI");
653  }
654 
655  IMS_typeCutoff_ = 2;
656  if (IMS_typeCutoff_ == 2) {
658  }
659 
660  MolalityVPSSTP::initThermoXML(phaseNode, id_);
661 
662 
663  setMoleFSolventMin(1.0E-5);
664  /*
665  * Set the state
666  */
667  if (phaseNode.hasChild("state")) {
668  XML_Node& stateNode = phaseNode.child("state");
669  setStateFromXML(stateNode);
670  }
671 
672 }
673 
674 void IdealMolalSoln::setParameters(int n, doublereal* const c)
675 {
676  warn_deprecated("IdealMolalSoln::setParameters");
677 }
678 
679 void IdealMolalSoln::getParameters(int& n, doublereal* const c) const
680 {
681  warn_deprecated("IdealMolalSoln::getParameters");
682 }
683 
685 {
686 }
687 
688 /*
689  * ------------ Private and Restricted Functions ------------------
690  */
691 
692 /*
693  * Bail out of functions with an error exit if they are not
694  * implemented.
695  */
696 doublereal IdealMolalSoln::err(const std::string& msg) const
697 {
698  throw CanteraError("IdealMolalSoln",
699  "Unfinished func called: " + msg);
700  return 0.0;
701 }
702 
704 {
705  double tmp;
706  /*
707  * Calculate the molalities. Currently, the molalities
708  * may not be current with respect to the contents of the
709  * State objects' data.
710  */
711  calcMolalities();
712 
713  double xmolSolvent = moleFraction(m_indexSolvent);
714  double xx = std::max(m_xmolSolventMIN, xmolSolvent);
715 
716  if (IMS_typeCutoff_ == 0) {
717  for (size_t k = 1; k < m_kk; k++) {
718  IMS_lnActCoeffMolal_[k]= 0.0;
719  }
720  IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
721  return;
722  } else if (IMS_typeCutoff_ == 1) {
723  if (xmolSolvent > 3.0 * IMS_X_o_cutoff_/2.0) {
724  for (size_t k = 1; k < m_kk; k++) {
725  IMS_lnActCoeffMolal_[k]= 0.0;
726  }
727  IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
728  return;
729  } else if (xmolSolvent < IMS_X_o_cutoff_/2.0) {
730  tmp = log(xx * IMS_gamma_k_min_);
731  for (size_t k = 1; k < m_kk; k++) {
732  IMS_lnActCoeffMolal_[k]= tmp;
733  }
735  return;
736  } else {
737 
738  /*
739  * If we are in the middle region, calculate the connecting polynomials
740  */
741  double xminus = xmolSolvent - IMS_X_o_cutoff_/2.0;
742  double xminus2 = xminus * xminus;
743  double xminus3 = xminus2 * xminus;
744  double x_o_cut2 = IMS_X_o_cutoff_ * IMS_X_o_cutoff_;
745  double x_o_cut3 = x_o_cut2 * IMS_X_o_cutoff_;
746 
747  double h2 = 3.5 * xminus2 / IMS_X_o_cutoff_ - 2.0 * xminus3 / x_o_cut2;
748  double h2_prime = 7.0 * xminus / IMS_X_o_cutoff_ - 6.0 * xminus2 / x_o_cut2;
749 
750  double h1 = (1.0 - 3.0 * xminus2 / x_o_cut2 + 2.0 * xminus3/ x_o_cut3);
751  double h1_prime = (- 6.0 * xminus / x_o_cut2 + 6.0 * xminus2/ x_o_cut3);
752 
753  double h1_g = h1 / IMS_gamma_o_min_;
754  double h1_g_prime = h1_prime / IMS_gamma_o_min_;
755 
756  double alpha = 1.0 / (exp(1.0) * IMS_gamma_k_min_);
757  double h1_f = h1 * alpha;
758  double h1_f_prime = h1_prime * alpha;
759 
760  double f = h2 + h1_f;
761  double f_prime = h2_prime + h1_f_prime;
762 
763  double g = h2 + h1_g;
764  double g_prime = h2_prime + h1_g_prime;
765 
766  tmp = (xmolSolvent/ g * g_prime + (1.0-xmolSolvent) / f * f_prime);
767  double lngammak = -1.0 - log(f) + tmp * xmolSolvent;
768  double lngammao =-log(g) - tmp * (1.0-xmolSolvent);
769 
770  tmp = log(xmolSolvent) + lngammak;
771  for (size_t k = 1; k < m_kk; k++) {
772  IMS_lnActCoeffMolal_[k]= tmp;
773  }
775  }
776  }
777 
778  // Exponentials - trial 2
779  else if (IMS_typeCutoff_ == 2) {
780  if (xmolSolvent > IMS_X_o_cutoff_) {
781  for (size_t k = 1; k < m_kk; k++) {
782  IMS_lnActCoeffMolal_[k]= 0.0;
783  }
784  IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
785  return;
786  } else {
787 
788  double xoverc = xmolSolvent/IMS_cCut_;
789  double eterm = std::exp(-xoverc);
790 
791  double fptmp = IMS_bfCut_ - IMS_afCut_ / IMS_cCut_ - IMS_bfCut_*xoverc
792  + 2.0*IMS_dfCut_*xmolSolvent - IMS_dfCut_*xmolSolvent*xoverc;
793  double f_prime = 1.0 + eterm*fptmp;
794  double f = xmolSolvent + IMS_efCut_ + eterm * (IMS_afCut_ + xmolSolvent * (IMS_bfCut_ + IMS_dfCut_*xmolSolvent));
795 
796  double gptmp = IMS_bgCut_ - IMS_agCut_ / IMS_cCut_ - IMS_bgCut_*xoverc
797  + 2.0*IMS_dgCut_*xmolSolvent - IMS_dgCut_*xmolSolvent*xoverc;
798  double g_prime = 1.0 + eterm*gptmp;
799  double g = xmolSolvent + IMS_egCut_ + eterm * (IMS_agCut_ + xmolSolvent * (IMS_bgCut_ + IMS_dgCut_*xmolSolvent));
800 
801  tmp = (xmolSolvent / g * g_prime + (1.0 - xmolSolvent) / f * f_prime);
802  double lngammak = -1.0 - log(f) + tmp * xmolSolvent;
803  double lngammao =-log(g) - tmp * (1.0-xmolSolvent);
804 
805  tmp = log(xx) + lngammak;
806  for (size_t k = 1; k < m_kk; k++) {
807  IMS_lnActCoeffMolal_[k]= tmp;
808  }
810  }
811  }
812  return;
813 }
814 
816 {
817  m_kk = nSpecies();
818  /*
819  * Obtain the limits of the temperature from the species
820  * thermo handler's limits.
821  */
822  m_pp.resize(m_kk);
823  m_speciesMolarVolume.resize(m_kk);
824  m_tmpV.resize(m_kk);
825  IMS_lnActCoeffMolal_.resize(m_kk);
826 }
827 
829 {
830  IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_);
831  IMS_efCut_ = 0.0;
832  bool converged = false;
833  double oldV = 0.0;
834  int its;
835  for (its = 0; its < 100 && !converged; its++) {
836  oldV = IMS_efCut_;
837  IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_) - IMS_efCut_;
838  IMS_bfCut_ = IMS_afCut_ / IMS_cCut_ + IMS_slopefCut_ - 1.0;
839  IMS_dfCut_ = ((- IMS_afCut_/IMS_cCut_ + IMS_bfCut_ - IMS_bfCut_*IMS_X_o_cutoff_/IMS_cCut_)
840  /
841  (IMS_X_o_cutoff_*IMS_X_o_cutoff_/IMS_cCut_ - 2.0 * IMS_X_o_cutoff_));
842  double tmp = IMS_afCut_ + IMS_X_o_cutoff_*(IMS_bfCut_ + IMS_dfCut_ * IMS_X_o_cutoff_);
843  double eterm = std::exp(-IMS_X_o_cutoff_/IMS_cCut_);
844  IMS_efCut_ = - eterm * (tmp);
845  if (fabs(IMS_efCut_ - oldV) < 1.0E-14) {
846  converged = true;
847  }
848  }
849  if (!converged) {
850  throw CanteraError(" IdealMolalSoln::calcCutoffParams_()",
851  " failed to converge on the f polynomial");
852  }
853  converged = false;
854  double f_0 = IMS_afCut_ + IMS_efCut_;
855  double f_prime_0 = 1.0 - IMS_afCut_ / IMS_cCut_ + IMS_bfCut_;
856  IMS_egCut_ = 0.0;
857  for (its = 0; its < 100 && !converged; its++) {
858  oldV = IMS_egCut_;
859  double lng_0 = -log(IMS_gamma_o_min_) - f_prime_0 / f_0;
860  IMS_agCut_ = exp(lng_0) - IMS_egCut_;
861  IMS_bgCut_ = IMS_agCut_ / IMS_cCut_ + IMS_slopegCut_ - 1.0;
862  IMS_dgCut_ = ((- IMS_agCut_/IMS_cCut_ + IMS_bgCut_ - IMS_bgCut_*IMS_X_o_cutoff_/IMS_cCut_)
863  /
864  (IMS_X_o_cutoff_*IMS_X_o_cutoff_/IMS_cCut_ - 2.0 * IMS_X_o_cutoff_));
865  double tmp = IMS_agCut_ + IMS_X_o_cutoff_*(IMS_bgCut_ + IMS_dgCut_ *IMS_X_o_cutoff_);
866  double eterm = std::exp(-IMS_X_o_cutoff_/IMS_cCut_);
867  IMS_egCut_ = - eterm * (tmp);
868  if (fabs(IMS_egCut_ - oldV) < 1.0E-14) {
869  converged = true;
870  }
871  }
872  if (!converged) {
873  throw CanteraError(" IdealMolalSoln::calcCutoffParams_()",
874  " failed to converge on the g polynomial");
875  }
876 }
877 
878 }
IdealMolalSoln & operator=(const IdealMolalSoln &)
Assignment operator.
XML_Node * findByAttr(const std::string &attr, const std::string &val, int depth=100000) const
This routine carries out a recursive search for an XML node based on an attribute of each XML node...
Definition: xml.cpp:716
ThermoPhase object for the ideal molal equation of state (see Thermodynamic Properties and class Idea...
virtual doublereal density() const
Density (kg/m^3).
Definition: Phase.h:534
virtual void setPressure(doublereal p)
Set the pressure at constant temperature.
XML_Node * findXMLPhase(XML_Node *root, const std::string &idtarget)
Search an XML_Node tree for a named phase XML_Node.
Definition: xml.cpp:1104
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:534
doublereal IMS_slopefCut_
Parameter in the polyExp cutoff treatment.
doublereal IMS_slopegCut_
Parameter in the polyExp cutoff treatment.
doublereal _RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:977
virtual void getStandardVolumes(doublereal *vol) const
Get the molar volumes of each species in their standard states at the current T and P of the solution...
IdealMolalSoln()
Constructor.
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:173
virtual void getPartialMolarVolumes(doublereal *vbar) const
virtual void getCp_R(doublereal *cpr) const
Get the nondimensional Heat Capacities at constant pressure for the standard state of the species at ...
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
virtual doublereal enthalpy_mole() const
Molar enthalpy of the solution. Units: J/kmol.
virtual void getActivityConcentrations(doublereal *c) const
vector_fp m_tmpV
vector of size m_kk, used as a temporary holding area.
virtual doublereal standardConcentration(size_t k=0) const
The standard concentration used to normalize the generalized concentration.
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
virtual void updateStandardStateThermo() const
Updates the standard state thermodynamic functions at the current T and P of the solution.
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
Definition: global.cpp:76
doublereal getFloat(const Cantera::XML_Node &parent, const std::string &name, const std::string &type)
Get a floating-point value from a child element.
Definition: ctml.cpp:267
ThermoPhase * duplMyselfAsThermoPhase() const
Duplication function.
doublereal IMS_gamma_k_min_
gamma_k minimum for the cutoff process at the zero solvent point
doublereal err(const std::string &msg) const
Internal error message.
void setDensity(const doublereal rho)
Overwritten setDensity() function is necessary because the density is not an independent variable...
doublereal molarDensity() const
Molar density (kmol/m^3).
Definition: Phase.cpp:597
void initLengths()
This internal function adjusts the lengths of arrays.
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:519
void setMolarDensity(const doublereal rho)
Overwritten setMolarDensity() function is necessary because the density is not an independent variabl...
doublereal IMS_gamma_o_min_
gamma_o value for the cutoff process at the zero solvent point
vector_fp m_pp
Temporary array used in equilibrium calculations.
vector_fp m_speciesMolarVolume
Species molar volume .
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:584
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
virtual doublereal gibbs_mole() const
Molar Gibbs function for the solution: Units J/kmol.
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:101
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials: Units: J/kmol.
doublereal mean_X(const doublereal *const Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
Definition: Phase.cpp:623
const XML_Node * findByName(const std::string &nm, int depth=100000) const
This routine carries out a recursive search for an XML node based on the name of the node...
Definition: xml.cpp:754
virtual void getActivities(doublereal *ac) const
bool importPhase(XML_Node &phase, ThermoPhase *th, SpeciesThermoFactory *spfactory)
Import a phase information into an empty thermophase object.
virtual doublereal isothermalCompressibility() const
The isothermal compressibility. Units: 1/Pa.
virtual void getUnitsStandardConc(double *uA, int k=0, int sizeUA=6) const
virtual doublereal cv_mole() const
Molar heat capacity of the solution at constant volume. Units: J/kmol/K.
void s_updateIMS_lnMolalityActCoeff() const
This function will be called to update the internally stored natural logarithm of the molality activi...
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id="")
Import and initialize an IdealMolalSoln phase specification in an XML tree into the current object...
virtual doublereal entropy_mole() const
Molar entropy of the solution. Units: J/kmol/K.
MolalityVPSSTP & operator=(const MolalityVPSSTP &b)
Assignment operator.
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution. Units: J/kmol...
virtual doublereal cp_mole() const
Molar heat capacity of the solution at constant pressure. Units: J/kmol/K.
#define AssertThrow(expr, procedure)
Assertion must be true or an error is thrown.
Definition: ctexceptions.h:229
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
virtual void getParameters(int &n, doublereal *const c) const
virtual doublereal intEnergy_mole() const
Molar internal energy of the solution: Units: J/kmol.
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:574
virtual void getPartialMolarCp(doublereal *cpbar) const
Partial molar heat capacity of the solution:. UnitsL J/kmol/K.
int IMS_typeCutoff_
Cutoff type.
virtual void setStateFromXML(const XML_Node &state)
Set equation of state parameter values from XML entries.
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:252
virtual doublereal logStandardConc(size_t k=0) const
const std::vector< std::string > & speciesNames() const
Return a const reference to the vector of species names.
Definition: Phase.cpp:252
doublereal moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition: Phase.cpp:524
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Enthalpy functions for the standard state species at the current T an...
doublereal temperature() const
Temperature (K).
Definition: Phase.h:528
size_t nDim() const
Returns the number of spatial dimensions (1, 2, or 3)
Definition: Phase.h:512
vector_fp m_molalities
Current value of the molalities of the species in the phase.
int m_formGC
The standard concentrations can have three different forms depending on the value of the member attri...
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:467
const doublereal SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:139
virtual void initThermo()
Initialization routine for an IdealMolalSoln phase.
void getStringArray(const Cantera::XML_Node &node, std::vector< std::string > &v)
This function interprets the value portion of an XML element as a string.
Definition: ctml.cpp:639
virtual void setTemperature(const doublereal temp)
Set the internally stored temperature of the phase (K).
Definition: Phase.h:562
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
virtual void getMolalityActivityCoefficients(doublereal *acMolality) const
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:588
void calcDensity()
Calculate the density of the mixture using the partial molar volumes and mole fractions as input...
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
Definition: ct_defs.h:66
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object.
virtual int eosType() const
Equation of state type flag.
size_t m_kk
Number of species in the phase.
Definition: Phase.h:716
virtual void initThermoFile(const std::string &inputFile, const std::string &id)
doublereal m_Pcurrent
Current value of the pressure - state variable.
This phase is based upon the mixing-rule assumption that all molality-based activity coefficients are...
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity.
XML_Node & root() const
Return the root of the current XML_Node tree.
Definition: xml.cpp:1091
size_t m_indexSolvent
Index of the solvent.
virtual void setParametersFromXML(const XML_Node &eosdata)
void calcIMSCutoffParams_()
Calculate parameters for cutoff treatments of activity coefficients.
virtual void setParameters(int n, doublereal *const c)
doublereal IMS_X_o_cutoff_
value of the solute mole fraction that centers the cutoff polynomials for the cutoff =1 process; ...
void calcMolalities() const
Calculates the molality of all species and stores the result internally.
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:246
XML_Node * get_XML_NameID(const std::string &nameTarget, const std::string &file_ID, XML_Node *root)
This routine will locate an XML node in either the input XML tree or in another input file specified ...
Definition: global.cpp:271
virtual void setDensity(const doublereal density_)
Set the internally stored density (kg/m^3) of the phase Note the density of a phase is an independent...
Definition: Phase.h:549
void setMoleFSolventMin(doublereal xmolSolventMIN)
Sets the minimum mole fraction in the molality formulation.
virtual doublereal thermalExpansionCoeff() const
The thermal expansion coefficient. Units: 1/K.
virtual void _updateStandardStateThermo() const
Updates the standard state thermodynamic functions at the current T and P of the solution.
vector_fp IMS_lnActCoeffMolal_
Logarithm of the molal activity coefficients.