/** * @file VPStandardStateTP.cpp * Definition file for a derived class of ThermoPhase that handles * variable pressure standard state methods for calculating * thermodynamic properties (see \ref thermoprops and * class \link Cantera::VPStandardStateTP VPStandardStateTP\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/VPStandardStateTP.h" #include "cantera/thermo/VPSSMgr.h" #include "cantera/thermo/PDSS.h" #include "cantera/base/stringUtils.h" using namespace std; namespace Cantera { /* * Default constructor */ VPStandardStateTP::VPStandardStateTP() : ThermoPhase(), m_Pcurrent(OneAtm), m_Tlast_ss(-1.0), m_Plast_ss(-1.0), m_P0(OneAtm), m_VPSS_ptr(0) { } /* * Copy Constructor: * * Note this stuff will not work until the underlying phase * has a working copy constructor. * * The copy constructor just calls the assignment operator * to do the heavy lifting. */ VPStandardStateTP::VPStandardStateTP(const VPStandardStateTP& b) : ThermoPhase(), m_Pcurrent(OneAtm), m_Tlast_ss(-1.0), m_Plast_ss(-1.0), m_P0(OneAtm), m_VPSS_ptr(0) { VPStandardStateTP::operator=(b); } /* * operator=() * * Note this stuff will not work until the underlying phase * has a working assignment operator */ VPStandardStateTP& VPStandardStateTP::operator=(const VPStandardStateTP& b) { if (&b != this) { /* * Mostly, this is a passthrough to the underlying * assignment operator for the ThermoPhase parent object. */ ThermoPhase::operator=(b); /* * However, we have to handle data that we own. */ m_Pcurrent = b.m_Pcurrent; m_Tlast_ss = b.m_Tlast_ss; m_Plast_ss = b.m_Plast_ss; m_P0 = b.m_P0; /* * Duplicate the pdss objects */ if (m_PDSS_storage.size() > 0) { for (int k = 0; k < (int) m_PDSS_storage.size(); k++) { delete(m_PDSS_storage[k]); } } m_PDSS_storage.resize(m_kk); for (size_t k = 0; k < m_kk; k++) { PDSS* ptmp = b.m_PDSS_storage[k]; m_PDSS_storage[k] = ptmp->duplMyselfAsPDSS(); } /* * Duplicate the VPSS Manager object that conducts the calculations */ if (m_VPSS_ptr) { delete m_VPSS_ptr; m_VPSS_ptr = 0; } m_VPSS_ptr = (b.m_VPSS_ptr)->duplMyselfAsVPSSMgr(); /* * The VPSSMgr object contains shallow pointers. Whenever you have shallow * pointers, they have to be fixed up to point to the correct objects referring * back to this ThermoPhase's properties. */ m_VPSS_ptr->initAllPtrs(this, m_spthermo); /* * The PDSS objects contains shallow pointers. Whenever you have shallow * pointers, they have to be fixed up to point to the correct objects referring * back to this ThermoPhase's properties. This function also sets m_VPSS_ptr * so it occurs after m_VPSS_ptr is set. */ for (size_t k = 0; k < m_kk; k++) { PDSS* ptmp = m_PDSS_storage[k]; ptmp->initAllPtrs(this, m_VPSS_ptr, m_spthermo); } /* * Ok, the VPSSMgr object is ready for business. * We need to resync the temperature and the pressure of the new standard states * with what is stored in this object. */ m_VPSS_ptr->setState_TP(m_Tlast_ss, m_Plast_ss); } return *this; } //==================================================================================================================== /* * ~VPStandardStateTP(): (virtual) * */ VPStandardStateTP::~VPStandardStateTP() { for (int k = 0; k < (int) m_PDSS_storage.size(); k++) { delete(m_PDSS_storage[k]); } delete m_VPSS_ptr; } /* * Duplication function. * This calls the copy constructor for this object. */ ThermoPhase* VPStandardStateTP::duplMyselfAsThermoPhase() const { return new VPStandardStateTP(*this); } // This method returns the convention used in specification // of the standard state, of which there are currently two, // temperature based, and variable pressure based. /* * Currently, there are two standard state conventions: * - Temperature-based activities * cSS_CONVENTION_TEMPERATURE 0 * - default * * - Variable Pressure and Temperature -based activities * cSS_CONVENTION_VPSS 1 */ int VPStandardStateTP::standardStateConvention() const { return cSS_CONVENTION_VPSS; } /* * ------------Molar Thermodynamic Properties ------------------------- */ doublereal VPStandardStateTP::err(const std::string& msg) const { throw CanteraError("VPStandardStateTP","Base class method " +msg+" called. Equation of state type: "+int2str(eosType())); return 0; } /* * ---- Partial Molar Properties of the Solution ----------------- */ /* * Get the array of non-dimensional species chemical potentials * These are partial molar Gibbs free energies. * \f$ \mu_k / \hat R T \f$. * Units: unitless * * We close the loop on this function, here, calling * getChemPotentials() and then dividing by RT. */ void VPStandardStateTP::getChemPotentials_RT(doublereal* muRT) const { getChemPotentials(muRT); doublereal invRT = 1.0 / _RT(); for (size_t k = 0; k < m_kk; k++) { muRT[k] *= invRT; } } /* * ----- Thermodynamic Values for the Species Standard States States ---- */ void VPStandardStateTP::getStandardChemPotentials(doublereal* g) const { getGibbs_RT(g); doublereal RT = _RT(); for (size_t k = 0; k < m_kk; k++) { g[k] *= RT; } } inline void VPStandardStateTP::getEnthalpy_RT(doublereal* hrt) const { updateStandardStateThermo(); m_VPSS_ptr->getEnthalpy_RT(hrt); } //================================================================================================ #ifdef H298MODIFY_CAPABILITY // Modify the value of the 298 K Heat of Formation of one species in the phase (J kmol-1) /* * The 298K heat of formation is defined as the enthalpy change to create the standard state * of the species from its constituent elements in their standard states at 298 K and 1 bar. * * @param k Species k * @param Hf298New Specify the new value of the Heat of Formation at 298K and 1 bar */ void VPStandardStateTP::modifyOneHf298SS(const size_t& k, const doublereal Hf298New) { m_spthermo->modifyOneHf298(k, Hf298New); m_Tlast_ss += 0.0001234; } #endif //================================================================================================ void VPStandardStateTP::getEntropy_R(doublereal* srt) const { updateStandardStateThermo(); m_VPSS_ptr->getEntropy_R(srt); } inline void VPStandardStateTP::getGibbs_RT(doublereal* grt) const { updateStandardStateThermo(); m_VPSS_ptr->getGibbs_RT(grt); } inline void VPStandardStateTP::getPureGibbs(doublereal* g) const { updateStandardStateThermo(); m_VPSS_ptr->getStandardChemPotentials(g); } void VPStandardStateTP::getIntEnergy_RT(doublereal* urt) const { updateStandardStateThermo(); m_VPSS_ptr->getIntEnergy_RT(urt); } void VPStandardStateTP::getCp_R(doublereal* cpr) const { updateStandardStateThermo(); m_VPSS_ptr->getCp_R(cpr); } void VPStandardStateTP::getStandardVolumes(doublereal* vol) const { updateStandardStateThermo(); m_VPSS_ptr->getStandardVolumes(vol); } const vector_fp& VPStandardStateTP::getStandardVolumes() const { updateStandardStateThermo(); return m_VPSS_ptr->getStandardVolumes(); } /* * ----- Thermodynamic Values for the Species Reference States ---- */ /* * Returns the vector of nondimensional enthalpies of the * reference state at the current temperature of the solution and * the reference pressure for the species. */ void VPStandardStateTP::getEnthalpy_RT_ref(doublereal* hrt) const { updateStandardStateThermo(); m_VPSS_ptr->getEnthalpy_RT_ref(hrt); } /* * Returns the vector of nondimensional * enthalpies of the reference state at the current temperature * of the solution and the reference pressure for the species. */ void VPStandardStateTP::getGibbs_RT_ref(doublereal* grt) const { updateStandardStateThermo(); m_VPSS_ptr->getGibbs_RT_ref(grt); } /* * Returns the vector of the * gibbs function of the reference state at the current temperature * of the solution and the reference pressure for the species. * units = J/kmol * * This is filled in here so that derived classes don't have to * take care of it. */ void VPStandardStateTP::getGibbs_ref(doublereal* g) const { updateStandardStateThermo(); m_VPSS_ptr->getGibbs_ref(g); } const vector_fp& VPStandardStateTP::Gibbs_RT_ref() const { updateStandardStateThermo(); return m_VPSS_ptr->Gibbs_RT_ref(); } /* * Returns the vector of nondimensional * entropies of the reference state at the current temperature * of the solution and the reference pressure for the species. */ void VPStandardStateTP::getEntropy_R_ref(doublereal* er) const { updateStandardStateThermo(); m_VPSS_ptr->getEntropy_R_ref(er); } /* * Returns the vector of nondimensional * constant pressure heat capacities of the reference state * at the current temperature of the solution * and reference pressure for the species. */ void VPStandardStateTP::getCp_R_ref(doublereal* cpr) const { updateStandardStateThermo(); m_VPSS_ptr->getCp_R_ref(cpr); } /* * Get the molar volumes of the species reference states at the current * T and P_ref of the solution. * * units = m^3 / kmol */ void VPStandardStateTP::getStandardVolumes_ref(doublereal* vol) const { updateStandardStateThermo(); m_VPSS_ptr->getStandardVolumes_ref(vol); } /* * Perform initializations after all species have been * added. */ void VPStandardStateTP::initThermo() { initLengths(); ThermoPhase::initThermo(); m_VPSS_ptr->initThermo(); for (size_t k = 0; k < m_kk; k++) { PDSS* kPDSS = m_PDSS_storage[k]; if (kPDSS) { kPDSS->initThermo(); } } } void VPStandardStateTP::setVPSSMgr(VPSSMgr* vp_ptr) { m_VPSS_ptr = vp_ptr; } /* * Initialize the internal lengths. * (this is not a virtual function) */ void VPStandardStateTP::initLengths() { m_kk = nSpecies(); } void VPStandardStateTP::setTemperature(const doublereal temp) { setState_TP(temp, m_Pcurrent); updateStandardStateThermo(); } void VPStandardStateTP::setPressure(doublereal p) { setState_TP(temperature(), p); updateStandardStateThermo(); } void VPStandardStateTP::calcDensity() { err("VPStandardStateTP::calcDensity() called, but EOS for phase is not known"); } void VPStandardStateTP::setState_TP(doublereal t, doublereal pres) { /* * A pretty tricky algorithm is needed here, due to problems involving * standard states of real fluids. For those cases you need * to combine the T and P specification for the standard state, or else * you may venture into the forbidden zone, especially when nearing the * triple point. * Therefore, we need to do the standard state thermo calc with the * (t, pres) combo. */ Phase::setTemperature(t); m_Pcurrent = pres; updateStandardStateThermo(); /* * Now, we still need to do the calculations for general ThermoPhase objects. * So, we switch back to a virtual function call, setTemperature, and * setPressure to recalculate stuff for child ThermoPhase objects of * the VPStandardStateTP object. At this point, * we haven't touched m_tlast or m_plast, so some calculations may still * need to be done at the ThermoPhase object level. */ //setTemperature(t); //setPressure(pres); calcDensity(); } void VPStandardStateTP::createInstallPDSS(size_t k, const XML_Node& s, const XML_Node* phaseNode_ptr) { if (m_PDSS_storage.size() < k+1) { m_PDSS_storage.resize(k+1,0); } if (m_PDSS_storage[k] != 0) { delete m_PDSS_storage[k] ; } m_PDSS_storage[k] = m_VPSS_ptr->createInstallPDSS(k, s, phaseNode_ptr); } PDSS* VPStandardStateTP::providePDSS(size_t k) { return m_PDSS_storage[k]; } const PDSS* VPStandardStateTP::providePDSS(size_t k) const { return m_PDSS_storage[k]; } /* * Import and initialize a ThermoPhase object * * param phaseNode This object must be the phase node of a * complete XML tree * description of the phase, including all of the * species data. In other words while "phase" must * point to an XML phase object, it must have * sibling nodes "speciesData" that describe * the species in the phase. * param id ID of the phase. If nonnull, a check is done * to see if phaseNode is pointing to the phase * with the correct id. * * This routine initializes the lengths in the current object and * then calls the parent routine. */ void VPStandardStateTP::initThermoXML(XML_Node& phaseNode, const std::string& id) { VPStandardStateTP::initLengths(); //m_VPSS_ptr->initThermo(); for (size_t k = 0; k < m_kk; k++) { PDSS* kPDSS = m_PDSS_storage[k]; AssertTrace(kPDSS != 0); if (kPDSS) { kPDSS->initThermoXML(phaseNode, id); } } m_VPSS_ptr->initThermoXML(phaseNode, id); ThermoPhase::initThermoXML(phaseNode, id); } VPSSMgr* VPStandardStateTP::provideVPSSMgr() { return m_VPSS_ptr; } /* * void _updateStandardStateThermo() (protected, virtual, const) * * If m_useTmpStandardStateStorage is true, * This function must be called for every call to functions in this * class that need standard state properties. * Child classes may require that it be called even if m_useTmpStandardStateStorage * is not true. * It checks to see whether the temperature has changed and * thus the ss thermodynamics functions for all of the species * must be recalculated. * * This */ void VPStandardStateTP::_updateStandardStateThermo() const { double Tnow = temperature(); m_Plast_ss = m_Pcurrent; m_Tlast_ss = Tnow; AssertThrowMsg(m_VPSS_ptr != 0, "VPStandardStateTP::_updateStandardStateThermo()", "Probably indicates that ThermoPhase object wasn't initialized correctly"); m_VPSS_ptr->setState_TP(Tnow, m_Pcurrent); } void VPStandardStateTP::updateStandardStateThermo() const { double Tnow = temperature(); if (Tnow != m_Tlast_ss || m_Pcurrent != m_Plast_ss) { _updateStandardStateThermo(); } } }