Cantera  2.5.1
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 // This file is part of Cantera. See License.txt in the top-level directory or
9 // at https://cantera.org/license.txt for license and copyright information.
10 
17 #include "cantera/base/ctml.h"
18 
19 #include <iomanip>
20 #include <fstream>
21 
22 using namespace std;
23 
24 namespace Cantera
25 {
26 
27 ThermoPhase::ThermoPhase() :
28  m_speciesData(0),
29  m_phi(0.0),
30  m_chargeNeutralityNecessary(false),
31  m_ssConvention(cSS_CONVENTION_TEMPERATURE),
32  m_tlast(0.0)
33 {
34 }
35 
36 ThermoPhase::~ThermoPhase()
37 {
38  for (size_t k = 0; k < m_speciesData.size(); k++) {
39  delete m_speciesData[k];
40  }
41 }
42 
43 void ThermoPhase::resetHf298(size_t k) {
44  if (k != npos) {
46  } else {
47  for (size_t k = 0; k < nSpecies(); k++) {
49  }
50  }
52 }
53 
55 {
56  return cAC_CONVENTION_MOLAR;
57 }
58 
60 {
61  return m_ssConvention;
62 }
63 
65 {
66  // kmol/m^3 for bulk phases, kmol/m^2 for surface phases, etc.
67  return Units(1.0, 0, -static_cast<double>(nDim()), 0, 0, 0, 1);
68 }
69 
70 doublereal ThermoPhase::logStandardConc(size_t k) const
71 {
72  return log(standardConcentration(k));
73 }
74 
75 void ThermoPhase::getActivities(doublereal* a) const
76 {
78  for (size_t k = 0; k < nSpecies(); k++) {
79  a[k] /= standardConcentration(k);
80  }
81 }
82 
83 void ThermoPhase::getLnActivityCoefficients(doublereal* lnac) const
84 {
86  for (size_t k = 0; k < m_kk; k++) {
87  lnac[k] = std::log(lnac[k]);
88  }
89 }
90 
91 void ThermoPhase::getElectrochemPotentials(doublereal* mu) const
92 {
94  double ve = Faraday * electricPotential();
95  for (size_t k = 0; k < m_kk; k++) {
96  mu[k] += ve*charge(k);
97  }
98 }
99 
100 void ThermoPhase::setState_TPX(doublereal t, doublereal p, const doublereal* x)
101 {
102  setMoleFractions(x);
103  setState_TP(t,p);
104 }
105 
106 void ThermoPhase::setState_TPX(doublereal t, doublereal p, const compositionMap& x)
107 {
109  setState_TP(t,p);
110 }
111 
112 void ThermoPhase::setState_TPX(doublereal t, doublereal p, const std::string& x)
113 {
115  setState_TP(t,p);
116 }
117 
118 void ThermoPhase::setState_TPY(doublereal t, doublereal p, const doublereal* y)
119 {
120  setMassFractions(y);
121  setState_TP(t,p);
122 }
123 
124 void ThermoPhase::setState_TPY(doublereal t, doublereal p, const compositionMap& y)
125 {
127  setState_TP(t,p);
128 }
129 
130 void ThermoPhase::setState_TPY(doublereal t, doublereal p, const std::string& y)
131 {
133  setState_TP(t,p);
134 }
135 
136 void ThermoPhase::setState_TP(doublereal t, doublereal p)
137 {
138  double tsave = temperature();
139  double dsave = density();
140  try {
141  setTemperature(t);
142  setPressure(p);
143  } catch (CanteraError&) {
144  setState_TR(tsave, dsave);
145  throw;
146  }
147 }
148 
149 void ThermoPhase::setState_RPX(doublereal rho, doublereal p, const doublereal* x)
150 {
151  setMoleFractions(x);
152  setState_RP(rho, p);
153 }
154 
155 void ThermoPhase::setState_RPX(doublereal rho, doublereal p, const compositionMap& x)
156 {
158  setState_RP(rho,p);
159 }
160 
161 void ThermoPhase::setState_RPX(doublereal rho, doublereal p, const std::string& x)
162 {
164  setState_RP(rho,p);
165 }
166 
167 void ThermoPhase::setState_RPY(doublereal rho, doublereal p, const doublereal* y)
168 {
169  setMassFractions(y);
170  setState_RP(rho,p);
171 }
172 
173 void ThermoPhase::setState_RPY(doublereal rho, doublereal p, const compositionMap& y)
174 {
176  setState_RP(rho,p);
177 }
178 
179 void ThermoPhase::setState_RPY(doublereal rho, doublereal p, const std::string& y)
180 {
182  setState_RP(rho,p);
183 }
184 
185 void ThermoPhase::setState_PX(doublereal p, doublereal* x)
186 {
187  setMoleFractions(x);
188  setPressure(p);
189 }
190 
191 void ThermoPhase::setState_PY(doublereal p, doublereal* y)
192 {
193  setMassFractions(y);
194  setPressure(p);
195 }
196 
197 void ThermoPhase::setState_HP(double Htarget, double p, double rtol)
198 {
199  setState_HPorUV(Htarget, p, rtol, false);
200 }
201 
202 void ThermoPhase::setState_UV(double u, double v, double rtol)
203 {
204  assertCompressible("setState_UV");
205  setState_HPorUV(u, v, rtol, true);
206 }
207 
208 void ThermoPhase::setState(const AnyMap& input_state)
209 {
210  AnyMap state = input_state;
211 
212  // Remap allowable synonyms
213  if (state.hasKey("mass-fractions")) {
214  state["Y"] = state["mass-fractions"];
215  state.erase("mass-fractions");
216  }
217  if (state.hasKey("mole-fractions")) {
218  state["X"] = state["mole-fractions"];
219  state.erase("mole-fractions");
220  }
221  if (state.hasKey("temperature")) {
222  state["T"] = state["temperature"];
223  }
224  if (state.hasKey("pressure")) {
225  state["P"] = state["pressure"];
226  }
227  if (state.hasKey("enthalpy")) {
228  state["H"] = state["enthalpy"];
229  }
230  if (state.hasKey("int-energy")) {
231  state["U"] = state["int-energy"];
232  }
233  if (state.hasKey("internal-energy")) {
234  state["U"] = state["internal-energy"];
235  }
236  if (state.hasKey("specific-volume")) {
237  state["V"] = state["specific-volume"];
238  }
239  if (state.hasKey("entropy")) {
240  state["S"] = state["entropy"];
241  }
242  if (state.hasKey("density")) {
243  state["D"] = state["density"];
244  }
245  if (state.hasKey("vapor-fraction")) {
246  state["Q"] = state["vapor-fraction"];
247  }
248 
249  // Set composition
250  if (state.hasKey("X")) {
251  if (state["X"].is<string>()) {
252  setMoleFractionsByName(state["X"].asString());
253  } else {
254  setMoleFractionsByName(state["X"].asMap<double>());
255  }
256  state.erase("X");
257  } else if (state.hasKey("Y")) {
258  if (state["Y"].is<string>()) {
259  setMassFractionsByName(state["Y"].asString());
260  } else {
261  setMassFractionsByName(state["Y"].asMap<double>());
262  }
263  state.erase("Y");
264  }
265  // set thermodynamic state using whichever property set is found
266  if (state.size() == 0) {
267  setState_TP(298.15, OneAtm);
268  } else if (state.hasKey("T") && state.hasKey("P")) {
269  double T = state.convert("T", "K");
270  double P = state.convert("P", "Pa");
271  if (state.hasKey("Q")) {
272  setState_TPQ(T, P, state["Q"].asDouble());
273  } else {
274  setState_TP(T, P);
275  }
276  } else if (state.hasKey("T") && state.hasKey("D")) {
277  setState_TR(state.convert("T", "K"), state.convert("D", "kg/m^3"));
278  } else if (state.hasKey("T") && state.hasKey("V")) {
279  setState_TV(state.convert("T", "K"), state.convert("V", "m^3/kg"));
280  } else if (state.hasKey("H") && state.hasKey("P")) {
281  setState_HP(state.convert("H", "J/kg"), state.convert("P", "Pa"));
282  } else if (state.hasKey("U") && state.hasKey("V")) {
283  setState_UV(state.convert("U", "J/kg"), state.convert("V", "m^3/kg"));
284  } else if (state.hasKey("S") && state.hasKey("P")) {
285  setState_SP(state.convert("S", "J/kg/K"), state.convert("P", "Pa"));
286  } else if (state.hasKey("S") && state.hasKey("V")) {
287  setState_SV(state.convert("S", "J/kg/K"), state.convert("V", "m^3/kg"));
288  } else if (state.hasKey("S") && state.hasKey("T")) {
289  setState_ST(state.convert("S", "J/kg/K"), state.convert("T", "K"));
290  } else if (state.hasKey("P") && state.hasKey("V")) {
291  setState_PV(state.convert("P", "Pa"), state.convert("V", "m^3/kg"));
292  } else if (state.hasKey("U") && state.hasKey("P")) {
293  setState_UP(state.convert("U", "J/kg"), state.convert("P", "Pa"));
294  } else if (state.hasKey("V") && state.hasKey("H")) {
295  setState_VH(state.convert("V", "m^3/kg"), state.convert("H", "J/kg"));
296  } else if (state.hasKey("T") && state.hasKey("H")) {
297  setState_TH(state.convert("T", "K"), state.convert("H", "J/kg"));
298  } else if (state.hasKey("S") && state.hasKey("H")) {
299  setState_SH(state.convert("S", "J/kg/K"), state.convert("H", "J/kg"));
300  } else if (state.hasKey("D") && state.hasKey("P")) {
301  setState_RP(state.convert("D", "kg/m^3"), state.convert("P", "Pa"));
302  } else if (state.hasKey("P") && state.hasKey("Q")) {
303  setState_Psat(state.convert("P", "Pa"), state["Q"].asDouble());
304  } else if (state.hasKey("T") && state.hasKey("Q")) {
305  setState_Tsat(state.convert("T", "K"), state["Q"].asDouble());
306  } else if (state.hasKey("T")) {
307  setState_TP(state.convert("T", "K"), OneAtm);
308  } else if (state.hasKey("P")) {
309  setState_TP(298.15, state.convert("P", "Pa"));
310  } else {
311  throw CanteraError("ThermoPhase::setState",
312  "'state' did not specify a recognized set of properties.\n"
313  "Keys provided were: {}", input_state.keys_str());
314  }
315 }
316 
317 void ThermoPhase::setState_conditional_TP(doublereal t, doublereal p, bool set_p)
318 {
319  setTemperature(t);
320  if (set_p) {
321  setPressure(p);
322  }
323 }
324 
325 void ThermoPhase::setState_HPorUV(double Htarget, double p,
326  double rtol, bool doUV)
327 {
328  doublereal dt;
329  doublereal v = 0.0;
330 
331  // Assign the specific volume or pressure and make sure it's positive
332  if (doUV) {
333  doublereal v = p;
334  if (v < 1.0E-300) {
335  throw CanteraError("ThermoPhase::setState_HPorUV (UV)",
336  "Input specific volume is too small or negative. v = {}", v);
337  }
338  setDensity(1.0/v);
339  } else {
340  if (p < 1.0E-300) {
341  throw CanteraError("ThermoPhase::setState_HPorUV (HP)",
342  "Input pressure is too small or negative. p = {}", p);
343  }
344  setPressure(p);
345  }
346  double Tmax = maxTemp() + 0.1;
347  double Tmin = minTemp() - 0.1;
348 
349  // Make sure we are within the temperature bounds at the start
350  // of the iteration
351  double Tnew = temperature();
352  double Tinit = Tnew;
353  if (Tnew > Tmax) {
354  Tnew = Tmax - 1.0;
355  } else if (Tnew < Tmin) {
356  Tnew = Tmin + 1.0;
357  }
358  if (Tnew != Tinit) {
359  setState_conditional_TP(Tnew, p, !doUV);
360  }
361 
362  double Hnew = (doUV) ? intEnergy_mass() : enthalpy_mass();
363  double Cpnew = (doUV) ? cv_mass() : cp_mass();
364  double Htop = Hnew;
365  double Ttop = Tnew;
366  double Hbot = Hnew;
367  double Tbot = Tnew;
368 
369  bool ignoreBounds = false;
370  // Unstable phases are those for which cp < 0.0. These are possible for
371  // cases where we have passed the spinodal curve.
372  bool unstablePhase = false;
373  // Counter indicating the last temperature point where the
374  // phase was unstable
375  double Tunstable = -1.0;
376  bool unstablePhaseNew = false;
377 
378  // Newton iteration
379  for (int n = 0; n < 500; n++) {
380  double Told = Tnew;
381  double Hold = Hnew;
382  double cpd = Cpnew;
383  if (cpd < 0.0) {
384  unstablePhase = true;
385  Tunstable = Tnew;
386  }
387  // limit step size to 100 K
388  dt = clip((Htarget - Hold)/cpd, -100.0, 100.0);
389 
390  // Calculate the new T
391  Tnew = Told + dt;
392 
393  // Limit the step size so that we are convergent This is the step that
394  // makes it different from a Newton's algorithm
395  if ((dt > 0.0 && unstablePhase) || (dt <= 0.0 && !unstablePhase)) {
396  if (Hbot < Htarget && Tnew < (0.75 * Tbot + 0.25 * Told)) {
397  dt = 0.75 * (Tbot - Told);
398  Tnew = Told + dt;
399  }
400  } else if (Htop > Htarget && Tnew > (0.75 * Ttop + 0.25 * Told)) {
401  dt = 0.75 * (Ttop - Told);
402  Tnew = Told + dt;
403  }
404 
405  // Check Max and Min values
406  if (Tnew > Tmax && !ignoreBounds) {
407  setState_conditional_TP(Tmax, p, !doUV);
408  double Hmax = (doUV) ? intEnergy_mass() : enthalpy_mass();
409  if (Hmax >= Htarget) {
410  if (Htop < Htarget) {
411  Ttop = Tmax;
412  Htop = Hmax;
413  }
414  } else {
415  Tnew = Tmax + 1.0;
416  ignoreBounds = true;
417  }
418  }
419  if (Tnew < Tmin && !ignoreBounds) {
420  setState_conditional_TP(Tmin, p, !doUV);
421  double Hmin = (doUV) ? intEnergy_mass() : enthalpy_mass();
422  if (Hmin <= Htarget) {
423  if (Hbot > Htarget) {
424  Tbot = Tmin;
425  Hbot = Hmin;
426  }
427  } else {
428  Tnew = Tmin - 1.0;
429  ignoreBounds = true;
430  }
431  }
432 
433  // Try to keep phase within its region of stability
434  // -> Could do a lot better if I calculate the
435  // spinodal value of H.
436  for (int its = 0; its < 10; its++) {
437  Tnew = Told + dt;
438  if (Tnew < Told / 3.0) {
439  Tnew = Told / 3.0;
440  dt = -2.0 * Told / 3.0;
441  }
442  setState_conditional_TP(Tnew, p, !doUV);
443  if (doUV) {
444  Hnew = intEnergy_mass();
445  Cpnew = cv_mass();
446  } else {
447  Hnew = enthalpy_mass();
448  Cpnew = cp_mass();
449  }
450  if (Cpnew < 0.0) {
451  unstablePhaseNew = true;
452  Tunstable = Tnew;
453  } else {
454  unstablePhaseNew = false;
455  break;
456  }
457  if (unstablePhase == false && unstablePhaseNew == true) {
458  dt *= 0.25;
459  }
460  }
461 
462  if (Hnew == Htarget) {
463  return;
464  } else if (Hnew > Htarget && (Htop < Htarget || Hnew < Htop)) {
465  Htop = Hnew;
466  Ttop = Tnew;
467  } else if (Hnew < Htarget && (Hbot > Htarget || Hnew > Hbot)) {
468  Hbot = Hnew;
469  Tbot = Tnew;
470  }
471  // Convergence in H
472  double Herr = Htarget - Hnew;
473  double acpd = std::max(fabs(cpd), 1.0E-5);
474  double denom = std::max(fabs(Htarget), acpd * Tnew);
475  double HConvErr = fabs((Herr)/denom);
476  if (HConvErr < rtol || fabs(dt/Tnew) < rtol) {
477  return;
478  }
479  }
480  // We are here when there hasn't been convergence
481 
482  // Formulate a detailed error message, since questions seem to arise often
483  // about the lack of convergence.
484  string ErrString = "No convergence in 500 iterations\n";
485  if (doUV) {
486  ErrString += fmt::format(
487  "\tTarget Internal Energy = {}\n"
488  "\tCurrent Specific Volume = {}\n"
489  "\tStarting Temperature = {}\n"
490  "\tCurrent Temperature = {}\n"
491  "\tCurrent Internal Energy = {}\n"
492  "\tCurrent Delta T = {}\n",
493  Htarget, v, Tinit, Tnew, Hnew, dt);
494  } else {
495  ErrString += fmt::format(
496  "\tTarget Enthalpy = {}\n"
497  "\tCurrent Pressure = {}\n"
498  "\tStarting Temperature = {}\n"
499  "\tCurrent Temperature = {}\n"
500  "\tCurrent Enthalpy = {}\n"
501  "\tCurrent Delta T = {}\n",
502  Htarget, p, Tinit, Tnew, Hnew, dt);
503  }
504  if (unstablePhase) {
505  ErrString += fmt::format(
506  "\t - The phase became unstable (Cp < 0) T_unstable_last = {}\n",
507  Tunstable);
508  }
509  if (doUV) {
510  throw CanteraError("ThermoPhase::setState_HPorUV (UV)", ErrString);
511  } else {
512  throw CanteraError("ThermoPhase::setState_HPorUV (HP)", ErrString);
513  }
514 }
515 
516 void ThermoPhase::setState_SP(double Starget, double p, double rtol)
517 {
518  setState_SPorSV(Starget, p, rtol, false);
519 }
520 
521 void ThermoPhase::setState_SV(double Starget, double v, double rtol)
522 {
523  assertCompressible("setState_SV");
524  setState_SPorSV(Starget, v, rtol, true);
525 }
526 
527 void ThermoPhase::setState_SPorSV(double Starget, double p,
528  double rtol, bool doSV)
529 {
530  doublereal v = 0.0;
531  doublereal dt;
532  if (doSV) {
533  v = p;
534  if (v < 1.0E-300) {
535  throw CanteraError("ThermoPhase::setState_SPorSV (SV)",
536  "Input specific volume is too small or negative. v = {}", v);
537  }
538  setDensity(1.0/v);
539  } else {
540  if (p < 1.0E-300) {
541  throw CanteraError("ThermoPhase::setState_SPorSV (SP)",
542  "Input pressure is too small or negative. p = {}", p);
543  }
544  setPressure(p);
545  }
546  double Tmax = maxTemp() + 0.1;
547  double Tmin = minTemp() - 0.1;
548 
549  // Make sure we are within the temperature bounds at the start
550  // of the iteration
551  double Tnew = temperature();
552  double Tinit = Tnew;
553  if (Tnew > Tmax) {
554  Tnew = Tmax - 1.0;
555  } else if (Tnew < Tmin) {
556  Tnew = Tmin + 1.0;
557  }
558  if (Tnew != Tinit) {
559  setState_conditional_TP(Tnew, p, !doSV);
560  }
561 
562  double Snew = entropy_mass();
563  double Cpnew = (doSV) ? cv_mass() : cp_mass();
564  double Stop = Snew;
565  double Ttop = Tnew;
566  double Sbot = Snew;
567  double Tbot = Tnew;
568 
569  bool ignoreBounds = false;
570  // Unstable phases are those for which Cp < 0.0. These are possible for
571  // cases where we have passed the spinodal curve.
572  bool unstablePhase = false;
573  double Tunstable = -1.0;
574  bool unstablePhaseNew = false;
575 
576  // Newton iteration
577  for (int n = 0; n < 500; n++) {
578  double Told = Tnew;
579  double Sold = Snew;
580  double cpd = Cpnew;
581  if (cpd < 0.0) {
582  unstablePhase = true;
583  Tunstable = Tnew;
584  }
585  // limit step size to 100 K
586  dt = clip((Starget - Sold)*Told/cpd, -100.0, 100.0);
587  Tnew = Told + dt;
588 
589  // Limit the step size so that we are convergent
590  if ((dt > 0.0 && unstablePhase) || (dt <= 0.0 && !unstablePhase)) {
591  if (Sbot < Starget && Tnew < Tbot) {
592  dt = 0.75 * (Tbot - Told);
593  Tnew = Told + dt;
594  }
595  } else if (Stop > Starget && Tnew > Ttop) {
596  dt = 0.75 * (Ttop - Told);
597  Tnew = Told + dt;
598  }
599 
600  // Check Max and Min values
601  if (Tnew > Tmax && !ignoreBounds) {
602  setState_conditional_TP(Tmax, p, !doSV);
603  double Smax = entropy_mass();
604  if (Smax >= Starget) {
605  if (Stop < Starget) {
606  Ttop = Tmax;
607  Stop = Smax;
608  }
609  } else {
610  Tnew = Tmax + 1.0;
611  ignoreBounds = true;
612  }
613  } else if (Tnew < Tmin && !ignoreBounds) {
614  setState_conditional_TP(Tmin, p, !doSV);
615  double Smin = entropy_mass();
616  if (Smin <= Starget) {
617  if (Sbot > Starget) {
618  Tbot = Tmin;
619  Sbot = Smin;
620  }
621  } else {
622  Tnew = Tmin - 1.0;
623  ignoreBounds = true;
624  }
625  }
626 
627  // Try to keep phase within its region of stability
628  // -> Could do a lot better if I calculate the
629  // spinodal value of H.
630  for (int its = 0; its < 10; its++) {
631  Tnew = Told + dt;
632  setState_conditional_TP(Tnew, p, !doSV);
633  Cpnew = (doSV) ? cv_mass() : cp_mass();
634  Snew = entropy_mass();
635  if (Cpnew < 0.0) {
636  unstablePhaseNew = true;
637  Tunstable = Tnew;
638  } else {
639  unstablePhaseNew = false;
640  break;
641  }
642  if (unstablePhase == false && unstablePhaseNew == true) {
643  dt *= 0.25;
644  }
645  }
646 
647  if (Snew == Starget) {
648  return;
649  } else if (Snew > Starget && (Stop < Starget || Snew < Stop)) {
650  Stop = Snew;
651  Ttop = Tnew;
652  } else if (Snew < Starget && (Sbot > Starget || Snew > Sbot)) {
653  Sbot = Snew;
654  Tbot = Tnew;
655  }
656  // Convergence in S
657  double Serr = Starget - Snew;
658  double acpd = std::max(fabs(cpd), 1.0E-5);
659  double denom = std::max(fabs(Starget), acpd * Tnew);
660  double SConvErr = fabs((Serr * Tnew)/denom);
661  if (SConvErr < rtol || fabs(dt/Tnew) < rtol) {
662  return;
663  }
664  }
665  // We are here when there hasn't been convergence
666 
667  // Formulate a detailed error message, since questions seem to arise often
668  // about the lack of convergence.
669  string ErrString = "No convergence in 500 iterations\n";
670  if (doSV) {
671  ErrString += fmt::format(
672  "\tTarget Entropy = {}\n"
673  "\tCurrent Specific Volume = {}\n"
674  "\tStarting Temperature = {}\n"
675  "\tCurrent Temperature = {}\n"
676  "\tCurrent Entropy = {}\n"
677  "\tCurrent Delta T = {}\n",
678  Starget, v, Tinit, Tnew, Snew, dt);
679  } else {
680  ErrString += fmt::format(
681  "\tTarget Entropy = {}\n"
682  "\tCurrent Pressure = {}\n"
683  "\tStarting Temperature = {}\n"
684  "\tCurrent Temperature = {}\n"
685  "\tCurrent Entropy = {}\n"
686  "\tCurrent Delta T = {}\n",
687  Starget, p, Tinit, Tnew, Snew, dt);
688  }
689  if (unstablePhase) {
690  ErrString += fmt::format("\t - The phase became unstable (Cp < 0) T_unstable_last = {}\n",
691  Tunstable);
692  }
693  if (doSV) {
694  throw CanteraError("ThermoPhase::setState_SPorSV (SV)", ErrString);
695  } else {
696  throw CanteraError("ThermoPhase::setState_SPorSV (SP)", ErrString);
697  }
698 }
699 
700 double ThermoPhase::o2Required(const double* y) const
701 {
702  // indices of fuel elements
703  size_t iC = elementIndex("C");
704  size_t iS = elementIndex("S");
705  size_t iH = elementIndex("H");
706 
707  double o2req = 0.0;
708  double sum = 0.0;
709  for (size_t k = 0; k != m_kk; ++k) {
710  sum += y[k];
711  double x = y[k] / molecularWeights()[k];
712  if (iC != npos) {
713  o2req += x * nAtoms(k, iC);
714  }
715  if (iS != npos) {
716  o2req += x * nAtoms(k, iS);
717  }
718  if (iH != npos) {
719  o2req += x * 0.25 * nAtoms(k, iH);
720  }
721  }
722  if (sum == 0.0) {
723  throw CanteraError("ThermoPhase::o2Required",
724  "No composition specified");
725  }
726  return o2req/sum;
727 }
728 
729 double ThermoPhase::o2Present(const double* y) const
730 {
731  size_t iO = elementIndex("O");
732  double o2pres = 0.0;
733  double sum = 0.0;
734  for (size_t k = 0; k != m_kk; ++k) {
735  sum += y[k];
736  o2pres += y[k] / molecularWeights()[k] * nAtoms(k, iO);
737  }
738  if (sum == 0.0) {
739  throw CanteraError("ThermoPhase::o2Present",
740  "No composition specified");
741  }
742  return 0.5 * o2pres / sum;
743 }
744 
746  const compositionMap& oxComp,
747  ThermoBasis basis) const
748 {
749  vector_fp fuel(getCompositionFromMap(fuelComp));
750  vector_fp ox(getCompositionFromMap(oxComp));
751  return stoichAirFuelRatio(fuel.data(), ox.data(), basis);
752 }
753 
754 double ThermoPhase::stoichAirFuelRatio(const std::string& fuelComp,
755  const std::string& oxComp,
756  ThermoBasis basis) const
757 {
758  return stoichAirFuelRatio(
759  parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
760  parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
761  basis);
762 }
763 
764 double ThermoPhase::stoichAirFuelRatio(const double* fuelComp,
765  const double* oxComp,
766  ThermoBasis basis) const
767 {
768  vector_fp fuel, ox;
769  if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
770  fuel.resize(m_kk);
771  ox.resize(m_kk);
772  moleFractionsToMassFractions(fuelComp, fuel.data());
773  moleFractionsToMassFractions(oxComp, ox.data());
774  fuelComp = fuel.data();
775  oxComp = ox.data();
776  }
777 
778  double o2_required_fuel = o2Required(fuelComp) - o2Present(fuelComp);
779  double o2_required_ox = o2Required(oxComp) - o2Present(oxComp);
780 
781  if (o2_required_fuel < 0.0 || o2_required_ox > 0.0) {
782  throw CanteraError("ThermoPhase::stoichAirFuelRatio",
783  "Fuel composition contains too much oxygen or "
784  "oxidizer contains not enough oxygen. "
785  "Fuel and oxidizer composition mixed up?");
786  }
787 
788  if (o2_required_ox == 0.0) {
789  return std::numeric_limits<double>::infinity();
790  }
791 
792  return o2_required_fuel / (-o2_required_ox);
793 }
794 
795 void ThermoPhase::setEquivalenceRatio(double phi, const double* fuelComp,
796  const double* oxComp, ThermoBasis basis)
797 {
798  if (phi < 0.0) {
799  throw CanteraError("ThermoPhase::setEquivalenceRatio",
800  "Equivalence ratio phi must be >= 0");
801  }
802 
803  double p = pressure();
804 
805  vector_fp fuel, ox;
806  if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
807  fuel.resize(m_kk);
808  ox.resize(m_kk);
809  moleFractionsToMassFractions(fuelComp, fuel.data());
810  moleFractionsToMassFractions(oxComp, ox.data());
811  fuelComp = fuel.data();
812  oxComp = ox.data();
813  }
814 
815  double AFR_st = stoichAirFuelRatio(fuelComp, oxComp, ThermoBasis::mass);
816 
817  double sum_f = std::accumulate(fuelComp, fuelComp+m_kk, 0.0);
818  double sum_o = std::accumulate(oxComp, oxComp+m_kk, 0.0);
819 
820  vector_fp y(m_kk);
821  for (size_t k = 0; k != m_kk; ++k) {
822  y[k] = phi * fuelComp[k]/sum_f + AFR_st * oxComp[k]/sum_o;
823  }
824 
825  setMassFractions(y.data());
826  setPressure(p);
827 }
828 
829 void ThermoPhase::setEquivalenceRatio(double phi, const std::string& fuelComp,
830  const std::string& oxComp, ThermoBasis basis)
831 {
833  parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
834  parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
835  basis);
836 }
837 
838 void ThermoPhase::setEquivalenceRatio(double phi, const compositionMap& fuelComp,
839  const compositionMap& oxComp, ThermoBasis basis)
840 {
841  vector_fp fuel = getCompositionFromMap(fuelComp);
842  vector_fp ox = getCompositionFromMap(oxComp);
843  setEquivalenceRatio(phi, fuel.data(), ox.data(), basis);
844 }
845 
847 {
848  double o2_required = o2Required(massFractions());
849  double o2_present = o2Present(massFractions());
850 
851  if (o2_present == 0.0) { // pure fuel
852  return std::numeric_limits<double>::infinity();
853  }
854 
855  return o2_required / o2_present;
856 }
857 
859  const compositionMap& oxComp,
860  ThermoBasis basis) const
861 {
862  vector_fp fuel(getCompositionFromMap(fuelComp));
863  vector_fp ox(getCompositionFromMap(oxComp));
864  return equivalenceRatio(fuel.data(), ox.data(), basis);
865 }
866 
867 double ThermoPhase::equivalenceRatio(const std::string& fuelComp,
868  const std::string& oxComp,
869  ThermoBasis basis) const
870 {
871  return equivalenceRatio(
872  parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
873  parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
874  basis);
875 }
876 
877 double ThermoPhase::equivalenceRatio(const double* fuelComp,
878  const double* oxComp,
879  ThermoBasis basis) const
880 {
881  double Z = mixtureFraction(fuelComp, oxComp, basis);
882 
883  if (Z == 0.0) {
884  return 0.0; // pure oxidizer
885  }
886 
887  if (Z == 1.0) {
888  return std::numeric_limits<double>::infinity(); // pure fuel
889  }
890 
891  vector_fp fuel, ox;
892  if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
893  fuel.resize(m_kk);
894  ox.resize(m_kk);
895  moleFractionsToMassFractions(fuelComp, fuel.data());
896  moleFractionsToMassFractions(oxComp, ox.data());
897  fuelComp = fuel.data();
898  oxComp = ox.data();
899  }
900 
901  double AFR_st = stoichAirFuelRatio(fuelComp, oxComp, ThermoBasis::mass);
902 
903  return std::max(Z / (1.0 - Z) * AFR_st, 0.0);
904 }
905 
906 void ThermoPhase::setMixtureFraction(double mixFrac, const compositionMap& fuelComp,
907  const compositionMap& oxComp, ThermoBasis basis)
908 {
909  vector_fp fuel(getCompositionFromMap(fuelComp));
910  vector_fp ox(getCompositionFromMap(oxComp));
911  setMixtureFraction(mixFrac, fuel.data(), ox.data(), basis);
912 }
913 
914 void ThermoPhase::setMixtureFraction(double mixFrac, const std::string& fuelComp,
915  const std::string& oxComp, ThermoBasis basis)
916 {
917  setMixtureFraction(mixFrac,
918  parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
919  parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
920  basis);
921 }
922 
923 void ThermoPhase::setMixtureFraction(double mixFrac, const double* fuelComp,
924  const double* oxComp, ThermoBasis basis)
925 {
926  if (mixFrac < 0.0 || mixFrac > 1.0) {
927  throw CanteraError("ThermoPhase::setMixtureFraction",
928  "Mixture fraction must be between 0 and 1");
929  }
930 
931  vector_fp fuel, ox;
932  if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
933  fuel.resize(m_kk);
934  ox.resize(m_kk);
935  moleFractionsToMassFractions(fuelComp, fuel.data());
936  moleFractionsToMassFractions(oxComp, ox.data());
937  fuelComp = fuel.data();
938  oxComp = ox.data();
939  }
940 
941  double sum_yf = std::accumulate(fuelComp, fuelComp+m_kk, 0.0);
942  double sum_yo = std::accumulate(oxComp, oxComp+m_kk, 0.0);
943 
944  if (sum_yf == 0.0 || sum_yo == 0.0) {
945  throw CanteraError("ThermoPhase::setMixtureFraction",
946  "No fuel and/or oxidizer composition specified");
947  }
948 
949  double p = pressure();
950 
951  vector_fp y(m_kk);
952 
953  for (size_t k = 0; k != m_kk; ++k) {
954  y[k] = mixFrac * fuelComp[k]/sum_yf + (1.0-mixFrac) * oxComp[k]/sum_yo;
955  }
956 
957  setMassFractions_NoNorm(y.data());
958  setPressure(p);
959 }
960 
962  const compositionMap& oxComp,
963  ThermoBasis basis,
964  const std::string& element) const
965 {
966  vector_fp fuel(getCompositionFromMap(fuelComp));
967  vector_fp ox(getCompositionFromMap(oxComp));
968  return mixtureFraction(fuel.data(), ox.data(), basis, element);
969 }
970 
971 double ThermoPhase::mixtureFraction(const std::string& fuelComp,
972  const std::string& oxComp,
973  ThermoBasis basis,
974  const std::string& element) const
975 {
976  return mixtureFraction(
977  parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
978  parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
979  basis, element);
980 }
981 
982 double ThermoPhase::mixtureFraction(const double* fuelComp,
983  const double* oxComp,
984  ThermoBasis basis,
985  const std::string& element) const
986 {
987  vector_fp fuel, ox;
988  if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
989  fuel.resize(m_kk);
990  ox.resize(m_kk);
991  moleFractionsToMassFractions(fuelComp, fuel.data());
992  moleFractionsToMassFractions(oxComp, ox.data());
993  fuelComp = fuel.data();
994  oxComp = ox.data();
995  }
996 
997  if (element == "Bilger") // compute the mixture fraction based on the Bilger mixture fraction
998  {
999  double o2_required_fuel = o2Required(fuelComp) - o2Present(fuelComp);
1000  double o2_required_ox = o2Required(oxComp) - o2Present(oxComp);
1001  double o2_required_mix = o2Required(massFractions()) - o2Present(massFractions());
1002 
1003  if (o2_required_fuel < 0.0 || o2_required_ox > 0.0) {
1004  throw CanteraError("ThermoPhase::mixtureFraction",
1005  "Fuel composition contains too much oxygen or "
1006  "oxidizer contains not enough oxygen. "
1007  "Fuel and oxidizer composition mixed up?");
1008  }
1009 
1010  double denominator = o2_required_fuel - o2_required_ox;
1011 
1012  if (denominator == 0.0) {
1013  throw CanteraError("ThermoPhase::mixtureFraction",
1014  "Fuel and oxidizer have the same composition");
1015  }
1016 
1017  double Z = (o2_required_mix - o2_required_ox) / denominator;
1018 
1019  return std::min(std::max(Z, 0.0), 1.0);
1020  } else {
1021  // compute the mixture fraction from a single element
1022  double sum_yf = std::accumulate(fuelComp, fuelComp+m_kk, 0.0);
1023  double sum_yo = std::accumulate(oxComp, oxComp+m_kk, 0.0);
1024 
1025  if (sum_yf == 0.0 || sum_yo == 0.0) {
1026  throw CanteraError("ThermoPhase::mixtureFraction",
1027  "No fuel and/or oxidizer composition specified");
1028  }
1029 
1030  auto elementalFraction = [this](size_t m, const double* y) {
1031  double Z_m = 0.0;
1032  for (size_t k = 0; k != m_kk; ++k) {
1033  Z_m += y[k] / molecularWeight(k) * nAtoms(k, m);
1034  }
1035  return Z_m;
1036  };
1037 
1038  size_t m = elementIndex(element);
1039  double Z_m_fuel = elementalFraction(m, fuelComp)/sum_yf;
1040  double Z_m_ox = elementalFraction(m, oxComp)/sum_yo;
1041  double Z_m_mix = elementalFraction(m, massFractions());
1042 
1043  if (Z_m_fuel == Z_m_ox) {
1044  throw CanteraError("ThermoPhase::mixtureFraction",
1045  "Fuel and oxidizer have the same composition for element {}",
1046  element);
1047  }
1048  double Z = (Z_m_mix - Z_m_ox) / (Z_m_fuel - Z_m_ox);
1049  return std::min(std::max(Z, 0.0), 1.0);
1050  }
1051 }
1052 
1054 {
1055  return m_spthermo;
1056 }
1057 
1059 {
1060  return m_spthermo;
1061 }
1062 
1063 
1064 void ThermoPhase::initThermoFile(const std::string& inputFile,
1065  const std::string& id)
1066 {
1067  size_t dot = inputFile.find_last_of(".");
1068  string extension;
1069  if (dot != npos) {
1070  extension = inputFile.substr(dot+1);
1071  }
1072 
1073  if (extension == "yml" || extension == "yaml") {
1074  AnyMap root = AnyMap::fromYamlFile(inputFile);
1075  auto& phase = root["phases"].getMapWhere("name", id);
1076  setupPhase(*this, phase, root);
1077  } else {
1078  XML_Node* fxml = get_XML_File(inputFile);
1079  XML_Node* fxml_phase = findXMLPhase(fxml, id);
1080  if (!fxml_phase) {
1081  throw CanteraError("ThermoPhase::initThermoFile",
1082  "ERROR: Can not find phase named {} in file"
1083  " named {}", id, inputFile);
1084  }
1085  importPhase(*fxml_phase, this);
1086  }
1087 }
1088 
1089 void ThermoPhase::initThermoXML(XML_Node& phaseNode, const std::string& id)
1090 {
1091  if (phaseNode.hasChild("state")) {
1092  setStateFromXML(phaseNode.child("state"));
1093  }
1094 }
1095 
1097 {
1098  // Check to see that all of the species thermo objects have been initialized
1099  if (!m_spthermo.ready(m_kk)) {
1100  throw CanteraError("ThermoPhase::initThermo()",
1101  "Missing species thermo data");
1102  }
1103 }
1104 
1105 void ThermoPhase::setState_TPQ(double T, double P, double Q)
1106 {
1107  if (T > critTemperature()) {
1108  if (P > critPressure() || Q == 1) {
1109  setState_TP(T, P);
1110  return;
1111  } else {
1112  throw CanteraError("ThermoPhase::setState_TPQ",
1113  "Temperature ({}), pressure ({}) and vapor fraction ({}) "
1114  "are inconsistent, above the critical temperature.",
1115  T, P, Q);
1116  }
1117  }
1118 
1119  double Psat = satPressure(T);
1120  if (std::abs(Psat / P - 1) < 1e-6) {
1121  setState_Tsat(T, Q);
1122  } else if ((Q == 0 && P >= Psat) || (Q == 1 && P <= Psat)) {
1123  setState_TP(T, P);
1124  } else {
1125  throw CanteraError("ThermoPhase::setState_TPQ",
1126  "Temperature ({}), pressure ({}) and vapor fraction ({}) "
1127  "are inconsistent.\nPsat at this T: {}\n"
1128  "Consider specifying the state using two fully independent "
1129  "properties (e.g. temperature and density)",
1130  T, P, Q, Psat);
1131  }
1132 }
1133 
1134 bool ThermoPhase::addSpecies(shared_ptr<Species> spec)
1135 {
1136  if (!spec->thermo) {
1137  throw CanteraError("ThermoPhase::addSpecies",
1138  "Species {} has no thermo data", spec->name);
1139  }
1140  bool added = Phase::addSpecies(spec);
1141  if (added) {
1142  spec->thermo->validate(spec->name);
1143  m_spthermo.install_STIT(m_kk-1, spec->thermo);
1144  }
1145  return added;
1146 }
1147 
1148 void ThermoPhase::modifySpecies(size_t k, shared_ptr<Species> spec)
1149 {
1150  if (!spec->thermo) {
1151  throw CanteraError("ThermoPhase::modifySpecies",
1152  "Species {} has no thermo data", spec->name);
1153  }
1154  Phase::modifySpecies(k, spec);
1155  if (speciesName(k) != spec->name) {
1156  throw CanteraError("ThermoPhase::modifySpecies",
1157  "New species '{}' does not match existing species '{}' at index {}",
1158  spec->name, speciesName(k), k);
1159  }
1160  spec->thermo->validate(spec->name);
1161  m_spthermo.modifySpecies(k, spec->thermo);
1162 }
1163 
1164 void ThermoPhase::saveSpeciesData(const size_t k, const XML_Node* const data)
1165 {
1166  if (m_speciesData.size() < (k + 1)) {
1167  m_speciesData.resize(k+1, 0);
1168  }
1169  m_speciesData[k] = new XML_Node(*data);
1170 }
1171 
1172 const std::vector<const XML_Node*> & ThermoPhase::speciesData() const
1173 {
1174  if (m_speciesData.size() != m_kk) {
1175  throw CanteraError("ThermoPhase::speciesData",
1176  "m_speciesData is the wrong size");
1177  }
1178  return m_speciesData;
1179 }
1180 
1181 void ThermoPhase::setParameters(const AnyMap& phaseNode, const AnyMap& rootNode)
1182 {
1183  m_input = phaseNode;
1184 }
1185 
1187 {
1188  return m_input;
1189 }
1190 
1192 {
1193  return m_input;
1194 }
1195 
1197 {
1198  string comp = getChildValue(state,"moleFractions");
1199  if (comp != "") {
1200  setMoleFractionsByName(comp);
1201  } else {
1202  comp = getChildValue(state,"massFractions");
1203  if (comp != "") {
1204  setMassFractionsByName(comp);
1205  }
1206  }
1207  if (state.hasChild("temperature")) {
1208  double t = getFloat(state, "temperature", "temperature");
1209  setTemperature(t);
1210  }
1211  if (state.hasChild("pressure")) {
1212  double p = getFloat(state, "pressure", "pressure");
1213  setPressure(p);
1214  }
1215  if (state.hasChild("density")) {
1216  double rho = getFloat(state, "density", "density");
1217  setDensity(rho);
1218  }
1219 }
1220 
1223  m_tlast += 0.1234;
1224 }
1225 
1226 void ThermoPhase::equilibrate(const std::string& XY, const std::string& solver,
1227  double rtol, int max_steps, int max_iter,
1228  int estimate_equil, int log_level)
1229 {
1230  if (solver == "auto" || solver == "element_potential") {
1231  vector_fp initial_state;
1232  saveState(initial_state);
1233  debuglog("Trying ChemEquil solver\n", log_level);
1234  try {
1235  ChemEquil E;
1236  E.options.maxIterations = max_steps;
1237  E.options.relTolerance = rtol;
1238  int ret = E.equilibrate(*this, XY.c_str(), log_level-1);
1239  if (ret < 0) {
1240  throw CanteraError("ThermoPhase::equilibrate",
1241  "ChemEquil solver failed. Return code: {}", ret);
1242  }
1243  debuglog("ChemEquil solver succeeded\n", log_level);
1244  return;
1245  } catch (std::exception& err) {
1246  debuglog("ChemEquil solver failed.\n", log_level);
1247  debuglog(err.what(), log_level);
1248  restoreState(initial_state);
1249  if (solver == "auto") {
1250  } else {
1251  throw;
1252  }
1253  }
1254  }
1255 
1256  if (solver == "auto" || solver == "vcs" || solver == "gibbs") {
1257  MultiPhase M;
1258  M.addPhase(this, 1.0);
1259  M.init();
1260  M.equilibrate(XY, solver, rtol, max_steps, max_iter,
1261  estimate_equil, log_level);
1262  return;
1263  }
1264 
1265  if (solver != "auto") {
1266  throw CanteraError("ThermoPhase::equilibrate",
1267  "Invalid solver specified: '{}'", solver);
1268  }
1269 }
1270 
1271 void ThermoPhase::getdlnActCoeffdlnN(const size_t ld, doublereal* const dlnActCoeffdlnN)
1272 {
1273  for (size_t m = 0; m < m_kk; m++) {
1274  for (size_t k = 0; k < m_kk; k++) {
1275  dlnActCoeffdlnN[ld * k + m] = 0.0;
1276  }
1277  }
1278  return;
1279 }
1280 
1281 void ThermoPhase::getdlnActCoeffdlnN_numderiv(const size_t ld, doublereal* const dlnActCoeffdlnN)
1282 {
1283  double deltaMoles_j = 0.0;
1284  double pres = pressure();
1285 
1286  // Evaluate the current base activity coefficients if necessary
1287  vector_fp ActCoeff_Base(m_kk);
1288  getActivityCoefficients(ActCoeff_Base.data());
1289  vector_fp Xmol_Base(m_kk);
1290  getMoleFractions(Xmol_Base.data());
1291 
1292  // Make copies of ActCoeff and Xmol_ for use in taking differences
1293  vector_fp ActCoeff(m_kk);
1294  vector_fp Xmol(m_kk);
1295  double v_totalMoles = 1.0;
1296  double TMoles_base = v_totalMoles;
1297 
1298  // Loop over the columns species to be deltad
1299  for (size_t j = 0; j < m_kk; j++) {
1300  // Calculate a value for the delta moles of species j
1301  // -> Note Xmol_[] and Tmoles are always positive or zero quantities.
1302  // -> experience has shown that you always need to make the deltas
1303  // greater than needed to change the other mole fractions in order
1304  // to capture some effects.
1305  double moles_j_base = v_totalMoles * Xmol_Base[j];
1306  deltaMoles_j = 1.0E-7 * moles_j_base + v_totalMoles * 1.0E-13 + 1.0E-150;
1307 
1308  // Now, update the total moles in the phase and all of the mole
1309  // fractions based on this.
1310  v_totalMoles = TMoles_base + deltaMoles_j;
1311  for (size_t k = 0; k < m_kk; k++) {
1312  Xmol[k] = Xmol_Base[k] * TMoles_base / v_totalMoles;
1313  }
1314  Xmol[j] = (moles_j_base + deltaMoles_j) / v_totalMoles;
1315 
1316  // Go get new values for the activity coefficients.
1317  // -> Note this calls setState_PX();
1318  setState_PX(pres, Xmol.data());
1319  getActivityCoefficients(ActCoeff.data());
1320 
1321  // Calculate the column of the matrix
1322  double* const lnActCoeffCol = dlnActCoeffdlnN + ld * j;
1323  for (size_t k = 0; k < m_kk; k++) {
1324  lnActCoeffCol[k] = (2*moles_j_base + deltaMoles_j) *(ActCoeff[k] - ActCoeff_Base[k]) /
1325  ((ActCoeff[k] + ActCoeff_Base[k]) * deltaMoles_j);
1326  }
1327  // Revert to the base case Xmol_, v_totalMoles
1328  v_totalMoles = TMoles_base;
1329  Xmol = Xmol_Base;
1330  }
1331 
1332  setState_PX(pres, Xmol_Base.data());
1333 }
1334 
1335 std::string ThermoPhase::report(bool show_thermo, doublereal threshold) const
1336 {
1337  fmt::memory_buffer b;
1338  // This is the width of the first column of names in the report.
1339  int name_width = 18;
1340 
1341  string blank_leader = fmt::format("{:{}}", "", name_width);
1342 
1343  string one_property = "{:>{}} {:<.5g} {}\n";
1344 
1345  string two_prop_header = "{} {:^15} {:^15}\n";
1346  string kg_kmol_header = fmt::format(
1347  two_prop_header, blank_leader, "1 kg", "1 kmol"
1348  );
1349  string Y_X_header = fmt::format(
1350  two_prop_header, blank_leader, "mass frac. Y", "mole frac. X"
1351  );
1352  string two_prop_sep = fmt::format(
1353  "{} {:-^15} {:-^15}\n", blank_leader, "", ""
1354  );
1355  string two_property = "{:>{}} {:15.5g} {:15.5g} {}\n";
1356 
1357  string three_prop_header = fmt::format(
1358  "{} {:^15} {:^15} {:^15}\n", blank_leader, "mass frac. Y",
1359  "mole frac. X", "chem. pot. / RT"
1360  );
1361  string three_prop_sep = fmt::format(
1362  "{} {:-^15} {:-^15} {:-^15}\n", blank_leader, "", "", ""
1363  );
1364  string three_property = "{:>{}} {:15.5g} {:15.5g} {:15.5g}\n";
1365 
1366  try {
1367  if (name() != "") {
1368  format_to(b, "\n {}:\n", name());
1369  }
1370  format_to(b, "\n");
1371  format_to(b, one_property, "temperature", name_width, temperature(), "K");
1372  format_to(b, one_property, "pressure", name_width, pressure(), "Pa");
1373  format_to(b, one_property, "density", name_width, density(), "kg/m^3");
1374  format_to(b, one_property, "mean mol. weight", name_width, meanMolecularWeight(), "kg/kmol");
1375 
1376  double phi = electricPotential();
1377  if (phi != 0.0) {
1378  format_to(b, one_property, "potential", name_width, phi, "V");
1379  }
1380 
1381  format_to(b, "{:>{}} {}\n", "phase of matter", name_width, phaseOfMatter());
1382 
1383  if (show_thermo) {
1384  format_to(b, "\n");
1385  format_to(b, kg_kmol_header);
1386  format_to(b, two_prop_sep);
1387  format_to(b, two_property, "enthalpy", name_width, enthalpy_mass(), enthalpy_mole(), "J");
1388  format_to(b, two_property, "internal energy", name_width, intEnergy_mass(), intEnergy_mole(), "J");
1389  format_to(b, two_property, "entropy", name_width, entropy_mass(), entropy_mole(), "J/K");
1390  format_to(b, two_property, "Gibbs function", name_width, gibbs_mass(), gibbs_mole(), "J");
1391  format_to(b, two_property, "heat capacity c_p", name_width, cp_mass(), cp_mole(), "J/K");
1392  try {
1393  format_to(b, two_property, "heat capacity c_v", name_width, cv_mass(), cv_mole(), "J/K");
1394  } catch (NotImplementedError&) {
1395  format_to(b, "{:>{}} <not implemented> \n", "heat capacity c_v", name_width);
1396  }
1397  }
1398 
1399  vector_fp x(m_kk);
1400  vector_fp y(m_kk);
1401  vector_fp mu(m_kk);
1402  getMoleFractions(&x[0]);
1403  getMassFractions(&y[0]);
1404  getChemPotentials(&mu[0]);
1405  int nMinor = 0;
1406  double xMinor = 0.0;
1407  double yMinor = 0.0;
1408  format_to(b, "\n");
1409  if (show_thermo) {
1410  format_to(b, three_prop_header);
1411  format_to(b, three_prop_sep);
1412  for (size_t k = 0; k < m_kk; k++) {
1413  if (abs(x[k]) >= threshold) {
1414  if (abs(x[k]) > SmallNumber) {
1415  format_to(b, three_property, speciesName(k), name_width, y[k], x[k], mu[k]/RT());
1416  } else {
1417  format_to(b, two_property, speciesName(k), name_width, y[k], x[k], "");
1418  }
1419  } else {
1420  nMinor++;
1421  xMinor += x[k];
1422  yMinor += y[k];
1423  }
1424  }
1425  } else {
1426  format_to(b, Y_X_header);
1427  format_to(b, two_prop_sep);
1428  for (size_t k = 0; k < m_kk; k++) {
1429  if (abs(x[k]) >= threshold) {
1430  format_to(b, two_property, speciesName(k), name_width, y[k], x[k], "");
1431  } else {
1432  nMinor++;
1433  xMinor += x[k];
1434  yMinor += y[k];
1435  }
1436  }
1437  }
1438  if (nMinor) {
1439  string minor = fmt::format("[{:+5d} minor]", nMinor);
1440  format_to(b, two_property, minor, name_width, yMinor, xMinor, "");
1441  }
1442  } catch (CanteraError& err) {
1443  return to_string(b) + err.what();
1444  }
1445  return to_string(b);
1446 }
1447 
1448 void ThermoPhase::reportCSV(std::ofstream& csvFile) const
1449 {
1450  int tabS = 15;
1451  int tabM = 30;
1452  csvFile.precision(8);
1453  vector_fp X(nSpecies());
1454  getMoleFractions(&X[0]);
1455  std::vector<std::string> pNames;
1456  std::vector<vector_fp> data;
1457  getCsvReportData(pNames, data);
1458 
1459  csvFile << setw(tabS) << "Species,";
1460  for (size_t i = 0; i < pNames.size(); i++) {
1461  csvFile << setw(tabM) << pNames[i] << ",";
1462  }
1463  csvFile << endl;
1464  for (size_t k = 0; k < nSpecies(); k++) {
1465  csvFile << setw(tabS) << speciesName(k) + ",";
1466  if (X[k] > SmallNumber) {
1467  for (size_t i = 0; i < pNames.size(); i++) {
1468  csvFile << setw(tabM) << data[i][k] << ",";
1469  }
1470  csvFile << endl;
1471  } else {
1472  for (size_t i = 0; i < pNames.size(); i++) {
1473  csvFile << setw(tabM) << 0 << ",";
1474  }
1475  csvFile << endl;
1476  }
1477  }
1478 }
1479 
1480 void ThermoPhase::getCsvReportData(std::vector<std::string>& names,
1481  std::vector<vector_fp>& data) const
1482 {
1483  names.clear();
1484  data.assign(10, vector_fp(nSpecies()));
1485 
1486  names.push_back("X");
1487  getMoleFractions(&data[0][0]);
1488 
1489  names.push_back("Y");
1490  getMassFractions(&data[1][0]);
1491 
1492  names.push_back("Chem. Pot (J/kmol)");
1493  getChemPotentials(&data[2][0]);
1494 
1495  names.push_back("Activity");
1496  getActivities(&data[3][0]);
1497 
1498  names.push_back("Act. Coeff.");
1499  getActivityCoefficients(&data[4][0]);
1500 
1501  names.push_back("Part. Mol Enthalpy (J/kmol)");
1502  getPartialMolarEnthalpies(&data[5][0]);
1503 
1504  names.push_back("Part. Mol. Entropy (J/K/kmol)");
1505  getPartialMolarEntropies(&data[6][0]);
1506 
1507  names.push_back("Part. Mol. Energy (J/kmol)");
1508  getPartialMolarIntEnergies(&data[7][0]);
1509 
1510  names.push_back("Part. Mol. Cp (J/K/kmol");
1511  getPartialMolarCp(&data[8][0]);
1512 
1513  names.push_back("Part. Mol. Cv (J/K/kmol)");
1514  getPartialMolarVolumes(&data[9][0]);
1515 }
1516 
1517 }
Chemical equilibrium.
Headers for the MultiPhase object that is used to set up multiphase equilibrium problems (see Equilfu...
Pure Virtual Base class for individual species reference state thermodynamic managers and text for th...
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:360
size_t size() const
Returns the number of elements in this map.
Definition: AnyMap.h:484
double convert(const std::string &key, const std::string &units) const
Convert the item stored by the given key to the units specified in units.
Definition: AnyMap.cpp:1055
static AnyMap fromYamlFile(const std::string &name, const std::string &parent_name="")
Create an AnyMap from a YAML file.
Definition: AnyMap.cpp:1156
void erase(const std::string &key)
Erase the value held by key.
Definition: AnyMap.cpp:989
std::string keys_str() const
Return a string listing the keys in this AnyMap, e.g.
Definition: AnyMap.cpp:999
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:984
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
const char * what() const
Get a description of the error.
Class ChemEquil implements a chemical equilibrium solver for single-phase solutions.
Definition: ChemEquil.h:83
int equilibrate(thermo_t &s, const char *XY, int loglevel=0)
Definition: ChemEquil.cpp:308
EquilOpt options
Options controlling how the calculation is carried out.
Definition: ChemEquil.h:131
doublereal relTolerance
Relative tolerance.
Definition: ChemEquil.h:34
int maxIterations
Maximum number of iterations.
Definition: ChemEquil.h:36
A class for multiphase mixtures.
Definition: MultiPhase.h:58
void init()
Process phases and build atomic composition array.
Definition: MultiPhase.cpp:116
void addPhase(ThermoPhase *p, doublereal moles)
Add a phase to the mixture.
Definition: MultiPhase.cpp:49
A species thermodynamic property manager for a phase.
bool ready(size_t nSpecies)
Check if data for all species (0 through nSpecies-1) has been installed.
virtual void install_STIT(size_t index, shared_ptr< SpeciesThermoInterpType > stit)
Install a new species thermodynamic property parameterization for one species.
virtual void modifySpecies(size_t index, shared_ptr< SpeciesThermoInterpType > spec)
Modify the species thermodynamic property parameterization for a species.
virtual void resetHf298(const size_t k)
Restore the original heat of formation of one or more species.
An error indicating that an unimplemented function has been called.
Definition: ctexceptions.h:187
virtual bool addSpecies(shared_ptr< Species > spec)
Add a Species to this Phase.
Definition: Phase.cpp:833
virtual void setMoleFractions(const double *const x)
Set the mole fractions to the specified values.
Definition: Phase.cpp:368
std::string name() const
Return the name of the phase.
Definition: Phase.cpp:84
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:285
void setMoleFractionsByName(const compositionMap &xMap)
Set the species mole fractions by name.
Definition: Phase.cpp:409
doublereal charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
Definition: Phase.h:643
virtual void setMassFractions_NoNorm(const double *const y)
Set the mass fractions to the specified values without normalizing.
Definition: Phase.cpp:434
void assertCompressible(const std::string &setter) const
Ensure that phase is compressible.
Definition: Phase.h:902
vector_fp getCompositionFromMap(const compositionMap &comp) const
Converts a compositionMap to a vector with entries for each species Species that are not specified ar...
Definition: Phase.cpp:1032
size_t m_kk
Number of species in the phase.
Definition: Phase.h:942
virtual void modifySpecies(size_t k, shared_ptr< Species > spec)
Modify the thermodynamic data associated with a species.
Definition: Phase.cpp:929
size_t nDim() const
Returns the number of spatial dimensions (1, 2, or 3)
Definition: Phase.h:651
void saveState(vector_fp &state) const
Save the current internal state of the phase.
Definition: Phase.cpp:315
const vector_fp & molecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition: Phase.cpp:538
virtual void setPressure(double p)
Set the internally stored pressure (Pa) at constant temperature and composition.
Definition: Phase.h:718
void moleFractionsToMassFractions(const double *X, double *Y) const
Converts a mixture composition from mass fractions to mole fractions.
Definition: Phase.cpp:1061
size_t elementIndex(const std::string &name) const
Return the index of element named 'name'.
Definition: Phase.cpp:120
doublereal molecularWeight(size_t k) const
Molecular weight of species k.
Definition: Phase.cpp:521
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:229
virtual void setDensity(const double density_)
Set the internally stored density (kg/m^3) of the phase.
Definition: Phase.cpp:716
const double * massFractions() const
Return a const pointer to the mass fraction array.
Definition: Phase.h:544
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:748
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:572
void setState_TR(doublereal t, doublereal rho)
Set the internally stored temperature (K) and density (kg/m^3)
Definition: Phase.cpp:491
doublereal nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
Definition: Phase.cpp:168
virtual double density() const
Density (kg/m^3).
Definition: Phase.h:685
doublereal temperature() const
Temperature (K).
Definition: Phase.h:667
virtual void setMassFractions(const double *const y)
Set the mass fractions to the specified values and normalize them.
Definition: Phase.cpp:420
void restoreState(const vector_fp &state)
Restore a state saved on a previous call to saveState.
Definition: Phase.cpp:339
virtual void setTemperature(const doublereal temp)
Set the internally stored temperature of the phase (K).
Definition: Phase.h:724
virtual void invalidateCache()
Invalidate any cached values which are normally updated only when a change in state is detected.
Definition: Phase.cpp:1014
void setMassFractionsByName(const compositionMap &yMap)
Set the species mass fractions by name.
Definition: Phase.cpp:445
void getMassFractions(double *const y) const
Get the species mass fractions.
Definition: Phase.cpp:614
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition: Phase.h:679
virtual void setStateFromXML(const XML_Node &state)
Set the initial state of the phase to the conditions specified in the state XML element.
int m_ssConvention
Contains the standard state convention.
Definition: ThermoPhase.h:1901
virtual std::string report(bool show_thermo=true, doublereal threshold=-1e-14) const
returns a summary of the state of the phase as a string
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 getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution.
Definition: ThermoPhase.h:525
virtual void setState_PY(doublereal p, doublereal *y)
Set the internally stored pressure (Pa) and mass fractions.
virtual void setState_HP(double h, double p, double tol=1e-9)
Set the internally stored specific enthalpy (J/kg) and pressure (Pa) of the phase.
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
Definition: ThermoPhase.h:249
virtual void setState_UV(double u, double v, double tol=1e-9)
Set the specific internal energy (J/kg) and specific volume (m^3/kg).
virtual bool addSpecies(shared_ptr< Species > spec)
double equivalenceRatio() const
Compute the equivalence ratio for the current mixture from available oxygen and required oxygen.
doublereal entropy_mass() const
Specific entropy. Units: J/kg/K.
Definition: ThermoPhase.h:752
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
virtual doublereal critPressure() const
Critical pressure (Pa).
Definition: ThermoPhase.h:1486
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
Definition: ThermoPhase.h:515
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:776
virtual void getActivities(doublereal *a) const
Get the array of non-dimensional activities at the current solution temperature, pressure,...
Definition: ThermoPhase.cpp:75
virtual void getLnActivityCoefficients(doublereal *lnac) const
Get the array of non-dimensional molar-based ln activity coefficients at the current solution tempera...
Definition: ThermoPhase.cpp:83
doublereal m_tlast
last value of the temperature processed by reference state
Definition: ThermoPhase.h:1904
virtual doublereal critTemperature() const
Critical temperature (K).
Definition: ThermoPhase.h:1481
virtual void setState_TV(double t, double v, double tol=1e-9)
Set the temperature (K) and specific volume (m^3/kg).
Definition: ThermoPhase.h:975
double o2Present(const double *y) const
Helper function for computing the amount of oxygen available in the current mixture.
virtual void setState_Tsat(doublereal t, doublereal x)
Set the state to a saturated system at a particular temperature.
Definition: ThermoPhase.h:1540
virtual void setState_PV(double p, double v, double tol=1e-9)
Set the pressure (Pa) and specific volume (m^3/kg).
Definition: ThermoPhase.h:991
virtual doublereal satPressure(doublereal t)
Return the saturation pressure given the temperature.
Definition: ThermoPhase.h:1526
virtual void setState(const AnyMap &state)
Set the state using an AnyMap containing any combination of properties supported by the thermodynamic...
void setState_SPorSV(double s, double p, double tol=1e-9, bool doSV=false)
Carry out work in SP and SV calculations.
void setState_HPorUV(doublereal h, doublereal p, doublereal tol=1e-9, bool doUV=false)
Carry out work in HP and UV calculations.
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: ThermoPhase.h:489
virtual void getActivityCoefficients(doublereal *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
Definition: ThermoPhase.h:448
virtual void initThermoFile(const std::string &inputFile, const std::string &id)
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
doublereal gibbs_mass() const
Specific Gibbs function. Units: J/kg.
Definition: ThermoPhase.h:757
virtual doublereal logStandardConc(size_t k=0) const
Natural logarithm of the standard concentration of the kth species.
Definition: ThermoPhase.cpp:70
virtual void modifySpecies(size_t k, shared_ptr< Species > spec)
Modify the thermodynamic data associated with a species.
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 setState_ST(double s, double t, double tol=1e-9)
Set the specific entropy (J/kg/K) and temperature (K).
Definition: ThermoPhase.h:959
double stoichAirFuelRatio(const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar) const
Compute the stoichiometric air to fuel ratio (kg oxidizer / kg fuel) given fuel and oxidizer composit...
virtual doublereal entropy_mole() const
Molar entropy. Units: J/kmol/K.
Definition: ThermoPhase.h:244
virtual void setState_RPY(doublereal rho, doublereal p, const doublereal *y)
Set the density (kg/m**3), pressure (Pa) and mass fractions.
virtual void setState_TPX(doublereal t, doublereal p, const doublereal *x)
Set the temperature (K), pressure (Pa), and mole fractions.
const std::vector< const XML_Node * > & speciesData() const
Return a pointer to the vector of XML nodes containing the species data for this phase.
virtual void getPartialMolarVolumes(doublereal *vbar) const
Return an array of partial molar volumes for the species in the mixture.
Definition: ThermoPhase.h:556
doublereal cp_mass() const
Specific heat at constant pressure. Units: J/kg/K.
Definition: ThermoPhase.h:762
virtual void getPartialMolarCp(doublereal *cpbar) const
Return an array of partial molar heat capacities for the species in the mixture.
Definition: ThermoPhase.h:546
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...
virtual doublereal cp_mole() const
Molar heat capacity at constant pressure. Units: J/kmol/K.
Definition: ThermoPhase.h:254
virtual void setState_PX(doublereal p, doublereal *x)
Set the pressure (Pa) and mole fractions.
virtual std::string phaseOfMatter() const
String indicating the mechanical phase of the matter in this Phase.
Definition: ThermoPhase.h:137
double o2Required(const double *y) const
Helper function for computing the amount of oxygen required for complete oxidation.
virtual doublereal cv_mole() const
Molar heat capacity at constant volume. Units: J/kmol/K.
Definition: ThermoPhase.h:259
virtual doublereal intEnergy_mole() const
Molar internal energy. Units: J/kmol.
Definition: ThermoPhase.h:239
virtual void getActivityConcentrations(doublereal *c) const
This method returns an array of generalized concentrations.
Definition: ThermoPhase.h:398
virtual void getPartialMolarIntEnergies(doublereal *ubar) const
Return an array of partial molar internal energies for the species in the mixture.
Definition: ThermoPhase.h:535
virtual int activityConvention() const
This method returns the convention used in specification of the activities, of which there are curren...
Definition: ThermoPhase.cpp:54
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
virtual doublereal standardConcentration(size_t k=0) const
Return the standard concentration for the kth species.
Definition: ThermoPhase.h:419
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.
virtual MultiSpeciesThermo & speciesThermo(int k=-1)
Return a changeable reference to the calculation manager for species reference-state thermodynamic pr...
virtual void setState_UP(double u, double p, double tol=1e-9)
Set the specific internal energy (J/kg) and pressure (Pa).
Definition: ThermoPhase.h:1007
virtual void setState_SP(double s, double p, double tol=1e-9)
Set the specific entropy (J/kg/K) and pressure (Pa).
virtual int standardStateConvention() const
This method returns the convention used in specification of the standard state, of which there are cu...
Definition: ThermoPhase.cpp:59
virtual doublereal maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
Definition: ThermoPhase.h:213
virtual void setState_SH(double s, double h, double tol=1e-9)
Set the specific entropy (J/kg/K) and the specific enthalpy (J/kg)
Definition: ThermoPhase.h:1055
void getElectrochemPotentials(doublereal *mu) const
Get the species electrochemical potentials.
Definition: ThermoPhase.cpp:91
doublereal cv_mass() const
Specific heat at constant volume. Units: J/kg/K.
Definition: ThermoPhase.h:767
virtual void setState_RP(doublereal rho, doublereal p)
Set the density (kg/m**3) and pressure (Pa) at constant composition.
Definition: ThermoPhase.h:1072
void setMixtureFraction(double mixFrac, const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar)
Set the mixture composition according to the mixture fraction = kg fuel / (kg oxidizer + kg fuel)
virtual void resetHf298(const size_t k=npos)
Restore the original heat of formation of one or more species.
Definition: ThermoPhase.cpp:43
virtual void setState_TH(double t, double h, double tol=1e-9)
Set the temperature (K) and the specific enthalpy (J/kg)
Definition: ThermoPhase.h:1039
virtual Units standardConcentrationUnits() const
Returns the units of the "standard concentration" for this phase.
Definition: ThermoPhase.cpp:64
virtual void setState_Psat(doublereal p, doublereal x)
Set the state to a saturated system at a particular pressure.
Definition: ThermoPhase.h:1549
std::vector< const XML_Node * > m_speciesData
Vector of pointers to the species databases.
Definition: ThermoPhase.h:1885
doublereal intEnergy_mass() const
Specific internal energy. Units: J/kg.
Definition: ThermoPhase.h:747
virtual void setState_RPX(doublereal rho, doublereal p, const doublereal *x)
Set the density (kg/m**3), pressure (Pa) and mole fractions.
virtual doublereal enthalpy_mole() const
Molar enthalpy. Units: J/kmol.
Definition: ThermoPhase.h:234
MultiSpeciesThermo m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
Definition: ThermoPhase.h:1870
virtual void setParameters(int n, doublereal *const c)
Set the equation of state parameters.
Definition: ThermoPhase.h:1691
doublereal enthalpy_mass() const
Specific enthalpy. Units: J/kg.
Definition: ThermoPhase.h:742
double mixtureFraction(const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar, const std::string &element="Bilger") const
Compute the mixture fraction = kg fuel / (kg oxidizer + kg fuel) for the current mixture given fuel a...
AnyMap m_input
Data supplied via setParameters.
Definition: ThermoPhase.h:1874
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:160
virtual void reportCSV(std::ofstream &csvFile) const
returns a summary of the state of the phase to a comma separated file.
void setEquivalenceRatio(double phi, const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar)
Set the mixture composition according to the equivalence ratio.
void setState_TPQ(double T, double P, double Q)
Set the temperature, pressure, and vapor fraction (quality).
virtual void invalidateCache()
Invalidate any cached values which are normally updated only when a change in state is detected.
void setState_conditional_TP(doublereal t, doublereal p, bool set_p)
Helper function used by setState_HPorUV and setState_SPorSV.
virtual void setState_VH(double v, double h, double tol=1e-9)
Set the specific volume (m^3/kg) and the specific enthalpy (J/kg)
Definition: ThermoPhase.h:1023
doublereal electricPotential() const
Returns the electric potential of this phase (V).
Definition: ThermoPhase.h:320
virtual void setState_SV(double s, double v, double tol=1e-9)
Set the specific entropy (J/kg/K) and specific volume (m^3/kg).
const AnyMap & input() const
Access input data associated with the phase description.
A representation of the units associated with a dimensional quantity.
Definition: Units.h:30
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:104
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:528
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:546
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
void equilibrate(const std::string &XY, const std::string &solver="auto", double rtol=1e-9, int max_steps=50000, int max_iter=100, int estimate_equil=0, int log_level=0)
Equilibrate a ThermoPhase object.
XML_Node * get_XML_File(const std::string &file, int debug)
Return a pointer to the XML tree for a Cantera input file.
Definition: global.cpp:110
void debuglog(const std::string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
Definition: global.h:140
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
Definition: global.h:300
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:188
const double Faraday
Faraday constant [C/kmol].
Definition: ct_defs.h:123
const double OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:78
const double SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:149
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:180
std::map< std::string, double > compositionMap
Map connecting a string name with a double.
Definition: ct_defs.h:172
void importPhase(XML_Node &phase, ThermoPhase *th)
Import a phase information into an empty ThermoPhase object.
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:264
doublereal dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition: utilities.h:112
doublereal getFloat(const XML_Node &parent, const std::string &name, const std::string &type)
Get a floating-point value from a child element.
Definition: ctml.cpp:164
XML_Node * findXMLPhase(XML_Node *root, const std::string &phaseId)
Search an XML_Node tree for a named phase XML_Node.
Definition: xml.cpp:1038
std::string getChildValue(const 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:131
const int cAC_CONVENTION_MOLAR
Standard state uses the molar convention.
Definition: ThermoPhase.h:26
void setupPhase(ThermoPhase &thermo, AnyMap &phaseNode, const AnyMap &rootNode)
Initialize a ThermoPhase object.
const int cSS_CONVENTION_TEMPERATURE
Standard state uses the molar convention.
Definition: ThermoPhase.h:36
ThermoBasis
Differentiate between mole fractions and mass fractions for input mixture composition.
Definition: ThermoPhase.h:45
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.
Definition: stringUtils.cpp:60
Contains declarations for string manipulation functions within Cantera.