Cantera  3.2.0a2
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 m_thermo->setSolution(weak_from_this());
46 for (const auto& [id, callback] : m_changeCallbacks) {
47 callback();
48 }
49}
50
51void Solution::setKinetics(shared_ptr<Kinetics> kinetics) {
52 if (kinetics == m_kinetics) {
53 return;
54 }
56 if (m_kinetics) {
57 m_kinetics->setRoot(shared_from_this());
58 }
59 for (const auto& [id, callback] : m_changeCallbacks) {
60 callback();
61 }
62}
63
65{
66 if (!m_transport) {
67 throw CanteraError("Solution::transportModel",
68 "The Transport object is not initialized.");
69 }
70 return m_transport->transportModel();
71}
72
73void Solution::setTransport(shared_ptr<Transport> transport) {
74 if (transport == m_transport) {
75 return;
76 }
78 for (const auto& [id, callback] : m_changeCallbacks) {
79 callback();
80 }
81}
82
83void Solution::setTransportModel(const string& model) {
84 if (!m_thermo) {
85 throw CanteraError("Solution::setTransportModel",
86 "Unable to set Transport model without valid ThermoPhase object.");
87 }
88 if (m_transport && transportModel() == model) {
89 return;
90 }
92}
93
94void Solution::addAdjacent(shared_ptr<Solution> adjacent) {
95 if (m_adjacentByName.count(adjacent->name())) {
96 throw CanteraError("Solution::addAdjacent",
97 "Solution '{}' already contains an adjacent phase named '{}'.",
98 name(), adjacent->name());
99 }
100 if (m_thermo && adjacent->thermo()
101 && adjacent->thermo()->nDim() <= m_thermo->nDim())
102 {
103 throw CanteraError("Solution::addAdjacent",
104 "Adjacent phases should have higher dimensionality than the reacting ",
105 "phase.\n'{}' is {}-dimensional while '{}' is {}-dimensional",
106 adjacent->thermo()->name(), adjacent->thermo()->nDim(),
107 m_thermo->name(), m_thermo->nDim());
108 }
109 m_adjacent.push_back(adjacent);
111}
112
113AnyMap Solution::parameters(bool withInput) const
114{
115 AnyMap out = m_thermo->parameters(false);
116 AnyValue empty("<NULL>");
117 if (m_kinetics) {
118 out.update(m_kinetics->parameters());
119 }
120 if (!m_transport) {
121 out["transport"] = empty;
122 } else if (m_transport->transportModel() == "none") {
123 out["transport"] = empty;
124 } else {
125 out.update(m_transport->parameters());
126 }
127 if (withInput) {
128 auto transport = out["transport"];
129 AnyMap input = m_thermo->input();
130 if (input.hasKey("reactions")) {
131 // all reactions are listed in the standard 'reactions' section
132 input.erase("reactions");
133 }
134 out.update(input);
135 if (input.hasKey("transport")) {
136 // revert changes / ensure that correct model is referenced
137 out["transport"] = transport;
138 }
139 }
140 if (out["transport"] == empty) {
141 out.erase("transport");
142 }
143 return out;
144}
145
147{
148 return m_header;
149}
150
152{
153 return m_header;
154}
155
156const string Solution::source() const {
157 AnyValue source = m_header.getMetadata("filename");
158 return source.empty() ? "<unknown>" : source.asString();
159}
160
161void Solution::setSource(const string& source) {
162 AnyValue filename(source);
163 m_header.setMetadata("filename", filename);
164}
165
166void Solution::holdExternalHandle(const string& name,
167 shared_ptr<ExternalHandle> handle)
168{
169 m_externalHandles[name] = handle;
170}
171
172shared_ptr<ExternalHandle> Solution::getExternalHandle(const string& name) const
173{
174 if (m_externalHandles.count(name)) {
175 return m_externalHandles.at(name);
176 } else {
177 return shared_ptr<ExternalHandle>();
178 }
179}
180
181void Solution::registerChangedCallback(void *id, const function<void()>& callback)
182{
183 m_changeCallbacks[id] = callback;
184}
185
187{
188 m_changeCallbacks.erase(id);
189}
190
191shared_ptr<Solution> newSolution(const string &infile,
192 const string &name,
193 const string &transport,
194 const vector<shared_ptr<Solution>> &adjacent)
195{
196 // get file extension
197 size_t dot = infile.find_last_of(".");
198 string extension;
199 if (dot != npos) {
200 extension = toLowerCopy(infile.substr(dot+1));
201 }
202
203 if (extension == "cti" || extension == "xml") {
204 throw CanteraError("newSolution",
205 "The CTI and XML formats are no longer supported.");
206 }
207
208 // load YAML file
209 auto rootNode = AnyMap::fromYamlFile(infile);
210 const AnyMap& phaseNode = rootNode.at("phases").getMapWhere("name", name);
211 auto sol = newSolution(phaseNode, rootNode, transport, adjacent);
212 sol->setSource(infile);
213 return sol;
214}
215
216shared_ptr<Solution> newSolution(const string& infile, const string& name,
217 const string& transport, const vector<string>& adjacent)
218{
219 auto rootNode = AnyMap::fromYamlFile(infile);
220 const AnyMap& phaseNode = rootNode.at("phases").getMapWhere("name", name);
221
222 vector<shared_ptr<Solution>> adjPhases;
223 // Create explicitly-specified adjacent bulk phases
224 for (auto& name : adjacent) {
225 const auto& adjNode = rootNode.at("phases").getMapWhere("name", name);
226 adjPhases.push_back(newSolution(adjNode, rootNode));
227 }
228 return newSolution(phaseNode, rootNode, transport, adjPhases);
229}
230
231shared_ptr<Solution> newSolution(const AnyMap& phaseNode,
232 const AnyMap& rootNode,
233 const string& transport,
234 const vector<shared_ptr<Solution>>& adjacent,
235 const map<string, shared_ptr<Solution>>& related)
236{
237 // thermo phase
238 auto thermo = newThermo(phaseNode, rootNode);
239
240 // instantiate Solution object of the correct derived type
241 shared_ptr<Solution> sol;
242 switch (thermo->nDim()) {
243 case 2:
244 sol = Interface::create();
245 break;
246 default:
247 sol = Solution::create();
248 }
249 sol->setSource("custom YAML");
250 sol->setThermo(thermo);
251
252 // Add explicitly-specified adjacent phases
253 for (auto& adj : adjacent) {
254 sol->addAdjacent(adj);
255 }
256
257 // If no adjacent phases were explicitly specified, look for them in the interface
258 // phase definition
259 if (adjacent.empty() && phaseNode.hasKey("adjacent-phases")) {
260 auto all_related = related;
261 for (auto& phase : adjacent) {
262 all_related[phase->name()] = phase;
263 }
264
265 // Helper function for adding individual phases
266 auto addPhase = [&](const AnyValue& phases, const AnyMap& root,
267 const string& name)
268 {
269 if (!all_related.count(name)) {
270 // Create a new phase only if there isn't already one with the same name
271 auto adj = newSolution(phases.getMapWhere("name", name), root,
272 "default", {}, all_related);
273 all_related[name] = adj;
274 for (size_t i = 0; i < adj->nAdjacent(); i++) {
275 all_related[adj->adjacent(i)->name()] = adj->adjacent(i);
276 }
277 }
278 sol->addAdjacent(all_related[name]);
279 };
280
281 auto& adjPhases = phaseNode["adjacent-phases"];
282 if (adjPhases.is<vector<string>>()) {
283 // 'adjacent' is a list of bulk phases from the current input file
284 for (auto& phase : adjPhases.as<vector<string>>()) {
285 addPhase(rootNode["phases"], rootNode, phase);
286 }
287 } else if (adjPhases.is<vector<AnyMap>>()) {
288 // Each element of 'adjacent' is a map with one item, where the key is
289 // a section in this file or another YAML file, and the value is a list of
290 // phase names to read from that section
291 for (auto& item : adjPhases.asVector<AnyMap>()) {
292 const string& source = item.begin()->first;
293 const auto& names = item.begin()->second.asVector<string>();
294 const auto& slash = boost::ifind_last(source, "/");
295 if (slash) {
296 // source is a different input file
297 string fileName(source.begin(), slash.begin());
298 string node(slash.end(), source.end());
299 AnyMap phaseSource = AnyMap::fromYamlFile(fileName,
300 rootNode.getString("__file__", ""));
301 for (auto& phase : names) {
302 addPhase(phaseSource[node], phaseSource, phase);
303 }
304 } else if (rootNode.hasKey(source)) {
305 // source is in the current file
306 for (auto& phase : names) {
307 addPhase(rootNode[source], rootNode, phase);
308 }
309 } else {
310 throw InputFileError("newSolution", adjPhases,
311 "Could not find a phases section named '{}'.", source);
312 }
313 }
314 } else {
315 throw InputFileError("addAdjacentPhases", adjPhases,
316 "Could not parse adjacent phase declaration of type '{}'",
317 adjPhases.type_str());
318 }
319 }
320
321 // kinetics
322 vector<shared_ptr<ThermoPhase>> phases;
323 phases.push_back(sol->thermo());
324 for (size_t i = 0; i < sol->nAdjacent(); i++) {
325 phases.push_back(sol->adjacent(i)->thermo());
326 }
327 sol->setKinetics(newKinetics(phases, phaseNode, rootNode, sol));
328
329 // set transport model by name
330 sol->setTransportModel(transport);
331
332 // save root-level information (YAML header)
333 AnyMap header;
334 for (const auto& [key, value] : rootNode.ordered()) {
335 if (key == "phases") {
336 // header ends with "phases" field
337 break;
338 }
339 header[key] = value;
340 }
341 sol->header() = header;
342
343 return sol;
344}
345
346} // 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:623
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
void setMetadata(const string &key, const AnyValue &value)
Set a metadata value that applies to this AnyMap and its children.
Definition AnyMap.cpp:1541
OrderedProxy ordered(bool withUnits=false) const
Return a proxy object that allows iteration in an order determined by the order of insertion,...
Definition AnyMap.h:629
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
void erase(const string &key)
Erase the value held by key.
Definition AnyMap.cpp:1483
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
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
Definition AnyMap.cpp:1493
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:88
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:1084
Base class for exceptions thrown by Cantera classes.
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition AnyMap.h:749
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:168
string transportModel()
Retrieve transport model name.
Definition Solution.cpp:64
void removeChangedCallback(void *id)
Remove the callback function associated with the specified object.
Definition Solution.cpp:186
map< string, shared_ptr< Solution > > m_adjacentByName
Adjacent phases, for access by name.
Definition Solution.h:171
void setSource(const string &source)
Overwrite source (only required if object is not created using newSolution)
Definition Solution.cpp:161
shared_ptr< Kinetics > kinetics()
Accessor for the Kinetics pointer.
Definition Solution.h:88
void setTransportModel(const string &model="default")
Set the Transport object by name.
Definition Solution.cpp:83
void addAdjacent(shared_ptr< Solution > adjacent)
Add a phase adjacent to this phase.
Definition Solution.cpp:94
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:164
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:177
shared_ptr< ThermoPhase > m_thermo
ThermoPhase manager.
Definition Solution.h:163
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:181
AnyMap m_header
Additional input fields; usually from a YAML input file.
Definition Solution.h:173
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:166
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:181
const string source() const
Retrieve source used for object creation; usually an input file name.
Definition Solution.cpp:156
virtual void setTransport(shared_ptr< Transport > transport)
Set the Transport object directly.
Definition Solution.cpp:73
shared_ptr< ThermoPhase > thermo()
Accessor for the ThermoPhase pointer.
Definition Solution.h:83
shared_ptr< Transport > transport()
Accessor for the Transport pointer.
Definition Solution.h:93
const AnyMap & header() const
Access input data associated with header definition.
Definition Solution.cpp:146
shared_ptr< Solution > adjacent(size_t i)
Get the Solution object for an adjacent phase by index.
Definition Solution.h:102
shared_ptr< Transport > m_transport
Transport manager.
Definition Solution.h:165
virtual void setKinetics(shared_ptr< Kinetics > kinetics)
Set the Kinetics object.
Definition Solution.cpp:51
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:172
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:191
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:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:180
Contains declarations for string manipulation functions within Cantera.