Cantera  3.1.0b1
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 }
79}
80
81void Solution::addAdjacent(shared_ptr<Solution> adjacent) {
82 if (m_adjacentByName.count(adjacent->name())) {
83 throw CanteraError("Solution::addAdjacent",
84 "Solution '{}' already contains an adjacent phase named '{}'.",
85 name(), adjacent->name());
86 }
87 if (m_thermo && adjacent->thermo()
88 && adjacent->thermo()->nDim() <= m_thermo->nDim())
89 {
90 throw CanteraError("Solution::addAdjacent",
91 "Adjacent phases should have higher dimensionality than the reacting ",
92 "phase.\n'{}' is {}-dimensional while '{}' is {}-dimensional",
93 adjacent->thermo()->name(), adjacent->thermo()->nDim(),
94 m_thermo->name(), m_thermo->nDim());
95 }
96 m_adjacent.push_back(adjacent);
98}
99
100AnyMap Solution::parameters(bool withInput) const
101{
102 AnyMap out = m_thermo->parameters(false);
103 AnyValue empty("<NULL>");
104 if (m_kinetics) {
105 out.update(m_kinetics->parameters());
106 }
107 if (!m_transport) {
108 out["transport"] = empty;
109 } else if (m_transport->transportModel() == "none") {
110 out["transport"] = empty;
111 } else {
112 out.update(m_transport->parameters());
113 }
114 if (withInput) {
115 auto transport = out["transport"];
116 AnyMap input = m_thermo->input();
117 if (input.hasKey("reactions")) {
118 // all reactions are listed in the standard 'reactions' section
119 input.erase("reactions");
120 }
121 out.update(input);
122 if (input.hasKey("transport")) {
123 // revert changes / ensure that correct model is referenced
124 out["transport"] = transport;
125 }
126 }
127 if (out["transport"] == empty) {
128 out.erase("transport");
129 }
130 return out;
131}
132
134{
135 return m_header;
136}
137
139{
140 return m_header;
141}
142
143const string Solution::source() const {
144 AnyValue source = m_header.getMetadata("filename");
145 return source.empty() ? "<unknown>" : source.asString();
146}
147
148void Solution::setSource(const string& source) {
149 AnyValue filename(source);
150 m_header.setMetadata("filename", filename);
151}
152
153void Solution::holdExternalHandle(const string& name,
154 shared_ptr<ExternalHandle> handle)
155{
156 m_externalHandles[name] = handle;
157}
158
159shared_ptr<ExternalHandle> Solution::getExternalHandle(const string& name) const
160{
161 if (m_externalHandles.count(name)) {
162 return m_externalHandles.at(name);
163 } else {
164 return shared_ptr<ExternalHandle>();
165 }
166}
167
168void Solution::registerChangedCallback(void *id, const function<void()>& callback)
169{
170 m_changeCallbacks[id] = callback;
171}
172
174{
175 m_changeCallbacks.erase(id);
176}
177
178shared_ptr<Solution> newSolution(const string &infile,
179 const string &name,
180 const string &transport,
181 const vector<shared_ptr<Solution>> &adjacent)
182{
183 // get file extension
184 size_t dot = infile.find_last_of(".");
185 string extension;
186 if (dot != npos) {
187 extension = toLowerCopy(infile.substr(dot+1));
188 }
189
190 if (extension == "cti" || extension == "xml") {
191 throw CanteraError("newSolution",
192 "The CTI and XML formats are no longer supported.");
193 }
194
195 // load YAML file
196 auto rootNode = AnyMap::fromYamlFile(infile);
197 const AnyMap& phaseNode = rootNode.at("phases").getMapWhere("name", name);
198 auto sol = newSolution(phaseNode, rootNode, transport, adjacent);
199 sol->setSource(infile);
200 return sol;
201}
202
203shared_ptr<Solution> newSolution(const string& infile, const string& name,
204 const string& transport, const vector<string>& adjacent)
205{
206 auto rootNode = AnyMap::fromYamlFile(infile);
207 const AnyMap& phaseNode = rootNode.at("phases").getMapWhere("name", name);
208
209 vector<shared_ptr<Solution>> adjPhases;
210 // Create explicitly-specified adjacent bulk phases
211 for (auto& name : adjacent) {
212 const auto& adjNode = rootNode.at("phases").getMapWhere("name", name);
213 adjPhases.push_back(newSolution(adjNode, rootNode));
214 }
215 return newSolution(phaseNode, rootNode, transport, adjPhases);
216}
217
218shared_ptr<Solution> newSolution(const AnyMap& phaseNode,
219 const AnyMap& rootNode,
220 const string& transport,
221 const vector<shared_ptr<Solution>>& adjacent,
222 const map<string, shared_ptr<Solution>>& related)
223{
224 // thermo phase
225 auto thermo = newThermo(phaseNode, rootNode);
226
227 // instantiate Solution object of the correct derived type
228 shared_ptr<Solution> sol;
229 switch (thermo->nDim()) {
230 case 2:
231 sol = Interface::create();
232 break;
233 default:
234 sol = Solution::create();
235 }
236 sol->setSource("custom YAML");
237 sol->setThermo(thermo);
238
239 // Add explicitly-specified adjacent phases
240 for (auto& adj : adjacent) {
241 sol->addAdjacent(adj);
242 }
243
244 // If no adjacent phases were explicitly specified, look for them in the interface
245 // phase definition
246 if (adjacent.empty() && phaseNode.hasKey("adjacent-phases")) {
247 auto all_related = related;
248 for (auto& phase : adjacent) {
249 all_related[phase->name()] = phase;
250 }
251
252 // Helper function for adding individual phases
253 auto addPhase = [&](const AnyValue& phases, const AnyMap& root,
254 const string& name)
255 {
256 if (!all_related.count(name)) {
257 // Create a new phase only if there isn't already one with the same name
258 auto adj = newSolution(phases.getMapWhere("name", name), root,
259 "default", {}, all_related);
260 all_related[name] = adj;
261 for (size_t i = 0; i < adj->nAdjacent(); i++) {
262 all_related[adj->adjacent(i)->name()] = adj->adjacent(i);
263 }
264 }
265 sol->addAdjacent(all_related[name]);
266 };
267
268 auto& adjPhases = phaseNode["adjacent-phases"];
269 if (adjPhases.is<vector<string>>()) {
270 // 'adjacent' is a list of bulk phases from the current input file
271 for (auto& phase : adjPhases.as<vector<string>>()) {
272 addPhase(rootNode["phases"], rootNode, phase);
273 }
274 } else if (adjPhases.is<vector<AnyMap>>()) {
275 // Each element of 'adjacent' is a map with one item, where the key is
276 // a section in this file or another YAML file, and the value is a list of
277 // phase names to read from that section
278 for (auto& item : adjPhases.asVector<AnyMap>()) {
279 const string& source = item.begin()->first;
280 const auto& names = item.begin()->second.asVector<string>();
281 const auto& slash = boost::ifind_last(source, "/");
282 if (slash) {
283 // source is a different input file
284 string fileName(source.begin(), slash.begin());
285 string node(slash.end(), source.end());
286 AnyMap phaseSource = AnyMap::fromYamlFile(fileName,
287 rootNode.getString("__file__", ""));
288 for (auto& phase : names) {
289 addPhase(phaseSource[node], phaseSource, phase);
290 }
291 } else if (rootNode.hasKey(source)) {
292 // source is in the current file
293 for (auto& phase : names) {
294 addPhase(rootNode[source], rootNode, phase);
295 }
296 } else {
297 throw InputFileError("newSolution", adjPhases,
298 "Could not find a phases section named '{}'.", source);
299 }
300 }
301 } else {
302 throw InputFileError("addAdjacentPhases", adjPhases,
303 "Could not parse adjacent phase declaration of type '{}'",
304 adjPhases.type_str());
305 }
306 }
307
308 // kinetics
309 vector<shared_ptr<ThermoPhase>> phases;
310 phases.push_back(sol->thermo());
311 for (size_t i = 0; i < sol->nAdjacent(); i++) {
312 phases.push_back(sol->adjacent(i)->thermo());
313 }
314 sol->setKinetics(newKinetics(phases, phaseNode, rootNode, sol));
315
316 // set transport model by name
317 sol->setTransportModel(transport);
318
319 // save root-level information (YAML header)
320 AnyMap header;
321 for (const auto& [key, value] : rootNode.ordered()) {
322 if (key == "phases") {
323 // header ends with "phases" field
324 break;
325 }
326 header[key] = value;
327 }
328 sol->header() = header;
329
330 return sol;
331}
332
333} // 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:87
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:155
void removeChangedCallback(void *id)
Remove the callback function associated with the specified object.
Definition Solution.cpp:173
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:148
shared_ptr< Kinetics > kinetics()
Accessor for the Kinetics pointer.
Definition Solution.h:84
void setTransportModel(const string &model="default")
Set the Transport object by name.
Definition Solution.cpp:73
void addAdjacent(shared_ptr< Solution > adjacent)
Add a phase adjacent to this phase.
Definition Solution.cpp:81
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
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:168
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:153
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:143
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:133
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:159
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:178
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.