47 ThermoFactory* ThermoFactory::s_factory = 0;
48 std::mutex ThermoFactory::thermo_mutex;
50 ThermoFactory::ThermoFactory()
53 addAlias(
"ideal-gas",
"IdealGas");
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");
63 addAlias(
"fixed-stoichiometry",
"StoichSubstance");
65 addAlias(
"pure-fluid",
"PureFluid");
67 addAlias(
"compound-lattice",
"LatticeSolid");
69 addAlias(
"lattice",
"Lattice");
70 reg(
"HMW-electrolyte", []() {
return new HMWSoln(); });
71 addAlias(
"HMW-electrolyte",
"HMW");
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");
80 addAlias(
"ideal-solution-VPSS",
"IdealSolnVPSS");
81 addAlias(
"ideal-gas-VPSS",
"IdealGasVPSS");
84 addAlias(
"ions-from-neutral-molecule",
"IonsFromNeutralMolecule");
86 addAlias(
"fixed-chemical-potential",
"FixedChemPot");
89 addAlias(
"Redlich-Kwong",
"RedlichKwongMFTP");
90 addAlias(
"Redlich-Kwong",
"RedlichKwong");
92 addAlias(
"Maskell-solid-solution",
"MaskellSolidSolnPhase");
93 reg(
"liquid-water-IAPWS95", []() {
return new WaterSSTP(); });
94 addAlias(
"liquid-water-IAPWS95",
"PureLiquidWater");
96 addAlias(
"binary-solution-tabulated",
"BinarySolutionTabulatedThermo");
101 return create(model);
106 string model = xmlphase.
child(
"thermo")[
"model"];
114 unique_ptr<ThermoPhase> t(
newThermoPhase(phaseNode[
"thermo"].asString()));
121 size_t dot = infile.find_last_of(
".");
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()));
141 "Couldn't find phase named \"" +
id +
"\" in file, " + infile);
163 std::vector<std::string> &spNamesList,
165 const std::vector<XML_Node*> spArray_names,
166 const std::vector<XML_Node*> spArray_dbases,
170 std::map<std::string, bool> declared;
172 for (
size_t jsp = 0; jsp < spArray_dbases.size(); jsp++) {
173 const XML_Node& speciesArray = *spArray_names[jsp];
176 const XML_Node* db = spArray_dbases[jsp];
179 std::vector<std::string> spnames;
181 size_t nsp = spnames.size();
186 if (nsp == 1 && spnames[0] ==
"all") {
187 std::vector<XML_Node*> allsp = db->
getChildren(
"species");
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]);
199 }
else if (nsp == 1 && spnames[0] ==
"unique") {
200 std::vector<XML_Node*> allsp = db->
getChildren(
"species");
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]);
213 std::map<std::string, XML_Node*> speciesNodes;
214 for (
size_t k = 0; k < db->
nChildren(); k++) {
216 speciesNodes[child[
"name"]] = &child;
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;
223 auto iter = speciesNodes.find(stemp);
224 if (iter == speciesNodes.end()) {
226 "no data for species, \"{}\"", stemp);
228 spNamesList.push_back(stemp);
229 spDataNodeList.push_back(iter->second);
230 spRuleList.push_back(sprule[jsp]);
240 if (phase.
name() !=
"phase") {
242 "Current const XML_Node named, " + phase.
name() +
243 ", is not a phase element.");
258 if (idim < 1 || idim > 3) {
260 "phase, " + th->
name() +
261 ", has unphysical number of dimensions: " + phase[
"dim"]);
276 " phase, " + th->
name() +
277 ", XML_Node does not have a \"thermo\" XML_Node");
286 "phase, " + th->
name() +
", was VPSS, but dynamic cast failed");
299 vector<XML_Node*> sparrays = phase.
getChildren(
"speciesArray");
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");
306 vector<XML_Node*> dbases;
314 for (
size_t jsp = 0; jsp < sparrays.size(); jsp++) {
315 const XML_Node& speciesArray = *sparrays[jsp];
329 if (speciesArray.
hasChild(
"skip")) {
331 string eskip = sk[
"element"];
332 if (eskip ==
"undeclared") {
335 string dskip = sk[
"species"];
336 if (dskip ==
"duplicate") {
347 "Can not find XML node for species database: {}",
348 speciesArray[
"datasrc"]);
352 dbases.push_back(db);
359 std::vector<XML_Node*> spDataNodeList;
360 std::vector<std::string> spNamesList;
363 sparrays, dbases, sprule);
365 size_t nsp = spDataNodeList.size();
367 throw CanteraError(
"importPhase",
"For Slave standard states, "
368 "number of species must be zero: {}", nsp);
370 for (
size_t k = 0; k < nsp; k++) {
379 std::string ss_model = (ss) ? ss->
attrib(
"model") :
"ideal-gas";
380 unique_ptr<PDSS> kPDSS(newPDSS(ss_model));
381 kPDSS->setParametersFromXML(*s);
397 void addDefaultElements(ThermoPhase& thermo,
const vector<string>& element_names) {
398 for (
const auto& symbol : element_names) {
399 thermo.addElement(symbol);
403 void addElements(ThermoPhase& thermo,
const vector<string>& element_names,
404 const AnyValue& elements,
bool allow_default)
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);
413 thermo.addElement(symbol, weight, number, e298);
414 }
else if (allow_default) {
415 thermo.addElement(symbol);
417 throw InputFileError(
"addElements", elements,
418 "Element '{}' not found", symbol);
423 void addSpecies(ThermoPhase& thermo,
const AnyValue& names,
const AnyValue& species)
425 if (names.is<vector<string>>()) {
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)));
432 throw InputFileError(
"addSpecies", names, species,
433 "Could not find a species named '{}'.", name);
436 }
else if (names ==
"all") {
438 for (
const auto& item : species.asVector<AnyMap>()) {
442 throw InputFileError(
"addSpecies", names,
443 "Could not parse species declaration of type '{}'", names.type_str());
449 thermo.
setName(phaseNode[
"name"].asString());
450 if (rootNode.
hasKey(
"__file__")) {
451 phaseNode[
"__file__"] = rootNode[
"__file__"];
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());
462 if (phaseNode.
hasKey(
"elements")) {
463 if (phaseNode.
getBool(
"skip-undeclared-elements",
false)) {
469 if (phaseNode[
"elements"].is<vector<string>>()) {
471 if (rootNode.
hasKey(
"elements")) {
472 addElements(thermo, phaseNode[
"elements"].asVector<string>(),
473 rootNode[
"elements"],
true);
475 addDefaultElements(thermo, phaseNode[
"elements"].asVector<string>());
477 }
else if (phaseNode[
"elements"].is<vector<AnyMap>>()) {
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,
"/");
486 std::string fileName(source.begin(), slash.begin());
487 std::string node(slash.end(), source.end());
488 const AnyMap elements = AnyMap::fromYamlFile(fileName,
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);
497 "Could not find elements section named '{}'", source);
502 "Could not parse elements declaration of type '{}'",
503 phaseNode[
"elements"].type_str());
512 if (phaseNode.
hasKey(
"species")) {
513 if (phaseNode[
"species"].is<vector<string>>()) {
516 addSpecies(thermo, phaseNode[
"species"], rootNode[
"species"]);
517 }
else if (phaseNode[
"species"].is<string>()) {
520 addSpecies(thermo, phaseNode[
"species"], rootNode[
"species"]);
521 }
else if (phaseNode[
"species"].is<vector<AnyMap>>()) {
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,
"/");
531 std::string fileName(source.begin(), slash.begin());
532 std::string node(slash.end(), source.end());
533 AnyMap species = AnyMap::fromYamlFile(fileName,
535 addSpecies(thermo, names, species[node]);
536 }
else if (rootNode.
hasKey(source)) {
538 addSpecies(thermo, names, rootNode[source]);
541 "Could not find species section named '{}'", source);
546 "Could not parse species declaration of type '{}'",
547 phaseNode[
"species"].type_str());
549 }
else if (rootNode.
hasKey(
"species")) {
551 addSpecies(thermo,
AnyValue(
"all"), rootNode[
"species"]);
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")) {
560 auto& eos = thermo.
species(k)->input[
"equation-of-state"];
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);
573 "Could not find an equation-of-state specification "
574 "which defines a known PDSS model.");
577 pdss.reset(newPDSS(
"ideal-gas"));
579 vpssThermo->installPDSS(k, std::move(pdss));
586 if (phaseNode.
hasKey(
"state")) {
587 auto node = phaseNode[
"state"].as<
AnyMap>();
597 if (!phaseNode.
hasChild(
"elementArray")) {
599 "phase XML node doesn't have \"elementArray\" XML Node");
602 vector<string> enames;
606 string element_database =
"elements.xml";
608 element_database = elements[
"datasrc"];
617 local_db = &root.
child(
"elementData");
620 for (
size_t i = 0; i < enames.size(); i++) {
630 throw CanteraError(
"installElements",
"no data for element '{}'",
635 doublereal weight = 0.0;
643 string symbol = e->
attrib(
"name");
651 th.
addElement(symbol, weight, anum, entropy298);
658 if (!phaseSpeciesData) {
661 string jname = phaseSpeciesData->
name();
662 if (jname !=
"speciesData") {
664 "Unexpected phaseSpeciesData name: " + jname);
666 vector<XML_Node*> xspecies = phaseSpeciesData->
getChildren(
"species");
667 for (
size_t j = 0; j < xspecies.size(); j++) {
670 if (jname == kname) {
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....
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...
A map of string keys to values whose type can vary at runtime.
const AnyValue & at(const std::string &key) const
Get the value of the item stored in key.
const std::string & getString(const std::string &key, const std::string &default_) const
If key exists, return it as a string, otherwise return default_.
bool getBool(const std::string &key, bool default_) const
If key exists, return it as a bool, otherwise return default_.
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
A wrapper for a variable whose type is determined at runtime.
Overloads the virtual methods of class IdealSolidSolnPhase to implement tabulated standard state ther...
Base class for exceptions thrown by Cantera classes.
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...
A thermodynamic phase representing a one dimensional edge between two surfaces.
Class FixedChemPotSSTP represents a stoichiometric (fixed composition) incompressible substance.
Class HMWSoln represents a dilute or concentrated liquid electrolyte phase which obeys the Pitzer for...
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.
A simple thermodynamic model for a bulk phase, assuming a lattice of solid atoms.
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 Phase is the base class for phases of matter, managing the species and elements in a phase,...
void setName(const std::string &nm)
Sets the string name for the phase.
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.
std::string name() const
Return the name of the phase.
size_t nSpecies() const
Returns the number of species in the phase.
void ignoreUndefinedElements()
Set behavior when adding a species containing undefined elements to just skip the species.
void addUndefinedElements()
Set behavior when adding a species containing undefined elements to add those elements to the phase.
void setNDim(size_t ndim)
Set the number of spatial dimensions (1, 2, or 3).
void setXMLdata(XML_Node &xmlPhase)
Stores the XML tree information for the current phase.
void throwUndefinedElements()
Set the behavior when adding a species containing undefined elements to throw an exception.
shared_ptr< Species > species(const std::string &name) const
Return the Species object for the named species.
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.
Base class for a phase with thermodynamic properties.
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...
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.
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 XML_Node is a tree-based representation of the contents of an XML file.
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.
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
std::string name() const
Returns the name of the XML node.
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
std::string id() const
Return the id attribute, if present.
XML_Node & root() const
Return the root of the current XML_Node tree.
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.
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...
size_t nChildren(bool discardComments=false) const
Return the number of children.
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
#define AssertTrace(expr)
Assertion must be true or an error is thrown.
const size_t npos
index returned by functions to indicate "no position"
const double OneAtm
One atmosphere [Pa].
std::vector< int > vector_int
Vector of ints.
void importPhase(XML_Node &phase, ThermoPhase *th)
Import a phase information into an empty ThermoPhase object.
Namespace for the Cantera kernel.
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.
doublereal dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
const int cSS_CONVENTION_VPSS
Standard state uses the molality convention.
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.
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.
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.