/** * @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); */ /* * $Id$ */ /* * Copywrite (2005) Sandia Corporation. Under the terms of * Contract DE-AC04-94AL85000 with Sandia Corporation, the * U.S. Government retains certain rights in this software. */ #ifdef WIN32 #pragma warning(disable:4786) #endif #include "SpeciesThermo.h" #include "VPSSMgr.h" #include "VPSSMgrFactory.h" #include "VPStandardStateTP.h" #include "VPSSMgr_IdealGas.h" #include "VPSSMgr_ConstVol.h" #include "VPSSMgr_Water_ConstVol.h" #include "VPSSMgr_Water_HKFT.h" #include "VPSSMgr_General.h" #include "VPSSMgr_types.h" #include "SpeciesThermoMgr.h" #include "speciesThermoTypes.h" #include "SpeciesThermo.h" #include "SpeciesThermoFactory.h" #include "GeneralSpeciesThermo.h" #include "mix_defs.h" #include "xml.h" #include "ctml.h" using namespace ctml; using namespace std; namespace Cantera { VPSSMgrFactory* VPSSMgrFactory::s_factory = 0; #if defined(THREAD_SAFE_CANTERA) // Defn of the static mutex variable that locks the // %VPSSMgr factory singelton boost::mutex VPSSMgrFactory::vpss_species_thermo_mutex; #endif /* * Examine the types of species thermo parameterizations, * and return a flag indicating the type of parameterization * needed by the species. * * @param spData_node Species Data XML node. This node contains a list * of species XML nodes underneath it. * * @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 { 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 { 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 { 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() { #if defined(THREAD_SAFE_CANTERA) boost::mutex::scoped_lock lock(species_thermo_mutex); #endif 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; } // 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; } // 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) { vpss = new VPSSMgr_Water_ConstVol(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); break; case cVPSSMGR_CONSTVOL: return new VPSSMgr_ConstVol(vp_ptr, &spthermoRef); break; case cVPSSMGR_PUREFLUID: throw CanteraError("VPSSMgrFactory::newVPSSMgr", "unimplemented"); case cVPSSMGR_WATER_CONSTVOL: return new VPSSMgr_Water_ConstVol(vp_ptr, &spthermoRef); break; case cVPSSMGR_WATER_HKFT: return new VPSSMgr_Water_HKFT(vp_ptr, &spthermoRef); break; case cVPSSMGR_GENERAL: return new VPSSMgr_General(vp_ptr, &spthermoRef); break; 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; } }