diff --git a/Cantera/src/base/ctml.cpp b/Cantera/src/base/ctml.cpp index a4856bbff..2305aa6a7 100644 --- a/Cantera/src/base/ctml.cpp +++ b/Cantera/src/base/ctml.cpp @@ -125,8 +125,13 @@ namespace ctml { */ void addInteger(Cantera::XML_Node& node, const std::string &title, const int val, const std::string units, const std::string type) { - XML_Node& f = node.addChild("integer",val); - f.addAttribute("title",title); +#ifdef CTML_VERSION_1_4 + XML_Node& f = node.addChild("integer", val); + f.addAttribute("title", title); +#else + XML_Node& f = node.addChild(title, val); +#endif + f.addAttribute("vtype", "integer"); if (type != "") f.addAttribute("type",type); if (units != "") f.addAttribute("units",units); } @@ -195,10 +200,17 @@ namespace ctml { else if (i > 0 && (i+1) % 3 == 0) v += ",\n"; else v += ", "; } - XML_Node& f = node.addChild("intArray",v); +#ifdef CTML_VERSION_1_4 + XML_Node& f = node.addChild("intArray",v); f.addAttribute("title",title); +#else + XML_Node& f = node.addChild(title, v); +#endif if (type != "") f.addAttribute("type",type); f.addAttribute("size",n); +#ifndef CTML_VERSION_1_4 + f.addAttribute("vtype", "intArray"); +#endif if (units != "") f.addAttribute("units",units); if (minval != Undef) f.addAttribute("min",minval); if (maxval != Undef) f.addAttribute("max",maxval); @@ -252,13 +264,14 @@ namespace ctml { const doublereal maxval) { string fmt = "%17.9E"; #ifdef CTML_VERSION_1_4 - XML_Node& f = node.addChild("float",val,fmt); - f.addAttribute("title",title); + XML_Node& f = node.addChild("float", val, fmt); + f.addAttribute("title", title); #else - XML_Node& f = node.addChild(title,val,fmt); + XML_Node& f = node.addChild(title, val, fmt); #endif if (type != "") f.addAttribute("type",type); if (units != "") f.addAttribute("units",units); + f.addAttribute("vtype", "float"); if (minval != Undef) f.addAttribute("min",minval); if (maxval != Undef) f.addAttribute("max",maxval); } @@ -300,7 +313,7 @@ namespace ctml { * @param unitsString String name of the Units attribute. This is an optional * parameter. The default is to * have an empty string. - * @param typeString String type. This is an optional parameter. The default + * @param type String type. This is an optional parameter. The default * is to have an empty string. * @param minval Minimum allowed value of the int. This is an optional * parameter. The default is the @@ -337,6 +350,87 @@ namespace ctml { if (maxval != Undef) f.addAttribute("max",maxval); } //==================================================================================================================== + // This function adds a child node with the name given by the first parameter with a value + // consisting of a comma separated list of floats + /* + * This function will add a child node to the current XML node, with the + * name given in the list. It will have a title attribute, and the body + * of the XML node will be filled out with a comma separated list of + * integers + * + * Example: + * + * Code snipet: + * @verbatum + const XML_Node &node; + std::string titleString = "additionalTemperatures"; + int n = 3; + int Tcases[3] = [273.15, 298.15, 373.15]; + std::string typeString = "optional"; + std::string units = "Kelvin"; + addNamedFloatArray(node, titleString, n, &cases[0], typeString, units); + @endverbatum + * + * Creates the following the snippet in the XML file: + * @verbatum + + + 273.15, 298.15, 373.15 + <\additionalTemperatures> + <\parentNode> + @endverbatum + * + * @param node reference to the XML_Node object of the parent XML element + * @param name Name of the XML node + * @param n Length of the doubles vector. + * @param values Pointer to a vector of doubles + * @param unitsString String name of the Units attribute. This is an optional + * parameter. The default is to + * have an empty string. + * @param type String type. This is an optional parameter. The default + * is to have an empty string. + * @param minval Minimum allowed value of the int. This is an optional + * parameter. The default is the + * special double, Cantera::Undef, which means to ignore the + * entry. + * @param maxval Maximum allowed value of the int. This is an optional + * parameter. The default is the + * special double, Cantera::Undef, which means to ignore the + * entry. + * + * @todo I don't think this is used. Figure out what is used for writing integers, + * and codify that. unitsString shouldn't be here, since it's an int. + * typeString should be codified as to its usage. + */ + void addNamedFloatArray(Cantera::XML_Node& node, const std::string &name, const int n, + const doublereal* const vals, const std::string units, + const std::string type, const doublereal minval, + const doublereal maxval) { + std::string fmt = "%17.9E"; + int i; + std::string v = ""; + for (i = 0; i < n; i++) { + v += fp2str(vals[i],fmt); + if (i == n-1) v += "\n"; + else if (i > 0 && (i+1) % 3 == 0) v += ",\n"; + else v += ", "; + } + XML_Node& f = node.addChild(name, v); + if (type != "") { + f.addAttribute("type",type); + } + /* + * Add vtype, which indicates the type of the value. Here we specify it as a list of floats separated + * by commas, with a length given by size attribute. + */ + f.addAttribute("vtype", "floatArray"); + + f.addAttribute("size", n); + if (units != "") f.addAttribute("units", units); + if (minval != Undef) f.addAttribute("min", minval); + if (maxval != Undef) f.addAttribute("max", maxval); + } + //==================================================================================================================== // This function adds a child node with the name string with a string value // to the current node /* @@ -1114,6 +1208,96 @@ namespace ctml { return v.size(); } //==================================================================================================================== + int getNamedFloatArray(const Cantera::XML_Node& parentNode, const std::string & nodeName, std::vector & v, + const bool convert, const std::string unitsString) { + std::string::size_type icom; + std::string numstr; + doublereal dtmp; + std::string nn = parentNode.name(); + v.clear(); + const Cantera::XML_Node *readNode = parentNode.findByName(nodeName); + if (!readNode) { + return 0; + } + + doublereal vmin = Undef; + doublereal vmax = Undef; + doublereal funit = 1.0; + /* + * Get the attributes field, units, from the XML node + */ + std::string units = (*readNode)["units"]; + if (units != "" && convert) { + if (unitsString == "actEnergy" && units != "") { + funit = actEnergyToSI(units); + } else if (unitsString != "" && units != "") { + funit = toSI(units); + } + } + + if ((*readNode)["min"] != "") + vmin = atofCheck((*readNode)["min"].c_str()); + if ((*readNode)["max"] != "") + vmax = atofCheck((*readNode)["max"].c_str()); + + int expectedSize = 0; + nn = (*readNode)["size"]; + expectedSize = atoi(nn.c_str()); + + nn = (*readNode)["vtype"]; + if (nn != "floatArray") { + throw CanteraError("getNamedFloatArray", + "node named " + nodeName + "didn't have correct vtype"); + } + + doublereal vv; + std::string val = readNode->value(); + while (1 > 0) { + icom = val.find(','); + if (icom != string::npos) { + numstr = val.substr(0,icom); + val = val.substr(icom+1,val.size()); + dtmp = atofCheck(numstr.c_str()); + v.push_back(dtmp); + } + else { + /* + * This little bit of code is to allow for the + * possibility of a comma being the last + * item in the value text. This was allowed in + * previous versions of Cantera, even though it + * would appear to be odd. So, we keep the + * possibilty in for backwards compatibility. + */ + int nlen = strlen(val.c_str()); + if (nlen > 0) { + dtmp = atofCheck(val.c_str()); + v.push_back(dtmp); + } + break; + } + vv = v.back(); + if (vmin != Undef && vv < vmin - Tiny) { + writelog("\nWarning: value "+fp2str(vv)+ + " is below lower limit of " +fp2str(vmin)+".\n"); + } + if (vmax != Undef && vv > vmax + Tiny) { + writelog("\nWarning: value "+fp2str(vv)+ + " is above upper limit of " +fp2str(vmin)+".\n"); + } + } + int nv = v.size(); + for (int n = 0; n < nv; n++) { + v[n] *= funit; + } + if (nv != expectedSize) { + throw CanteraError("getNamedFloatArray", + "node named " + nodeName + "didn't have correct number of floats" + + int2str(expectedSize) + " vs " + int2str(nv)); + } + return nv; + } + //==================================================================================================================== // This routine is used to interpret the value portions of XML // elements that contain colon separated pairs. /* diff --git a/Cantera/src/base/ctml.h b/Cantera/src/base/ctml.h index bd0614b16..434e5fa02 100644 --- a/Cantera/src/base/ctml.h +++ b/Cantera/src/base/ctml.h @@ -282,6 +282,15 @@ namespace ctml { const doublereal minval = Cantera::Undef, const doublereal maxval = Cantera::Undef); + void addNamedFloatArray(Cantera::XML_Node& parentNode, const std::string &name, const int n, + const doublereal* const vals, const std::string units = "", + const std::string type = "", + const doublereal minval = Cantera::Undef, + const doublereal maxval = Cantera::Undef); + + + + //! This function adds a child node with the name string with a string value //! to the current node /*! diff --git a/Cantera/src/base/units.h b/Cantera/src/base/units.h index bf81f8820..ac988cb23 100644 --- a/Cantera/src/base/units.h +++ b/Cantera/src/base/units.h @@ -216,6 +216,7 @@ namespace Cantera { // temperature m_u["K"] = 1.0; m_u["C"] = 1.0; + m_u["Kelvin"] = 1.0; // mass m_u["gm"] = 1.0e-3; @@ -233,6 +234,11 @@ namespace Cantera { m_u["hr"] = 3600.0; m_u["ms"] = 0.001; + // electric potential + m_u["volt"] = 1.0; + + // charge + m_u["coulomb"] = 1.0; /* // frequency - Took frequency out to reevaluate it. Inverse cm is probably the wrong default unit diff --git a/Cantera/src/base/xml.cpp b/Cantera/src/base/xml.cpp index e5cb9aa94..0db1dc8f3 100644 --- a/Cantera/src/base/xml.cpp +++ b/Cantera/src/base/xml.cpp @@ -539,7 +539,7 @@ namespace Cantera { XML_Node& XML_Node::mergeAsChild(XML_Node& node) { m_children.push_back(&node); m_nchildren = static_cast(m_children.size()); - m_childindex[node.name()] = m_children.back(); + m_childindex.insert(pair(node.name(), m_children.back())); node.setRoot(root()); node.setParent(this); return *m_children.back(); @@ -559,7 +559,7 @@ namespace Cantera { XML_Node *xx = new XML_Node(node); m_children.push_back(xx); m_nchildren = static_cast(m_children.size()); - m_childindex[xx->name()] = m_children.back(); + m_childindex.insert( pair(xx->name(), xx)); xx->setRoot(root()); xx->setParent(this); return *m_children.back(); @@ -578,7 +578,7 @@ namespace Cantera { XML_Node *xxx = new XML_Node(sname, this); m_children.push_back(xxx); m_nchildren = static_cast(m_children.size()); - m_childindex[sname] = m_children.back(); + m_childindex.insert(pair(sname, xxx)); xxx->setRoot(root()); xxx->setParent(this); return *m_children.back(); @@ -1098,15 +1098,17 @@ namespace Cantera { * * @return Returns the pointer to the XML node that fits the criteria */ - XML_Node* XML_Node::findByName(const std::string& nm) { + XML_Node* XML_Node::findByName(const std::string& nm, int depth) { if (name() == nm) { return this; } - XML_Node* r = 0; - int n = nChildren(); - for (int i = 0; i < n; i++) { - r = m_children[i]->findByName(nm); - if (r != 0) return r; + if (depth > 0) { + XML_Node* r = 0; + int n = nChildren(); + for (int i = 0; i < n; i++) { + r = m_children[i]->findByName(nm); + if (r != 0) return r; + } } return 0; } @@ -1122,15 +1124,17 @@ namespace Cantera { * * @return Returns the pointer to the XML node that fits the criteria */ - const XML_Node* XML_Node::findByName(const std::string& nm) const { + const XML_Node* XML_Node::findByName(const std::string& nm, int depth) const { if (name() == nm) { return const_cast(this); } - const XML_Node* r = 0; - int n = nChildren(); - for (int i = 0; i < n; i++) { - r = m_children[i]->findByName(nm); - if (r != 0) return r; + if (depth > 0) { + const XML_Node* r = 0; + int n = nChildren(); + for (int i = 0; i < n; i++) { + r = m_children[i]->findByName(nm); + if (r != 0) return r; + } } return 0; } diff --git a/Cantera/src/base/xml.h b/Cantera/src/base/xml.h index 890470fe9..b81fe6c00 100644 --- a/Cantera/src/base/xml.h +++ b/Cantera/src/base/xml.h @@ -156,6 +156,10 @@ namespace Cantera { class XML_Node { public: + //! Value_type for the lookup multimap m_childindex. This is a convenience definition + //! for manipulating the multimap + typedef std::pair CIPair; + //! Default constructor for XML_Node, representing a tree structure /*! * Constructor for an XML_Node, which is a node in a tree-like structure @@ -621,10 +625,12 @@ namespace Cantera { * This is the const version of the routine. * * @param nm Name of the XML node + * @param depth Depth of the search. A value of 1 means that only the + * immediate children are searched. * * @return Returns the pointer to the XML node that fits the criteria */ - const XML_Node* findByName(const std::string& nm) const; + const XML_Node* findByName(const std::string& nm, int depth = 100000) const; //! This routine carries out a recursive search for an XML node based //! on the name of the node. @@ -634,10 +640,12 @@ namespace Cantera { * This is the non-const version of the routine. * * @param nm Name of the XML node + * @param depth Depth of the search. A value of 1 means that only the + * immediate children are searched. * * @return Returns the pointer to the XML node that fits the criteria */ - XML_Node* findByName(const std::string& nm); + XML_Node* findByName(const std::string& nm, int depth = 100000); //! Get a vector of pointers to XML_Node containing all of the children //! of the current node which matches the input name @@ -649,9 +657,11 @@ namespace Cantera { */ void getChildren(const std::string &name, std::vector& children) const; - //! Return a changeable reference to a child of the current node, - //! named by the argument + //! Return a changeable reference to a child of the current node, named by the argument /*! + * Note the underlying data allows for more than one XML element with the same name. + * This routine returns the first child with the given name. + * * @param loc Name of the child to return */ XML_Node& child(const std::string &loc) const; @@ -782,9 +792,10 @@ namespace Cantera { /*! * m_childindex[node.name()] = XML_Node *pointer * - * This object helps to speed up searches + * This object helps to speed up searches. + * The value_type for this multimap is CIPair. */ - std::map m_childindex; + std::multimap m_childindex; //! Storage of attributes for a node /*!