From 4dd3e1d2bc08a504d656edb96938743d7af15c56 Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Fri, 17 Oct 2014 23:44:47 +0000 Subject: [PATCH] Use Species objects when adding species from XML --- include/cantera/thermo/Mu0Poly.h | 5 +- include/cantera/thermo/Species.h | 2 +- include/cantera/thermo/SpeciesThermoFactory.h | 8 + src/thermo/LatticeSolidPhase.cpp | 8 +- src/thermo/Mu0Poly.cpp | 9 +- src/thermo/Species.cpp | 2 +- src/thermo/SpeciesThermoFactory.cpp | 453 ++++++++---------- src/thermo/ThermoFactory.cpp | 32 +- src/thermo/ThermoPhase.cpp | 5 +- src/thermo/VPSSMgr.cpp | 8 +- src/thermo/VPSSMgr_IdealGas.cpp | 7 +- 11 files changed, 236 insertions(+), 303 deletions(-) diff --git a/include/cantera/thermo/Mu0Poly.h b/include/cantera/thermo/Mu0Poly.h index 7f4997ec5..1b57633ed 100644 --- a/include/cantera/thermo/Mu0Poly.h +++ b/include/cantera/thermo/Mu0Poly.h @@ -220,9 +220,8 @@ private: * * @ingroup spthermo */ -void installMu0ThermoFromXML(const std::string& speciesName, - SpeciesThermo& sp, size_t k, - const XML_Node* Mu0Node_ptr); +Mu0Poly* newMu0ThermoFromXML(const std::string& speciesName, + const XML_Node& Mu0Node); } #endif diff --git a/include/cantera/thermo/Species.h b/include/cantera/thermo/Species.h index 609890030..11bda2246 100644 --- a/include/cantera/thermo/Species.h +++ b/include/cantera/thermo/Species.h @@ -34,7 +34,7 @@ public: ~Species(); //! Access the thermodynamic parameterization for the species - const SpeciesThermoInterpType& thermo() const; + SpeciesThermoInterpType& thermo(); //! The name of the species std::string name; diff --git a/include/cantera/thermo/SpeciesThermoFactory.h b/include/cantera/thermo/SpeciesThermoFactory.h index 457a01e5f..1856089ae 100644 --- a/include/cantera/thermo/SpeciesThermoFactory.h +++ b/include/cantera/thermo/SpeciesThermoFactory.h @@ -296,6 +296,14 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(int type, double tlow, SpeciesThermoInterpType* newSpeciesThermoInterpType(const std::string& type, double tlow, double thigh, double pref, const double* coeffs); +//! Create a new SpeciesThermoInterpType object from XML_Node +/*! + * @param speciesNode XML_Node defining the species (with child 'thermo' node) + * @return Returns the pointer to the newly allocated + * SpeciesThermoInterpType object + */ +SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& speciesNode); + } #endif diff --git a/src/thermo/LatticeSolidPhase.cpp b/src/thermo/LatticeSolidPhase.cpp index 4a0f1e44d..ea28940e1 100644 --- a/src/thermo/LatticeSolidPhase.cpp +++ b/src/thermo/LatticeSolidPhase.cpp @@ -338,7 +338,6 @@ void LatticeSolidPhase::installSlavePhases(Cantera::XML_Node* phaseNode) { size_t kk = 0; size_t kstart = 0; - SpeciesThermoFactory* spFactory = SpeciesThermoFactory::factory(); m_speciesData.clear(); XML_Node& eosdata = phaseNode->child("thermo"); @@ -347,7 +346,6 @@ void LatticeSolidPhase::installSlavePhases(Cantera::XML_Node* phaseNode) la.getChildren("phase",lattices); for (size_t n = 0; n < m_nlattice; n++) { LatticePhase* lp = m_lattice[n]; - XML_Node* phaseNode_ptr = lattices[n]; size_t nsp = lp->nSpecies(); vector constArr(lp->nElements()); const vector_fp& aws = lp->atomicWeights(); @@ -383,8 +381,10 @@ void LatticeSolidPhase::installSlavePhases(Cantera::XML_Node* phaseNode) double chrg = lp->charge(k); double sz = lp->size(k); addUniqueSpecies(sname, &ecomp[0], chrg, sz); - spFactory->installThermoForSpecies(kk, *(spNode[k]), this, *m_spthermo, phaseNode_ptr); - + SpeciesThermoInterpType* stit = newSpeciesThermoInterpType(*spNode[k]); + stit->setIndex(kk); + stit->validate(spNode[k]->attrib("name")); + m_spthermo->install_STIT(stit); m_speciesData.push_back(new XML_Node(*(spNode[k]))); kk++; } diff --git a/src/thermo/Mu0Poly.cpp b/src/thermo/Mu0Poly.cpp index b741fda74..dc5d9911d 100644 --- a/src/thermo/Mu0Poly.cpp +++ b/src/thermo/Mu0Poly.cpp @@ -117,14 +117,11 @@ void Mu0Poly::modifyParameters(doublereal* coeffs) processCoeffs(coeffs); } -void installMu0ThermoFromXML(const std::string& speciesName, - SpeciesThermo& sp, size_t k, - const XML_Node* Mu0Node_ptr) +Mu0Poly* newMu0ThermoFromXML(const std::string& speciesName, + const XML_Node& Mu0Node) { - doublereal tmin, tmax; bool dimensionlessMu0Values = false; - const XML_Node& Mu0Node = *Mu0Node_ptr; tmin = fpValue(Mu0Node["Tmin"]); tmax = fpValue(Mu0Node["Tmax"]); @@ -200,7 +197,7 @@ void installMu0ThermoFromXML(const std::string& speciesName, c[2+i*2+1] = cValues[i]; } - sp.install(speciesName, k, MU0_INTERP, &c[0], tmin, tmax, pref); + return new Mu0Poly(0, tmin, tmax, pref, &c[0]); } void Mu0Poly::processCoeffs(const doublereal* coeffs) diff --git a/src/thermo/Species.cpp b/src/thermo/Species.cpp index 00df0a0f9..8bd8c88e8 100644 --- a/src/thermo/Species.cpp +++ b/src/thermo/Species.cpp @@ -62,7 +62,7 @@ Species& Species::operator=(const Species& other) } -const SpeciesThermoInterpType& Species::thermo() const +SpeciesThermoInterpType& Species::thermo() { if (thermo_) { return *thermo_; diff --git a/src/thermo/SpeciesThermoFactory.cpp b/src/thermo/SpeciesThermoFactory.cpp index 78c466c61..13343f7e3 100644 --- a/src/thermo/SpeciesThermoFactory.cpp +++ b/src/thermo/SpeciesThermoFactory.cpp @@ -49,6 +49,7 @@ mutex_t SpeciesThermoFactory::species_thermo_mutex; * @param has_other Return int that indicates whether the phase has a form for one of its species that is not one of the ones listed above. * * @todo Make sure that spDadta_node is species Data XML node by checking its name is speciesData + * @deprecated */ static void getSpeciesThermoTypes(std::vector & spDataNodeList, int& has_nasa, int& has_shomate, int& has_simple, @@ -239,32 +240,22 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(const std::string& stype, return newSpeciesThermoInterpType(itype, tlow, thigh, pref, coeffs); } -//! Install a NASA polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. +//! Create a NASA polynomial thermodynamic property parameterization for a +//! species from a set ! of XML nodes /*! - * This is called by method installThermoForSpecies if a NASA block is found in the XML input. + * This is called if a 'NASA' node is found in the XML input. * - * @param speciesName String name of the species - * @param sp SpeciesThermo object that will receive the NASA polynomial object - * @param k Species index within the phase - * @param f0ptr Ptr to the first XML_Node for the first NASA polynomial - * @param f1ptr Ptr to the first XML_Node for the first NASA polynomial + * @param speciesName name of the species + * @param nodes vector of 1 or 2 'NASA' XML_Nodes, each defining the + * coefficients for a temperature range */ -static void installNasaThermoFromXML(const std::string& speciesName, - SpeciesThermo& sp, size_t k, - const XML_Node* f0ptr, const XML_Node* f1ptr) +static SpeciesThermoInterpType* newNasaThermoFromXML( + const std::string& speciesName, vector nodes) { doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax; - const XML_Node& f0 = *f0ptr; - - // default to a single temperature range - bool dualRange = false; - - // but if f1ptr is suppled, then it is a two-range - // parameterization - if (f1ptr) { - dualRange = true; - } + const XML_Node& f0 = *nodes[0]; + bool dualRange = (nodes.size() > 1); tmin0 = fpValue(f0["Tmin"]); tmax0 = fpValue(f0["Tmax"]); @@ -281,8 +272,8 @@ static void installNasaThermoFromXML(const std::string& speciesName, tmin1 = tmax0; tmax1 = tmin1 + 0.0001; if (dualRange) { - tmin1 = fpValue((*f1ptr)["Tmin"]); - tmax1 = fpValue((*f1ptr)["Tmax"]); + tmin1 = fpValue(nodes[1]->attrib("Tmin")); + tmax1 = fpValue(nodes[1]->attrib("Tmax")); } vector_fp c0, c1; @@ -293,7 +284,7 @@ static void installNasaThermoFromXML(const std::string& speciesName, tmax = tmax1; getFloatArray(f0.child("floatArray"), c0, false); if (dualRange) { - getFloatArray(f1ptr->child("floatArray"), c1, false); + getFloatArray(nodes[1]->child("floatArray"), c1, false); } else { // if there is no higher range data, then copy c0 to c1. c1.resize(7,0.0); @@ -304,7 +295,7 @@ static void installNasaThermoFromXML(const std::string& speciesName, tmin = tmin1; tmid = tmax1; tmax = tmax0; - getFloatArray(f1ptr->child("floatArray"), c0, false); + getFloatArray(nodes[1]->child("floatArray"), c0, false); getFloatArray(f0.child("floatArray"), c1, false); } else { throw CanteraError("installNasaThermo", @@ -322,7 +313,7 @@ static void installNasaThermoFromXML(const std::string& speciesName, c[8] = c1[5]; c[9] = c1[6]; copy(c1.begin(), c1.begin()+5, c.begin() + 10); - sp.install(speciesName, k, NASA, &c[0], tmin, tmax, p0); + return newSpeciesThermoInterpType(NASA, tmin, tmax, p0, &c[0]); } //! Look up the elemental reference state entropies @@ -352,22 +343,22 @@ static doublereal LookupGe(const std::string& elemName, ThermoPhase* th_ptr) * @param k species index * @param th_ptr Pointer to the ThermoPhase */ -static doublereal convertDGFormation(size_t k, ThermoPhase* th_ptr) +static doublereal convertDGFormation(const compositionMap& comp, ThermoPhase* th_ptr) { /* * Ok let's get the element compositions and conversion factors. */ - size_t ne = th_ptr->nElements(); doublereal na; doublereal ge; string ename; doublereal totalSum = 0.0; - for (size_t m = 0; m < ne; m++) { - na = th_ptr->nAtoms(k, m); + for (compositionMap::const_iterator iter = comp.begin(); + iter != comp.end(); + ++iter) { + na = iter->second; if (na > 0.0) { - ename = th_ptr->elementName(m); - ge = LookupGe(ename, th_ptr); + ge = LookupGe(iter->first, th_ptr); totalSum += na * ge; } } @@ -375,40 +366,34 @@ static doublereal convertDGFormation(size_t k, ThermoPhase* th_ptr) } -//! Install a NASA96 polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. +//! Create a Shomate polynomial from an XML node giving the 'EQ3' coefficients /*! - * This is called by method installThermoForSpecies if a MinEQ3node block is found in the XML input. + * This is called if a 'MinEQ3' node is found in the XML input. * - * @param speciesName String name of the species - * @param th_ptr Pointer to the %ThermoPhase object - * @param sp SpeciesThermo object that will receive the NASA polynomial object - * @param k Species index within the phase - * @param MinEQ3node Ptr to the first XML_Node for the first MinEQ3 parameterization + * @param speciesName name of the species + * @param MinEQ3node The XML_Node containing the MinEQ3 parameterization */ -static void installMinEQ3asShomateThermoFromXML(const std::string& speciesName, - ThermoPhase* th_ptr, - SpeciesThermo& sp, size_t k, - const XML_Node* MinEQ3node) +SpeciesThermoInterpType* newShomateForMineralEQ3(const std::string& name, + const XML_Node& MinEQ3node) { - vector_fp coef(15), c0(7, 0.0); - std::string astring = (*MinEQ3node)["Tmin"]; + std::string astring = MinEQ3node["Tmin"]; doublereal tmin0 = strSItoDbl(astring); - astring = (*MinEQ3node)["Tmax"]; + astring = MinEQ3node["Tmax"]; doublereal tmax0 = strSItoDbl(astring); - astring = (*MinEQ3node)["Pref"]; + astring = MinEQ3node["Pref"]; doublereal p0 = strSItoDbl(astring); doublereal deltaG_formation_pr_tr = - getFloatDefaultUnits(*MinEQ3node, "DG0_f_Pr_Tr", "cal/gmol", "actEnergy"); + getFloatDefaultUnits(MinEQ3node, "DG0_f_Pr_Tr", "cal/gmol", "actEnergy"); doublereal deltaH_formation_pr_tr = - getFloatDefaultUnits(*MinEQ3node, "DH0_f_Pr_Tr", "cal/gmol", "actEnergy"); - doublereal Entrop_pr_tr = getFloatDefaultUnits(*MinEQ3node, "S0_Pr_Tr", "cal/gmol/K"); - doublereal a = getFloatDefaultUnits(*MinEQ3node, "a", "cal/gmol/K"); - doublereal b = getFloatDefaultUnits(*MinEQ3node, "b", "cal/gmol/K2"); - doublereal c = getFloatDefaultUnits(*MinEQ3node, "c", "cal-K/gmol"); + getFloatDefaultUnits(MinEQ3node, "DH0_f_Pr_Tr", "cal/gmol", "actEnergy"); + doublereal Entrop_pr_tr = getFloatDefaultUnits(MinEQ3node, "S0_Pr_Tr", "cal/gmol/K"); + doublereal a = getFloatDefaultUnits(MinEQ3node, "a", "cal/gmol/K"); + doublereal b = getFloatDefaultUnits(MinEQ3node, "b", "cal/gmol/K2"); + doublereal c = getFloatDefaultUnits(MinEQ3node, "c", "cal-K/gmol"); doublereal dg = deltaG_formation_pr_tr * 4.184 * 1.0E3; - doublereal fac = convertDGFormation(k, th_ptr); + doublereal fac = 0; // convertDGFormation(comp, th_ptr); doublereal Mu0_tr_pr = fac + dg; doublereal e = Entrop_pr_tr * 1.0E3 * 4.184; doublereal Hcalc = Mu0_tr_pr + 298.15 * e; @@ -459,45 +444,43 @@ static void installMinEQ3asShomateThermoFromXML(const std::string& speciesName, coef[0] = tmax0 - 0.001; copy(c0.begin(), c0.begin()+7, coef.begin() + 1); copy(c0.begin(), c0.begin()+7, coef.begin() + 8); - sp.install(speciesName, k, SHOMATE, &coef[0], tmin0, tmax0, p0); + return newSpeciesThermoInterpType(SHOMATE, tmin0, tmax0, p0, &coef[0]); } -//! Install a Shomate polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. +//! Create a Shomate polynomial thermodynamic property parameterization for a +//! species /*! - * This is called by method installThermoForSpecies if a Shomate block is found in the XML input. + * This is called if a 'Shomate' node is found in the XML input. * - * @param speciesName String name of the species - * @param sp SpeciesThermo object that will receive the NASA polynomial object - * @param k Species index within the phase - * @param f0ptr Ptr to the first XML_Node for the first NASA polynomial - * @param f1ptr Ptr to the first XML_Node for the first NASA polynomial + * @param speciesName name of the species + * @param nodes vector of 1 or 2 'Shomate' XML_Nodes, each defining the + * coefficients for a temperature range */ -static void installShomateThermoFromXML(const std::string& speciesName, SpeciesThermo& sp, size_t k, - const XML_Node* f0ptr, const XML_Node* f1ptr) +static SpeciesThermoInterpType* newShomateThermoFromXML( + const std::string& speciesName, vector& nodes) { doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax; - const XML_Node& f0 = *f0ptr; bool dualRange = false; - if (f1ptr) { + if (nodes.size() == 2) { dualRange = true; } - tmin0 = fpValue(f0["Tmin"]); - tmax0 = fpValue(f0["Tmax"]); + tmin0 = fpValue(nodes[0]->attrib("Tmin")); + tmax0 = fpValue(nodes[0]->attrib("Tmax")); doublereal p0 = OneAtm; - if (f0.hasAttrib("P0")) { - p0 = fpValue(f0["P0"]); + if (nodes[0]->hasAttrib("P0")) { + p0 = fpValue(nodes[0]->attrib("P0")); } - if (f0.hasAttrib("Pref")) { - p0 = fpValue(f0["Pref"]); + if (nodes[0]->hasAttrib("Pref")) { + p0 = fpValue(nodes[0]->attrib("Pref")); } p0 = OneAtm; tmin1 = tmax0; tmax1 = tmin1 + 0.0001; if (dualRange) { - tmin1 = fpValue((*f1ptr)["Tmin"]); - tmax1 = fpValue((*f1ptr)["Tmax"]); + tmin1 = fpValue(nodes[1]->attrib("Tmin")); + tmax1 = fpValue(nodes[1]->attrib("Tmax")); } vector_fp c0, c1; @@ -505,9 +488,9 @@ static void installShomateThermoFromXML(const std::string& speciesName, SpeciesT tmin = tmin0; tmid = tmax0; tmax = tmax1; - getFloatArray(f0.child("floatArray"), c0, false); + getFloatArray(nodes[0]->child("floatArray"), c0, false); if (dualRange) { - getFloatArray(f1ptr->child("floatArray"), c1, false); + getFloatArray(nodes[1]->child("floatArray"), c1, false); } else { if(c0.size() != 7) { @@ -521,8 +504,8 @@ static void installShomateThermoFromXML(const std::string& speciesName, SpeciesT tmin = tmin1; tmid = tmax1; tmax = tmax0; - getFloatArray(f1ptr->child("floatArray"), c0, false); - getFloatArray(f0.child("floatArray"), c1, false); + getFloatArray(nodes[1]->child("floatArray"), c0, false); + getFloatArray(nodes[0]->child("floatArray"), c1, false); } else { throw CanteraError("installShomateThermoFromXML", "non-continuous temperature ranges."); @@ -536,25 +519,22 @@ static void installShomateThermoFromXML(const std::string& speciesName, SpeciesT c[0] = tmid; copy(c0.begin(), c0.begin()+7, c.begin() + 1); copy(c1.begin(), c1.begin()+7, c.begin() + 8); - sp.install(speciesName, k, SHOMATE, &c[0], tmin, tmax, p0); + return newSpeciesThermoInterpType(SHOMATE, tmin, tmax, p0, &c[0]); } -//! Install a Simple thermodynamic property parameterization for species k into a SpeciesThermo instance. +//! Create a "simple" constant heat capacity thermodynamic property +//! parameterization for a ! species /*! - * This is called by method installThermoForSpecies if a SimpleThermo block is found + * This is called if a 'const_cp' XML node is found * - * @param speciesName String name of the species - * @param sp SpeciesThermo object that will receive the NASA polynomial object - * @param k Species index within the phase - * @param f XML_Node for the SimpleThermo block + * @param speciesName name of the species + * @param f 'const_cp' XML node */ -static void installSimpleThermoFromXML(const std::string& speciesName, - SpeciesThermo& sp, size_t k, - const XML_Node& f) +static SpeciesThermoInterpType* newConstCpThermoFromXML( + const std::string& speciesName, XML_Node& f) { - doublereal tmin, tmax; - tmin = fpValue(f["Tmin"]); - tmax = fpValue(f["Tmax"]); + double tmin = fpValue(f["Tmin"]); + double tmax = fpValue(f["Tmax"]); if (tmax == 0.0) { tmax = 1.0e30; } @@ -565,133 +545,95 @@ static void installSimpleThermoFromXML(const std::string& speciesName, c[2] = getFloat(f, "s0", "toSI"); c[3] = getFloat(f, "cp0", "toSI"); doublereal p0 = OneAtm; - sp.install(speciesName, k, SIMPLE, &c[0], tmin, tmax, p0); + return newSpeciesThermoInterpType(CONSTANT_CP, tmin, tmax, p0, &c[0]); } -//! Install a NASA9 polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. +//! Create a NASA9 polynomial thermodynamic property parameterization for a +//! species /*! - * This is called by method installThermoForSpecies if a NASA9 block is found in the XML input. + * This is called if a 'NASA9' Node is found in the XML input. * - * @param speciesName String name of the species - * @param sp SpeciesThermo object that will receive the NASA polynomial object - * @param k Species index within the phase - * @param tp Vector of XML Nodes that make up the parameterization + * @param speciesName name of the species + * @param tp Vector of XML Nodes that make up the parameterization */ -static void installNasa9ThermoFromXML(const std::string& speciesName, - SpeciesThermo& sp, size_t k, - const std::vector& tp) +static SpeciesThermoInterpType* newNasa9ThermoFromXML( + const std::string& speciesName, const std::vector& tp) { - const XML_Node* fptr = tp[0]; int nRegions = 0; vector_fp cPoly; - Nasa9Poly1* np_ptr = 0; std::vector regionPtrs; - doublereal tmin, tmax, pref = OneAtm; + doublereal pref = OneAtm; // Loop over all of the possible temperature regions for (size_t i = 0; i < tp.size(); i++) { - fptr = tp[i]; - if (fptr) { - if (fptr->name() == "NASA9") { - if (fptr->hasChild("floatArray")) { - - tmin = fpValue((*fptr)["Tmin"]); - tmax = fpValue((*fptr)["Tmax"]); - if ((*fptr).hasAttrib("P0")) { - pref = fpValue((*fptr)["P0"]); - } - if ((*fptr).hasAttrib("Pref")) { - pref = fpValue((*fptr)["Pref"]); - } - - getFloatArray(fptr->child("floatArray"), cPoly, false); - if (cPoly.size() != 9) { - throw CanteraError("installNasa9ThermoFromXML", - "Expected 9 coeff polynomial"); - } - np_ptr = new Nasa9Poly1(k, tmin, tmax, pref, - DATA_PTR(cPoly)); - regionPtrs.push_back(np_ptr); - nRegions++; - } + const XML_Node& fptr = *tp[i]; + if (fptr.name() == "NASA9" && fptr.hasChild("floatArray")) { + double tmin = fpValue(fptr["Tmin"]); + double tmax = fpValue(fptr["Tmax"]); + if (fptr.hasAttrib("P0")) { + pref = fpValue(fptr["P0"]); } + if (fptr.hasAttrib("Pref")) { + pref = fpValue(fptr["Pref"]); + } + + getFloatArray(fptr.child("floatArray"), cPoly, false); + if (cPoly.size() != 9) { + throw CanteraError("installNasa9ThermoFromXML", + "Expected 9 coeff polynomial"); + } + regionPtrs.push_back(new Nasa9Poly1(0, tmin, tmax, pref, &cPoly[0])); + nRegions++; } } if (nRegions == 0) { throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesName, " "); } else if (nRegions == 1) { - sp.install_STIT(np_ptr); + return regionPtrs[0]; } else { - Nasa9PolyMultiTempRegion* npMulti_ptr = new Nasa9PolyMultiTempRegion(regionPtrs); - sp.install_STIT(npMulti_ptr); + return new Nasa9PolyMultiTempRegion(regionPtrs); } } /** - * Install a stat mech based property solver - * for species k into a SpeciesThermo instance. + * Create a stat mech based property solver for a species + * @deprecated */ -static void installStatMechThermoFromXML(const std::string& speciesName, - SpeciesThermo& sp, int k, - const std::vector& tp) +static StatMech* newStatMechThermoFromXML(const std::string& speciesName, XML_Node& f) { - const XML_Node* fptr = tp[0]; - int nRegTmp = tp.size(); - vector_fp cPoly; - std::vector regionPtrs; - doublereal tmin = 0.0; - doublereal tmax = 0.0; + doublereal tmin = fpValue(f["Tmin"]); + doublereal tmax = fpValue(f["Tmax"]); doublereal pref = OneAtm; - - // Loop over all of the possible temperature regions - for (int i = 0; i < nRegTmp; i++) { - fptr = tp[i]; - if (fptr) { - if (fptr->name() == "StatMech") { - tmin = fpValue((*fptr)["Tmin"]); - tmax = fpValue((*fptr)["Tmax"]); - if ((*fptr).hasAttrib("P0")) { - pref = fpValue((*fptr)["P0"]); - } - if ((*fptr).hasAttrib("Pref")) { - pref = fpValue((*fptr)["Pref"]); - } - if (fptr->hasChild("floatArray")) { - getFloatArray(fptr->child("floatArray"), cPoly, false); - if (cPoly.size() != 0) { - throw CanteraError("installStatMechThermoFromXML", - "Expected no coeff: this is not a polynomial representation"); - } - } - } - } + if (f.hasAttrib("P0")) { + pref = fpValue(f["P0"]); } + if (f.hasAttrib("Pref")) { + pref = fpValue(f["Pref"]); + } + // set properties tmin = 0.1; vector_fp coeffs(1); coeffs[0] = 0.0; - (&sp)->install(speciesName, k, STAT, &coeffs[0], tmin, tmax, pref); + return new StatMech(0, tmin, tmax, pref, &coeffs[0], speciesName); } -//! Install a Adsorbate polynomial thermodynamic property parameterization for species k into a SpeciesThermo instance. +//! Create an Adsorbate polynomial thermodynamic property parameterization for a +//! species /*! - * This is called by method installThermoForSpecies if a Adsorbate block is found in the XML input. + * This is called if a 'Adsorbate' node is found in the XML input. * - * @param speciesName String name of the species - * @param sp SpeciesThermo object that will receive the NASA polynomial object - * @param k Species index within the phase - * @param f XML Node that contains the parameterization + * @param speciesName name of the species + * @param f XML Node that contains the parameterization */ -static void installAdsorbateThermoFromXML(const std::string& speciesName, - SpeciesThermo& sp, size_t k, - const XML_Node& f) +static SpeciesThermoInterpType* newAdsorbateThermoFromXML( + const std::string& speciesName, const XML_Node& f) { vector_fp freqs; - doublereal tmin, tmax, pref = OneAtm; - size_t nfreq = 0; - tmin = fpValue(f["Tmin"]); - tmax = fpValue(f["Tmax"]); + doublereal pref = OneAtm; + double tmin = fpValue(f["Tmin"]); + double tmax = fpValue(f["Tmax"]); if (f.hasAttrib("P0")) { pref = fpValue(f["P0"]); } @@ -704,8 +646,8 @@ static void installAdsorbateThermoFromXML(const std::string& speciesName, if (f.hasChild("floatArray")) { getFloatArray(f.child("floatArray"), freqs, false); - nfreq = freqs.size(); } + size_t nfreq = freqs.size(); for (size_t n = 0; n < nfreq; n++) { freqs[n] *= 3.0e10; } @@ -713,92 +655,17 @@ static void installAdsorbateThermoFromXML(const std::string& speciesName, coeffs[0] = static_cast(nfreq); coeffs[1] = getFloat(f, "binding_energy", "toSI"); copy(freqs.begin(), freqs.end(), coeffs.begin() + 2); - (&sp)->install(speciesName, k, ADSORBATE, &coeffs[0], tmin, tmax, pref); + return new Adsorbate(0, tmin, tmax, pref, &coeffs[0]); } void SpeciesThermoFactory::installThermoForSpecies (size_t k, const XML_Node& speciesNode, ThermoPhase* th_ptr, SpeciesThermo& spthermo, const XML_Node* phaseNode_ptr) const { - /* - * Check to see that the species block has a thermo block - * before processing. Throw an error if not there. - */ - if (!(speciesNode.hasChild("thermo"))) { - throw UnknownSpeciesThermoModel("installThermoForSpecies", - speciesNode["name"], ""); - } - const XML_Node& thermo = speciesNode.child("thermo"); - - // 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 any point. - const std::vector& tpWC = thermo.children(); - std::vector tp; - for (size_t i = 0; i < tpWC.size(); i++) { - if (!(tpWC[i])->isComment()) { - tp.push_back(tpWC[i]); - } - } - - if (thermo["model"] == "MineralEQ3") { - const XML_Node* f = tp[0]; - if (f->name() != "MinEQ3") { - throw CanteraError("SpeciesThermoFactory::installThermoForSpecies", - "confused: expedted MinEQ3"); - } - installMinEQ3asShomateThermoFromXML(speciesNode["name"], th_ptr, spthermo, k, f); - } else { - if (tp.size() == 1) { - const XML_Node* f = tp[0]; - if (f->name() == "Shomate") { - installShomateThermoFromXML(speciesNode["name"], spthermo, k, f, 0); - } else if (f->name() == "const_cp") { - installSimpleThermoFromXML(speciesNode["name"], spthermo, k, *f); - } else if (f->name() == "NASA") { - installNasaThermoFromXML(speciesNode["name"], spthermo, k, f, 0); - } else if (f->name() == "Mu0") { - installMu0ThermoFromXML(speciesNode["name"], spthermo, k, f); - } else if (f->name() == "NASA9") { - installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp); - } else if (f->name() == "StatMech") { - installStatMechThermoFromXML(speciesNode["name"], spthermo, k, tp); - } else if (f->name() == "adsorbate") { - installAdsorbateThermoFromXML(speciesNode["name"], spthermo, k, *f); - } else { - throw UnknownSpeciesThermoModel("installThermoForSpecies", - speciesNode["name"], f->name()); - } - } else if (tp.size() == 2) { - const XML_Node* f0 = tp[0]; - const XML_Node* f1 = tp[1]; - if (f0->name() == "NASA" && f1->name() == "NASA") { - installNasaThermoFromXML(speciesNode["name"], spthermo, k, f0, f1); - } else if (f0->name() == "Shomate" && f1->name() == "Shomate") { - installShomateThermoFromXML(speciesNode["name"], spthermo, k, f0, f1); - } else if (f0->name() == "StatMech") { - installStatMechThermoFromXML(speciesNode["name"], spthermo, k, tp); - } else if (f0->name() == "NASA9" && f1->name() == "NASA9") { - installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp); - } else { - throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"], - f0->name() + " and " + f1->name()); - } - } else if (tp.size() > 2) { - const XML_Node* f0 = tp[0]; - if (f0->name() == "NASA9") { - installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp); - } else if (f0->name() == "StatMech") { - installStatMechThermoFromXML(speciesNode["name"], spthermo, k, tp); - } else { - throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"], - "multiple"); - } - } else { - throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"], - "multiple"); - } - } + SpeciesThermoInterpType* stit = newSpeciesThermoInterpType(speciesNode); + stit->validate(speciesNode["name"]); + stit->setIndex(k); + spthermo.install_STIT(stit); } void SpeciesThermoFactory::installVPThermoForSpecies(size_t k, @@ -831,6 +698,74 @@ void SpeciesThermoFactory::installVPThermoForSpecies(size_t k, vp_ptr->createInstallPDSS(k, speciesNode, phaseNode_ptr); } +SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& speciesNode) +{ + /* + * Check to see that the species block has a thermo block + * before processing. Throw an error if not there. + */ + if (!(speciesNode.hasChild("thermo"))) { + throw UnknownSpeciesThermoModel("installThermoForSpecies", + speciesNode["name"], ""); + } + const XML_Node& thermo = speciesNode.child("thermo"); + + // 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 any point. + const std::vector& tpWC = thermo.children(); + std::vector tp; + for (size_t i = 0; i < tpWC.size(); i++) { + if (!(tpWC[i])->isComment()) { + tp.push_back(tpWC[i]); + } + } + + std::string thermoType = lowercase(tp[0]->name()); + std::string specName = speciesNode["name"]; + + for (size_t i = 1; i < tp.size(); i++) { + if (lowercase(tp[i]->name()) != thermoType) { + throw CanteraError("newSpeciesThermoInterpType", + "Encounter unsupported mixed species thermo parameterizations " + "for species '" + specName + "'."); + } + } + if ((tp.size() > 2 && thermoType != "nasa9") || + (tp.size() > 1 && (thermoType == "const_cp" || + thermoType == "mu0" || + thermoType == "adsorbate"))) { + throw CanteraError("newSpeciesThermoInterpType", + "Too many regions in thermo parameterization for species '" + + specName + "'."); + } + + if (thermo["model"] == "MineralEQ3") { + if (thermoType != "mineq3") { + throw CanteraError("SpeciesThermoFactory::installThermoForSpecies", + "confused: expedted MinEQ3"); + } + return newShomateForMineralEQ3(specName, *tp[0]); + } else if (thermoType == "shomate") { + return newShomateThermoFromXML(specName, tp); + } else if (thermoType == "const_cp") { + return newConstCpThermoFromXML(specName, *tp[0]); + } else if (thermoType == "nasa") { + return newNasaThermoFromXML(specName, tp); + } else if (thermoType == "mu0") { + return newMu0ThermoFromXML(specName, *tp[0]); + } else if (thermoType == "nasa9") { + return newNasa9ThermoFromXML(specName, tp); + } else if (thermoType == "adsorbate") { + return newAdsorbateThermoFromXML(specName, *tp[0]); + } else if (thermoType == "statmech") { + return newStatMechThermoFromXML(specName, *tp[0]); + } else { + throw UnknownSpeciesThermoModel("installThermoForSpecies", + specName, thermoType); + } +} + SpeciesThermo* newSpeciesThermoMgr(int type, SpeciesThermoFactory* f) { warn_deprecated("newSpeciesThermoMgr", "To be removed after Cantera 2.2. " diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 4f64895b5..d633131bb 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -585,32 +585,22 @@ bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, throw CanteraError("installSpecies", "Unexpected XML name of species XML_Node: " + xname); } + + if (rule) { + th.ignoreUndefinedElements(); + } + // get the composition of the species const XML_Node& a = s.child("atomArray"); map comp; getMap(a, comp); - // check that all elements in the species exist in 'p'. If rule != 0, - // quietly skip this species if some elements are undeclared; otherwise, - // throw an exception - map::const_iterator _b = comp.begin(); - for (; _b != comp.end(); ++_b) { - if (th.elementIndex(_b->first) == npos) { - if (rule == 0) { - throw CanteraError("installSpecies", - "Species " + s["name"] + - " contains undeclared element " + _b->first); - } else { - return false; - } - } - } - // construct a vector of atom numbers for each element in phase th. Elements // not declared in the species (i.e., not in map comp) will have zero // entries in the vector. size_t nel = th.nElements(); vector_fp ecomp(nel, 0.0); + compositionMap comp_map = parseCompString(a.value()); for (size_t m = 0; m < nel; m++) { std::string& es = comp[th.elementName(m)]; if (!es.empty()) { @@ -618,7 +608,6 @@ bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, } } - // get the species charge, if any. Note that the charge need // not be explicitly specified if special element 'E' // (electron) is one of the elements. @@ -634,16 +623,13 @@ bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, sz = getFloat(s, "size"); } - // add the species to phase th - th.addUniqueSpecies(s["name"], &ecomp[0], chrg, sz); - if (vpss_ptr) { + th.addUniqueSpecies(s["name"], &ecomp[0], chrg, sz); VPStandardStateTP* vp_ptr = dynamic_cast(&th); factory->installVPThermoForSpecies(k, s, vp_ptr, phaseNode_ptr); } else { - // install the thermo parameterization for this species into - // the species thermo manager for phase th - factory->installThermoForSpecies(k, s, &th, *spthermo_ptr, phaseNode_ptr); + SpeciesThermoInterpType* st = newSpeciesThermoInterpType(s); + th.addSpecies(Species(s["name"], comp_map, st, chrg, sz)); } return true; diff --git a/src/thermo/ThermoPhase.cpp b/src/thermo/ThermoPhase.cpp index 70c2db1e1..83c82c62b 100644 --- a/src/thermo/ThermoPhase.cpp +++ b/src/thermo/ThermoPhase.cpp @@ -699,7 +699,10 @@ bool ThermoPhase::addSpecies(const Species& spec) { bool added = Phase::addSpecies(spec); if (added) { - m_spthermo->install_STIT(spec.thermo().duplMyselfAsSpeciesThermoInterpType()); + Species& s = m_species[spec.name]; + s.thermo().validate(spec.name); + s.thermo().setIndex(m_kk-1); + m_spthermo->install_STIT(s.thermo().duplMyselfAsSpeciesThermoInterpType()); } return added; } diff --git a/src/thermo/VPSSMgr.cpp b/src/thermo/VPSSMgr.cpp index c868253f8..422ea0d9a 100644 --- a/src/thermo/VPSSMgr.cpp +++ b/src/thermo/VPSSMgr.cpp @@ -18,6 +18,7 @@ #include "cantera/thermo/PDSS.h" #include "cantera/thermo/GeneralSpeciesThermo.h" #include "cantera/base/vec_functions.h" +#include "cantera/base/xml.h" using namespace std; @@ -400,9 +401,10 @@ void VPSSMgr::initThermoXML(XML_Node& phaseNode, const std::string& id) void VPSSMgr::installSTSpecies(size_t k, const XML_Node& s, const XML_Node* phaseNode_ptr) { - - SpeciesThermoFactory* f = SpeciesThermoFactory::factory(); - f->installThermoForSpecies(k, s, m_vptp_ptr, *m_spthermo, phaseNode_ptr); + SpeciesThermoInterpType* stit = newSpeciesThermoInterpType(s); + stit->setIndex(k); + stit->validate(s["name"]); + m_spthermo->install_STIT(stit); if (m_p0 < 0.0) { m_p0 = m_spthermo->refPressure(k); } diff --git a/src/thermo/VPSSMgr_IdealGas.cpp b/src/thermo/VPSSMgr_IdealGas.cpp index d52d33dec..9b287d843 100644 --- a/src/thermo/VPSSMgr_IdealGas.cpp +++ b/src/thermo/VPSSMgr_IdealGas.cpp @@ -16,6 +16,7 @@ #include "cantera/base/ctml.h" #include "cantera/thermo/SpeciesThermoFactory.h" #include "cantera/thermo/PDSS_IdealGas.h" +#include "cantera/thermo/SpeciesThermoInterpType.h" using namespace std; using namespace ctml; @@ -103,8 +104,10 @@ VPSSMgr_IdealGas::createInstallPDSS(size_t k, const XML_Node& speciesNode, m_Vss.resize(k+1, 0.0); } - SpeciesThermoFactory* f = SpeciesThermoFactory::factory(); - f->installThermoForSpecies(k, speciesNode,(ThermoPhase*) m_vptp_ptr, *m_spthermo, phaseNode_ptr); + SpeciesThermoInterpType* stit = newSpeciesThermoInterpType(speciesNode); + stit->setIndex(k); + stit->validate(speciesNode["name"]); + m_spthermo->install_STIT(stit); PDSS* kPDSS = new PDSS_IdealGas(m_vptp_ptr, k, speciesNode, *phaseNode_ptr, true);