WaterSSTP.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file WaterSSTP.cpp
00003  * Definitions for a %ThermoPhase class consisting of  pure water (see \ref thermoprops
00004  * and class \link Cantera::WaterSSTP WaterSSTP\endlink).
00005  */
00006 /*
00007  * Copywrite (2006) Sandia Corporation. Under the terms of
00008  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
00009  * U.S. Government retains certain rights in this software.
00010  */
00011 /*
00012  * $Id: WaterSSTP.cpp 384 2010-01-16 18:57:05Z hkmoffa $
00013  */
00014 
00015 #include "xml.h"
00016 #include "WaterSSTP.h"
00017 #include "WaterPropsIAPWS.h"
00018 //#include "importCTML.h"
00019 #include "WaterProps.h"
00020 #include "ThermoFactory.h"
00021 #include <cmath>
00022 
00023 using namespace std;
00024 
00025 namespace Cantera {
00026   /**
00027    * Basic list of constructors and duplicators
00028    */
00029 
00030   WaterSSTP::WaterSSTP() :
00031     SingleSpeciesTP(),
00032     m_sub(0),
00033     m_waterProps(0),
00034     m_mw(0.0),
00035     EW_Offset(0.0),
00036     SW_Offset(0.0),
00037     m_ready(false),
00038     m_allowGasPhase(false)
00039   {
00040     //constructPhase();
00041   }
00042 
00043 
00044   WaterSSTP::WaterSSTP(std::string inputFile, std::string id) :
00045     SingleSpeciesTP(),
00046     m_sub(0),
00047     m_waterProps(0),
00048     m_mw(0.0),
00049     EW_Offset(0.0),
00050     SW_Offset(0.0),
00051     m_ready(false),
00052     m_allowGasPhase(false)
00053   {
00054     constructPhaseFile(inputFile, id);
00055   }
00056 
00057 
00058   WaterSSTP::WaterSSTP(XML_Node& phaseRoot, std::string id) :
00059     SingleSpeciesTP(),
00060     m_sub(0),
00061     m_waterProps(0),
00062     m_mw(0.0),
00063     EW_Offset(0.0),
00064     SW_Offset(0.0),
00065     m_ready(false),
00066     m_allowGasPhase(false)
00067   {
00068     constructPhaseXML(phaseRoot, id) ;
00069   }
00070 
00071 
00072 
00073   WaterSSTP::WaterSSTP(const WaterSSTP &b) :
00074     SingleSpeciesTP(b),
00075     m_sub(0),
00076     m_waterProps(0),
00077     m_mw(b.m_mw),
00078     EW_Offset(b.EW_Offset),
00079     SW_Offset(b.SW_Offset),
00080     m_ready(false),
00081     m_allowGasPhase(b.m_allowGasPhase)
00082   {
00083     m_sub = new WaterPropsIAPWS(*(b.m_sub));
00084     m_waterProps =  new WaterProps(m_sub);
00085 
00086     /*
00087      * Use the assignment operator to do the brunt
00088      * of the work for the copy construtor.
00089      */
00090     *this = b;
00091   }
00092 
00093   /*
00094    * Assignment operator
00095    */
00096   WaterSSTP& WaterSSTP::operator=(const WaterSSTP&b) {
00097     if (&b == this) return *this;
00098     m_sub->operator=(*(b.m_sub));
00099 
00100     if (!m_waterProps) {
00101       m_waterProps = new WaterProps(m_sub);
00102     }
00103     m_waterProps->operator=(*(b.m_waterProps));
00104 
00105 
00106     m_mw = b.m_mw;
00107     m_ready = b.m_ready;
00108     m_allowGasPhase = b.m_allowGasPhase;
00109     return *this;
00110   }
00111 
00112 
00113   ThermoPhase *WaterSSTP::duplMyselfAsThermoPhase() const {
00114     WaterSSTP* wtp = new WaterSSTP(*this);
00115     return (ThermoPhase *) wtp;
00116   }
00117 
00118   WaterSSTP::~WaterSSTP() { 
00119     delete m_sub; 
00120     delete m_waterProps;
00121   }
00122 
00123 
00124   
00125    
00126   /*
00127    * @param infile XML file containing the description of the
00128    *        phase
00129    *
00130    * @param id  Optional parameter identifying the name of the
00131    *            phase. If none is given, the first XML
00132    *            phase element will be used.
00133    */
00134   void WaterSSTP::constructPhaseXML(XML_Node& phaseNode, std::string id) {
00135 
00136     /*
00137      * Call the Cantera importPhase() function. This will import
00138      * all of the species into the phase. This will also handle
00139      * all of the solvent and solute standard states.
00140      */
00141     bool m_ok = importPhase(phaseNode, this);
00142     if (!m_ok) {
00143       throw CanteraError("initThermo","importPhase failed ");
00144     }
00145         
00146   }
00147 
00148   /*
00149    * constructPhaseFile
00150    *
00151    *
00152    * This routine is a precursor to constructPhaseXML(XML_Node*)
00153    * routine, which does most of the work.
00154    *
00155    * @param inputFile XML file containing the description of the
00156    *        phase
00157    *
00158    * @param id  Optional parameter identifying the name of the
00159    *            phase. If none is given, the first XML
00160    *            phase element will be used.
00161    */
00162   void WaterSSTP::constructPhaseFile(std::string inputFile, std::string id) {
00163 
00164     if (inputFile.size() == 0) {
00165       throw CanteraError("WaterTp::initThermo",
00166                          "input file is null");
00167     }
00168     std::string path = findInputFile(inputFile);
00169     std::ifstream fin(path.c_str());
00170     if (!fin) {
00171       throw CanteraError("WaterSSTP::initThermo","could not open "
00172                          +path+" for reading.");
00173     }
00174     /*
00175      * The phase object automatically constructs an XML object.
00176      * Use this object to store information.
00177      */
00178     XML_Node &phaseNode_XML = xml();
00179     XML_Node *fxml = new XML_Node();
00180     fxml->build(fin);
00181     XML_Node *fxml_phase = findXMLPhase(fxml, id);
00182     if (!fxml_phase) {
00183       throw CanteraError("WaterSSTP::initThermo",
00184                          "ERROR: Can not find phase named " +
00185                          id + " in file named " + inputFile);
00186     }
00187     fxml_phase->copy(&phaseNode_XML);   
00188     constructPhaseXML(*fxml_phase, id);
00189     delete fxml;
00190   }
00191 
00192 
00193 
00194   void WaterSSTP::initThermo() {
00195     SingleSpeciesTP::initThermo();
00196   }
00197 
00198   void WaterSSTP::
00199   initThermoXML(XML_Node& phaseNode, std::string id) {
00200 
00201     /*
00202      * Do initializations that don't depend on knowing the XML file
00203      */
00204     initThermo();
00205     if (m_sub) delete m_sub;
00206     m_sub = new WaterPropsIAPWS();
00207     if (m_sub == 0) {
00208       throw CanteraError("WaterSSTP::initThermo",
00209                          "could not create new substance object.");
00210     }
00211     /*
00212      * Calculate the molecular weight. Note while there may
00213      * be a very good calculated weight in the steam table
00214      * class, using this weight may lead to codes exhibiting
00215      * mass loss issues. We need to grab the elemental
00216      * atomic weights used in the Element class and calculate
00217      * a consistent H2O molecular weight based on that.
00218      */
00219     int nH = elementIndex("H");
00220     if (nH < 0) {
00221       throw CanteraError("WaterSSTP::initThermo",
00222                          "H not an element");
00223     }
00224     double mw_H = atomicWeight(nH);
00225     int nO = elementIndex("O");
00226     if (nO < 0) {
00227       throw CanteraError("WaterSSTP::initThermo",
00228                          "O not an element");
00229     }
00230     double mw_O = atomicWeight(nO);
00231     m_mw = 2.0 * mw_H + mw_O;
00232     m_weight[0] = m_mw;
00233     setMolecularWeight(0,m_mw);
00234     double one = 1.0;
00235     setMoleFractions(&one);
00236 
00237     /*
00238      * Set the baseline 
00239      */
00240     doublereal T = 298.15;
00241     State::setDensity(7.0E-8);
00242     State::setTemperature(T);
00243 
00244     doublereal presLow = 1.0E-2;
00245     doublereal oneBar = 1.0E5;
00246     doublereal dd = m_sub->density(T, presLow, WATER_GAS, 7.0E-8);
00247     setDensity(dd);
00248     setTemperature(T);
00249     SW_Offset = 0.0;
00250     doublereal s = entropy_mole();
00251     s -=  GasConstant * log(oneBar/presLow);
00252     if (s != 188.835E3) {
00253       SW_Offset = 188.835E3 - s;
00254     }
00255     s = entropy_mole();
00256     s -=  GasConstant * log(oneBar/presLow);
00257     //printf("s = %g\n", s);
00258 
00259     doublereal h = enthalpy_mole();
00260     if (h != -241.826E6) {
00261       EW_Offset = -241.826E6 - h;
00262     }
00263     h = enthalpy_mole();
00264 
00265     //printf("h = %g\n", h);
00266 
00267 
00268     /*
00269      * Set the initial state of the system to 298.15 K and 
00270      * 1 bar.
00271      */
00272     setTemperature(298.15);
00273     double rho0 = m_sub->density(298.15, OneAtm, WATER_LIQUID);
00274     setDensity(rho0);
00275 
00276     m_waterProps =  new WaterProps(m_sub);
00277 
00278 
00279     /*
00280      * We have to do something with the thermo function here.
00281      */
00282     if (m_spthermo) {
00283       delete m_spthermo;
00284       m_spthermo = 0;
00285     }
00286 
00287     /*
00288      * Set the flag to say we are ready to calculate stuff
00289      */
00290     m_ready = true;
00291   }
00292 
00293   void WaterSSTP::
00294   setParametersFromXML(const XML_Node& eosdata) {
00295     eosdata._require("model","PureLiquidWater");
00296   }
00297 
00298   /*
00299    * Return the molar dimensionless enthalpy
00300    */
00301   void WaterSSTP::getEnthalpy_RT(doublereal* hrt) const {
00302     double T = temperature();
00303     doublereal h = m_sub->enthalpy();
00304     *hrt = (h + EW_Offset)/(GasConstant*T);
00305   }
00306 
00307   /*
00308    * Calculate the internal energy in mks units of
00309    * J kmol-1 
00310    */
00311   void WaterSSTP::getIntEnergy_RT(doublereal *ubar) const {
00312     doublereal u = m_sub->intEnergy();
00313     *ubar = (u + EW_Offset)/GasConstant;            
00314   }
00315 
00316   /*
00317    * Calculate the dimensionless entropy
00318    */
00319   void WaterSSTP::getEntropy_R(doublereal* sr) const {
00320     doublereal s = m_sub->entropy();
00321     sr[0] = (s + SW_Offset) / GasConstant;
00322   }
00323 
00324   /*
00325    * Calculate the Gibbs free energy in mks units of
00326    * J kmol-1 K-1.
00327    */
00328   void WaterSSTP::getGibbs_RT(doublereal *grt) const {
00329     double T = temperature();
00330     doublereal g = m_sub->Gibbs();
00331     *grt = (g + EW_Offset - SW_Offset*T) / (GasConstant * T);
00332     if (!m_ready) {
00333       throw CanteraError("waterSSTP::", "Phase not ready");
00334     }
00335   }
00336 
00337   /*
00338    * Calculate the Gibbs free energy in mks units of
00339    * J kmol-1 K-1.
00340    */
00341   void WaterSSTP::getStandardChemPotentials(doublereal *gss) const {
00342     double T = temperature();
00343     doublereal g = m_sub->Gibbs();
00344     *gss = (g + EW_Offset - SW_Offset*T);
00345     if (!m_ready) {
00346       throw CanteraError("waterSSTP::", "Phase not ready");
00347     }
00348   }
00349   
00350   void WaterSSTP::getCp_R(doublereal* cpr) const {
00351     doublereal cp = m_sub->cp();
00352     cpr[0] = cp / GasConstant;
00353   }
00354 
00355   /*
00356    * Calculate the constant volume heat capacity
00357    * in mks units of J kmol-1 K-1
00358    */
00359   doublereal WaterSSTP::cv_mole() const {
00360     doublereal cv = m_sub->cv();
00361     return cv;
00362   }
00363 
00364   // @name Thermodynamic Values for the Species Reference State
00365 
00366 
00367   void WaterSSTP::getEnthalpy_RT_ref(doublereal *hrt) const {
00368     doublereal p = pressure();
00369     double T = temperature();
00370     double dens = density();
00371     int waterState = WATER_GAS;
00372     double rc = m_sub->Rhocrit();
00373     if (dens > rc) {
00374       waterState = WATER_LIQUID;
00375     }
00376     doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
00377     if (dd <= 0.0) {
00378       throw CanteraError("setPressure", "error");
00379     }
00380     doublereal h = m_sub->enthalpy();
00381     *hrt = (h + EW_Offset) / (GasConstant * T);
00382     dd = m_sub->density(T, p, waterState, dens);
00383   }
00384 
00385   void WaterSSTP::getGibbs_RT_ref(doublereal *grt) const {
00386     doublereal p = pressure();
00387     double T = temperature();
00388     double dens = density();
00389     int waterState = WATER_GAS;
00390     double rc = m_sub->Rhocrit();
00391     if (dens > rc) {
00392       waterState = WATER_LIQUID;
00393     }
00394     doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
00395     if (dd <= 0.0) {
00396       throw CanteraError("setPressure", "error");
00397     }
00398     m_sub->setState_TR(T, dd);
00399     doublereal g = m_sub->Gibbs();
00400     *grt = (g + EW_Offset - SW_Offset*T)/ (GasConstant * T);
00401     dd = m_sub->density(T, p, waterState, dens);
00402  
00403   }
00404 
00405   void WaterSSTP::getGibbs_ref(doublereal *g) const {
00406     getGibbs_RT_ref(g);
00407     doublereal rt = _RT();
00408     for (int k = 0; k < m_kk; k++) {
00409       g[k] *= rt;
00410     }
00411   }
00412 
00413   void WaterSSTP::getEntropy_R_ref(doublereal *sr) const {
00414     doublereal p = pressure();
00415     double T = temperature();
00416     double dens = density();
00417     int waterState = WATER_GAS;
00418     double rc = m_sub->Rhocrit();
00419     if (dens > rc) {
00420       waterState = WATER_LIQUID;
00421     }
00422     doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
00423    
00424     if (dd <= 0.0) {
00425       throw CanteraError("setPressure", "error");
00426     }
00427     m_sub->setState_TR(T, dd);
00428 
00429     doublereal s = m_sub->entropy();
00430     *sr = (s + SW_Offset)/ (GasConstant);
00431     dd = m_sub->density(T, p, waterState, dens); 
00432  
00433   }
00434 
00435   void WaterSSTP::getCp_R_ref(doublereal *cpr) const {
00436     doublereal p = pressure();
00437     double T = temperature();
00438     double dens = density();
00439     int waterState = WATER_GAS;
00440     double rc = m_sub->Rhocrit();
00441     if (dens > rc) {
00442       waterState = WATER_LIQUID;
00443     }
00444     doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
00445     m_sub->setState_TR(T, dd);
00446     if (dd <= 0.0) {
00447       throw CanteraError("setPressure", "error");
00448     }
00449     doublereal cp = m_sub->cp();
00450     *cpr = cp / (GasConstant);
00451     dd = m_sub->density(T, p, waterState, dens); 
00452   }
00453 
00454   void WaterSSTP::getStandardVolumes_ref(doublereal *vol) const {
00455     doublereal p = pressure();
00456     double T = temperature();
00457     double dens = density();
00458     int waterState = WATER_GAS;
00459     double rc = m_sub->Rhocrit();
00460     if (dens > rc) {
00461       waterState = WATER_LIQUID;
00462     }
00463     doublereal dd = m_sub->density(T, OneAtm, waterState, dens);
00464     if (dd <= 0.0) {
00465       throw CanteraError("setPressure", "error");
00466     }
00467     *vol = meanMolecularWeight() /dd;
00468     dd = m_sub->density(T, p, waterState, dens); 
00469   }
00470 
00471   /*
00472    * Calculate the pressure (Pascals), given the temperature and density
00473    *  Temperature: kelvin
00474    *  rho: density in kg m-3
00475    */
00476   doublereal WaterSSTP::pressure() const {
00477     doublereal p = m_sub->pressure();
00478     return p;
00479   }
00480         
00481   void WaterSSTP::
00482   setPressure(doublereal p) {
00483     double T = temperature();
00484     double dens = density();
00485     int waterState = WATER_GAS;
00486     double rc = m_sub->Rhocrit();
00487     if (dens > rc) {
00488       waterState = WATER_LIQUID;
00489     }
00490     doublereal dd = m_sub->density(T, p, waterState, dens);
00491     if (dd <= 0.0) {
00492       throw CanteraError("setPressure", "error");
00493     }
00494     setDensity(dd);
00495   }
00496   
00497   // Returns  the isothermal compressibility. Units: 1/Pa.
00498   /*
00499    * The isothermal compressibility is defined as
00500    * \f[
00501    * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T
00502    * \f]
00503    *  or
00504    * \f[
00505    * \kappa_T = \frac{1}{\rho}\left(\frac{\partial \rho}{\partial P}\right)_T
00506    * \f]
00507    */
00508   doublereal WaterSSTP::isothermalCompressibility() const {
00509     doublereal val = m_sub->isothermalCompressibility();
00510     return val;
00511   }
00512 
00513   // Return the volumetric thermal expansion coefficient. Units: 1/K.
00514   /*
00515    * The thermal expansion coefficient is defined as
00516    * \f[
00517    * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P
00518    * \f]
00519    */
00520   doublereal WaterSSTP::thermalExpansionCoeff() const {
00521     doublereal val = m_sub->coeffThermExp();
00522     return val;
00523   }
00524 
00525   doublereal WaterSSTP::dthermalExpansionCoeffdT() const {
00526     doublereal pres = pressure();
00527     doublereal dens_save = density();
00528     double T = temperature();
00529     double tt = T - 0.04;
00530     doublereal dd = m_sub->density(tt, pres, WATER_LIQUID, dens_save);
00531     if (dd < 0.0) {
00532       throw CanteraError("WaterSSTP::dthermalExpansionCoeffdT", 
00533                          "Unable to solve for the density at T = " + fp2str(tt) + ", P = " + fp2str(pres));
00534     }
00535     doublereal vald = m_sub->coeffThermExp();
00536     m_sub->setState_TR(T, dens_save);
00537     doublereal val2 = m_sub->coeffThermExp();
00538     doublereal val = (val2 - vald) / 0.04;
00539     return val;
00540   }
00541 
00542 
00543   // critical temperature 
00544   doublereal WaterSSTP::critTemperature() const { return m_sub->Tcrit(); }
00545         
00546   // critical pressure
00547   doublereal WaterSSTP::critPressure() const { return m_sub->Pcrit(); }
00548         
00549   // critical density
00550   doublereal WaterSSTP::critDensity() const { return m_sub->Rhocrit(); }
00551         
00552 
00553   void WaterSSTP::setTemperature(const doublereal temp) {
00554     State::setTemperature(temp);
00555     doublereal dd = density();
00556     m_sub->setState_TR(temp, dd);
00557   }
00558 
00559   void WaterSSTP::setDensity(const doublereal dens) {
00560     State::setDensity(dens);
00561     doublereal temp = temperature();
00562     m_sub->setState_TR(temp, dens);
00563   }
00564 
00565   // saturation pressure
00566   doublereal WaterSSTP::satPressure(doublereal t) const {
00567     doublereal tsave = temperature();
00568     doublereal dsave = density();
00569     doublereal pp = m_sub->psat(t);
00570     m_sub->setState_TR(tsave, dsave);
00571     return pp;
00572   }
00573 
00574   // Return the fraction of vapor at the current conditions
00575   doublereal WaterSSTP::vaporFraction() const {
00576     if (temperature() >= m_sub->Tcrit()) {
00577       double dens = density();
00578       if (dens >= m_sub->Rhocrit()) {
00579         return 0.0;
00580       }
00581       return 1.0;
00582     }
00583     /*
00584      * If below tcrit we always return 0 from this class
00585      */
00586     return 0.0;
00587   }
00588 
00589 
00590 }
Generated by  doxygen 1.6.3