From c884917c95cf57ecc676685c2c1adb105ab36dee Mon Sep 17 00:00:00 2001 From: Harry Moffat Date: Tue, 23 Sep 2008 15:57:52 +0000 Subject: [PATCH] Bug fixes for liquid electrolyte thermo capability. thermo XML node now takes a couple of extra XML nodes that can specify explicitly which standardStateManager and which variblePressureStandardState manager to use. These are : and Previously, these were being determined implicitly by querying the input deck. However, it seems a no brainer to put the capability for putting explicit instructions in. --- Cantera/src/thermo/PDSS.cpp | 11 +- Cantera/src/thermo/PDSS.h | 17 +++ Cantera/src/thermo/PDSS_HKFT.cpp | 23 ++- Cantera/src/thermo/PDSS_Water.cpp | 45 +++--- Cantera/src/thermo/PDSS_Water.h | 9 +- Cantera/src/thermo/SpeciesThermoFactory.cpp | 32 +++- Cantera/src/thermo/SpeciesThermoFactory.h | 33 +++++ .../src/thermo/SpeciesThermoInterpType.cpp | 6 +- Cantera/src/thermo/SpeciesThermoMgr.h | 4 + Cantera/src/thermo/ThermoFactory.cpp | 14 +- Cantera/src/thermo/VPSSMgr.cpp | 8 +- Cantera/src/thermo/VPSSMgrFactory.cpp | 138 +++++++----------- Cantera/src/thermo/VPSSMgr_General.cpp | 62 ++++++-- Cantera/src/thermo/WaterPropsIAPWS.cpp | 17 ++- Cantera/src/thermo/WaterPropsIAPWS.h | 2 +- 15 files changed, 260 insertions(+), 161 deletions(-) diff --git a/Cantera/src/thermo/PDSS.cpp b/Cantera/src/thermo/PDSS.cpp index 3d4da4b31..baeab7a1f 100644 --- a/Cantera/src/thermo/PDSS.cpp +++ b/Cantera/src/thermo/PDSS.cpp @@ -32,6 +32,8 @@ namespace Cantera { m_temp(-1.0), m_pres(-1.0), m_p0(-1.0), + m_minTemp(-1.0), + m_maxTemp(10000.0), m_tp(0), m_vpssmgr_ptr(0), m_mw(0.0), @@ -55,6 +57,8 @@ namespace Cantera { m_temp(-1.0), m_pres(-1.0), m_p0(-1.0), + m_minTemp(-1.0), + m_maxTemp(10000.0), m_tp(tp), m_vpssmgr_ptr(0), m_mw(0.0), @@ -87,6 +91,8 @@ namespace Cantera { m_temp(-1.0), m_pres(-1.0), m_p0(-1.0), + m_minTemp(-1.0), + m_maxTemp(10000.0), m_tp(0), m_vpssmgr_ptr(0), m_mw(b.m_mw), @@ -121,6 +127,8 @@ namespace Cantera { m_temp = b.m_temp; m_pres = b.m_pres; m_p0 = b.m_p0; + m_minTemp = b.m_minTemp; + m_maxTemp = b.m_maxTemp; m_tp = b.m_tp; m_vpssmgr_ptr = b.m_vpssmgr_ptr; m_mw = b.m_mw; @@ -158,10 +166,12 @@ namespace Cantera { void PDSS::initThermoXML(const XML_Node& phaseNode, std::string& id) { + AssertThrow(m_tp != 0, "PDSS::initThermoXML()"); m_vpssmgr_ptr = m_tp->provideVPSSMgr(); } void PDSS::initThermo() { + AssertThrow(m_tp != 0, "PDSS::initThermo()"); m_vpssmgr_ptr = m_tp->provideVPSSMgr(); initPtrs(); } @@ -361,7 +371,6 @@ namespace Cantera { return(cp_mole() - GasConstant * tmp); } - /** * Calculate the pressure (Pascals), given the temperature and density * Temperature: kelvin diff --git a/Cantera/src/thermo/PDSS.h b/Cantera/src/thermo/PDSS.h index 6df1ef860..f27dacf98 100644 --- a/Cantera/src/thermo/PDSS.h +++ b/Cantera/src/thermo/PDSS.h @@ -279,6 +279,17 @@ namespace Cantera { return m_p0; } + //! return the minimum temperature + doublereal minTemp() const { + return m_minTemp; + } + + + //! return the minimum temperature + doublereal maxTemp() const { + return m_maxTemp; + } + //! Return the molar gibbs free energy divided by RT at reference pressure /*! * Returns the species reference state gibbs free energy divided by RT at the @@ -486,6 +497,12 @@ namespace Cantera { //! reference state pressure of the species. doublereal m_p0; + //! minimum temperature + doublereal m_minTemp; + + //! maximum temperature + doublereal m_maxTemp; + //! Thermophase which this species belongs to. /*! * Note, in some diff --git a/Cantera/src/thermo/PDSS_HKFT.cpp b/Cantera/src/thermo/PDSS_HKFT.cpp index 05104877e..710cbbc1a 100644 --- a/Cantera/src/thermo/PDSS_HKFT.cpp +++ b/Cantera/src/thermo/PDSS_HKFT.cpp @@ -155,7 +155,7 @@ namespace Cantera { // Ok we may change this evaluation method in the future. double GG = gibbs_mole(); double SS = entropy_mole(); - double h = GG - m_temp * SS; + double h = GG + m_temp * SS; return h; } @@ -483,8 +483,8 @@ namespace Cantera { const XML_Node& speciesNode, const XML_Node& phaseNode, bool spInstalled) { PDSS::initThermo(); - SpeciesThermo &sp = m_tp->speciesThermo(); - m_p0 = sp.refPressure(m_spindex); + + // m_p0 = OneAtm; if (!spInstalled) { throw CanteraError("PDSS_HKFT::constructPDSSXML", "spInstalled false not handled"); @@ -507,6 +507,23 @@ namespace Cantera { "no Thermo::HKFT Node for species " + speciesNode.name()); } + // go get the attributes + m_p0 = OneAtm; + std::string p0string = (*hh)["Pref"]; + if (p0string != "") { + m_p0 = strSItoDbl(p0string); + } + + std::string minTstring = (*hh)["Tmin"]; + if (minTstring != "") { + m_minTemp = atofCheck(minTstring.c_str()); + } + + std::string maxTstring = (*hh)["Tmax"]; + if (maxTstring != "") { + m_maxTemp = atofCheck(maxTstring.c_str()); + } + if (hh->hasChild("DG0_f_Pr_Tr")) { double val = getFloat(*hh, "DG0_f_Pr_Tr"); m_deltaG_formation_tr_pr = val; diff --git a/Cantera/src/thermo/PDSS_Water.cpp b/Cantera/src/thermo/PDSS_Water.cpp index b01954d17..dd3b3a9b0 100644 --- a/Cantera/src/thermo/PDSS_Water.cpp +++ b/Cantera/src/thermo/PDSS_Water.cpp @@ -28,9 +28,8 @@ namespace Cantera { PDSS_Water::PDSS_Water() : PDSS(), m_sub(0), - m_temp(0.0), m_dens(1000.0), - m_iState(-3000), + m_iState(WATER_LIQUID), EW_Offset(0.0), SW_Offset(0.0), m_verbose(0), @@ -40,14 +39,15 @@ namespace Cantera { m_sub = new WaterPropsIAPWS(); m_spthermo = 0; constructSet(); + m_minTemp = 200.; + m_maxTemp = 10000.; } PDSS_Water::PDSS_Water(VPStandardStateTP *tp, int spindex) : PDSS(tp, spindex), m_sub(0), - m_temp(0.0), m_dens(1000.0), - m_iState(-3000), + m_iState(WATER_LIQUID), EW_Offset(0.0), SW_Offset(0.0), m_verbose(0), @@ -57,6 +57,8 @@ namespace Cantera { m_sub = new WaterPropsIAPWS(); m_spthermo = 0; constructSet(); + m_minTemp = 200.; + m_maxTemp = 10000.; } @@ -64,9 +66,8 @@ namespace Cantera { std::string inputFile, std::string id) : PDSS(tp, spindex), m_sub(0), - m_temp(0.0), m_dens(1000.0), - m_iState(-3000), + m_iState(WATER_LIQUID), EW_Offset(0.0), SW_Offset(0.0), m_verbose(0), @@ -76,6 +77,8 @@ namespace Cantera { m_sub = new WaterPropsIAPWS(); constructPDSSFile(tp, spindex, inputFile, id); m_spthermo = 0; + m_minTemp = 200.; + m_maxTemp = 10000.; } PDSS_Water::PDSS_Water(VPStandardStateTP *tp, int spindex, @@ -83,9 +86,8 @@ namespace Cantera { const XML_Node& phaseRoot, bool spInstalled) : PDSS(tp, spindex), m_sub(0), - m_temp(0.0), m_dens(1000.0), - m_iState(-3000), + m_iState(WATER_LIQUID), EW_Offset(0.0), SW_Offset(0.0), m_verbose(0), @@ -97,6 +99,8 @@ namespace Cantera { constructPDSSXML(tp, spindex, phaseRoot, id) ; initThermo(); m_spthermo = 0; + m_minTemp = 200.; + m_maxTemp = 10000.; } @@ -104,9 +108,8 @@ namespace Cantera { PDSS_Water::PDSS_Water(const PDSS_Water &b) : PDSS(), m_sub(0), - m_temp(0.0), m_dens(1000.0), - m_iState(-3000), + m_iState(WATER_LIQUID), EW_Offset(b.EW_Offset), SW_Offset(b.SW_Offset), m_verbose(b.m_verbose), @@ -131,7 +134,6 @@ namespace Cantera { PDSS::operator=(b); m_sub->operator=(*(b.m_sub)); - m_temp = b.m_temp; m_dens = b.m_dens; m_iState = b.m_iState; EW_Offset = b.EW_Offset; @@ -375,9 +377,7 @@ namespace Cantera { if (T > m_sub->Tcrit()) { waterState = WATER_SUPERCRIT; } - if (p < 1.0) { - waterState = WATER_GAS; - } + #ifdef DEBUG_HKM //printf("waterPDSS: set pres = %g t = %g, waterState = %d\n", @@ -393,8 +393,14 @@ namespace Cantera { m_dens = dd; m_pres = p; + // We are only putting the phase check here because of speed considerations. m_iState = m_sub->phaseState(true); - + if (! m_allowGasPhase) { + if (m_iState != WATER_SUPERCRIT && m_iState != WATER_LIQUID && m_iState != WATER_UNSTABLELIQUID) { + throw CanteraError("PDSS_Water::setPressure", + "Water State isn't liquid or crit"); + } + } } // Return the volumetric thermal expansion coefficient. Units: 1/K. @@ -467,13 +473,10 @@ namespace Cantera { // saturation pressure doublereal PDSS_Water::satPressure(doublereal t){ - doublereal pp = m_sub->psat(t); - doublereal dens = m_dens; + doublereal pp = m_sub->psat(t, WATER_LIQUID); + m_dens = m_sub->density(); m_temp = t; - m_dens = dens; return pp; } - - - + } diff --git a/Cantera/src/thermo/PDSS_Water.h b/Cantera/src/thermo/PDSS_Water.h index afd601ad0..6a8af1c15 100644 --- a/Cantera/src/thermo/PDSS_Water.h +++ b/Cantera/src/thermo/PDSS_Water.h @@ -486,11 +486,6 @@ namespace Cantera { */ mutable WaterPropsIAPWS *m_sub; - /** - * state of the system (temperature and density); - */ - doublereal m_temp; - //! State of the system - density /*! * Density is the independent variable here, but it's hidden behind the @@ -525,6 +520,7 @@ namespace Cantera { //! Verbose flag - used? bool m_verbose; + public: /** * Since this phase represents a liquid phase, it's an error to * return a gas-phase answer. However, if the below is true, then @@ -537,6 +533,3 @@ namespace Cantera { } #endif - - - diff --git a/Cantera/src/thermo/SpeciesThermoFactory.cpp b/Cantera/src/thermo/SpeciesThermoFactory.cpp index 0b4c4f557..d6bf0c6ef 100755 --- a/Cantera/src/thermo/SpeciesThermoFactory.cpp +++ b/Cantera/src/thermo/SpeciesThermoFactory.cpp @@ -155,10 +155,7 @@ namespace Cantera { + SHOMATE*ishomate + SIMPLE*isimple); } - - SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(int type) { - switch (type) { case NASA: return new NasaThermo; @@ -173,12 +170,36 @@ namespace Cantera { case SHOMATE + SIMPLE: return new SpeciesThermoDuo; default: - throw UnknownSpeciesThermo( - "SpeciesThermoFactory::newSpeciesThermo",type); + throw UnknownSpeciesThermo("SpeciesThermoFactory::newSpeciesThermo", + type); return 0; } } + SpeciesThermo* SpeciesThermoFactory::newSpeciesThermoManager(std::string &stype) { + std::string ltype = lowercase(stype); + if (ltype == "nasa") { + return new NasaThermo; + } else if (ltype == "shomate") { + return new ShomateThermo; + } else if (ltype == "simple" || ltype == "constant_cp") { + return new SimpleThermo; + } else if (ltype == "nasa_shomate_duo") { + return new SpeciesThermoDuo; + } else if (ltype == "nasa_simple_duo") { + return new SpeciesThermoDuo; + } else if (ltype == "shomate_simple_duo") { + return new SpeciesThermoDuo; + } else if (ltype == "general") { + return new GeneralSpeciesThermo(); + } else if (ltype == "") { + return (SpeciesThermo*) 0; + } else { + throw UnknownSpeciesThermo("SpeciesThermoFactory::newSpeciesThermoManager", + stype); + } + return (SpeciesThermo*) 0; + } /* * Check the continuity of properties at the midpoint @@ -186,7 +207,6 @@ namespace Cantera { */ void NasaThermo::checkContinuity(std::string name, double tmid, const doublereal* clow, doublereal* chigh) { - // heat capacity doublereal cplow = poly4(tmid, clow); doublereal cphigh = poly4(tmid, chigh); diff --git a/Cantera/src/thermo/SpeciesThermoFactory.h b/Cantera/src/thermo/SpeciesThermoFactory.h index b4657159c..d649317ef 100755 --- a/Cantera/src/thermo/SpeciesThermoFactory.h +++ b/Cantera/src/thermo/SpeciesThermoFactory.h @@ -130,6 +130,16 @@ namespace Cantera { */ SpeciesThermo* newSpeciesThermo(int type); + + //! Create a new species thermo property manager given a string + /*! + * Create a new species thermo property manager, given a + * string. + * + * @param stype String name for the species thermo type + */ + SpeciesThermo* newSpeciesThermoManager(std::string &stype); + //! Create a new species property manager. /*! * This routine will look through species nodes. It will discover what @@ -257,6 +267,29 @@ namespace Cantera { return sptherm; } + //! Create a new species thermo manager instance, by specifying + //!the type and (optionally) a pointer to the factory to use to create it. + /*! + * This utility program is a basic factory operation for spawning a + * new species reference-state thermo mananger + * + * These functions allows for using a different factory class that + * derives from SpeciesThermoFactory. However, no applications of this + * have been done yet. + * + * @param type Species thermo type. + * @param f Pointer to a SpeciesThermoFactory. optional parameter. + * Defautls to NULL. + */ + inline SpeciesThermo* newSpeciesThermoMgr(std::string &stype, + SpeciesThermoFactory* f=0) { + if (f == 0) { + f = SpeciesThermoFactory::factory(); + } + SpeciesThermo* sptherm = f->newSpeciesThermoManager(stype); + return sptherm; + } + //! Function to return SpeciesThermo manager /*! * This utility program will look through species nodes. It will discover what diff --git a/Cantera/src/thermo/SpeciesThermoInterpType.cpp b/Cantera/src/thermo/SpeciesThermoInterpType.cpp index d153b4152..bc1b3f583 100644 --- a/Cantera/src/thermo/SpeciesThermoInterpType.cpp +++ b/Cantera/src/thermo/SpeciesThermoInterpType.cpp @@ -72,15 +72,13 @@ namespace Cantera { //! Returns the minimum temperature that the thermo //! parameterization is valid doublereal STITbyPDSS::minTemp() const { - // This concept needs to be put into PDSS - return 0.0; + return m_PDSS_ptr->minTemp(); } //! Returns the maximum temperature that the thermo //! parameterization is valid doublereal STITbyPDSS::maxTemp() const { - // This concept needs to be put into PDSS - return 0.0; + return m_PDSS_ptr->maxTemp(); } //! Returns the reference pressure (Pa) diff --git a/Cantera/src/thermo/SpeciesThermoMgr.h b/Cantera/src/thermo/SpeciesThermoMgr.h index e40221586..b284aa9e3 100755 --- a/Cantera/src/thermo/SpeciesThermoMgr.h +++ b/Cantera/src/thermo/SpeciesThermoMgr.h @@ -133,6 +133,10 @@ namespace Cantera { UnknownSpeciesThermo(std::string proc, int type) : CanteraError(proc, "Specified species parameterization type (" + int2str(type) + ") does not match any known type.") {} + + UnknownSpeciesThermo(std::string proc, std::string stype) : + CanteraError(proc, "Specified species parameterization type (" + stype + + ") does not match any known type.") {} //! destructor virtual ~UnknownSpeciesThermo() {} }; diff --git a/Cantera/src/thermo/ThermoFactory.cpp b/Cantera/src/thermo/ThermoFactory.cpp index cf78abfef..e6c6faba2 100644 --- a/Cantera/src/thermo/ThermoFactory.cpp +++ b/Cantera/src/thermo/ThermoFactory.cpp @@ -377,14 +377,14 @@ namespace Cantera { SpeciesThermo* spth = 0; VPSSMgr* vp_spth = 0; if (ssConvention == cSS_CONVENTION_TEMPERATURE) { - // Create a new species thermo manager. Function - // 'newSpeciesThermoMgr' looks at the species in the database - // to see what thermodynamic property parameterizations are - // used, and selects a class that can handle the - // parameterizations found. + // Create a new species thermo manager. Function + // 'newSpeciesThermoMgr' looks at the species in the database + // to see what thermodynamic property parameterizations are + // used, and selects a class that can handle the + // parameterizations found. spth = newSpeciesThermoMgr(dbases); - - // install it in the phase object + + // install it in the phase object th->setSpeciesThermo(spth); // SpeciesThermo& spthermo = th->speciesThermo(); } else { diff --git a/Cantera/src/thermo/VPSSMgr.cpp b/Cantera/src/thermo/VPSSMgr.cpp index 255036fc3..182852f35 100644 --- a/Cantera/src/thermo/VPSSMgr.cpp +++ b/Cantera/src/thermo/VPSSMgr.cpp @@ -43,7 +43,7 @@ namespace Cantera { m_plast(-1.0), m_p0(-1.0), m_minTemp(-1.0), - m_maxTemp(-1.0), + m_maxTemp(1.0E8), m_useTmpRefStateStorage(false), m_useTmpStandardStateStorage(false) { @@ -67,7 +67,7 @@ namespace Cantera { m_plast(-1.0), m_p0(-1.0), m_minTemp(-1.0), - m_maxTemp(-1.0), + m_maxTemp(1.0E8), m_useTmpRefStateStorage(false), m_useTmpStandardStateStorage(false) { @@ -399,9 +399,7 @@ namespace Cantera { PDSS * VPSSMgr::createInstallPDSS(int k, const XML_Node& s, const XML_Node *phaseNode_ptr) { - // VPSSMgr_enumType tt = reportVPSSMgrType(); - //string ttt = "createInstallPDSS: " + int2str(int(tt)); - err( "createInstallPDSS: "); + err("VPSSMgr::createInstallPDSS"); return (PDSS *) 0; } diff --git a/Cantera/src/thermo/VPSSMgrFactory.cpp b/Cantera/src/thermo/VPSSMgrFactory.cpp index 1daa2904c..964323a01 100644 --- a/Cantera/src/thermo/VPSSMgrFactory.cpp +++ b/Cantera/src/thermo/VPSSMgrFactory.cpp @@ -150,18 +150,19 @@ namespace Cantera { VPSSMgr_enumType VPSSMgrFactory::VPSSMgr_StringConversion(std::string ssModel) const { + std::string lssModel = lowercase(ssModel); VPSSMgr_enumType type; - if (ssModel == "IdealGas") { + if (lssModel == "idealgas") { type = cVPSSMGR_IDEALGAS; - } else if (ssModel == "ConstVol") { + } else if (lssModel == "constvol") { type = cVPSSMGR_CONSTVOL; - } else if (ssModel == "PureFuild") { + } else if (lssModel == "purefuild") { type = cVPSSMGR_PUREFLUID; - } else if (ssModel == "Water_ConstVol") { + } else if (lssModel == "water_constvol") { type = cVPSSMGR_WATER_CONSTVOL; - } else if (ssModel == "Water_HKFT") { + } else if (lssModel == "water_hkft") { type = cVPSSMGR_WATER_HKFT; - } else if (ssModel == "General") { + } else if (lssModel == "general") { type = cVPSSMGR_GENERAL; } else { type = cVPSSMGR_UNDEF; @@ -169,108 +170,65 @@ namespace Cantera { return type; } - // Stub out of new capabilities. - + // Chose the variable pressure standard state manager + // and the reference standard state manager VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPStandardStateTP *vp_ptr, XML_Node* phaseNode_ptr, XML_Node* spData_node) { - std::string ssModel=""; - VPSSMgr *vpss = 0; - // First look for any explicit instructions within the XML Data - if (phaseNode_ptr) { - if (phaseNode_ptr->hasChild("thermo")) { - const XML_Node& thermoNode = phaseNode_ptr->child("thermo"); - if (thermoNode.hasChild("standardState")) { - const XML_Node& ssNode = thermoNode.child("standardState"); - ssModel = ssNode["model"]; - } - } - } - - - // first get the reference state handler - SpeciesThermo *spth = newSpeciesThermoMgr(spData_node); - vp_ptr->setSpeciesThermo(spth); - - if (ssModel != "") { - VPSSMgr_enumType type = VPSSMgr_StringConversion(ssModel); - vpss = newVPSSMgr(type, vp_ptr); - return vpss; - } - - // If it comes back as general, then there may be some unknown - // parameterizations to the SpeciesThermo factory routine. - bool haveSomeUnknowns = true; - GeneralSpeciesThermo *ttmp = dynamic_cast(spth); - if (ttmp == 0) { - haveSomeUnknowns = false; - } - - - if (vp_ptr->eosType() == cVPSS_IdealGas) { - vpss = new VPSSMgr_IdealGas(vp_ptr, spth); - - } - - if (vp_ptr->eosType() == cVPSS_ConstVol) { - vpss = new VPSSMgr_ConstVol(vp_ptr, spth); - } - - int inasa = 0, ishomate = 0, isimple = 0, iwater = 0, itpx = 0, iother = 0; - int ihptx = 0; - - try { - getVPSSMgrTypes(spData_node, inasa, ishomate, isimple, iwater, - itpx, ihptx, iother); - } catch (UnknownSpeciesThermoModel) { - iother = 1; - popError(); - } - - if (iwater == 1) { - if (ihptx == 0) { - vpss = new VPSSMgr_Water_ConstVol(vp_ptr, spth); - } else { - vpss = new VPSSMgr_Water_HKFT(vp_ptr, spth); - } - } - // The default here is to fall back to use the completely - // general representation. - if (vpss == 0) { - vpss = new VPSSMgr_General(vp_ptr, spth); - } - return vpss; + std::vector spData_nodes; + spData_nodes.push_back(spData_node); + VPSSMgr *vv = newVPSSMgr(vp_ptr, phaseNode_ptr, spData_nodes); + return vv; } - + + // Chose the variable pressure standard state manager + // and the reference standard state manager VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPStandardStateTP *vp_ptr, XML_Node* phaseNode_ptr, std::vector spData_nodes) { - std::string ssModel=""; + std::string ssManager=""; + std::string vpssManager=""; VPSSMgr *vpss = 0; - // First look for any explicit instructions within the XML Data + + // First look for any explicit instructions within the XML Database + // for the standard state manager and the variable pressure + // standard state manager if (phaseNode_ptr) { if (phaseNode_ptr->hasChild("thermo")) { const XML_Node& thermoNode = phaseNode_ptr->child("thermo"); - if (thermoNode.hasChild("standardState")) { - const XML_Node& ssNode = thermoNode.child("standardState"); - ssModel = ssNode["model"]; + if (thermoNode.hasChild("standardStateManager")) { + const XML_Node& ssNode = thermoNode.child("standardStateManager"); + ssManager = ssNode["model"]; + } + if (thermoNode.hasChild("variablePressureStandardStateManager")) { + const XML_Node& vpssNode = thermoNode.child("variablePressureStandardStateManager"); + vpssManager = vpssNode["model"]; } } } - // first get the reference state handler - SpeciesThermo *spth = newSpeciesThermoMgr(spData_nodes); + // first get the reference state handler. If we have explicit instructions, + // use them to spawn the object. + SpeciesThermo *spth = 0; + if (ssManager != "") { + spth = newSpeciesThermoMgr(ssManager); + } else { + spth = newSpeciesThermoMgr(spData_nodes); + } vp_ptr->setSpeciesThermo(spth); - if (ssModel != "") { - VPSSMgr_enumType type = VPSSMgr_StringConversion(ssModel); + // Next, if we have specific directions, use them to get the VPSSSMgr object + // and return immediately + if (vpssManager != "") { + VPSSMgr_enumType type = VPSSMgr_StringConversion(vpssManager); vpss = newVPSSMgr(type, vp_ptr); return vpss; } + // If it comes back as general, then there may be some unknown // parameterizations to the SpeciesThermo factory routine. bool haveSomeUnknowns = true; @@ -278,14 +236,16 @@ namespace Cantera { if (ttmp == 0) { haveSomeUnknowns = false; } - - if (vp_ptr->eosType() == cIdealSolnGasVPSS) { + + // Handle special cases based on the VPStandardState types + if (vp_ptr->eosType() == cVPSS_IdealGas) { vpss = new VPSSMgr_IdealGas(vp_ptr, spth); + return vpss; + } else if (vp_ptr->eosType() == cVPSS_ConstVol) { + vpss = new VPSSMgr_ConstVol(vp_ptr, spth); + return vpss; } - if (vp_ptr->eosType() == cIdealSolnGasVPSS_iscv) { - vpss = new VPSSMgr_ConstVol(vp_ptr, spth); - } int n = static_cast(spData_nodes.size()); int inasa = 0, ishomate = 0, isimple = 0, iwater = 0, itpx = 0, iother = 0; diff --git a/Cantera/src/thermo/VPSSMgr_General.cpp b/Cantera/src/thermo/VPSSMgr_General.cpp index 9ea1ca28f..6db09888f 100644 --- a/Cantera/src/thermo/VPSSMgr_General.cpp +++ b/Cantera/src/thermo/VPSSMgr_General.cpp @@ -31,6 +31,7 @@ #include "PDSS_Water.h" #include "PDSS_ConstVol.h" #include "PDSS_HKFT.h" +#include "GeneralSpeciesThermo.h" using namespace std; @@ -75,20 +76,20 @@ namespace Cantera { } - void VPSSMgr_General::_updateRefStateThermo() const { - for (int k = 0; k < m_kk; k++) { - PDSS *kPDSS = m_PDSS_ptrs[k]; - kPDSS->setState_TP(m_tlast, m_plast); - m_h0_RT[k] = kPDSS->enthalpy_RT_ref(); - m_s0_R[k] = kPDSS->entropy_R_ref(); - m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k]; - m_cp0_R[k] = kPDSS->cp_R_ref(); - m_V0[k] = kPDSS->molarVolume_ref(); + if (m_useTmpRefStateStorage) { + for (int k = 0; k < m_kk; k++) { + PDSS *kPDSS = m_PDSS_ptrs[k]; + kPDSS->setState_TP(m_tlast, m_plast); + m_h0_RT[k] = kPDSS->enthalpy_RT_ref(); + m_s0_R[k] = kPDSS->entropy_R_ref(); + m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k]; + m_cp0_R[k] = kPDSS->cp_R_ref(); + m_V0[k] = kPDSS->molarVolume_ref(); + } } } - void VPSSMgr_General::_updateStandardStateThermo() { @@ -120,7 +121,9 @@ namespace Cantera { const XML_Node *phaseNode_ptr, bool &doST) { PDSS *kPDSS = 0; doST = true; - + GeneralSpeciesThermo *genSpthermo = dynamic_cast(m_spthermo); + + const XML_Node * const ss = speciesNode.findByName("standardState"); if (!ss) { VPSSMgr::installSTSpecies(k, speciesNode, phaseNode_ptr); @@ -131,12 +134,23 @@ namespace Cantera { if (model == "constant_incompressible") { VPSSMgr::installSTSpecies(k, speciesNode, phaseNode_ptr); kPDSS = new PDSS_ConstVol(m_vptp_ptr, k, speciesNode, *phaseNode_ptr, true); - } else if (model == "waterIAPWS" || model == "waterPDSS") { - doST = false; - kPDSS = new PDSS_Water(); + } else if (model == "waterIAPWS" || model == "waterPDSS") { + // VPSSMgr::installSTSpecies(k, speciesNode, phaseNode_ptr); + kPDSS = new PDSS_Water(m_vptp_ptr, 0); + if (!genSpthermo) { + throw CanteraError("VPSSMgr_General::returnPDSS_ptr", + "failed dynamic cast"); + } + genSpthermo->installPDSShandler(k, kPDSS, this); + m_useTmpRefStateStorage = false; } else if (model == "HKFT") { doST = false; kPDSS = new PDSS_HKFT(m_vptp_ptr, k, speciesNode, *phaseNode_ptr, true); + if (!genSpthermo) { + throw CanteraError("VPSSMgr_General::returnPDSS_ptr", + "failed dynamic cast"); + } + genSpthermo->installPDSShandler(k, kPDSS, this); } else { throw CanteraError("VPSSMgr_General::returnPDSS_ptr", "unknown"); @@ -153,8 +167,26 @@ namespace Cantera { if ((int) m_PDSS_ptrs.size() < k+1) { m_PDSS_ptrs.resize(k+1, 0); } - m_PDSS_ptrs[k] = kPDSS; + if ((k+1) >= m_kk) { + m_kk = k+1; + } + + doublereal minTemp = kPDSS->minTemp(); + if (minTemp > m_minTemp) { + m_minTemp = minTemp; + } + + doublereal maxTemp = kPDSS->maxTemp(); + if (maxTemp < m_maxTemp) { + m_maxTemp = maxTemp; + } + + doublereal p0 = kPDSS->refPressure(); + if (k == 0) { + m_p0 = p0; + } + return kPDSS; } diff --git a/Cantera/src/thermo/WaterPropsIAPWS.cpp b/Cantera/src/thermo/WaterPropsIAPWS.cpp index 05fabf3aa..a2d92e2d9 100644 --- a/Cantera/src/thermo/WaterPropsIAPWS.cpp +++ b/Cantera/src/thermo/WaterPropsIAPWS.cpp @@ -406,9 +406,15 @@ corr1(doublereal temperature, doublereal pressure, doublereal &densLiq, * p : Pascals : Newtons/m**2 */ static int method = 1; -doublereal WaterPropsIAPWS::psat(doublereal temperature) { + +doublereal WaterPropsIAPWS::psat(doublereal temperature, int waterState) { doublereal densLiq = -1.0, densGas = -1.0, delGRT = 0.0; doublereal dp, pcorr; + if (temperature >= T_c) { + densGas = density(temperature, P_c, WATER_SUPERCRIT); + setState_TR(temperature, densGas); + return P_c; + } doublereal p = psat_est(temperature); bool conv = false; for (int i = 0; i < 30; i++) { @@ -432,6 +438,15 @@ doublereal WaterPropsIAPWS::psat(doublereal temperature) { } } } + // Put the fluid in the desired end condition + if (waterState == WATER_LIQUID) { + setState_TR(temperature, densLiq); + } else if (waterState == WATER_GAS) { + setState_TR(temperature, densGas); + } else { + throw Cantera::CanteraError("WaterPropsIAPWS::psat", + "unknown water state input: " + Cantera::int2str(waterState)); + } return p; } diff --git a/Cantera/src/thermo/WaterPropsIAPWS.h b/Cantera/src/thermo/WaterPropsIAPWS.h index a9601ed5b..56e4807ef 100644 --- a/Cantera/src/thermo/WaterPropsIAPWS.h +++ b/Cantera/src/thermo/WaterPropsIAPWS.h @@ -332,7 +332,7 @@ public: * Returns the saturation pressure * units = Pascal */ - doublereal psat(doublereal temperature); + doublereal psat(doublereal temperature, int waterState = WATER_LIQUID); //! Return the value of the density at the water spinodal point //! for the current temperature.