Cantera  3.1.0a1
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 
15 #include "cantera/base/Solution.h"
16 #include <boost/algorithm/string.hpp>
17 
18 namespace Cantera
19 {
20 
21 KineticsFactory* KineticsFactory::s_factory = 0;
22 std::mutex KineticsFactory::kinetics_mutex;
23 
24 KineticsFactory::KineticsFactory() {
25  reg("none", []() { return new Kinetics(); });
26  addDeprecatedAlias("none", "Kinetics");
27  addDeprecatedAlias("none", "None");
28  reg("bulk", []() { return new BulkKinetics(); });
29  addAlias("bulk", "gas");
30  addDeprecatedAlias("bulk", "gaskinetics");
31  addDeprecatedAlias("bulk", "Gas");
32  reg("surface", []() { return new InterfaceKinetics(); });
33  addAlias("surface", "interface");
34  addDeprecatedAlias("surface", "Surf");
35  addDeprecatedAlias("surface", "surf");
36  reg("edge", []() { return new EdgeKinetics(); });
37  addDeprecatedAlias("edge", "Edge");
38 }
39 
40 KineticsFactory* KineticsFactory::factory() {
41  std::unique_lock<std::mutex> lock(kinetics_mutex);
42  if (!s_factory) {
43  s_factory = new KineticsFactory;
44  }
45  return s_factory;
46 }
47 
49  std::unique_lock<std::mutex> lock(kinetics_mutex);
50  delete s_factory;
51  s_factory = 0;
52 }
53 
55 {
56  return create(toLowerCopy(model));
57 }
58 
59 shared_ptr<Kinetics> newKinetics(const string& model)
60 {
61  shared_ptr<Kinetics> kin(KineticsFactory::factory()->newKinetics(model));
62  return kin;
63 }
64 
65 shared_ptr<Kinetics> newKinetics(const vector<shared_ptr<ThermoPhase>>& phases,
66  const AnyMap& phaseNode,
67  const AnyMap& rootNode,
68  shared_ptr<Solution> soln)
69 {
70  string kinType = phaseNode.getString("kinetics", "none");
71  kinType = KineticsFactory::factory()->canonicalize(kinType);
72  if (kinType == "none") {
73  // determine phase with minimum number of dimensions
74  size_t nDim = 3;
75  for (auto& phase : phases) {
76  nDim = std::min(phase->nDim(), nDim);
77  }
78  // change kinetics type as necessary
79  if (nDim == 2) {
80  kinType = "surface";
81  } else if (nDim == 1) {
82  kinType = "edge";
83  }
84  }
85 
86  shared_ptr<Kinetics> kin(KineticsFactory::factory()->newKinetics(kinType));
87  if (soln) {
88  soln->setKinetics(kin);
89  }
90  for (auto& phase : phases) {
91  kin->addThermo(phase);
92  }
93  kin->init();
94  addReactions(*kin, phaseNode, rootNode);
95  return kin;
96 }
97 
98 shared_ptr<Kinetics> newKinetics(const vector<shared_ptr<ThermoPhase>>& phases,
99  const string& filename)
100 {
101  string reaction_phase = phases.at(0)->name();
102  AnyMap root = AnyMap::fromYamlFile(filename);
103  AnyMap& phaseNode = root["phases"].getMapWhere("name", reaction_phase);
104  return newKinetics(phases, phaseNode, root);
105 }
106 
107 void addReactions(Kinetics& kin, const AnyMap& phaseNode, const AnyMap& rootNode)
108 {
110  phaseNode.getBool("skip-undeclared-third-bodies", false));
111 
112  loadExtensions(rootNode);
113 
114  // Find sections containing reactions to add
115  vector<string> sections, rules;
116 
117  if (phaseNode.hasKey("reactions")) {
118  const auto& reactionsNode = phaseNode.at("reactions");
119  if (reactionsNode.is<string>()) {
120  if (rootNode.hasKey("reactions")) {
121  // Specification of the rule for adding species from the default
122  // 'reactions' section, if it exists
123  sections.push_back("reactions");
124  rules.push_back(reactionsNode.asString());
125  } else if (reactionsNode.asString() != "none") {
126  throw InputFileError("addReactions", reactionsNode,
127  "Phase entry implies existence of 'reactions' section "
128  "which does not exist in the current input file.");
129  }
130  } else if (reactionsNode.is<vector<string>>()) {
131  // List of sections from which all species should be added
132  for (const auto& item : reactionsNode.as<vector<string>>()) {
133  sections.push_back(item);
134  rules.push_back("all");
135  }
136  } else if (reactionsNode.is<vector<AnyMap>>()) {
137  // Mapping of rules to apply for each specified section containing
138  // reactions
139  for (const auto& item : reactionsNode.as<vector<AnyMap>>()) {
140  sections.push_back(item.begin()->first);
141  rules.push_back(item.begin()->second.asString());
142  }
143  }
144  } else if (kin.kineticsType() != "none") {
145  if (!phaseNode.hasKey("kinetics")) {
146  // Do nothing - default surface or edge kinetics require separate detection
147  // while not adding reactions
148  } else if (rootNode.hasKey("reactions")) {
149  // Default behavior is to add all reactions from the 'reactions'
150  // section, if a 'kinetics' model has been specified
151  sections.push_back("reactions");
152  rules.push_back("all");
153  } else {
154  throw InputFileError("addReactions", phaseNode,
155  "Phase entry implies existence of 'reactions' section which "
156  "does not exist in the current input file. Add the field "
157  "'reactions: none' to the phase entry to specify a kinetics "
158  "model with no reactions.");
159  }
160  }
161 
162  // Add reactions from each section
163  fmt::memory_buffer add_rxn_err;
164  for (size_t i = 0; i < sections.size(); i++) {
165  if (rules[i] == "all") {
166  kin.skipUndeclaredSpecies(false);
167  } else if (rules[i] == "declared-species") {
168  kin.skipUndeclaredSpecies(true);
169  } else if (rules[i] == "none") {
170  continue;
171  } else {
172  throw InputFileError("addReactions", phaseNode.at("reactions"),
173  "Unknown rule '{}' for adding species from the '{}' section.",
174  rules[i], sections[i]);
175  }
176  const auto& slash = boost::ifind_last(sections[i], "/");
177  if (slash) {
178  // specified section is in a different file
179  string fileName (sections[i].begin(), slash.begin());
180  string node(slash.end(), sections[i].end());
181  AnyMap reactions = AnyMap::fromYamlFile(fileName,
182  rootNode.getString("__file__", ""));
183  loadExtensions(reactions);
184  for (const auto& R : reactions[node].asVector<AnyMap>()) {
185  #ifdef NDEBUG
186  try {
187  kin.addReaction(newReaction(R, kin), false);
188  } catch (CanteraError& err) {
189  fmt_append(add_rxn_err, "{}", err.what());
190  }
191  #else
192  kin.addReaction(newReaction(R, kin), false);
193  #endif
194  }
195  } else {
196  // specified section is in the current file
197  for (const auto& R : rootNode.at(sections[i]).asVector<AnyMap>()) {
198  #ifdef NDEBUG
199  try {
200  kin.addReaction(newReaction(R, kin), false);
201  } catch (CanteraError& err) {
202  fmt_append(add_rxn_err, "{}", err.what());
203  }
204  #else
205  kin.addReaction(newReaction(R, kin), false);
206  #endif
207  }
208  }
209  }
210 
211  if (add_rxn_err.size()) {
212  throw CanteraError("addReactions", to_string(add_rxn_err));
213  }
214  kin.checkDuplicates();
215  kin.resizeReactions();
216 }
217 
218 }
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:427
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:1423
bool getBool(const string &key, bool default_) const
If key exists, return it as a bool, otherwise return default_.
Definition: AnyMap.cpp:1515
const string & getString(const string &key, const string &default_) const
If key exists, return it as a string, otherwise return default_.
Definition: AnyMap.cpp:1530
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
Definition: AnyMap.cpp:1771
const AnyValue & at(const string &key) const
Get the value of the item stored in key.
Definition: AnyMap.cpp:1408
const 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:109
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:66
const char * what() const override
Get a description of the error.
Kinetics * create(const string &name, Args... args)
Create an object using the object construction function corresponding to "name" and the provided cons...
Definition: FactoryBase.h:75
void reg(const string &name, function< Kinetics *(Args...)> f)
Register a new object construction function.
Definition: FactoryBase.h:80
void addAlias(const string &original, const string &alias)
Add an alias for an existing registered type.
Definition: FactoryBase.h:85
void addDeprecatedAlias(const string &original, const string &alias)
Add a deprecated alias for an existing registered type.
Definition: FactoryBase.h:116
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:738
void deleteFactory() override
Virtual abstract function that deletes the factory.
Kinetics * newKinetics(const string &model)
Return a new, empty kinetics manager.
Public interface for kinetics managers.
Definition: Kinetics.h:125
virtual void resizeReactions()
Finalize Kinetics object and associated objects.
Definition: Kinetics.cpp:35
virtual string kineticsType() const
Identifies the Kinetics manager type.
Definition: Kinetics.h:144
virtual pair< size_t, size_t > checkDuplicates(bool throw_err=true) const
Check for unmarked duplicate reactions and unmatched marked duplicates.
Definition: Kinetics.cpp:102
virtual bool addReaction(shared_ptr< Reaction > r, bool resize=true)
Add a single reaction to the mechanism.
Definition: Kinetics.cpp:565
void skipUndeclaredSpecies(bool skip)
Determine behavior when adding a new reaction that contains species not defined in any of the phases ...
Definition: Kinetics.h:1326
void skipUndeclaredThirdBodies(bool skip)
Determine behavior when adding a new reaction that contains third-body efficiencies for species not d...
Definition: Kinetics.h:1338
void fmt_append(fmt::memory_buffer &b, Args... args)
Versions 6.2.0 and 6.2.1 of fmtlib do not include this define before they include windows....
Definition: fmt.h:29
string toLowerCopy(const string &input)
Convert to lower case.
shared_ptr< Kinetics > newKinetics(const string &model)
Create a new Kinetics instance.
void addReactions(Kinetics &kin, const AnyMap &phaseNode, const AnyMap &rootNode)
Add reactions to a Kinetics object.
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:564
void loadExtensions(const AnyMap &node)
Load extensions providing user-defined models from the extensions section of the given node.
Definition: global.cpp:179
unique_ptr< Reaction > newReaction(const string &type)
Create a new empty Reaction object.
Definition: Reaction.cpp:832
Contains declarations for string manipulation functions within Cantera.