/** * @file PDSS_SSVol.cpp * Implementation of a pressure dependent standard state * virtual function. */ /* * Copyright (2006) 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/base/ct_defs.h" #include "cantera/base/xml.h" #include "cantera/base/ctml.h" #include "cantera/thermo/PDSS_SSVol.h" #include "cantera/thermo/ThermoFactory.h" #include "cantera/thermo/VPStandardStateTP.h" using namespace std; namespace Cantera { /** * Basic list of constructors and duplicators */ PDSS_SSVol::PDSS_SSVol(VPStandardStateTP* tp, size_t spindex) : PDSS(tp, spindex), volumeModel_(cSSVOLUME_CONSTANT), m_constMolarVolume(-1.0) { m_pdssType = cPDSS_SSVOL; TCoeff_[0] = 0.0; TCoeff_[1] = 0.0; TCoeff_[2] = 0.0; } PDSS_SSVol::PDSS_SSVol(VPStandardStateTP* tp, size_t spindex, std::string inputFile, std::string id) : PDSS(tp, spindex), volumeModel_(cSSVOLUME_CONSTANT), m_constMolarVolume(-1.0) { m_pdssType = cPDSS_SSVOL; constructPDSSFile(tp, spindex, inputFile, id); } PDSS_SSVol::PDSS_SSVol(VPStandardStateTP* tp, size_t spindex, const XML_Node& speciesNode, const XML_Node& phaseRoot, bool spInstalled) : PDSS(tp, spindex), volumeModel_(cSSVOLUME_CONSTANT), m_constMolarVolume(-1.0) { m_pdssType = cPDSS_SSVOL; constructPDSSXML(tp, spindex, speciesNode, phaseRoot, spInstalled) ; } PDSS_SSVol::PDSS_SSVol(const PDSS_SSVol& b) : PDSS(b), volumeModel_(cSSVOLUME_CONSTANT), m_constMolarVolume(-1.0) { /* * Use the assignment operator to do the brunt * of the work for the copy constructor. */ *this = b; } /* * Assignment operator */ PDSS_SSVol& PDSS_SSVol::operator=(const PDSS_SSVol& b) { if (&b == this) { return *this; } PDSS::operator=(b); volumeModel_ = b.volumeModel_; m_constMolarVolume = b.m_constMolarVolume; TCoeff_ = b.TCoeff_; return *this; } PDSS_SSVol::~PDSS_SSVol() { } //! Duplicator PDSS* PDSS_SSVol::duplMyselfAsPDSS() const { PDSS_SSVol* idg = new PDSS_SSVol(*this); return (PDSS*) idg; } /* * constructPDSSXML: * * Initialization of a PDSS_SSVol object using an * xml file. * * This routine is a precursor to initThermo(XML_Node*) * routine, which does most of the work. * * @param infile XML file containing the description of the * phase * * @param id Optional parameter identifying the name of the * phase. If none is given, the first XML * phase element will be used. */ void PDSS_SSVol::constructPDSSXML(VPStandardStateTP* tp, size_t spindex, const XML_Node& speciesNode, const XML_Node& phaseNode, bool spInstalled) { PDSS::initThermo(); SpeciesThermo& sp = m_tp->speciesThermo(); m_p0 = sp.refPressure(m_spindex); if (!spInstalled) { throw CanteraError("PDSS_SSVol::constructPDSSXML", "spInstalled false not handled"); } const XML_Node* ss = speciesNode.findByName("standardState"); if (!ss) { throw CanteraError("PDSS_SSVol::constructPDSSXML", "no standardState Node for species " + speciesNode.name()); } std::string model = (*ss)["model"]; if (model == "constant_incompressible" || model == "constant") { volumeModel_ = cSSVOLUME_CONSTANT; m_constMolarVolume = ctml::getFloat(*ss, "molarVolume", "toSI"); } else if (model == "temperature_polynomial") { volumeModel_ = cSSVOLUME_TPOLY; size_t num = ctml::getFloatArray(*ss, TCoeff_, true, "toSI", "volumeTemperaturePolynomial"); if (num != 4) { throw CanteraError("PDSS_SSVol::constructPDSSXML", " Didn't get 4 density polynomial numbers for species " + speciesNode.name()); } } else if (model == "density_temperature_polynomial") { volumeModel_ = cSSVOLUME_DENSITY_TPOLY; size_t num = ctml::getFloatArray(*ss, TCoeff_, true, "toSI", "densityTemperaturePolynomial"); if (num != 4) { throw CanteraError("PDSS_SSVol::constructPDSSXML", " Didn't get 4 density polynomial numbers for species " + speciesNode.name()); } } else { throw CanteraError("PDSS_SSVol::constructPDSSXML", "standardState model for species isn't constant_incompressible: " + speciesNode.name()); } std::string id = ""; } /* * constructPDSSFile(): * * Initialization of a PDSS_SSVol object using an * xml file. * * This routine is a precursor to initThermo(XML_Node*) * routine, which does most of the work. * * @param infile XML file containing the description of the * phase * * @param id Optional parameter identifying the name of the * phase. If none is given, the first XML * phase element will be used. */ void PDSS_SSVol::constructPDSSFile(VPStandardStateTP* tp, size_t spindex, std::string inputFile, std::string id) { if (inputFile.size() == 0) { throw CanteraError("PDSS_SSVol::initThermo", "input file is null"); } std::string path = findInputFile(inputFile); ifstream fin(path.c_str()); if (!fin) { throw CanteraError("PDSS_SSVol::initThermo","could not open " +path+" for reading."); } /* * The phase object automatically constructs an XML object. * Use this object to store information. */ XML_Node* fxml = new XML_Node(); fxml->build(fin); XML_Node* fxml_phase = findXMLPhase(fxml, id); if (!fxml_phase) { throw CanteraError("PDSS_SSVol::initThermo", "ERROR: Can not find phase named " + id + " in file named " + inputFile); } XML_Node& speciesList = fxml_phase->child("speciesArray"); XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"], &(fxml_phase->root())); const vector&sss = tp->speciesNames(); const XML_Node* s = speciesDB->findByAttr("name", sss[spindex]); constructPDSSXML(tp, spindex, *s, *fxml_phase, true); delete fxml; } void PDSS_SSVol::initThermoXML(const XML_Node& phaseNode, std::string& id) { PDSS::initThermoXML(phaseNode, id); m_minTemp = m_spthermo->minTemp(m_spindex); m_maxTemp = m_spthermo->maxTemp(m_spindex); m_p0 = m_spthermo->refPressure(m_spindex); m_mw = m_tp->molecularWeight(m_spindex); } void PDSS_SSVol::initThermo() { PDSS::initThermo(); SpeciesThermo& sp = m_tp->speciesThermo(); m_p0 = sp.refPressure(m_spindex); m_V0_ptr[m_spindex] = m_constMolarVolume; m_Vss_ptr[m_spindex] = m_constMolarVolume; } doublereal PDSS_SSVol::enthalpy_mole() const { doublereal val = enthalpy_RT(); doublereal RT = GasConstant * m_temp; return (val * RT); } doublereal PDSS_SSVol::enthalpy_RT() const { doublereal val = m_hss_RT_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::intEnergy_mole() const { doublereal pVRT = (m_pres * m_Vss_ptr[m_spindex]) / (GasConstant * m_temp); doublereal val = m_h0_RT_ptr[m_spindex] - pVRT; doublereal RT = GasConstant * m_temp; return (val * RT); } doublereal PDSS_SSVol::entropy_mole() const { doublereal val = entropy_R(); return (val * GasConstant); } doublereal PDSS_SSVol::entropy_R() const { doublereal val = m_sss_R_ptr[m_spindex]; return (val); } /** * Calculate the Gibbs free energy in mks units of * J kmol-1 K-1. */ doublereal PDSS_SSVol::gibbs_mole() const { doublereal val = gibbs_RT(); doublereal RT = GasConstant * m_temp; return (val * RT); } doublereal PDSS_SSVol::gibbs_RT() const { doublereal val = m_gss_RT_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::cp_mole() const { doublereal val = m_cpss_R_ptr[m_spindex]; return (val * GasConstant); } doublereal PDSS_SSVol::cp_R() const { doublereal val = m_cpss_R_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::cv_mole() const { doublereal val = (cp_mole() - m_V0_ptr[m_spindex]); return (val); } doublereal PDSS_SSVol::molarVolume() const { doublereal val = m_Vss_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::density() const { doublereal val = m_Vss_ptr[m_spindex]; return (m_mw/val); } doublereal PDSS_SSVol::gibbs_RT_ref() const { doublereal val = m_g0_RT_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::enthalpy_RT_ref() const { doublereal val = m_h0_RT_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::entropy_R_ref() const { doublereal val = m_s0_R_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::cp_R_ref() const { doublereal val = m_cp0_R_ptr[m_spindex]; return (val); } doublereal PDSS_SSVol::molarVolume_ref() const { doublereal val = m_V0_ptr[m_spindex]; return (val); } void PDSS_SSVol::calcMolarVolume() const { if (volumeModel_ == cSSVOLUME_CONSTANT) { m_Vss_ptr[m_spindex] = m_constMolarVolume; } else if (volumeModel_ == cSSVOLUME_TPOLY) { m_Vss_ptr[m_spindex] = TCoeff_[0] + m_temp * (TCoeff_[1] + m_temp * (TCoeff_[2] + m_temp * TCoeff_[3])); dVdT_ = TCoeff_[1] + 2.0 * m_temp * TCoeff_[2] + 3.0 * m_temp * m_temp * TCoeff_[3]; d2VdT2_ = 2.0 * TCoeff_[2] + 6.0 * m_temp * TCoeff_[3]; } else if (volumeModel_ == cSSVOLUME_DENSITY_TPOLY) { doublereal dens = TCoeff_[0] + m_temp * (TCoeff_[1] + m_temp * (TCoeff_[2] + m_temp * TCoeff_[3])); m_Vss_ptr[m_spindex] = m_mw / dens; doublereal dens2 = dens * dens; doublereal ddensdT = TCoeff_[1] + 2.0 * m_temp * TCoeff_[2] + 3.0 * m_temp * m_temp * TCoeff_[3]; doublereal d2densdT2 = 2.0 * TCoeff_[2] + 6.0 * m_temp * TCoeff_[3]; dVdT_ = - m_mw / (dens2) * (ddensdT); d2VdT2_ = 2.0 * m_mw / (dens2 * dens) * ddensdT * ddensdT - m_mw / dens2 * d2densdT2; } else { throw CanteraError("PDSS_SSVol::calcMolarVolume", "unimplemented"); } } /// critical temperature doublereal PDSS_SSVol::critTemperature() const { throw CanteraError("PDSS_SSVol::critTemperature()", "unimplemented"); return (0.0); } /// critical pressure doublereal PDSS_SSVol::critPressure() const { throw CanteraError("PDSS_SSVol::critPressure()", "unimplemented"); return (0.0); } /// critical density doublereal PDSS_SSVol::critDensity() const { throw CanteraError("PDSS_SSVol::critDensity()", "unimplemented"); return (0.0); } void PDSS_SSVol::setPressure(doublereal p) { m_pres = p; doublereal deltaP = m_pres - m_p0; if (fabs(deltaP) < 1.0E-10) { m_hss_RT_ptr[m_spindex] = m_h0_RT_ptr[m_spindex]; m_sss_R_ptr[m_spindex] = m_s0_R_ptr[m_spindex]; m_gss_RT_ptr[m_spindex] = m_hss_RT_ptr[m_spindex] - m_sss_R_ptr[m_spindex]; m_cpss_R_ptr[m_spindex] = m_cp0_R_ptr[m_spindex]; } else { doublereal del_pRT = deltaP / (GasConstant * m_temp); doublereal sV_term = - deltaP / (GasConstant) * dVdT_; m_hss_RT_ptr[m_spindex] = m_h0_RT_ptr[m_spindex] + sV_term + del_pRT * (m_Vss_ptr[m_spindex]); m_sss_R_ptr[m_spindex] = m_s0_R_ptr[m_spindex] + sV_term; m_gss_RT_ptr[m_spindex] = m_hss_RT_ptr[m_spindex] - m_sss_R_ptr[m_spindex]; m_cpss_R_ptr[m_spindex] = m_cp0_R_ptr[m_spindex] - m_temp * deltaP * d2VdT2_; } } void PDSS_SSVol::setTemperature(doublereal temp) { m_temp = temp; m_spthermo->update_one(m_spindex, temp, m_cp0_R_ptr, m_h0_RT_ptr, m_s0_R_ptr); calcMolarVolume(); m_g0_RT_ptr[m_spindex] = m_h0_RT_ptr[m_spindex] - m_s0_R_ptr[m_spindex]; doublereal deltaP = m_pres - m_p0; if (fabs(deltaP) < 1.0E-10) { m_hss_RT_ptr[m_spindex] = m_h0_RT_ptr[m_spindex]; m_sss_R_ptr[m_spindex] = m_s0_R_ptr[m_spindex]; m_gss_RT_ptr[m_spindex] = m_hss_RT_ptr[m_spindex] - m_sss_R_ptr[m_spindex]; m_cpss_R_ptr[m_spindex] = m_cp0_R_ptr[m_spindex]; } else { doublereal del_pRT = deltaP / (GasConstant * m_temp); doublereal sV_term = - deltaP / (GasConstant) * dVdT_; m_hss_RT_ptr[m_spindex] = m_h0_RT_ptr[m_spindex] + sV_term + del_pRT * (m_Vss_ptr[m_spindex]); m_sss_R_ptr[m_spindex] = m_s0_R_ptr[m_spindex] + sV_term; m_gss_RT_ptr[m_spindex] = m_hss_RT_ptr[m_spindex] - m_sss_R_ptr[m_spindex]; m_cpss_R_ptr[m_spindex] = m_cp0_R_ptr[m_spindex] - m_temp * deltaP * d2VdT2_; } } void PDSS_SSVol::setState_TP(doublereal temp, doublereal pres) { m_pres = pres; setTemperature(temp); } void PDSS_SSVol::setState_TR(doublereal temp, doublereal rho) { doublereal rhoStored = m_mw / m_constMolarVolume; if (fabs(rhoStored - rho) / (rhoStored + rho) > 1.0E-4) { throw CanteraError("PDSS_SSVol::setState_TR", "Inconsistent supplied rho"); } setTemperature(temp); } /// saturation pressure doublereal PDSS_SSVol::satPressure(doublereal t) { return (1.0E-200); } }