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