Cantera  4.0.0a1
Loading...
Searching...
No Matches
YamlWriter.cpp
1// This file is part of Cantera. See License.txt in the top-level directory or
2// at https://cantera.org/license.txt for license and copyright information.
3
13
14#include <fstream>
15#include <chrono>
16
17namespace Cantera {
18
19void YamlWriter::setHeader(const AnyMap& header) {
20 m_header = header;
21}
22
23void YamlWriter::addPhase(shared_ptr<Solution> soln, bool includeAdjacent) {
24 for (auto& phase : m_phases) {
25 if (phase->name() == soln->name()) {
26 if (phase.get() == soln.get()) {
27 // This phase has already been added, so nothing needs to be done. This
28 // is expected in cases such as bulk phases adjacent to multiple
29 // surface phases.
30 return;
31 } else {
32 throw CanteraError("YamlWriter::addPhase",
33 "Duplicate phase name '{}'", soln->name());
34 }
35 }
36 }
37 m_phases.push_back(soln);
38 if (includeAdjacent) {
39 for (size_t i = 0; i < soln->nAdjacent(); i++) {
40 addPhase(soln->adjacent(i));
41 }
42 }
43}
44
45void YamlWriter::addPhase(shared_ptr<ThermoPhase> thermo,
46 shared_ptr<Kinetics> kin,
47 shared_ptr<Transport> tran) {
48 auto soln = Solution::create();
49 soln->setThermo(thermo);
50 soln->setKinetics(kin);
51 soln->setTransport(tran);
52 addPhase(soln);
53}
54
56{
57 AnyMap output;
58 bool hasDescription = m_header.hasKey("description");
59 if (hasDescription) {
60 output["description"] = m_header["description"];
61 }
62 output["generator"] = "YamlWriter";
63 output["cantera-version"] = CANTERA_VERSION;
64 output["git-commit"] = gitCommit();
65 time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
66 output["date"] = trimCopy(std::ctime(&now));
67 if (hasDescription) {
68 output["description"].setLoc(-6, 0);
69 }
70 output["generator"].setLoc(-5, 0);
71 output["cantera-version"].setLoc(-4, 0);
72 output["git-commit"].setLoc(-3, 0);
73 output["date"].setLoc(-2, 0);
74
75 // Add remaining header information, ignoring obsolete information
76 set<string> exclude = {
77 "description", "generator", "cantera-version", "git-commit", "date"};
78 for (const auto& [key, value] : m_header) {
79 if (!exclude.count(key)) {
80 output[key] = value;
81 }
82 }
83
84 // Build phase definitions
85 vector<AnyMap> phaseDefs(m_phases.size());
86 size_t nspecies_total = 0;
87 for (size_t i = 0; i < m_phases.size(); i++) {
88 phaseDefs[i] = m_phases[i]->parameters(!m_skip_user_defined);
89 if (m_phases[i]->nAdjacent()) {
90 vector<string> adj_names;
91 for (size_t j = 0; j < m_phases[i]->nAdjacent(); j++) {
92 adj_names.push_back(m_phases[i]->adjacent(j)->name());
93 }
94 phaseDefs[i]["adjacent-phases"] = adj_names;
95 }
96 nspecies_total += m_phases[i]->thermo()->nSpecies();
97 }
98 output["phases"] = phaseDefs;
99
100 // Build custom element definitions needed by any phase
101 vector<AnyMap> elementDefs;
102 std::unordered_map<string, size_t> elementDefIndex;
103 for (const auto& phase : m_phases) {
104 for (auto& elementDef : phase->thermo()->elementDefinitions()) {
105 const string& symbol = elementDef["symbol"].asString();
106 if (elementDefIndex.count(symbol) == 0) {
107 elementDefs.emplace_back(std::move(elementDef));
108 elementDefIndex[symbol] = elementDefs.size() - 1;
109 } else if (elementDefs[elementDefIndex[symbol]] != elementDef) {
110 throw CanteraError("YamlWriter::toYamlString",
111 "Multiple elements with different definitions are not "
112 "supported:\n>>>>>>\n{}\n======\n{}\n<<<<<<\n",
113 elementDef.toYamlString(),
114 elementDefs[elementDefIndex[symbol]].toYamlString());
115 }
116 }
117 }
118 if (!elementDefs.empty()) {
119 output["elements"] = std::move(elementDefs);
120 }
121
122 // Build species definitions for all phases
123 vector<AnyMap> speciesDefs;
124 speciesDefs.reserve(nspecies_total);
125 std::unordered_map<string, size_t> speciesDefIndex;
126 for (const auto& phase : m_phases) {
127 const auto thermo = phase->thermo();
128 for (const auto& name : thermo->speciesNames()) {
129 const auto& species = thermo->species(name);
130 AnyMap speciesDef = species->parameters(thermo.get(), !m_skip_user_defined);
131
132 if (speciesDefIndex.count(name) == 0) {
133 speciesDefs.emplace_back(speciesDef);
134 speciesDefIndex[name] = speciesDefs.size() - 1;
135 } else if (speciesDefs[speciesDefIndex[name]] != speciesDef) {
136 throw CanteraError("YamlWriter::toYamlString",
137 "Multiple species with different definitions are not "
138 "supported:\n>>>>>>\n{}\n======\n{}\n<<<<<<\n",
139 speciesDef.toYamlString(),
140 speciesDefs[speciesDefIndex[name]].toYamlString());
141 }
142 }
143 }
144 output["species"] = speciesDefs;
145
146 // build reaction definitions for all phases
147 map<string, vector<AnyMap>> allReactions;
148 for (const auto& phase : m_phases) {
149 const auto kin = phase->kinetics();
150 if (!kin || !kin->nReactions()) {
151 continue;
152 }
153 // Update duplicate reaction labels in case of a dynamically-built mechanism
154 kin->checkDuplicates(false, true);
155 vector<AnyMap> reactions;
156 for (size_t i = 0; i < kin->nReactions(); i++) {
157 reactions.push_back(kin->reaction(i)->parameters(!m_skip_user_defined));
158 }
159 allReactions[phase->name()] = std::move(reactions);
160 }
161
162 // Figure out which phase definitions have identical sets of reactions,
163 // and can share a reaction definition section
164
165 // key: canonical phase in allReactions
166 // value: phases using this reaction set
167 map<string, vector<string>> phaseGroups;
168
169 for (const auto& phase : m_phases) {
170 const auto kin = phase->kinetics();
171 string name = phase->name();
172 if (!kin || !kin->nReactions()) {
173 continue;
174 }
175 bool match = false;
176 for (auto& [canonicalPhase, dependentPhases] : phaseGroups) {
177 if (allReactions[canonicalPhase] == allReactions[name]) {
178 dependentPhases.push_back(name);
179 allReactions.erase(name);
180 match = true;
181 break;
182 }
183 }
184 if (!match) {
185 phaseGroups[name].push_back(name);
186 }
187 }
188
189 // Generate the reactions section(s) in the output file
190 if (phaseGroups.size() == 1) {
191 output["reactions"] = std::move(allReactions[phaseGroups.begin()->first]);
192 } else {
193 for (const auto& [canonicalPhase, dependentPhases] : phaseGroups) {
194 string groupName;
195 for (auto& name : dependentPhases) {
196 groupName += name + "-";
197 }
198 groupName += "reactions";
199 output[groupName] = std::move(allReactions[canonicalPhase]);
200
201 for (auto& name : dependentPhases) {
202 AnyMap& phaseDef = output["phases"].getMapWhere("name", name);
203 phaseDef["reactions"] = vector<string>{groupName};
204 }
205 }
206 }
207
208 output.setMetadata("precision", AnyValue(m_float_precision));
209 output.setUnits(m_output_units);
210 return output.toYamlString();
211}
212
213void YamlWriter::toYamlFile(const string& filename) const
214{
215 std::ofstream out(filename);
216 out << toYamlString();
217}
218
219void YamlWriter::setUnits(const map<string, string>& units)
220{
223}
224
226{
227 m_output_units = units;
228}
229
230}
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
Declaration for class Cantera::Species.
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...
Declaration for class Cantera::YamlWriter.
void setLoc(int line, int column)
For values which are derived from an input file, set the line and column of this value in that file.
Definition AnyMap.cpp:617
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
size_t size() const
Returns the number of elements in this map.
Definition AnyMap.cpp:1728
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
void setUnits(const UnitSystem &units)
Set the unit system for this AnyMap.
Definition AnyMap.cpp:1782
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:88
Base class for exceptions thrown by Cantera classes.
static shared_ptr< Solution > create()
Create an empty Solution object.
Definition Solution.h:54
Unit conversion utility.
Definition Units.h:169
void setDefaults(std::initializer_list< string > units)
Set the default units to convert from when explicit units are not provided.
Definition Units.cpp:429
bool m_skip_user_defined
See skipUserDefined()
Definition YamlWriter.h:87
string toYamlString() const
Return a YAML string that contains the definitions for the added phases, species, and reactions.
void setUnitSystem(const UnitSystem &units=UnitSystem())
Set the units to be used in the output file.
long int m_float_precision
See setPrecision()
Definition YamlWriter.h:84
AnyMap m_header
Top-level information used in YAML header block.
Definition YamlWriter.h:79
void setHeader(const AnyMap &header)
Include top-level information used in YAML header block.
void addPhase(shared_ptr< Solution > soln, bool includeAdjacent=true)
Include a phase definition for the specified Solution object.
UnitSystem m_output_units
Top-level units directive for the output file.
Definition YamlWriter.h:91
void toYamlFile(const string &filename) const
Write the definitions for the added phases, species and reactions to the specified file.
void setUnits(const map< string, string > &units={})
Set the units to be used in the output file.
string trimCopy(const string &input)
Trim.
string gitCommit()
Returns the hash of the git commit from which Cantera was compiled, if known.
Definition global.cpp:150
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
Contains declarations for string manipulation functions within Cantera.