| Cantera 3.0.0

Loading...
Searching...
No Matches
Solution.cpp
Go to the documentation of this file.
1/**
2 * @file Solution.cpp
3 * Definition file for class Solution.
4 */
5
6// This file is part of Cantera. See License.txt in the top-level directory or
7// at https://cantera.org/license.txt for license and copyright information.
8
9#include "cantera/base/Solution.h"
10#include "cantera/base/Interface.h"
11#include "cantera/base/ExtensionManager.h"
12#include "cantera/thermo/ThermoPhase.h"
13#include "cantera/thermo/ThermoFactory.h"
14#include "cantera/kinetics/Kinetics.h"
15#include "cantera/kinetics/KineticsFactory.h"
16#include "cantera/transport/Transport.h"
17#include "cantera/transport/TransportFactory.h"
18#include "cantera/base/stringUtils.h"
19
20#include <boost/algorithm/string.hpp>
21
22 namespace Cantera
23{
24
25 string Solution::name() const {
26 if (m_thermo) {
27 return m_thermo->name();
28 } else {
29 throw CanteraError("Solution::name",
30 "Requires associated 'ThermoPhase'");
31 }
32}
33
34 void Solution::setName(const string& name) {
35 if (m_thermo) {
36 m_thermo->setName(name);
37 } else {
38 throw CanteraError("Solution::setName",
39 "Requires associated 'ThermoPhase'");
40 }
41}
42
43 void Solution::setThermo(shared_ptr<ThermoPhase> thermo) {
44 m_thermo = thermo;
45 for (const auto& [id, callback] : m_changeCallbacks) {
46 callback();
47 }
48}
49
50 void Solution::setKinetics(shared_ptr<Kinetics> kinetics) {
51 if (kinetics == m_kinetics) {
52 return;
53 }
54 m_kinetics = kinetics;
55 if (m_kinetics) {
56 m_kinetics->setRoot(shared_from_this());
57 }
58 for (const auto& [id, callback] : m_changeCallbacks) {
59 callback();
60 }
61}
62
63 void Solution::setTransport(shared_ptr<Transport> transport) {
64 if (transport == m_transport) {
65 return;
66 }
67 m_transport = transport;
68 for (const auto& [id, callback] : m_changeCallbacks) {
69 callback();
70 }
71}
72
73 void Solution::setTransportModel(const string& model) {
74 if (!m_thermo) {
75 throw CanteraError("Solution::setTransportModel",
76 "Unable to set Transport model without valid ThermoPhase object.");
77 }
78 if (model == "") {
79 setTransport(newTransport(m_thermo, "default"));
80 } else {
81 setTransport(newTransport(m_thermo, model));
82 }
83}
84
85 void Solution::addAdjacent(shared_ptr<Solution> adjacent) {
86 if (m_adjacentByName.count(adjacent->name())) {
87 throw CanteraError("Solution::addAdjacent",
88 "Solution '{}' already contains an adjacent phase named '{}'.",
89 name(), adjacent->name());
90 }
91 if (m_thermo && adjacent->thermo()
92 && adjacent->thermo()->nDim() <= m_thermo->nDim())
93 {
94 throw CanteraError("Solution::addAdjacent",
95 "Adjacent phases should have higher dimensionality than the reacting ",
96 "phase.\n'{}' is {}-dimensional while '{}' is {}-dimensional",
97 adjacent->thermo()->name(), adjacent->thermo()->nDim(),
98 m_thermo->name(), m_thermo->nDim());
99 }
100 m_adjacent.push_back(adjacent);
101 m_adjacentByName[adjacent->name()] = adjacent;
102}
103
104 AnyMap Solution::parameters(bool withInput) const
105{
106 AnyMap out = m_thermo->parameters(false);
107 AnyValue empty("<NULL>");
108 if (m_kinetics) {
109 out.update(m_kinetics->parameters());
110 }
111 if (!m_transport) {
112 out["transport"] = empty;
113 } else if (m_transport->transportModel() == "none") {
114 out["transport"] = empty;
115 } else {
116 out.update(m_transport->parameters());
117 }
118 if (withInput) {
119 auto transport = out["transport"];
120 AnyMap input = m_thermo->input();
121 if (input.hasKey("reactions")) {
122 // all reactions are listed in the standard 'reactions' section
123 input.erase("reactions");
124 }
125 out.update(input);
126 if (input.hasKey("transport")) {
127 // revert changes / ensure that correct model is referenced
128 out["transport"] = transport;
129 }
130 }
131 if (out["transport"] == empty) {
132 out.erase("transport");
133 }
134 return out;
135}
136
137 const AnyMap& Solution::header() const
138{
139 return m_header;
140}
141
142 AnyMap& Solution::header()
143{
144 return m_header;
145}
146
147 const string Solution::source() const {
148 AnyValue source = m_header.getMetadata("filename");
149 return source.empty() ? "<unknown>" : source.asString();
150}
151
152 void Solution::setSource(const string& source) {
153 AnyValue filename(source);
154 m_header.setMetadata("filename", filename);
155}
156
157 void Solution::holdExternalHandle(const string& name,
158 shared_ptr<ExternalHandle> handle)
159{
160 m_externalHandles[name] = handle;
161}
162
163shared_ptr<ExternalHandle> Solution::getExternalHandle(const string& name) const
164{
165 if (m_externalHandles.count(name)) {
166 return m_externalHandles.at(name);
167 } else {
168 return shared_ptr<ExternalHandle>();
169 }
170}
171
172 void Solution::registerChangedCallback(void *id, const function<void()>& callback)
173{
174 m_changeCallbacks[id] = callback;
175}
176
177 void Solution::removeChangedCallback(void* id)
178{
179 m_changeCallbacks.erase(id);
180}
181
182shared_ptr<Solution> newSolution(const string &infile,
183 const string &name,
184 const string &transport,
185 const vector<shared_ptr<Solution>> &adjacent)
186{
187 // get file extension
188 size_t dot = infile.find_last_of(".");
189 string extension;
190 if (dot != npos) {
191 extension = toLowerCopy(infile.substr(dot+1));
192 }
193
194 if (extension == "cti" || extension == "xml") {
195 throw CanteraError("newSolution",
196 "The CTI and XML formats are no longer supported.");
197 }
198
199 // load YAML file
200 auto rootNode = AnyMap::fromYamlFile(infile);
201 AnyMap& phaseNode = rootNode["phases"].getMapWhere("name", name);
202 auto sol = newSolution(phaseNode, rootNode, transport, adjacent);
203 sol->setSource(infile);
204 return sol;
205}
206
207shared_ptr<Solution> newSolution(const string& infile, const string& name,
208 const string& transport, const vector<string>& adjacent)
209{
210 auto rootNode = AnyMap::fromYamlFile(infile);
211 AnyMap& phaseNode = rootNode["phases"].getMapWhere("name", name);
212
213 vector<shared_ptr<Solution>> adjPhases;
214 // Create explicitly-specified adjacent bulk phases
215 for (auto& name : adjacent) {
216 auto& adjNode = rootNode["phases"].getMapWhere("name", name);
217 adjPhases.push_back(newSolution(adjNode, rootNode));
218 }
219 return newSolution(phaseNode, rootNode, transport, adjPhases);
220}
221
222shared_ptr<Solution> newSolution(const AnyMap& phaseNode,
223 const AnyMap& rootNode,
224 const string& transport,
225 const vector<shared_ptr<Solution>>& adjacent,
226 const map<string, shared_ptr<Solution>>& related)
227{
228 // thermo phase
229 auto thermo = newThermo(phaseNode, rootNode);
230
231 // instantiate Solution object of the correct derived type
232 shared_ptr<Solution> sol;
233 switch (thermo->nDim()) {
234 case 2:
235 sol = Interface::create();
236 break;
237 default:
238 sol = Solution::create();
239 }
240 sol->setSource("custom YAML");
241 sol->setThermo(thermo);
242
243 // Add explicitly-specified adjacent phases
244 for (auto& adj : adjacent) {
245 sol->addAdjacent(adj);
246 }
247
248 // If no adjacent phases were explicitly specified, look for them in the interface
249 // phase definition
250 if (adjacent.empty() && phaseNode.hasKey("adjacent-phases")) {
251 auto all_related = related;
252 for (auto& phase : adjacent) {
253 all_related[phase->name()] = phase;
254 }
255
256 // Helper function for adding individual phases
257 auto addPhase = [&](const AnyValue& phases, const AnyMap& root,
258 const string& name)
259 {
260 if (!all_related.count(name)) {
261 // Create a new phase only if there isn't already one with the same name
262 auto adj = newSolution(phases.getMapWhere("name", name), root,
263 "", {}, all_related);
264 all_related[name] = adj;
265 for (size_t i = 0; i < adj->nAdjacent(); i++) {
266 all_related[adj->adjacent(i)->name()] = adj->adjacent(i);
267 }
268 }
269 sol->addAdjacent(all_related[name]);
270 };
271
272 auto& adjPhases = phaseNode["adjacent-phases"];
273 if (adjPhases.is<vector<string>>()) {
274 // 'adjacent' is a list of bulk phases from the current input file
275 for (auto& phase : adjPhases.as<vector<string>>()) {
276 addPhase(rootNode["phases"], rootNode, phase);
277 }
278 } else if (adjPhases.is<vector<AnyMap>>()) {
279 // Each element of 'adjacent' is a map with one item, where the key is
280 // a section in this file or another YAML file, and the value is a list of
281 // phase names to read from that section
282 for (auto& item : adjPhases.asVector<AnyMap>()) {
283 const string& source = item.begin()->first;
284 const auto& names = item.begin()->second.asVector<string>();
285 const auto& slash = boost::ifind_last(source, "/");
286 if (slash) {
287 // source is a different input file
288 string fileName(source.begin(), slash.begin());
289 string node(slash.end(), source.end());
290 AnyMap phaseSource = AnyMap::fromYamlFile(fileName,
291 rootNode.getString("__file__", ""));
292 for (auto& phase : names) {
293 addPhase(phaseSource[node], phaseSource, phase);
294 }
295 } else if (rootNode.hasKey(source)) {
296 // source is in the current file
297 for (auto& phase : names) {
298 addPhase(rootNode[source], rootNode, phase);
299 }
300 } else {
301 throw InputFileError("newSolution", adjPhases,
302 "Could not find a phases section named '{}'.", source);
303 }
304 }
305 } else {
306 throw InputFileError("addAdjacentPhases", adjPhases,
307 "Could not parse adjacent phase declaration of type '{}'",
308 adjPhases.type_str());
309 }
310 }
311
312 // kinetics
313 vector<shared_ptr<ThermoPhase>> phases;
314 phases.push_back(sol->thermo());
315 for (size_t i = 0; i < sol->nAdjacent(); i++) {
316 phases.push_back(sol->adjacent(i)->thermo());
317 }
318 sol->setKinetics(newKinetics(phases, phaseNode, rootNode, sol));
319
320 // set transport model by name
321 sol->setTransportModel(transport);
322
323 // save root-level information (YAML header)
324 AnyMap header;
325 for (const auto& [key, value] : rootNode.ordered()) {
326 if (key == "phases") {
327 // header ends with "phases" field
328 break;
329 } else if (key != "units") {
330 header[key] = value;
331 }
332 }
333 sol->header() = header;
334
335 return sol;
336}
337
338} // namespace Cantera
ExtensionManager.h
Interface.h
KineticsFactory.h
Kinetics.h
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
Solution.h
ThermoFactory.h
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
ThermoPhase.h
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
TransportFactory.h
Header file defining class TransportFactory (see TransportFactory)
Transport.h
Headers for the Transport object, which is the virtual base class for all transport property evaluato...
Cantera::AnyBase::getMetadata
const AnyValue & getMetadata(const string &key) const
Get a value from the metadata applicable to the AnyMap tree containing this node.
Definition AnyMap.cpp:580
Cantera::AnyMap
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:427
Cantera::AnyMap::hasKey
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1423
Cantera::AnyMap::setMetadata
void setMetadata(const string &key, const AnyValue &value)
Set a metadata value that applies to this AnyMap and its children.
Definition AnyMap.cpp:1481
Cantera::AnyMap::getString
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
Cantera::AnyMap::erase
void erase(const string &key)
Erase the value held by key.
Definition AnyMap.cpp:1428
Cantera::AnyMap::fromYamlFile
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
Definition AnyMap.cpp:1771
Cantera::AnyMap::update
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
Definition AnyMap.cpp:1438
Cantera::AnyValue
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:86
Cantera::AnyValue::empty
bool empty() const
Return boolean indicating whether AnyValue is empty.
Definition AnyMap.cpp:647
Cantera::AnyValue::getMapWhere
AnyMap & getMapWhere(const string &key, const string &value, bool create=false)
Treating the value as vector<AnyMap>, return the item where the given key has the specified value.
Definition AnyMap.cpp:1034
Cantera::CanteraError
Base class for exceptions thrown by Cantera classes.
Definition ctexceptions.h:66
Cantera::InputFileError
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition AnyMap.h:738
Cantera::Interface::create
static shared_ptr< Interface > create()
Create an empty Interface object.
Definition Interface.h:33
Cantera::Solution::create
static shared_ptr< Solution > create()
Create an empty Solution object.
Definition Solution.h:54
Cantera::Solution::m_adjacent
vector< shared_ptr< Solution > > m_adjacent
Adjacent phases, for access by index.
Definition Solution.h:155
Cantera::Solution::removeChangedCallback
void removeChangedCallback(void *id)
Remove the callback function associated with the specified object.
Definition Solution.cpp:177
Cantera::Solution::m_adjacentByName
map< string, shared_ptr< Solution > > m_adjacentByName
Adjacent phases, for access by name.
Definition Solution.h:158
Cantera::Solution::setSource
void setSource(const string &source)
Overwrite source (only required if object is not created using newSolution)
Definition Solution.cpp:152
Cantera::Solution::kinetics
shared_ptr< Kinetics > kinetics()
Accessor for the Kinetics pointer.
Definition Solution.h:84
Cantera::Solution::addAdjacent
void addAdjacent(shared_ptr< Solution > adjacent)
Add a phase adjacent to this phase.
Definition Solution.cpp:85
Cantera::Solution::setName
void setName(const string &name)
Set the name of this Solution object.
Definition Solution.cpp:34
Cantera::Solution::m_kinetics
shared_ptr< Kinetics > m_kinetics
Kinetics manager.
Definition Solution.h:151
Cantera::Solution::setTransportModel
void setTransportModel(const string &model="")
Set the Transport object by name.
Definition Solution.cpp:73
Cantera::Solution::setThermo
virtual void setThermo(shared_ptr< ThermoPhase > thermo)
Set the ThermoPhase object.
Definition Solution.cpp:43
Cantera::Solution::m_externalHandles
map< string, shared_ptr< ExternalHandle > > m_externalHandles
Wrappers for this Solution object in extension languages, for evaluation of user-defined reaction rat...
Definition Solution.h:164
Cantera::Solution::m_thermo
shared_ptr< ThermoPhase > m_thermo
ThermoPhase manager.
Definition Solution.h:150
Cantera::Solution::registerChangedCallback
void registerChangedCallback(void *id, const function< void()> &callback)
Register a function to be called if any of the Solution's thermo, kinetics, or transport objects is r...
Definition Solution.cpp:172
Cantera::Solution::m_header
AnyMap m_header
Additional input fields; usually from a YAML input file.
Definition Solution.h:160
Cantera::Solution::holdExternalHandle
void holdExternalHandle(const string &name, shared_ptr< ExternalHandle > handle)
Store a handle to a wrapper for this Solution object from an external language interface (for example...
Definition Solution.cpp:157
Cantera::Solution::m_changeCallbacks
map< void *, function< void()> > m_changeCallbacks
Callback functions that are invoked when the therm, kinetics, or transport members of the Solution ar...
Definition Solution.h:168
Cantera::Solution::source
const string source() const
Retrieve source used for object creation; usually an input file name.
Definition Solution.cpp:147
Cantera::Solution::setTransport
virtual void setTransport(shared_ptr< Transport > transport)
Set the Transport object directly.
Definition Solution.cpp:63
Cantera::Solution::thermo
shared_ptr< ThermoPhase > thermo()
Accessor for the ThermoPhase pointer.
Definition Solution.h:79
Cantera::Solution::transport
shared_ptr< Transport > transport()
Accessor for the Transport pointer.
Definition Solution.h:89
Cantera::Solution::header
const AnyMap & header() const
Access input data associated with header definition.
Definition Solution.cpp:137
Cantera::Solution::adjacent
shared_ptr< Solution > adjacent(size_t i)
Get the Solution object for an adjacent phase by index.
Definition Solution.h:98
Cantera::Solution::m_transport
shared_ptr< Transport > m_transport
Transport manager.
Definition Solution.h:152
Cantera::Solution::setKinetics
virtual void setKinetics(shared_ptr< Kinetics > kinetics)
Set the Kinetics object.
Definition Solution.cpp:50
Cantera::Solution::getExternalHandle
shared_ptr< ExternalHandle > getExternalHandle(const string &name) const
Get the handle for a wrapper for this Solution object from an external language interface.
Definition Solution.cpp:163
Cantera::Solution::name
string name() const
Return the name of this Solution object.
Definition Solution.cpp:25
Cantera::toLowerCopy
string toLowerCopy(const string &input)
Convert to lower case.
Definition stringUtils.cpp:219
Cantera::newKinetics
shared_ptr< Kinetics > newKinetics(const string &model)
Create a new Kinetics instance.
Definition KineticsFactory.cpp:71
Cantera::dot
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition utilities.h:82
Cantera::newSolution
shared_ptr< Solution > newSolution(const string &infile, const string &name, const string &transport, const vector< shared_ptr< Solution > > &adjacent)
Create and initialize a new Solution manager from an input file.
Definition Solution.cpp:182
Cantera::newThermo
shared_ptr< ThermoPhase > newThermo(const AnyMap &phaseNode, const AnyMap &rootNode)
Create a new ThermoPhase object and initialize it.
Definition ThermoFactory.cpp:147
Cantera::newTransport
shared_ptr< Transport > newTransport(shared_ptr< ThermoPhase > thermo, const string &model)
Create a new Transport instance.
Definition TransportFactory.cpp:117
Cantera
Namespace for the Cantera kernel.
Definition AnyMap.cpp:564
Cantera::npos
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:195
stringUtils.h
Contains declarations for string manipulation functions within Cantera.