IdealSolnGasVPSS.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file IdealSolnGasVPSS.cpp
00003  * Definition file for a derived class of ThermoPhase that assumes either
00004  * an ideal gas or ideal solution approximation and handles
00005  * variable pressure standard state methods for calculating
00006  * thermodynamic properties (see \ref thermoprops and
00007  * class \link Cantera::IdealSolnGasVPSS IdealSolnGasVPSS\endlink).
00008  */
00009 /*
00010  * Copywrite (2005) Sandia Corporation. Under the terms of 
00011  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
00012  * U.S. Government retains certain rights in this software.
00013  */
00014 /*
00015  *  $Author: hkmoffa $
00016  *  $Date: 2009-12-05 14:08:43 -0500 (Sat, 05 Dec 2009) $
00017  *  $Revision: 279 $
00018  */
00019 
00020 // turn off warnings under Windows
00021 #ifdef WIN32
00022 #pragma warning(disable:4786)
00023 #pragma warning(disable:4503)
00024 #endif
00025 
00026 #include "IdealSolnGasVPSS.h"
00027 #include "VPSSMgr.h"
00028 #include "PDSS.h"
00029 #include "mix_defs.h"
00030 #include "ThermoFactory.h"
00031 
00032 using namespace std;
00033 
00034 namespace Cantera {
00035 
00036   /*
00037    * Default constructor
00038    */
00039   IdealSolnGasVPSS::IdealSolnGasVPSS() :
00040     VPStandardStateTP(),
00041     m_idealGas(0),
00042     m_formGC(0)
00043   {
00044   }
00045 
00046 
00047   IdealSolnGasVPSS::IdealSolnGasVPSS(std::string infile, std::string id) :
00048     VPStandardStateTP(),
00049     m_idealGas(0),
00050     m_formGC(0)
00051   {
00052     XML_Node* root = get_XML_File(infile);
00053     if (id == "-") id = "";
00054     XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id, root);
00055     if (!xphase) {
00056       throw CanteraError("newPhase",
00057                          "Couldn't find phase named \"" + id + "\" in file, " + infile);
00058     }
00059     importPhase(*xphase, this);
00060   }
00061 
00062   /*
00063    * Copy Constructor:
00064    *
00065    *  Note this stuff will not work until the underlying phase
00066    *  has a working copy constructor.
00067    *
00068    *  The copy constructor just calls the assignment operator
00069    *  to do the heavy lifting.
00070    */
00071   IdealSolnGasVPSS::IdealSolnGasVPSS(const IdealSolnGasVPSS &b) :
00072     VPStandardStateTP(),
00073     m_idealGas(0),
00074     m_formGC(0)
00075   {
00076     *this = b;
00077   }
00078 
00079   /*
00080    * operator=()
00081    *
00082    *  Note this stuff will not work until the underlying phase
00083    *  has a working assignment operator
00084    */
00085   IdealSolnGasVPSS& IdealSolnGasVPSS::
00086   operator=(const IdealSolnGasVPSS &b) {
00087     if (&b != this) {
00088       /*
00089        * Mostly, this is a passthrough to the underlying
00090        * assignment operator for the ThermoPhae parent object.
00091        */
00092       VPStandardStateTP::operator=(b);
00093       /*
00094        * However, we have to handle data that we own.
00095        */
00096       m_idealGas = b.m_idealGas;
00097       m_formGC   = b.m_formGC;
00098     }
00099     return *this;
00100   }
00101 
00102   /*
00103    * ~IdealSolnGasVPSS():   (virtual)
00104    *
00105    */
00106   IdealSolnGasVPSS::~IdealSolnGasVPSS() {
00107   }
00108 
00109   /*
00110    * Duplication function.
00111    *  This calls the copy constructor for this object.
00112    */
00113   ThermoPhase* IdealSolnGasVPSS::duplMyselfAsThermoPhase() const {
00114     IdealSolnGasVPSS* vptp = new IdealSolnGasVPSS(*this);
00115     return (ThermoPhase *) vptp;
00116   }
00117  
00118   int IdealSolnGasVPSS::eosType() const {
00119     if (m_idealGas) {
00120       return cIdealSolnGasVPSS;
00121     }
00122     return cIdealSolnGasVPSS_iscv;
00123   }
00124   
00125 
00126   /*
00127    * ------------Molar Thermodynamic Properties -------------------------
00128    */
00129 
00130   /// Molar enthalpy. Units: J/kmol. 
00131   doublereal IdealSolnGasVPSS::enthalpy_mole() const {
00132     updateStandardStateThermo();
00133     const vector_fp &enth_RT = m_VPSS_ptr->enthalpy_RT();
00134     return (GasConstant * temperature() *
00135             mean_X(DATA_PTR(enth_RT)));
00136   }
00137 
00138   /// Molar internal energy. Units: J/kmol. 
00139   doublereal IdealSolnGasVPSS::intEnergy_mole() const {
00140     doublereal p0 = pressure();
00141     doublereal md = molarDensity();
00142     return (enthalpy_mole() - p0 / md); 
00143   }
00144 
00145   /// Molar entropy. Units: J/kmol/K. 
00146   doublereal IdealSolnGasVPSS::entropy_mole() const {
00147     updateStandardStateThermo();
00148     const vector_fp &entrop_R = m_VPSS_ptr->entropy_R();
00149     return GasConstant * (mean_X(DATA_PTR(entrop_R)) - sum_xlogx());
00150 
00151   }
00152 
00153   /// Molar Gibbs function. Units: J/kmol. 
00154   doublereal IdealSolnGasVPSS::gibbs_mole() const {
00155     return enthalpy_mole() - temperature() * entropy_mole();
00156   }
00157 
00158   /// Molar heat capacity at constant pressure. Units: J/kmol/K. 
00159   doublereal IdealSolnGasVPSS::cp_mole() const {
00160     updateStandardStateThermo();
00161     const vector_fp &cp_R = m_VPSS_ptr->cp_R();
00162     return  GasConstant * (mean_X(DATA_PTR(cp_R)));
00163   }
00164 
00165   /// Molar heat capacity at constant volume. Units: J/kmol/K. 
00166   doublereal IdealSolnGasVPSS::cv_mole() const {
00167     return cp_mole() - GasConstant;
00168 
00169   }
00170 
00171   void IdealSolnGasVPSS::setPressure(doublereal p) {
00172     m_Pcurrent = p;
00173     updateStandardStateThermo();
00174     calcDensity();
00175   }
00176   
00177   void IdealSolnGasVPSS::calcDensity() {
00178     /*
00179      * Calculate the molarVolume of the solution (m**3 kmol-1)
00180      */
00181     if (m_idealGas) {
00182       double dens =  (m_Pcurrent * meanMolecularWeight()
00183                       /(GasConstant * temperature()));
00184       State::setDensity(dens);
00185     } else {
00186       const doublereal * const dtmp = moleFractdivMMW();
00187       const vector_fp& vss = m_VPSS_ptr->standardVolumes();
00188       double invDens = dot(vss.begin(), vss.end(), dtmp);
00189       /*
00190        * Set the density in the parent State object directly,
00191        * by calling the State::setDensity() function.
00192        */
00193       double dens = 1.0/invDens;
00194       State::setDensity(dens);
00195     }
00196   }
00197 
00198   doublereal IdealSolnGasVPSS::isothermalCompressibility() const {
00199     if (m_idealGas) {
00200       return -1.0 / m_Pcurrent;
00201     } else {
00202       throw CanteraError("IdealSolnGasVPSS::isothermalCompressibility() ",
00203                          "not implemented");
00204     }
00205     return 0.0;
00206   }
00207 
00208   void IdealSolnGasVPSS::getActivityConcentrations(doublereal* c) const {
00209     if (m_idealGas) {
00210       getConcentrations(c);
00211     } else {
00212       int k;
00213       const vector_fp& vss = m_VPSS_ptr->standardVolumes();
00214       switch (m_formGC) {
00215       case 0:
00216         for (k = 0; k < m_kk; k++) {
00217           c[k] = moleFraction(k);
00218         }
00219         break;
00220       case 1:
00221         for (k = 0; k < m_kk; k++) {
00222           c[k] = moleFraction(k) / vss[k];
00223         }
00224         break;
00225       case 2:
00226         for (k = 0; k < m_kk; k++) {
00227           c[k] = moleFraction(k) / vss[0];
00228         }
00229         break;
00230       }
00231     }
00232   }
00233 
00234   /*
00235    * Returns the standard concentration \f$ C^0_k \f$, which is used to normalize
00236    * the generalized concentration.
00237    */
00238   doublereal IdealSolnGasVPSS::standardConcentration(int k) const {
00239     if (m_idealGas) {
00240       double p = pressure();
00241       return p/(GasConstant * temperature());
00242     } else {
00243       const vector_fp& vss = m_VPSS_ptr->standardVolumes();
00244       switch (m_formGC) {
00245       case 0:
00246         return 1.0;
00247       case 1:
00248         return 1.0 / vss[k];
00249       case 2:
00250         return 1.0/ vss[0];
00251       }
00252       return 0.0;
00253       
00254     }
00255   }
00256 
00257   /*
00258    * Returns the natural logarithm of the standard
00259    * concentration of the kth species
00260    */
00261   doublereal IdealSolnGasVPSS::logStandardConc(int k) const {
00262     double c = standardConcentration(k);
00263     double lc = std::log(c);
00264     return lc;
00265   }
00266 
00267   /*
00268    *
00269    * getUnitsStandardConcentration()
00270    *
00271    * Returns the units of the standard and general concentrations
00272    * Note they have the same units, as their divisor is
00273    * defined to be equal to the activity of the kth species
00274    * in the solution, which is unitless.
00275    *
00276    * This routine is used in print out applications where the
00277    * units are needed. Usually, MKS units are assumed throughout
00278    * the program and in the XML input files.
00279    *
00280    *  uA[0] = kmol units - default  = 1
00281    *  uA[1] = m    units - default  = -nDim(), the number of spatial
00282    *                                dimensions in the Phase class.
00283    *  uA[2] = kg   units - default  = 0;
00284    *  uA[3] = Pa(pressure) units - default = 0;
00285    *  uA[4] = Temperature units - default = 0;
00286    *  uA[5] = time units - default = 0
00287    *
00288    *  For EOS types other than cIdealSolidSolnPhase1, the default
00289    *  kmol/m3 holds for standard concentration units. For
00290    *  cIdealSolidSolnPhase0 type, the standard concentrtion is
00291    *  unitless.
00292    */
00293   void IdealSolnGasVPSS::getUnitsStandardConc(double *uA, int, int sizeUA) const {
00294     int eos = eosType();
00295     if (eos == cIdealSolnGasPhase0) {
00296       for (int i = 0; i < sizeUA; i++) {
00297         uA[i] = 0.0;
00298       }
00299     } else {
00300       for (int i = 0; i < sizeUA; i++) {
00301         if (i == 0) uA[0] = 1.0;
00302         if (i == 1) uA[1] = -nDim();
00303         if (i == 2) uA[2] = 0.0;
00304         if (i == 3) uA[3] = 0.0;
00305         if (i == 4) uA[4] = 0.0;
00306         if (i == 5) uA[5] = 0.0;
00307       }
00308     }
00309   }
00310 
00311 
00312   /*
00313    * Get the array of non-dimensional activity coefficients
00314    */
00315   void IdealSolnGasVPSS::getActivityCoefficients(doublereal *ac) const {
00316     for (int k = 0; k < m_kk; k++) {
00317       ac[k] = 1.0;
00318     }
00319   }
00320  
00321   /*
00322    * ---- Partial Molar Properties of the Solution -----------------
00323    */
00324 
00325   /*
00326    * Get the array of non-dimensional species chemical potentials
00327    * These are partial molar Gibbs free energies.
00328    * \f$ \mu_k / \hat R T \f$.
00329    * Units: unitless
00330    *
00331    * We close the loop on this function, here, calling
00332    * getChemPotentials() and then dividing by RT.
00333    */
00334   void IdealSolnGasVPSS::getChemPotentials_RT(doublereal* muRT) const{
00335     getChemPotentials(muRT);
00336     doublereal invRT = 1.0 / _RT();
00337     for (int k = 0; k < m_kk; k++) {
00338       muRT[k] *= invRT;
00339     }
00340   }
00341 
00342   void IdealSolnGasVPSS::getChemPotentials(doublereal* mu) const {
00343     getStandardChemPotentials(mu);
00344     doublereal xx;
00345     doublereal rt = temperature() * GasConstant;
00346     for (int k = 0; k < m_kk; k++) {
00347       xx = fmaxx(SmallNumber, moleFraction(k));
00348       mu[k] += rt*(log(xx));
00349     }
00350   }
00351  
00352 
00353   void IdealSolnGasVPSS::getPartialMolarEnthalpies(doublereal* hbar) const {
00354     getEnthalpy_RT(hbar);
00355     doublereal rt = GasConstant * temperature();
00356     scale(hbar, hbar+m_kk, hbar, rt);
00357   }
00358 
00359   void IdealSolnGasVPSS::getPartialMolarEntropies(doublereal* sbar) const {
00360     getEntropy_R(sbar);
00361     doublereal r = GasConstant;
00362     scale(sbar, sbar+m_kk, sbar, r);
00363     for (int k = 0; k < m_kk; k++) {
00364       doublereal xx = fmaxx(SmallNumber, moleFraction(k));
00365       sbar[k] += r * ( - log(xx));
00366     }
00367   }
00368 
00369   void IdealSolnGasVPSS::getPartialMolarIntEnergies(doublereal* ubar) const {
00370     getIntEnergy_RT(ubar);
00371     doublereal rt = GasConstant * temperature();
00372     scale(ubar, ubar+m_kk, ubar, rt);
00373   }
00374 
00375   void IdealSolnGasVPSS::getPartialMolarCp(doublereal* cpbar) const {
00376     getCp_R(cpbar);
00377     doublereal r = GasConstant;
00378     scale(cpbar, cpbar+m_kk, cpbar, r);
00379   }
00380 
00381   void IdealSolnGasVPSS::getPartialMolarVolumes(doublereal* vbar) const {
00382     getStandardVolumes(vbar);
00383   }
00384 
00385   /*
00386    * ----- Thermodynamic Values for the Species Reference States ----
00387    */
00388 
00389 
00390 
00391 
00392   /*
00393    * Perform initializations after all species have been
00394    * added.
00395    */
00396   void IdealSolnGasVPSS::initThermo() {
00397     initLengths();
00398     VPStandardStateTP::initThermo();
00399   }
00400   
00401 
00402  void IdealSolnGasVPSS::setToEquilState(const doublereal* mu_RT)
00403   {
00404     double tmp, tmp2;
00405     updateStandardStateThermo();
00406     const array_fp& grt = m_VPSS_ptr->Gibbs_RT_ref();
00407 
00408     /*
00409      * Within the method, we protect against inf results if the
00410      * exponent is too high.
00411      *
00412      * If it is too low, we set
00413      * the partial pressure to zero. This capability is needed
00414      * by the elemental potential method.
00415      */
00416     doublereal pres = 0.0;
00417     double m_p0 = m_VPSS_ptr->refPressure();
00418     for (int k = 0; k < m_kk; k++) {
00419       tmp = -grt[k] + mu_RT[k];
00420       if (tmp < -600.) {
00421         m_pp[k] = 0.0;
00422       } else if (tmp > 500.0) {
00423         tmp2 = tmp / 500.;
00424         tmp2 *= tmp2;
00425         m_pp[k] = m_p0 * exp(500.) * tmp2;
00426       } else {
00427         m_pp[k] = m_p0 * exp(tmp);
00428       }
00429       pres += m_pp[k];
00430     }
00431     // set state
00432     setState_PX(pres, &m_pp[0]);
00433   }
00434 
00435   /*
00436    * Initialize the internal lengths.
00437    *       (this is not a virtual function)
00438    */
00439   void IdealSolnGasVPSS::initLengths() {
00440     m_kk = nSpecies();
00441     m_pp.resize(m_kk, 0.0);
00442   }
00443 
00444   /*
00445    *   Import and initialize a ThermoPhase object
00446    *
00447    * param phaseNode This object must be the phase node of a
00448    *             complete XML tree
00449    *             description of the phase, including all of the
00450    *             species data. In other words while "phase" must
00451    *             point to an XML phase object, it must have
00452    *             sibling nodes "speciesData" that describe
00453    *             the species in the phase.
00454    * param id   ID of the phase. If nonnull, a check is done
00455    *             to see if phaseNode is pointing to the phase
00456    *             with the correct id.
00457    *
00458    * This routine initializes the lengths in the current object and
00459    * then calls the parent routine.
00460    */
00461   void IdealSolnGasVPSS::initThermoXML(XML_Node& phaseNode, std::string id) {
00462     IdealSolnGasVPSS::initLengths();
00463 
00464     if (phaseNode.hasChild("thermo")) {
00465       XML_Node& thermoNode = phaseNode.child("thermo");
00466       std::string model = thermoNode["model"];
00467       if (model == "IdealGasVPSS") {
00468         m_idealGas = 1;
00469       } else if (model == "IdealSolnVPSS") {
00470         m_idealGas = 0;
00471       } else {
00472         throw CanteraError("IdealSolnGasVPSS::initThermoXML",
00473                            "Unknown thermo model : " + model);
00474       }
00475     }
00476 
00477     /*
00478      * Form of the standard concentrations. Must have one of:
00479      *
00480      *     <standardConc model="unity" />
00481      *     <standardConc model="molar_volume" />
00482      *     <standardConc model="solvent_volume" />
00483      */
00484     if (phaseNode.hasChild("standardConc")) {
00485       if (m_idealGas) {
00486         throw CanteraError("IdealSolnGasVPSS::initThermoXML",
00487                            "standardConc node for ideal gas");
00488       }
00489       XML_Node& scNode = phaseNode.child("standardConc");
00490       string formStringa = scNode.attrib("model");
00491       string formString = lowercase(formStringa);
00492       if (formString == "unity") {
00493         m_formGC = 0;
00494       } else if (formString == "molar_volume") {
00495         m_formGC = 1;
00496       } else if (formString == "solvent_volume") {
00497         m_formGC = 2;
00498       } else {
00499         throw CanteraError("initThermoXML",
00500                            "Unknown standardConc model: " + formStringa);
00501       }
00502     } else {
00503       if (!m_idealGas) {
00504         throw CanteraError("initThermoXML",
00505                            "Unspecified standardConc model");
00506       }
00507     }
00508 
00509     VPStandardStateTP::initThermoXML(phaseNode, id);
00510   }
00511 
00512   void IdealSolnGasVPSS::setParametersFromXML(const XML_Node& thermoNode) {
00513     VPStandardStateTP::setParametersFromXML(thermoNode);
00514     std::string model = thermoNode["model"];
00515     if (model == "IdealGasVPSS") {
00516       m_idealGas = 1;
00517     } else if (model == "IdealSolnVPSS") {
00518       m_idealGas = 0;
00519     } else {
00520       throw CanteraError("IdealSolnGasVPSS::initThermoXML",
00521                          "Unknown thermo model : " + model);
00522     }
00523   }
00524     
00525 }
00526 
00527 
Generated by  doxygen 1.6.3