Cantera  2.5.1
KineticsFactory.cpp
Go to the documentation of this file.
1 /**
2  * @file KineticsFactory.cpp
3  */
4 
5 // This file is part of Cantera. See License.txt in the top-level directory or
6 // at https://cantera.org/license.txt for license and copyright information.
7 
13 #include "cantera/base/xml.h"
14 
15 using namespace std;
16 
17 namespace Cantera
18 {
19 
20 KineticsFactory* KineticsFactory::s_factory = 0;
21 std::mutex KineticsFactory::kinetics_mutex;
22 
24  vector<ThermoPhase*> th)
25 {
26  // Look for a child of the XML element phase called "kinetics". It has an
27  // attribute name "model". Store the value of that attribute in the variable
28  // kintype
29  string kintype = phaseData.child("kinetics")["model"];
30 
31  // Create a kinetics object of the desired type
32  Kinetics* k = newKinetics(kintype);
33  // Now that we have the kinetics manager, we can import the reaction
34  // mechanism into it.
35  importKinetics(phaseData, th, k);
36 
37  // Return the pointer to the kinetics manager
38  return k;
39 }
40 
41 KineticsFactory::KineticsFactory() {
42  reg("none", []() { return new Kinetics(); });
43  reg("gas", []() { return new GasKinetics(); });
44  addAlias("gas", "gaskinetics");
45  reg("surface", []() { return new InterfaceKinetics(); });
46  addAlias("surface", "interface");
47  reg("edge", []() { return new EdgeKinetics(); });
48 }
49 
51 {
52  return create(toLowerCopy(model));
53 }
54 
55 unique_ptr<Kinetics> newKinetics(vector<ThermoPhase*>& phases,
56  const AnyMap& phaseNode,
57  const AnyMap& rootNode)
58 {
59  unique_ptr<Kinetics> kin(KineticsFactory::factory()->newKinetics(
60  phaseNode.getString("kinetics", "none")));
61  for (auto& phase : phases) {
62  kin->addPhase(*phase);
63  }
64  kin->init();
65  addReactions(*kin, phaseNode, rootNode);
66  return kin;
67 }
68 
69 unique_ptr<Kinetics> newKinetics(std::vector<ThermoPhase*>& phases,
70  const std::string& filename,
71  const std::string& phase_name)
72 {
73  size_t dot = filename.find_last_of(".");
74  string extension;
75  if (dot != npos) {
76  extension = toLowerCopy(filename.substr(dot+1));
77  }
78 
79  if (extension == "yml" || extension == "yaml") {
80  AnyMap root = AnyMap::fromYamlFile(filename);
81  AnyMap& phaseNode = root["phases"].getMapWhere("name", phase_name);
82  return newKinetics(phases, phaseNode, root);
83  } else {
84  XML_Node* root = get_XML_File(filename);
85  XML_Node* xphase = get_XML_NameID("phase", "#"+phase_name, root);
86  if (!xphase) {
87  throw CanteraError("newKinetics",
88  "Couldn't find phase named '{}' in file '{}'.",
89  phase_name, filename);
90  }
91  return unique_ptr<Kinetics>(newKineticsMgr(*xphase, phases));
92  }
93 }
94 
95 void addReactions(Kinetics& kin, const AnyMap& phaseNode, const AnyMap& rootNode)
96 {
98  phaseNode.getBool("skip-undeclared-third-bodies", false));
99 
100  // Find sections containing reactions to add
101  vector<string> sections, rules;
102 
103  if (phaseNode.hasKey("reactions")) {
104  if (kin.kineticsType() == "Kinetics") {
105  throw InputFileError("addReactions", phaseNode["reactions"],
106  "Phase entry includes a 'reactions' field but does not "
107  "specify a kinetics model.");
108  }
109  const auto& reactionsNode = phaseNode.at("reactions");
110  if (reactionsNode.is<string>()) {
111  if (rootNode.hasKey("reactions")) {
112  // Specification of the rule for adding species from the default
113  // 'reactions' section, if it exists
114  sections.push_back("reactions");
115  rules.push_back(reactionsNode.asString());
116  } else if (reactionsNode.asString() != "none") {
117  throw InputFileError("addReactions", reactionsNode,
118  "Phase entry implies existence of 'reactions' section "
119  "which does not exist in the current input file.");
120  }
121  } else if (reactionsNode.is<vector<string>>()) {
122  // List of sections from which all species should be added
123  for (const auto& item : reactionsNode.as<vector<string>>()) {
124  sections.push_back(item);
125  rules.push_back("all");
126  }
127  } else if (reactionsNode.is<vector<AnyMap>>()) {
128  // Mapping of rules to apply for each specified section containing
129  // reactions
130  for (const auto& item : reactionsNode.as<vector<AnyMap>>()) {
131  sections.push_back(item.begin()->first);
132  rules.push_back(item.begin()->second.asString());
133  }
134  }
135  } else if (kin.kineticsType() != "Kinetics") {
136  if (rootNode.hasKey("reactions")) {
137  // Default behavior is to add all reactions from the 'reactions'
138  // section, if a 'kinetics' model has been specified
139  sections.push_back("reactions");
140  rules.push_back("all");
141  } else {
142  throw InputFileError("addReactions", phaseNode,
143  "Phase entry implies existence of 'reactions' section which "
144  "does not exist in the current input file. Add the field "
145  "'reactions: none' to the phase entry to specify a kinetics "
146  "model with no reactions.");
147  }
148  }
149 
150  // Add reactions from each section
151  fmt::memory_buffer add_rxn_err;
152  for (size_t i = 0; i < sections.size(); i++) {
153  if (rules[i] == "all") {
154  kin.skipUndeclaredSpecies(false);
155  } else if (rules[i] == "declared-species") {
156  kin.skipUndeclaredSpecies(true);
157  } else if (rules[i] == "none") {
158  continue;
159  } else {
160  throw InputFileError("addReactions", phaseNode.at("reactions"),
161  "Unknown rule '{}' for adding species from the '{}' section.",
162  rules[i], sections[i]);
163  }
164  const auto& slash = boost::ifind_last(sections[i], "/");
165  if (slash) {
166  // specified section is in a different file
167  string fileName (sections[i].begin(), slash.begin());
168  string node(slash.end(), sections[i].end());
169  AnyMap reactions = AnyMap::fromYamlFile(fileName,
170  rootNode.getString("__file__", ""));
171  for (const auto& R : reactions[node].asVector<AnyMap>()) {
172  try {
173  kin.addReaction(newReaction(R, kin));
174  } catch (CanteraError& err) {
175  format_to(add_rxn_err, "{}", err.what());
176  }
177  }
178  } else {
179  // specified section is in the current file
180  for (const auto& R : rootNode.at(sections[i]).asVector<AnyMap>()) {
181  try {
182  kin.addReaction(newReaction(R, kin));
183  } catch (CanteraError& err) {
184  format_to(add_rxn_err, "{}", err.what());
185  }
186  }
187  }
188  }
189 
190  kin.checkDuplicates();
191  if (add_rxn_err.size()) {
192  throw CanteraError("addReactions", to_string(add_rxn_err));
193  }
194 }
195 
196 }
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
const std::vector< T > & asVector(size_t nMin=npos, size_t nMax=npos) const
Return the held value, if it is a vector of type T.
Definition: AnyMap.inl.h:73
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
const char * what() const
Get a description of the error.
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:539
Public interface for kinetics managers.
Definition: Kinetics.h:111
virtual bool addReaction(shared_ptr< Reaction > r)
Add a single reaction to the mechanism.
Definition: Kinetics.cpp:476
void skipUndeclaredSpecies(bool skip)
Determine behavior when adding a new reaction that contains species not defined in any of the phases ...
Definition: Kinetics.h:740
void skipUndeclaredThirdBodies(bool skip)
Determine behavior when adding a new reaction that contains third-body efficiencies for species not d...
Definition: Kinetics.h:752
virtual std::string kineticsType() const
Identifies the Kinetics manager type.
Definition: Kinetics.h:130
virtual std::pair< size_t, size_t > checkDuplicates(bool throw_err=true) const
Check for unmarked duplicate reactions and unmatched marked duplicates.
Definition: Kinetics.cpp:78
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:104
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
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_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
bool importKinetics(const XML_Node &phase, std::vector< ThermoPhase * > th, Kinetics *k)
Import a reaction mechanism for a phase or an interface.
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:188
Definitions of global routines for the importing of data from XML files (see Input File Handling).
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:264
doublereal dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition: utilities.h:112
shared_ptr< Reaction > newReaction(const XML_Node &rxn_node)
Create a new Reaction object for the reaction defined in rxn_node
Definition: Reaction.cpp:1010
std::string toLowerCopy(const std::string &input)
Convert to lower case.
Kinetics * newKineticsMgr(XML_Node &phase, std::vector< ThermoPhase * > th)
Create a new kinetics manager.
unique_ptr< Kinetics > newKinetics(std::vector< ThermoPhase * > &phases, const std::string &filename, const std::string &phase_name)
void addReactions(Kinetics &kin, const AnyMap &phaseNode, const AnyMap &rootNode)
Classes providing support for XML data files.