Cantera 2.6.0
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
18
19namespace Cantera
20{
21
22Solution::Solution() {}
23
24std::string Solution::name() const {
25 if (m_thermo) {
26 return m_thermo->name();
27 } else {
28 throw CanteraError("Solution::name",
29 "Requires associated 'ThermoPhase'");
30 }
31}
32
33void Solution::setName(const std::string& name) {
34 if (m_thermo) {
35 m_thermo->setName(name);
36 } else {
37 throw CanteraError("Solution::setName",
38 "Requires associated 'ThermoPhase'");
39 }
40}
41
42void Solution::setThermo(shared_ptr<ThermoPhase> thermo) {
44}
45
46void Solution::setKinetics(shared_ptr<Kinetics> kinetics) {
48}
49
50void Solution::setTransport(shared_ptr<Transport> transport) {
52}
53
54void Solution::addAdjacent(shared_ptr<Solution> adjacent) {
55 if (m_adjacentByName.count(adjacent->name())) {
56 throw CanteraError("Solution::addAdjacent",
57 "Solution '{}' already contains an adjacent phase named '{}'.",
58 name(), adjacent->name());
59 }
60 if (m_thermo && adjacent->thermo()
61 && adjacent->thermo()->nDim() <= m_thermo->nDim())
62 {
63 throw CanteraError("Solution::addAdjacent",
64 "Adjacent phases should have higher dimensionality than the reacting ",
65 "phase.\n'{}' is {}-dimensional while '{}' is {}-dimensional",
66 adjacent->thermo()->name(), adjacent->thermo()->nDim(),
67 m_thermo->name(), m_thermo->nDim());
68 }
69 m_adjacent.push_back(adjacent);
71}
72
73AnyMap Solution::parameters(bool withInput) const
74{
75 AnyMap out = m_thermo->parameters(false);
76 AnyValue empty("<NULL>");
77 if (m_kinetics) {
78 out.update(m_kinetics->parameters());
79 }
80 if (!m_transport) {
81 out["transport"] = empty;
82 } else if (m_transport->transportType() == "None") {
83 out["transport"] = empty;
84 } else {
85 out.update(m_transport->parameters());
86 }
87 if (withInput) {
88 auto transport = out["transport"];
89 AnyMap input = m_thermo->input();
90 out.update(input);
91 if (input.hasKey("transport")) {
92 // revert changes / ensure that correct model is referenced
93 out["transport"] = transport;
94 }
95 }
96 if (out["transport"] == empty) {
97 out.erase("transport");
98 }
99 return out;
100}
101
103{
104 return m_header;
105}
106
108{
109 return m_header;
110}
111
112const std::string Solution::source() const {
113 AnyValue source = m_header.getMetadata("filename");
114 return source.empty() ? "<unknown>" : source.asString();
115}
116
117void Solution::setSource(const std::string& source) {
118 AnyValue filename(source);
119 m_header.setMetadata("filename", filename);
120}
121
122shared_ptr<Solution> newSolution(const std::string& infile,
123 const std::string& name,
124 const std::string& transport,
125 const std::vector<shared_ptr<Solution>>& adjacent)
126{
127 // get file extension
128 size_t dot = infile.find_last_of(".");
129 std::string extension;
130 if (dot != npos) {
131 extension = toLowerCopy(infile.substr(dot+1));
132 }
133
134 if (extension == "yml" || extension == "yaml") {
135 // load YAML file
136 auto rootNode = AnyMap::fromYamlFile(infile);
137 AnyMap& phaseNode = rootNode["phases"].getMapWhere("name", name);
138 auto sol = newSolution(phaseNode, rootNode, transport, adjacent);
139 sol->setSource(infile);
140 return sol;
141 }
142
143 // instantiate Solution object
144 auto sol = Solution::create();
145 sol->setSource(infile);
146
147 // thermo phase
148 sol->setThermo(shared_ptr<ThermoPhase>(newPhase(infile, name)));
149
150 // kinetics
151 std::vector<ThermoPhase*> phases;
152 phases.push_back(sol->thermo().get());
153 for (auto& adj : adjacent) {
154 phases.push_back(adj->thermo().get());
155 }
156 sol->setKinetics(newKinetics(phases, infile, name));
157
158 // transport
159 if (transport == "") {
160 sol->setTransport(shared_ptr<Transport>(
161 newDefaultTransportMgr(sol->thermo().get())));
162 } else if (transport == "None") {
163 sol->setTransport(shared_ptr<Transport>(newTransportMgr("None")));
164 } else {
165 sol->setTransport(shared_ptr<Transport>(
166 newTransportMgr(transport, sol->thermo().get())));
167 }
168
169 return sol;
170}
171
172shared_ptr<Solution> newSolution(const std::string& infile, const std::string& name,
173 const std::string& transport, const std::vector<std::string>& adjacent)
174{
175 // @todo Remove file extension check after Cantera 2.6
176 // get file extension
177 size_t dot = infile.find_last_of(".");
178 std::string extension;
179 if (dot != npos) {
180 extension = toLowerCopy(infile.substr(dot+1));
181 }
182
183 if (extension == "xml" || extension == "cti") {
184 throw CanteraError("newSolution(string infile, string name, string transport, "
185 "vector<string> adjacent)",
186 "This constructor is only compatible with YAML input files");
187 }
188
189 auto rootNode = AnyMap::fromYamlFile(infile);
190 AnyMap& phaseNode = rootNode["phases"].getMapWhere("name", name);
191
192 std::vector<shared_ptr<Solution>> adjPhases;
193 // Create explicitly-specified adjacent bulk phases
194 for (auto& name : adjacent) {
195 auto& adjNode = rootNode["phases"].getMapWhere("name", name);
196 adjPhases.push_back(newSolution(adjNode, rootNode));
197 }
198 return newSolution(phaseNode, rootNode, transport, adjPhases);
199}
200
201shared_ptr<Solution> newSolution(const AnyMap& phaseNode,
202 const AnyMap& rootNode,
203 const std::string& transport,
204 const std::vector<shared_ptr<Solution>>& adjacent,
205 const std::map<std::string, shared_ptr<Solution>>& related)
206{
207 // thermo phase
208 auto thermo = shared_ptr<ThermoPhase>(newPhase(phaseNode, rootNode));
209
210 // instantiate Solution object of the correct derived type
211 shared_ptr<Solution> sol;
212 switch (thermo->nDim()) {
213 case 2:
214 sol = Interface::create();
215 break;
216 default:
217 sol = Solution::create();
218 }
219 sol->setSource("custom YAML");
220 sol->setThermo(thermo);
221
222 // Add explicitly-specified adjacent phases
223 for (auto& adj : adjacent) {
224 sol->addAdjacent(adj);
225 }
226
227 // If no adjacent phases were explicitly specified, look for them in the interface
228 // phase definition
229 if (adjacent.empty() && phaseNode.hasKey("adjacent-phases")) {
230 auto all_related = related;
231 for (auto& phase : adjacent) {
232 all_related[phase->name()] = phase;
233 }
234
235 // Helper function for adding individual phases
236 auto addPhase = [&](const AnyValue& phases, const AnyMap& root,
237 const std::string& name)
238 {
239 if (!all_related.count(name)) {
240 // Create a new phase only if there isn't already one with the same name
241 auto adj = newSolution(phases.getMapWhere("name", name), root,
242 "", {}, all_related);
243 all_related[name] = adj;
244 for (size_t i = 0; i < adj->nAdjacent(); i++) {
245 all_related[adj->adjacent(i)->name()] = adj->adjacent(i);
246 }
247 }
248 sol->addAdjacent(all_related[name]);
249 };
250
251 auto& adjPhases = phaseNode["adjacent-phases"];
252 if (adjPhases.is<std::vector<std::string>>()) {
253 // 'adjacent' is a list of bulk phases from the current input file
254 for (auto& phase : adjPhases.as<std::vector<std::string>>()) {
255 addPhase(rootNode["phases"], rootNode, phase);
256 }
257 } else if (adjPhases.is<std::vector<AnyMap>>()) {
258 // Each element of 'adjacent' is a map with one item, where the key is
259 // a section in this file or another YAML file, and the value is a list of
260 // phase names to read from that section
261 for (auto& item : adjPhases.asVector<AnyMap>()) {
262 const std::string& source = item.begin()->first;
263 const auto& names = item.begin()->second.asVector<std::string>();
264 const auto& slash = boost::ifind_last(source, "/");
265 if (slash) {
266 // source is a different input file
267 std::string fileName(source.begin(), slash.begin());
268 std::string node(slash.end(), source.end());
269 AnyMap phaseSource = AnyMap::fromYamlFile(fileName,
270 rootNode.getString("__file__", ""));
271 for (auto& phase : names) {
272 addPhase(phaseSource[node], phaseSource, phase);
273 }
274 } else if (rootNode.hasKey(source)) {
275 // source is in the current file
276 for (auto& phase : names) {
277 addPhase(rootNode[source], rootNode, phase);
278 }
279 } else {
280 throw InputFileError("newSolution", adjPhases,
281 "Could not find a phases section named '{}'.", source);
282 }
283 }
284 } else {
285 throw InputFileError("addAdjacentPhases", adjPhases,
286 "Could not parse adjacent phase declaration of type '{}'",
287 adjPhases.type_str());
288 }
289 }
290
291 // kinetics
292 std::vector<ThermoPhase*> phases;
293 phases.push_back(sol->thermo().get());
294 for (size_t i = 0; i < sol->nAdjacent(); i++) {
295 phases.push_back(sol->adjacent(i)->thermo().get());
296 }
297 sol->setKinetics(newKinetics(phases, phaseNode, rootNode));
298
299 // transport
300 if (transport == "") {
301 sol->setTransport(shared_ptr<Transport>(
302 newDefaultTransportMgr(sol->thermo().get())));
303 } else if (transport == "None") {
304 sol->setTransport(shared_ptr<Transport>(newTransportMgr("None")));
305 } else {
306 sol->setTransport(shared_ptr<Transport>(
307 newTransportMgr(transport, sol->thermo().get())));
308 }
309
310 // save root-level information (YAML header)
311 AnyMap header;
312 for (const auto& item : rootNode.ordered()) {
313 std::string key = item.first;
314 if (key == "phases") {
315 // header ends with "phases" field
316 break;
317 } else if (key != "units") {
318 header[key] = item.second;
319 }
320 }
321 sol->header() = header;
322
323 return sol;
324}
325
326} // 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,...
Headers for the Transport object, which is the virtual base class for all transport property evaluato...
Header file defining class TransportFactory (see TransportFactory)
const AnyValue & getMetadata(const std::string &key) const
Get a value from the metadata applicable to the AnyMap tree containing this node.
Definition: AnyMap.cpp:577
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:399
const std::string & getString(const std::string &key, const std::string &default_) const
If key exists, return it as a string, otherwise return default_.
Definition: AnyMap.cpp:1502
static AnyMap fromYamlFile(const std::string &name, const std::string &parent_name="")
Create an AnyMap from a YAML file.
Definition: AnyMap.cpp:1743
void erase(const std::string &key)
Erase the value held by key.
Definition: AnyMap.cpp:1411
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:1406
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
Definition: AnyMap.cpp:1421
void setMetadata(const std::string &key, const AnyValue &value)
Set a metadata value that applies to this AnyMap and its children.
Definition: AnyMap.cpp:1453
A wrapper for a variable whose type is determined at runtime.
Definition: AnyMap.h:84
AnyMap & getMapWhere(const std::string &key, const std::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:1012
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:702
static shared_ptr< Interface > create()
Create an empty Interface object.
Definition: Interface.h:28
static shared_ptr< Solution > create()
Create an empty Solution object.
Definition: Solution.h:31
std::string name() const
Return the name of this Solution object.
Definition: Solution.cpp:24
shared_ptr< Kinetics > kinetics()
Accessor for the Kinetics pointer.
Definition: Solution.h:56
void addAdjacent(shared_ptr< Solution > adjacent)
Add a phase adjacent to this phase.
Definition: Solution.cpp:54
void setSource(const std::string &source)
Overwrite source (only required if object is not created using newSolution)
Definition: Solution.cpp:117
shared_ptr< Kinetics > m_kinetics
Kinetics manager.
Definition: Solution.h:98
virtual void setThermo(shared_ptr< ThermoPhase > thermo)
Set the ThermoPhase object.
Definition: Solution.cpp:42
shared_ptr< ThermoPhase > m_thermo
ThermoPhase manager.
Definition: Solution.h:97
std::map< std::string, shared_ptr< Solution > > m_adjacentByName
Adjacent phases, for access by name.
Definition: Solution.h:105
void setName(const std::string &name)
Set the name of this Solution object.
Definition: Solution.cpp:33
AnyMap m_header
Additional input fields; usually from a YAML input file.
Definition: Solution.h:107
std::vector< shared_ptr< Solution > > m_adjacent
Adjacent phases, for access by index.
Definition: Solution.h:102
virtual void setTransport(shared_ptr< Transport > transport)
Set the Transport object.
Definition: Solution.cpp:50
const std::string source() const
Retrieve source used for object creation; usually an input file name.
Definition: Solution.cpp:112
shared_ptr< ThermoPhase > thermo()
Accessor for the ThermoPhase pointer.
Definition: Solution.h:51
shared_ptr< Transport > transport()
Accessor for the Transport pointer.
Definition: Solution.h:61
const AnyMap & header() const
Access input data associated with header definition.
Definition: Solution.cpp:102
shared_ptr< Solution > adjacent(size_t i)
Get the Solution object for an adjacent phase by index.
Definition: Solution.h:70
shared_ptr< Transport > m_transport
Transport manager.
Definition: Solution.h:99
virtual void setKinetics(shared_ptr< Kinetics > kinetics)
Set the Kinetics object.
Definition: Solution.cpp:46
ThermoPhase * newPhase(XML_Node &phase)
Create a new ThermoPhase object and initializes it according to the XML tree.
Transport * newDefaultTransportMgr(ThermoPhase *thermo, int loglevel=0)
Create a new transport manager instance.
Namespace for the Cantera kernel.
Definition: AnyMap.h:29
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:192
doublereal dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition: utilities.h:77
Transport * newTransportMgr(const std::string &model="", ThermoPhase *thermo=0, int log_level=0)
Build a new transport manager using a transport manager that may not be the same as in the phase desc...
shared_ptr< Solution > newSolution(const std::string &infile, const std::string &name, const std::string &transport, const std::vector< std::string > &adjacent)
Create and initialize a new Solution from an input file.
Definition: Solution.cpp:172
std::string toLowerCopy(const std::string &input)
Convert to lower case.
shared_ptr< Kinetics > newKinetics(const std::string &model)
Create a new Kinetics instance.
Contains declarations for string manipulation functions within Cantera.