Add options for handling Species containing undefined elements

This commit is contained in:
Ray Speth 2014-10-17 23:44:37 +00:00
parent 26b6f190f3
commit 5bc4a12e2e
5 changed files with 158 additions and 12 deletions

View file

@ -14,6 +14,7 @@
namespace Cantera
{
/**
* @defgroup phases Models of Phases of Matter
*
@ -717,7 +718,10 @@ public:
doublereal entropy298 = ENTROPY298_UNKNOWN,
int elem_type = CT_ELEM_TYPE_ABSPOS);
virtual void addSpecies(const Species& spec);
//! Add a Species to this Phase. Returns `true` if the species was
//! successfully added, or `false` if the species was ignored.
//! @see ignoreUndefinedElements addUndefinedElements throwUndefinedElements
virtual bool addSpecies(const Species& spec);
void addSpecies(const std::string& name, const doublereal* comp,
doublereal charge = 0.0, doublereal size = 1.0);
@ -733,6 +737,23 @@ public:
void addUniqueSpecies(const std::string& name, const doublereal* comp,
doublereal charge = 0.0,
doublereal size = 1.0);
//! Set behavior when adding a species containing undefined elements to just
//! skip the species.
void ignoreUndefinedElements();
//! Set behavior when adding a species containing undefined elements to add
//! those elements to the phase.
void addUndefinedElements();
//! Set the behavior when adding a species containing undefined elements to
//! throw an exception. This is the default behavior.
void throwUndefinedElements();
struct UndefElement { enum behavior {
error, ignore, add
}; };
//!@} end group adding species and elements
//! Returns a bool indicating wether the object is ready for use
@ -782,6 +803,9 @@ protected:
std::map<std::string, Species> m_species;
//! Flag determining behavior when adding species with an undefined element
UndefElement::behavior m_undefinedElementBehavior;
private:
XML_Node* m_xml; //!< XML node containing the XML info for this phase

View file

@ -1278,7 +1278,7 @@ public:
//@{
using Phase::addSpecies;
virtual void addSpecies(const Species& spec);
virtual bool addSpecies(const Species& spec);
//! Store a reference pointer to the XML tree containing the species data
//! for this phase.

View file

@ -19,6 +19,7 @@ namespace Cantera
Phase::Phase() :
m_kk(0),
m_ndim(3),
m_undefinedElementBehavior(UndefElement::error),
m_xml(new XML_Node("phase")),
m_id("<phase>"),
m_name(""),
@ -35,6 +36,7 @@ Phase::Phase() :
Phase::Phase(const Phase& right) :
m_kk(0),
m_ndim(3),
m_undefinedElementBehavior(right.m_undefinedElementBehavior),
m_xml(0),
m_id("<phase>"),
m_name(""),
@ -60,6 +62,7 @@ Phase& Phase::operator=(const Phase& right)
// Handle our own data
m_kk = right.m_kk;
m_ndim = right.m_ndim;
m_undefinedElementBehavior = right.m_undefinedElementBehavior;
m_temp = right.m_temp;
m_dens = right.m_dens;
m_mmw = right.m_mmw;
@ -817,17 +820,30 @@ size_t Phase::addUniqueElementAfterFreeze(const std::string& symbol,
return addElement(symbol, weight, atomicNumber, entropy298, elem_type);
}
void Phase::addSpecies(const Species& spec) {
bool Phase::addSpecies(const Species& spec) {
m_species[spec.name] = spec;
vector_fp comp(nElements());
for (map<string, double>::const_iterator iter = spec.composition.begin();
iter != spec.composition.end();
iter++) {
size_t m = elementIndex(iter->first);
if (m == npos) {
throw CanteraError("Phase::addSpecies",
"Species '" + spec.name + "' contains an "
"undefined element '" + iter->first + "'.");
if (m == npos) { // Element doesn't exist in this phase
switch (m_undefinedElementBehavior) {
case UndefElement::ignore:
return false;
case UndefElement::add:
addElement(iter->first);
comp.resize(nElements());
m = elementIndex(iter->first);
break;
case UndefElement::error:
default:
throw CanteraError("Phase::addSpecies",
"Species '" + spec.name + "' contains an "
"undefined element '" + iter->first + "'.");
}
}
comp[m] = iter->second;
}
@ -886,6 +902,7 @@ void Phase::addSpecies(const Species& spec) {
m_y.push_back(0.0);
m_ym.push_back(0.0);
}
return true;
}
void Phase::addSpecies(const std::string& name_, const doublereal* comp,
@ -929,6 +946,18 @@ void Phase::addUniqueSpecies(const std::string& name_, const doublereal* comp,
addSpecies(name_, comp, charge_, size_);
}
void Phase::ignoreUndefinedElements() {
m_undefinedElementBehavior = UndefElement::ignore;
}
void Phase::addUndefinedElements() {
m_undefinedElementBehavior = UndefElement::add;
}
void Phase::throwUndefinedElements() {
m_undefinedElementBehavior = UndefElement::error;
}
bool Phase::ready() const
{
return (m_kk > 0);

View file

@ -695,10 +695,13 @@ void ThermoPhase::installSlavePhases(Cantera::XML_Node* phaseNode)
{
}
void ThermoPhase::addSpecies(const Species& spec)
bool ThermoPhase::addSpecies(const Species& spec)
{
Phase::addSpecies(spec);
m_spthermo->install_STIT(spec.thermo().duplMyselfAsSpeciesThermoInterpType());
bool added = Phase::addSpecies(spec);
if (added) {
m_spthermo->install_STIT(spec.thermo().duplMyselfAsSpeciesThermoInterpType());
}
return added;
}
void ThermoPhase::saveSpeciesData(const size_t k, const XML_Node* const data)

View file

@ -1,11 +1,12 @@
#include "gtest/gtest.h"
#include "cantera/thermo/FixedChemPotSSTP.h"
#include "cantera/thermo/ThermoFactory.h"
#include "cantera/thermo/SpeciesThermoFactory.h"
#include "cantera/thermo/speciesThermoTypes.h"
#include "cantera/thermo/NasaPoly2.h"
#include "cantera/thermo/IdealGasPhase.h"
#include "cantera/base/ctml.h"
#include "cantera/base/stringUtils.h"
#include <fstream>
#include "thermo_data.h"
namespace Cantera
{
@ -100,4 +101,93 @@ TEST_F(ChemkinConversionTest, FailedConversion) {
}
#endif
class ConstructFromScratch : public testing::Test
{
public:
ConstructFromScratch()
: sH2O("H2O", parseCompString("H:2 O:1"),
new NasaPoly2(0, 200, 3500, 101325, h2o_nasa_coeffs))
, sH2("H2", parseCompString("H:2"),
new NasaPoly2(0, 200, 3500, 101325, h2_nasa_coeffs))
, sO2("O2", parseCompString("O:2"),
new NasaPoly2(0, 200, 3500, 101325, o2_nasa_coeffs))
, sOH("OH", parseCompString("H:1 O:1"),
new NasaPoly2(0, 200, 3500, 101325, oh_nasa_coeffs))
, sCO("CO", parseCompString("C:1 O:1"),
new NasaPoly2(0, 200, 3500, 101325, o2_nasa_coeffs))
, sCO2("CO2", parseCompString("C:1 O:2"),
new NasaPoly2(0, 200, 3500, 101325, h2o_nasa_coeffs))
{
}
IdealGasPhase p;
Species sH2O, sH2, sO2, sOH, sCO, sCO2;
};
TEST_F(ConstructFromScratch, AddElements)
{
p.addElement("H");
p.addElement("O");
ASSERT_EQ((size_t) 2, p.nElements());
ASSERT_EQ("H", p.elementName(0));
ASSERT_EQ((size_t) 1, p.elementIndex("O"));
}
TEST_F(ConstructFromScratch, AddSpeciesDefaultBehavior)
{
p.addElement("H");
p.addElement("O");
p.addSpecies(sH2O);
p.addSpecies(sH2);
ASSERT_EQ((size_t) 2, p.nSpecies());
p.addSpecies(sO2);
p.addSpecies(sOH);
ASSERT_EQ((size_t) 4, p.nSpecies());
ASSERT_EQ("H2", p.speciesName(1));
ASSERT_EQ(2, p.nAtoms(2, 1)); // O in O2
ASSERT_EQ(2, p.nAtoms(0, 0)); // H in H2O
ASSERT_THROW(p.addSpecies(sCO), CanteraError);
}
TEST_F(ConstructFromScratch, ignoreUndefinedElements)
{
p.addElement("H");
p.addElement("O");
p.ignoreUndefinedElements();
p.addSpecies(sO2);
p.addSpecies(sOH);
ASSERT_EQ((size_t) 2, p.nSpecies());
p.addSpecies(sCO);
p.addSpecies(sCO2);
ASSERT_EQ((size_t) 2, p.nSpecies());
ASSERT_EQ((size_t) 2, p.nElements());
ASSERT_EQ(npos, p.speciesIndex("CO2"));
}
TEST_F(ConstructFromScratch, addUndefinedElements)
{
p.addElement("H");
p.addElement("O");
p.addUndefinedElements();
p.addSpecies(sH2);
p.addSpecies(sOH);
ASSERT_EQ((size_t) 2, p.nSpecies());
ASSERT_EQ((size_t) 2, p.nElements());
p.addSpecies(sCO);
p.addSpecies(sCO2);
ASSERT_EQ((size_t) 4, p.nSpecies());
ASSERT_EQ((size_t) 3, p.nElements());
ASSERT_EQ((size_t) 1, p.nAtoms(p.speciesIndex("CO2"), p.elementIndex("C")));
ASSERT_EQ((size_t) 2, p.nAtoms(p.speciesIndex("CO2"), p.elementIndex("O")));
p.setMassFractionsByName("H2:0.5, CO2:0.5");
ASSERT_FLOAT_EQ(0.5, p.massFraction("CO2"));
}
} // namespace Cantera