[Thermo] Allow instantiation of IdealMolalSoln without XML
This commit is contained in:
parent
f8ef4a8b2b
commit
a6ac446021
3 changed files with 108 additions and 76 deletions
|
|
@ -47,14 +47,8 @@ namespace Cantera
|
|||
* ThermoPhase, and overloads the virtual methods defined there with ones that
|
||||
* use expressions appropriate for incompressible mixtures.
|
||||
*
|
||||
* The standard concentrations can have three different forms depending on the
|
||||
* value of the member attribute m_formGC, which is supplied in the XML file.
|
||||
*
|
||||
* | m_formGC | ActivityConc | StandardConc |
|
||||
* | -------- | -------------------------------- | ------------------ |
|
||||
* | 0 | \f$ {m_k}/ { m^{\Delta}}\f$ | \f$ 1.0 \f$ |
|
||||
* | 1 | \f$ m_k / (m^{\Delta} V_k)\f$ | \f$ 1.0 / V_k \f$ |
|
||||
* | 2 | \f$ m_k / (m^{\Delta} V^0_0)\f$ | \f$ 1.0 / V^0_0\f$ |
|
||||
* The standard concentrations can have three different forms.
|
||||
* See setStandardConcentrationModel().
|
||||
*
|
||||
* \f$ V^0_0 \f$ is the solvent standard molar volume. \f$ m^{\Delta} \f$ is a
|
||||
* constant equal to a molality of \f$ 1.0 \quad\mbox{gm kmol}^{-1} \f$.
|
||||
|
|
@ -414,6 +408,24 @@ public:
|
|||
|
||||
virtual void initThermoXML(XML_Node& phaseNode, const std::string& id="");
|
||||
|
||||
virtual void initThermo();
|
||||
|
||||
//! Set the standard concentration model.
|
||||
/*!
|
||||
* Must be one of 'unity', 'molar_volume', or 'solvent_volume'.
|
||||
* The default is 'solvent_volume'.
|
||||
*
|
||||
* | model | ActivityConc | StandardConc |
|
||||
* | -------------- | -------------------------------- | ------------------ |
|
||||
* | unity | \f$ {m_k}/ { m^{\Delta}}\f$ | \f$ 1.0 \f$ |
|
||||
* | molar_volume | \f$ m_k / (m^{\Delta} V_k)\f$ | \f$ 1.0 / V_k \f$ |
|
||||
* | solvent_volume | \f$ m_k / (m^{\Delta} V^0_0)\f$ | \f$ 1.0 / V^0_0\f$ |
|
||||
*/
|
||||
void setStandardConcentrationModel(const std::string& model);
|
||||
|
||||
//! Set cutoff model. Must be one of 'none', 'poly', or 'polyExp'.
|
||||
void setCutoffModel(const std::string& model);
|
||||
|
||||
//! Report the molar volume of species k
|
||||
/*!
|
||||
* units - \f$ m^3 kmol^{-1} \f$
|
||||
|
|
@ -436,19 +448,12 @@ protected:
|
|||
vector_fp m_speciesMolarVolume;
|
||||
|
||||
/**
|
||||
* The standard concentrations can have three different forms depending on
|
||||
* the value of the member attribute m_formGC, which is supplied in the XML
|
||||
* file.
|
||||
*
|
||||
* | m_formGC | ActivityConc | StandardConc |
|
||||
* | -------- | -------------------------------- | ------------------ |
|
||||
* | 0 | \f$ {m_k}/ { m^{\Delta}}\f$ | \f$ 1.0 \f$ |
|
||||
* | 1 | \f$ m_k / (m^{\Delta} V_k)\f$ | \f$ 1.0 / V_k \f$ |
|
||||
* | 2 | \f$ m_k / (m^{\Delta} V^0_0)\f$ | \f$ 1.0 / V^0_0\f$ |
|
||||
* The standard concentrations can have one of three different forms:
|
||||
* 0 = 'unity', 1 = 'molar_volume', 2 = 'solvent_volume'. See
|
||||
* setStandardConcentrationModel().
|
||||
*/
|
||||
int m_formGC;
|
||||
|
||||
public:
|
||||
//! Cutoff type
|
||||
int IMS_typeCutoff_;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "cantera/thermo/IdealMolalSoln.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
#include "cantera/base/ctml.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace Cantera
|
||||
|
|
@ -356,8 +357,7 @@ bool IdealMolalSoln::addSpecies(shared_ptr<Species> spec)
|
|||
|
||||
void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
||||
{
|
||||
// Initialize the whole thermo object, using a virtual function.
|
||||
initThermo();
|
||||
MolalityVPSSTP::initThermoXML(phaseNode, id_);
|
||||
|
||||
if (id_.size() > 0 && phaseNode.id() != id_) {
|
||||
throw CanteraError("IdealMolalSoln::initThermo",
|
||||
|
|
@ -374,20 +374,7 @@ void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
|||
// Possible change the form of the standard concentrations
|
||||
if (thermoNode.hasChild("standardConc")) {
|
||||
XML_Node& scNode = thermoNode.child("standardConc");
|
||||
m_formGC = 2;
|
||||
std::string formString = scNode.attrib("model");
|
||||
if (formString != "") {
|
||||
if (formString == "unity") {
|
||||
m_formGC = 0;
|
||||
} else if (formString == "molar_volume") {
|
||||
m_formGC = 1;
|
||||
} else if (formString == "solvent_volume") {
|
||||
m_formGC = 2;
|
||||
} else {
|
||||
throw CanteraError("IdealMolalSoln::initThermo",
|
||||
"Unknown standardConc model: " + formString);
|
||||
}
|
||||
}
|
||||
setStandardConcentrationModel(scNode["model"]);
|
||||
}
|
||||
|
||||
// Get the Name of the Solvent:
|
||||
|
|
@ -406,7 +393,6 @@ void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
|||
if (thermoNode.hasChild("activityCoefficients")) {
|
||||
XML_Node& acNode = thermoNode.child("activityCoefficients");
|
||||
std::string modelString = acNode.attrib("model");
|
||||
IMS_typeCutoff_ = 0;
|
||||
if (modelString != "IdealMolalSoln") {
|
||||
throw CanteraError("IdealMolalSoln::initThermoXML",
|
||||
"unknown ActivityCoefficient model: " + modelString);
|
||||
|
|
@ -415,15 +401,7 @@ void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
|||
XML_Node& ccNode = acNode.child("idealMolalSolnCutoff");
|
||||
modelString = ccNode.attrib("model");
|
||||
if (modelString != "") {
|
||||
if (modelString == "polyExp") {
|
||||
IMS_typeCutoff_ = 2;
|
||||
} else if (modelString == "poly") {
|
||||
IMS_typeCutoff_ = 1;
|
||||
} else {
|
||||
throw CanteraError("IdealMolalSoln::initThermoXML",
|
||||
"Unknown idealMolalSolnCutoff form: " + modelString);
|
||||
}
|
||||
|
||||
setCutoffModel(modelString);
|
||||
if (ccNode.hasChild("gamma_o_limit")) {
|
||||
IMS_gamma_o_min_ = getFloat(ccNode, "gamma_o_limit");
|
||||
}
|
||||
|
|
@ -443,6 +421,8 @@ void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
|||
IMS_slopegCut_ = getFloat(ccNode, "slope_g_limit");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setCutoffModel("none");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -464,32 +444,45 @@ void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
|||
"Solvent " + solventName +
|
||||
" should be first species");
|
||||
}
|
||||
}
|
||||
|
||||
// Now go get the molar volumes
|
||||
XML_Node& speciesList = phaseNode.child("speciesArray");
|
||||
XML_Node* speciesDB =
|
||||
get_XML_NameID("speciesData", speciesList["datasrc"],
|
||||
&phaseNode.root());
|
||||
const std::vector<std::string> &sss = speciesNames();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
XML_Node* s = speciesDB->findByAttr("name", sss[k]);
|
||||
XML_Node* ss = s->findByName("standardState");
|
||||
m_speciesMolarVolume[k] = getFloat(*ss, "molarVolume", "toSI");
|
||||
void IdealMolalSoln::initThermo()
|
||||
{
|
||||
MolalityVPSSTP::initThermo();
|
||||
for (size_t k = 0; k < nSpecies(); k++) {
|
||||
m_speciesMolarVolume[k] = providePDSS(k)->molarVolume();
|
||||
}
|
||||
|
||||
IMS_typeCutoff_ = 2;
|
||||
if (IMS_typeCutoff_ == 2) {
|
||||
calcIMSCutoffParams_();
|
||||
}
|
||||
|
||||
MolalityVPSSTP::initThermoXML(phaseNode, id_);
|
||||
setMoleFSolventMin(1.0E-5);
|
||||
}
|
||||
|
||||
// Set the state
|
||||
if (phaseNode.hasChild("state")) {
|
||||
XML_Node& stateNode = phaseNode.child("state");
|
||||
setStateFromXML(stateNode);
|
||||
void IdealMolalSoln::setStandardConcentrationModel(const std::string& model)
|
||||
{
|
||||
if (ba::iequals(model, "unity")) {
|
||||
m_formGC = 0;
|
||||
} else if (ba::iequals(model, "molar_volume")) {
|
||||
m_formGC = 1;
|
||||
} else if (ba::iequals(model, "solvent_volume")) {
|
||||
m_formGC = 2;
|
||||
} else {
|
||||
throw CanteraError("IdealSolnGasVPSS::setStandardConcentrationModel",
|
||||
"Unknown standard concentration model '{}'", model);
|
||||
}
|
||||
}
|
||||
|
||||
void IdealMolalSoln::setCutoffModel(const std::string& model)
|
||||
{
|
||||
if (ba::iequals(model, "none")) {
|
||||
IMS_typeCutoff_ = 0;
|
||||
} else if (ba::iequals(model, "poly")) {
|
||||
IMS_typeCutoff_ = 1;
|
||||
} else if (ba::iequals(model, "polyexp")) {
|
||||
IMS_typeCutoff_ = 2;
|
||||
} else {
|
||||
throw CanteraError("IdealMolalSoln::setCutoffModel",
|
||||
"Unknown cutoff model '{}'", model);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
#include "cantera/thermo/PDSSFactory.h"
|
||||
#include "cantera/thermo/PDSS_ConstVol.h"
|
||||
#include "cantera/thermo/FixedChemPotSSTP.h"
|
||||
#include "cantera/thermo/PureFluidPhase.h"
|
||||
#include "cantera/thermo/WaterSSTP.h"
|
||||
#include "cantera/thermo/RedlichKwongMFTP.h"
|
||||
#include "cantera/thermo/IonsFromNeutralVPSSTP.h"
|
||||
#include "cantera/thermo/IdealSolnGasVPSS.h"
|
||||
#include "cantera/thermo/IdealMolalSoln.h"
|
||||
#include "cantera/thermo/NasaPoly2.h"
|
||||
#include "cantera/thermo/ShomatePoly.h"
|
||||
#include "cantera/thermo/IdealGasPhase.h"
|
||||
|
|
@ -18,6 +20,14 @@
|
|||
namespace Cantera
|
||||
{
|
||||
|
||||
shared_ptr<Species> make_species(const std::string& name,
|
||||
const std::string& composition, const double* nasa_coeffs)
|
||||
{
|
||||
auto species = make_shared<Species>(name, parseCompString(composition));
|
||||
species->thermo.reset(new NasaPoly2(200, 3500, 101325, nasa_coeffs));
|
||||
return species;
|
||||
}
|
||||
|
||||
class FixedChemPotSstpConstructorTest : public testing::Test
|
||||
{
|
||||
};
|
||||
|
|
@ -115,18 +125,13 @@ class ConstructFromScratch : public testing::Test
|
|||
{
|
||||
public:
|
||||
ConstructFromScratch()
|
||||
: sH2O(new Species("H2O", parseCompString("H:2 O:1")))
|
||||
, sH2(new Species("H2", parseCompString("H:2")))
|
||||
, sO2(new Species("O2", parseCompString("O:2")))
|
||||
, sOH(new Species("OH", parseCompString("H:1 O:1")))
|
||||
, sCO(new Species("CO", parseCompString("C:1 O:1")))
|
||||
: sH2O(make_species("H2O", "H:2 O:1", h2o_nasa_coeffs))
|
||||
, sH2(make_species("H2", "H:2", h2_nasa_coeffs))
|
||||
, sO2(make_species("O2", "O:2", o2_nasa_coeffs))
|
||||
, sOH(make_species("OH", "H:1 O:1", oh_nasa_coeffs))
|
||||
, sCO(make_species("CO", "C:1 O:1", o2_nasa_coeffs))
|
||||
, sCO2(new Species("CO2", parseCompString("C:1 O:2")))
|
||||
{
|
||||
sH2O->thermo.reset(new NasaPoly2(200, 3500, 101325, h2o_nasa_coeffs));
|
||||
sH2->thermo.reset(new NasaPoly2(200, 3500, 101325, h2_nasa_coeffs));
|
||||
sO2->thermo.reset(new NasaPoly2(200, 3500, 101325, o2_nasa_coeffs));
|
||||
sOH->thermo.reset(new NasaPoly2(200, 3500, 101325, oh_nasa_coeffs));
|
||||
sCO->thermo.reset(new NasaPoly2(200, 3500, 101325, o2_nasa_coeffs));
|
||||
sCO2->thermo.reset(new ShomatePoly2(200, 3500, 101325, co2_shomate_coeffs));
|
||||
}
|
||||
|
||||
|
|
@ -268,13 +273,42 @@ TEST(PureFluidFromScratch, CarbonDioxide)
|
|||
TEST(WaterSSTP, fromScratch)
|
||||
{
|
||||
WaterSSTP water;
|
||||
auto sH2O = make_shared<Species>("H2O", parseCompString("H:2 O:1"));
|
||||
sH2O->thermo.reset(new NasaPoly2(200, 3500, 101325, h2o_nasa_coeffs)); // unused
|
||||
water.addUndefinedElements();
|
||||
water.addSpecies(sH2O);
|
||||
water.addSpecies(make_species("H2O", "H:2, O:1", h2o_nasa_coeffs));
|
||||
water.initThermo();
|
||||
water.setState_TP(298.15, 1e5);
|
||||
EXPECT_NEAR(water.enthalpy_mole() / 1e6, -285.83, 2e-2);
|
||||
}
|
||||
|
||||
TEST(IdealMolalSoln, fromScratch)
|
||||
{
|
||||
IdealMolalSoln p;
|
||||
p.addUndefinedElements();
|
||||
p.addSpecies(make_species("H2O(l)", "H:2, O:1", h2_nasa_coeffs));
|
||||
p.addSpecies(make_species("CO2(aq)", "C:1, O:2", h2_nasa_coeffs));
|
||||
p.addSpecies(make_species("H2S(aq)", "H:2, S:1", h2_nasa_coeffs));
|
||||
p.addSpecies(make_species("CH4(aq)", "C:1, H:4", h2_nasa_coeffs));
|
||||
size_t k = 0;
|
||||
for (double v : {1.5, 1.3, 0.1, 0.1}) {
|
||||
std::unique_ptr<PDSS_ConstVol> ss(new PDSS_ConstVol());
|
||||
ss->setMolarVolume(v);
|
||||
p.installPDSS(k++, std::move(ss));
|
||||
}
|
||||
p.setStandardConcentrationModel("solvent_volume");
|
||||
p.setCutoffModel("polyexp");
|
||||
// These propreties probably shouldn't be public
|
||||
p.IMS_X_o_cutoff_ = 0.20;
|
||||
p.IMS_gamma_o_min_ = 0.00001;
|
||||
p.IMS_gamma_k_min_ = 10.0;
|
||||
p.IMS_slopefCut_ = 0.6;
|
||||
p.IMS_slopegCut_ = 0.0;
|
||||
p.IMS_cCut_ = .05;
|
||||
p.initThermo();
|
||||
p.setState_TPM(298.15, OneAtm, "CH4(aq):0.01, H2S(aq):0.03, CO2(aq):0.1");
|
||||
|
||||
EXPECT_NEAR(p.enthalpy_mole(), 0.013282, 1e-6);
|
||||
EXPECT_NEAR(p.gibbs_mole(), -3.8986e7, 1e3);
|
||||
EXPECT_NEAR(p.density(), 12.058, 1e-3);
|
||||
}
|
||||
|
||||
} // namespace Cantera
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue