ctml.cpp

Go to the documentation of this file.
00001 /**
00002  * @file ctml.cpp
00003  * Definitions for functions to read and write CTML.
00004  *
00005  */
00006 
00007 /*
00008  * $Revision: 374 $
00009  * $Date: 2010-01-12 16:27:32 -0500 (Tue, 12 Jan 2010) $
00010  */
00011 
00012 // Copyright 2002  California Institute of Technology
00013 
00014 
00015 // turn off warnings under Windows
00016 #ifdef WIN32
00017 #pragma warning(disable:4786)
00018 #pragma warning(disable:4503)
00019 #endif
00020 
00021 #include "ctml.h"
00022 
00023 //@{
00024 #define CTML_VERSION_1_4_1
00025 //@}
00026 
00027 #include "global.h"
00028 #include "stringUtils.h"
00029 
00030 #include <cctype>
00031 #include <cstring>
00032 #include <cstdlib>
00033 
00034 
00035 using namespace std;
00036 using namespace Cantera;
00037 
00038 namespace ctml {
00039 
00040   static doublereal fpValue(std::string val) {
00041     return atof(stripws(val).c_str());
00042   }
00043 
00044   //  This function adds a child node with the name, "bool", with a value
00045   //  consisting of a single bool
00046   /*
00047    *   This function will add a child node to the current XML node, with the
00048    *   name "bool". It will have a title attribute, and the body
00049    *   of the XML node will be filled out with a single bool
00050    *
00051    *  Example:
00052    *
00053    * Code snipet:
00054    *       @verbatum
00055      const XML_Node &node;
00056      std::string titleString = "doSpecialOp";
00057      bool value = true;
00058      addBool(node, titleString, value);
00059      @endverbatum
00060    *
00061    *  Creates the following the snippet in the XML file:
00062    *  @verbatum
00063      <parentNode>
00064        <bool title="doSpecialOp" type="optional">
00065           true
00066        <\integer>
00067      <\parentNode>
00068    @endverbatum
00069    *
00070    *   @param node          reference to the XML_Node object of the parent XML element
00071    *   @param titleString   String name of the title attribute
00072    *   @param value         Value - single bool
00073    *
00074    * @todo I don't think this is used. Figure out what is used for writing bools,
00075    *       and codify that.
00076    */
00077   void addBool(Cantera::XML_Node& node, const std::string &title, const bool val) {
00078     std::string v = (val ? "true" : "false");
00079     XML_Node& f = node.addChild("bool", v);
00080     f.addAttribute("title", title);
00081   }
00082 
00083   //  This function adds a child node with the name, "integer", with a value
00084   //  consisting of a single integer
00085   /*
00086    *   This function will add a child node to the current XML node, with the
00087    *   name "integer". It will have a title attribute, and the body
00088    *   of the XML node will be filled out with a single integer
00089    *
00090    *  Example:
00091    *
00092    * Code snipet:
00093    *       @verbatum
00094    const XML_Node &node;
00095    std::string titleString = "maxIterations";
00096    int  value = 1000;
00097    std::string typeString = "optional";
00098    std::string units = "";
00099    addInteger(node, titleString, value, typeString, units);
00100    @endverbatum
00101    *
00102    *  Creates the following the snippet in the XML file:
00103    *  @verbatum
00104    <parentNode>
00105    <integer title="maxIterations" type="optional">
00106    100
00107    <\integer>
00108    <\parentNode>
00109    @endverbatum
00110    *
00111    *   @param node          reference to the XML_Node object of the parent XML element
00112    *   @param titleString   String name of the title attribute
00113    *   @param value         Value - single integer
00114    *   @param unitsString   String name of the Units attribute. The default is to
00115    *                        have an empty string.
00116    *   @param typeString    String type. This is an optional parameter. The default
00117    *                        is to have an empty string.
00118    */
00119   void addInteger(Cantera::XML_Node& node, const std::string &title, const int val, 
00120                   const std::string units, const std::string type) {
00121     XML_Node& f = node.addChild("integer",val);
00122     f.addAttribute("title",title);
00123     if (type != "") f.addAttribute("type",type);
00124     if (units != "") f.addAttribute("units",units);
00125   } 
00126 
00127   //  This function adds a child node with the name, "intArray", with a value
00128   //  consisting of a comma separated list of integers
00129   /*
00130    *   This function will add a child node to the current XML node, with the
00131    *   name "intArray". It will have a title attribute, and the body
00132    *   of the XML node will be filled out with a comma separated list of
00133    *   integers
00134    *
00135    *  Example:
00136    *
00137    *       @verbatum
00138      const XML_Node &node;
00139      std::string titleString = "additionalCases";
00140      int  n = 3;
00141      int cases[3] = [3, 6, 10];
00142      std::string typeString = "optional";
00143      std::string units = "";
00144      addIntegerArray(node, titleString, n, &cases[0], typeString, units);
00145      @endverbatum 
00146    *
00147    *  Creates the following the snippet in the XML file:
00148    *  @verbatum
00149      <parentNode>
00150        <intArray title="additionalCases" type="optional">
00151           3, 6, 10
00152        <\intArray>
00153      <\parentNode>
00154    @endverbatum
00155    *
00156    *
00157    *   @param node          reference to the XML_Node object of the parent XML element
00158    *   @param titleString   String name of the title attribute
00159    *   @param n             Length of the integer vector.
00160    *   @param values        Pointer to a vector of integers
00161    *   @param unitsString   String name of the Units attribute. This is an optional 
00162    *                        parameter. The default is to
00163    *                        have an empty string.
00164    *   @param typeString    String type. This is an optional parameter. The default
00165    *                        is to have an empty string.
00166    *   @param minval        Minimum allowed value of the int. This is an optional
00167    *                        parameter. The default is the
00168    *                        special double, Cantera::Undef, which means to ignore the
00169    *                        entry.
00170    *   @param maxval        Maximum allowed value of the int. This is an optional
00171    *                        parameter. The default is the
00172    *                        special double, Cantera::Undef, which means to ignore the
00173    *                        entry.
00174    *
00175    * @todo I don't think this is used. Figure out what is used for writing integers,
00176    *       and codify that. unitsString shouldn't be here, since it's an int.
00177    *       typeString should be codified as to its usage.
00178    */
00179   void addIntegerArray(Cantera::XML_Node& node, const std::string &title, const int n,
00180                        const int* const vals, const std::string units, const std::string type,
00181                        const doublereal minval, const doublereal maxval) {
00182     std::string fmt = "%8d";
00183     int i;
00184     std::string v = "";
00185     for (i = 0; i < n; i++) {
00186       v += int2str(vals[i],fmt);
00187       if (i == n-1) v += "\n"; 
00188       else if (i > 0 && (i+1) % 3 == 0) v += ",\n";
00189       else v += ", ";
00190     }
00191     XML_Node& f = node.addChild("intArray",v);
00192     f.addAttribute("title",title);
00193     if (type != "") f.addAttribute("type",type);        
00194     f.addAttribute("size",n);
00195     if (units != "") f.addAttribute("units",units);
00196     if (minval != Undef) f.addAttribute("min",minval);
00197     if (maxval != Undef) f.addAttribute("max",maxval);
00198   }
00199 
00200   //  This function adds a child node with the name, "float", with a value
00201   //  consisting of a single floating point number
00202   /*
00203    *   This function will add a child node to the current XML node, with the
00204    *   name "float". It will have a title attribute, and the body
00205    *   of the XML node will be filled out with a single float
00206    *
00207    *  Example:
00208    *
00209    * Code snipet:
00210    *       @verbatum
00211    const XML_Node &node;
00212    std::string titleString = "activationEnergy";
00213    double  value = 50.3;
00214    doublereal maxval = 1.0E3;
00215    doublereal minval = 0.0;
00216    std::string typeString = "optional";
00217    std::string unitsString = "kcal/gmol";
00218    addFloat(node, titleString, value, unitsString, typeString, minval, maxval);
00219    @endverbatum
00220    *
00221    *  Creates the following the snippet in the XML file:
00222    *  @verbatum
00223    <parentNode>
00224    <float title="activationEnergy" type="optional" units="kcal/gmol" min="0.0" max="1.0E3">
00225    50.3
00226    <\float>
00227    <\parentNode>
00228    @endverbatum
00229    *
00230    *   @param node          reference to the XML_Node object of the parent XML element
00231    *   @param titleString   String name of the title attribute
00232    *   @param value         Value - single integer
00233    *   @param unitsString   String name of the Units attribute. The default is to
00234    *                        have an empty string.
00235    *   @param typeString    String type. This is an optional parameter. The default
00236    *                        is to have an empty string.
00237    *
00238    * @todo I don't think this is used. Figure out what is used for writing floats,
00239    *       and codify that. minval and maxval should be codified.
00240    *       typeString should be codified as to its usage.
00241    */
00242   void addFloat(Cantera::XML_Node& node, const std::string &title, 
00243                 const doublereal val, const std::string units, 
00244                 const std::string type, const doublereal minval, 
00245                 const doublereal maxval) {
00246     string fmt = "%17.9E";
00247 #ifdef CTML_VERSION_1_4
00248     XML_Node& f = node.addChild("float",val,fmt);
00249     f.addAttribute("title",title);
00250 #else
00251     XML_Node& f = node.addChild(title,val,fmt); 
00252 #endif
00253     if (type != "") f.addAttribute("type",type);
00254     if (units != "") f.addAttribute("units",units);
00255     if (minval != Undef) f.addAttribute("min",minval);
00256     if (maxval != Undef) f.addAttribute("max",maxval);
00257   }
00258 
00259   //  This function adds a child node with the name, "floatArray", with a value
00260   //  consisting of a comma separated list of floats
00261   /*
00262    *   This function will add a child node to the current XML node, with the
00263    *   name "floatArray". It will have a title attribute, and the body
00264    *   of the XML node will be filled out with a comma separated list of
00265    *   integers
00266    *
00267    *  Example:
00268    *
00269    * Code snipet:
00270    *       @verbatum
00271      const XML_Node &node;
00272      std::string titleString = "additionalTemperatures";
00273      int  n = 3;
00274      int Tcases[3] = [273.15, 298.15, 373.15];
00275      std::string typeString = "optional";
00276      std::string units = "Kelvin";
00277      addFloatArray(node, titleString, n, &cases[0], typeString, units);
00278      @endverbatum
00279    *
00280    *  Creates the following the snippet in the XML file:
00281    *  @verbatum
00282      <parentNode>
00283        <floatArray title="additionalTemperatures" type="optional" units="Kelvin">
00284           273.15, 298.15, 373.15
00285        <\floatArray>
00286      <\parentNode>
00287    @endverbatum
00288    *
00289    *   @param node          reference to the XML_Node object of the parent XML element
00290    *   @param titleString   String name of the title attribute
00291    *   @param n             Length of the doubles vector.
00292    *   @param values        Pointer to a vector of doubles
00293    *   @param unitsString   String name of the Units attribute. This is an optional 
00294    *                        parameter. The default is to
00295    *                        have an empty string.
00296    *   @param typeString    String type. This is an optional parameter. The default
00297    *                        is to have an empty string.
00298    *   @param minval        Minimum allowed value of the int. This is an optional
00299    *                        parameter. The default is the
00300    *                        special double, Cantera::Undef, which means to ignore the
00301    *                        entry.
00302    *   @param maxval        Maximum allowed value of the int. This is an optional
00303    *                        parameter. The default is the
00304    *                        special double, Cantera::Undef, which means to ignore the
00305    *                        entry.
00306    *
00307    * @todo I don't think this is used. Figure out what is used for writing integers,
00308    *       and codify that. unitsString shouldn't be here, since it's an int.
00309    *       typeString should be codified as to its usage.
00310    */
00311   void addFloatArray(Cantera::XML_Node& node, const std::string &title, const int n, 
00312                      const doublereal* const vals, const std::string units, 
00313                      const std::string type,
00314                      const doublereal minval, const doublereal maxval) {
00315     std::string fmt = "%17.9E";
00316     int i;
00317     std::string v = "";
00318     for (i = 0; i < n; i++) {
00319       v += fp2str(vals[i],fmt);
00320       if (i == n-1) v += "\n"; 
00321       else if (i > 0 && (i+1) % 3 == 0) v += ",\n";
00322       else v += ", ";
00323     }
00324     XML_Node& f = node.addChild("floatArray",v);
00325     f.addAttribute("title",title);
00326     if (type != "") f.addAttribute("type",type);        
00327     f.addAttribute("size",n);
00328     if (units != "") f.addAttribute("units",units);
00329     if (minval != Undef) f.addAttribute("min",minval);
00330     if (maxval != Undef) f.addAttribute("max",maxval);
00331   }
00332 
00333   //  This function adds a child node with the name string with a string value
00334   //  to the current node
00335   /* 
00336    *   This function will add a child node to the current XML node, with the
00337    *   name "string". It will have a title attribute, and the body
00338    *   of the XML node will be filled out with the valueString argument verbatim.
00339    *
00340    *  Example:  
00341    *
00342    * Code snipet:
00343    *       @verbatum
00344    const XML_Node &node;
00345    addString(XML_Node& node, std::string titleString, std::string valueString, 
00346    std::string typeString);
00347    @endverbatum
00348    *
00349    *  Creates the following the snippet in the XML file:
00350    *  @verbatum
00351    <string title="titleString" type="typeString">
00352    valueString
00353    <\string>
00354    @endverbatum
00355    *
00356    *   @param node          reference to the XML_Node object of the parent XML element
00357    *   @param valueString   Value string to be used in the new XML node.
00358    *   @param titleString   String name of the title attribute
00359    *   @param typeString    String type. This is an optional parameter.
00360    */
00361   void addString(Cantera::XML_Node& node, const std::string &titleString, 
00362                  const std::string &valueString, 
00363                  const std::string typeString) {
00364     XML_Node& f = node.addChild("string", valueString);
00365     f.addAttribute("title", titleString);
00366     if (typeString != "") f.addAttribute("type", typeString);        
00367   }
00368 
00369   XML_Node* getByTitle(const Cantera::XML_Node& node, const std::string &title) {
00370     XML_Node* s = node.findByAttr("title", title);
00371     if (!s) return 0;
00372     if (s->parent() == &node) {
00373       return s;
00374     }
00375     return 0;
00376   }
00377 
00378   //  This function reads a child node with the name string and returns
00379   //  its xml value as the return string
00380   /*
00381    *   If the child XML_node named "name" doesn't exist, the empty string is returned.
00382    *  
00383    * Code snipet:
00384    *       @verbatum
00385    const XML_Node &parent;
00386    string name = "vacency_species";
00387    string valueString = getChildValue(parent, name
00388    std::string typeString);
00389    @endverbatum
00390    *
00391    *  returns valueString = "O(V)"
00392    * 
00393    *  from the following the snippet in the XML file:
00394    *
00395    *  @verbatum
00396    <vacencySpecies>
00397    O(V)
00398    <\vancencySpecies>
00399    @endverbatum
00400    *
00401    *   @param parent   parent reference to the XML_Node object of the parent XML element
00402    *   @param name     Name of the childe XML_Node to read the value from.
00403    *
00404    *   @return         String value of the child XML_Node
00405    */
00406   std::string getChildValue(const Cantera::XML_Node& parent, const std::string &nameString) {
00407     if (!parent.hasChild(nameString)) return "";
00408     return parent(nameString);
00409   }
00410 
00411   //  This function reads a child node with the name, "string", with a specific
00412   //  title attribute named "titleString"
00413   /* 
00414    *   This function will read a child node to the current XML node, with the
00415    *   name "string". It must have a title attribute, named titleString, and the body
00416    *   of the XML node will be read into the valueString output argument.
00417    *
00418    *  Example:  
00419    *
00420    * Code snipet:
00421    *       @verbatum
00422    const XML_Node &node;
00423    getString(XML_Node& node, std::string titleString, std::string valueString, 
00424    std::string typeString);
00425    @endverbatum
00426    *
00427    *  Reads the following the snippet in the XML file:
00428    *  @verbatum
00429    <string title="titleString" type="typeString">
00430      valueString
00431    <\string>
00432    @endverbatum
00433    *
00434    *   @param node          reference to the XML_Node object of the parent XML element
00435    *   @param titleString   String name of the title attribute of the child node
00436    *   @param valueString   Value string that is found in the child node. output variable
00437    *   @param typeString    String type. This is an optional output variable
00438    */
00439   void getString(const Cantera::XML_Node& node, const std::string &titleString, std::string& valueString, 
00440                  std::string& typeString) {
00441     valueString = "";
00442     typeString = "";
00443     XML_Node* s = getByTitle(node, titleString);
00444     if (s) 
00445       if (s->name() == "string") {
00446         valueString = (*s).value();
00447         typeString = (*s)["type"];
00448         return;
00449       }
00450   }
00451 
00452 
00453   //  Get a vector of integer values from a child element. 
00454   /* 
00455    *  Returns a std::map containing a keyed values for child XML_Nodes
00456    *  of the current node with the name, "integer". 
00457    *  In the keyed mapping there will be a list of titles vs. values
00458    *  for all of the XML nodes. 
00459    *  The integer XML_nodes are expected to be in a particular form created
00460    *  by the function addInteger(). One value per XML_node is expected.
00461    *  
00462    *
00463    *  Example:  
00464    *
00465    * Code snipet:
00466    *       @verbatum
00467      const XML_Node &State_XMLNode;
00468      std::map<std::string, integer> v;
00469      getinteger(State_XMLNode, v);
00470    @endverbatum
00471    *
00472    *  reads the corresponding XML file:
00473    *
00474    *  @verbatum
00475    <state>
00476      <integer title="i1">   1  <\integer>
00477      <integer title="i2">   2  <\integer>
00478      <integer title="i3">   3  <\integer>
00479    <\state>
00480    @endverbatum
00481    *
00482    *  Will produce the mapping:
00483    *
00484    *         v["i1"] = 1
00485    *         v["i2"] = 2
00486    *         v["i3"] = 3
00487    *
00488    *
00489    *   @param node     Current XML node to get the values from
00490    *   @param v        Output map of the results.
00491    */
00492   void getIntegers(const Cantera::XML_Node& node,
00493                    std::map<std::string, int>& v) {
00494     std::vector<XML_Node*> f;
00495     node.getChildren("integer",f);
00496     int n = static_cast<int>(f.size());
00497     integer x, x0, x1;
00498     std::string typ, title, vmin, vmax;
00499     for (int i = 0; i < n; i++) {
00500       const XML_Node& fi = *(f[i]);
00501       x = atoi(fi().c_str());
00502       title = fi["title"];
00503       vmin = fi["min"];
00504       vmax = fi["max"];
00505       if (vmin != "")
00506         x0 = atoi(vmin.c_str());
00507       if (fi["max"] != "")
00508         x1 = atoi(vmax.c_str());
00509       v[title] = x;
00510     }
00511   }
00512 
00513 
00514   //  Get a vector of floating-point values from a child element. 
00515   /* 
00516    *  Returns a std::map containing a keyed values for child XML_Nodes
00517    *  of the current node with the name, "float". 
00518    *  In the keyed mapping there will be a list of titles vs. values
00519    *  for all of the XML nodes. 
00520    *  The float XML_nodes are expected to be in a particular form created
00521    *  by the function addFloat(). One value per XML_node is expected.
00522    *  
00523    *
00524    *  Example:  
00525    *
00526    * Code snipet:
00527    *       @verbatum
00528      const XML_Node &State_XMLNode;
00529      std::map<std::string,double> v;
00530      bool convert = true;
00531      getFloats(State_XMLNode, v, convert);
00532    @endverbatum
00533    *
00534    *  reads the corresponding XML file:
00535    *
00536    *  @verbatum
00537    <state>
00538      <float title="a1" units="m3">   32.4 <\float>
00539      <float title="a2" units="cm3">   1.  <\float>
00540      <float title="a3">             100.  <\float>
00541    <\state>
00542    @endverbatum
00543    *
00544    *  Will produce the mapping:
00545    *
00546    *         v["a1"] = 32.4
00547    *         v["a2"] = 1.0E-6
00548    *         v["a3"] = 100.
00549    *
00550    *
00551    *   @param node     Current XML node to get the values from
00552    *   @param v        Output map of the results.
00553    *   @param convert  Turn on conversion to SI units
00554    */
00555   void getFloats(const Cantera::XML_Node& node, std::map<std::string, double>& v,
00556                  const bool convert) {
00557     std::vector<XML_Node*> f;
00558     node.getChildren("float",f);
00559     int n = static_cast<int>(f.size());
00560     doublereal x, x0, x1, fctr;
00561     std::string typ, title, units, vmin, vmax;
00562     for (int i = 0; i < n; i++) {
00563       const XML_Node& fi = *(f[i]);
00564       x = atof(fi().c_str());
00565       x0 = Undef;
00566       x1 = Undef;
00567       typ = fi["type"];
00568       title = fi["title"];
00569       units = fi["units"];
00570       vmin = fi["min"];
00571       vmax = fi["max"];
00572       if (vmin != "") {
00573         x0 = atof(vmin.c_str());
00574         if (x < x0 - Tiny) {
00575           writelog("\nWarning: value "+fi()+" is below lower limit of "
00576                    +vmin+".\n");
00577         }
00578       }
00579       if (fi["max"] != "") {
00580         x1 = atof(vmax.c_str());
00581         if (x > x1 + Tiny) {
00582           writelog("\nWarning: value "+fi()+" is above upper limit of "
00583                    +vmax+".\n");
00584         }
00585       }
00586       fctr = (convert ? toSI(units) : 1.0); // toSI(typ,units);
00587       v[title] = fctr*x;
00588     }
00589   }
00590 
00591 
00592   //  Get a floating-point value from a child element. 
00593   /* 
00594    *  Returns a double value for the child named 'name' of element 'parent'. If
00595    *  'type' is supplied and matches a known unit type, unit
00596    *  conversion to SI will be done if the child element has an attribute
00597    *  'units'.
00598    *
00599    *  Note, it's an error for the child element not to exist.
00600    *
00601    *  Example:  
00602    *
00603    * Code snipet:
00604    *       @verbatum
00605    const XML_Node &State_XMLNode;
00606    doublereal pres = OneAtm;
00607    if (state_XMLNode.hasChild("pressure")) {
00608    pres = getFloat(State_XMLNode, "pressure", "toSI");
00609    }
00610    @endverbatum
00611    *
00612    *  reads the corresponding XML file:
00613    *  @verbatum
00614    <state>
00615    <pressure units="Pa"> 101325.0 </pressure>
00616    <\state>
00617    @endverbatum
00618    *
00619    *   @param parent reference to the XML_Node object of the parent XML element
00620    *   @param name   Name of the XML child element
00621    *   @param type   String type. Currently known types are "toSI" and "actEnergy",
00622    *                 and "" , for no conversion. The default value is ""
00623    *                 which implies that no conversion is allowed.
00624    */
00625   doublereal getFloat(const Cantera::XML_Node& parent,
00626                       const std::string &name,
00627                       const std::string type) {
00628     if (!parent.hasChild(name)) 
00629       throw CanteraError("getFloat (called from XML Node \"" +
00630                          parent.name() + "\"): ",
00631                          "no child XML element named \"" + name + "\" exists");
00632     const XML_Node& node = parent.child(name);
00633     return getFloatCurrent(node, type);
00634   }
00635 
00636   doublereal getFloatCurrent(const Cantera::XML_Node& node,
00637                              const std::string type) {
00638     doublereal x, x0, x1, fctr = 1.0;
00639     string units, vmin, vmax;
00640     x = atof(node().c_str());
00641     x0 = Undef;
00642     x1 = Undef;
00643     units = node["units"];
00644     vmin = node["min"];
00645     vmax = node["max"];
00646     if (vmin != "") {
00647       x0 = atof(vmin.c_str());
00648       if (x < x0 - Tiny) {
00649         writelog("\nWarning: value "+node()+" is below lower limit of "
00650                  +vmin+".\n");
00651       }
00652     }
00653     if (node["max"] != "") {
00654       x1 = atof(vmax.c_str());
00655       if (x > x1 + Tiny) {
00656         writelog("\nWarning: value "+node()+" is above upper limit of "
00657                  +vmax+".\n");
00658       }
00659     }
00660     // Note, most type's of converters default to toSI() type atm.
00661     // This may change and become more specific in the future.
00662     if (type == "actEnergy" && units != "") {
00663       fctr = actEnergyToSI(units);
00664     } else if (type == "toSI" && units != "") {
00665       fctr = toSI(units);
00666     } else if (type == "temperature" && units != "") {
00667       fctr = toSI(units);
00668     } else if (type == "density" && units != "") {
00669       fctr = toSI(units);
00670     } else if (type == "pressure" && units != "") {
00671       fctr = toSI(units);
00672     } else if (type != "" && units != "") {
00673       fctr = toSI(units);
00674 #ifdef DEBUG_MODE
00675       writelog("\nWarning: conversion toSI() was done on node value "  + node.name() + 
00676                "but wasn't explicity requested. Type was \"" + type + "\"\n");
00677 #endif
00678     }
00679     // Note, below currently produces a lot of output due to transport blocks.
00680     // This needs to be addressed.
00681 #ifdef DEBUG_MODE_MORE
00682     else if (type == "" && units != "") {
00683       writelog("\nWarning: XML node "  + node.name() + 
00684                "has a units attribute, \"" + units + "\","
00685                "but no conversion was done because the getFloat() command didn't have a type\n");
00686     }
00687 #endif
00688     return fctr*x;
00689   }
00690 
00691   
00692   bool getOptionalFloat(const Cantera::XML_Node& parent,
00693                         const std::string &name,
00694                         doublereal &fltRtn,
00695                         const std::string type) {
00696     if (parent.hasChild(name)) {
00697       fltRtn= getFloat(parent, name, type);
00698       return true;
00699     }
00700     return false;
00701   }
00702 
00703   //  Get an optional floating-point value from a child element. 
00704   /* 
00705    *  Returns a doublereal value for the child named 'name' of element 'parent'. If
00706    *  'type' is supplied and matches a known unit type, unit
00707    *  conversion to SI will be done if the child element has an attribute
00708    *  'units'.
00709    *
00710    * 
00711    *
00712    *  Example:  
00713    *
00714    * Code snipet:
00715    *       @verbatim
00716    const XML_Node &State_XMLNode;
00717    doublereal pres = OneAtm;
00718    bool exists = getOptionalFloat(State_XMLNode, "pressure", pres, "toSI");
00719    @endverbatim
00720    *
00721    *  reads the corresponding XML file:
00722    *  @verbatim
00723    <state>
00724      <pressure units="Pa"> 101325.0 </pressure>
00725    <\state>
00726    @endverbatim
00727    *
00728    *   @param parent reference to the XML_Node object of the parent XML element
00729    *   @param name   Name of the XML child element
00730    *   @param fltRtn Float Return. It will be overridden if the XML 
00731    *                 element exists.
00732    *   @param type   String type. Currently known types are "toSI"
00733    *                 and "actEnergy",
00734    *                 and "" , for no conversion. The default value is "",
00735    *                 which implies that no conversion is allowed.
00736    *
00737    * @return returns true if the child element named "name" exists
00738    */
00739   doublereal getFloatDefaultUnits(const Cantera::XML_Node& parent, std::string name,
00740                                   std::string defaultUnits, std::string type) {
00741 
00742     doublereal fctr = 1.0;
00743     if (defaultUnits == "") {
00744       throw CanteraError("getFloatDefaultUnits",
00745                          "need to supply an actual value of defaultUnits"); 
00746     }
00747     if (type == "actEnergy") {
00748       fctr = actEnergyToSI(defaultUnits);
00749     } else if (type == "toSI") {
00750       fctr = toSI(defaultUnits);
00751     } else if (defaultUnits == "temperature") {
00752       fctr = toSI(defaultUnits);
00753     } else if (type == "density") {
00754       fctr = toSI(defaultUnits);
00755     } else if (type == "pressure") {
00756       fctr = toSI(defaultUnits);
00757     } else {
00758       throw CanteraError("getFloatDefaultUnits",
00759                          "type of units must be supplied and understood");
00760     }
00761     doublereal val = getFloat(parent, name, type);
00762     val /= fctr;
00763     return val;
00764   }
00765 
00766   bool getOptionalModel(const Cantera::XML_Node& parent, const std::string nodeName,
00767                         std::string &modelName) {
00768    if (parent.hasChild(nodeName)) {
00769      const XML_Node& node = parent.child(nodeName);
00770      modelName = node["model"];
00771      return true;
00772    }
00773    return false;
00774   }
00775 
00776   //  Get an integer value from a child element. 
00777   /* 
00778    *  Returns an integer value for the child named 'name' of element 'parent'.
00779    *
00780    *  Note, it's an error for the child element not to exist.
00781    *
00782    *  Example:  
00783    *
00784    * Code snipet:
00785    *       @verbatum
00786    const XML_Node &State_XMLNode;
00787    int number = 1;
00788    if (state_XMLNode.hasChild("NumProcs")) {
00789    number = getInteger(State_XMLNode, "numProcs");
00790    }
00791    @endverbatum
00792    *
00793    *  reads the corresponding XML file:
00794    *  @verbatum
00795    <state>
00796    <numProcs> 10 <numProcs/>
00797    <\state>
00798    @endverbatum
00799    *
00800    *   @param parent reference to the XML_Node object of the parent XML element
00801    *   @param name   Name of the XML child element
00802    */
00803   int getInteger(const Cantera::XML_Node& parent, std::string name) {
00804     if (!parent.hasChild(name)) { 
00805       throw CanteraError("getInteger (called from XML Node \"" +
00806                          parent.name() + "\"): ",
00807                          "no child XML element named " + name);
00808     }
00809     const XML_Node& node = parent.child(name);
00810     int x, x0, x1;
00811     string units, vmin, vmax;
00812     x = atoi(node().c_str());
00813     x0 = -9999999;
00814     x1 =  9999999;
00815     vmin = node["min"];
00816     vmax = node["max"];
00817     if (vmin != "") {
00818       x0 = atoi(vmin.c_str());
00819       if (x < x0) {
00820         writelog("\nWarning: value "+node()+" is below lower limit of "
00821                  +vmin+".\n");
00822       }
00823     }
00824     if (node["max"] != "") {
00825       x1 = atoi(vmax.c_str());
00826       if (x > x1) {
00827         writelog("\nWarning: value "+node()+" is above upper limit of "
00828                  +vmax+".\n");
00829       }
00830     }
00831     return x;
00832   }
00833 
00834   //  This function reads the current node or a  child node of the current node
00835   //  with the default name, "floatArray", with a value field
00836   //  consisting of a comma separated list of floats
00837   /*
00838    *   This function will read either the current XML node or a  child node
00839    *   to the current XML node, with the
00840    *   name "floatArray". It will have a title attribute, and the body
00841    *   of the XML node will be filled out with a comma separated list of
00842    *   doublereals.
00843    *     Get an array of floats from the XML Node. The argument field
00844    *   is assumed to consist of an arbitrary number of comma
00845    *   separated floats, with an arbitrary amount of white space
00846    *   separating each field.
00847    *      If the node array has an units attribute field, then
00848    *   the units are used to convert the floats, iff convert is true.
00849    *
00850    *  Example:  
00851    *
00852    * Code snipet:
00853    *       @verbatum
00854      const XML_Node &State_XMLNode;
00855      vector_fp v;
00856      bool convert = true;
00857      unitsString = "";
00858      nodeName="floatArray";
00859      getFloatArray(State_XMLNode, v, convert, unitsString, nodeName);
00860    @endverbatum
00861    *
00862    *  reads the corresponding XML file:
00863    *
00864    *  @verbatum
00865    <state>
00866      <floatArray  units="m3">   32.4, 1, 100. <\floatArray>
00867    <\state>
00868    @endverbatum
00869    *
00870    *  Will produce the vector
00871    *
00872    *         v[0] = 32.4
00873    *         v[1] = 1.0
00874    *         v[2] = 100.
00875    *
00876    *
00877    *   @param  node         XML parent node of the floatArray
00878    *   @param  v            Output vector of floats containing the floatArray information.
00879    *   @param  convert      Conversion to SI is carried out if this boolean is
00880    *                        True. The default is true.
00881    *   @param  unitsString  String name of the type attribute. This is an optional 
00882    *                        parameter. The default is to have an empty string.
00883    *                        The only string that is recognized is actEnergy. 
00884    *                        Anything else has no effect. This affects what
00885    *                        units converter is used.
00886    *   @param  nodeName     XML Name of the XML node to read. 
00887    *                        The default value for the node name is floatArray
00888    *
00889    *   @return              Returns the number of floats read
00890    */
00891   int  getFloatArray(const Cantera::XML_Node& node, Cantera::vector_fp& v, 
00892                      const bool convert, const std::string unitsString,
00893                      const std::string nodeName) {
00894     string::size_type icom;
00895     string numstr;
00896     doublereal dtmp;
00897     string nn = node.name();
00898     const Cantera::XML_Node *readNode = &node;
00899     if (nn != nodeName) { 
00900       vector<Cantera::XML_Node *> ll;  
00901       node.getChildren(nodeName, ll);
00902       if (ll.size() == 0) {
00903         throw CanteraError("getFloatArray",
00904                            "wrong xml element type/name: was expecting "
00905                          + nodeName + "but accessed " + node.name());
00906       } else {
00907         readNode = ll[0];
00908       }
00909     }
00910 
00911     v.clear();
00912     doublereal vmin = Undef, vmax = Undef;
00913 
00914     doublereal funit = 1.0;
00915     /*
00916      * Get the attributes field, units, from the XML node
00917      */
00918     std::string units = (*readNode)["units"];
00919     if (units != "" && convert) {
00920       if (unitsString == "actEnergy" && units != "") {
00921         funit = actEnergyToSI(units);
00922       } else if (unitsString != "" && units != "") {
00923         funit = toSI(units);
00924       }
00925     }
00926 
00927     if ((*readNode)["min"] != "") 
00928       vmin = atofCheck((*readNode)["min"].c_str());
00929     if ((*readNode)["max"] != "") 
00930       vmax = atofCheck((*readNode)["max"].c_str());
00931 
00932     doublereal vv;
00933     std::string val = readNode->value();
00934     while (1 > 0) {
00935       icom = val.find(',');
00936       if (icom != string::npos) {
00937         numstr = val.substr(0,icom);
00938         val = val.substr(icom+1,val.size());
00939         dtmp = atofCheck(numstr.c_str());
00940         v.push_back(dtmp);
00941       }
00942       else {
00943         /*
00944          * This little bit of code is to allow for the
00945          * possibility of a comma being the last 
00946          * item in the value text. This was allowed in
00947          * previous versions of Cantera, even though it
00948          * would appear to be odd. So, we keep the
00949          * possibilty in for backwards compatibility.
00950          */
00951         int nlen = strlen(val.c_str());
00952         if (nlen > 0) {
00953           dtmp = atofCheck(val.c_str());
00954           v.push_back(dtmp);
00955         }
00956         break;
00957       }
00958       vv = v.back();
00959       if (vmin != Undef && vv < vmin - Tiny) {
00960         writelog("\nWarning: value "+fp2str(vv)+
00961                  " is below lower limit of " +fp2str(vmin)+".\n");
00962       }
00963       if (vmax != Undef && vv > vmax + Tiny) {
00964         writelog("\nWarning: value "+fp2str(vv)+
00965                  " is above upper limit of " +fp2str(vmin)+".\n");
00966       }
00967     }
00968     int nv = v.size();
00969     for (int n = 0; n < nv; n++) {
00970       v[n] *= funit;
00971     }
00972     return v.size();
00973   }
00974 
00975   // This routine is used to interpret the value portions of XML
00976   // elements that contain colon separated pairs.
00977   /*
00978    *  These are used, for example, in describing the element 
00979    *  composition of species.
00980    *
00981    *       <atomArray> H:4 C:1 <atomArray>
00982    *
00983    *  The string is first separated into a string vector according
00984    * to the location of white space. Then each string is again
00985    * separated into two parts according to the location of a
00986    * colon in the string. The first part of the string is
00987    * used as the key, while the second part of the string is
00988    * used as the value, in the return map.
00989    * It is an error to not find a colon in each string pair.
00990    *
00991    *  @param node Current node
00992    *  @param m    Output Map containing the pairs of values found
00993    *              in the XML Node
00994    */
00995   void getMap(const Cantera::XML_Node& node, std::map<std::string, std::string>& m) {
00996     std::vector<std::string> v;
00997     getStringArray(node, v);
00998     std::string key, val;
00999     int n = static_cast<int>(v.size());
01000     string::size_type icolon;
01001     for (int i = 0; i < n; i++) {
01002       icolon = v[i].find(":");
01003       if (icolon == string::npos) {
01004         throw CanteraError("getMap","missing colon in map entry ("
01005                            +v[i]+")");
01006       }
01007       key = v[i].substr(0,icolon);
01008       val = v[i].substr(icolon+1, v[i].size());
01009       m[key] = val;
01010     }
01011   }
01012 
01013   // This function interprets the value portion of an XML element
01014   // as a series of "Pairs" separated by white space.
01015   /*
01016    * Each pair consists of nonwhite-space characters.
01017    * The first ":" found in the pair string is used to separate
01018    * the string into two parts. The first part is called the "key"
01019    * The second part is called the "val".
01020    * String vectors of key[i] and val[i] are returned in the
01021    * argument list.
01022    * Warning: No spaces are allowed in each pair. Quotes get included as part
01023    *          of the string.
01024    *   Example: @verbatum
01025        <xmlNode> 
01026           red:112    blue:34
01027           green:banana
01028        </xmlNode> 
01029               @endverbatum
01030    * 
01031    * Returns:
01032    *          key       val
01033    *     0:   "red"     "112"
01034    *     1:   "blue"    "34"
01035    *     2:   "green"   "banana"
01036    *
01037    *
01038    *  @param node             XML Node 
01039    *  @param key              Vector of keys for each entry
01040    *  @param val              Vector of values for each entry
01041    *
01042    *  @return Returns the number of pairs found
01043    */
01044   int getPairs(const Cantera::XML_Node& node, std::vector<std::string>& key, 
01045                 std::vector<std::string>& val) {
01046     vector<string> v;
01047     getStringArray(node, v);
01048     int n = static_cast<int>(v.size());
01049     string::size_type icolon;
01050     for (int i = 0; i < n; i++) {
01051       icolon = v[i].find(":");
01052       if (icolon == string::npos) {
01053         throw CanteraError("getPairs","Missing a colon in the Pair entry ("
01054                            +v[i]+")");
01055       }
01056       key.push_back(v[i].substr(0,icolon));
01057       val.push_back(v[i].substr(icolon+1, v[i].size()));
01058       //cout << "getPairs: " << key.back() << " " << val.back() << endl;
01059     }
01060     return n;
01061   }
01062 
01063   // This function interprets the value portion of an XML element
01064   // as a series of "Matrix ids and entries" separated by white space.
01065   /*
01066    * Each pair consists of nonwhite-space characters.
01067    * The first two ":" found in the pair string is used to separate
01068    * the string into three parts. The first part is called the first
01069    * key. The second part is the second key. Both parts must match
01070    * an entry in the keyString1 and keyString2, respectively,
01071    * in order to provide a location to
01072    * place the object in the matrix.
01073    * The third part is called the value. It is expected to be
01074    * a double. It is translated into a double and placed into the
01075    * correct location in the matrix.
01076    *
01077    * Warning: No spaces are allowed in each triplet. Quotes are part
01078    *          of the string.
01079    *   Example
01080    *         keyString = red, blue, black, green
01081    *    <xmlNode>
01082    *        red:green:112
01083    *        blue:black:3.3E-23
01084    *
01085    *    </xmlNode>
01086    *
01087    * Returns:
01088    *     retnValues(0, 3) = 112
01089    *     retnValues(1, 2) = 3.3E-23
01090    *
01091    *
01092    *  @param node          XML Node containing the information for the matrix
01093    *  @param keyStringRow  Key string for the row
01094    *  @param keyStringCol  Key string for the column entries
01095    *  @param returnValues  Return Matrix.
01096    *  @param convert       If this is true, and if the node has a units 
01097    *                       attribute, then conversion to si units is carried
01098    *                       out. Default is true.
01099    *  @param matrixSymmetric  If true entries are made so that the matrix
01100    *                       is always symmetric. Default is false.
01101    */
01102   void getMatrixValues(const Cantera::XML_Node& node,
01103                        const std::vector<std::string>& keyStringRow,
01104                        const std::vector<std::string>& keyStringCol,
01105                        Cantera::Array2D &retnValues, const bool convert,
01106                        const bool matrixSymmetric) {
01107     int szKey1 = keyStringRow.size();
01108     int szKey2 = keyStringCol.size();
01109     int nrow   = retnValues.nRows();
01110     int ncol   = retnValues.nColumns();
01111     if (szKey1 > nrow) {
01112       throw CanteraError("getMatrixValues", 
01113                          "size of key1 greater than numrows");
01114     }
01115     if (szKey2 > ncol) {
01116       throw CanteraError("getMatrixValues", 
01117                          "size of key2 greater than num cols");
01118     }
01119     if (matrixSymmetric) {
01120       if (nrow != ncol) {
01121         throw CanteraError("getMatrixValues", 
01122                            "nrow != ncol for a symmetric matrix");
01123       }
01124     }
01125 
01126     /*
01127      * Get the attributes field, units, from the XML node
01128      * and determine the conversion factor, funit.
01129      */
01130     doublereal funit = 1.0;
01131     string units = node["units"];
01132     if (units != "" && convert) {
01133       funit = toSI(units);
01134     }
01135         
01136     string key1;
01137     string key2;
01138     string rmm;
01139     string val;
01140     vector<string> v;
01141     getStringArray(node, v);
01142     int icol, irow;
01143     int n = static_cast<int>(v.size());
01144     string::size_type icolon;
01145     for (int i = 0; i < n; i++) {
01146       icolon = v[i].find(":");
01147       if (icolon == string::npos) {
01148         throw CanteraError("getMatrixValues","Missing two colons ("
01149                            +v[i]+")");
01150       }
01151       key1 = v[i].substr(0,icolon);
01152       rmm = v[i].substr(icolon+1, v[i].size());
01153       icolon = rmm.find(":");
01154       if (icolon == string::npos) {
01155         throw CanteraError("getMatrixValues","Missing one colon ("
01156                            +v[i]+")");
01157       }
01158       key2 = rmm.substr(0,icolon);
01159       val = rmm.substr(icolon+1, rmm.size());
01160       icol = -1;
01161       irow = -1;
01162       for (int j = 0; j < szKey1; j++) {
01163         if (key1 == keyStringRow[j]) {
01164           irow = j;
01165           break;
01166         }
01167       }
01168       if (irow == -1) {
01169         throw CanteraError("getMatrixValues","Row not matched by string: "
01170                            + key1);             
01171       }
01172       for (int j = 0; j < szKey2; j++) {
01173         if (key2 == keyStringCol[j]) {
01174           icol = j;
01175           break;
01176         }
01177       }
01178       if (icol == -1) {
01179         throw CanteraError("getMatrixValues","Col not matched by string: "
01180                            + key2);     
01181       }
01182       double dval = atofCheck(val.c_str());
01183       dval *= funit;
01184       /*
01185        * Finally, insert the value;
01186        */
01187       retnValues(irow, icol) = dval;
01188       if (matrixSymmetric) {
01189         retnValues(icol, irow) = dval;
01190       }
01191     }
01192   }
01193 
01194   // This function interprets the value portion of an XML element
01195   // as a string. It then separates the string up into tokens
01196   // according to the location of white space.
01197   /*
01198    * The separate tokens are returned in the string vector
01199    *
01200    * @param node   Node to get the value from
01201    * @param v      Output vector containing the string tokens 
01202    */
01203   void getStringArray(const Cantera::XML_Node& node, std::vector<std::string>& v) {
01204     std::string val = node.value();
01205     tokenizeString(val, v);
01206   }
01207 
01208   //  This function reads a child node with the default name, "floatArray", with a value
01209   //  consisting of a comma separated list of floats
01210   /*
01211    *   This function will read a child node to the current XML node, with the
01212    *   name "floatArray". It will have a title attribute, and the body
01213    *   of the XML node will be filled out with a comma separated list of
01214    *   doublereals.
01215    *     Get an array of floats from the XML Node. The argument field
01216    *   is assumed to consist of an arbitrary number of comma
01217    *   separated floats, with an arbitrary amount of white space
01218    *   separating each field.
01219    *      If the node array has an units attribute field, then
01220    *   the units are used to convert the floats, iff convert is true.
01221    *
01222    *  Example:  
01223    *
01224    * Code snipet:
01225    *       @verbatum
01226      const XML_Node &State_XMLNode;
01227      vector_fp v;
01228      bool convert = true;
01229      unitsString = "";
01230      nodeName="floatArray";
01231      getFloatArray(State_XMLNode, v, convert, unitsString, nodeName);
01232    @endverbatum
01233    *
01234    *  reads the corresponding XML file:
01235    *
01236    *  @verbatum
01237    <state>
01238      <floatArray  units="m3">   32.4, 1, 100. <\floatArray>
01239    <\state>
01240    @endverbatum
01241    *
01242    *  Will produce the vector
01243    *
01244    *         v[0] = 32.4
01245    *         v[1] = 1.0
01246    *         v[2] = 100.
01247    *
01248    *
01249    *   @param  node         XML parent node of the floatArray
01250    *   @param  v            Output vector of floats containing the floatArray information.
01251    *   @param  convert      Conversion to SI is carried out if this boolean is
01252    *                        True. The default is true.
01253    *   @param  typeString   String name of the type attribute. This is an optional 
01254    *                        parameter. The default is to have an empty string.
01255    *                        The only string that is recognized is actEnergy. 
01256    *                        Anything else has no effect. This affects what
01257    *                        units converter is used.
01258    *   @param  nodeName     XML Name of the XML node to read. 
01259    *                        The default value for the node name is floatArray
01260    */
01261   void getFunction(const Cantera::XML_Node& node, std::string& type, doublereal& xmin,
01262                    doublereal& xmax, Cantera::vector_fp& coeffs) {
01263     const XML_Node& c = node.child("floatArray");
01264     coeffs.clear();
01265     getFloatArray(c,coeffs);
01266     xmin = Cantera::Undef;
01267     xmin = Cantera::Undef;
01268     if (node["min"] != "") xmin = fpValue(node["min"]);
01269     if (node["max"] != "") xmax = fpValue(node["max"]);
01270     type = node["type"];
01271   }
01272 }
Generated by  doxygen 1.6.3