Cantera  2.5.1
ThermoFactory.cpp
Go to the documentation of this file.
1 /**
2  * @file ThermoFactory.cpp
3  * Definitions for the factory class that can create known ThermoPhase objects
4  * (see \ref thermoprops and class \link Cantera::ThermoFactory ThermoFactory\endlink).
5  */
6 
7 // This file is part of Cantera. See License.txt in the top-level directory or
8 // at https://cantera.org/license.txt for license and copyright information.
9 
11 
12 #include "cantera/thermo/Species.h"
18 
34 #include "cantera/thermo/HMWSoln.h"
41 
42 using namespace std;
43 
44 namespace Cantera
45 {
46 
47 ThermoFactory* ThermoFactory::s_factory = 0;
48 std::mutex ThermoFactory::thermo_mutex;
49 
50 ThermoFactory::ThermoFactory()
51 {
52  reg("ideal-gas", []() { return new IdealGasPhase(); });
53  addAlias("ideal-gas", "IdealGas");
54  reg("constant-density", []() { return new ConstDensityThermo(); });
55  addAlias("constant-density", "Incompressible");
56  reg("ideal-surface", []() { return new SurfPhase(); });
57  addAlias("ideal-surface", "Surface");
58  reg("edge", []() { return new EdgePhase(); });
59  addAlias("edge", "Edge");
60  reg("electron-cloud", []() { return new MetalPhase(); });
61  addAlias("electron-cloud", "Metal");
62  reg("fixed-stoichiometry", []() { return new StoichSubstance(); });
63  addAlias("fixed-stoichiometry", "StoichSubstance");
64  reg("pure-fluid", []() { return new PureFluidPhase(); });
65  addAlias("pure-fluid", "PureFluid");
66  reg("compound-lattice", []() { return new LatticeSolidPhase(); });
67  addAlias("compound-lattice", "LatticeSolid");
68  reg("lattice", []() { return new LatticePhase(); });
69  addAlias("lattice", "Lattice");
70  reg("HMW-electrolyte", []() { return new HMWSoln(); });
71  addAlias("HMW-electrolyte", "HMW");
72  reg("ideal-condensed", []() { return new IdealSolidSolnPhase(); });
73  addAlias("ideal-condensed", "IdealSolidSolution");
74  reg("Debye-Huckel", []() { return new DebyeHuckel(); });
75  addAlias("Debye-Huckel", "DebyeHuckel");
76  reg("ideal-molal-solution", []() { return new IdealMolalSoln(); });
77  addAlias("ideal-molal-solution", "IdealMolalSolution");
78  reg("ideal-solution-VPSS", []() { return new IdealSolnGasVPSS(); });
79  reg("ideal-gas-VPSS", []() { return new IdealSolnGasVPSS(); });
80  addAlias("ideal-solution-VPSS", "IdealSolnVPSS");
81  addAlias("ideal-gas-VPSS", "IdealGasVPSS");
82  reg("Margules", []() { return new MargulesVPSSTP(); });
83  reg("ions-from-neutral-molecule", []() { return new IonsFromNeutralVPSSTP(); });
84  addAlias("ions-from-neutral-molecule", "IonsFromNeutralMolecule");
85  reg("fixed-chemical-potential", []() { return new FixedChemPotSSTP(); });
86  addAlias("fixed-chemical-potential", "FixedChemPot");
87  reg("Redlich-Kister", []() { return new RedlichKisterVPSSTP(); });
88  reg("Redlich-Kwong", []() { return new RedlichKwongMFTP(); });
89  addAlias("Redlich-Kwong", "RedlichKwongMFTP");
90  addAlias("Redlich-Kwong", "RedlichKwong");
91  reg("Maskell-solid-solution", []() { return new MaskellSolidSolnPhase(); });
92  addAlias("Maskell-solid-solution", "MaskellSolidSolnPhase");
93  reg("liquid-water-IAPWS95", []() { return new WaterSSTP(); });
94  addAlias("liquid-water-IAPWS95", "PureLiquidWater");
95  reg("binary-solution-tabulated", []() { return new BinarySolutionTabulatedThermo(); });
96  addAlias("binary-solution-tabulated", "BinarySolutionTabulatedThermo");
97 }
98 
99 ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model)
100 {
101  return create(model);
102 }
103 
105 {
106  string model = xmlphase.child("thermo")["model"];
107  unique_ptr<ThermoPhase> t(newThermoPhase(model));
108  importPhase(xmlphase, t.get());
109  return t.release();
110 }
111 
112 unique_ptr<ThermoPhase> newPhase(AnyMap& phaseNode, const AnyMap& rootNode)
113 {
114  unique_ptr<ThermoPhase> t(newThermoPhase(phaseNode["thermo"].asString()));
115  setupPhase(*t, phaseNode, rootNode);
116  return t;
117 }
118 
119 ThermoPhase* newPhase(const std::string& infile, std::string id)
120 {
121  size_t dot = infile.find_last_of(".");
122  string extension;
123  if (dot != npos) {
124  extension = toLowerCopy(infile.substr(dot+1));
125  }
126  if (id == "-") {
127  id = "";
128  }
129 
130  if (extension == "yml" || extension == "yaml") {
131  AnyMap root = AnyMap::fromYamlFile(infile);
132  AnyMap& phase = root["phases"].getMapWhere("name", id);
133  unique_ptr<ThermoPhase> t(newThermoPhase(phase["thermo"].asString()));
134  setupPhase(*t, phase, root);
135  return t.release();
136  } else {
137  XML_Node* root = get_XML_File(infile);
138  XML_Node* xphase = get_XML_NameID("phase", "#"+id, root);
139  if (!xphase) {
140  throw CanteraError("newPhase",
141  "Couldn't find phase named \"" + id + "\" in file, " + infile);
142  }
143  return newPhase(*xphase);
144  }
145 }
146 
147 //! Gather a vector of pointers to XML_Nodes for a phase
148 /*!
149  * @param spDataNodeList Output vector of pointer to XML_Nodes which contain
150  * the species XML_Nodes for the species in the current phase.
151  * @param spNamesList Output Vector of strings, which contain the names
152  * of the species in the phase
153  * @param spRuleList Output Vector of ints, which contain the value of
154  * sprule for each species in the phase
155  * @param spArray_names Vector of pointers to the XML_Nodes which contains
156  * the names of the species in the phase
157  * @param spArray_dbases Input vector of pointers to species data bases. We
158  * search each data base for the required species
159  * names
160  * @param sprule Input vector of sprule values
161  */
162 static void formSpeciesXMLNodeList(std::vector<XML_Node*> &spDataNodeList,
163  std::vector<std::string> &spNamesList,
164  vector_int &spRuleList,
165  const std::vector<XML_Node*> spArray_names,
166  const std::vector<XML_Node*> spArray_dbases,
167  const vector_int sprule)
168 {
169  // used to check that each species is declared only once
170  std::map<std::string, bool> declared;
171 
172  for (size_t jsp = 0; jsp < spArray_dbases.size(); jsp++) {
173  const XML_Node& speciesArray = *spArray_names[jsp];
174 
175  // Get the top XML for the database
176  const XML_Node* db = spArray_dbases[jsp];
177 
178  // Get the array of species name strings and then count them
179  std::vector<std::string> spnames;
180  getStringArray(speciesArray, spnames);
181  size_t nsp = spnames.size();
182 
183  // if 'all' is specified as the one and only species in the
184  // spArray_names field, then add all species defined in the
185  // corresponding database to the phase
186  if (nsp == 1 && spnames[0] == "all") {
187  std::vector<XML_Node*> allsp = db->getChildren("species");
188  nsp = allsp.size();
189  spnames.resize(nsp);
190  for (size_t nn = 0; nn < nsp; nn++) {
191  string stemp = (*allsp[nn])["name"];
192  if (!declared[stemp] || sprule[jsp] < 10) {
193  declared[stemp] = true;
194  spNamesList.push_back(stemp);
195  spDataNodeList.push_back(allsp[nn]);
196  spRuleList.push_back(sprule[jsp]);
197  }
198  }
199  } else if (nsp == 1 && spnames[0] == "unique") {
200  std::vector<XML_Node*> allsp = db->getChildren("species");
201  nsp = allsp.size();
202  spnames.resize(nsp);
203  for (size_t nn = 0; nn < nsp; nn++) {
204  string stemp = (*allsp[nn])["name"];
205  if (!declared[stemp]) {
206  declared[stemp] = true;
207  spNamesList.push_back(stemp);
208  spDataNodeList.push_back(allsp[nn]);
209  spRuleList.push_back(sprule[jsp]);
210  }
211  }
212  } else {
213  std::map<std::string, XML_Node*> speciesNodes;
214  for (size_t k = 0; k < db->nChildren(); k++) {
215  XML_Node& child = db->child(k);
216  speciesNodes[child["name"]] = &child;
217  }
218  for (size_t k = 0; k < nsp; k++) {
219  string stemp = spnames[k];
220  if (!declared[stemp] || sprule[jsp] < 10) {
221  declared[stemp] = true;
222  // Find the species in the database by name.
223  auto iter = speciesNodes.find(stemp);
224  if (iter == speciesNodes.end()) {
225  throw CanteraError("formSpeciesXMLNodeList",
226  "no data for species, \"{}\"", stemp);
227  }
228  spNamesList.push_back(stemp);
229  spDataNodeList.push_back(iter->second);
230  spRuleList.push_back(sprule[jsp]);
231  }
232  }
233  }
234  }
235 }
236 
238 {
239  // Check the the supplied XML node in fact represents a phase.
240  if (phase.name() != "phase") {
241  throw CanteraError("importPhase",
242  "Current const XML_Node named, " + phase.name() +
243  ", is not a phase element.");
244  }
245 
246  // In this section of code, we get the reference to the phase XML tree
247  // within the ThermoPhase object. Then, we clear it and fill it with the
248  // current information that we are about to use to construct the object. We
249  // will then be able to resurrect the information later by calling xml().
250  th->setXMLdata(phase);
251 
252  // set the id attribute of the phase to the 'id' attribute in the XML tree.
253  th->setName(phase.id());
254 
255  // Number of spatial dimensions. Defaults to 3 (bulk phase)
256  if (phase.hasAttrib("dim")) {
257  int idim = intValue(phase["dim"]);
258  if (idim < 1 || idim > 3) {
259  throw CanteraError("importPhase",
260  "phase, " + th->name() +
261  ", has unphysical number of dimensions: " + phase["dim"]);
262  }
263  th->setNDim(idim);
264  } else {
265  th->setNDim(3); // default
266  }
267 
268  // Set equation of state parameters. The parameters are specific to each
269  // subclass of ThermoPhase, so this is done by method setParametersFromXML
270  // in each subclass.
271  const XML_Node& eos = phase.child("thermo");
272  if (phase.hasChild("thermo")) {
273  th->setParametersFromXML(eos);
274  } else {
275  throw CanteraError("importPhase",
276  " phase, " + th->name() +
277  ", XML_Node does not have a \"thermo\" XML_Node");
278  }
279 
280  VPStandardStateTP* vpss_ptr = 0;
281  int ssConvention = th->standardStateConvention();
282  if (ssConvention == cSS_CONVENTION_VPSS) {
283  vpss_ptr = dynamic_cast <VPStandardStateTP*>(th);
284  if (vpss_ptr == 0) {
285  throw CanteraError("importPhase",
286  "phase, " + th->name() + ", was VPSS, but dynamic cast failed");
287  }
288  }
289 
290  // Add the elements.
291  if (ssConvention != cSS_CONVENTION_SLAVE) {
292  installElements(*th, phase);
293  }
294 
295  // Add the species.
296  //
297  // Species definitions may be imported from multiple sources. For each one,
298  // a speciesArray element must be present.
299  vector<XML_Node*> sparrays = phase.getChildren("speciesArray");
300  if (ssConvention != cSS_CONVENTION_SLAVE && sparrays.empty()) {
301  throw CanteraError("importPhase",
302  "phase, " + th->name() + ", has zero \"speciesArray\" XML nodes.\n"
303  + " There must be at least one speciesArray nodes "
304  "with one or more species");
305  }
306  vector<XML_Node*> dbases;
307  vector_int sprule(sparrays.size(),0);
308 
309  // Default behavior when importing from CTI/XML is for undefined elements to
310  // be treated as an error
312 
313  // loop over the speciesArray elements
314  for (size_t jsp = 0; jsp < sparrays.size(); jsp++) {
315  const XML_Node& speciesArray = *sparrays[jsp];
316 
317  // If the speciesArray element has a child element
318  //
319  // <skip element="undeclared">
320  //
321  // then set sprule[jsp] to 1, so that any species with an undeclared
322  // element will be quietly skipped when importing species. Additionally,
323  // if the skip node has the following attribute:
324  //
325  // <skip species="duplicate">
326  //
327  // then duplicate species names will not cause Cantera to throw an
328  // exception. Instead, the duplicate entry will be discarded.
329  if (speciesArray.hasChild("skip")) {
330  const XML_Node& sk = speciesArray.child("skip");
331  string eskip = sk["element"];
332  if (eskip == "undeclared") {
333  sprule[jsp] = 1;
334  }
335  string dskip = sk["species"];
336  if (dskip == "duplicate") {
337  sprule[jsp] += 10;
338  }
339  }
340 
341  // Get a pointer to the node containing the species definitions for the
342  // species declared in this speciesArray element. This may be in the
343  // local file containing the phase element, or may be in another file.
344  XML_Node* db = get_XML_Node(speciesArray["datasrc"], &phase.root());
345  if (db == 0) {
346  throw CanteraError("importPhase",
347  "Can not find XML node for species database: {}",
348  speciesArray["datasrc"]);
349  }
350 
351  // add this node to the list of species database nodes.
352  dbases.push_back(db);
353  }
354 
355  // Now, collect all the species names and all the XML_Node * pointers for
356  // those species in a single vector. This is where we decide what species
357  // are to be included in the phase. The logic is complicated enough that we
358  // put it in a separate routine.
359  std::vector<XML_Node*> spDataNodeList;
360  std::vector<std::string> spNamesList;
361  vector_int spRuleList;
362  formSpeciesXMLNodeList(spDataNodeList, spNamesList, spRuleList,
363  sparrays, dbases, sprule);
364 
365  size_t nsp = spDataNodeList.size();
366  if (ssConvention == cSS_CONVENTION_SLAVE && nsp > 0) {
367  throw CanteraError("importPhase", "For Slave standard states, "
368  "number of species must be zero: {}", nsp);
369  }
370  for (size_t k = 0; k < nsp; k++) {
371  XML_Node* s = spDataNodeList[k];
372  AssertTrace(s != 0);
373  if (spRuleList[k]) {
375  }
376  th->addSpecies(newSpecies(*s));
377  if (vpss_ptr) {
378  const XML_Node* const ss = s->findByName("standardState");
379  std::string ss_model = (ss) ? ss->attrib("model") : "ideal-gas";
380  unique_ptr<PDSS> kPDSS(newPDSS(ss_model));
381  kPDSS->setParametersFromXML(*s);
382  vpss_ptr->installPDSS(k, std::move(kPDSS));
383  }
384  th->saveSpeciesData(k, s);
385  }
386 
387  // Done adding species. Perform any required subclass-specific
388  // initialization.
389  th->initThermo();
390 
391  // Perform any required subclass-specific initialization that requires the
392  // XML phase object
393  std::string id = "";
394  th->initThermoXML(phase, id);
395 }
396 
397 void addDefaultElements(ThermoPhase& thermo, const vector<string>& element_names) {
398  for (const auto& symbol : element_names) {
399  thermo.addElement(symbol);
400  }
401 }
402 
403 void addElements(ThermoPhase& thermo, const vector<string>& element_names,
404  const AnyValue& elements, bool allow_default)
405 {
406  const auto& local_elements = elements.asMap("symbol");
407  for (const auto& symbol : element_names) {
408  if (local_elements.count(symbol)) {
409  auto& element = *local_elements.at(symbol);
410  double weight = element["atomic-weight"].asDouble();
411  long int number = element.getInt("atomic-number", 0);
412  double e298 = element.getDouble("entropy298", ENTROPY298_UNKNOWN);
413  thermo.addElement(symbol, weight, number, e298);
414  } else if (allow_default) {
415  thermo.addElement(symbol);
416  } else {
417  throw InputFileError("addElements", elements,
418  "Element '{}' not found", symbol);
419  }
420  }
421 }
422 
423 void addSpecies(ThermoPhase& thermo, const AnyValue& names, const AnyValue& species)
424 {
425  if (names.is<vector<string>>()) {
426  // 'names' is a list of species names which should be found in 'species'
427  const auto& species_nodes = species.asMap("name");
428  for (const auto& name : names.asVector<string>()) {
429  if (species_nodes.count(name)) {
430  thermo.addSpecies(newSpecies(*species_nodes.at(name)));
431  } else {
432  throw InputFileError("addSpecies", names, species,
433  "Could not find a species named '{}'.", name);
434  }
435  }
436  } else if (names == "all") {
437  // The keyword 'all' means to add all species from this source
438  for (const auto& item : species.asVector<AnyMap>()) {
439  thermo.addSpecies(newSpecies(item));
440  }
441  } else {
442  throw InputFileError("addSpecies", names,
443  "Could not parse species declaration of type '{}'", names.type_str());
444  }
445 }
446 
447 void setupPhase(ThermoPhase& thermo, AnyMap& phaseNode, const AnyMap& rootNode)
448 {
449  thermo.setName(phaseNode["name"].asString());
450  if (rootNode.hasKey("__file__")) {
451  phaseNode["__file__"] = rootNode["__file__"];
452  }
453 
454  if (phaseNode.hasKey("deprecated")) {
455  string msg = phaseNode["deprecated"].asString();
456  string filename = phaseNode.getString("__file__", "unknown file");
457  string method = fmt::format("{}/{}", filename, phaseNode["name"].asString());
458  warn_deprecated(method, msg);
459  }
460 
461  // Add elements
462  if (phaseNode.hasKey("elements")) {
463  if (phaseNode.getBool("skip-undeclared-elements", false)) {
464  thermo.ignoreUndefinedElements();
465  } else {
466  thermo.throwUndefinedElements();
467  }
468 
469  if (phaseNode["elements"].is<vector<string>>()) {
470  // 'elements' is a list of element symbols
471  if (rootNode.hasKey("elements")) {
472  addElements(thermo, phaseNode["elements"].asVector<string>(),
473  rootNode["elements"], true);
474  } else {
475  addDefaultElements(thermo, phaseNode["elements"].asVector<string>());
476  }
477  } else if (phaseNode["elements"].is<vector<AnyMap>>()) {
478  // Each item in 'elements' is a map with one item, where the key is
479  // a section in this file or another YAML file, and the value is a
480  // list of element symbols to read from that section
481  for (const auto& elemNode : phaseNode["elements"].asVector<AnyMap>()) {
482  const string& source = elemNode.begin()->first;
483  const auto& names = elemNode.begin()->second.asVector<string>();
484  const auto& slash = boost::ifind_last(source, "/");
485  if (slash) {
486  std::string fileName(source.begin(), slash.begin());
487  std::string node(slash.end(), source.end());
488  const AnyMap elements = AnyMap::fromYamlFile(fileName,
489  rootNode.getString("__file__", ""));
490  addElements(thermo, names, elements.at(node), false);
491  } else if (rootNode.hasKey(source)) {
492  addElements(thermo, names, rootNode.at(source), false);
493  } else if (source == "default") {
494  addDefaultElements(thermo, names);
495  } else {
496  throw InputFileError("setupPhase", elemNode,
497  "Could not find elements section named '{}'", source);
498  }
499  }
500  } else {
501  throw InputFileError("setupPhase", phaseNode["elements"],
502  "Could not parse elements declaration of type '{}'",
503  phaseNode["elements"].type_str());
504  }
505  } else {
506  // If no elements list is provided, just add elements as-needed from the
507  // default list.
508  thermo.addUndefinedElements();
509  }
510 
511  // Add species
512  if (phaseNode.hasKey("species")) {
513  if (phaseNode["species"].is<vector<string>>()) {
514  // 'species' is a list of species names to be added from the current
515  // file's 'species' section
516  addSpecies(thermo, phaseNode["species"], rootNode["species"]);
517  } else if (phaseNode["species"].is<string>()) {
518  // 'species' is a keyword applicable to the current file's 'species'
519  // section
520  addSpecies(thermo, phaseNode["species"], rootNode["species"]);
521  } else if (phaseNode["species"].is<vector<AnyMap>>()) {
522  // Each item in 'species' is a map with one item, where the key is
523  // a section in this file or another YAML file, and the value is a
524  // list of species names to read from that section
525  for (const auto& speciesNode : phaseNode["species"].asVector<AnyMap>()) {
526  const string& source = speciesNode.begin()->first;
527  const auto& names = speciesNode.begin()->second;
528  const auto& slash = boost::ifind_last(source, "/");
529  if (slash) {
530  // source is a different input file
531  std::string fileName(source.begin(), slash.begin());
532  std::string node(slash.end(), source.end());
533  AnyMap species = AnyMap::fromYamlFile(fileName,
534  rootNode.getString("__file__", ""));
535  addSpecies(thermo, names, species[node]);
536  } else if (rootNode.hasKey(source)) {
537  // source is in the current file
538  addSpecies(thermo, names, rootNode[source]);
539  } else {
540  throw InputFileError("setupPhase", speciesNode,
541  "Could not find species section named '{}'", source);
542  }
543  }
544  } else {
545  throw InputFileError("setupPhase", phaseNode["species"],
546  "Could not parse species declaration of type '{}'",
547  phaseNode["species"].type_str());
548  }
549  } else if (rootNode.hasKey("species")) {
550  // By default, add all species from the 'species' section
551  addSpecies(thermo, AnyValue("all"), rootNode["species"]);
552  }
553 
554  auto* vpssThermo = dynamic_cast<VPStandardStateTP*>(&thermo);
555  if (vpssThermo) {
556  for (size_t k = 0; k < thermo.nSpecies(); k++) {
557  unique_ptr<PDSS> pdss;
558  if (thermo.species(k)->input.hasKey("equation-of-state")) {
559  // Use the first node which specifies a valid PDSS model
560  auto& eos = thermo.species(k)->input["equation-of-state"];
561  bool found = false;
562  for (auto& node : eos.asVector<AnyMap>()) {
563  string model = node["model"].asString();
564  if (PDSSFactory::factory()->exists(model)) {
565  pdss.reset(newPDSS(model));
566  pdss->setParameters(node);
567  found = true;
568  break;
569  }
570  }
571  if (!found) {
572  throw InputFileError("setupPhase", eos,
573  "Could not find an equation-of-state specification "
574  "which defines a known PDSS model.");
575  }
576  } else {
577  pdss.reset(newPDSS("ideal-gas"));
578  }
579  vpssThermo->installPDSS(k, std::move(pdss));
580  }
581  }
582 
583  thermo.setParameters(phaseNode, rootNode);
584  thermo.initThermo();
585 
586  if (phaseNode.hasKey("state")) {
587  auto node = phaseNode["state"].as<AnyMap>();
588  thermo.setState(node);
589  } else {
590  thermo.setState_TP(298.15, OneAtm);
591  }
592 }
593 
594 void installElements(Phase& th, const XML_Node& phaseNode)
595 {
596  // get the declared element names
597  if (!phaseNode.hasChild("elementArray")) {
598  throw CanteraError("installElements",
599  "phase XML node doesn't have \"elementArray\" XML Node");
600  }
601  XML_Node& elements = phaseNode.child("elementArray");
602  vector<string> enames;
603  getStringArray(elements, enames);
604 
605  // // element database defaults to elements.xml
606  string element_database = "elements.xml";
607  if (elements.hasAttrib("datasrc")) {
608  element_database = elements["datasrc"];
609  }
610 
611  XML_Node* doc = get_XML_File(element_database);
612  XML_Node* dbe = &doc->child("elementData");
613 
614  XML_Node& root = phaseNode.root();
615  XML_Node* local_db = 0;
616  if (root.hasChild("elementData")) {
617  local_db = &root.child("elementData");
618  }
619 
620  for (size_t i = 0; i < enames.size(); i++) {
621  // Find the element data
622  XML_Node* e = 0;
623  if (local_db) {
624  e = local_db->findByAttr("name",enames[i]);
625  }
626  if (!e) {
627  e = dbe->findByAttr("name",enames[i]);
628  }
629  if (!e) {
630  throw CanteraError("installElements", "no data for element '{}'",
631  enames[i]);
632  }
633 
634  // Add the element
635  doublereal weight = 0.0;
636  if (e->hasAttrib("atomicWt")) {
637  weight = fpValue(e->attrib("atomicWt"));
638  }
639  int anum = 0;
640  if (e->hasAttrib("atomicNumber")) {
641  anum = intValue(e->attrib("atomicNumber"));
642  }
643  string symbol = e->attrib("name");
644  doublereal entropy298 = ENTROPY298_UNKNOWN;
645  if (e->hasChild("entropy298")) {
646  XML_Node& e298Node = e->child("entropy298");
647  if (e298Node.hasAttrib("value")) {
648  entropy298 = fpValueCheck(e298Node["value"]);
649  }
650  }
651  th.addElement(symbol, weight, anum, entropy298);
652  }
653 }
654 
655 const XML_Node* speciesXML_Node(const std::string& kname,
656  const XML_Node* phaseSpeciesData)
657 {
658  if (!phaseSpeciesData) {
659  return 0;
660  }
661  string jname = phaseSpeciesData->name();
662  if (jname != "speciesData") {
663  throw CanteraError("speciesXML_Node",
664  "Unexpected phaseSpeciesData name: " + jname);
665  }
666  vector<XML_Node*> xspecies = phaseSpeciesData->getChildren("species");
667  for (size_t j = 0; j < xspecies.size(); j++) {
668  const XML_Node& sp = *xspecies[j];
669  jname = sp["name"];
670  if (jname == kname) {
671  return &sp;
672  }
673  }
674  return 0;
675 }
676 
677 }
Header file for an binary solution model with tabulated standard state thermodynamic data (see Thermo...
Header for a Thermo manager for incompressible ThermoPhases (see Thermodynamic Properties and ConstDe...
Headers for the DebyeHuckel ThermoPhase object, which models dilute electrolyte solutions (see Thermo...
Declarations for the EdgePhase ThermoPhase object, which models the interface between two surfaces (s...
#define ENTROPY298_UNKNOWN
Number indicating we don't know the entropy of the element in its most stable state at 298....
Definition: Elements.h:87
Header file for the FixedChemPotSSTP class, which represents a fixed-composition incompressible subst...
Headers for the HMWSoln ThermoPhase object, which models concentrated electrolyte solutions (see Ther...
ThermoPhase object for the ideal gas equation of state - workhorse for Cantera (see Thermodynamic Pro...
ThermoPhase object for the ideal molal equation of state (see Thermodynamic Properties and class Idea...
Header file for an ideal solid solution model with incompressible thermodynamics (see Thermodynamic P...
Definition file for a derived class of ThermoPhase that assumes either an ideal gas or ideal solution...
Header for intermediate ThermoPhase object for phases which consist of ions whose thermodynamics is c...
Header for a simple thermodynamics model of a bulk phase derived from ThermoPhase,...
Header for a simple thermodynamics model of a bulk solid phase derived from ThermoPhase,...
(see Thermodynamic Properties and class MargulesVPSSTP).
Header file for a solid solution model following Maskell, Shaw, and Tye.
Header for a general species thermodynamic property manager for a phase (see MultiSpeciesThermo).
Header for a ThermoPhase class for a pure fluid phase consisting of gas, liquid, mixed-gas-liquid and...
(see Thermodynamic Properties and class RedlichKisterVPSSTP).
Header for factory functions to build instances of classes that manage the standard-state thermodynam...
Declaration for class Cantera::Species.
Header file for the StoichSubstance class, which represents a fixed-composition incompressible substa...
Header for a simple thermodynamics model of a surface phase derived from ThermoPhase,...
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
Declares a ThermoPhase class consisting of pure water (see Thermodynamic Properties and class WaterSS...
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:360
const AnyValue & at(const std::string &key) const
Get the value of the item stored in key.
Definition: AnyMap.cpp:974
const std::string & getString(const std::string &key, const std::string &default_) const
If key exists, return it as a string, otherwise return default_.
Definition: AnyMap.cpp:1049
bool getBool(const std::string &key, bool default_) const
If key exists, return it as a bool, otherwise return default_.
Definition: AnyMap.cpp:1034
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:984
A wrapper for a variable whose type is determined at runtime.
Definition: AnyMap.h:77
Overloads the virtual methods of class IdealSolidSolnPhase to implement tabulated standard state ther...
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Overloads the virtual methods of class ThermoPhase to implement the incompressible equation of state.
Class DebyeHuckel represents a dilute liquid electrolyte phase which obeys the Debye Huckel formulati...
Definition: DebyeHuckel.h:559
A thermodynamic phase representing a one dimensional edge between two surfaces.
Definition: EdgePhase.h:31
Class FixedChemPotSSTP represents a stoichiometric (fixed composition) incompressible substance.
Class HMWSoln represents a dilute or concentrated liquid electrolyte phase which obeys the Pitzer for...
Definition: HMWSoln.h:1039
Class IdealGasPhase represents low-density gases that obey the ideal gas equation of state.
This phase is based upon the mixing-rule assumption that all molality-based activity coefficients are...
Class IdealSolidSolnPhase represents a condensed phase ideal solution compound.
An ideal solution or an ideal gas approximation of a phase.
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:539
A simple thermodynamic model for a bulk phase, assuming a lattice of solid atoms.
Definition: LatticePhase.h:231
A phase that is comprised of a fixed additive combination of other lattice phases.
MargulesVPSSTP is a derived class of GibbsExcessVPSSTP that employs the Margules approximation for th...
Class MaskellSolidSolnPhase represents a condensed phase non-ideal solution with 2 species following ...
Class MetalPhase represents electrons in a metal.
Definition: MetalPhase.h:23
Class Phase is the base class for phases of matter, managing the species and elements in a phase,...
Definition: Phase.h:101
void setName(const std::string &nm)
Sets the string name for the phase.
Definition: Phase.cpp:89
size_t addElement(const std::string &symbol, doublereal weight=-12345.0, int atomicNumber=0, doublereal entropy298=ENTROPY298_UNKNOWN, int elem_type=CT_ELEM_TYPE_ABSPOS)
Add an element.
Definition: Phase.cpp:765
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 ignoreUndefinedElements()
Set behavior when adding a species containing undefined elements to just skip the species.
Definition: Phase.cpp:997
void addUndefinedElements()
Set behavior when adding a species containing undefined elements to add those elements to the phase.
Definition: Phase.cpp:1001
void setNDim(size_t ndim)
Set the number of spatial dimensions (1, 2, or 3).
Definition: Phase.h:658
void setXMLdata(XML_Node &xmlPhase)
Stores the XML tree information for the current phase.
Definition: Phase.cpp:50
void throwUndefinedElements()
Set the behavior when adding a species containing undefined elements to throw an exception.
Definition: Phase.cpp:1005
shared_ptr< Species > species(const std::string &name) const
Return the Species object for the named species.
Definition: Phase.cpp:980
This phase object consists of a single component that can be a gas, a liquid, a mixed gas-liquid flui...
RedlichKisterVPSSTP is a derived class of GibbsExcessVPSSTP that employs the Redlich-Kister approxima...
Implementation of a multi-species Redlich-Kwong equation of state.
Class StoichSubstance represents a stoichiometric (fixed composition) incompressible substance.
A simple thermodynamic model for a surface phase, assuming an ideal solution model.
Definition: SurfPhase.h:143
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:102
virtual bool addSpecies(shared_ptr< Species > spec)
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
virtual void setState(const AnyMap &state)
Set the state using an AnyMap containing any combination of properties supported by the thermodynamic...
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
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 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 void setParameters(int n, doublereal *const c)
Set the equation of state parameters.
Definition: ThermoPhase.h:1691
virtual void setParametersFromXML(const XML_Node &eosdata)
Set equation of state parameter values from XML entries.
Definition: ThermoPhase.h:1728
This is a filter class for ThermoPhase that implements some preparatory steps for efficiently handlin...
void installPDSS(size_t k, std::unique_ptr< PDSS > &&pdss)
Install a PDSS object for species k
Class for single-component water.
Definition: WaterSSTP.h:120
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:104
XML_Node * findByAttr(const std::string &attr, const std::string &val, int depth=100000) const
This routine carries out a recursive search for an XML node based on an attribute of each XML node.
Definition: xml.cpp:661
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:492
std::string name() const
Returns the name of the XML node.
Definition: xml.h:372
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:528
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:538
XML_Node & root() const
Return the root of the current XML_Node tree.
Definition: xml.cpp:749
const XML_Node * findByName(const std::string &nm, int depth=100000) const
This routine carries out a recursive search for an XML node based on the name of the node.
Definition: xml.cpp:679
std::vector< XML_Node * > getChildren(const std::string &name) const
Get a vector of pointers to XML_Node containing all of the children of the current node which match t...
Definition: xml.cpp:711
size_t nChildren(bool discardComments=false) const
Return the number of children.
Definition: xml.cpp:556
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
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
Definition: xml.cpp:533
#define AssertTrace(expr)
Assertion must be true or an error is thrown.
Definition: ctexceptions.h:234
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
XML_Node * get_XML_Node(const std::string &file_ID, XML_Node *root)
This routine will locate an XML node in either the input XML tree or in another input file specified ...
Definition: global.cpp:194
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
Definition: global.cpp:54
XML_Node * get_XML_NameID(const std::string &nameTarget, const std::string &file_ID, XML_Node *root)
This routine will locate an XML node in either the input XML tree or in another input file specified ...
Definition: global.cpp:232
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:188
const double OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:78
std::vector< int > vector_int
Vector of ints.
Definition: ct_defs.h:182
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
int intValue(const std::string &val)
Translate a string into one integer value.
void getStringArray(const XML_Node &node, std::vector< std::string > &v)
This function interprets the value portion of an XML element as a string.
Definition: ctml.cpp:427
doublereal dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition: utilities.h:112
const int cSS_CONVENTION_VPSS
Standard state uses the molality convention.
Definition: ThermoPhase.h:38
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
shared_ptr< Species > newSpecies(const XML_Node &species_node)
Create a new Species object from a 'species' XML_Node.
Definition: Species.cpp:36
void setupPhase(ThermoPhase &thermo, AnyMap &phaseNode, const AnyMap &rootNode)
Initialize a ThermoPhase object.
std::string toLowerCopy(const std::string &input)
Convert to lower case.
const XML_Node * speciesXML_Node(const std::string &kname, const XML_Node *phaseSpeciesData)
Search an XML tree for species data.
static void formSpeciesXMLNodeList(std::vector< XML_Node * > &spDataNodeList, std::vector< std::string > &spNamesList, vector_int &spRuleList, const std::vector< XML_Node * > spArray_names, const std::vector< XML_Node * > spArray_dbases, const vector_int sprule)
Gather a vector of pointers to XML_Nodes for a phase.
void installElements(Phase &th, const XML_Node &phaseNode)
Add the elements given in an XML_Node tree to the specified phase.
ThermoPhase * newThermoPhase(const std::string &model)
Create a new thermo manager instance.
const int cSS_CONVENTION_SLAVE
Standard state thermodynamics is obtained from slave ThermoPhase objects.
Definition: ThermoPhase.h:40
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
ThermoPhase * newPhase(const std::string &infile, std::string id)
Create and Initialize a ThermoPhase object from an input file.
Contains const definitions for types of species reference-state thermodynamics managers (see Species ...
Contains declarations for string manipulation functions within Cantera.