diff --git a/include/cantera/kinetics/InterfaceKinetics.h b/include/cantera/kinetics/InterfaceKinetics.h index 98b57cc23..3b3258c19 100644 --- a/include/cantera/kinetics/InterfaceKinetics.h +++ b/include/cantera/kinetics/InterfaceKinetics.h @@ -312,9 +312,7 @@ public: * For a reaction rate that was given in units of Amps/m2 (exchange current * density formulation with iECDFormulation == true), convert the rate to * kmoles/m2/s. - * RENAMED THIS METHOD from "apply" to "convert" */ - void convertExchangeCurrentDensityFormulation(doublereal* const kfwd); //! Set the existence of a phase in the reaction object diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index 9012a00cc..989094783 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -111,10 +111,24 @@ public: //! @param right Reference to the class to be used in the copy Phase& operator=(const Phase& right); - //! Returns a reference to the XML_Node stored for the phase. - //! The XML_Node for the phase contains all of the input data used to set - //! up the model for the phase, during its initialization. - XML_Node& xml(); + //! Returns a const reference to the XML_Node that describes the phase. + /*! + * The XML_Node for the phase contains all of the input data used to set + * up the model for the phase during its initialization. + * + */ + XML_Node& xml() const; + + //! Stores the XML tree information for the current phase + /*! + * This function now stores the complete XML_Node tree as read into the code + * via a file. This is needed to move around within the XML tree during + * construction of transport and kinetics mechanisms after copy + * construction operations. + * + * @param xmlPhase Reference to the XML node corresponding to the phase + */ + void setXMLdata(XML_Node& xmlPhase); /*! @name Name and ID * Class Phase contains two strings that identify a phase. The ID is the @@ -122,13 +136,13 @@ public: * initialize a phase when it is read. The name field is also initialized * to the value of the ID attribute of the XML phase node. * - * However, the name field may be changed to another value during the + * However, the name field may be changed to another value during the * course of a calculation. For example, if a phase is located in two - * places, but has the same constitutive input, the ids of the two phases + * places, but has the same constitutive input, the IDs of the two phases * will be the same, but the names of the two phases may be different. * * It is an error to have two phases in a single problem with the same name - * or the same id (or the name from one phase being the same as the id of + * and ID (or the name from one phase being the same as the id of * another phase). Thus, it is expected that there is a 1-1 correspondence * between names and unique phases within a Cantera problem. */ @@ -138,10 +152,15 @@ public: std::string id() const; //! Set the string id for the phase. - //! @param id String id of the phase + /*! + * @param id String id of the phase + */ void setID(const std::string& id); //! Return the name of the phase. + /*! + * Names are unique within a Cantera problem. + */ std::string name() const; //! Sets the string name for the phase. diff --git a/src/base/xml.cpp b/src/base/xml.cpp index 64fc27b47..d53a3f9ef 100644 --- a/src/base/xml.cpp +++ b/src/base/xml.cpp @@ -1101,9 +1101,7 @@ XML_Node* findXMLPhase(XML_Node* root, idattrib = root->id(); if (idtarget == idattrib) { return root; - } else { - return 0; - } + } } const vector &vsc = root->children(); @@ -1121,12 +1119,12 @@ XML_Node* findXMLPhase(XML_Node* root, } for (size_t n = 0; n < root->nChildren(); n++) { sc = vsc[n]; - if (sc->name() != "phase") { + //if (sc->name() != "phase") { scResult = findXMLPhase(sc, idtarget); if (scResult) { return scResult; } - } + //} } return scResult; } diff --git a/src/kinetics/InterfaceKinetics.cpp b/src/kinetics/InterfaceKinetics.cpp index cbd668d06..7d9d14566 100644 --- a/src/kinetics/InterfaceKinetics.cpp +++ b/src/kinetics/InterfaceKinetics.cpp @@ -453,7 +453,7 @@ void InterfaceKinetics::applyButlerVolmerCorrection(doublereal* const kf) } } -/** +/* * For a reaction rate that was given in units of Amps/m2 (exchange current * density formulation with iECDFormulation == true), convert the rate to * kmoles/m2/s. diff --git a/src/kinetics/importKinetics.cpp b/src/kinetics/importKinetics.cpp index e748a3145..612879c88 100644 --- a/src/kinetics/importKinetics.cpp +++ b/src/kinetics/importKinetics.cpp @@ -953,10 +953,12 @@ bool importKinetics(const XML_Node& phase, std::vector th, string owning_phase = phase["id"]; bool check_for_duplicates = false; - if (phase.parent()->hasChild("validate")) { - const XML_Node& d = phase.parent()->child("validate"); - if (d["reactions"] == "yes") { - check_for_duplicates = true; + if (phase.parent()) { + if (phase.parent()->hasChild("validate")) { + const XML_Node& d = phase.parent()->child("validate"); + if (d["reactions"] == "yes") { + check_for_duplicates = true; + } } } diff --git a/src/thermo/HMWSoln_input.cpp b/src/thermo/HMWSoln_input.cpp index 072f1f927..be9c446e9 100644 --- a/src/thermo/HMWSoln_input.cpp +++ b/src/thermo/HMWSoln_input.cpp @@ -990,16 +990,16 @@ void HMWSoln::constructPhaseFile(std::string inputFile, std::string id_) * The phase object automatically constructs an XML object. * Use this object to store information. */ - XML_Node& phaseNode_XML = xml(); XML_Node* fxml = new XML_Node(); fxml->build(fin); XML_Node* fxml_phase = findXMLPhase(fxml, id_); + if (!fxml_phase) { throw CanteraError("HMWSoln:constructPhaseFile", "ERROR: Can not find phase named " + id_ + " in file named " + inputFile); } - fxml_phase->copy(&phaseNode_XML); + setXMLdata(*fxml_phase); constructPhaseXML(*fxml_phase, id_); delete fxml; } diff --git a/src/thermo/IonsFromNeutralVPSSTP.cpp b/src/thermo/IonsFromNeutralVPSSTP.cpp index 16b9393ab..5a7e4c052 100644 --- a/src/thermo/IonsFromNeutralVPSSTP.cpp +++ b/src/thermo/IonsFromNeutralVPSSTP.cpp @@ -213,7 +213,7 @@ void IonsFromNeutralVPSSTP::constructPhaseFile(std::string inputFile, std::strin * The phase object automatically constructs an XML object. * Use this object to store information. */ - XML_Node& phaseNode_XML = xml(); + //XML_Node& phaseNode_XML = xml(); XML_Node* fxml = new XML_Node(); fxml->build(fin); XML_Node* fxml_phase = findXMLPhase(fxml, id_); @@ -222,7 +222,8 @@ void IonsFromNeutralVPSSTP::constructPhaseFile(std::string inputFile, std::strin "ERROR: Can not find phase named " + id_ + " in file named " + inputFile); } - fxml_phase->copy(&phaseNode_XML); + setXMLdata(*fxml_phase); + //fxml_phase->copy(&phaseNode_XML); constructPhaseXML(*fxml_phase, id_); delete fxml; } diff --git a/src/thermo/Phase.cpp b/src/thermo/Phase.cpp index 099aff0bf..88f095c84 100644 --- a/src/thermo/Phase.cpp +++ b/src/thermo/Phase.cpp @@ -46,7 +46,7 @@ Phase::Phase(const Phase& right) : m_elem_type(0) { // Use the assignment operator to do the actual copying - *this = operator=(right); + operator=(right); } Phase& Phase::operator=(const Phase& right) @@ -86,11 +86,23 @@ Phase& Phase::operator=(const Phase& right) * to have our own individual copies of the XML data tree * in each object */ - delete m_xml; - m_xml = 0; + if (m_xml) { + XML_Node* rroot = &(m_xml->root()); + delete rroot; + m_xml = 0; + } if (right.m_xml) { - m_xml = new XML_Node(); - (right.m_xml)->copy(m_xml); + XML_Node *rroot = &(right.m_xml->root()); + XML_Node *root_xml = new XML_Node(); + (rroot)->copy(root_xml); + string iidd = right.m_xml->id(); + m_xml = findXMLPhase(root_xml, iidd); + if (!m_xml) { + throw CanteraError("Phase::operator=()", "Confused: Couldn't find original phase " + iidd); + } + if (&(m_xml->root()) != root_xml) { + throw CanteraError("Phase::operator=()", "confused: root changed"); + } } m_id = right.m_id; m_name = right.m_name; @@ -100,15 +112,38 @@ Phase& Phase::operator=(const Phase& right) Phase::~Phase() { - delete m_xml; + if (m_xml) { + XML_Node* xroot = &(m_xml->root()); + delete xroot; + } m_xml = 0; } -XML_Node& Phase::xml() +XML_Node& Phase::xml() const { return *m_xml; } +void Phase::setXMLdata(XML_Node& xmlPhase) +{ + XML_Node* xroot = &(xmlPhase.root()); + XML_Node *root_xml = new XML_Node(); + (xroot)->copy(root_xml); + std::string iidd = xmlPhase.id(); + if (m_xml) { + XML_Node *rOld = &(m_xml->root()); + delete rOld; + m_xml = 0; + } + m_xml = findXMLPhase(root_xml, iidd); + if (!m_xml) { + throw CanteraError("Phase::setXMLdata()", "confused"); + } + if (&(m_xml->root()) != root_xml) { + throw CanteraError("Phase::setXMLdata()", "confused"); + } +} + std::string Phase::id() const { return m_id; diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 424933e92..37da68aa9 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -333,9 +333,7 @@ bool importPhase(XML_Node& phase, ThermoPhase* th, * we are about to use to construct the object. We will then * be able to resurrect the information later by calling xml(). */ - XML_Node& phaseNode_XML = th->xml(); - phaseNode_XML.clear(); - phase.copy(&phaseNode_XML); + th->setXMLdata(phase); // set the id attribute of the phase to the 'id' attribute in the XML tree. th->setID(phase.id()); diff --git a/test_problems/SConscript b/test_problems/SConscript index 271ddefbc..e560bf784 100644 --- a/test_problems/SConscript +++ b/test_problems/SConscript @@ -41,6 +41,7 @@ class Test(object): self.artifacts = [self.artifacts] self.comparisons = kwargs.get('comparisons') or () self.tolerance = kwargs.get('tolerance') or 1e-5 # error tolerance for CSV comparison + # self.tolerance = kwargs.get('tolerance') or 1e-7 # error tolerance for CSV comparison self.threshold = kwargs.get('threshold') or 1e-14 # error threshold for CSV comparison # ignore lines starting with specified strings when comparing output files