diff --git a/include/cantera/thermo/Elements.h b/include/cantera/thermo/Elements.h index e9269e340..412b91cdd 100644 --- a/include/cantera/thermo/Elements.h +++ b/include/cantera/thermo/Elements.h @@ -1,26 +1,18 @@ /** * @file Elements.h - * Header file for class, Elements, which contains the elements that - * make up species (see \ref phases and \link Cantera::Elements Elements\endlink). - * - * This file contains the declarations for the elements class. + * Contains the LookupWtElements function and the definitions of element + * constraint types. */ // Copyright 2001 California Institute of Technology #ifndef CT_ELEMENTS_H #define CT_ELEMENTS_H -#undef USE_DGG_CODE - #include "cantera/base/ct_defs.h" - namespace Cantera { -class XML_Node; -class ElementRangeError; - /*! * @name Types of Element Constraint Equations * @@ -87,330 +79,21 @@ class ElementRangeError; #define CT_ELEM_TYPE_OTHERCONSTRAINT 6 //@} - -//! Positive number indicating we don't know the gibbs free energy -//! of the element in its most stable state at 298.15 K and 1 bar. +//! Number indicating we don't know the entropy of the element in its most +//! stable state at 298.15 K and 1 bar. #define ENTROPY298_UNKNOWN -123456789. -//! Object containing the elements that make up species in a phase. -/*! - * Class %Elements manages the elements that are part of a - * chemistry specification. This class may support calculations - * employing Multiple phases. In this case, a single Elements object may - * be shared by more than one Constituents class. Reactions between - * the phases may then be described using stoichiometry base on the - * same Elements class object. - * - * The member functions return information about the elements described - * in a particular instantiation of the class. - * - * @ingroup phases - */ -class Elements -{ - -public: - - //! Default constructor for the elements class - Elements(); - - //! Default destructor for the elements class - ~Elements(); - - - //! copy constructor - /*! - * This copy constructor just calls the assignment operator for this - * class. It sets the number of subscribers to zer0. - * - * @param right Reference to the object to be copied. - */ - Elements(const Elements& right); - - //! Assigntment operator - /*! - * This is the assignment operator for the Elements class. - * Right now we pretty much do a straight uncomplicated - * assignment. However, subscribers are not mucked with, as they - * have to do with the address of the object to be subscribed to - * - * @param right Reference to the object to be copied. - */ - Elements& operator=(const Elements& right); - - - //! Static function to look up an atomic weight - /*! - * This static function looks up the argument string in the - * database above and returns the associated molecular weight. - * The data are from the periodic table. - * - * Note: The idea behind this function is to provide a unified - * source for the element atomic weights. This helps to - * ensure that mass is conserved. - * - * @param ename String, Only the first 3 characters are significant - * - * @return - * Return value contains the atomic weight of the element - * If a match for the string is not found, a value of -1.0 is - * returned. - * - * @exception CanteraError - * If a match is not found, a CanteraError is thrown as well - */ - static double LookupWtElements(const std::string& ename); - - /// Atomic weight of element m. - /*! - * @param m element index - */ - doublereal atomicWeight(size_t m) const { - return m_atomicWeights[m]; - } - - /// Atomic number of element m. - /*! - * @param m element index - */ - int atomicNumber(size_t m) const { - return m_atomicNumbers[m]; - } - - //! Entropy at 298.15 K and 1 bar of stable state - //! of the element - /*! - * units J kmol-1 K-1 - * - * @param m Element index - */ - doublereal entropyElement298(size_t m) const; - - //! Return the element constraint type - /*! - * Possible types include: - * - * CT_ELEM_TYPE_ABSPOS 0 - * CT_ELEM_TYPE_ELECTRONCHARGE 1 - * CT_ELEM_TYPE_CHARGENEUTRALITY 2 - * CT_ELEM_TYPE_LATTICERATIO 3 - * CT_ELEM_TYPE_KINETICFROZEN 4 - * CT_ELEM_TYPE_SURFACECONSTRAINT 5 - * CT_ELEM_TYPE_OTHERCONSTRAINT 6 - * - * The default is CT_ELEM_TYPE_ABSPOS - * - * @param m Element index - * - * @return Returns the element type - */ - int elementType(size_t m) const; - - //! Change the element type of the mth constraint - /*! - * Reassigns an element type - * - * @param m Element index - * @param elem_type New elem type to be assigned - * - * @return Returns the old element type - */ - int changeElementType(int m, int elem_type); - - /// vector of element atomic weights - const vector_fp& atomicWeights() const { - return m_atomicWeights; - } - - /** - * Inline function that returns the number of elements in the object. - * - * @return - * \c int: The number of elements in the object. - */ - size_t nElements() const { - return m_mm; - } - - //! Function that returns the index of an element. - /*! - * Index of element named \c name. The index is an integer - * assigned to each element in the order it was added, - * beginning with 0 for the first element. If \c name is not - * the name of an element in the set, then the value -1 is - * returned. - * - * @param name String containing the index. - */ - size_t elementIndex(std::string name) const; - - //! Name of the element with index \c m. - /*! - * @param m Element index. If m < 0 or m >= nElements() an exception is thrown. - */ - std::string elementName(size_t m) const; - - //! Returns a string vector containing the element names - /*! - * Returns a read-only reference to the vector of element names. - * @return const vector& : The vector contains - * the element names in their indexed order. - */ - const std::vector& elementNames() const { - return m_elementNames; - } - - //! Add an element to the current set of elements in the current object. - /*! - * The default weight is a special value, which will cause the - * routine to look up the actual weight via a string lookup. - * - * There are two interfaces to this routine. The XML interface - * looks up the required parameters for the regular interface - * and then calls the base routine. - * - * @param symbol string symbol for the element. - * @param weight Atomic weight of the element. If no argument - * is provided, a lookup is attempted. - */ - void addElement(const std::string& symbol, - doublereal weight = -12345.0); - - //! Add an element to the current set of elements in the current object. - /*! - * @param e Reference to the XML_Node containing the element information - * The node name is the element symbol and the atomWt attribute - * is used as the atomic weight. - */ - void addElement(const XML_Node& e); - - //! Add an element only if the element hasn't been added before. - /*! - * This is accomplished via a string match on symbol. - * - * @param symbol string symbol for the element. - * @param weight Atomic weight of the element. If no argument - * is provided, a lookup is attempted. - * @param atomicNumber defaults to 0 - * @param entropy298 Value of the entropy at 298 and 1 bar of the - * element in its most stable form. - * The default is to specify an ENTROPY298_UNKNOWN value, - * which will cause a throw error if it's ever - * needed. - * @param elem_type New elem type to be assigned. - * The default is a regular element, CT_ELEM_TYPE_ABSPOS - */ - void addUniqueElement(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 to the current set of elements in the current object. - /*! - * @param e Reference to the XML_Node containing the element information - * The node name is the element symbol and the atomWt attribute - * is used as the atomic weight. - */ - void addUniqueElement(const XML_Node& e); - - //! Add multiple elements from a XML_Node phase description - /*! - * @param phase XML_Node reference to a phase - */ - void addElementsFromXML(const XML_Node& phase); - - //! Prohibit addition of more elements, and prepare to add species. - void freezeElements(); - - //! True if freezeElements has been called. - bool elementsFrozen() const; - - /// Remove all elements - void clear(); - - /// True if both elements and species have been frozen - bool ready() const; - - - //! subscribe to this object - /*! - * Increment by one the number of subscriptions to this object. - */ - void subscribe(); - - //! unsubscribe to this object - /*! - * decrement by one the number of subscriptions to this object. - */ - int unsubscribe(); - - //! report the number of subscriptions - int reportSubscriptions() const; - -protected: - - /******************************************************************/ - /* Description of DATA in the Object */ - /******************************************************************/ - - //! Number of elements. - size_t m_mm; - - /* m_elementsFrozen: */ - /** boolean indicating completion of object - * - * If this is true, then no elements may be added to the - * object. - */ - bool m_elementsFrozen; - - /** - * Vector of element atomic weights: - * - * units = kg / kmol - */ - vector_fp m_atomicWeights; - - /** - * Vector of element atomic numbers: - * - */ - vector_int m_atomicNumbers; - - /** Vector of strings containing the names of the elements - * - * Note, a string search is the primary way to identify elements. - */ - std::vector m_elementNames; - - //! Entropy at 298.15 K and 1 bar of stable state - /*! - * units J kmol-1 - */ - vector_fp m_entropy298; - - //! Vector of element types - vector_int m_elem_type; - - /** - * Number of Constituents Objects that use this object - * - * Number of Constituents Objects that require this Elements object - * to complete its definition. - * The destructor checks to see that this is equal to zero. - * when the element object is released. - */ - int numSubscribers; - - /********* GLOBAL STATIC SECTION *************/ - -public: - /** Vector of pointers to Elements Objects - * - */ - static std::vector Global_Elements_List; - - friend class Phase; -}; +//! Function to look up an atomic weight +//! This function looks up the argument string in the database above and +//! returns the associated molecular weight. +//! The data are from the periodic table. +//! +//! Note: The idea behind this function is to provide a unified source for the +//! element atomic weights. This helps to ensure that mass is conserved. +//! @param ename String, Only the first 3 characters are significant +//! @return The atomic weight of the element +//! @exception CanteraError If a match is not found, throws a CanteraError +double LookupWtElements(const std::string& ename); } // namespace diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index 04af40c9f..c2e079f36 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -15,6 +15,20 @@ namespace Cantera { class SpeciesThermo; +//! 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(std::string func) + : CanteraError(func, "Elements cannot be added after species.") {} +}; + //! Base class for phases of matter /*! * Class Phase manages the species and elements in a phase, as well as the @@ -149,8 +163,30 @@ public: //! @param m Element index int atomicNumber(size_t m) const; + //! Return the element constraint type + //! Possible types include: + //! + //! CT_ELEM_TYPE_TURNEDOFF -1 + //! CT_ELEM_TYPE_ABSPOS 0 + //! CT_ELEM_TYPE_ELECTRONCHARGE 1 + //! CT_ELEM_TYPE_CHARGENEUTRALITY 2 + //! CT_ELEM_TYPE_LATTICERATIO 3 + //! CT_ELEM_TYPE_KINETICFROZEN 4 + //! CT_ELEM_TYPE_SURFACECONSTRAINT 5 + //! CT_ELEM_TYPE_OTHERCONSTRAINT 6 + //! + //! The default is CT_ELEM_TYPE_ABSPOS. + //! @param m Element index + //! @return Returns the element type int elementType(size_t m) const; + //! Change the element type of the mth constraint + //! Reassigns an element type. + //! @param m Element index + //! @param elem_type New elem type to be assigned + //! @return Returns the old element type + int changeElementType(int m, int elem_type); + //! Return a read-only reference to the vector of atomic weights. const vector_fp& atomicWeights() const; @@ -547,7 +583,7 @@ public: //! Add an element. //! @param symbol Atomic symbol std::string. //! @param weight Atomic mass in amu. - void addElement(const std::string& symbol, doublereal weight); + void addElement(const std::string& symbol, doublereal weight=-12345.0); //! Add an element from an XML specification. //! @param e Reference to the XML_Node where the element is described. @@ -565,7 +601,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. - void addUniqueElement(const std::string& symbol, doublereal weight, + void addUniqueElement(const std::string& symbol, doublereal weight=-12345.0, int atomicNumber = 0, doublereal entropy298 = ENTROPY298_UNKNOWN, int elem_type = CT_ELEM_TYPE_ABSPOS); @@ -629,9 +665,6 @@ public: virtual bool ready() const; - //! Remove all elements and species - void clear(); - //! Return the State Mole Fraction Number DEPRECATED(int stateMFNumber() const) { return m_stateNum; @@ -717,12 +750,21 @@ private: //! of the the phase, this is true. bool m_speciesFrozen; - //! Pointer to the element object corresponding to this phase. Normally, - //! this will be the default Element object common to all phases. - Elements* m_Elements; + //! If this is true, then no elements may be added to the object. + bool m_elementsFrozen; //! Vector of the species names std::vector m_speciesNames; + + size_t m_mm; //!< Number of elements. + vector_fp m_atomicWeights; //!< element atomic weights (kg kmol-1) + vector_int m_atomicNumbers; //!< element atomic numbers + std::vector m_elementNames; //!< element names + vector_int m_elem_type; //!< Vector of element types + + //! Entropy at 298.15 K and 1 bar of stable state pure elements (J kmol-1) + vector_fp m_entropy298; + }; //! typedef for the base Phase class diff --git a/src/thermo/Elements.cpp b/src/thermo/Elements.cpp index b8d1d8fb9..1b99cb27a 100644 --- a/src/thermo/Elements.cpp +++ b/src/thermo/Elements.cpp @@ -9,27 +9,16 @@ // Copyright 2003 California Institute of Technology #include "cantera/thermo/Elements.h" -#include "cantera/base/xml.h" -#include "cantera/base/ctml.h" #include "cantera/base/ctexceptions.h" -#include "cantera/base/stringUtils.h" -using namespace ctml; using namespace std; -#ifdef USE_DGG_CODE -#include -#endif #include namespace Cantera { - -/* awData structure */ -/** - * Database for atomic molecular weights - * +/*! Database for atomic molecular weights * Values are taken from the 1989 Standard Atomic Weights, CRC * * awTable[] is a static function with scope limited to this file. @@ -38,13 +27,11 @@ namespace Cantera * * units = kg / kg-mol (or equivalently gm / gm-mol) * - * (note: this structure was picked because it's simple, compact, - * and extensible). - * + * This structure was picked because it's simple, compact, and extensible. */ struct awData { - char name[4]; ///< Null Terminated name, First letter capitalized - double atomicWeight; ///< atomic weight in kg / kg-mol + char name[4]; //!< Null Terminated name, First letter capitalized + double atomicWeight; //!< atomic weight in kg / kg-mol }; /*! @@ -152,28 +139,7 @@ static struct awData aWTable[] = { {"Pu", 244.0482 } }; - -// Static function to look up an atomic weight -/* - * This static function looks up the argument string in the - * database above and returns the associated molecular weight. - * The data are from the periodic table. - * - * Note: The idea behind this function is to provide a unified - * source for the element atomic weights. This helps to - * ensure that mass is conserved. - * - * @param s String, Only the first 3 characters are significant - * - * @return - * Return value contains the atomic weight of the element - * If a match for the string is not found, a value of -1.0 is - * returned. - * - * @exception CanteraError - * If a match is not found, a CanteraError is thrown as well - */ -doublereal Elements::LookupWtElements(const std::string& ename) +doublereal LookupWtElements(const std::string& ename) { int num = sizeof(aWTable) / sizeof(struct awData); string s3 = ename.substr(0,3); @@ -186,486 +152,4 @@ doublereal Elements::LookupWtElements(const std::string& ename) return -1.0; } - -//! 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(string func) - : CanteraError(func, - "elements cannot be added after species.") {} -}; - -/* - * Elements Class Constructor - * We initialize all internal variables to zero here. - */ -Elements::Elements() : - m_mm(0), - m_elementsFrozen(false), - m_elem_type(0), - numSubscribers(0) -{ -} - -/* - * Elements Class Destructor - * If the number of subscribers is not zero, through an error. - * A logic problem has occurred. - * - * @exception CanteraError - */ -Elements::~Elements() -{ - if (numSubscribers != 0) { - throw CanteraError("~Elements", "numSubscribers not zero"); - } -} - -Elements::Elements(const Elements& right) : - m_mm(0), - m_elementsFrozen(false), - numSubscribers(0) -{ - *this = operator=(right); -} - -Elements& Elements::operator=(const Elements& right) -{ - if (&right == this) { - return *this; - } - - 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; - m_entropy298 = right.m_entropy298; - m_elem_type = right.m_elem_type; - numSubscribers = 0; - - return *this; -} - - - -/* - * freezeElements(): - * - * Set the freeze flag. This is a prerequesite to other - * activivities, i.e., this is done before species are defined. - */ -void Elements::freezeElements() -{ - m_elementsFrozen = true; -} - -#ifdef INCL_DEPRECATED_METHODS -/* - * - * Returns an ElementData struct that contains the parameters - * for element index m. - */ -ElementData Elements::element(int m) const -{ - ElementData e; - e.name = m_elementNames[m]; - e.atomicWeight = m_atomicWeights[m]; - return e; -} -#endif -/* - * elementIndex(): - * - * Index of element named \c name. The index is an integer - * assigned to each element in the order it was added, - * beginning with 0 for the first element. If \c name is not - * the name of an element in the set, then the value -1 is - * returned. - * - */ -#ifdef USE_DGG_CODE -size_t Elements::elementIndex(std::string name) const -{ - map::const_iterator it; - it = m_definedElements.find(name); - if (it != m_definedElements.end()) { - return it->second; - } - return -1; -} -#else -size_t Elements::elementIndex(std::string name) const -{ - for (size_t i = 0; i < m_mm; i++) { - if (m_elementNames[i] == name) { - return i; - } - } - return npos; -} -#endif - -/* - * - * Name of the element with index \c m. @param m Element - * index. If m < 0 or m >= nElements() an exception is thrown. - */ -string Elements::elementName(size_t m) const -{ - if (m >= nElements()) { - throw IndexError("Elements::elementName", "m_elementNames", - m, nElements()); - } - return m_elementNames[m]; -} - - -doublereal Elements::entropyElement298(size_t m) const -{ - AssertThrowMsg(m_entropy298[m] != ENTROPY298_UNKNOWN, - "Elements::entropy298", - "Entropy at 298 K of element is unknown"); - AssertTrace(m < m_mm); - return (m_entropy298[m]); -} -//==================================================================================================================== -//! Return the element constraint type -/*! - * Possible types include: - * - * CT_ELEM_TYPE_TURNEDOFF -1 - * CT_ELEM_TYPE_ABSPOS 0 - * CT_ELEM_TYPE_ELECTRONCHARGE 1 - * CT_ELEM_TYPE_CHARGENEUTRALITY 2 - * CT_ELEM_TYPE_LATTICERATIO 3 - * CT_ELEM_TYPE_KINETICFROZEN 4 - * CT_ELEM_TYPE_SURFACECONSTRAINT 5 - * CT_ELEM_TYPE_OTHERCONSTRAINT 6 - * - * The default is CT_ELEM_TYPE_ABSPOS - */ -int Elements::elementType(size_t m) const -{ - return m_elem_type[m]; -} -//==================================================================================================================== -// Change the element type of the mth constraint -/* - * Reassigns an element type - * - * @param m Element index - * @param elem_type New elem type to be assigned - * - * @return Returns the old element type - */ -int Elements::changeElementType(int m, int elem_type) -{ - int old = m_elem_type[m]; - m_elem_type[m] = elem_type; - return old; -} -//==================================================================================================================== -/* - * - * Add an element to the current set of elements in the current object. - * @param symbol symbol string - * @param weight atomic weight in kg/kmol. - * - * The default weight is a special value, which will cause the - * routine to look up the actual weight via a string lookup. - * - * There are two interfaces to this routine. The XML interface - * looks up the required parameters for the regular interface - * and then calls the base routine. - */ -void Elements:: -addElement(const std::string& symbol, doublereal weight) -{ - if (weight == -12345.0) { - weight = LookupWtElements(symbol); - if (weight < 0.0) { - throw ElementsFrozen("addElement"); - } - } - if (m_elementsFrozen) { - throw ElementsFrozen("addElement"); - return; - } - m_atomicWeights.push_back(weight); - m_elementNames.push_back(symbol); -#ifdef USE_DGG_CODE - m_definedElements[symbol] = nElements() + 1; -#endif - if (symbol == "E") { - m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE); - } else { - m_elem_type.push_back(CT_ELEM_TYPE_ABSPOS); - } - - m_mm++; -} -//=========================================================================================================== -void Elements:: -addElement(const XML_Node& e) -{ - doublereal weight = atof(e["atomicWt"].c_str()); - string symbol = e["name"]; - addElement(symbol, weight); -} -//=========================================================================================================== -/* - * addUniqueElement(): - * - * Add a unique element to the set. This routine will not allow - * duplicate elements to be input. - * - * @param symbol symbol string - * @param weight atomic weight in kg/kmol. - * - * - * The default weight is a special value, which will cause the - * routine to look up the actual weight via a string lookup. - */ -#ifdef USE_DGG_CODE -void Elements:: -addUniqueElement(const std::string& symbol, doublereal weight, int atomicNumber, - doublereal entropy298, int elem_type) -{ - if (m_elementsFrozen) { - throw ElementsFrozen("addElement"); - } - - if (weight == -12345.0) { - weight = LookupWtElements(symbol); - } - - /* - * First decide if this element has been previously added. - * If it unique, add it to the list. - */ - - int i = m_definedElements[symbol] - 1; - if (i < 0) { - m_atomicWeights.push_back(weight); - m_elementNames.push_back(symbol); - m_atomicNumbers.push_back(atomicNumber); - 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"); - } - } -} - -#else -void Elements:: -addUniqueElement(const std::string& symbol, - doublereal weight, int atomicNumber, 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::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(atomicNumber); - 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"); - } - } -} -#endif - - -/* - * @todo call addUniqueElement(symbol, weight) instead of - * addElement. - */ -void Elements:: -addUniqueElement(const XML_Node& e) -{ - doublereal weight = 0.0; - if (e.hasAttrib("atomicWt")) { - weight = atof(stripws(e["atomicWt"]).c_str()); - } - int anum = 0; - if (e.hasAttrib("atomicNumber")) { - anum = atoi(stripws(e["atomicNumber"]).c_str()); - } - string symbol = e["name"]; - doublereal entropy298 = ENTROPY298_UNKNOWN; - if (e.hasChild("entropy298")) { - XML_Node& e298Node = e.child("entropy298"); - if (e298Node.hasAttrib("value")) { - entropy298 = atofCheck(stripws(e298Node["value"]).c_str()); - } - } - if (weight != 0.0) { - addUniqueElement(symbol, weight, anum, entropy298); - } else { - addUniqueElement(symbol); - } -} - -// True if freezeElements has been called. -bool Elements::elementsFrozen() const -{ - return m_elementsFrozen; -} - -/* - * clear() - * - * Remove all elements from the structure. - */ -void Elements::clear() -{ - m_mm = 0; - m_atomicWeights.resize(0); - m_elementNames.resize(0); - m_entropy298.resize(0); - m_elem_type.resize(0); - m_elementsFrozen = false; -} - -/* - * ready(): - * - * True if the elements have been frozen - */ -bool Elements::ready() const -{ - return (m_elementsFrozen); -} - - -void Elements::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 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 = phase.root(); - XML_Node* local_db = 0; - if (root.hasChild("ctml")) { - if (root.child("ctml").hasChild("elementData")) { - local_db = &root.child("ctml/elementData"); - } - } - - int nel = static_cast(enames.size()); - int i; - string enm; - XML_Node* e = 0; - for (i = 0; i < nel; i++) { - e = 0; - if (local_db) { - //writelog("looking in local database."); - e = local_db->findByAttr("name",enames[i]); - //if (!e) writelog(enames[i]+" not found."); - } - if (!e) { - e = dbe->findByAttr("name",enames[i]); - } - if (e) { - addUniqueElement(*e); - } else { - throw CanteraError("addElementsFromXML","no data for element " - +enames[i]); - } - } - -} - -/* - * subscribe(), unsubscribe(), and reportSubscriptions(): - * - * Handles setting and reporting the number of subscriptions to this - * object. - */ -void Elements::subscribe() -{ - ++numSubscribers; -} -int Elements::unsubscribe() -{ - --numSubscribers; - return numSubscribers; -} -int Elements::reportSubscriptions() const -{ - return numSubscribers; -} - -/********************* GLOBAL STATIC SECTION **************************/ -/* - * We keep track of a vector of pointers to element objects. - * Initially there are no Elements objects. Whenever one is created, - * the pointer to that object is added onto this list. - */ -vector Elements::Global_Elements_List; -/***********************************************************************/ } diff --git a/src/thermo/Phase.cpp b/src/thermo/Phase.cpp index bb2086c49..76fe6ab86 100644 --- a/src/thermo/Phase.cpp +++ b/src/thermo/Phase.cpp @@ -25,10 +25,11 @@ Phase::Phase() : m_dens(0.001), m_mmw(0.0), m_stateNum(-1), - m_speciesFrozen(false) , - m_Elements(new Elements()) + m_speciesFrozen(false), + m_elementsFrozen(false), + m_mm(0), + m_elem_type(0) { - m_Elements->subscribe(); } Phase::Phase(const Phase& right) : @@ -42,7 +43,9 @@ Phase::Phase(const Phase& right) : m_mmw(0.0), m_stateNum(-1), m_speciesFrozen(false) , - m_Elements(0) + m_elementsFrozen(false), + m_mm(0), + m_elem_type(0) { // Use the assignment operator to do the actual copying *this = operator=(right); @@ -66,30 +69,20 @@ Phase& Phase::operator=(const Phase& right) m_molwts = right.m_molwts; m_rmolwts = right.m_rmolwts; m_stateNum = -1; + m_speciesFrozen = right.m_speciesFrozen; - if (m_Elements) { - int nleft = m_Elements->unsubscribe(); - if (nleft <= 0) { - vector::iterator it; - for (it = Elements::Global_Elements_List.begin(); - it != Elements::Global_Elements_List.end(); ++it) { - if (*it == m_Elements) { - Elements::Global_Elements_List.erase(it); - break; - } - } - delete m_Elements; - } - } - m_Elements = right.m_Elements; - if (m_Elements) { - m_Elements->subscribe(); - } m_speciesNames = right.m_speciesNames; m_speciesComp = right.m_speciesComp; m_speciesCharge = right.m_speciesCharge; 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; + m_entropy298 = right.m_entropy298; + m_elem_type = right.m_elem_type; /* * This is a little complicated. -> Because we delete m_xml * in the destructor, we own m_xml completely, and we need @@ -117,24 +110,6 @@ Phase::~Phase() delete m_xml; m_xml = 0; } - - int ileft = m_Elements->unsubscribe(); - /* - * Here we may delete Elements Objects or not. Right now, we - * will delete them. We also delete the global pointer entry - * to keep everything consistent. - */ - if (ileft <= 0) { - vector::iterator it; - for (it = Elements::Global_Elements_List.begin(); - it != Elements::Global_Elements_List.end(); ++it) { - if (*it == m_Elements) { - Elements::Global_Elements_List.erase(it); - break; - } - } - delete m_Elements; - } } inline void Phase::stateMFChangeCalc(bool forcerChange) @@ -174,52 +149,71 @@ void Phase::setName(std::string nm) size_t Phase::nElements() const { - return m_Elements->nElements(); + return m_mm; } string Phase::elementName(size_t m) const { - return m_Elements->elementName(m); + if (m >= nElements()) { + throw IndexError("Elements::elementName", "m_elementNames", + m, nElements()); + } + return m_elementNames[m]; } size_t Phase::elementIndex(std::string name) const { - return m_Elements->elementIndex(name); + for (size_t i = 0; i < m_mm; i++) { + if (m_elementNames[i] == name) { + return i; + } + } + return npos; } const vector& Phase::elementNames() const { - return m_Elements->elementNames(); + return m_elementNames; } doublereal Phase::atomicWeight(size_t m) const { - return m_Elements->atomicWeight(m); + return m_atomicWeights[m]; } doublereal Phase::entropyElement298(size_t m) const { - return m_Elements->entropyElement298(m); + AssertThrowMsg(m_entropy298[m] != ENTROPY298_UNKNOWN, + "Elements::entropy298", + "Entropy at 298 K of element is unknown"); + AssertTrace(m < m_mm); + return (m_entropy298[m]); } const vector_fp& Phase::atomicWeights() const { - return m_Elements->atomicWeights(); + return m_atomicWeights; } int Phase::atomicNumber(size_t m) const { - return m_Elements->atomicNumber(m); + return m_atomicNumbers[m]; } int Phase::elementType(size_t m) const { - return m_Elements->elementType(m); + return m_elem_type[m]; +} + +int Phase::changeElementType(int m, int elem_type) +{ + int old = m_elem_type[m]; + m_elem_type[m] = elem_type; + return old; } doublereal Phase::nAtoms(size_t k, size_t m) const { - const size_t m_mm = m_Elements->nElements(); if (m >= m_mm) { throw IndexError("Phase::nAtoms", "", m, nElements()); } @@ -231,7 +225,6 @@ doublereal Phase::nAtoms(size_t k, size_t m) const void Phase::getAtoms(size_t k, double* atomArray) const { - const size_t m_mm = m_Elements->nElements(); for (size_t m = 0; m < m_mm; m++) { atomArray[m] = (double) m_speciesComp[m_mm * k + m]; } @@ -655,40 +648,165 @@ doublereal Phase::sum_xlogQ(doublereal* Q) const void Phase::addElement(const std::string& symbol, doublereal weight) { - m_Elements->addElement(symbol, weight); + if (weight == -12345.0) { + weight = LookupWtElements(symbol); + if (weight < 0.0) { + throw ElementsFrozen("addElement"); + } + } + if (m_elementsFrozen) { + throw ElementsFrozen("addElement"); + return; + } + m_atomicWeights.push_back(weight); + m_elementNames.push_back(symbol); + if (symbol == "E") { + m_elem_type.push_back(CT_ELEM_TYPE_ELECTRONCHARGE); + } else { + m_elem_type.push_back(CT_ELEM_TYPE_ABSPOS); + } + + m_mm++; } void Phase::addElement(const XML_Node& e) { - m_Elements->addElement(e); + doublereal weight = atof(e["atomicWt"].c_str()); + string symbol = e["name"]; + addElement(symbol, weight); } void Phase::addUniqueElement(const std::string& symbol, doublereal weight, int atomicNumber, doublereal entropy298, int elem_type) { - m_Elements->addUniqueElement(symbol, weight, atomicNumber, - entropy298, 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::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(atomicNumber); + 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) { - m_Elements->addUniqueElement(e); + doublereal weight = 0.0; + if (e.hasAttrib("atomicWt")) { + weight = atof(stripws(e["atomicWt"]).c_str()); + } + int anum = 0; + if (e.hasAttrib("atomicNumber")) { + anum = atoi(stripws(e["atomicNumber"]).c_str()); + } + string symbol = e["name"]; + doublereal entropy298 = ENTROPY298_UNKNOWN; + if (e.hasChild("entropy298")) { + XML_Node& e298Node = e.child("entropy298"); + if (e298Node.hasAttrib("value")) { + entropy298 = atofCheck(stripws(e298Node["value"]).c_str()); + } + } + if (weight != 0.0) { + addUniqueElement(symbol, weight, anum, entropy298); + } else { + addUniqueElement(symbol); + } } void Phase::addElementsFromXML(const XML_Node& phase) { - m_Elements->addElementsFromXML(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 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"); + } + } + + int nel = static_cast(enames.size()); + int i; + string enm; + XML_Node* e = 0; + for (i = 0; i < nel; i++) { + e = 0; + if (local_db) { + //writelog("looking in local database."); + e = local_db->findByAttr("name",enames[i]); + //if (!e) writelog(enames[i]+" not found."); + } + if (!e) { + e = dbe->findByAttr("name",enames[i]); + } + if (e) { + addUniqueElement(*e); + } else { + throw CanteraError("addElementsFromXML","no data for element " + +enames[i]); + } + } } void Phase::freezeElements() { - m_Elements->freezeElements(); + m_elementsFrozen = true; } bool Phase::elementsFrozen() { - return m_Elements->elementsFrozen(); + return m_elementsFrozen; } size_t Phase::addUniqueElementAfterFreeze(const std::string& symbol, @@ -700,10 +818,9 @@ size_t Phase::addUniqueElementAfterFreeze(const std::string& symbol, return ii; } // Check to see that the element isn't really in the list - m_Elements->m_elementsFrozen = false; + m_elementsFrozen = false; addUniqueElement(symbol, weight, atomicNumber, entropy298, elem_type); - m_Elements->m_elementsFrozen = true; - size_t m_mm = m_Elements->nElements(); + m_elementsFrozen = true; ii = elementIndex(symbol); if (ii != m_mm-1) { throw CanteraError("Phase::addElementAfterFreeze()", "confused"); @@ -725,11 +842,11 @@ size_t Phase::addUniqueElementAfterFreeze(const std::string& symbol, void Phase::addSpecies(const std::string& name, const doublereal* comp, doublereal charge, doublereal size) { - m_Elements->freezeElements(); + freezeElements(); m_speciesNames.push_back(name); m_speciesCharge.push_back(charge); m_speciesSize.push_back(size); - size_t ne = m_Elements->nElements(); + size_t ne = nElements(); // Create a changeable copy of the element composition. We now change // the charge potentially vector_fp compNew(ne); @@ -737,9 +854,9 @@ void Phase::addSpecies(const std::string& name, const doublereal* comp, compNew[m] = comp[m]; } double wt = 0.0; - const vector_fp& aw = m_Elements->atomicWeights(); + const vector_fp& aw = atomicWeights(); if (charge != 0.0) { - size_t eindex = m_Elements->elementIndex("E"); + size_t eindex = elementIndex("E"); if (eindex != npos) { doublereal ecomp = compNew[eindex]; if (fabs(charge + ecomp) > 0.001) { @@ -756,8 +873,8 @@ void Phase::addSpecies(const std::string& name, const doublereal* comp, } else { addUniqueElementAfterFreeze("E", 0.000545, 0, 0.0, CT_ELEM_TYPE_ELECTRONCHARGE); - ne = m_Elements->nElements(); - eindex = m_Elements->elementIndex("E"); + ne = nElements(); + eindex = elementIndex("E"); compNew.resize(ne); compNew[ne - 1] = - charge; } @@ -779,7 +896,6 @@ void Phase::addUniqueSpecies(const std::string& name, const doublereal* comp, // We have found a match. At this point we could do some // compatibility checks. However, let's just return for the moment // without specifying any error. - size_t m_mm = m_Elements->nElements(); for (size_t i = 0; i < m_mm; i++) { if (comp[i] != m_speciesComp[m_kk * m_mm + i]) { throw CanteraError("addUniqueSpecies", @@ -809,7 +925,6 @@ void Phase::freezeSpecies() m_speciesFrozen = true; init(molecularWeights()); size_t kk = nSpecies(); - size_t nv = kk + 2; m_kk = nSpecies(); } @@ -848,7 +963,7 @@ void Phase::init(const vector_fp& mw) bool Phase::ready() const { - return (m_kk > 0 && m_Elements->elementsFrozen() && m_speciesFrozen); + return (m_kk > 0 && m_elementsFrozen && m_speciesFrozen); } } // namespace Cantera