Cantera  2.3.0
SpeciesThermoFactory.cpp
Go to the documentation of this file.
1 /**
2  * @file SpeciesThermoFactory.cpp
3  * Definitions for factory functions to build instances of classes that
4  * manage the standard-state thermodynamic properties of a set of species
5  * (see \ref spthermo);
6  */
7 
8 // This file is part of Cantera. See License.txt in the top-level directory or
9 // at http://www.cantera.org/license.txt for license and copyright information.
10 
13 #include "cantera/thermo/Mu0Poly.h"
21 #include "cantera/thermo/VPSSMgr.h"
23 #include "cantera/base/ctml.h"
25 
26 using namespace std;
27 
28 namespace Cantera
29 {
30 
32  double thigh, double pref, const double* coeffs)
33 {
34  switch (type) {
35  case NASA1:
36  return new NasaPoly1(tlow, thigh, pref, coeffs);
37  case SHOMATE1:
38  return new ShomatePoly(tlow, thigh, pref, coeffs);
39  case CONSTANT_CP:
40  case SIMPLE:
41  return new ConstCpPoly(tlow, thigh, pref, coeffs);
42  case MU0_INTERP:
43  return new Mu0Poly(tlow, thigh, pref, coeffs);
44  case SHOMATE2:
45  return new ShomatePoly2(tlow, thigh, pref, coeffs);
46  case NASA2:
47  return new NasaPoly2(tlow, thigh, pref, coeffs);
48  case ADSORBATE:
49  return new Adsorbate(tlow, thigh, pref, coeffs);
50  default:
51  throw CanteraError("newSpeciesThermoInterpType",
52  "Unknown species thermo type: {}.", type);
53  }
54 }
55 
57  double tlow, double thigh, double pref, const double* coeffs)
58 {
59  int itype = -1;
60  std::string type = ba::to_lower_copy(stype);
61  if (type == "nasa2" || type == "nasa") {
62  itype = NASA2; // two-region 7-coefficient NASA polynomials
63  } else if (type == "const_cp" || type == "simple") {
64  itype = CONSTANT_CP;
65  } else if (type == "shomate" || type == "shomate1") {
66  itype = SHOMATE1; // single-region Shomate polynomial
67  } else if (type == "shomate2") {
68  itype = SHOMATE2; // two-region Shomate polynomials
69  } else if (type == "nasa1") {
70  itype = NASA1; // single-region, 7-coefficient NASA polynomial
71  } else if (type == "nasa9") {
72  itype = NASA9; // single-region, 9-coefficient NASA polynomial
73  } else if (type == "nasa9multi") {
74  itype = NASA9MULTITEMP; // multi-region, 9-coefficient NASA polynomials
75  } else if (type == "mu0") {
76  itype = MU0_INTERP;
77  } else if (type == "adsorbate") {
78  itype = ADSORBATE;
79  } else {
80  throw CanteraError("newSpeciesThermoInterpType",
81  "Unknown species thermo type: '" + stype + "'.");
82  }
83  return newSpeciesThermoInterpType(itype, tlow, thigh, pref, coeffs);
84 }
85 
86 //! Create a NASA polynomial thermodynamic property parameterization for a
87 //! species from a set ! of XML nodes
88 /*!
89  * This is called if a 'NASA' node is found in the XML input.
90  *
91  * @param nodes vector of 1 or 2 'NASA' XML_Nodes, each defining the
92  * coefficients for a temperature range
93  */
94 static SpeciesThermoInterpType* newNasaThermoFromXML(vector<XML_Node*> nodes)
95 {
96  const XML_Node& f0 = *nodes[0];
97  bool dualRange = (nodes.size() > 1);
98  double tmin0 = fpValue(f0["Tmin"]);
99  double tmax0 = fpValue(f0["Tmax"]);
100 
101  doublereal p0 = OneAtm;
102  if (f0.hasAttrib("P0")) {
103  p0 = fpValue(f0["P0"]);
104  }
105  if (f0.hasAttrib("Pref")) {
106  p0 = fpValue(f0["Pref"]);
107  }
108  p0 = OneAtm;
109 
110  double tmin1 = tmax0;
111  double tmax1 = tmin1 + 0.0001;
112  if (dualRange) {
113  tmin1 = fpValue(nodes[1]->attrib("Tmin"));
114  tmax1 = fpValue(nodes[1]->attrib("Tmax"));
115  }
116 
117  vector_fp c0, c1;
118  doublereal tmin, tmid, tmax;
119  if (fabs(tmax0 - tmin1) < 0.01) {
120  // f0 has the lower T data, and f1 the higher T data
121  tmin = tmin0;
122  tmid = tmax0;
123  tmax = tmax1;
124  getFloatArray(f0.child("floatArray"), c0, false);
125  if (dualRange) {
126  getFloatArray(nodes[1]->child("floatArray"), c1, false);
127  } else {
128  // if there is no higher range data, then copy c0 to c1.
129  c1 = c0;
130  }
131  } else if (fabs(tmax1 - tmin0) < 0.01) {
132  // f1 has the lower T data, and f0 the higher T data
133  tmin = tmin1;
134  tmid = tmax1;
135  tmax = tmax0;
136  getFloatArray(nodes[1]->child("floatArray"), c0, false);
137  getFloatArray(f0.child("floatArray"), c1, false);
138  } else {
139  throw CanteraError("installNasaThermo",
140  "non-continuous temperature ranges.");
141  }
142 
143  vector_fp c(15);
144  c[0] = tmid;
145  copy(c1.begin(), c1.begin()+7, c.begin() + 1); // high-T coefficients
146  copy(c0.begin(), c0.begin()+7, c.begin() + 8); // low-T coefficients
147  return newSpeciesThermoInterpType(NASA, tmin, tmax, p0, &c[0]);
148 }
149 
150 //! Create a Shomate polynomial from an XML node giving the 'EQ3' coefficients
151 /*!
152  * This is called if a 'MinEQ3' node is found in the XML input.
153  * @param MinEQ3node The XML_Node containing the MinEQ3 parameterization
154  */
156 {
157  doublereal tmin0 = strSItoDbl(MinEQ3node["Tmin"]);
158  doublereal tmax0 = strSItoDbl(MinEQ3node["Tmax"]);
159  doublereal p0 = strSItoDbl(MinEQ3node["Pref"]);
160 
161  doublereal deltaG_formation_pr_tr =
162  getFloat(MinEQ3node, "DG0_f_Pr_Tr", "actEnergy") / actEnergyToSI("cal/gmol");
163  doublereal deltaH_formation_pr_tr =
164  getFloat(MinEQ3node, "DH0_f_Pr_Tr", "actEnergy") / actEnergyToSI("cal/gmol");
165  doublereal Entrop_pr_tr = getFloat(MinEQ3node, "S0_Pr_Tr", "toSI") / toSI("cal/gmol/K");
166  doublereal a = getFloat(MinEQ3node, "a", "toSI") / toSI("cal/gmol/K");
167  doublereal b = getFloat(MinEQ3node, "b", "toSI") / toSI("cal/gmol/K2");
168  doublereal c = getFloat(MinEQ3node, "c", "toSI") / toSI("cal-K/gmol");
169  doublereal dg = deltaG_formation_pr_tr * toSI("cal/gmol");
170  doublereal DHjmol = deltaH_formation_pr_tr * toSI("cal/gmol");
171  doublereal fac = DHjmol - dg - 298.15 * Entrop_pr_tr * toSI("cal/gmol");
172  doublereal Mu0_tr_pr = fac + dg;
173  doublereal e = Entrop_pr_tr * toSI("cal/gmol");
174  doublereal Hcalc = Mu0_tr_pr + 298.15 * e;
175 
176  // Now calculate the shomate polynomials
177  //
178  // Cp first
179  //
180  // Shomate: (Joules / gmol / K)
181  // Cp = As + Bs * t + Cs * t*t + Ds * t*t*t + Es / (t*t)
182  // where
183  // t = temperature(Kelvin) / 1000
184  double As = a * toSI("cal");
185  double Bs = b * toSI("cal") * 1000.;
186  double Cs = 0.0;
187  double Ds = 0.0;
188  double Es = c * toSI("cal") / (1.0E6);
189 
190  double t = 298.15 / 1000.;
191  double H298smFs = As * t + Bs * t * t / 2.0 - Es / t;
192  double HcalcS = Hcalc / 1.0E6;
193  double Fs = HcalcS - H298smFs;
194  double S298smGs = As * log(t) + Bs * t - Es/(2.0*t*t);
195  double ScalcS = e / 1.0E3;
196  double Gs = ScalcS - S298smGs;
197 
198  double c0[7] = {As, Bs, Cs, Ds, Es, Fs, Gs};
199  return newSpeciesThermoInterpType(SHOMATE1, tmin0, tmax0, p0, c0);
200 }
201 
202 //! Create a Shomate polynomial thermodynamic property parameterization for a
203 //! species
204 /*!
205  * This is called if a 'Shomate' node is found in the XML input.
206  *
207  * @param nodes vector of 1 or 2 'Shomate' XML_Nodes, each defining the
208  * coefficients for a temperature range
209  */
211  vector<XML_Node*>& nodes)
212 {
213  bool dualRange = false;
214  if (nodes.size() == 2) {
215  dualRange = true;
216  }
217  double tmin0 = fpValue(nodes[0]->attrib("Tmin"));
218  double tmax0 = fpValue(nodes[0]->attrib("Tmax"));
219 
220  doublereal p0 = OneAtm;
221  if (nodes[0]->hasAttrib("P0")) {
222  p0 = fpValue(nodes[0]->attrib("P0"));
223  }
224  if (nodes[0]->hasAttrib("Pref")) {
225  p0 = fpValue(nodes[0]->attrib("Pref"));
226  }
227  p0 = OneAtm;
228 
229  double tmin1 = tmax0;
230  double tmax1 = tmin1 + 0.0001;
231  if (dualRange) {
232  tmin1 = fpValue(nodes[1]->attrib("Tmin"));
233  tmax1 = fpValue(nodes[1]->attrib("Tmax"));
234  }
235 
236  vector_fp c0, c1;
237  doublereal tmin, tmid, tmax;
238  if (fabs(tmax0 - tmin1) < 0.01) {
239  tmin = tmin0;
240  tmid = tmax0;
241  tmax = tmax1;
242  getFloatArray(nodes[0]->child("floatArray"), c0, false);
243  if (dualRange) {
244  getFloatArray(nodes[1]->child("floatArray"), c1, false);
245  } else {
246  if(c0.size() != 7)
247  {
248  throw CanteraError("installShomateThermoFromXML",
249  "Shomate thermo requires 7 coefficients in float array.");
250  }
251  c1.resize(7,0.0);
252  copy(c0.begin(), c0.begin()+7, c1.begin());
253  }
254  } else if (fabs(tmax1 - tmin0) < 0.01) {
255  tmin = tmin1;
256  tmid = tmax1;
257  tmax = tmax0;
258  getFloatArray(nodes[1]->child("floatArray"), c0, false);
259  getFloatArray(nodes[0]->child("floatArray"), c1, false);
260  } else {
261  throw CanteraError("installShomateThermoFromXML",
262  "non-continuous temperature ranges.");
263  }
264  if(c0.size() != 7 || c1.size() != 7)
265  {
266  throw CanteraError("installShomateThermoFromXML",
267  "Shomate thermo requires 7 coefficients in float array.");
268  }
269  vector_fp c(15);
270  c[0] = tmid;
271  copy(c0.begin(), c0.begin()+7, c.begin() + 1);
272  copy(c1.begin(), c1.begin()+7, c.begin() + 8);
273  return newSpeciesThermoInterpType(SHOMATE, tmin, tmax, p0, &c[0]);
274 }
275 
276 //! Create a "simple" constant heat capacity thermodynamic property
277 //! parameterization for a ! species
278 /*!
279  * This is called if a 'const_cp' XML node is found
280  *
281  * @param f 'const_cp' XML node
282  */
284 {
285  double tmin = fpValue(f["Tmin"]);
286  double tmax = fpValue(f["Tmax"]);
287  if (tmax == 0.0) {
288  tmax = 1.0e30;
289  }
290 
291  vector_fp c(4);
292  c[0] = getFloat(f, "t0", "toSI");
293  c[1] = getFloat(f, "h0", "toSI");
294  c[2] = getFloat(f, "s0", "toSI");
295  c[3] = getFloat(f, "cp0", "toSI");
296  doublereal p0 = OneAtm;
297  return newSpeciesThermoInterpType(CONSTANT_CP, tmin, tmax, p0, &c[0]);
298 }
299 
300 //! Create a NASA9 polynomial thermodynamic property parameterization for a
301 //! species
302 /*!
303  * This is called if a 'NASA9' Node is found in the XML input.
304  *
305  * @param tp Vector of XML Nodes that make up the parameterization
306  */
308  const std::vector<XML_Node*>& tp)
309 {
310  int nRegions = 0;
311  vector_fp cPoly;
312  std::vector<Nasa9Poly1*> regionPtrs;
313  doublereal pref = OneAtm;
314  // Loop over all of the possible temperature regions
315  for (size_t i = 0; i < tp.size(); i++) {
316  const XML_Node& fptr = *tp[i];
317  if (fptr.name() == "NASA9" && fptr.hasChild("floatArray")) {
318  double tmin = fpValue(fptr["Tmin"]);
319  double tmax = fpValue(fptr["Tmax"]);
320  if (fptr.hasAttrib("P0")) {
321  pref = fpValue(fptr["P0"]);
322  }
323  if (fptr.hasAttrib("Pref")) {
324  pref = fpValue(fptr["Pref"]);
325  }
326 
327  getFloatArray(fptr.child("floatArray"), cPoly, false);
328  if (cPoly.size() != 9) {
329  throw CanteraError("installNasa9ThermoFromXML",
330  "Expected 9 coeff polynomial");
331  }
332  regionPtrs.push_back(new Nasa9Poly1(tmin, tmax, pref, &cPoly[0]));
333  nRegions++;
334  }
335  }
336  if (nRegions == 0) {
337  throw CanteraError("newNasa9ThermoFromXML", "zero regions found");
338  } else if (nRegions == 1) {
339  return regionPtrs[0];
340  } else {
341  return new Nasa9PolyMultiTempRegion(regionPtrs);
342  }
343 }
344 
345 //! Create an Adsorbate polynomial thermodynamic property parameterization for a
346 //! species
347 /*!
348  * This is called if a 'Adsorbate' node is found in the XML input.
349  *
350  * @param f XML Node that contains the parameterization
351  */
353 {
354  vector_fp freqs;
355  doublereal pref = OneAtm;
356  double tmin = fpValue(f["Tmin"]);
357  double tmax = fpValue(f["Tmax"]);
358  if (f.hasAttrib("P0")) {
359  pref = fpValue(f["P0"]);
360  }
361  if (f.hasAttrib("Pref")) {
362  pref = fpValue(f["Pref"]);
363  }
364  if (tmax == 0.0) {
365  tmax = 1.0e30;
366  }
367 
368  if (f.hasChild("floatArray")) {
369  getFloatArray(f.child("floatArray"), freqs, false);
370  }
371  for (size_t n = 0; n < freqs.size(); n++) {
372  freqs[n] *= 3.0e10;
373  }
374  vector_fp coeffs(freqs.size() + 2);
375  coeffs[0] = static_cast<double>(freqs.size());
376  coeffs[1] = getFloat(f, "binding_energy", "toSI");
377  copy(freqs.begin(), freqs.end(), coeffs.begin() + 2);
378  return new Adsorbate(tmin, tmax, pref, &coeffs[0]);
379 }
380 
382 {
383  // Get the children of the thermo XML node. In the next bit of code we take
384  // out the comments that may have been children of the thermo XML node by
385  // doing a selective copy. These shouldn't interfere with the algorithm at
386  // any point.
387  const std::vector<XML_Node*>& tpWC = thermo.children();
388  std::vector<XML_Node*> tp;
389  for (size_t i = 0; i < tpWC.size(); i++) {
390  if (!tpWC[i]->isComment()) {
391  tp.push_back(tpWC[i]);
392  }
393  }
394 
395  std::string thermoType = ba::to_lower_copy(tp[0]->name());
396 
397  for (size_t i = 1; i < tp.size(); i++) {
398  if (!ba::iequals(tp[i]->name(), thermoType)) {
399  throw CanteraError("newSpeciesThermoInterpType",
400  "Encountered unsupported mixed species thermo parameterizations");
401  }
402  }
403  if ((tp.size() > 2 && thermoType != "nasa9") ||
404  (tp.size() > 1 && (thermoType == "const_cp" ||
405  thermoType == "mu0" ||
406  thermoType == "adsorbate"))) {
407  throw CanteraError("newSpeciesThermoInterpType",
408  "Too many regions in thermo parameterization.");
409  }
410 
411  std::string model = ba::to_lower_copy(thermo["model"]);
412  if (model == "mineraleq3") {
413  if (thermoType != "mineq3") {
414  throw CanteraError("newSpeciesThermoInterpType",
415  "confused: expected MinEQ3");
416  }
417  return newShomateForMineralEQ3(*tp[0]);
418  } else if (thermoType == "shomate") {
419  return newShomateThermoFromXML(tp);
420  } else if (thermoType == "const_cp") {
421  return newConstCpThermoFromXML(*tp[0]);
422  } else if (thermoType == "nasa") {
423  return newNasaThermoFromXML(tp);
424  } else if (thermoType == "mu0") {
425  return newMu0ThermoFromXML(*tp[0]);
426  } else if (thermoType == "nasa9") {
427  return newNasa9ThermoFromXML(tp);
428  } else if (thermoType == "adsorbate") {
429  return newAdsorbateThermoFromXML(*tp[0]);
430  } else if (model == "hkft" || model == "ionfromneutral") {
431  // Some PDSS species use the 'thermo' node, but don't specify a
432  // SpeciesThermoInterpType parameterization. This function needs to just
433  // ignore this data.
434  return 0;
435  } else {
436  throw CanteraError("newSpeciesThermoInterpType",
437  "Unknown species thermo model '" + thermoType + "'.");
438  }
439 }
440 
441 }
Header for a general species thermodynamic property manager for a phase (see MultiSpeciesThermo).
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
size_t getFloatArray(const XML_Node &node, vector_fp &v, const bool convert, const std::string &unitsString, const std::string &nodeName)
This function reads the current node or a child node of the current node with the default name...
Definition: ctml.cpp:299
Header for a single-species standard state object derived from SpeciesThermoInterpType based on a pie...
Abstract Base class for the thermodynamic manager for an individual species&#39; reference state...
#define NASA
Two regions of 7 coefficient NASA Polynomials This is implemented in the class NasaPoly2 in NasaPoly2...
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
std::string name() const
Returns the name of the XML node.
Definition: xml.h:370
#define SHOMATE
Two regions of Shomate Polynomials.
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the N...
#define CONSTANT_CP
Constant Cp.
The NASA polynomial parameterization for two temperature ranges.
Definition: NasaPoly2.h:48
const doublereal OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:69
doublereal actEnergyToSI(const std::string &unit)
Return the conversion factor to convert activation energy unit std::string &#39;unit&#39; to Kelvin...
Definition: global.cpp:171
Declaration file for a virtual base class that manages the calculation of standard state properties f...
static SpeciesThermoInterpType * newAdsorbateThermoFromXML(const XML_Node &f)
Create an Adsorbate polynomial thermodynamic property parameterization for a species.
doublereal toSI(const std::string &unit)
Return the conversion factor to convert unit std::string &#39;unit&#39; to SI units.
Definition: global.cpp:160
static SpeciesThermoInterpType * newNasa9ThermoFromXML(const std::vector< XML_Node *> &tp)
Create a NASA9 polynomial thermodynamic property parameterization for a species.
static SpeciesThermoInterpType * newNasaThermoFromXML(vector< XML_Node *> nodes)
Create a NASA polynomial thermodynamic property parameterization for a species from a set ! of XML no...
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the N...
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:97
#define NASA2
Two regions of 7 coefficient NASA Polynomials This is implemented in the class NasaPoly2 in NasaPoly2...
STL namespace.
The Mu0Poly class implements an interpolation of the Gibbs free energy based on a piecewise constant ...
Definition: Mu0Poly.h:73
SpeciesThermoInterpType * newShomateForMineralEQ3(const XML_Node &MinEQ3node)
Create a Shomate polynomial from an XML node giving the &#39;EQ3&#39; coefficients.
SpeciesThermoInterpType * newSpeciesThermoInterpType(const XML_Node &thermo)
Create a new SpeciesThermoInterpType object from XML_Node.
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
Definition: xml.cpp:541
A constant-heat capacity species thermodynamic property manager class.
Definition: ConstCpPoly.h:43
#define MU0_INTERP
piecewise interpolation of mu0.
#define NASA1
7 coefficient NASA Polynomials This is implemented in the class NasaPoly1 in NasaPoly1.h
Contains const definitions for types of species reference-state thermodynamics managers (see Species ...
#define NASA9MULTITEMP
9 coefficient NASA Polynomials in multiple temperature regions This is implemented in the class Nasa9...
#define NASA9
9 coefficient NASA Polynomials This is implemented in the class Nasa9Poly1 in Nasa9Poly1.h
const std::vector< XML_Node * > & children() const
Return an unchangeable reference to the vector of children of the current node.
Definition: xml.cpp:551
The Shomate polynomial parameterization for one temperature range for one species.
Definition: ShomatePoly.h:57
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the S...
The Shomate polynomial parameterization for two temperature ranges for one species.
Definition: ShomatePoly.h:232
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:65
#define SIMPLE
Constant Cp thermo.
static SpeciesThermoInterpType * newConstCpThermoFromXML(XML_Node &f)
Create a "simple" constant heat capacity thermodynamic property parameterization for a ! species...
#define SHOMATE2
Two regions of Shomate Polynomials.
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:536
XML_Node & child(const size_t n) const
Return a changeable reference to the n&#39;th child of the current node.
Definition: xml.cpp:546
An adsorbed surface species.
Header for factory functions to build instances of classes that manage the standard-state thermodynam...
Header file for a derived class of ThermoPhase that handles variable pressure standard state methods ...
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:157
Headers for the SpeciesThermoInterpType object that employs a constant heat capacity assumption (see ...
Contains declarations for string manipulation functions within Cantera.
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:178
The NASA 9 polynomial parameterization for one temperature range.
Definition: Nasa9Poly1.h:61
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the e...
static SpeciesThermoInterpType * newShomateThermoFromXML(vector< XML_Node *> &nodes)
Create a Shomate polynomial thermodynamic property parameterization for a species.
The NASA polynomial parameterization for one temperature range.
Definition: NasaPoly1.h:45
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the N...
Namespace for the Cantera kernel.
Definition: application.cpp:29
The NASA 9 polynomial parameterization for a single species encompassing multiple temperature regions...
doublereal strSItoDbl(const std::string &strSI)
Interpret one or two token string as a single double.
Mu0Poly * newMu0ThermoFromXML(const XML_Node &Mu0Node)
Install a Mu0 polynomial thermodynamic reference state.
Definition: Mu0Poly.cpp:94
#define SHOMATE1
one region of Shomate Polynomials used in NIST database This is implemented in the NIST database...
#define ADSORBATE
Surface Adsorbate Model for a species on a surface.