/** * @file VPSSMgrFactory.cpp * Definitions for factory to build instances of classes that manage the * calculation of standard state properties for all the species in a phase * (see \ref spthermo and class * \link Cantera::VPSSMgrFactory VPSSMgrFactory\endlink); */ /* * Copyright (2005) Sandia Corporation. Under the terms of * Contract DE-AC04-94AL85000 with Sandia Corporation, the * U.S. Government retains certain rights in this software. */ #include "cantera/thermo/SpeciesThermo.h" #include "cantera/thermo/VPSSMgr.h" #include "VPSSMgrFactory.h" #include "cantera/thermo/VPStandardStateTP.h" #include "cantera/thermo/VPSSMgr_IdealGas.h" #include "cantera/thermo/VPSSMgr_ConstVol.h" #include "cantera/thermo/VPSSMgr_Water_ConstVol.h" #include "cantera/thermo/VPSSMgr_Water_HKFT.h" #include "cantera/thermo/VPSSMgr_General.h" #include "cantera/thermo/VPSSMgr_types.h" #include "cantera/thermo/SpeciesThermoMgr.h" #include "cantera/thermo/speciesThermoTypes.h" #include "cantera/thermo/SpeciesThermo.h" #include "cantera/thermo/SpeciesThermoFactory.h" #include "cantera/thermo/GeneralSpeciesThermo.h" #include "cantera/thermo/mix_defs.h" #include "cantera/base/xml.h" #include "cantera/base/ctml.h" using namespace ctml; using namespace std; namespace Cantera { VPSSMgrFactory* VPSSMgrFactory::s_factory = 0; // Defn of the static mutex variable that locks the %VPSSMgr factory singleton mutex_t VPSSMgrFactory::vpss_species_thermo_mutex; //! Examine the types of species thermo parameterizations, and return a flag indicating the type of parameterization //! needed by the species. /*! * * @param spDataNodeList Species Data XML node. This node contains a list * of species XML nodes underneath it. * @param has_nasa_idealGas Boolean indicating that one species has a nasa ideal gas standard state * @param has_nasa_constVol Boolean indicating that one species has a nasa ideal solution standard state * @param has_shomate_idealGas Boolean indicating that one species has a shomate ideal gas standard state * @param has_shomate_constVol Boolean indicating that one species has a shomate ideal solution standard state * @param has_simple_idealGas Boolean indicating that one species has a simple ideal gas standard state * @param has_simple_constVol Boolean indicating that one species has a simple ideal solution standard state * @param has_water Boolean indicating that one species has a water standard state * @param has_tpx Boolean indicating that one species has a tpx standard state * @param has_hptx Boolean indicating that one species has a htpx standard state * @param has_other Boolean indicating that one species has different standard state than the ones listed above * * @todo Make sure that spDadta_node is species Data XML node by checking * its name is speciesData */ static void getVPSSMgrTypes(std::vector & spDataNodeList, int& has_nasa_idealGas, int& has_nasa_constVol, int& has_shomate_idealGas, int& has_shomate_constVol, int& has_simple_idealGas, int& has_simple_constVol, int& has_water, int& has_tpx, int& has_hptx, int& has_other) { XML_Node* ss_ptr = 0; string ssModel = "idealGas"; size_t ns = spDataNodeList.size(); for (size_t n = 0; n < ns; n++) { bool ifound = false; XML_Node* spNode = spDataNodeList[n]; if (spNode->hasChild("standardState")) { const XML_Node& ssN = spNode->child("standardState"); string mm = ssN["model"]; if (mm == "waterIAPWS" || mm == "waterPDSS") { has_water++; ifound = true; } if (mm == "HKFT") { has_hptx++; ifound = true; } } if (!ifound) { if (spNode->hasChild("thermo")) { const XML_Node& th = spNode->child("thermo"); if (spNode->hasChild("standardState")) { ss_ptr = &(spNode->child("standardState")); ssModel = ss_ptr->attrib("model"); } if (th.hasChild("NASA")) { if (ssModel == "idealGas") { has_nasa_idealGas++; } else if (ssModel == "constant_incompressible" || ssModel == "constantVolume") { has_nasa_constVol++; } else if (ssModel == "temperature_polynomial" || ssModel == "density_temperature_polynomial" || ssModel == "constant") { has_other++; } else { throw UnknownVPSSMgrModel("getVPSSMgrTypes:", spNode->attrib("name")); } ifound = true; } if (th.hasChild("Shomate")) { if (ssModel == "idealGas") { has_shomate_idealGas++; } else if (ssModel == "constant_incompressible" || ssModel == "constantVolume") { has_shomate_constVol++; } else if (ssModel == "temperature_polynomial" || ssModel == "density_temperature_polynomial" || ssModel == "constant") { has_other++; } else { throw UnknownVPSSMgrModel("getVPSSMgrTypes:", spNode->attrib("name")); } ifound = true; } if (th.hasChild("const_cp")) { if (ssModel == "idealGas") { has_simple_idealGas++; } else if (ssModel == "constant_incompressible" || ssModel == "constantVolume") { has_simple_constVol++; } else if (ssModel == "temperature_polynomial" || ssModel == "density_temperature_polynomial" || ssModel == "constant") { has_other++; } else { throw UnknownVPSSMgrModel("getVPSSMgrTypes:", spNode->attrib("name")); } ifound = true; } if (th.hasChild("poly")) { if (th.child("poly")["order"] == "1") { has_simple_constVol = 1; ifound = true; } else throw CanteraError("newSpeciesThermo", "poly with order > 1 not yet supported"); } if (th.hasChild("Mu0")) { has_other++; ifound = true; } if (th.hasChild("NASA9")) { has_other++; ifound = true; } if (th.hasChild("NASA9MULTITEMP")) { has_other++; ifound = true; } if (th.hasChild("adsorbate")) { has_other++; ifound = true; } if (th.hasChild("HKFT")) { has_hptx++; ifound = true; } } else { throw UnknownVPSSMgrModel("getVPSSMgrTypes:", spNode->attrib("name")); } } } } // Delete static instance of this class /* * If it is necessary to explicitly delete the factory before * the process terminates (for example, when checking for * memory leaks) then this method can be called to delete it. */ void VPSSMgrFactory::deleteFactory() { ScopedLock lock(vpss_species_thermo_mutex); if (s_factory) { delete s_factory; s_factory = 0; } } VPSSMgrFactory::~VPSSMgrFactory() { } VPSSMgr_enumType VPSSMgrFactory::VPSSMgr_StringConversion(std::string ssModel) const { std::string lssModel = lowercase(ssModel); VPSSMgr_enumType type; if (lssModel == "idealgas") { type = cVPSSMGR_IDEALGAS; } else if (lssModel == "constvol") { type = cVPSSMGR_CONSTVOL; } else if (lssModel == "purefuild") { type = cVPSSMGR_PUREFLUID; } else if (lssModel == "water_constvol") { type = cVPSSMGR_WATER_CONSTVOL; } else if (lssModel == "water_hkft") { type = cVPSSMGR_WATER_HKFT; } else if (lssModel == "general") { type = cVPSSMGR_GENERAL; } else { type = cVPSSMGR_UNDEF; } return type; } // 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 & spDataNodeList) { std::string ssManager=""; std::string vpssManager=""; VPSSMgr* vpss = 0; // 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("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. If we have explicit instructions, // use them to spawn the object. SpeciesThermo* spth = 0; if (ssManager != "") { spth = newSpeciesThermoMgr(ssManager); } else { spth = newSpeciesThermoMgr(spDataNodeList); } vp_ptr->setSpeciesThermo(spth); // 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; } // 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; } int inasaIG = 0, inasaCV = 0, ishomateIG = 0, ishomateCV = 0, isimpleIG = 0, isimpleCV = 0, iwater = 0, itpx = 0, iother = 0; int ihptx = 0; try { getVPSSMgrTypes(spDataNodeList, inasaIG, inasaCV, ishomateIG, ishomateCV, isimpleIG, isimpleCV, iwater, itpx, ihptx, iother); } catch (UnknownSpeciesThermoModel) { iother = 1; popError(); } if (iwater == 1) { if (ihptx == 0) { if (inasaIG || ishomateIG || isimpleIG) { throw CanteraError("newVPSSMgr", "Ideal gas with liquid water"); } else { vpss = new VPSSMgr_Water_ConstVol(vp_ptr, spth); } } else { if (inasaIG || ishomateIG || isimpleIG) { throw CanteraError("newVPSSMgr", "Ideal gas with liquid water"); } else if (inasaCV || ishomateCV || isimpleCV) { vpss = new VPSSMgr_General(vp_ptr, spth); } else { vpss = new VPSSMgr_Water_HKFT(vp_ptr, spth); } } } if (vpss == 0) { if (inasaCV || ishomateCV || isimpleCV) { if (!inasaIG && !ishomateIG && !isimpleIG && !itpx && !ihptx && !iother) { vpss = new VPSSMgr_ConstVol(vp_ptr, spth); } } } if (vpss == 0) { vpss = new VPSSMgr_General(vp_ptr, spth); } return vpss; } // I don't think this is currently used. However, this is a virtual // function where additional capabilities may be added. VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPSSMgr_enumType type, VPStandardStateTP* vp_ptr) { SpeciesThermo& spthermoRef = vp_ptr->speciesThermo(); switch (type) { case cVPSSMGR_IDEALGAS: return new VPSSMgr_IdealGas(vp_ptr, &spthermoRef); case cVPSSMGR_CONSTVOL: return new VPSSMgr_ConstVol(vp_ptr, &spthermoRef); case cVPSSMGR_PUREFLUID: throw CanteraError("VPSSMgrFactory::newVPSSMgr", "unimplemented"); case cVPSSMGR_WATER_CONSTVOL: return new VPSSMgr_Water_ConstVol(vp_ptr, &spthermoRef); case cVPSSMGR_WATER_HKFT: return new VPSSMgr_Water_HKFT(vp_ptr, &spthermoRef); case cVPSSMGR_GENERAL: return new VPSSMgr_General(vp_ptr, &spthermoRef); case cVPSSMGR_UNDEF: default: throw UnknownVPSSMgrModel("VPSSMgrFactory::newVPSSMgr", int2str(type)); return 0; } } // I don't think this is currently used VPSSMgr* newVPSSMgr(VPSSMgr_enumType type, VPStandardStateTP* vp_ptr, Cantera::VPSSMgrFactory* f) { if (f == 0) { f = VPSSMgrFactory::factory(); } VPSSMgr* vpsssptherm = f->newVPSSMgr(type, vp_ptr); return vpsssptherm; } VPSSMgr* newVPSSMgr(VPStandardStateTP* tp_ptr, XML_Node* phaseNode_ptr, std::vector & spDataNodeList, VPSSMgrFactory* f) { if (f == 0) { f = VPSSMgrFactory::factory(); } VPSSMgr* vpsssptherm = f->newVPSSMgr(tp_ptr, phaseNode_ptr, spDataNodeList); return vpsssptherm; } }