diff --git a/include/cantera/thermo/IonsFromNeutralVPSSTP.h b/include/cantera/thermo/IonsFromNeutralVPSSTP.h index cb4ae512c9..fb9c0eb429 100644 --- a/include/cantera/thermo/IonsFromNeutralVPSSTP.h +++ b/include/cantera/thermo/IonsFromNeutralVPSSTP.h @@ -291,6 +291,7 @@ class IonsFromNeutralVPSSTP : public GibbsExcessVPSSTP virtual void initThermo(); virtual void initThermoXML(XML_Node& phaseNode, const std::string& id); + virtual void setParametersFromXML(const XML_Node& thermoNode); private: //! Initialize lengths of local variables after all species have diff --git a/src/thermo/IonsFromNeutralVPSSTP.cpp b/src/thermo/IonsFromNeutralVPSSTP.cpp index d6c6489eae..fba0f4244b 100644 --- a/src/thermo/IonsFromNeutralVPSSTP.cpp +++ b/src/thermo/IonsFromNeutralVPSSTP.cpp @@ -532,6 +532,29 @@ static double factorOverlap(const std::vector& elnamesVN , } return fMax; } + +void IonsFromNeutralVPSSTP::setParametersFromXML(const XML_Node& thermoNode) +{ + GibbsExcessVPSSTP::setParametersFromXML(thermoNode); + // Find the Neutral Molecule Phase + if (!thermoNode.hasChild("neutralMoleculePhase")) { + throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML", + "no neutralMoleculePhase XML node"); + } + XML_Node& neutralMoleculeNode = thermoNode.child("neutralMoleculePhase"); + + XML_Node* neut_ptr = get_XML_Node(neutralMoleculeNode["datasrc"], 0); + if (!neut_ptr) { + throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML", + "neut_ptr = 0"); + } + + // Create the neutralMolecule ThermoPhase if we haven't already + if (!neutralMoleculePhase_) { + neutralMoleculePhase_ = newPhase(*neut_ptr); + } +} + void IonsFromNeutralVPSSTP::initThermoXML(XML_Node& phaseNode, const std::string& id_) { if (id_.size() > 0 && phaseNode.id() != id_) { @@ -553,24 +576,6 @@ void IonsFromNeutralVPSSTP::initThermoXML(XML_Node& phaseNode, const std::string + thermoNode["model"]); } - // Find the Neutral Molecule Phase - if (!thermoNode.hasChild("neutralMoleculePhase")) { - throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML", - "no neutralMoleculePhase XML node"); - } - XML_Node& neutralMoleculeNode = thermoNode.child("neutralMoleculePhase"); - - XML_Node* neut_ptr = get_XML_Node(neutralMoleculeNode["datasrc"], 0); - if (!neut_ptr) { - throw CanteraError("IonsFromNeutralVPSSTP::initThermoXML", - "neut_ptr = 0"); - } - - // Create the neutralMolecule ThermoPhase if we haven't already - if (!neutralMoleculePhase_) { - neutralMoleculePhase_ = newPhase(*neut_ptr); - } - cationList_.clear(); for (size_t k = 0; k < m_kk; k++) { if (charge(k) > 0) { diff --git a/src/thermo/SpeciesThermoFactory.cpp b/src/thermo/SpeciesThermoFactory.cpp index a19ff40cf7..85cff86cdb 100644 --- a/src/thermo/SpeciesThermoFactory.cpp +++ b/src/thermo/SpeciesThermoFactory.cpp @@ -379,6 +379,14 @@ static SpeciesThermoInterpType* newAdsorbateThermoFromXML(const XML_Node& f) SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& thermo) { + std::string model = ba::to_lower_copy(thermo["model"]); + if (model == "hkft" || model == "ionfromneutral") { + // Some PDSS species use the 'thermo' node, but don't specify a + // SpeciesThermoInterpType parameterization. This function needs to + // just ignore this data. + return 0; + } + // Get the children of the thermo XML node. In the next bit of code we take // out the comments that may have been children of the thermo XML node by // doing a selective copy. These shouldn't interfere with the algorithm at @@ -408,7 +416,6 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& thermo) "Too many regions in thermo parameterization."); } - std::string model = ba::to_lower_copy(thermo["model"]); if (model == "mineraleq3") { if (thermoType != "mineq3") { throw CanteraError("newSpeciesThermoInterpType", @@ -427,11 +434,6 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& thermo) return newNasa9ThermoFromXML(tp); } else if (thermoType == "adsorbate") { return newAdsorbateThermoFromXML(*tp[0]); - } else if (model == "hkft" || model == "ionfromneutral") { - // Some PDSS species use the 'thermo' node, but don't specify a - // SpeciesThermoInterpType parameterization. This function needs to just - // ignore this data. - return 0; } else { throw CanteraError("newSpeciesThermoInterpType", "Unknown species thermo model '" + thermoType + "'."); diff --git a/test/data/mock_ion.xml b/test/data/mock_ion.xml new file mode 100644 index 0000000000..4a4f7ad384 --- /dev/null +++ b/test/data/mock_ion.xml @@ -0,0 +1,81 @@ + + + + + + + + K Cl + + + K+ Cl- + + + + + + + + + + + + + K Cl + + + KCl(L) + + + + + + + + + + + + + + K:1 + 1 + + + + KCl(L):1.2 + + + 0.0 + + + + Cl:1 + -1 + + + + + KCl(L):1.5 + + + 0.0 + + + + K:1 Cl:1 + + + + 73.59698, 0.0, 0.0, + 0.0, 0.0, -443.7341, + 175.7209 + + + + + 37.57 + + + + diff --git a/test/thermo/phaseConstructors.cpp b/test/thermo/phaseConstructors.cpp index b9ff67806e..4a50a2e9f8 100644 --- a/test/thermo/phaseConstructors.cpp +++ b/test/thermo/phaseConstructors.cpp @@ -4,6 +4,7 @@ #include "cantera/thermo/PureFluidPhase.h" #include "cantera/thermo/WaterSSTP.h" #include "cantera/thermo/RedlichKwongMFTP.h" +#include "cantera/thermo/IonsFromNeutralVPSSTP.h" #include "cantera/thermo/NasaPoly2.h" #include "cantera/thermo/ShomatePoly.h" #include "cantera/thermo/IdealGasPhase.h" @@ -37,6 +38,15 @@ TEST_F(FixedChemPotSstpConstructorTest, SimpleConstructor) ASSERT_DOUBLE_EQ(-2.3e7, mu); } +TEST(IonsFromNeutralConstructor, fromXML) +{ + std::unique_ptr p(newPhase("../data/mock_ion.xml", + "mock_ion_phase")); + ASSERT_EQ((int) p->nSpecies(), 2); + vector_fp mu(p->nSpecies()); + p->getPartialMolarEnthalpies(mu.data()); +} + #ifndef HAS_NO_PYTHON // skip these tests if the Python converter is unavailable class CtiConversionTest : public testing::Test {