Cantera  2.1.2
ThermoPhase.cpp
Go to the documentation of this file.
1 /**
2  * @file ThermoPhase.cpp
3  * Definition file for class ThermoPhase, the base class for phases with
4  * thermodynamic properties
5  * (see class \link Cantera::ThermoPhase ThermoPhase\endlink).
6  */
7 
8 // Copyright 2002 California Institute of Technology
9 
13 
14 #include <iomanip>
15 #include <fstream>
16 
17 using namespace std;
18 using namespace ctml;
19 
20 namespace Cantera
21 {
22 
23 ThermoPhase::ThermoPhase() :
24  Phase(),
25  m_spthermo(0), m_speciesData(0),
26  m_phi(0.0),
27  m_hasElementPotentials(false),
28  m_chargeNeutralityNecessary(false),
29  m_ssConvention(cSS_CONVENTION_TEMPERATURE)
30 {
31 }
32 
34 {
35  for (size_t k = 0; k < m_speciesData.size(); k++) {
36  delete m_speciesData[k];
37  }
38  delete m_spthermo;
39 }
40 
42  Phase(),
43  m_spthermo(0),
44  m_speciesData(0),
45  m_phi(0.0),
46  m_hasElementPotentials(false),
47  m_chargeNeutralityNecessary(false),
48  m_ssConvention(cSS_CONVENTION_TEMPERATURE)
49 {
50  /*
51  * Call the assignment operator
52  */
53  *this = operator=(right);
54 }
55 
57 operator=(const ThermoPhase& right)
58 {
59  /*
60  * Check for self assignment.
61  */
62  if (this == &right) {
63  return *this;
64  }
65 
66  /*
67  * We need to destruct first
68  */
69  for (size_t k = 0; k < m_speciesData.size(); k++) {
70  delete m_speciesData[k];
71  }
72  delete m_spthermo;
73 
74  /*
75  * Call the base class assignment operator
76  */
77  (void)Phase::operator=(right);
78 
79  /*
80  * Pointer to the species thermodynamic property manager
81  * We own this, so we need to do a deep copy
82  */
83  m_spthermo = (right.m_spthermo)->duplMyselfAsSpeciesThermo();
84 
85  /*
86  * Do a deep copy of species Data, because we own this
87  */
88  m_speciesData.resize(m_kk);
89  for (size_t k = 0; k < m_kk; k++) {
90  m_speciesData[k] = new XML_Node(*(right.m_speciesData[k]));
91  }
92 
93  m_phi = right.m_phi;
94  m_lambdaRRT = right.m_lambdaRRT;
98  return *this;
99 }
100 
102 {
103  return new ThermoPhase(*this);
104 }
105 
107 {
108  return cAC_CONVENTION_MOLAR;
109 }
110 
112 {
113  return m_ssConvention;
114 }
115 
116 doublereal ThermoPhase::logStandardConc(size_t k) const
117 {
118  return log(standardConcentration(k));
119 }
120 
121 void ThermoPhase::getActivities(doublereal* a) const
122 {
124  for (size_t k = 0; k < nSpecies(); k++) {
125  a[k] /= standardConcentration(k);
126  }
127 }
128 
129 void ThermoPhase::getLnActivityCoefficients(doublereal* lnac) const
130 {
132  for (size_t k = 0; k < m_kk; k++) {
133  lnac[k] = std::log(lnac[k]);
134  }
135 }
136 
137 void ThermoPhase::setState_TPX(doublereal t, doublereal p, const doublereal* x)
138 {
139  setMoleFractions(x);
140  setState_TP(t,p);
141 }
142 
143 void ThermoPhase::setState_TPX(doublereal t, doublereal p, compositionMap& x)
144 {
146  setState_TP(t,p);
147 }
148 
149 void ThermoPhase::setState_TPX(doublereal t, doublereal p, const std::string& x)
150 {
153  setState_TP(t,p);
154 }
155 
156 void ThermoPhase::setState_TPY(doublereal t, doublereal p,
157  const doublereal* y)
158 {
159  setMassFractions(y);
160  setState_TP(t,p);
161 }
162 
163 void ThermoPhase::setState_TPY(doublereal t, doublereal p,
164  compositionMap& y)
165 {
167  setState_TP(t,p);
168 }
169 
170 void ThermoPhase::setState_TPY(doublereal t, doublereal p,
171  const std::string& y)
172 {
175  setState_TP(t,p);
176 }
177 
178 void ThermoPhase::setState_TP(doublereal t, doublereal p)
179 {
180  setTemperature(t);
181  setPressure(p);
182 }
183 
184 void ThermoPhase::setState_PX(doublereal p, doublereal* x)
185 {
186  setMoleFractions(x);
187  setPressure(p);
188 }
189 
190 void ThermoPhase::setState_PY(doublereal p, doublereal* y)
191 {
192  setMassFractions(y);
193  setPressure(p);
194 }
195 
196 void ThermoPhase::setState_HP(doublereal Htarget, doublereal p,
197  doublereal dTtol)
198 {
199  setState_HPorUV(Htarget, p, dTtol, false);
200 }
201 
202 void ThermoPhase::setState_UV(doublereal u, doublereal v,
203  doublereal dTtol)
204 {
205  setState_HPorUV(u, v, dTtol, true);
206 }
207 
208 void ThermoPhase::setState_conditional_TP(doublereal t, doublereal p, bool set_p)
209 {
210  setTemperature(t);
211  if (set_p) {
212  setPressure(p);
213  }
214 }
215 
216 void ThermoPhase::setState_HPorUV(doublereal Htarget, doublereal p,
217  doublereal dTtol, bool doUV)
218 {
219  doublereal dt;
220  doublereal Hmax = 0.0, Hmin = 0.0;
221  doublereal v = 0.0;
222 
223  // Assign the specific volume or pressure and make sure it's positive
224  if (doUV) {
225  v = p;
226  if (v < 1.0E-300) {
227  throw CanteraError("setState_HPorUV (UV)",
228  "Input specific volume is too small or negative. v = " + fp2str(v));
229  }
230  setDensity(1.0/v);
231  } else {
232  if (p < 1.0E-300) {
233  throw CanteraError("setState_HPorUV (HP)",
234  "Input pressure is too small or negative. p = " + fp2str(p));
235  }
236  setPressure(p);
237  }
238  double Tmax = maxTemp() + 0.1;
239  double Tmin = minTemp() - 0.1;
240 
241  // Make sure we are within the temperature bounds at the start
242  // of the iteration
243  double Tnew = temperature();
244  double Tinit = Tnew;
245  if (Tnew > Tmax) {
246  Tnew = Tmax - 1.0;
247  } else if (Tnew < Tmin) {
248  Tnew = Tmin + 1.0;
249  }
250  if (Tnew != Tinit) {
251  setState_conditional_TP(Tnew, p, !doUV);
252  }
253 
254  double Hnew = (doUV) ? intEnergy_mass() : enthalpy_mass();
255  double Cpnew = (doUV) ? cv_mass() : cp_mass();
256  double Htop = Hnew;
257  double Ttop = Tnew;
258  double Hbot = Hnew;
259  double Tbot = Tnew;
260  double Told = Tnew;
261  double Hold = Hnew;
262 
263  bool ignoreBounds = false;
264  // Unstable phases are those for which
265  // cp < 0.0. These are possible for cases where
266  // we have passed the spinodal curve.
267  bool unstablePhase = false;
268  // Counter indicating the last temperature point where the
269  // phase was unstable
270  double Tunstable = -1.0;
271  bool unstablePhaseNew = false;
272 
273  // Newton iteration
274  for (int n = 0; n < 500; n++) {
275  Told = Tnew;
276  Hold = Hnew;
277  double cpd = Cpnew;
278  if (cpd < 0.0) {
279  unstablePhase = true;
280  Tunstable = Tnew;
281  }
282  // limit step size to 100 K
283  dt = clip((Htarget - Hold)/cpd, -100.0, 100.0);
284 
285  // Calculate the new T
286  Tnew = Told + dt;
287 
288  // Limit the step size so that we are convergent
289  // This is the step that makes it different from a
290  // Newton's algorithm
291  if ((dt > 0.0 && unstablePhase) || (dt <= 0.0 && !unstablePhase)) {
292  if (Hbot < Htarget && Tnew < (0.75 * Tbot + 0.25 * Told)) {
293  dt = 0.75 * (Tbot - Told);
294  Tnew = Told + dt;
295  }
296  } else if (Htop > Htarget && Tnew > (0.75 * Ttop + 0.25 * Told)) {
297  dt = 0.75 * (Ttop - Told);
298  Tnew = Told + dt;
299  }
300 
301  // Check Max and Min values
302  if (Tnew > Tmax && !ignoreBounds) {
303  setState_conditional_TP(Tmax, p, !doUV);
304  Hmax = (doUV) ? intEnergy_mass() : enthalpy_mass();
305  if (Hmax >= Htarget) {
306  if (Htop < Htarget) {
307  Ttop = Tmax;
308  Htop = Hmax;
309  }
310  } else {
311  Tnew = Tmax + 1.0;
312  ignoreBounds = true;
313  }
314  }
315  if (Tnew < Tmin && !ignoreBounds) {
316  setState_conditional_TP(Tmin, p, !doUV);
317  Hmin = (doUV) ? intEnergy_mass() : enthalpy_mass();
318  if (Hmin <= Htarget) {
319  if (Hbot > Htarget) {
320  Tbot = Tmin;
321  Hbot = Hmin;
322  }
323  } else {
324  Tnew = Tmin - 1.0;
325  ignoreBounds = true;
326  }
327  }
328 
329  // Try to keep phase within its region of stability
330  // -> Could do a lot better if I calculate the
331  // spinodal value of H.
332  for (int its = 0; its < 10; its++) {
333  Tnew = Told + dt;
334  if (Tnew < Told / 3.0) {
335  Tnew = Told / 3.0;
336  dt = -2.0 * Told / 3.0;
337  }
338  setState_conditional_TP(Tnew, p, !doUV);
339  if (doUV) {
340  Hnew = intEnergy_mass();
341  Cpnew = cv_mass();
342  } else {
343  Hnew = enthalpy_mass();
344  Cpnew = cp_mass();
345  }
346  if (Cpnew < 0.0) {
347  unstablePhaseNew = true;
348  Tunstable = Tnew;
349  } else {
350  unstablePhaseNew = false;
351  break;
352  }
353  if (unstablePhase == false && unstablePhaseNew == true) {
354  dt *= 0.25;
355  }
356  }
357 
358  if (Hnew == Htarget) {
359  return;
360  } else if (Hnew > Htarget && (Htop < Htarget || Hnew < Htop)) {
361  Htop = Hnew;
362  Ttop = Tnew;
363  } else if (Hnew < Htarget && (Hbot > Htarget || Hnew > Hbot)) {
364  Hbot = Hnew;
365  Tbot = Tnew;
366  }
367  // Convergence in H
368  double Herr = Htarget - Hnew;
369  double acpd = std::max(fabs(cpd), 1.0E-5);
370  double denom = std::max(fabs(Htarget), acpd * dTtol);
371  double HConvErr = fabs((Herr)/denom);
372  if (HConvErr < 0.00001 *dTtol || fabs(dt) < dTtol) {
373  return;
374  }
375  }
376  // We are here when there hasn't been convergence
377  /*
378  * Formulate a detailed error message, since questions seem to
379  * arise often about the lack of convergence.
380  */
381  string ErrString = "No convergence in 500 iterations\n";
382  if (doUV) {
383  ErrString += "\tTarget Internal Energy = " + fp2str(Htarget) + "\n";
384  ErrString += "\tCurrent Specific Volume = " + fp2str(v) + "\n";
385  ErrString += "\tStarting Temperature = " + fp2str(Tinit) + "\n";
386  ErrString += "\tCurrent Temperature = " + fp2str(Tnew) + "\n";
387  ErrString += "\tCurrent Internal Energy = " + fp2str(Hnew) + "\n";
388  ErrString += "\tCurrent Delta T = " + fp2str(dt) + "\n";
389  } else {
390  ErrString += "\tTarget Enthalpy = " + fp2str(Htarget) + "\n";
391  ErrString += "\tCurrent Pressure = " + fp2str(p) + "\n";
392  ErrString += "\tStarting Temperature = " + fp2str(Tinit) + "\n";
393  ErrString += "\tCurrent Temperature = " + fp2str(Tnew) + "\n";
394  ErrString += "\tCurrent Enthalpy = " + fp2str(Hnew) + "\n";
395  ErrString += "\tCurrent Delta T = " + fp2str(dt) + "\n";
396  }
397  if (unstablePhase) {
398  ErrString += "\t - The phase became unstable (Cp < 0) T_unstable_last = "
399  + fp2str(Tunstable) + "\n";
400  }
401  if (doUV) {
402  throw CanteraError("setState_HPorUV (UV)", ErrString);
403  } else {
404  throw CanteraError("setState_HPorUV (HP)", ErrString);
405  }
406 }
407 
408 void ThermoPhase::setState_SP(doublereal Starget, doublereal p,
409  doublereal dTtol)
410 {
411  setState_SPorSV(Starget, p, dTtol, false);
412 }
413 
414 void ThermoPhase::setState_SV(doublereal Starget, doublereal v,
415  doublereal dTtol)
416 {
417  setState_SPorSV(Starget, v, dTtol, true);
418 }
419 
420 void ThermoPhase::setState_SPorSV(doublereal Starget, doublereal p,
421  doublereal dTtol, bool doSV)
422 {
423  doublereal v = 0.0;
424  doublereal dt;
425  if (doSV) {
426  v = p;
427  if (v < 1.0E-300) {
428  throw CanteraError("setState_SPorSV (SV)",
429  "Input specific volume is too small or negative. v = " + fp2str(v));
430  }
431  setDensity(1.0/v);
432  } else {
433  if (p < 1.0E-300) {
434  throw CanteraError("setState_SPorSV (SP)",
435  "Input pressure is too small or negative. p = " + fp2str(p));
436  }
437  setPressure(p);
438  }
439  double Tmax = maxTemp() + 0.1;
440  double Tmin = minTemp() - 0.1;
441 
442  // Make sure we are within the temperature bounds at the start
443  // of the iteration
444  double Tnew = temperature();
445  double Tinit = Tnew;
446  if (Tnew > Tmax) {
447  Tnew = Tmax - 1.0;
448  } else if (Tnew < Tmin) {
449  Tnew = Tmin + 1.0;
450  }
451  if (Tnew != Tinit) {
452  setState_conditional_TP(Tnew, p, !doSV);
453  }
454 
455  double Snew = entropy_mass();
456  double Cpnew = (doSV) ? cv_mass() : cp_mass();
457 
458  double Stop = Snew;
459  double Ttop = Tnew;
460  double Sbot = Snew;
461  double Tbot = Tnew;
462  double Told = Tnew;
463  double Sold = Snew;
464 
465  bool ignoreBounds = false;
466  // Unstable phases are those for which
467  // Cp < 0.0. These are possible for cases where
468  // we have passed the spinodal curve.
469  bool unstablePhase = false;
470  double Tunstable = -1.0;
471  bool unstablePhaseNew = false;
472 
473  // Newton iteration
474  for (int n = 0; n < 500; n++) {
475  Told = Tnew;
476  Sold = Snew;
477  double cpd = Cpnew;
478  if (cpd < 0.0) {
479  unstablePhase = true;
480  Tunstable = Tnew;
481  }
482  // limit step size to 100 K
483  dt = clip((Starget - Sold)*Told/cpd, -100.0, 100.0);
484  Tnew = Told + dt;
485 
486  // Limit the step size so that we are convergent
487  if ((dt > 0.0 && unstablePhase) || (dt <= 0.0 && !unstablePhase)) {
488  if (Sbot < Starget && Tnew < Tbot) {
489  dt = 0.75 * (Tbot - Told);
490  Tnew = Told + dt;
491  }
492  } else if (Stop > Starget && Tnew > Ttop) {
493  dt = 0.75 * (Ttop - Told);
494  Tnew = Told + dt;
495  }
496 
497  // Check Max and Min values
498  if (Tnew > Tmax && !ignoreBounds) {
499  setState_conditional_TP(Tmax, p, !doSV);
500  double Smax = entropy_mass();
501  if (Smax >= Starget) {
502  if (Stop < Starget) {
503  Ttop = Tmax;
504  Stop = Smax;
505  }
506  } else {
507  Tnew = Tmax + 1.0;
508  ignoreBounds = true;
509  }
510  } else if (Tnew < Tmin && !ignoreBounds) {
511  setState_conditional_TP(Tmin, p, !doSV);
512  double Smin = entropy_mass();
513  if (Smin <= Starget) {
514  if (Sbot > Starget) {
515  Tbot = Tmin;
516  Sbot = Smin;
517  }
518  } else {
519  Tnew = Tmin - 1.0;
520  ignoreBounds = true;
521  }
522  }
523 
524  // Try to keep phase within its region of stability
525  // -> Could do a lot better if I calculate the
526  // spinodal value of H.
527  for (int its = 0; its < 10; its++) {
528  Tnew = Told + dt;
529  setState_conditional_TP(Tnew, p, !doSV);
530  Cpnew = (doSV) ? cv_mass() : cp_mass();
531  Snew = entropy_mass();
532  if (Cpnew < 0.0) {
533  unstablePhaseNew = true;
534  Tunstable = Tnew;
535  } else {
536  unstablePhaseNew = false;
537  break;
538  }
539  if (unstablePhase == false && unstablePhaseNew == true) {
540  dt *= 0.25;
541  }
542  }
543 
544  if (Snew == Starget) {
545  return;
546  } else if (Snew > Starget && (Stop < Starget || Snew < Stop)) {
547  Stop = Snew;
548  Ttop = Tnew;
549  } else if (Snew < Starget && (Sbot > Starget || Snew > Sbot)) {
550  Sbot = Snew;
551  Tbot = Tnew;
552  }
553  // Convergence in S
554  double Serr = Starget - Snew;
555  double acpd = std::max(fabs(cpd), 1.0E-5);
556  double denom = std::max(fabs(Starget), acpd * dTtol);
557  double SConvErr = fabs((Serr * Tnew)/denom);
558  if (SConvErr < 0.00001 *dTtol || fabs(dt) < dTtol) {
559  return;
560  }
561  }
562  // We are here when there hasn't been convergence
563  /*
564  * Formulate a detailed error message, since questions seem to
565  * arise often about the lack of convergence.
566  */
567  string ErrString = "No convergence in 500 iterations\n";
568  if (doSV) {
569  ErrString += "\tTarget Entropy = " + fp2str(Starget) + "\n";
570  ErrString += "\tCurrent Specific Volume = " + fp2str(v) + "\n";
571  ErrString += "\tStarting Temperature = " + fp2str(Tinit) + "\n";
572  ErrString += "\tCurrent Temperature = " + fp2str(Tnew) + "\n";
573  ErrString += "\tCurrent Entropy = " + fp2str(Snew) + "\n";
574  ErrString += "\tCurrent Delta T = " + fp2str(dt) + "\n";
575  } else {
576  ErrString += "\tTarget Entropy = " + fp2str(Starget) + "\n";
577  ErrString += "\tCurrent Pressure = " + fp2str(p) + "\n";
578  ErrString += "\tStarting Temperature = " + fp2str(Tinit) + "\n";
579  ErrString += "\tCurrent Temperature = " + fp2str(Tnew) + "\n";
580  ErrString += "\tCurrent Entropy = " + fp2str(Snew) + "\n";
581  ErrString += "\tCurrent Delta T = " + fp2str(dt) + "\n";
582  }
583  if (unstablePhase) {
584  ErrString += "\t - The phase became unstable (Cp < 0) T_unstable_last = "
585  + fp2str(Tunstable) + "\n";
586  }
587  if (doSV) {
588  throw CanteraError("setState_SPorSV (SV)", ErrString);
589  } else {
590  throw CanteraError("setState_SPorSV (SP)", ErrString);
591  }
592 }
593 
594 doublereal ThermoPhase::err(const std::string& msg) const
595 {
596  throw CanteraError("ThermoPhase","Base class method "
597  +msg+" called. Equation of state type: "+int2str(eosType()));
598  return 0.0;
599 }
600 
601 void ThermoPhase::getUnitsStandardConc(double* uA, int k, int sizeUA) const
602 {
603  for (int i = 0; i < sizeUA; i++) {
604  if (i == 0) {
605  uA[0] = 1.0;
606  }
607  if (i == 1) {
608  uA[1] = -int(nDim());
609  }
610  if (i == 2) {
611  uA[2] = 0.0;
612  }
613  if (i == 3) {
614  uA[3] = 0.0;
615  }
616  if (i == 4) {
617  uA[4] = 0.0;
618  }
619  if (i == 5) {
620  uA[5] = 0.0;
621  }
622  }
623 }
624 
626 {
627  if (m_spthermo) {
628  if (m_spthermo != spthermo) {
629  delete m_spthermo;
630  }
631  }
632  m_spthermo = spthermo;
633 }
634 
636 {
637  if (!m_spthermo) {
638  throw CanteraError("ThermoPhase::speciesThermo()",
639  "species reference state thermo manager was not set");
640  }
641  return *m_spthermo;
642 }
643 
644 void ThermoPhase::initThermoFile(const std::string& inputFile,
645  const std::string& id)
646 {
647 
648  if (inputFile.size() == 0) {
649  throw CanteraError("ThermoPhase::initThermoFile",
650  "input file is null");
651  }
652  string path = findInputFile(inputFile);
653  ifstream fin(path.c_str());
654  if (!fin) {
655  throw CanteraError("initThermoFile","could not open "
656  +path+" for reading.");
657  }
658  /*
659  * The phase object automatically constructs an XML object.
660  * Use this object to store information.
661  */
662  //XML_Node& phaseNode_XML = xml();
663  XML_Node* fxml = new XML_Node();
664  fxml->build(fin);
665  XML_Node* fxml_phase = findXMLPhase(fxml, id);
666  if (!fxml_phase) {
667  throw CanteraError("ThermoPhase::initThermo",
668  "ERROR: Can not find phase named " +
669  id + " in file named " + inputFile);
670  }
671  //fxml_phase->copy(&phaseNode_XML);
672  //initThermoXML(*fxml_phase, id);
673  bool m_ok = importPhase(*fxml_phase, this);
674  if (!m_ok) {
675  throw CanteraError("ThermoPhase::initThermoFile","importPhase failed ");
676  }
677  delete fxml;
678 }
679 
680 void ThermoPhase::initThermoXML(XML_Node& phaseNode, const std::string& id)
681 {
682 
683  /*
684  * and sets the state
685  */
686  if (phaseNode.hasChild("state")) {
687  XML_Node& stateNode = phaseNode.child("state");
688  setStateFromXML(stateNode);
689  }
691 }
692 
693 void ThermoPhase::setReferenceComposition(const doublereal* const x)
694 {
695  xMol_Ref.resize(m_kk);
696  if (x) {
697  for (size_t k = 0; k < m_kk; k++) {
698  xMol_Ref[k] = x[k];
699  }
700  } else {
702  }
703  double sum = -1.0;
704  for (size_t k = 0; k < m_kk; k++) {
705  sum += xMol_Ref[k];
706  }
707  if (fabs(sum) > 1.0E-11) {
708  throw CanteraError("ThermoPhase::setReferenceComposition",
709  "input mole fractions don't sum to 1.0");
710  }
711 
712 }
713 
714 void ThermoPhase::getReferenceComposition(doublereal* const x) const
715 {
716  for (size_t k = 0; k < m_kk; k++) {
717  x[k] = xMol_Ref[k];
718  }
719 }
720 
722 {
723  // Check to see that there is at least one species defined in the phase
724  if (m_kk == 0) {
725  throw CanteraError("ThermoPhase::initThermo()",
726  "Number of species is equal to zero");
727  }
728  xMol_Ref.resize(m_kk, 0.0);
729 }
731 {
732 }
733 
734 void ThermoPhase::saveSpeciesData(const size_t k, const XML_Node* const data)
735 {
736  if (m_speciesData.size() < (k + 1)) {
737  m_speciesData.resize(k+1, 0);
738  }
739  m_speciesData[k] = new XML_Node(*data);
740 }
741 
742 const std::vector<const XML_Node*> & ThermoPhase::speciesData() const
743 {
744  if (m_speciesData.size() != m_kk) {
745  throw CanteraError("ThermoPhase::speciesData",
746  "m_speciesData is the wrong size");
747  }
748  return m_speciesData;
749 }
750 
752 {
753  string comp = getChildValue(state,"moleFractions");
754  if (comp != "") {
756  } else {
757  comp = getChildValue(state,"massFractions");
758  if (comp != "") {
760  }
761  }
762  if (state.hasChild("temperature")) {
763  double t = getFloat(state, "temperature", "temperature");
764  setTemperature(t);
765  }
766  if (state.hasChild("pressure")) {
767  double p = getFloat(state, "pressure", "pressure");
768  setPressure(p);
769  }
770  if (state.hasChild("density")) {
771  double rho = getFloat(state, "density", "density");
772  setDensity(rho);
773  }
774 }
775 
777 {
778  doublereal rrt = 1.0/(GasConstant* temperature());
779  size_t mm = nElements();
780  if (lambda.size() < mm) {
781  throw CanteraError("setElementPotentials", "lambda too small");
782  }
783  if (!m_hasElementPotentials) {
784  m_lambdaRRT.resize(mm);
785  }
786  for (size_t m = 0; m < mm; m++) {
787  m_lambdaRRT[m] = lambda[m] * rrt;
788  }
789  m_hasElementPotentials = true;
790 }
791 
792 bool ThermoPhase::getElementPotentials(doublereal* lambda) const
793 {
794  doublereal rt = GasConstant* temperature();
796  for (size_t m = 0; m < nElements(); m++) {
797  lambda[m] = m_lambdaRRT[m] * rt;
798  }
799  }
800  return m_hasElementPotentials;
801 }
802 
803 void ThermoPhase::getdlnActCoeffdlnN(const size_t ld, doublereal* const dlnActCoeffdlnN)
804 {
805  for (size_t m = 0; m < m_kk; m++) {
806  for (size_t k = 0; k < m_kk; k++) {
807  dlnActCoeffdlnN[ld * k + m] = 0.0;
808  }
809  }
810  return;
811 }
812 
813 void ThermoPhase::getdlnActCoeffdlnN_numderiv(const size_t ld, doublereal* const dlnActCoeffdlnN)
814 {
815  double deltaMoles_j = 0.0;
816  double pres = pressure();
817 
818  /*
819  * Evaluate the current base activity coefficients if necessary
820  */
821  std::vector<double> ActCoeff_Base(m_kk);
822  getActivityCoefficients(DATA_PTR(ActCoeff_Base));
823  std::vector<double> Xmol_Base(m_kk);
824  getMoleFractions(DATA_PTR(Xmol_Base));
825 
826  // Make copies of ActCoeff and Xmol_ for use in taking differences
827  std::vector<double> ActCoeff(m_kk);
828  std::vector<double> Xmol(m_kk);
829  double v_totalMoles = 1.0;
830  double TMoles_base = v_totalMoles;
831 
832  /*
833  * Loop over the columns species to be deltad
834  */
835  for (size_t j = 0; j < m_kk; j++) {
836  /*
837  * Calculate a value for the delta moles of species j
838  * -> NOte Xmol_[] and Tmoles are always positive or zero
839  * quantities.
840  * -> experience has shown that you always need to make the deltas greater than needed to
841  * change the other mole fractions in order to capture some effects.
842  */
843  double moles_j_base = v_totalMoles * Xmol_Base[j];
844  deltaMoles_j = 1.0E-7 * moles_j_base + v_totalMoles * 1.0E-13 + 1.0E-150;
845  /*
846  * Now, update the total moles in the phase and all of the
847  * mole fractions based on this.
848  */
849  v_totalMoles = TMoles_base + deltaMoles_j;
850  for (size_t k = 0; k < m_kk; k++) {
851  Xmol[k] = Xmol_Base[k] * TMoles_base / v_totalMoles;
852  }
853  Xmol[j] = (moles_j_base + deltaMoles_j) / v_totalMoles;
854 
855  /*
856  * Go get new values for the activity coefficients.
857  * -> Note this calls setState_PX();
858  */
859  setState_PX(pres, DATA_PTR(Xmol));
861 
862  /*
863  * Calculate the column of the matrix
864  */
865  double* const lnActCoeffCol = dlnActCoeffdlnN + ld * j;
866  for (size_t k = 0; k < m_kk; k++) {
867  lnActCoeffCol[k] = (2*moles_j_base + deltaMoles_j) *(ActCoeff[k] - ActCoeff_Base[k]) /
868  ((ActCoeff[k] + ActCoeff_Base[k]) * deltaMoles_j);
869  }
870  /*
871  * Revert to the base case Xmol_, v_totalMoles
872  */
873  v_totalMoles = TMoles_base;
874  Xmol = Xmol_Base;
875  }
876  /*
877  * Go get base values for the activity coefficients.
878  * -> Note this calls setState_TPX() again;
879  * -> Just wanted to make sure that cantera is in sync
880  * with VolPhase after this call.
881  */
882  setState_PX(pres, DATA_PTR(Xmol_Base));
883 }
884 
885 std::string ThermoPhase::report(bool show_thermo) const
886 {
887  char p[800];
888  string s = "";
889  try {
890  if (name() != "") {
891  sprintf(p, " \n %s:\n", name().c_str());
892  s += p;
893  }
894  sprintf(p, " \n temperature %12.6g K\n", temperature());
895  s += p;
896  sprintf(p, " pressure %12.6g Pa\n", pressure());
897  s += p;
898  sprintf(p, " density %12.6g kg/m^3\n", density());
899  s += p;
900  sprintf(p, " mean mol. weight %12.6g amu\n", meanMolecularWeight());
901  s += p;
902 
903  doublereal phi = electricPotential();
904  if (phi != 0.0) {
905  sprintf(p, " potential %12.6g V\n", phi);
906  s += p;
907  }
908  if (show_thermo) {
909  sprintf(p, " \n");
910  s += p;
911  sprintf(p, " 1 kg 1 kmol\n");
912  s += p;
913  sprintf(p, " ----------- ------------\n");
914  s += p;
915  sprintf(p, " enthalpy %12.6g %12.4g J\n",
917  s += p;
918  sprintf(p, " internal energy %12.6g %12.4g J\n",
920  s += p;
921  sprintf(p, " entropy %12.6g %12.4g J/K\n",
923  s += p;
924  sprintf(p, " Gibbs function %12.6g %12.4g J\n",
925  gibbs_mass(), gibbs_mole());
926  s += p;
927  sprintf(p, " heat capacity c_p %12.6g %12.4g J/K\n",
928  cp_mass(), cp_mole());
929  s += p;
930  try {
931  sprintf(p, " heat capacity c_v %12.6g %12.4g J/K\n",
932  cv_mass(), cv_mole());
933  s += p;
934  } catch (CanteraError& err) {
935  err.save();
936  sprintf(p, " heat capacity c_v <not implemented> \n");
937  s += p;
938  }
939  }
940 
941  size_t kk = nSpecies();
942  vector_fp x(kk);
943  vector_fp y(kk);
944  vector_fp mu(kk);
945  getMoleFractions(&x[0]);
946  getMassFractions(&y[0]);
947  getChemPotentials(&mu[0]);
948  doublereal rt = GasConstant * temperature();
949  //if (th.nSpecies() > 1) {
950 
951  if (show_thermo) {
952  sprintf(p, " \n X "
953  " Y Chem. Pot. / RT \n");
954  s += p;
955  sprintf(p, " ------------- "
956  "------------ ------------\n");
957  s += p;
958  for (size_t k = 0; k < kk; k++) {
959  if (x[k] > SmallNumber) {
960  sprintf(p, "%18s %12.6g %12.6g %12.6g\n",
961  speciesName(k).c_str(), x[k], y[k], mu[k]/rt);
962  } else {
963  sprintf(p, "%18s %12.6g %12.6g \n",
964  speciesName(k).c_str(), x[k], y[k]);
965  }
966  s += p;
967  }
968  } else {
969  sprintf(p, " \n X "
970  " Y\n");
971  s += p;
972  sprintf(p, " -------------"
973  " ------------\n");
974  s += p;
975  for (size_t k = 0; k < kk; k++) {
976  sprintf(p, "%18s %12.6g %12.6g\n",
977  speciesName(k).c_str(), x[k], y[k]);
978  s += p;
979  }
980  }
981  }
982  //}
983  catch (CanteraError& err) {
984  err.save();
985  }
986  return s;
987 }
988 
989 void ThermoPhase::reportCSV(std::ofstream& csvFile) const
990 {
991  int tabS = 15;
992  int tabM = 30;
993  csvFile.precision(8);
994 
995  vector_fp X(nSpecies());
996  getMoleFractions(&X[0]);
997 
998  std::vector<std::string> pNames;
999  std::vector<vector_fp> data;
1000  getCsvReportData(pNames, data);
1001 
1002  csvFile << setw(tabS) << "Species,";
1003  for (size_t i = 0; i < pNames.size(); i++) {
1004  csvFile << setw(tabM) << pNames[i] << ",";
1005  }
1006  csvFile << endl;
1007  for (size_t k = 0; k < nSpecies(); k++) {
1008  csvFile << setw(tabS) << speciesName(k) + ",";
1009  if (X[k] > SmallNumber) {
1010  for (size_t i = 0; i < pNames.size(); i++) {
1011  csvFile << setw(tabM) << data[i][k] << ",";
1012  }
1013  csvFile << endl;
1014  } else {
1015  for (size_t i = 0; i < pNames.size(); i++) {
1016  csvFile << setw(tabM) << 0 << ",";
1017  }
1018  csvFile << endl;
1019  }
1020  }
1021 }
1022 
1023 void ThermoPhase::getCsvReportData(std::vector<std::string>& names,
1024  std::vector<vector_fp>& data) const
1025 {
1026  names.clear();
1027  data.assign(10, vector_fp(nSpecies()));
1028 
1029  names.push_back("X");
1030  getMoleFractions(&data[0][0]);
1031 
1032  names.push_back("Y");
1033  getMassFractions(&data[1][0]);
1034 
1035  names.push_back("Chem. Pot (J/kmol)");
1036  getChemPotentials(&data[2][0]);
1037 
1038  names.push_back("Activity");
1039  getActivities(&data[3][0]);
1040 
1041  names.push_back("Act. Coeff.");
1042  getActivityCoefficients(&data[4][0]);
1043 
1044  names.push_back("Part. Mol Enthalpy (J/kmol)");
1045  getPartialMolarEnthalpies(&data[5][0]);
1046 
1047  names.push_back("Part. Mol. Entropy (J/K/kmol)");
1048  getPartialMolarEntropies(&data[6][0]);
1049 
1050  names.push_back("Part. Mol. Energy (J/kmol)");
1051  getPartialMolarIntEnergies(&data[7][0]);
1052 
1053  names.push_back("Part. Mol. Cp (J/K/kmol");
1054  getPartialMolarCp(&data[8][0]);
1055 
1056  names.push_back("Part. Mol. Cv (J/K/kmol)");
1057  getPartialMolarVolumes(&data[9][0]);
1058 }
1059 
1060 }
std::map< std::string, doublereal > compositionMap
Map connecting a string name with a double.
Definition: ct_defs.h:162
virtual void setState_HP(doublereal h, doublereal p, doublereal tol=1.e-4)
Set the internally stored specific enthalpy (J/kg) and pressure (Pa) of the phase.
ThermoPhase()
Constructor.
Definition: ThermoPhase.cpp:23
virtual doublereal density() const
Density (kg/m^3).
Definition: Phase.h:534
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Definition: stringUtils.cpp:40
doublereal electricPotential() const
Returns the electric potential of this phase (V).
Definition: ThermoPhase.h:391
doublereal err(const std::string &msg) const
Error function that gets called for unhandled cases.
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
Definition: ThermoPhase.h:279
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
size_t nElements() const
Number of elements.
Definition: Phase.cpp:139
std::vector< const XML_Node * > m_speciesData
Vector of pointers to the species databases.
Definition: ThermoPhase.h:1635
void getMassFractions(doublereal *const y) const
Get the species mass fractions.
Definition: Phase.cpp:561
virtual void setState_TPX(doublereal t, doublereal p, const doublereal *x)
Set the temperature (K), pressure (Pa), and mole fractions.
std::string findInputFile(const std::string &name)
Find an input file.
Definition: global.cpp:191
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
ThermoPhase & operator=(const ThermoPhase &right)
Assignment operator.
Definition: ThermoPhase.cpp:57
const int cAC_CONVENTION_MOLAR
Standard state uses the molar convention.
Definition: ThermoPhase.h:24
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
void setState_HPorUV(doublereal h, doublereal p, doublereal tol=1.e-4, bool doUV=false)
Carry out work in HP and UV calculations.
virtual void reportCSV(std::ofstream &csvFile) const
returns a summary of the state of the phase to a comma separated file.
const int cSS_CONVENTION_TEMPERATURE
Standard state uses the molar convention.
Definition: ThermoPhase.h:34
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
void setState_conditional_TP(doublereal t, doublereal p, bool set_p)
Helper function used by setState_HPorUV and setState_SPorSV.
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
Definition: global.h:324
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
Base class for phases of matter.
Definition: Phase.h:98
vector_fp m_lambdaRRT
Vector of element potentials.
Definition: ThermoPhase.h:1645
virtual void getPartialMolarVolumes(doublereal *vbar) const
Return an array of partial molar volumes for the species in the mixture.
Definition: ThermoPhase.h:669
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:519
void saveSpeciesData(const size_t k, const XML_Node *const data)
Store a reference pointer to the XML tree containing the species data for this phase.
std::string name() const
Return the name of the phase.
Definition: Phase.cpp:129
Pure Virtual base class for the species thermo manager classes.
virtual void setState_PY(doublereal p, doublereal *y)
Set the internally stored pressure (Pa) and mass fractions.
virtual doublereal entropy_mole() const
Molar entropy. Units: J/kmol/K.
Definition: ThermoPhase.h:274
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 doublereal standardConcentration(size_t k=0) const
Return the standard concentration for the kth species.
Definition: ThermoPhase.h:487
doublereal intEnergy_mass() const
Specific internal energy.
Definition: ThermoPhase.h:940
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:101
virtual void setReferenceComposition(const doublereal *const x)
Sets the reference composition.
bool getElementPotentials(doublereal *lambda) const
Returns the element potentials stored in the ThermoPhase object.
void setMassFractionsByName(compositionMap &yMap)
Set the species mass fractions by name.
Definition: Phase.cpp:399
bool m_chargeNeutralityNecessary
Boolean indicating whether a charge neutrality condition is a necessity.
Definition: ThermoPhase.h:1659
virtual void setStateFromXML(const XML_Node &state)
Set the initial state of the phase to the conditions specified in the state XML element.
bool importPhase(XML_Node &phase, ThermoPhase *th, SpeciesThermoFactory *spfactory)
Import a phase information into an empty thermophase object.
virtual doublereal intEnergy_mole() const
Molar internal energy. Units: J/kmol.
Definition: ThermoPhase.h:269
virtual void getActivities(doublereal *a) const
Get the array of non-dimensional activities at the current solution temperature, pressure, and solution concentration.
virtual doublereal enthalpy_mole() const
Molar enthalpy. Units: J/kmol.
Definition: ThermoPhase.h:264
doublereal gibbs_mass() const
Specific Gibbs function.
Definition: ThermoPhase.h:954
doublereal entropy_mass() const
Specific entropy.
Definition: ThermoPhase.h:947
doublereal m_phi
Stored value of the electric potential for this phase.
Definition: ThermoPhase.h:1641
virtual void getUnitsStandardConc(double *uA, int k=0, int sizeUA=6) const
Returns the units of the standard and generalized concentrations.
virtual ThermoPhase * duplMyselfAsThermoPhase() const
Duplication routine for objects which inherit from ThermoPhase.
virtual doublereal maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
Definition: ThermoPhase.h:244
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
Definition: stringUtils.cpp:29
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: ThermoPhase.h:595
doublereal cp_mass() const
Specific heat at constant pressure.
Definition: ThermoPhase.h:961
virtual void setState_SP(doublereal s, doublereal p, doublereal tol=1.e-4)
Set the specific entropy (J/kg/K) and pressure (Pa).
virtual void setState_TPY(doublereal t, doublereal p, const doublereal *y)
Set the internally stored temperature (K), pressure (Pa), and mass fractions of the phase...
virtual void getCsvReportData(std::vector< std::string > &names, std::vector< vector_fp > &data) const
Fills names and data with the column names and species thermo properties to be included in the output...
int m_ssConvention
Contains the standard state convention.
Definition: ThermoPhase.h:1662
virtual void getReferenceComposition(doublereal *const x) const
Gets the reference composition.
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution.
Definition: ThermoPhase.h:638
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
void setMoleFractionsByName(compositionMap &xMap)
Set the species mole fractions by name.
Definition: Phase.cpp:354
compositionMap parseCompString(const std::string &ss, const std::vector< std::string > &names)
Parse a composition string into a map consisting of individual key:composition pairs.
doublereal cv_mass() const
Specific heat at constant volume.
Definition: ThermoPhase.h:968
void setElementPotentials(const vector_fp &lambda)
Stores the element potentials in the ThermoPhase object.
virtual void setMoleFractions(const doublereal *const x)
Set the mole fractions to the specified values There is no restriction on the sum of the mole fractio...
Definition: Phase.cpp:306
virtual void setState_UV(doublereal u, doublereal v, doublereal tol=1.e-4)
Set the specific internal energy (J/kg) and specific volume (m^3/kg).
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 std::string report(bool show_thermo=true) const
returns a summary of the state of the phase as a string
virtual void getPartialMolarIntEnergies(doublereal *ubar) const
Return an array of partial molar internal energies for the species in the mixture.
Definition: ThermoPhase.h:648
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
virtual doublereal cv_mole() const
Molar heat capacity at constant volume. Units: J/kmol/K.
Definition: ThermoPhase.h:289
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:252
virtual doublereal pressure() const
Return the thermodynamic pressure (Pa).
Definition: ThermoPhase.h:314
virtual void installSlavePhases(Cantera::XML_Node *phaseNode)
Add in species from Slave phases.
const std::vector< std::string > & speciesNames() const
Return a const reference to the vector of species names.
Definition: Phase.cpp:252
virtual void setState_SV(doublereal s, doublereal v, doublereal tol=1.e-4)
Set the specific entropy (J/kg/K) and specific volume (m^3/kg).
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
virtual void getActivityConcentrations(doublereal *c) const
This method returns an array of generalized concentrations.
Definition: ThermoPhase.h:465
virtual void setPressure(doublereal p)
Set the internally stored pressure (Pa) at constant temperature and composition.
Definition: ThermoPhase.h:331
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
const doublereal SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:139
virtual int standardStateConvention() const
This method returns the convention used in specification of the standard state, of which there are cu...
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:165
void setState_SPorSV(doublereal s, doublereal p, doublereal tol=1.e-4, bool doSV=false)
Carry out work in SP and SV calculations.
virtual void getLnActivityCoefficients(doublereal *lnac) const
Get the array of non-dimensional molar-based ln activity coefficients at the current solution tempera...
virtual int eosType() const
Equation of state type flag.
Definition: ThermoPhase.h:151
virtual void setTemperature(const doublereal temp)
Set the internally stored temperature of the phase (K).
Definition: Phase.h:562
doublereal enthalpy_mass() const
Specific enthalpy.
Definition: ThermoPhase.h:933
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:588
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
Definition: ct_defs.h:66
virtual void getActivityCoefficients(doublereal *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
Definition: ThermoPhase.h:553
virtual void setState_PX(doublereal p, doublereal *x)
Set the pressure (Pa) and mole fractions.
virtual int activityConvention() const
This method returns the convention used in specification of the activities, of which there are curren...
const std::vector< const XML_Node * > & speciesData() const
Return a pointer to the vector of XML nodes containing the species data for this phase.
Contains declarations for string manipulation functions within Cantera.
std::vector< doublereal > xMol_Ref
Reference Mole Fraction Composition.
Definition: ThermoPhase.h:1671
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
Definition: ThermoPhase.h:628
virtual doublereal cp_mole() const
Molar heat capacity at constant pressure. Units: J/kmol/K.
Definition: ThermoPhase.h:284
virtual void setMassFractions(const doublereal *const y)
Set the mass fractions to the specified values and normalize them.
Definition: Phase.cpp:374
virtual SpeciesThermo & speciesThermo(int k=-1)
Return a changeable reference to the calculation manager for species reference-state thermodynamic pr...
virtual doublereal logStandardConc(size_t k=0) const
Natural logarithm of the standard concentration of the kth species.
size_t m_kk
Number of species in the phase.
Definition: Phase.h:716
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal *const dlnActCoeffdlnN)
Get the array of derivatives of the log activity coefficients with respect to the log of the species ...
virtual void getPartialMolarCp(doublereal *cpbar) const
Return an array of partial molar heat capacities for the species in the mixture.
Definition: ThermoPhase.h:659
void setSpeciesThermo(SpeciesThermo *spthermo)
Install a species thermodynamic property manager.
virtual void initThermoFile(const std::string &inputFile, const std::string &id)
virtual ~ThermoPhase()
Destructor. Deletes the species thermo manager.
Definition: ThermoPhase.cpp:33
bool m_hasElementPotentials
Boolean indicating whether there is a valid set of saved element potentials for this phase...
Definition: ThermoPhase.h:1649
std::string getChildValue(const Cantera::XML_Node &parent, const std::string &nameString)
This function reads a child node with the name, nameString, and returns its xml value as the return s...
Definition: ctml.cpp:164
Header file for class ThermoPhase, the base class for phases with thermodynamic properties, and the text for the Module thermoprops (see Thermodynamic Properties and class ThermoPhase).
SpeciesThermo * m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
Definition: ThermoPhase.h:1625
void build(std::istream &f)
Main routine to create an tree-like representation of an XML file.
Definition: xml.cpp:776
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:246
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
virtual doublereal minTemp(size_t k=npos) const
Minimum temperature for which the thermodynamic data for the species or phase are valid...
Definition: ThermoPhase.h:175
void save()
Function to put this error onto Cantera's error stack.