[Thermo] Simplify interface for adding elements to a Phase

Phase::addElements(string name, ...) is the single entry point for adding
elements. It always perform the uniqueness check, and can do the extra
additional work required to add elements to a phase that already has species,
removing the need for "freezing" the phase's elements. Parsing the XML tree for
elements is now handled in "installElements". The variant element-adding methods
are deprecated.
This commit is contained in:
Ray Speth 2014-09-27 00:09:05 +00:00
parent 473827a8a6
commit 4baccc732c
8 changed files with 172 additions and 159 deletions

View file

@ -110,6 +110,8 @@ class XML_Node;
* in a particular instantiation of the class.
*
* @ingroup phases
* @deprecated. Functionality is now part of class Phase. To be removed after
* Cantera 2.2.
*/
class Elements
{

View file

@ -25,20 +25,6 @@ namespace Cantera
* support thermodynamic calculations (see \ref thermoprops).
*/
//! Exception class to indicate a fixed set of elements.
/*!
* This class is used to warn the user when the number of elements
* are changed after at least one species is defined.
*/
class ElementsFrozen : public CanteraError
{
public:
//! Constructor for class
//! @param func Function where the error occurred.
ElementsFrozen(const std::string& func)
: CanteraError(func, "Elements cannot be added after species.") {}
};
//! Class %Phase is the base class for phases of matter, managing the species and elements in a phase, as well as the
//! independent variables of temperature, mass density, species mass/mole fraction,
//! and other generalized forces and intrinsic properties (such as electric potential)
@ -658,10 +644,21 @@ public:
//! Add an element.
//! @param symbol Atomic symbol std::string.
//! @param weight Atomic mass in amu.
void addElement(const std::string& symbol, doublereal weight=-12345.0);
//! @param atomicNumber Atomic number of the element (unitless)
//! @param entropy298 Entropy of the element at 298 K and 1 bar in its
//! most stable form. The default is the value ENTROPY298_UNKNOWN,
//! which is interpreted as an unknown, and if used will cause
//! %Cantera to throw an error.
//! @param elem_type Specifies the type of the element constraint
//! equation. This defaults to CT_ELEM_TYPE_ABSPOS, i.e., an element.
//! @return index of the element added
size_t addElement(const std::string& symbol, doublereal weight=-12345.0,
int atomicNumber=0, doublereal entropy298=ENTROPY298_UNKNOWN,
int elem_type=CT_ELEM_TYPE_ABSPOS);
//! Add an element from an XML specification.
//! @param e Reference to the XML_Node where the element is described.
//! @deprecated. To be removed after Cantera 2.2.
void addElement(const XML_Node& e);
//! Add an element, checking for uniqueness
@ -676,6 +673,7 @@ public:
//! error.
//! @param elem_type Specifies the type of the element constraint
//! equation. This defaults to CT_ELEM_TYPE_ABSPOS, i.e., an element.
//! @deprecated. Equivalent to addElement. To be removed after Cantera 2.2.
void addUniqueElement(const std::string& symbol, doublereal weight=-12345.0,
int atomicNumber = 0,
doublereal entropy298 = ENTROPY298_UNKNOWN,
@ -685,16 +683,20 @@ public:
//! The uniqueness is checked by comparing the string symbol. If not unique,
//! nothing is done.
//! @param e Reference to the XML_Node where the element is described.
//! @deprecated. To be removed after Cantera 2.2.
void addUniqueElement(const XML_Node& e);
//! Add all elements referenced in an XML_Node tree
//! @param phase Reference to the root XML_Node of a phase
//! @deprecated. To be removed after Cantera 2.2.
void addElementsFromXML(const XML_Node& phase);
//! Prohibit addition of more elements, and prepare to add species.
//! @deprecated. To be removed after Cantera 2.2.
void freezeElements();
//! True if freezeElements has been called.
//! @deprecated. To be removed after Cantera 2.2.
bool elementsFrozen();
//! Add an element after elements have been frozen, checking for uniqueness
@ -708,6 +710,7 @@ public:
//! if used will cause Cantera to throw an error.
//! @param elem_type Specifies the type of the element constraint
//! equation. This defaults to CT_ELEM_TYPE_ABSPOS, i.e., an element.
//! @deprecated. Equivalentto addElement. To be removed after Cantera 2.2.
size_t addUniqueElementAfterFreeze(const std::string& symbol,
doublereal weight, int atomicNumber,
doublereal entropy298 = ENTROPY298_UNKNOWN,
@ -814,9 +817,6 @@ private:
//! this int is incremented.
int m_stateNum;
//! If this is true, then no elements may be added to the object.
bool m_elementsFrozen;
//! Vector of the species names
std::vector<std::string> m_speciesNames;

View file

@ -230,6 +230,9 @@ ThermoPhase* newPhase(const std::string& infile, std::string id);
*/
bool importPhase(XML_Node& phase, ThermoPhase* th, SpeciesThermoFactory* spfactory = 0);
//! Add the elements given in an XML_Node tree to the specified phase
void installElements(Phase& th, const XML_Node& phaseNode);
//! Install a species into a ThermoPhase object, which defines
//! the phase thermodynamics and speciation.
/*!

View file

@ -209,6 +209,9 @@ Elements::Elements() :
m_elem_type(0),
numSubscribers(0)
{
warn_deprecated("class Elements",
"Functionality is now part of class Phase. "
"To be removed after Cantera 2.2.");
}
/*

View file

@ -85,8 +85,7 @@ FixedChemPotSSTP::FixedChemPotSSTP(const std::string& Ename, doublereal val) :
setID(pname);
setName(pname);
setNDim(3);
addUniqueElement(Ename, -12345.);
freezeElements();
addElement(Ename);
vector_fp ecomp(nElements(), 0.0);
ecomp[0] = 1.0;
double chrg = 0.0;

View file

@ -359,7 +359,7 @@ void LatticeSolidPhase::installSlavePhases(Cantera::XML_Node* phaseNode)
int an = lp->atomicNumber(es);
int e298 = lp->entropyElement298(es); //! @todo Why is this an int instead of a double?
int et = lp->elementType(es);
addUniqueElementAfterFreeze(esName, wt, an, e298, et);
addElement(esName, wt, an, e298, et);
}
const std::vector<const XML_Node*> & spNode = lp->speciesData();
kstart = kk;
@ -397,7 +397,7 @@ void LatticeSolidPhase::installSlavePhases(Cantera::XML_Node* phaseNode)
string econ = "LC_";
econ += int2str(n);
econ += "_" + id();
size_t m = addUniqueElementAfterFreeze(econ, 0.0, 0, 0.0, CT_ELEM_TYPE_LATTICERATIO);
size_t m = addElement(econ, 0.0, 0, 0.0, CT_ELEM_TYPE_LATTICERATIO);
size_t mm = nElements();
LatticePhase* lp0 = m_lattice[0];
size_t nsp0 = lp0->nSpecies();

View file

@ -9,6 +9,7 @@
#include "cantera/base/vec_functions.h"
#include "cantera/base/stringUtils.h"
#include "cantera/base/ctml.h"
#include "cantera/thermo/ThermoFactory.h"
using namespace std;
@ -25,7 +26,6 @@ Phase::Phase() :
m_dens(0.001),
m_mmw(0.0),
m_stateNum(-1),
m_elementsFrozen(false),
m_mm(0),
m_elem_type(0),
realNumberRangeBehavior_(THROWON_OVERFLOW_DEBUGMODEONLY_CTRB)
@ -42,7 +42,6 @@ Phase::Phase(const Phase& right) :
m_dens(0.001),
m_mmw(0.0),
m_stateNum(-1),
m_elementsFrozen(false),
m_mm(0),
m_elem_type(0),
realNumberRangeBehavior_(THROWON_OVERFLOW_DEBUGMODEONLY_CTRB)
@ -76,7 +75,6 @@ Phase& Phase::operator=(const Phase& right)
m_speciesSize = right.m_speciesSize;
m_mm = right.m_mm;
m_elementsFrozen = right.m_elementsFrozen;
m_atomicWeights = right.m_atomicWeights;
m_atomicNumbers = right.m_atomicNumbers;
m_elementNames = right.m_elementNames;
@ -695,85 +693,67 @@ doublereal Phase::sum_xlogQ(doublereal* Q) const
return m_mmw * Cantera::sum_xlogQ(m_ym.begin(), m_ym.end(), Q);
}
void Phase::addElement(const std::string& symbol, doublereal weight)
size_t Phase::addElement(const std::string& symbol, doublereal weight,
int atomic_number, doublereal entropy298,
int elem_type)
{
// Look up the atomic weight if not given
if (weight == -12345.0) {
weight = LookupWtElements(symbol);
if (weight < 0.0) {
throw ElementsFrozen("addElement");
throw CanteraError("Phase::addElement",
"No atomic weight found for element: " + symbol);
}
}
if (m_elementsFrozen) {
throw ElementsFrozen("addElement");
return;
// Check for duplicates
vector<string>::const_iterator iter = find(m_elementNames.begin(),
m_elementNames.end(),
symbol);
if (iter != m_elementNames.end()) {
size_t m = iter - m_elementNames.begin();
if (m_atomicWeights[m] != weight) {
throw CanteraError("Phase::addElement",
"Duplicate elements (" + symbol + ") have different weights");
} else {
// Ignore attempt to add duplicate element with the same weight
return m;
}
}
// Add the new element
m_atomicWeights.push_back(weight);
m_elementNames.push_back(symbol);
m_atomicNumbers.push_back(atomic_number);
m_entropy298.push_back(entropy298);
if (symbol == "E") {
m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE);
} else {
m_elem_type.push_back(CT_ELEM_TYPE_ABSPOS);
m_elem_type.push_back(elem_type);
}
m_mm++;
// Update species compositions
if (m_kk) {
vector_fp old(m_speciesComp);
m_speciesComp.resize(m_kk*m_mm, 0.0);
for (size_t k = 0; k < m_kk; k++) {
size_t m_old = m_mm - 1;
for (size_t m = 0; m < m_old; m++) {
m_speciesComp[k * m_mm + m] = old[k * (m_old) + m];
}
m_speciesComp[k * (m_mm) + (m_mm-1)] = 0.0;
}
}
return m_mm-1;
}
void Phase::addElement(const XML_Node& e)
{
doublereal weight = fpValue(e["atomicWt"]);
string symbol = e["name"];
addElement(symbol, weight);
}
void Phase::addUniqueElement(const std::string& symbol, doublereal weight,
int atomic_number, doublereal entropy298,
int elem_type)
{
if (weight == -12345.0) {
weight = LookupWtElements(symbol);
if (weight < 0.0) {
throw ElementsFrozen("addElement");
}
}
/*
* First decide if this element has been previously added
* by conducting a string search. If it unique, add it to
* the list.
*/
int ifound = 0;
int i = 0;
for (vector<string>::const_iterator it = m_elementNames.begin();
it < m_elementNames.end(); ++it, ++i) {
if (*it == symbol) {
ifound = 1;
break;
}
}
if (!ifound) {
if (m_elementsFrozen) {
throw ElementsFrozen("addElement");
return;
}
m_atomicWeights.push_back(weight);
m_elementNames.push_back(symbol);
m_atomicNumbers.push_back(atomic_number);
m_entropy298.push_back(entropy298);
if (symbol == "E") {
m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE);
} else {
m_elem_type.push_back(elem_type);
}
m_mm++;
} else {
if (m_atomicWeights[i] != weight) {
throw CanteraError("AddUniqueElement",
"Duplicate Elements (" + symbol + ") have different weights");
}
}
}
void Phase::addUniqueElement(const XML_Node& e)
{
warn_deprecated("Phase::addElement(XML_Node&)",
"To be removed after Cantera 2.2.");
doublereal weight = 0.0;
if (e.hasAttrib("atomicWt")) {
weight = fpValue(stripws(e["atomicWt"]));
@ -791,101 +771,61 @@ void Phase::addUniqueElement(const XML_Node& e)
}
}
if (weight != 0.0) {
addUniqueElement(symbol, weight, anum, entropy298);
addElement(symbol, weight, anum, entropy298);
} else {
addUniqueElement(symbol);
addElement(symbol);
}
}
void Phase::addUniqueElement(const std::string& symbol, doublereal weight,
int atomic_number, doublereal entropy298,
int elem_type)
{
warn_deprecated("Phase::addUniqueElement",
"Equivalent to Phase::addElement. "
"To be removed after Cantera 2.2.");
addElement(symbol, weight, atomic_number, entropy298, elem_type);
}
void Phase::addUniqueElement(const XML_Node& e)
{
warn_deprecated("Phase::addUniqueElement",
"To be removed after Cantera 2.2.");
addElement(e);
}
void Phase::addElementsFromXML(const XML_Node& phase)
{
// get the declared element names
if (! phase.hasChild("elementArray")) {
throw CanteraError("Elements::addElementsFromXML",
"phase xml node doesn't have \"elementArray\" XML Node");
}
XML_Node& elements = phase.child("elementArray");
vector<string> enames;
ctml::getStringArray(elements, enames);
// // element database defaults to elements.xml
string element_database = "elements.xml";
if (elements.hasAttrib("datasrc")) {
element_database = elements["datasrc"];
}
XML_Node* doc = get_XML_File(element_database);
XML_Node* dbe = &doc->child("ctml/elementData");
XML_Node& root = phase.root();
XML_Node* local_db = 0;
if (root.hasChild("ctml")) {
if (root.child("ctml").hasChild("elementData")) {
local_db = &root.child("ctml/elementData");
}
}
for (size_t i = 0; i < enames.size(); i++) {
XML_Node* e = 0;
if (local_db) {
e = local_db->findByAttr("name",enames[i]);
}
if (!e) {
e = dbe->findByAttr("name",enames[i]);
}
if (e) {
addUniqueElement(*e);
} else {
throw CanteraError("addElementsFromXML","no data for element "
+enames[i]);
}
}
warn_deprecated("Phase::addElementsFromXML",
"Use 'addElements' function. "
"To be removed after Cantera 2.2.");
installElements(*this, phase);
}
void Phase::freezeElements()
{
m_elementsFrozen = true;
warn_deprecated("Phase::freezeElements", "To be removed after Cantera 2.2.");
}
bool Phase::elementsFrozen()
{
return m_elementsFrozen;
warn_deprecated("Phase::elementsFrozen", "To be removed after Cantera 2.2.");
return false;
}
size_t Phase::addUniqueElementAfterFreeze(const std::string& symbol,
doublereal weight, int atomicNumber,
doublereal entropy298, int elem_type)
{
size_t ii = elementIndex(symbol);
if (ii != npos) {
return ii;
}
// Check to see that the element isn't really in the list
m_elementsFrozen = false;
addUniqueElement(symbol, weight, atomicNumber, entropy298, elem_type);
m_elementsFrozen = true;
ii = elementIndex(symbol);
if (ii != m_mm-1) {
throw CanteraError("Phase::addElementAfterFreeze()", "index error");
}
if (m_kk > 0) {
vector_fp old(m_speciesComp);
m_speciesComp.resize(m_kk*m_mm, 0.0);
for (size_t k = 0; k < m_kk; k++) {
size_t m_old = m_mm - 1;
for (size_t m = 0; m < m_old; m++) {
m_speciesComp[k * m_mm + m] = old[k * (m_old) + m];
}
m_speciesComp[k * (m_mm) + (m_mm-1)] = 0.0;
}
}
return ii;
warn_deprecated("Phase::addUniqueElementAfterFreeze",
"Equivalent to Phase::addElement. "
"To be removed after Cantera 2.2");
return addElement(symbol, weight, atomicNumber, entropy298, elem_type);
}
void Phase::addSpecies(const std::string& name_, const doublereal* comp,
doublereal charge_, doublereal size_)
{
freezeElements();
m_speciesNames.push_back(name_);
m_speciesCharge.push_back(charge_);
m_speciesSize.push_back(size_);
@ -914,8 +854,7 @@ void Phase::addSpecies(const std::string& name_, const doublereal* comp,
}
}
} else {
addUniqueElementAfterFreeze("E", 0.000545, 0, 0.0,
CT_ELEM_TYPE_ELECTRONCHARGE);
addElement("E", 0.000545, 0, 0.0, CT_ELEM_TYPE_ELECTRONCHARGE);
ne = nElements();
eindex = elementIndex("E");
compNew.resize(ne);
@ -979,7 +918,7 @@ void Phase::addUniqueSpecies(const std::string& name_, const doublereal* comp,
bool Phase::ready() const
{
return (m_kk > 0 && m_elementsFrozen);
return (m_kk > 0);
}
} // namespace Cantera

View file

@ -382,7 +382,7 @@ bool importPhase(XML_Node& phase, ThermoPhase* th,
* Add the elements.
***************************************************************/
if (ssConvention != cSS_CONVENTION_SLAVE) {
th->addElementsFromXML(phase);
installElements(*th, phase);
}
/***************************************************************
@ -523,6 +523,73 @@ bool importPhase(XML_Node& phase, ThermoPhase* th,
return true;
}
void installElements(Phase& th, const XML_Node& phaseNode)
{
// get the declared element names
if (!phaseNode.hasChild("elementArray")) {
throw CanteraError("installElements",
"phase xml node doesn't have \"elementArray\" XML Node");
}
XML_Node& elements = phaseNode.child("elementArray");
vector<string> enames;
getStringArray(elements, enames);
// // element database defaults to elements.xml
string element_database = "elements.xml";
if (elements.hasAttrib("datasrc")) {
element_database = elements["datasrc"];
}
XML_Node* doc = get_XML_File(element_database);
XML_Node* dbe = &doc->child("ctml/elementData");
XML_Node& root = phaseNode.root();
XML_Node* local_db = 0;
if (root.hasChild("ctml")) {
if (root.child("ctml").hasChild("elementData")) {
local_db = &root.child("ctml/elementData");
}
}
for (size_t i = 0; i < enames.size(); i++) {
// Find the element data
XML_Node* e = 0;
if (local_db) {
e = local_db->findByAttr("name",enames[i]);
}
if (!e) {
e = dbe->findByAttr("name",enames[i]);
}
if (!e) {
throw CanteraError("addElementsFromXML","no data for element "
+enames[i]);
}
// Add the element
doublereal weight = 0.0;
if (e->hasAttrib("atomicWt")) {
weight = fpValue(e->attrib("atomicWt"));
}
int anum = 0;
if (e->hasAttrib("atomicNumber")) {
anum = intValue(e->attrib("atomicNumber"));
}
string symbol = e->attrib("name");
doublereal entropy298 = ENTROPY298_UNKNOWN;
if (e->hasChild("entropy298")) {
XML_Node& e298Node = e->child("entropy298");
if (e298Node.hasAttrib("value")) {
entropy298 = fpValueCheck(e298Node["value"]);
}
}
if (weight != 0.0) {
th.addElement(symbol, weight, anum, entropy298);
} else {
th.addElement(symbol);
}
}
}
bool installSpecies(size_t k, const XML_Node& s, thermo_t& th,
SpeciesThermo* spthermo_ptr, int rule,
XML_Node* phaseNode_ptr,