Cantera 2.6.0
ctml.cpp
Go to the documentation of this file.
1/**
2 * @file ctml.cpp
3 * Definitions for functions to read and write CTML.
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
9#include "cantera/base/ctml.h"
11#include "cantera/base/Array.h"
13#include "cantera/base/global.h"
14
15using namespace std;
16
17namespace Cantera
18{
19std::string FP_Format = "%23.15E";
20
21void addFloat(XML_Node& node, const std::string& title,
22 const doublereal val, const std::string& units,
23 const std::string& type, const doublereal minval,
24 const doublereal maxval)
25{
26 XML_Node& f = node.addChild(title, val, FP_Format);
27 if (type != "") {
28 f.addAttribute("type",type);
29 }
30 if (units != "") {
31 f.addAttribute("units",units);
32 }
33 f.addAttribute("vtype", "float");
34 if (minval != Undef) {
35 f.addAttribute("min",minval);
36 }
37 if (maxval != Undef) {
38 f.addAttribute("max",maxval);
39 }
40}
41
42void addFloatArray(XML_Node& node, const std::string& title, const size_t n,
43 const doublereal* const vals, const std::string& units,
44 const std::string& type,
45 const doublereal minval, const doublereal maxval)
46{
47 std::string v = "";
48 for (size_t i = 0; i < n; i++) {
49 v += fmt::sprintf(FP_Format, vals[i]);
50 if (i == n-1) {
51 v += "\n";
52 } else if (i > 0 && (i+1) % 3 == 0) {
53 v += ",\n";
54 } else {
55 v += ", ";
56 }
57 }
58 XML_Node& f = node.addChild("floatArray",v);
59 f.addAttribute("title",title);
60 if (type != "") {
61 f.addAttribute("type",type);
62 }
63 f.addAttribute("size", double(n));
64 if (units != "") {
65 f.addAttribute("units",units);
66 }
67 if (minval != Undef) {
68 f.addAttribute("min",minval);
69 }
70 if (maxval != Undef) {
71 f.addAttribute("max",maxval);
72 }
73}
74
75void addNamedFloatArray(XML_Node& node, const std::string& name, const size_t n,
76 const doublereal* const vals, const std::string units,
77 const std::string type, const doublereal minval,
78 const doublereal maxval)
79{
80 std::string v = "";
81 for (size_t i = 0; i < n; i++) {
82 v += fmt::sprintf(FP_Format, vals[i]);
83 if (i == n-1) {
84 v += "\n";
85 } else if (i > 0 && (i+1) % 3 == 0) {
86 v += ",\n";
87 } else {
88 v += ", ";
89 }
90 }
91 XML_Node& f = node.addChild(name, v);
92 if (type != "") {
93 f.addAttribute("type",type);
94 }
95
96 // Add vtype, which indicates the type of the value. Here we specify it as a
97 // list of floats separated by commas, with a length given by size
98 // attribute.
99 f.addAttribute("vtype", "floatArray");
100
101 f.addAttribute("size", n);
102 if (units != "") {
103 f.addAttribute("units", units);
104 }
105 if (minval != Undef) {
106 f.addAttribute("min", minval);
107 }
108 if (maxval != Undef) {
109 f.addAttribute("max", maxval);
110 }
111}
112
113void addString(XML_Node& node, const std::string& titleString,
114 const std::string& valueString,
115 const std::string& typeString)
116{
117 XML_Node& f = node.addChild("string", valueString);
118 f.addAttribute("title", titleString);
119 if (typeString != "") {
120 f.addAttribute("type", typeString);
121 }
122}
123
124XML_Node* getByTitle(const XML_Node& node, const std::string& title)
125{
126 XML_Node* s = node.findByAttr("title", title);
127 if (s && s->parent() == &node) {
128 return s;
129 }
130 return 0;
131}
132
133std::string getChildValue(const XML_Node& parent, const std::string& nameString)
134{
135 if (!parent.hasChild(nameString)) {
136 return "";
137 }
138 return parent(nameString);
139}
140
141void getString(const XML_Node& node, const std::string& titleString, std::string& valueString,
142 std::string& typeString)
143{
144 XML_Node* s = getByTitle(node, titleString);
145 if (s && s->name() == "string") {
146 valueString = s->value();
147 typeString = s->attrib("type");
148 } else {
149 valueString = "";
150 typeString = "";
151 }
152}
153
154void getIntegers(const XML_Node& node,
155 std::map<std::string, int>& v)
156{
157 std::vector<XML_Node*> f = node.getChildren("integer");
158 for (size_t i = 0; i < f.size(); i++) {
159 const XML_Node& fi = *f[i];
160 if (fi["min"] != "" && fi["max"] != "") {
161 v[fi["title"]] = fi.int_value();
162 }
163 }
164}
165
166doublereal getFloat(const XML_Node& parent,
167 const std::string& name,
168 const std::string& type)
169{
170 if (!parent.hasChild(name)) {
171 throw CanteraError("getFloat (called from XML Node \"" +
172 parent.name() + "\"): ",
173 "no child XML element named \"" + name + "\" exists");
174 }
175 const XML_Node& node = parent.child(name);
176 return getFloatCurrent(node, type);
177}
178
179doublereal getFloatCurrent(const XML_Node& node, const std::string& type)
180{
181 doublereal fctr = 1.0;
182 doublereal x = node.fp_value();
183 const string& units = node["units"];
184 const string& vmin = node["min"];
185 const string& vmax = node["max"];
186 if (vmin != "" && x < fpValue(vmin) - Tiny) {
187 writelog("\nWarning: value "+node.value()+" is below lower limit of "
188 +vmin+".\n");
189 }
190 if (node["max"] != "" && x > fpValue(vmax) + Tiny) {
191 writelog("\nWarning: value "+node.value()+" is above upper limit of "
192 +vmax+".\n");
193 }
194 // Note, most types of converters default to toSI() type atm.
195 // This may change and become more specific in the future.
196 if (type == "actEnergy" && units != "") {
197 fctr = actEnergyToSI(units);
198 } else if (type == "toSI" && units != "") {
199 fctr = toSI(units);
200 } else if (type == "temperature" && units != "") {
201 fctr = toSI(units);
202 } else if (type == "density" && units != "") {
203 fctr = toSI(units);
204 } else if (type == "pressure" && units != "") {
205 fctr = toSI(units);
206 } else if (type != "" && units != "") {
207 fctr = toSI(units);
208 writelog("\nWarning: conversion toSI() was done on node value " + node.name() +
209 "but wasn't explicitly requested. Type was \"" + type + "\"\n");
210 }
211 return fctr*x;
212}
213
214bool getOptionalFloat(const XML_Node& parent,
215 const std::string& name,
216 doublereal& fltRtn,
217 const std::string& type)
218{
219 if (parent.hasChild(name)) {
220 fltRtn = getFloat(parent, name, type);
221 return true;
222 }
223 return false;
224}
225
226bool getOptionalModel(const XML_Node& parent, const std::string& nodeName,
227 std::string& modelName)
228{
229 if (parent.hasChild(nodeName)) {
230 modelName = parent.child(nodeName)["model"];
231 return true;
232 }
233 return false;
234}
235
236int getInteger(const XML_Node& parent, const std::string& name)
237{
238 if (!parent.hasChild(name)) {
239 throw CanteraError("getInteger (called from XML Node \"" +
240 parent.name() + "\"): ",
241 "no child XML element named " + name);
242 }
243 const XML_Node& node = parent.child(name);
244 int x = node.int_value();
245 const string& vmin = node["min"];
246 const string& vmax = node["max"];
247 if (vmin != "" && x < intValue(vmin)) {
248 writelog("\nWarning: value "+node.value()+" is below lower limit of "
249 +vmin+".\n");
250 }
251 if (node["max"] != "" && x > intValue(vmax)) {
252 writelog("\nWarning: value "+node.value()+" is above upper limit of "
253 +vmax+".\n");
254 }
255 return x;
256}
257
258size_t getFloatArray(const XML_Node& node, vector_fp & v,
259 const bool convert, const std::string& unitsString,
260 const std::string& nodeName)
261{
262 const XML_Node* readNode = &node;
263 if (node.name() != nodeName) {
264 vector<XML_Node*> ll = node.getChildren(nodeName);
265 if (ll.size() == 0) {
266 throw CanteraError("getFloatArray",
267 "wrong XML element type/name: was expecting "
268 + nodeName + "but accessed " + node.name());
269 } else {
270 readNode = ll[0];
271 ll = readNode->getChildren("floatArray");
272 if (ll.size() > 0) {
273 readNode = ll[0];
274 }
275 }
276 }
277
278 v.clear();
279 doublereal vmin = Undef, vmax = Undef;
280 doublereal funit = 1.0;
281
282 // Get the attributes field, units, from the XML node
283 std::string units = readNode->attrib("units");
284 if (units != "" && convert) {
285 if (unitsString == "actEnergy" && units != "") {
286 funit = actEnergyToSI(units);
287 } else if (unitsString != "" && units != "") {
288 funit = toSI(units);
289 }
290 }
291
292 if (readNode->attrib("min") != "") {
293 vmin = fpValueCheck(readNode->attrib("min"));
294 }
295 if (readNode->attrib("max") != "") {
296 vmax = fpValueCheck(readNode->attrib("max"));
297 }
298
299 std::string val = readNode->value();
300 while (true) {
301 size_t icom = val.find(',');
302 if (icom != string::npos) {
303 string numstr = val.substr(0,icom);
304 val = val.substr(icom+1,val.size());
305 v.push_back(fpValueCheck(numstr));
306 } else {
307 // This little bit of code is to allow for the possibility of a
308 // comma being the last item in the value text. This was allowed in
309 // previous versions of Cantera, even though it would appear to be
310 // odd. So, we keep the possibility in for backwards compatibility.
311 if (!val.empty()) {
312 v.push_back(fpValueCheck(val));
313 }
314 break;
315 }
316 doublereal vv = v.back();
317 if (vmin != Undef && vv < vmin - Tiny) {
318 writelog("\nWarning: value {} is below lower limit of {}.\n",
319 vv, vmin);
320 }
321 if (vmax != Undef && vv > vmax + Tiny) {
322 writelog("\nWarning: value {} is above upper limit of {}.\n",
323 vv, vmax);
324 }
325 }
326 for (size_t n = 0; n < v.size(); n++) {
327 v[n] *= funit;
328 }
329 return v.size();
330}
331
332void getMap(const XML_Node& node, std::map<std::string, std::string>& m)
333{
334 std::vector<std::string> v;
335 getStringArray(node, v);
336 for (size_t i = 0; i < v.size(); i++) {
337 size_t icolon = v[i].find(":");
338 if (icolon == string::npos) {
339 throw CanteraError("getMap","missing colon in map entry ("
340 +v[i]+")");
341 }
342 m[v[i].substr(0,icolon)] = v[i].substr(icolon+1, v[i].size());
343 }
344}
345
346int getPairs(const XML_Node& node, std::vector<std::string>& key,
347 std::vector<std::string>& val)
348{
349 vector<string> v;
350 getStringArray(node, v);
351 int n = static_cast<int>(v.size());
352 for (int i = 0; i < n; i++) {
353 size_t icolon = v[i].find(":");
354 if (icolon == string::npos) {
355 throw CanteraError("getPairs","Missing a colon in the Pair entry ("
356 +v[i]+")");
357 }
358 key.push_back(v[i].substr(0,icolon));
359 val.push_back(v[i].substr(icolon+1, v[i].size()));
360 }
361 return n;
362}
363
364void getMatrixValues(const XML_Node& node,
365 const std::vector<std::string>& keyStringRow,
366 const std::vector<std::string>& keyStringCol,
367 Array2D& retnValues, const bool convert,
368 const bool matrixSymmetric)
369{
370 if (keyStringRow.size() > retnValues.nRows()) {
371 throw CanteraError("getMatrixValues",
372 "size of key1 greater than numrows");
373 } else if (keyStringCol.size() > retnValues.nColumns()) {
374 throw CanteraError("getMatrixValues",
375 "size of key2 greater than num cols");
376 } else if (matrixSymmetric && retnValues.nRows() != retnValues.nColumns()) {
377 throw CanteraError("getMatrixValues",
378 "nrow != ncol for a symmetric matrix");
379 }
380
381 // Get the attributes field, units, from the XML node and determine the
382 // conversion factor, funit.
383 doublereal funit = 1.0;
384 if (convert && node["units"] != "") {
385 funit = toSI(node["units"]);
386 }
387
388 vector<string> v;
389 getStringArray(node, v);
390 for (size_t i = 0; i < v.size(); i++) {
391 size_t icolon = v[i].find(":");
392 if (icolon == string::npos) {
393 throw CanteraError("getMatrixValues","Missing two colons ("
394 +v[i]+")");
395 }
396 string key1 = v[i].substr(0,icolon);
397 string rmm = v[i].substr(icolon+1, v[i].size());
398
399 icolon = rmm.find(":");
400 if (icolon == string::npos) {
401 throw CanteraError("getMatrixValues","Missing one colon ("
402 +v[i]+")");
403 }
404
405 size_t irow = find(keyStringRow.begin(), keyStringRow.end(), key1)
406 - keyStringRow.begin();
407 if (irow == keyStringRow.size()) {
408 throw CanteraError("getMatrixValues","Row not matched by string: "
409 + key1);
410 }
411
412 string key2 = rmm.substr(0,icolon);
413 size_t icol = find(keyStringCol.begin(), keyStringCol.end(), key2)
414 - keyStringCol.begin();
415 if (icol == keyStringCol.size()) {
416 throw CanteraError("getMatrixValues","Col not matched by string: "
417 + key2);
418 }
419 double dval = fpValueCheck(rmm.substr(icolon+1, rmm.size())) * funit;
420
421 // Finally, insert the value;
422 retnValues(irow, icol) = dval;
423 if (matrixSymmetric) {
424 retnValues(icol, irow) = dval;
425 }
426 }
427}
428
429void getStringArray(const XML_Node& node, std::vector<std::string>& v)
430{
431 tokenizeString(node.value(), v);
432}
433
434}
Header file for class Cantera::Array2D.
A class for 2D arrays stored in column-major (Fortran-compatible) form.
Definition: Array.h:30
size_t nRows() const
Number of rows.
Definition: Array.h:188
size_t nColumns() const
Number of columns.
Definition: Array.h:193
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:103
XML_Node * findByAttr(const std::string &attr, const std::string &val, int depth=100000) const
This routine carries out a recursive search for an XML node based on an attribute of each XML node.
Definition: xml.cpp:662
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:493
std::string name() const
Returns the name of the XML node.
Definition: xml.h:371
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:529
void addAttribute(const std::string &attrib, const std::string &value)
Add or modify an attribute of the current node.
Definition: xml.cpp:467
integer int_value() const
Return the value of an XML node as a single int.
Definition: xml.cpp:462
doublereal fp_value() const
Return the value of an XML node as a single double.
Definition: xml.cpp:457
XML_Node * parent() const
Returns a pointer to the parent node of the current node.
Definition: xml.cpp:518
void clear()
Clear the current node and everything under it.
Definition: xml.cpp:366
std::vector< XML_Node * > getChildren(const std::string &name) const
Get a vector of pointers to XML_Node containing all of the children of the current node which match t...
Definition: xml.cpp:712
std::string value() const
Return the value of an XML node as a string.
Definition: xml.cpp:442
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:547
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
This file contains definitions for utility functions and text for modules, inputfiles,...
void writelog(const std::string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition: global.h:164
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
void getString(const XML_Node &node, const std::string &titleString, std::string &valueString, std::string &typeString)
This function reads a child node with the name string with a specific title attribute named titleStri...
Definition: ctml.cpp:141
const double Tiny
Small number to compare differences of mole fractions against.
Definition: ct_defs.h:170
int intValue(const std::string &val)
Translate a string into one integer value.
void getStringArray(const XML_Node &node, std::vector< std::string > &v)
This function interprets the value portion of an XML element as a string.
Definition: ctml.cpp:429
const double Undef
Fairly random number to be used to initialize variables against to see if they are subsequently defin...
Definition: ct_defs.h:161
XML_Node * getByTitle(const XML_Node &node, const std::string &title)
Search the child nodes of the current node for an XML Node with a Title attribute of a given name.
Definition: ctml.cpp:124
doublereal getFloatCurrent(const XML_Node &currXML, const std::string &type="")
Get a floating-point value from the current XML element.
Definition: ctml.cpp:179
doublereal getFloat(const XML_Node &parent, const std::string &name, const std::string &type="")
Get a floating-point value from a child element.
Definition: ctml.cpp:166
bool getOptionalFloat(const XML_Node &parent, const std::string &name, doublereal &fltRtn, const std::string &type="")
Get an optional floating-point value from a child element.
Definition: ctml.cpp:214
std::string getChildValue(const XML_Node &parent, const std::string &nameString)
This function reads a child node with the name, nameString, and returns its XML value as the return s...
Definition: ctml.cpp:133
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
void addFloat(XML_Node &node, const std::string &titleString, const doublereal value, const std::string &unitsString="", const std::string &typeString="", const doublereal minval=Undef, const doublereal maxval=Undef)
This function adds a child node with the name, "float", with a value consisting of a single floating ...
Definition: ctml.cpp:21
bool getOptionalModel(const XML_Node &parent, const std::string &nodeName, std::string &modelName)
Get an optional model name from a named child node.
Definition: ctml.cpp:226
int getPairs(const XML_Node &node, std::vector< std::string > &key, std::vector< std::string > &val)
This function interprets the value portion of an XML element as a series of "Pairs" separated by whit...
Definition: ctml.cpp:346
doublereal actEnergyToSI(const std::string &unit)
Return the conversion factor to convert activation energy unit std::string 'unit' to Kelvin.
Definition: global.cpp:181
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:184
int getInteger(const XML_Node &parent, const std::string &name)
Get an integer value from a child element.
Definition: ctml.cpp:236
size_t getFloatArray(const XML_Node &node, vector_fp &v, const bool convert=true, const std::string &unitsString="", const std::string &nodeName="floatArray")
This function reads the current node or a child node of the current node with the default name,...
Definition: ctml.cpp:258
void getMatrixValues(const XML_Node &node, const std::vector< std::string > &keyStringRow, const std::vector< std::string > &keyStringCol, Array2D &returnValues, const bool convert=true, const bool matrixSymmetric=false)
This function interprets the value portion of an XML element as a series of "Matrix ids and entries" ...
Definition: ctml.cpp:364
doublereal toSI(const std::string &unit)
Return the conversion factor to convert unit std::string 'unit' to SI units.
Definition: global.cpp:170
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
void addString(XML_Node &node, const std::string &titleString, const std::string &valueString, const std::string &typeString="")
This function adds a child node with the name string with a string value to the current node.
Definition: ctml.cpp:113
void tokenizeString(const std::string &oval, std::vector< std::string > &v)
This function separates a string up into tokens according to the location of white space.
void addFloatArray(XML_Node &node, const std::string &titleString, const size_t n, const doublereal *const values, const std::string &unitsString="", const std::string &typeString="", const doublereal minval=Undef, const doublereal maxval=Undef)
This function adds a child node with the name, "floatArray", with a value consisting of a comma separ...
Definition: ctml.cpp:42
void addNamedFloatArray(XML_Node &parentNode, const std::string &name, const size_t n, const doublereal *const vals, const std::string units="", const std::string type="", const doublereal minval=Undef, const doublereal maxval=Undef)
This function adds a child node with the name given by the first parameter with a value consisting of...
Definition: ctml.cpp:75
void getIntegers(const XML_Node &node, std::map< std::string, int > &v)
Get a vector of integer values from a child element.
Definition: ctml.cpp:154
void getMap(const XML_Node &node, std::map< std::string, std::string > &m)
This routine is used to interpret the value portions of XML elements that contain colon separated pai...
Definition: ctml.cpp:332
Contains declarations for string manipulation functions within Cantera.