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