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