From 675df76b1c07f90c0d4e69275396ce7eb6cf6366 Mon Sep 17 00:00:00 2001 From: Harry Moffat Date: Tue, 20 May 2014 19:02:20 +0000 Subject: [PATCH] Fixed a long standing problem with the combination of storred XML files and duplicator functions. Now the complete XML file is storred within the ThermPhase object starting with the root node. This is needed for later processing of kinetics and transport mechanisms when the ThermoPhase file is duplicated and the original file is deleted. xml() is now a const function, and still returns the same pointer. setXMLdata() is a new function will stores the xml data. --- include/cantera/kinetics/InterfaceKinetics.h | 2 - include/cantera/thermo/Phase.h | 35 ++++++++++---- src/base/xml.cpp | 8 ++-- src/kinetics/InterfaceKinetics.cpp | 2 +- src/kinetics/importKinetics.cpp | 10 ++-- src/thermo/HMWSoln_input.cpp | 4 +- src/thermo/IonsFromNeutralVPSSTP.cpp | 5 +- src/thermo/Phase.cpp | 49 +++++++++++++++++--- src/thermo/ThermoFactory.cpp | 4 +- test_problems/SConscript | 1 + 10 files changed, 86 insertions(+), 34 deletions(-) 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