Cantera  3.3.0a1
Loading...
Searching...
No Matches
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
38
39#include <boost/algorithm/string.hpp>
40
41namespace Cantera
42{
43
44ThermoFactory* ThermoFactory::s_factory = 0;
46
48{
49 reg("none", []() { return new ThermoPhase(); });
50 addDeprecatedAlias("none", "ThermoPhase");
51 addDeprecatedAlias("none", "None");
52 reg("ideal-gas", []() { return new IdealGasPhase(); });
53 addDeprecatedAlias("ideal-gas", "IdealGas");
54 reg("plasma", []() { return new PlasmaPhase(); });
55 reg("ideal-surface", []() { return new SurfPhase(); });
56 addDeprecatedAlias("ideal-surface", "Surface");
57 addDeprecatedAlias("ideal-surface", "Surf");
58 reg("coverage-dependent-surface", []() { return new CoverageDependentSurfPhase(); });
59 reg("edge", []() { return new EdgePhase(); });
60 addDeprecatedAlias("edge", "Edge");
61 reg("electron-cloud", []() { return new MetalPhase(); });
62 addDeprecatedAlias("electron-cloud", "Metal");
63 reg("fixed-stoichiometry", []() { return new StoichSubstance(); });
64 addDeprecatedAlias("fixed-stoichiometry", "StoichSubstance");
65 reg("pure-fluid", []() { return new PureFluidPhase(); });
66 addDeprecatedAlias("pure-fluid", "PureFluid");
67 reg("HMW-electrolyte", []() { return new HMWSoln(); });
68 addDeprecatedAlias("HMW-electrolyte", "HMW");
69 addDeprecatedAlias("HMW-electrolyte", "HMWSoln");
70 reg("ideal-condensed", []() { return new IdealSolidSolnPhase(); });
71 addDeprecatedAlias("ideal-condensed", "IdealSolidSolution");
72 addDeprecatedAlias("ideal-condensed", "IdealSolidSoln");
73 reg("Debye-Huckel", []() { return new DebyeHuckel(); });
74 addDeprecatedAlias("Debye-Huckel", "DebyeHuckel");
75 reg("ideal-molal-solution", []() { return new IdealMolalSoln(); });
76 addDeprecatedAlias("ideal-molal-solution", "IdealMolalSolution");
77 addDeprecatedAlias("ideal-molal-solution", "IdealMolalSoln");
78 reg("ideal-solution-VPSS", []() { return new IdealSolnGasVPSS(); });
79 reg("ideal-gas-VPSS", []() { return new IdealSolnGasVPSS(); });
80 addDeprecatedAlias("ideal-solution-VPSS", "IdealSolnVPSS");
81 addDeprecatedAlias("ideal-solution-VPSS", "IdealSolnGas");
82 addDeprecatedAlias("ideal-gas-VPSS", "IdealGasVPSS");
83 reg("Margules", []() { return new MargulesVPSSTP(); });
84 reg("Redlich-Kister", []() { return new RedlichKisterVPSSTP(); });
85 addDeprecatedAlias("Redlich-Kister", "RedlichKister");
86 reg("Redlich-Kwong", []() { return new RedlichKwongMFTP(); });
87 addDeprecatedAlias("Redlich-Kwong", "RedlichKwongMFTP");
88 addDeprecatedAlias("Redlich-Kwong", "RedlichKwong");
89 reg("liquid-water-IAPWS95", []() { return new WaterSSTP(); });
90 addDeprecatedAlias("liquid-water-IAPWS95", "PureLiquidWater");
91 addDeprecatedAlias("liquid-water-IAPWS95", "Water");
92 reg("binary-solution-tabulated", []() { return new BinarySolutionTabulatedThermo(); });
93 addDeprecatedAlias("binary-solution-tabulated", "BinarySolutionTabulatedThermo");
94 reg("Peng-Robinson", []() { return new PengRobinson(); });
95}
96
98{
99 std::unique_lock<std::mutex> lock(thermo_mutex);
100 if (!s_factory) {
102 }
103 return s_factory;
104}
105
107{
108 std::unique_lock<std::mutex> lock(thermo_mutex);
109 delete s_factory;
110 s_factory = 0;
111}
112
113shared_ptr<ThermoPhase> newThermoModel(const string& model)
114{
115 shared_ptr<ThermoPhase> tptr(ThermoFactory::factory()->create(model));
116 return tptr;
117}
118
119shared_ptr<ThermoPhase> newThermo(const AnyMap& phaseNode, const AnyMap& rootNode)
120{
121 if (!phaseNode.hasKey("kinetics") && phaseNode.hasKey("reactions")) {
122 throw InputFileError("newThermo", phaseNode["reactions"],
123 "Phase entry includes a 'reactions' field but does not "
124 "specify a kinetics model.");
125 }
126 string model = phaseNode["thermo"].asString();
127 shared_ptr<ThermoPhase> t = newThermoModel(model);
128 setupPhase(*t, phaseNode, rootNode);
129 return t;
130}
131
132shared_ptr<ThermoPhase> newThermo(const string& infile, const string& id)
133{
134 size_t dot = infile.find_last_of(".");
135 string extension;
136 extension = toLowerCopy(infile.substr(dot+1));
137 string id_ = id;
138 if (id == "-") {
139 id_ = "";
140 }
141 if (extension == "cti" || extension == "xml") {
142 throw CanteraError("newThermo",
143 "The CTI and XML formats are no longer supported.");
144 }
145
146 AnyMap root = AnyMap::fromYamlFile(infile);
147 AnyMap& phase = root["phases"].getMapWhere("name", id_);
148 return newThermo(phase, root);
149}
150
151void addDefaultElements(ThermoPhase& thermo, const vector<string>& element_names) {
152 for (const auto& symbol : element_names) {
153 thermo.addElement(symbol);
154 }
155}
156
157void addElements(ThermoPhase& thermo, const vector<string>& element_names,
158 const AnyValue& elements, bool allow_default)
159{
160 const auto& local_elements = elements.asMap("symbol");
161 for (const auto& symbol : element_names) {
162 if (local_elements.count(symbol)) {
163 auto& element = *local_elements.at(symbol);
164 double weight = element["atomic-weight"].asDouble();
165 long int number = element.getInt("atomic-number", 0);
166 double e298 = element.getDouble("entropy298", ENTROPY298_UNKNOWN);
167 thermo.addElement(symbol, weight, number, e298);
168 } else if (allow_default) {
169 thermo.addElement(symbol);
170 } else {
171 throw InputFileError("addElements", elements,
172 "Element '{}' not found", symbol);
173 }
174 }
175}
176
177void addSpecies(ThermoPhase& thermo, const AnyValue& names, const AnyValue& species)
178{
179 if (names.is<vector<string>>()) {
180 // 'names' is a list of species names which should be found in 'species'
181 const auto& species_nodes = species.asMap("name");
182 for (const auto& name : names.asVector<string>()) {
183 if (species_nodes.count(name)) {
184 thermo.addSpecies(newSpecies(*species_nodes.at(name)));
185 } else {
186 throw InputFileError("addSpecies", names, species,
187 "Could not find a species named '{}'.", name);
188 }
189 }
190 } else if (names == "all") {
191 // The keyword 'all' means to add all species from this source
192 for (const auto& item : species.asVector<AnyMap>()) {
193 thermo.addSpecies(newSpecies(item));
194 }
195 } else {
196 throw InputFileError("addSpecies", names,
197 "Could not parse species declaration of type '{}'", names.type_str());
198 }
199}
200
201void setupPhase(ThermoPhase& thermo, const AnyMap& phaseNode, const AnyMap& rootNode)
202{
203 thermo.setName(phaseNode["name"].asString());
204
205 if (phaseNode.hasKey("deprecated")) {
206 string msg = phaseNode["deprecated"].asString();
207 string filename = phaseNode.getString("__file__",
208 rootNode.getString("__file__", "unknown file"));
209 string method = fmt::format("{}/{}", filename, phaseNode["name"].asString());
210 warn_deprecated(method, phaseNode, msg);
211 }
212
213 // Add elements
214 if (phaseNode.hasKey("elements")) {
215 if (phaseNode.getBool("skip-undeclared-elements", false)) {
217 } else {
218 thermo.throwUndefinedElements();
219 }
220
221 if (phaseNode["elements"].is<vector<string>>()) {
222 // 'elements' is a list of element symbols
223 if (rootNode.hasKey("elements")) {
224 addElements(thermo, phaseNode["elements"].asVector<string>(),
225 rootNode["elements"], true);
226 } else {
227 addDefaultElements(thermo, phaseNode["elements"].asVector<string>());
228 }
229 } else if (phaseNode["elements"].is<vector<AnyMap>>()) {
230 // Each item in 'elements' is a map with one item, where the key is
231 // a section in this file or another YAML file, and the value is a
232 // list of element symbols to read from that section
233 for (const auto& elemNode : phaseNode["elements"].asVector<AnyMap>()) {
234 const string& source = elemNode.begin()->first;
235 const auto& names = elemNode.begin()->second.asVector<string>();
236 const auto& slash = boost::ifind_last(source, "/");
237 if (slash) {
238 string fileName(source.begin(), slash.begin());
239 string node(slash.end(), source.end());
240 const AnyMap elements = AnyMap::fromYamlFile(fileName,
241 rootNode.getString("__file__", ""));
242 addElements(thermo, names, elements.at(node), false);
243 } else if (rootNode.hasKey(source)) {
244 addElements(thermo, names, rootNode.at(source), false);
245 } else if (source == "default") {
246 addDefaultElements(thermo, names);
247 } else {
248 throw InputFileError("setupPhase", elemNode,
249 "Could not find elements section named '{}'", source);
250 }
251 }
252 } else {
253 throw InputFileError("setupPhase", phaseNode["elements"],
254 "Could not parse elements declaration of type '{}'",
255 phaseNode["elements"].type_str());
256 }
257 } else {
258 // If no elements list is provided, just add elements as-needed from the
259 // default list.
260 thermo.addUndefinedElements();
261 }
262
263 // Add species
264 if (phaseNode.hasKey("species")) {
265 if (phaseNode["species"].is<vector<string>>()) {
266 // 'species' is a list of species names to be added from the current
267 // file's 'species' section
268 addSpecies(thermo, phaseNode["species"], rootNode["species"]);
269 } else if (phaseNode["species"].is<string>()) {
270 // 'species' is a keyword applicable to the current file's 'species'
271 // section
272 addSpecies(thermo, phaseNode["species"], rootNode["species"]);
273 } else if (phaseNode["species"].is<vector<AnyMap>>()) {
274 // Each item in 'species' is a map with one item, where the key is
275 // a section in this file or another YAML file, and the value is a
276 // list of species names to read from that section
277 for (const auto& speciesNode : phaseNode["species"].asVector<AnyMap>()) {
278 const string& source = speciesNode.begin()->first;
279 const auto& names = speciesNode.begin()->second;
280 const auto& slash = boost::ifind_last(source, "/");
281 if (slash) {
282 // source is a different input file
283 string fileName(source.begin(), slash.begin());
284 string node(slash.end(), source.end());
285 AnyMap species = AnyMap::fromYamlFile(fileName,
286 rootNode.getString("__file__", ""));
287 addSpecies(thermo, names, species[node]);
288 } else if (rootNode.hasKey(source)) {
289 // source is in the current file
290 addSpecies(thermo, names, rootNode[source]);
291 } else {
292 throw InputFileError("setupPhase", speciesNode,
293 "Could not find species section named '{}'", source);
294 }
295 }
296 } else {
297 throw InputFileError("setupPhase", phaseNode["species"],
298 "Could not parse species declaration of type '{}'",
299 phaseNode["species"].type_str());
300 }
301 } else if (rootNode.hasKey("species")) {
302 // By default, add all species from the 'species' section
303 addSpecies(thermo, AnyValue("all"), rootNode["species"]);
304 }
305
306 auto* vpssThermo = dynamic_cast<VPStandardStateTP*>(&thermo);
307 if (vpssThermo) {
308 for (size_t k = 0; k < thermo.nSpecies(); k++) {
309 unique_ptr<PDSS> pdss;
310 if (!thermo.species(k)->input.hasKey("equation-of-state")) {
311 throw InputFileError("setupPhase", thermo.species(k)->input,
312 "Species '{}' in use by a ThermoPhase model of type '{}'\n"
313 "must define an 'equation-of-state' field.",
314 thermo.speciesName(k), thermo.type());
315 }
316 // Use the first node which specifies a valid PDSS model
317 auto& eos = thermo.species(k)->input["equation-of-state"];
318 bool found = false;
319 for (auto& node : eos.asVector<AnyMap>()) {
320 string model = node["model"].asString();
321 if (PDSSFactory::factory()->exists(model)) {
322 pdss.reset(newPDSS(model));
323 pdss->setParameters(node);
324 found = true;
325 break;
326 }
327 }
328 if (!found) {
329 throw InputFileError("setupPhase", eos,
330 "Could not find an equation-of-state specification "
331 "which defines a known PDSS model.");
332 }
333 vpssThermo->installPDSS(k, std::move(pdss));
334 }
335 }
336
337 thermo.setParameters(phaseNode, rootNode);
338 thermo.initThermo();
339
340 if (phaseNode.hasKey("state")) {
341 auto node = phaseNode["state"].as<AnyMap>();
342 thermo.setState(node);
343 } else {
344 thermo.setState_TP(298.15, OneAtm);
345 }
346}
347
348}
Header file for an binary solution model with tabulated standard state thermodynamic data (see Thermo...
Header for a thermodynamics model of a coverage-dependent surface phase derived from SurfPhase,...
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:85
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...
(see Thermodynamic Properties and class MargulesVPSSTP).
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:431
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1477
bool getBool(const string &key, bool default_) const
If key exists, return it as a bool, otherwise return default_.
Definition AnyMap.cpp:1575
const string & getString(const string &key, const string &default_) const
If key exists, return it as a string, otherwise return default_.
Definition AnyMap.cpp:1590
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
Definition AnyMap.cpp:1841
const AnyValue & at(const string &key) const
Get the value of the item stored in key.
Definition AnyMap.cpp:1458
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:88
Overloads the virtual methods of class IdealSolidSolnPhase to implement tabulated standard state ther...
Base class for exceptions thrown by Cantera classes.
A thermodynamic model for a coverage-dependent surface phase, applying surface species lateral intera...
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.
Definition EdgePhase.h:31
void reg(const string &name, function< ThermoPhase *(Args...)> f)
Register a new object construction function.
Definition FactoryBase.h:80
bool exists(const string &name) const
Returns true if name is registered with this factory.
void addDeprecatedAlias(const string &original, const string &alias)
Add a deprecated alias for an existing registered type.
Class HMWSoln represents a dilute or concentrated liquid electrolyte phase which obeys the Pitzer for...
Definition HMWSoln.h:778
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:749
MargulesVPSSTP is a derived class of GibbsExcessVPSSTP that employs the Margules approximation for th...
Class MetalPhase represents electrons in a metal.
Definition MetalPhase.h:22
static PDSSFactory * factory()
Static function that creates a static instance of the factory.
Implementation of a multi-species Peng-Robinson equation of state.
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:245
void ignoreUndefinedElements()
Set behavior when adding a species containing undefined elements to just skip the species.
Definition Phase.cpp:909
void addUndefinedElements()
Set behavior when adding a species containing undefined elements to add those elements to the phase.
Definition Phase.cpp:913
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:143
shared_ptr< Species > species(const string &name) const
Return the Species object for the named species.
Definition Phase.cpp:897
void throwUndefinedElements()
Set the behavior when adding a species containing undefined elements to throw an exception.
Definition Phase.cpp:917
void setName(const string &nm)
Sets the string name for the phase.
Definition Phase.cpp:25
Base class for handling plasma properties, specifically focusing on the electron energy distribution.
Definition PlasmaPhase.h:84
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:114
Factory class for thermodynamic property managers.
void deleteFactory() override
delete the static instance of this factory
ThermoFactory()
Private constructors prevents usage.
static ThermoFactory * factory()
Static function that creates a static instance of the factory.
static std::mutex thermo_mutex
Decl for locking mutex for thermo factory singleton.
static ThermoFactory * s_factory
static member of a single instance
Base class for a phase with thermodynamic properties.
virtual void setParameters(const AnyMap &phaseNode, const AnyMap &rootNode=AnyMap())
Set equation of state parameters from an AnyMap phase description.
virtual void setState_TP(double t, double 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...
string type() const override
String indicating the thermodynamic model implemented.
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
This is a filter class for ThermoPhase that implements some preparatory steps for efficiently handlin...
Class for single-component water.
Definition WaterSSTP.h:69
string toLowerCopy(const string &input)
Convert to lower case.
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition utilities.h:82
const double OneAtm
One atmosphere [Pa].
Definition ct_defs.h:96
shared_ptr< ThermoPhase > newThermo(const AnyMap &phaseNode, const AnyMap &rootNode)
Create a new ThermoPhase object and initialize it.
void setupPhase(ThermoPhase &thermo, const AnyMap &phaseNode, const AnyMap &rootNode)
Initialize a ThermoPhase object.
shared_ptr< ThermoPhase > newThermoModel(const string &model)
Create a new ThermoPhase instance.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
unique_ptr< Species > newSpecies(const AnyMap &node)
Create a new Species object from an AnyMap specification.
Definition Species.cpp:113
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1997
Contains const definitions for types of species reference-state thermodynamics managers (see Species ...
Contains declarations for string manipulation functions within Cantera.