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