SurfPhase.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file SurfPhase.cpp 
00003  *  Definitions for a simple thermoydnamics model of a surface phase 
00004  *  derived from ThermoPhase,  assuming an ideal solution model
00005  *  (see \ref thermoprops and class 
00006  *  \link Cantera::SurfPhase SurfPhase\endlink).
00007  */
00008 
00009 /*
00010  * $Revision: 279 $
00011  * $Date: 2009-12-05 14:08:43 -0500 (Sat, 05 Dec 2009) $
00012  */
00013 
00014 // Copyright 2002  California Institute of Technology
00015 
00016 // turn off warnings under Windows
00017 #ifdef WIN32
00018 #pragma warning(disable:4786)
00019 #pragma warning(disable:4503)
00020 #endif
00021 
00022 #include "SurfPhase.h"
00023 #include "EdgePhase.h"
00024 #include "ThermoFactory.h"
00025 
00026 using namespace std;
00027 
00028     ///////////////////////////////////////////////////////////
00029     //
00030     //    class SurfPhase methods
00031     //
00032     ///////////////////////////////////////////////////////////
00033 
00034 namespace Cantera {
00035 
00036   SurfPhase::SurfPhase(doublereal n0):
00037     ThermoPhase(),
00038     m_n0(n0),
00039     m_logn0(0.0),
00040     m_tmin(0.0),
00041     m_tmax(0.0),
00042     m_press(OneAtm),
00043     m_tlast(0.0) 
00044   {
00045     if (n0 > 0.0) m_logn0 = log(n0);
00046     setNDim(2);
00047   }
00048 
00049   SurfPhase::SurfPhase(std::string infile, std::string id) :
00050     ThermoPhase(),
00051     m_n0(0.0),
00052     m_logn0(0.0),
00053     m_tmin(0.0),
00054     m_tmax(0.0),
00055     m_press(OneAtm),
00056     m_tlast(0.0) 
00057   {
00058     XML_Node* root = get_XML_File(infile);
00059     if (id == "-") id = "";
00060     XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id, root);
00061     if (!xphase) {
00062       throw CanteraError("SurfPhase::SurfPhase",
00063                          "Couldn't find phase name in file:" + id);
00064     }
00065     // Check the model name to ensure we have compatibility
00066     const XML_Node& th = xphase->child("thermo");
00067     string model = th["model"];
00068     if (model != "Surface" && model != "Edge") {
00069       throw CanteraError("SurfPhase::SurfPhase", 
00070                          "thermo model attribute must be Surface or Edge");
00071     }
00072     importPhase(*xphase, this);
00073   }
00074 
00075 
00076   SurfPhase::SurfPhase(XML_Node& xmlphase) :
00077     ThermoPhase(),
00078     m_n0(0.0),
00079     m_logn0(0.0),
00080     m_tmin(0.0),
00081     m_tmax(0.0),
00082     m_press(OneAtm),
00083     m_tlast(0.0) 
00084   {
00085     const XML_Node& th = xmlphase.child("thermo");
00086     string model = th["model"];
00087     if (model != "Surface" && model != "Edge") {
00088       throw CanteraError("SurfPhase::SurfPhase", 
00089                          "thermo model attribute must be Surface or Edge");
00090     }
00091     importPhase(xmlphase, this);
00092   }
00093 
00094   // Copy Constructor
00095   /*
00096    * Copy constructor for the object. Constructed
00097    * object will be a clone of this object, but will
00098    * also own all of its data.
00099    * This is a wrapper around the assignment operator
00100    *
00101    * @param right Object to be copied.
00102    */
00103   SurfPhase::SurfPhase(const SurfPhase &right) :
00104     m_n0(right.m_n0),
00105     m_logn0(right.m_logn0),
00106     m_tmin(right.m_tmin),
00107     m_tmax(right.m_tmax),
00108     m_press(right.m_press),
00109     m_tlast(right.m_tlast)
00110   {
00111     *this = operator=(right);
00112   }
00113 
00114   // Asignment operator
00115   /*
00116    * Assignment operator for the object. Constructed
00117    * object will be a clone of this object, but will
00118    * also own all of its data.
00119    *
00120    * @param right Object to be copied.
00121    */
00122   SurfPhase& SurfPhase::
00123   operator=(const SurfPhase &right) {
00124     if (&right != this) {
00125       ThermoPhase::operator=(right);
00126       m_n0         = right.m_n0;
00127       m_logn0      = right.m_logn0;
00128       m_tmin       = right.m_tmin;
00129       m_tmax       = right.m_tmax;
00130       m_press      = right.m_press;
00131       m_tlast      = right.m_tlast;
00132       m_h0         = right.m_h0;
00133       m_s0         = right.m_s0;
00134       m_cp0        = right.m_cp0;
00135       m_mu0        = right.m_mu0;
00136       m_work       = right.m_work;
00137       m_pe         = right.m_pe;
00138       m_logsize    = right.m_logsize;
00139     }
00140     return *this;
00141   }
00142 
00143   // Duplicator from the %ThermoPhase parent class
00144   /*
00145    * Given a pointer to a %ThermoPhase object, this function will
00146    * duplicate the %ThermoPhase object and all underlying structures.
00147    * This is basically a wrapper around the copy constructor.
00148    *
00149    * @return returns a pointer to a %ThermoPhase
00150    */
00151   ThermoPhase *SurfPhase::duplMyselfAsThermoPhase() const {
00152     SurfPhase *igp = new SurfPhase(*this);
00153     return (ThermoPhase *) igp;
00154   }
00155 
00156   doublereal SurfPhase::
00157   enthalpy_mole() const {
00158     if (m_n0 <= 0.0) return 0.0; 
00159     _updateThermo();
00160     return mean_X(DATA_PTR(m_h0));
00161   }
00162 
00163   SurfPhase::~SurfPhase() { 
00164   }
00165 
00166   /*
00167    * For a surface phase, the pressure is not a relevant
00168    * thermodynamic variable, and so the Enthalpy is equal to the
00169    * internal energy.
00170    */
00171   doublereal SurfPhase::
00172   intEnergy_mole() const { return enthalpy_mole(); }
00173 
00174   /*
00175    * Get the array of partial molar enthalpies of the species
00176    * units = J / kmol
00177    */
00178   void SurfPhase::getPartialMolarEnthalpies(doublereal* hbar) const {
00179     getEnthalpy_RT(hbar);
00180     doublereal rt = GasConstant * temperature();
00181     for (int k = 0; k < m_kk; k++) {
00182       hbar[k] *= rt;
00183     }
00184   }
00185 
00186   // Returns an array of partial molar entropies of the species in the
00187   // solution. Units: J/kmol/K.
00188   /*
00189    * @param sbar    Output vector of species partial molar entropies.
00190    *                Length = m_kk. units are J/kmol/K.
00191    */
00192   void SurfPhase::getPartialMolarEntropies(doublereal* sbar) const {
00193     getEntropy_R(sbar);
00194     for (int k = 0; k < m_kk; k++) {
00195       sbar[k] *= GasConstant;
00196     }
00197   }
00198 
00199   // Returns an array of partial molar heat capacities of the species in the
00200   // solution. Units: J/kmol/K.
00201   /*
00202    * @param sbar    Output vector of species partial molar entropies.
00203    *                Length = m_kk. units are J/kmol/K.
00204    */
00205   void SurfPhase::getPartialMolarCp(doublereal* cpbar) const {
00206     getCp_R(cpbar);
00207     for (int k = 0; k < m_kk; k++) {
00208       cpbar[k] *= GasConstant;
00209     }
00210   }
00211 
00212   void SurfPhase::getPartialMolarVolumes(doublereal* vbar) const {
00213     getStandardVolumes(vbar);
00214   }
00215 
00216   void SurfPhase::getStandardChemPotentials(doublereal* mu0) const {
00217     _updateThermo();
00218     copy(m_mu0.begin(), m_mu0.end(), mu0);
00219   }
00220 
00221   void SurfPhase::getChemPotentials(doublereal* mu) const {
00222     _updateThermo();
00223     copy(m_mu0.begin(), m_mu0.end(), mu);
00224     int k;
00225     getActivityConcentrations(DATA_PTR(m_work));
00226     for (k = 0; k < m_kk; k++) {
00227       mu[k] += GasConstant * temperature() * 
00228         (log(m_work[k]) - logStandardConc(k));
00229     } 
00230   }
00231 
00232   void SurfPhase::getActivityConcentrations(doublereal* c) const { 
00233     getConcentrations(c); 
00234   }
00235 
00236   doublereal SurfPhase::standardConcentration(int k) const {
00237     return m_n0/size(k); 
00238   }
00239 
00240   doublereal SurfPhase::logStandardConc(int k) const {
00241     return m_logn0 - m_logsize[k];
00242   }
00243 
00244   /// The only parameter that can be set is the site density.
00245   void SurfPhase::setParameters(int n, doublereal* const c) {
00246     if (n != 1) {
00247       throw CanteraError("SurfPhase::setParameters",
00248                          "Bad value for number of parameter");
00249     }
00250     m_n0 = c[0];
00251     if (m_n0 <= 0.0) {
00252       throw CanteraError("SurfPhase::setParameters",
00253                          "Bad value for parameter");
00254     }
00255     m_logn0 = log(m_n0);
00256   }
00257 
00258   void SurfPhase::getGibbs_RT(doublereal* grt) const {
00259     _updateThermo();
00260     double rrt = 1.0/(GasConstant*temperature());
00261     scale(m_mu0.begin(), m_mu0.end(), grt, rrt);
00262   }
00263 
00264   void SurfPhase::
00265   getEnthalpy_RT(doublereal* hrt) const {
00266     _updateThermo();
00267     double rrt = 1.0/(GasConstant*temperature());
00268     scale(m_h0.begin(), m_h0.end(), hrt, rrt);
00269   }
00270 
00271   void SurfPhase::getEntropy_R(doublereal* sr) const {
00272     _updateThermo();
00273     double rr = 1.0/GasConstant;
00274     scale(m_s0.begin(), m_s0.end(), sr, rr);
00275   }
00276 
00277   void SurfPhase::getCp_R(doublereal* cpr) const {
00278     _updateThermo();
00279     double rr = 1.0/GasConstant;
00280     scale(m_cp0.begin(), m_cp0.end(), cpr, rr);
00281   }
00282 
00283   void SurfPhase::getStandardVolumes(doublereal* vol) const {
00284     _updateThermo();
00285     for (int k = 0; k < m_kk; k++) {
00286       vol[k] = 1.0/standardConcentration(k);
00287     }
00288   }
00289 
00290   void SurfPhase::getGibbs_RT_ref(doublereal* grt) const {
00291     getGibbs_RT(grt);
00292   }
00293 
00294   void SurfPhase::getEnthalpy_RT_ref(doublereal* hrt) const {
00295     getEnthalpy_RT(hrt);
00296   }
00297 
00298   void SurfPhase::getEntropy_R_ref(doublereal* sr) const {
00299     getEntropy_R(sr);
00300   }
00301 
00302   void SurfPhase::getCp_R_ref(doublereal* cprt) const {
00303     getCp_R(cprt);
00304   }
00305 
00306   void SurfPhase::initThermo() {
00307     if (m_kk <= 0) {
00308       throw CanteraError("SurfPhase::initThermo",
00309                          "Number of species is less than or equal to zero");
00310     }
00311     m_h0.resize(m_kk);
00312     m_s0.resize(m_kk);
00313     m_cp0.resize(m_kk);
00314     m_mu0.resize(m_kk);
00315     m_work.resize(m_kk);
00316     m_pe.resize(m_kk, 0.0);
00317     vector_fp cov(m_kk, 0.0);
00318     cov[0] = 1.0;
00319     setCoverages(DATA_PTR(cov));
00320     m_logsize.resize(m_kk);
00321     for (int k = 0; k < m_kk; k++) 
00322       m_logsize[k] = log(size(k));
00323   }
00324 
00325   void SurfPhase::setPotentialEnergy(int k, doublereal pe) {
00326     m_pe[k] = pe;
00327     _updateThermo(true);
00328   }
00329 
00330   void SurfPhase::setSiteDensity(doublereal n0) {
00331     doublereal x = n0;
00332     setParameters(1, &x);
00333   }
00334 
00335   //void SurfPhase::
00336   //setElectricPotential(doublereal V) {
00337   //    for (int k = 0; k < m_kk; k++) {
00338   //        m_pe[k] = charge(k)*Faraday*V;
00339   //    }
00340   //    _updateThermo(true);
00341   //}
00342 
00343 
00344   /**
00345    * Set the coverage fractions to a specified 
00346    * state. This routine converts to concentrations
00347    * in kmol/m2, using m_n0, the surface site density,
00348    * and size(k), which is defined to be the number of
00349    * surface sites occupied by the kth molecule.
00350    * It then calls State::setConcentrations to set the
00351    * internal concentration in the object.
00352    */
00353   void SurfPhase::
00354   setCoverages(const doublereal* theta) {
00355     double sum = 0.0;
00356     int k;
00357     for (k = 0; k < m_kk; k++) {
00358       sum += theta[k];
00359     }
00360     if (sum <= 0.0) {
00361       for (k = 0; k < m_kk; k++) {
00362         cout << "theta(" << k << ") = " << theta[k] << endl;
00363       }
00364       throw CanteraError("SurfPhase::setCoverages",
00365                          "Sum of Coverage fractions is zero or negative");
00366     }
00367     for (k = 0; k < m_kk; k++) {
00368       m_work[k] = m_n0*theta[k]/(sum*size(k));
00369     }
00370     /*
00371      * Call the State:: class function
00372      * setConcentrations.
00373      */
00374     setConcentrations(DATA_PTR(m_work));
00375   }
00376 
00377   void SurfPhase::
00378   setCoveragesNoNorm(const doublereal* theta) {
00379     for (int k = 0; k < m_kk; k++) {
00380       m_work[k] = m_n0*theta[k]/(size(k));
00381     }
00382     /*
00383      * Call the State:: class function
00384      * setConcentrations.
00385      */
00386     setConcentrations(DATA_PTR(m_work));
00387   }
00388 
00389   void SurfPhase::
00390   getCoverages(doublereal* theta) const {
00391     getConcentrations(theta);
00392     for (int k = 0; k < m_kk; k++) {
00393       theta[k] *= size(k)/m_n0; 
00394     }
00395   }
00396 
00397   void SurfPhase::
00398   setCoveragesByName(std::string cov) {
00399     int kk = nSpecies();
00400     int k;
00401     compositionMap cc;
00402     for (k = 0; k < kk; k++) { 
00403       cc[speciesName(k)] = -1.0;
00404     }
00405     parseCompString(cov, cc);
00406     doublereal c;
00407     vector_fp cv(kk, 0.0);
00408     bool ifound = false;
00409     for (k = 0; k < kk; k++) { 
00410       c = cc[speciesName(k)];
00411       if (c > 0.0) {
00412         ifound = true;
00413         cv[k] = c;
00414       }
00415     }
00416     if (!ifound) {
00417       throw CanteraError("SurfPhase::setCoveragesByName",
00418                          "Input coverages are all zero or negative");
00419     }
00420     setCoverages(DATA_PTR(cv));
00421   }
00422 
00423 
00424   void SurfPhase::
00425   _updateThermo(bool force) const {
00426     doublereal tnow = temperature();
00427     if (m_tlast != tnow || force) {
00428       m_spthermo->update(tnow, DATA_PTR(m_cp0), DATA_PTR(m_h0), 
00429                          DATA_PTR(m_s0));
00430       m_tlast = tnow;
00431       doublereal rt = GasConstant * tnow;
00432       int k;
00433       for (k = 0; k < m_kk; k++) {
00434         m_h0[k] *= rt;
00435         m_s0[k] *= GasConstant;
00436         m_cp0[k] *= GasConstant;
00437         m_mu0[k] = m_h0[k] - tnow*m_s0[k];
00438       }
00439       m_tlast = tnow;
00440     }
00441   }
00442 
00443   void SurfPhase::
00444   setParametersFromXML(const XML_Node& eosdata) {
00445     eosdata._require("model","Surface");
00446     doublereal n = getFloat(eosdata, "site_density", "toSI");
00447     if (n <= 0.0) 
00448       throw CanteraError("SurfPhase::setParametersFromXML",
00449                          "missing or negative site density");
00450     m_n0 = n;
00451     m_logn0 = log(m_n0);
00452   }
00453 
00454 
00455   void SurfPhase::setStateFromXML(const XML_Node& state) {
00456 
00457     double t;
00458     if (getOptionalFloat(state, "temperature", t, "temperature")) {
00459       setTemperature(t);
00460     }
00461 
00462     if (state.hasChild("coverages")) {
00463       string comp = getChildValue(state,"coverages");
00464       setCoveragesByName(comp);
00465     }
00466   }
00467 
00468   // Default constructor
00469   EdgePhase::EdgePhase(doublereal n0) : SurfPhase(n0) {
00470     setNDim(1);
00471   }
00472 
00473   // Copy Constructor
00474   /*
00475    * @param right Object to be copied
00476    */
00477   EdgePhase::EdgePhase(const EdgePhase & right) :
00478     SurfPhase(right.m_n0)
00479   {
00480     setNDim(1);
00481     *this = operator=(right);
00482   }
00483 
00484   // Assignment Operator
00485   /*
00486    * @param right Object to be copied
00487    */
00488   EdgePhase& EdgePhase::operator=(const EdgePhase & right) {
00489     if (&right != this) {
00490       SurfPhase::operator=(right);
00491       setNDim(1);
00492     }
00493     return *this;
00494   }
00495 
00496   // Duplicator from the %ThermoPhase parent class
00497   /*
00498    * Given a pointer to a %ThermoPhase object, this function will
00499    * duplicate the %ThermoPhase object and all underlying structures.
00500    * This is basically a wrapper around the copy constructor.
00501    *
00502    * @return returns a pointer to a %ThermoPhase
00503    */
00504   ThermoPhase *EdgePhase::duplMyselfAsThermoPhase() const {
00505     EdgePhase *igp = new EdgePhase(*this);
00506     return (ThermoPhase *) igp;
00507   }
00508 
00509   void EdgePhase::
00510   setParametersFromXML(const XML_Node& eosdata) {
00511     eosdata._require("model","Edge");
00512     doublereal n = getFloat(eosdata, "site_density", "toSI");
00513     if (n <= 0.0) 
00514       throw CanteraError("EdgePhase::setParametersFromXML",
00515                          "missing or negative site density");
00516     m_n0 = n;
00517     m_logn0 = log(m_n0);
00518   }
00519 
00520 
00521 }
Generated by  doxygen 1.6.3