Cantera  2.1.2
SpeciesThermoFactory.cpp
Go to the documentation of this file.
1 /**
2  * @file SpeciesThermoFactory.cpp
3  * Definitions for factory to build instances of classes that manage the
4  * standard-state thermodynamic properties of a set of species
5  * (see \ref spthermo and class \link Cantera::SpeciesThermoFactory SpeciesThermoFactory\endlink);
6  */
7 // Copyright 2001 California Institute of Technology
8 
10 using namespace std;
11 
13 #include "NasaThermo.h"
14 #include "ShomateThermo.h"
17 #include "cantera/thermo/Mu0Poly.h"
21 
25 #include "cantera/thermo/VPSSMgr.h"
27 
28 #include "cantera/base/xml.h"
29 #include "cantera/base/ctml.h"
30 
31 using namespace ctml;
32 
33 namespace Cantera
34 {
35 
36 SpeciesThermoFactory* SpeciesThermoFactory::s_factory = 0;
37 mutex_t SpeciesThermoFactory::species_thermo_mutex;
38 
39 //! Examine the types of species thermo parameterizations,
40 //! and return a flag indicating the type of reference state thermo manager
41 //! that will be needed in order to evaluate them all.
42 /*!
43  *
44  * @param spDataNodeList This vector contains a list
45  * of species XML nodes that will be in the phase
46  * @param has_nasa Return int that indicates whether the phase has a NASA polynomial form for one of its species
47  * @param has_shomate Return int that indicates whether the phase has a SHOMATE polynomial form for one of its species
48  * @param has_simple Return int that indicates whether the phase has a SIMPLE polynomial form for one of its species
49  * @param has_other Return int that indicates whether the phase has a form for one of its species that is not one of the ones listed above.
50  *
51  * @todo Make sure that spDadta_node is species Data XML node by checking its name is speciesData
52  */
53 static void getSpeciesThermoTypes(std::vector<XML_Node*> & spDataNodeList,
54  int& has_nasa, int& has_shomate, int& has_simple,
55  int& has_other)
56 {
57  size_t ns = spDataNodeList.size();
58  for (size_t n = 0; n < ns; n++) {
59  XML_Node* spNode = spDataNodeList[n];
60  if (spNode->hasChild("standardState")) {
61  const XML_Node& ss = spNode->child("standardState");
62  string mname = ss["model"];
63  if (mname == "water" || mname == "waterIAPWS") {
64  has_other = 1;
65  continue;
66  }
67  }
68  if (spNode->hasChild("thermo")) {
69  const XML_Node& th = spNode->child("thermo");
70  if (th.hasChild("NASA")) {
71  has_nasa = 1;
72  } else if (th.hasChild("Shomate")) {
73  has_shomate = 1;
74  } else if (th.hasChild("MinEQ3")) {
75  has_shomate = 1;
76  } else if (th.hasChild("const_cp")) {
77  has_simple = 1;
78  } else if (th.hasChild("poly")) {
79  if (th.child("poly")["order"] == "1") {
80  has_simple = 1;
81  } else throw CanteraError("newSpeciesThermo",
82  "poly with order > 1 not yet supported");
83  } else if (th.hasChild("Mu0")) {
84  has_other = 1;
85  } else if (th.hasChild("NASA9")) {
86  has_other = 1;
87  } else if (th.hasChild("NASA9MULTITEMP")) {
88  has_other = 1;
89  } else if (th.hasChild("adsorbate")) {
90  has_other = 1;
91  } else {
92  has_other = 1;
93  //throw UnknownSpeciesThermoModel("getSpeciesThermoTypes:",
94  // spNode->attrib("name"), "missing");
95  }
96  } else {
97  throw CanteraError("getSpeciesThermoTypes:",
98  spNode->attrib("name") + " is missing the thermo XML node");
99  }
100  }
101 }
102 
103 //! Static method to return an instance of this class
104 /*!
105  * This class is implemented as a singleton -- one in which
106  * only one instance is needed. The recommended way to access
107  * the factory is to call this static method, which
108  * instantiates the class if it is the first call, but
109  * otherwise simply returns the pointer to the existing
110  * instance.
111  */
112 SpeciesThermoFactory* SpeciesThermoFactory::factory()
113 {
114  ScopedLock lock(species_thermo_mutex);
115  if (!s_factory) {
116  s_factory = new SpeciesThermoFactory;
117  }
118  return s_factory;
119 }
120 
121 void SpeciesThermoFactory::deleteFactory()
122 {
123  ScopedLock lock(species_thermo_mutex);
124  if (s_factory) {
125  delete s_factory;
126  s_factory = 0;
127  }
128 }
129 
130 SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(std::vector<XML_Node*> & spDataNodeList) const
131 {
132  int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
133  try {
134  getSpeciesThermoTypes(spDataNodeList, inasa, ishomate, isimple, iother);
135  } catch (UnknownSpeciesThermoModel) {
136  iother = 1;
137  popError();
138  }
139  if (iother) {
140  //writelog("returning new GeneralSpeciesThermo");
141  return new GeneralSpeciesThermo();
142  }
143  return newSpeciesThermo(NASA*inasa
144  + SHOMATE*ishomate + SIMPLE*isimple);
145 }
146 
147 SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(int type) const
148 {
149  switch (type) {
150  case NASA:
151  return new NasaThermo;
152  case SHOMATE:
153  return new ShomateThermo;
154  case SIMPLE:
155  return new SimpleThermo;
156  case NASA + SHOMATE:
158  case NASA + SIMPLE:
160  case SHOMATE + SIMPLE:
162  default:
163  throw UnknownSpeciesThermo("SpeciesThermoFactory::newSpeciesThermo",
164  type);
165  return 0;
166  }
167 }
168 
169 SpeciesThermo* SpeciesThermoFactory::newSpeciesThermoManager(std::string& stype) const
170 {
171  std::string ltype = lowercase(stype);
172  if (ltype == "nasa") {
173  return new NasaThermo;
174  } else if (ltype == "shomate") {
175  return new ShomateThermo;
176  } else if (ltype == "simple" || ltype == "constant_cp") {
177  return new SimpleThermo;
178  } else if (ltype == "nasa_shomate_duo") {
180  } else if (ltype == "nasa_simple_duo") {
182  } else if (ltype == "shomate_simple_duo") {
184  } else if (ltype == "general") {
185  return new GeneralSpeciesThermo();
186  } else if (ltype == "") {
187  return (SpeciesThermo*) 0;
188  } else {
189  throw UnknownSpeciesThermo("SpeciesThermoFactory::newSpeciesThermoManager",
190  stype);
191  }
192  return (SpeciesThermo*) 0;
193 }
194 
195 //! Install a NASA polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance.
196 /*!
197  * This is called by method installThermoForSpecies if a NASA block is found in the XML input.
198  *
199  * @param speciesName String name of the species
200  * @param sp SpeciesThermo object that will receive the NASA polynomial object
201  * @param k Species index within the phase
202  * @param f0ptr Ptr to the first XML_Node for the first NASA polynomial
203  * @param f1ptr Ptr to the first XML_Node for the first NASA polynomial
204  */
205 static void installNasaThermoFromXML(const std::string& speciesName,
206  SpeciesThermo& sp, size_t k,
207  const XML_Node* f0ptr, const XML_Node* f1ptr)
208 {
209  doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
210 
211  const XML_Node& f0 = *f0ptr;
212 
213  // default to a single temperature range
214  bool dualRange = false;
215 
216  // but if f1ptr is suppled, then it is a two-range
217  // parameterization
218  if (f1ptr) {
219  dualRange = true;
220  }
221 
222  tmin0 = fpValue(f0["Tmin"]);
223  tmax0 = fpValue(f0["Tmax"]);
224 
225  doublereal p0 = OneAtm;
226  if (f0.hasAttrib("P0")) {
227  p0 = fpValue(f0["P0"]);
228  }
229  if (f0.hasAttrib("Pref")) {
230  p0 = fpValue(f0["Pref"]);
231  }
232  p0 = OneAtm;
233 
234  tmin1 = tmax0;
235  tmax1 = tmin1 + 0.0001;
236  if (dualRange) {
237  tmin1 = fpValue((*f1ptr)["Tmin"]);
238  tmax1 = fpValue((*f1ptr)["Tmax"]);
239  }
240 
241  vector_fp c0, c1;
242  if (fabs(tmax0 - tmin1) < 0.01) {
243  // f0 has the lower T data, and f1 the higher T data
244  tmin = tmin0;
245  tmid = tmax0;
246  tmax = tmax1;
247  getFloatArray(f0.child("floatArray"), c0, false);
248  if (dualRange) {
249  getFloatArray(f1ptr->child("floatArray"), c1, false);
250  } else {
251  // if there is no higher range data, then copy c0 to c1.
252  c1.resize(7,0.0);
253  copy(c0.begin(), c0.end(), c1.begin());
254  }
255  } else if (fabs(tmax1 - tmin0) < 0.01) {
256  // f1 has the lower T data, and f0 the higher T data
257  tmin = tmin1;
258  tmid = tmax1;
259  tmax = tmax0;
260  getFloatArray(f1ptr->child("floatArray"), c0, false);
261  getFloatArray(f0.child("floatArray"), c1, false);
262  } else {
263  throw CanteraError("installNasaThermo",
264  "non-continuous temperature ranges.");
265  }
266 
267  // The NasaThermo species property manager expects the
268  // coefficients in a different order, so rearrange them.
269  vector_fp c(15);
270  c[0] = tmid;
271 
272  c[1] = c0[5];
273  c[2] = c0[6];
274  copy(c0.begin(), c0.begin()+5, c.begin() + 3);
275  c[8] = c1[5];
276  c[9] = c1[6];
277  copy(c1.begin(), c1.begin()+5, c.begin() + 10);
278  sp.install(speciesName, k, NASA, &c[0], tmin, tmax, p0);
279 }
280 
281 //! Look up the elemental reference state entropies
282 /*!
283  * @param elemName String name of the element
284  * @param th_ptr Pointer to the thermophase.
285  */
286 static doublereal LookupGe(const std::string& elemName, ThermoPhase* th_ptr)
287 {
288  size_t iE = th_ptr->elementIndex(elemName);
289  if (iE == npos) {
290  throw CanteraError("PDSS_HKFT::LookupGe", "element " + elemName + " not found");
291  }
292  doublereal geValue = th_ptr->entropyElement298(iE);
293  if (geValue == ENTROPY298_UNKNOWN) {
294  throw CanteraError("PDSS_HKFT::LookupGe",
295  "element " + elemName + " does not have a supplied entropy298");
296  }
297  geValue *= (-298.15);
298  return geValue;
299 }
300 
301 //! Convert delta G formulation
302 /*!
303  * Calculates the sum of the elemental reference state entropies
304  *
305  * @param k species index
306  * @param th_ptr Pointer to the ThermoPhase
307  */
308 static doublereal convertDGFormation(size_t k, ThermoPhase* th_ptr)
309 {
310  /*
311  * Ok let's get the element compositions and conversion factors.
312  */
313  size_t ne = th_ptr->nElements();
314  doublereal na;
315  doublereal ge;
316  string ename;
317 
318  doublereal totalSum = 0.0;
319  for (size_t m = 0; m < ne; m++) {
320  na = th_ptr->nAtoms(k, m);
321  if (na > 0.0) {
322  ename = th_ptr->elementName(m);
323  ge = LookupGe(ename, th_ptr);
324  totalSum += na * ge;
325  }
326  }
327  return totalSum;
328 }
329 
330 
331 //! Install a NASA96 polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance.
332 /*!
333  * This is called by method installThermoForSpecies if a MinEQ3node block is found in the XML input.
334  *
335  * @param speciesName String name of the species
336  * @param th_ptr Pointer to the %ThermoPhase object
337  * @param sp SpeciesThermo object that will receive the NASA polynomial object
338  * @param k Species index within the phase
339  * @param MinEQ3node Ptr to the first XML_Node for the first MinEQ3 parameterization
340  */
341 static void installMinEQ3asShomateThermoFromXML(const std::string& speciesName,
342  ThermoPhase* th_ptr,
343  SpeciesThermo& sp, size_t k,
344  const XML_Node* MinEQ3node)
345 {
346 
347  vector_fp coef(15), c0(7, 0.0);
348  std::string astring = (*MinEQ3node)["Tmin"];
349  doublereal tmin0 = strSItoDbl(astring);
350  astring = (*MinEQ3node)["Tmax"];
351  doublereal tmax0 = strSItoDbl(astring);
352  astring = (*MinEQ3node)["Pref"];
353  doublereal p0 = strSItoDbl(astring);
354 
355  doublereal deltaG_formation_pr_tr =
356  getFloatDefaultUnits(*MinEQ3node, "DG0_f_Pr_Tr", "cal/gmol", "actEnergy");
357  doublereal deltaH_formation_pr_tr =
358  getFloatDefaultUnits(*MinEQ3node, "DH0_f_Pr_Tr", "cal/gmol", "actEnergy");
359  doublereal Entrop_pr_tr = getFloatDefaultUnits(*MinEQ3node, "S0_Pr_Tr", "cal/gmol/K");
360  doublereal a = getFloatDefaultUnits(*MinEQ3node, "a", "cal/gmol/K");
361  doublereal b = getFloatDefaultUnits(*MinEQ3node, "b", "cal/gmol/K2");
362  doublereal c = getFloatDefaultUnits(*MinEQ3node, "c", "cal-K/gmol");
363  doublereal dg = deltaG_formation_pr_tr * 4.184 * 1.0E3;
364  doublereal fac = convertDGFormation(k, th_ptr);
365  doublereal Mu0_tr_pr = fac + dg;
366  doublereal e = Entrop_pr_tr * 1.0E3 * 4.184;
367  doublereal Hcalc = Mu0_tr_pr + 298.15 * e;
368  doublereal DHjmol = deltaH_formation_pr_tr * 1.0E3 * 4.184;
369 
370  // If the discrepancy is greater than 100 cal gmol-1, print
371  // an error and exit.
372  if (fabs(Hcalc -DHjmol) > 10.* 1.0E6 * 4.184) {
373  throw CanteraError("installMinEQ3asShomateThermoFromXML()",
374  "DHjmol is not consistent with G and S" +
375  fp2str(Hcalc) + " vs " + fp2str(DHjmol));
376  }
377 
378  /*
379  * Now calculate the shomate polynomials
380  *
381  * Cp first
382  *
383  * Shomate: (Joules / gmol / K)
384  * Cp = As + Bs * t + Cs * t*t + Ds * t*t*t + Es / (t*t)
385  * where
386  * t = temperature(Kelvin) / 1000
387  */
388  double As = a * 4.184;
389  double Bs = b * 4.184 * 1000.;
390  double Cs = 0.0;
391  double Ds = 0.0;
392  double Es = c * 4.184 / (1.0E6);
393 
394  double t = 298.15 / 1000.;
395  double H298smFs = As * t + Bs * t * t / 2.0 - Es / t;
396 
397  double HcalcS = Hcalc / 1.0E6;
398  double Fs = HcalcS - H298smFs;
399 
400  double S298smGs = As * log(t) + Bs * t - Es/(2.0*t*t);
401  double ScalcS = e / 1.0E3;
402  double Gs = ScalcS - S298smGs;
403 
404  c0[0] = As;
405  c0[1] = Bs;
406  c0[2] = Cs;
407  c0[3] = Ds;
408  c0[4] = Es;
409  c0[5] = Fs;
410  c0[6] = Gs;
411 
412  coef[0] = tmax0 - 0.001;
413  copy(c0.begin(), c0.begin()+7, coef.begin() + 1);
414  copy(c0.begin(), c0.begin()+7, coef.begin() + 8);
415  sp.install(speciesName, k, SHOMATE, &coef[0], tmin0, tmax0, p0);
416 }
417 
418 //! Install a Shomate polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance.
419 /*!
420  * This is called by method installThermoForSpecies if a Shomate block is found in the XML input.
421  *
422  * @param speciesName String name of the species
423  * @param sp SpeciesThermo object that will receive the NASA polynomial object
424  * @param k Species index within the phase
425  * @param f0ptr Ptr to the first XML_Node for the first NASA polynomial
426  * @param f1ptr Ptr to the first XML_Node for the first NASA polynomial
427  */
428 static void installShomateThermoFromXML(const std::string& speciesName, SpeciesThermo& sp, size_t k,
429  const XML_Node* f0ptr, const XML_Node* f1ptr)
430 {
431  doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
432  const XML_Node& f0 = *f0ptr;
433  bool dualRange = false;
434  if (f1ptr) {
435  dualRange = true;
436  }
437  tmin0 = fpValue(f0["Tmin"]);
438  tmax0 = fpValue(f0["Tmax"]);
439 
440  doublereal p0 = OneAtm;
441  if (f0.hasAttrib("P0")) {
442  p0 = fpValue(f0["P0"]);
443  }
444  if (f0.hasAttrib("Pref")) {
445  p0 = fpValue(f0["Pref"]);
446  }
447  p0 = OneAtm;
448 
449  tmin1 = tmax0;
450  tmax1 = tmin1 + 0.0001;
451  if (dualRange) {
452  tmin1 = fpValue((*f1ptr)["Tmin"]);
453  tmax1 = fpValue((*f1ptr)["Tmax"]);
454  }
455 
456  vector_fp c0, c1;
457  if (fabs(tmax0 - tmin1) < 0.01) {
458  tmin = tmin0;
459  tmid = tmax0;
460  tmax = tmax1;
461  getFloatArray(f0.child("floatArray"), c0, false);
462  if (dualRange) {
463  getFloatArray(f1ptr->child("floatArray"), c1, false);
464  } else {
465  if(c0.size() != 7)
466  {
467  throw CanteraError("installShomateThermoFromXML",
468  "Shomate thermo requires 7 coefficients in float array.");
469  }
470  c1.resize(7,0.0);
471  copy(c0.begin(), c0.begin()+7, c1.begin());
472  }
473  } else if (fabs(tmax1 - tmin0) < 0.01) {
474  tmin = tmin1;
475  tmid = tmax1;
476  tmax = tmax0;
477  getFloatArray(f1ptr->child("floatArray"), c0, false);
478  getFloatArray(f0.child("floatArray"), c1, false);
479  } else {
480  throw CanteraError("installShomateThermoFromXML",
481  "non-continuous temperature ranges.");
482  }
483  if(c0.size() != 7 || c1.size() != 7)
484  {
485  throw CanteraError("installShomateThermoFromXML",
486  "Shomate thermo requires 7 coefficients in float array.");
487  }
488  vector_fp c(15);
489  c[0] = tmid;
490  copy(c0.begin(), c0.begin()+7, c.begin() + 1);
491  copy(c1.begin(), c1.begin()+7, c.begin() + 8);
492  sp.install(speciesName, k, SHOMATE, &c[0], tmin, tmax, p0);
493 }
494 
495 //! Install a Simple thermodynamic property parameterization for species k into a SpeciesThermo instance.
496 /*!
497  * This is called by method installThermoForSpecies if a SimpleThermo block is found
498  *
499  * @param speciesName String name of the species
500  * @param sp SpeciesThermo object that will receive the NASA polynomial object
501  * @param k Species index within the phase
502  * @param f XML_Node for the SimpleThermo block
503  */
504 static void installSimpleThermoFromXML(const std::string& speciesName,
505  SpeciesThermo& sp, size_t k,
506  const XML_Node& f)
507 {
508  doublereal tmin, tmax;
509  tmin = fpValue(f["Tmin"]);
510  tmax = fpValue(f["Tmax"]);
511  if (tmax == 0.0) {
512  tmax = 1.0e30;
513  }
514 
515  vector_fp c(4);
516  c[0] = getFloat(f, "t0", "toSI");
517  c[1] = getFloat(f, "h0", "toSI");
518  c[2] = getFloat(f, "s0", "toSI");
519  c[3] = getFloat(f, "cp0", "toSI");
520  doublereal p0 = OneAtm;
521  sp.install(speciesName, k, SIMPLE, &c[0], tmin, tmax, p0);
522 }
523 
524 
525 //! Install a NASA9 polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance.
526 /*!
527  * This is called by method installThermoForSpecies if a NASA9 block is found in the XML input.
528  *
529  * @param speciesName String name of the species
530  * @param sp SpeciesThermo object that will receive the NASA polynomial object
531  * @param k Species index within the phase
532  * @param tp Vector of XML Nodes that make up the parameterization
533  */
534 static void installNasa9ThermoFromXML(const std::string& speciesName,
535  SpeciesThermo& sp, size_t k,
536  const std::vector<XML_Node*>& tp)
537 {
538  const XML_Node* fptr = tp[0];
539  int nRegions = 0;
540  vector_fp cPoly;
541  Nasa9Poly1* np_ptr = 0;
542  std::vector<Nasa9Poly1*> regionPtrs;
543  doublereal tmin, tmax, pref = OneAtm;
544  // Loop over all of the possible temperature regions
545  for (size_t i = 0; i < tp.size(); i++) {
546  fptr = tp[i];
547  if (fptr) {
548  if (fptr->name() == "NASA9") {
549  if (fptr->hasChild("floatArray")) {
550 
551  tmin = fpValue((*fptr)["Tmin"]);
552  tmax = fpValue((*fptr)["Tmax"]);
553  if ((*fptr).hasAttrib("P0")) {
554  pref = fpValue((*fptr)["P0"]);
555  }
556  if ((*fptr).hasAttrib("Pref")) {
557  pref = fpValue((*fptr)["Pref"]);
558  }
559 
560  getFloatArray(fptr->child("floatArray"), cPoly, false);
561  if (cPoly.size() != 9) {
562  throw CanteraError("installNasa9ThermoFromXML",
563  "Expected 9 coeff polynomial");
564  }
565  np_ptr = new Nasa9Poly1(k, tmin, tmax, pref,
566  DATA_PTR(cPoly));
567  regionPtrs.push_back(np_ptr);
568  nRegions++;
569  }
570  }
571  }
572  }
573  if (nRegions == 0) {
574  throw UnknownSpeciesThermoModel("installThermoForSpecies",
575  speciesName, " ");
576  } else if (nRegions == 1) {
577  sp.install_STIT(np_ptr);
578  } else {
579  Nasa9PolyMultiTempRegion* npMulti_ptr = new Nasa9PolyMultiTempRegion(regionPtrs);
580  sp.install_STIT(npMulti_ptr);
581  }
582 }
583 
584 /**
585  * Install a stat mech based property solver
586  * for species k into a SpeciesThermo instance.
587  */
588 static void installStatMechThermoFromXML(const std::string& speciesName,
589  SpeciesThermo& sp, int k,
590  const std::vector<XML_Node*>& tp)
591 {
592  const XML_Node* fptr = tp[0];
593  int nRegTmp = tp.size();
594  vector_fp cPoly;
595  std::vector<StatMech*> regionPtrs;
596  doublereal tmin, tmax = 0.0, pref = OneAtm;
597 
598  // Loop over all of the possible temperature regions
599  for (int i = 0; i < nRegTmp; i++) {
600  fptr = tp[i];
601  if (fptr) {
602  if (fptr->name() == "StatMech") {
603  if (fptr->hasChild("floatArray")) {
604 
605  tmin = fpValue((*fptr)["Tmin"]);
606  tmax = fpValue((*fptr)["Tmax"]);
607  if ((*fptr).hasAttrib("P0")) {
608  pref = fpValue((*fptr)["P0"]);
609  }
610  if ((*fptr).hasAttrib("Pref")) {
611  pref = fpValue((*fptr)["Pref"]);
612  }
613 
614  getFloatArray(fptr->child("floatArray"), cPoly, false);
615  if (cPoly.size() != 0) {
616  throw CanteraError("installStatMechThermoFromXML",
617  "Expected no coeff: this is not a polynomial representation");
618  }
619  }
620  }
621  }
622  }
623  // set properties
624  tmin = 0.1;
625  vector_fp coeffs(1);
626  coeffs[0] = 0.0;
627  (&sp)->install(speciesName, k, STAT, &coeffs[0], tmin, tmax, pref);
628 }
629 
630 //! Install a Adsorbate polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance.
631 /*!
632  * This is called by method installThermoForSpecies if a Adsorbate block is found in the XML input.
633  *
634  * @param speciesName String name of the species
635  * @param sp SpeciesThermo object that will receive the NASA polynomial object
636  * @param k Species index within the phase
637  * @param f XML Node that contains the parameterization
638  */
639 static void installAdsorbateThermoFromXML(const std::string& speciesName,
640  SpeciesThermo& sp, size_t k,
641  const XML_Node& f)
642 {
643  vector_fp freqs;
644  doublereal tmin, tmax, pref = OneAtm;
645  size_t nfreq = 0;
646  tmin = fpValue(f["Tmin"]);
647  tmax = fpValue(f["Tmax"]);
648  if (f.hasAttrib("P0")) {
649  pref = fpValue(f["P0"]);
650  }
651  if (f.hasAttrib("Pref")) {
652  pref = fpValue(f["Pref"]);
653  }
654  if (tmax == 0.0) {
655  tmax = 1.0e30;
656  }
657 
658  if (f.hasChild("floatArray")) {
659  getFloatArray(f.child("floatArray"), freqs, false);
660  nfreq = freqs.size();
661  }
662  for (size_t n = 0; n < nfreq; n++) {
663  freqs[n] *= 3.0e10;
664  }
665  vector_fp coeffs(nfreq + 2);
666  coeffs[0] = static_cast<double>(nfreq);
667  coeffs[1] = getFloat(f, "binding_energy", "toSI");
668  copy(freqs.begin(), freqs.end(), coeffs.begin() + 2);
669  (&sp)->install(speciesName, k, ADSORBATE, &coeffs[0], tmin, tmax, pref);
670 }
671 
672 void SpeciesThermoFactory::installThermoForSpecies
673 (size_t k, const XML_Node& speciesNode, ThermoPhase* th_ptr,
674  SpeciesThermo& spthermo, const XML_Node* phaseNode_ptr) const
675 {
676  /*
677  * Check to see that the species block has a thermo block
678  * before processing. Throw an error if not there.
679  */
680  if (!(speciesNode.hasChild("thermo"))) {
681  throw UnknownSpeciesThermoModel("installThermoForSpecies",
682  speciesNode["name"], "<nonexistent>");
683  }
684  const XML_Node& thermo = speciesNode.child("thermo");
685 
686  // Get the children of the thermo XML node. In the next bit of code we take out the comments that
687  // may have been children of the thermo XML node by doing a selective copy.
688  // These shouldn't interfere with the algorithm at any point.
689  const std::vector<XML_Node*>& tpWC = thermo.children();
690  std::vector<XML_Node*> tp;
691  for (int i = 0; i < static_cast<int>(tpWC.size()); i++) {
692  if (!(tpWC[i])->isComment()) {
693  tp.push_back(tpWC[i]);
694  }
695  }
696  int nc = static_cast<int>(tp.size());
697  string mname = thermo["model"];
698 
699  if (mname == "MineralEQ3") {
700  const XML_Node* f = tp[0];
701  if (f->name() != "MinEQ3") {
702  throw CanteraError("SpeciesThermoFactory::installThermoForSpecies",
703  "confused: expedted MinEQ3");
704  }
705  installMinEQ3asShomateThermoFromXML(speciesNode["name"], th_ptr, spthermo, k, f);
706  } else {
707  if (nc == 1) {
708  const XML_Node* f = tp[0];
709  if (f->name() == "Shomate") {
710  installShomateThermoFromXML(speciesNode["name"], spthermo, k, f, 0);
711  } else if (f->name() == "const_cp") {
712  installSimpleThermoFromXML(speciesNode["name"], spthermo, k, *f);
713  } else if (f->name() == "NASA") {
714  installNasaThermoFromXML(speciesNode["name"], spthermo, k, f, 0);
715  } else if (f->name() == "Mu0") {
716  installMu0ThermoFromXML(speciesNode["name"], spthermo, k, f);
717  } else if (f->name() == "NASA9") {
718  installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp);
719  } else if (f->name() == "StatMech") {
720  installStatMechThermoFromXML(speciesNode["name"], spthermo, k, tp);
721  } else if (f->name() == "adsorbate") {
722  installAdsorbateThermoFromXML(speciesNode["name"], spthermo, k, *f);
723  } else {
724  throw UnknownSpeciesThermoModel("installThermoForSpecies",
725  speciesNode["name"], f->name());
726  }
727  } else if (nc == 2) {
728  const XML_Node* f0 = tp[0];
729  const XML_Node* f1 = tp[1];
730  if (f0->name() == "NASA" && f1->name() == "NASA") {
731  installNasaThermoFromXML(speciesNode["name"], spthermo, k, f0, f1);
732  } else if (f0->name() == "Shomate" && f1->name() == "Shomate") {
733  installShomateThermoFromXML(speciesNode["name"], spthermo, k, f0, f1);
734  } else if (f0->name() == "StatMech") {
735  installStatMechThermoFromXML(speciesNode["name"], spthermo, k, tp);
736  } else if (f0->name() == "NASA9" && f1->name() == "NASA9") {
737  installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp);
738  } else {
739  throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"],
740  f0->name() + " and " + f1->name());
741  }
742  } else if (nc > 2) {
743  const XML_Node* f0 = tp[0];
744  if (f0->name() == "NASA9") {
745  installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp);
746  } else if (f0->name() == "StatMech") {
747  installStatMechThermoFromXML(speciesNode["name"], spthermo, k, tp);
748  } else {
749  throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"],
750  "multiple");
751  }
752  } else {
753  throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"],
754  "multiple");
755  }
756  }
757 }
758 
759 void SpeciesThermoFactory::
760 installVPThermoForSpecies(size_t k, const XML_Node& speciesNode,
761  VPStandardStateTP* vp_ptr,
762  VPSSMgr* vpssmgr_ptr,
763  SpeciesThermo* spthermo_ptr,
764  const XML_Node* phaseNode_ptr) const
765 {
766 
767  // Call the VPStandardStateTP object to install the pressure dependent species
768  // standard state into the object.
769  //
770  // We don't need to pass spthermo_ptr down, because it's already installed
771  // into vp_ptr.
772  //
773  // We don't need to pass vpssmgr_ptr down, because it's already installed
774  // into vp_ptr.
775  vp_ptr->createInstallPDSS(k, speciesNode, phaseNode_ptr);
776 }
777 
779 {
780  if (f == 0) {
781  f = SpeciesThermoFactory::factory();
782  }
783  return f->newSpeciesThermo(type);
784 }
785 
786 SpeciesThermo* newSpeciesThermoMgr(std::string& stype,
788 {
789  if (f == 0) {
790  f = SpeciesThermoFactory::factory();
791  }
792  return f->newSpeciesThermoManager(stype);
793 }
794 
795 SpeciesThermo* newSpeciesThermoMgr(std::vector<XML_Node*> spData_nodes,
797 {
798  if (f == 0) {
799  f = SpeciesThermoFactory::factory();
800  }
801  return f->newSpeciesThermo(spData_nodes);
802 }
803 
804 }
static void installShomateThermoFromXML(const std::string &speciesName, SpeciesThermo &sp, size_t k, const XML_Node *f0ptr, const XML_Node *f1ptr)
Install a Shomate polynomial thermodynamic property parameterization for species k into a SpeciesTher...
Factory to build instances of classes that manage the standard-state thermodynamic properties of a se...
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
doublereal nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
Definition: Phase.cpp:215
Header for a single-species standard state object derived from SpeciesThermoInterpType based on a pie...
#define NASA
Two regions of 7 coefficient NASA Polynomials This is implemented in the class NasaPoly2 in NasaPoly2...
static void installAdsorbateThermoFromXML(const std::string &speciesName, SpeciesThermo &sp, size_t k, const XML_Node &f)
Install a Adsorbate polynomial thermodynamic property parameterization for species k into a SpeciesTh...
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
void popError()
Discard the last error message.
Definition: global.cpp:161
#define SHOMATE
Two regions of Shomate Polynomials.
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the N...
size_t nElements() const
Number of elements.
Definition: Phase.cpp:139
const doublereal OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:71
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:534
const std::vector< XML_Node * > & children() const
Return an unchangeable reference to the vector of children of the current node.
Definition: xml.cpp:589
Virtual base class for the classes that manage the calculation of standard state properties for all t...
Definition: VPSSMgr.h:238
Declaration file for a virtual base class that manages the calculation of standard state properties f...
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:173
Header for the SimpleThermo (constant heat capacity) species reference-state model for multiple speci...
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the N...
static void installNasa9ThermoFromXML(const std::string &speciesName, SpeciesThermo &sp, size_t k, const std::vector< XML_Node * > &tp)
Install a NASA9 polynomial thermodynamic property parameterization for species k into a SpeciesThermo...
virtual void install(const std::string &name, size_t index, int type, const doublereal *c, doublereal minTemp, doublereal maxTemp, doublereal refPressure)=0
Install a new species thermodynamic property parameterization for one species.
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
Virtual base class for the calculation of multiple-species thermodynamic reference-state property man...
doublereal getFloat(const Cantera::XML_Node &parent, const std::string &name, const std::string &type)
Get a floating-point value from a child element.
Definition: ctml.cpp:267
A species thermodynamic property manager for the NASA polynomial parameterization with two temperatur...
Definition: NasaThermo.h:47
std::string lowercase(const std::string &s)
Cast a copy of a string to lower case.
Definition: stringUtils.cpp:58
void installMu0ThermoFromXML(const std::string &speciesName, SpeciesThermo &sp, size_t k, const XML_Node *Mu0Node_ptr)
Install a Mu0 polynomial thermodynamic reference state.
Definition: Mu0Poly.cpp:126
Pure Virtual base class for the species thermo manager classes.
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:584
doublereal entropyElement298(size_t m) const
Entropy of the element in its standard state at 298 K and 1 bar.
Definition: Phase.cpp:184
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:101
Contains const definitions for types of species reference-state thermodynamics managers (see Species ...
static void getSpeciesThermoTypes(std::vector< XML_Node * > &spDataNodeList, int &has_nasa, int &has_shomate, int &has_simple, int &has_other)
Examine the types of species thermo parameterizations, and return a flag indicating the type of refer...
SpeciesThermo * newSpeciesThermoMgr(std::vector< XML_Node * > spData_nodes, SpeciesThermoFactory *f)
Function to return SpeciesThermo manager.
static doublereal LookupGe(const std::string &elemName, ThermoPhase *th_ptr)
Look up the elemental reference state entropies.
A species thermodynamic property manager for a phase.
static void installNasaThermoFromXML(const std::string &speciesName, SpeciesThermo &sp, size_t k, const XML_Node *f0ptr, const XML_Node *f1ptr)
Install a NASA polynomial thermodynamic property parameterization for species k into a SpeciesThermo ...
virtual void install_STIT(SpeciesThermoInterpType *stit_ptr)=0
Install a new species thermodynamic property parameterization for one species.
static doublereal convertDGFormation(size_t k, ThermoPhase *th_ptr)
Convert delta G formulation.
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
Definition: stringUtils.cpp:29
std::string name() const
Returns the name of the XML node.
Definition: xml.h:390
Classes providing support for XML data files.
static void installStatMechThermoFromXML(const std::string &speciesName, SpeciesThermo &sp, int k, const std::vector< XML_Node * > &tp)
Install a stat mech based property solver for species k into a SpeciesThermo instance.
Header for the 2 regime 7 coefficient Nasa thermodynamic polynomials for multiple species in a phase...
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
This is a filter class for ThermoPhase that implements some prepatory steps for efficiently handling ...
#define SIMPLE
Constant Cp thermo.
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:574
SpeciesThermo * newSpeciesThermo(int type) const
Create a new species property manager for the reference state.
SpeciesThermo * newSpeciesThermoManager(std::string &stype) const
Create a new species thermo property manager given a string.
Header for a single-species standard state object derived from.
static void installMinEQ3asShomateThermoFromXML(const std::string &speciesName, ThermoPhase *th_ptr, SpeciesThermo &sp, size_t k, const XML_Node *MinEQ3node)
Install a NASA96 polynomial thermodynamic property parameterization for species k into a SpeciesTherm...
This species thermo manager requires that all species have one of two parameterizations.
#define ENTROPY298_UNKNOWN
Number indicating we don't know the entropy of the element in its most stable state at 298...
Definition: Elements.h:84
This file contains descriptions of templated subclasses of the virtual base class, SpeciesThermo, which includes SpeciesThermoDuo (see Managers for Calculating Reference-State Thermodynamics and class SpeciesThermoDuo)
Throw a named error for an unknown or missing species thermo model.
static void installSimpleThermoFromXML(const std::string &speciesName, SpeciesThermo &sp, size_t k, const XML_Node &f)
Install a Simple thermodynamic property parameterization for species k into a SpeciesThermo instance...
Header for factory to build instances of classes that manage the standard-state thermodynamic propert...
doublereal getFloatDefaultUnits(const Cantera::XML_Node &parent, const std::string &name, const std::string &defaultUnits, const std::string &type)
Get a floating-point value from a child element with a defined units field.
Definition: ctml.cpp:347
Headers for a completely general species thermodynamic property manager for a phase (see Managers for...
Header for the 2 regions Shomate polynomial for multiple species in a phase, derived from the Species...
A species thermodynamic property manager for the Shomate polynomial parameterization.
Definition: ShomateThermo.h:59
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:165
Unknown species thermo manager string error.
size_t elementIndex(const std::string &name) const
Return the index of element named 'name'.
Definition: Phase.cpp:164
#define STAT
Properties derived from theoretical considerations This is implemented in the class statmech in StatM...
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
The NASA 9 polynomial parameterization for one temperature range.
Definition: Nasa9Poly1.h:69
std::string elementName(size_t m) const
Name of the element with index m.
Definition: Phase.cpp:158
Header for a single-species standard state object derived from SpeciesThermoInterpType based on the e...
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.
size_t getFloatArray(const Cantera::XML_Node &node, std::vector< doublereal > &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:419
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
Definition: xml.cpp:579
#define ADSORBATE
Surface Adsorbate Model for a species on a surface.