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