Skip to content

Commit

Permalink
[Thermo] Fix creation of IonsFromNeutralVPSSTP objects
Browse files Browse the repository at this point in the history
Added a mock input file derived from the initialization code in
IonsFromNeutralVPSSTP and PDSS_IonsFromNeutral.
  • Loading branch information
speth committed Feb 23, 2017
1 parent dfb32f0 commit 3a11938
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 24 deletions.
1 change: 1 addition & 0 deletions include/cantera/thermo/IonsFromNeutralVPSSTP.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 23 additions & 18 deletions src/thermo/IonsFromNeutralVPSSTP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,29 @@ static double factorOverlap(const std::vector<std::string>& 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_) {
Expand All @@ -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) {
Expand Down
14 changes: 8 additions & 6 deletions src/thermo/SpeciesThermoFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand All @@ -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 + "'.");
Expand Down
81 changes: 81 additions & 0 deletions test/data/mock_ion.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@

<?xml version="1.0"?>
<ctml>
<validate reactions="yes" species="yes"/>

<phase dim="3" id="mock_ion_phase">
<elementArray datasrc="elements.xml">
K Cl
</elementArray>
<speciesArray datasrc="#species_data">
K+ Cl-
</speciesArray>
<thermo model="IonsFromNeutralMolecule">
<neutralMoleculePhase datasrc="../data/mock_ion.xml#mock_neutral" />
<variablePressureStandardStateManager model="general" />
<standardConc model="constant_volume" />
</thermo>
<transport model="None"/>
<kinetics model="none"/>
</phase>

<phase dim="3" id="mock_neutral">
<elementArray datasrc="elements.xml">
K Cl
</elementArray>
<speciesArray datasrc="#species_data">
KCl(L)
</speciesArray>
<thermo model="Margules">
<standardConc model="constant_volume" />
<activityCoefficients model="Margules" TempModel="constant">
</activityCoefficients>
</thermo>
<transport model="None"/>
<kinetics model="none"/>
</phase>

<!-- species definitions -->
<speciesData id="species_data">
<species name="K+">
<atomArray> K:1 </atomArray>
<charge> 1 </charge>
<standardState model="IonFromNeutral" />
<thermo model="IonFromNeutral">
<neutralSpeciesMultipliers>
KCl(L):1.2
</neutralSpeciesMultipliers>
</thermo>
<density units="g/cm3"> 0.0 </density>
</species>

<species name="Cl-">
<atomArray> Cl:1 </atomArray>
<charge> -1 </charge>
<standardState model="IonFromNeutral" />
<thermo model="IonFromNeutral">
<specialSpecies/>
<neutralSpeciesMultipliers>
KCl(L):1.5
</neutralSpeciesMultipliers>
</thermo>
<density units="g/cm3"> 0.0 </density>
</species>

<species name="KCl(L)">
<atomArray> K:1 Cl:1 </atomArray>
<thermo>
<Shomate Pref="1 bar" Tmax="2000.0" Tmin="700.0">
<floatArray size="7">
73.59698, 0.0, 0.0,
0.0, 0.0, -443.7341,
175.7209
</floatArray>
</Shomate>
</thermo>
<standardState model="constant_incompressible">
<molarVolume units="cm3/gmol"> 37.57 </molarVolume>
</standardState>
</species>
</speciesData>
</ctml>
10 changes: 10 additions & 0 deletions test/thermo/phaseConstructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -37,6 +38,15 @@ TEST_F(FixedChemPotSstpConstructorTest, SimpleConstructor)
ASSERT_DOUBLE_EQ(-2.3e7, mu);
}

TEST(IonsFromNeutralConstructor, fromXML)
{
std::unique_ptr<ThermoPhase> 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
{
Expand Down

0 comments on commit 3a11938

Please sign in to comment.