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
19
20#include <boost/algorithm/string.hpp>
21
22namespace Cantera
23{
24
25string 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
34void 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
43void Solution::setThermo(shared_ptr<ThermoPhase> thermo) {
45 for (const auto& [id, callback] : m_changeCallbacks) {
46 callback();
47 }
48}
49
50void Solution::setKinetics(shared_ptr<Kinetics> kinetics) {
51 if (kinetics == m_kinetics) {
52 return;
53 }
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
63void Solution::setTransport(shared_ptr<Transport> transport) {
64 if (transport == m_transport) {
65 return;
66 }
68 for (const auto& [id, callback] : m_changeCallbacks) {
69 callback();
70 }
71}
72
73void 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 == "") {
80 } else {
82 }
83}
84
85void 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);
102}
103
104AnyMap 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
138{
139 return m_header;
140}
141
143{
144 return m_header;
145}
146
147const string Solution::source() const {
148 AnyValue source = m_header.getMetadata("filename");
149 return source.empty() ? "<unknown>" : source.asString();
150}
151
152void Solution::setSource(const string& source) {
153 AnyValue filename(source);
154 m_header.setMetadata("filename", filename);
155}
156
157void 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
172void Solution::registerChangedCallback(void *id, const function<void()>& callback)
173{
174 m_changeCallbacks[id] = callback;
175}
176
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
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
Header file defining class TransportFactory (see TransportFactory)
Headers for the Transport object, which is the virtual base class for all transport property evaluato...
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
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
void setMetadata(const string &key, const AnyValue &value)
Set a metadata value that applies to this AnyMap and its children.
Definition AnyMap.cpp:1481
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
void erase(const string &key)
Erase the value held by key.
Definition AnyMap.cpp:1428
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
Definition AnyMap.cpp:1771
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
Definition AnyMap.cpp:1438
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:86
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
Base class for exceptions thrown by Cantera classes.
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition AnyMap.h:738
static shared_ptr< Interface > create()
Create an empty Interface object.
Definition Interface.h:33
static shared_ptr< Solution > create()
Create an empty Solution object.
Definition Solution.h:54
vector< shared_ptr< Solution > > m_adjacent
Adjacent phases, for access by index.
Definition Solution.h:155
void removeChangedCallback(void *id)
Remove the callback function associated with the specified object.
Definition Solution.cpp:177
map< string, shared_ptr< Solution > > m_adjacentByName
Adjacent phases, for access by name.
Definition Solution.h:158
void setSource(const string &source)
Overwrite source (only required if object is not created using newSolution)
Definition Solution.cpp:152
shared_ptr< Kinetics > kinetics()
Accessor for the Kinetics pointer.
Definition Solution.h:84
void addAdjacent(shared_ptr< Solution > adjacent)
Add a phase adjacent to this phase.
Definition Solution.cpp:85
void setName(const string &name)
Set the name of this Solution object.
Definition Solution.cpp:34
shared_ptr< Kinetics > m_kinetics
Kinetics manager.
Definition Solution.h:151
void setTransportModel(const string &model="")
Set the Transport object by name.
Definition Solution.cpp:73
virtual void setThermo(shared_ptr< ThermoPhase > thermo)
Set the ThermoPhase object.
Definition Solution.cpp:43
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
shared_ptr< ThermoPhase > m_thermo
ThermoPhase manager.
Definition Solution.h:150
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
AnyMap m_header
Additional input fields; usually from a YAML input file.
Definition Solution.h:160
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
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
const string source() const
Retrieve source used for object creation; usually an input file name.
Definition Solution.cpp:147
virtual void setTransport(shared_ptr< Transport > transport)
Set the Transport object directly.
Definition Solution.cpp:63
shared_ptr< ThermoPhase > thermo()
Accessor for the ThermoPhase pointer.
Definition Solution.h:79
shared_ptr< Transport > transport()
Accessor for the Transport pointer.
Definition Solution.h:89
const AnyMap & header() const
Access input data associated with header definition.
Definition Solution.cpp:137
shared_ptr< Solution > adjacent(size_t i)
Get the Solution object for an adjacent phase by index.
Definition Solution.h:98
shared_ptr< Transport > m_transport
Transport manager.
Definition Solution.h:152
virtual void setKinetics(shared_ptr< Kinetics > kinetics)
Set the Kinetics object.
Definition Solution.cpp:50
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
string name() const
Return the name of this Solution object.
Definition Solution.cpp:25
string toLowerCopy(const string &input)
Convert to lower case.
shared_ptr< Kinetics > newKinetics(const string &model)
Create a new Kinetics instance.
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition utilities.h:82
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
shared_ptr< ThermoPhase > newThermo(const AnyMap &phaseNode, const AnyMap &rootNode)
Create a new ThermoPhase object and initialize it.
shared_ptr< Transport > newTransport(shared_ptr< ThermoPhase > thermo, const string &model)
Create a new Transport instance.
Namespace for the Cantera kernel.
Definition AnyMap.cpp:564
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:195
Contains declarations for string manipulation functions within Cantera.