Mu0Poly.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file Mu0Poly.cpp
00003  *  Definitions for a single-species standard state object derived
00004  *  from \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink  based 
00005  *  on a piecewise constant mu0 interpolation
00006  *  (see \ref spthermo and class \link Cantera::Mu0Poly Mu0Poly\endlink).
00007  */
00008 /*
00009  * $Author: hkmoffa $
00010  * $Revision: 385 $
00011  * $Date: 2010-01-17 12:05:46 -0500 (Sun, 17 Jan 2010) $
00012  */
00013 
00014 
00015 #include "Mu0Poly.h"
00016 #include "ctexceptions.h"
00017 #include "speciesThermoTypes.h"
00018 #include "SpeciesThermo.h"
00019 #include "xml.h"
00020 #include "ctml.h"
00021 
00022 using namespace std;
00023 using namespace ctml;
00024 
00025 namespace Cantera {
00026 
00027  
00028   Mu0Poly::Mu0Poly() : m_numIntervals(0),
00029                        m_H298(0.0),
00030                        m_lowT(0.0),
00031                        m_highT(0.0),
00032                        m_Pref(0.0),
00033                        m_index(0) {
00034   }
00035 
00036   /*
00037    * Mu0Poly():
00038    *
00039    * In the constructor, we calculate and store the
00040    * piecewise linear approximation to the thermodynamic
00041    * functions.
00042    *
00043    *  coeffs[0] = number of points (integer)
00044    *         1  = H298(J/kmol)
00045    *         2  = T1  (Kelvin)
00046    *         3  = mu1 (J/kmol) 
00047    *         4  = T2  (Kelvin)
00048    *         5  = mu2 (J/kmol) 
00049    *         6  = T3  (Kelvin)
00050    *         7  = mu3 (J/kmol)
00051    *         ........
00052    */
00053   Mu0Poly::Mu0Poly(int n, doublereal tlow, doublereal thigh, 
00054                    doublereal pref,
00055                    const doublereal* coeffs) :
00056     m_numIntervals(0),
00057     m_H298(0.0),
00058     m_lowT      (tlow),
00059     m_highT     (thigh),
00060     m_Pref      (pref),
00061     m_index     (n) {
00062 
00063     processCoeffs(coeffs);
00064   }
00065 
00066 
00067   Mu0Poly::Mu0Poly(const Mu0Poly &b)
00068     : m_numIntervals (b.m_numIntervals),
00069       m_H298         (b.m_H298),
00070       m_t0_int       (b.m_t0_int),
00071       m_mu0_R_int    (b.m_mu0_R_int),
00072       m_h0_R_int     (b.m_h0_R_int),
00073       m_s0_R_int     (b.m_s0_R_int),
00074       m_cp0_R_int    (b.m_cp0_R_int),
00075       m_lowT         (b.m_lowT),
00076       m_highT        (b.m_highT),
00077       m_Pref         (b.m_Pref),
00078       m_index        (b.m_index) {
00079   }
00080 
00081   Mu0Poly& Mu0Poly::operator=(const Mu0Poly& b) {
00082     if (&b != this) {
00083       m_numIntervals = b.m_numIntervals;
00084       m_H298         = b.m_H298;
00085       m_t0_int       = b.m_t0_int;
00086       m_mu0_R_int    = b.m_mu0_R_int;
00087       m_h0_R_int     = b.m_h0_R_int;
00088       m_s0_R_int     = b.m_s0_R_int;
00089       m_cp0_R_int    = b.m_cp0_R_int;
00090       m_lowT         = b.m_lowT;
00091       m_highT        = b.m_highT;
00092       m_Pref         = b.m_Pref;
00093       m_index        = b.m_index;
00094     }
00095     return *this;
00096   }
00097     
00098   /*
00099    * Destructor:
00100    */
00101   Mu0Poly::~Mu0Poly(){
00102   }
00103     
00104   SpeciesThermoInterpType *
00105   Mu0Poly::duplMyselfAsSpeciesThermoInterpType() const {
00106     Mu0Poly* mp = new Mu0Poly(*this);
00107     return (SpeciesThermoInterpType *) mp;
00108   }
00109         
00110   doublereal Mu0Poly::minTemp() const { return m_lowT;}
00111   doublereal  Mu0Poly::maxTemp() const { return m_highT;}
00112   doublereal Mu0Poly::refPressure() const { return m_Pref; }
00113     
00114   /*
00115    *  updateProperties is the main workhorse program. 
00116    *  Given a temperature (*tt), it calculates the thermodynamic
00117    *  functions H/RT, S_R, and cp_R, and returns the answer.
00118    *
00119    *  Note, it returns an answer by inserting the values into the
00120    *  index position, m_index in vectors of  H/RT, S_R, and cp_R.
00121    *
00122    *
00123    *   Input
00124    *  -------
00125    *       *tt = Temperature (Kelvin)
00126    *      
00127    */
00128   void  Mu0Poly::
00129   updateProperties(const doublereal* tt,  doublereal* cp_R,
00130                    doublereal* h_RT, doublereal* s_R) const {
00131     int j = m_numIntervals;
00132     double T = *tt;
00133     for (int i = 0; i < m_numIntervals; i++) {
00134       double T2 =  m_t0_int[i+1];
00135       if (T <=T2) {
00136         j = i;
00137         break;
00138       }
00139     }
00140     double T1 = m_t0_int[j];
00141     double cp_Rj = m_cp0_R_int[j];
00142 
00143     doublereal rt = 1.0/T;
00144     cp_R[m_index] = cp_Rj;
00145     h_RT[m_index] = rt*(m_h0_R_int[j] + (T - T1) * cp_Rj);
00146     s_R[m_index]  = m_s0_R_int[j] + cp_Rj * (log(T/T1));
00147   }
00148 
00149   void  Mu0Poly::
00150   updatePropertiesTemp(const doublereal T,
00151                        doublereal* cp_R,
00152                        doublereal* h_RT,
00153                        doublereal* s_R) const {
00154     updateProperties(&T, cp_R, h_RT, s_R);
00155   }
00156 
00157   /*
00158    * report all of the parameters that make up this 
00159    * interpolation.
00160    *
00161    * 
00162    */
00163   void Mu0Poly::reportParameters(int &n, int &type,
00164                                  doublereal &tlow, doublereal &thigh,
00165                                  doublereal &pref,
00166                                  doublereal* const coeffs) const {
00167     n = m_index;
00168     type = MU0_INTERP;
00169     tlow = m_lowT;
00170     thigh = m_highT;
00171     pref = m_Pref;
00172     coeffs[0] = m_numIntervals+1;
00173     coeffs[1] = m_H298 * GasConstant;
00174     int j = 2;
00175     for (int i = 0; i < m_numIntervals+1; i++) {
00176       coeffs[j] = m_t0_int[i];
00177       coeffs[j+1] = m_mu0_R_int[i] * GasConstant;
00178       j += 2;
00179     }
00180   }
00181 
00182   void Mu0Poly::modifyParameters(doublereal* coeffs) {
00183     processCoeffs(coeffs);
00184   }
00185 
00186   /*
00187    * Install a Mu0 polynomial thermodynamic reference state property
00188    * parameterization for species k into a SpeciesThermo instance,
00189    * getting the information from an XML database.
00190    */
00191   void installMu0ThermoFromXML(std::string speciesName,
00192                                SpeciesThermo& sp, int k, 
00193                                const XML_Node* Mu0Node_ptr) {
00194 
00195     doublereal tmin, tmax;
00196     bool dimensionlessMu0Values = false;
00197     const XML_Node& Mu0Node = *Mu0Node_ptr;
00198   
00199     tmin = fpValue(Mu0Node["Tmin"]);
00200     tmax = fpValue(Mu0Node["Tmax"]);
00201     doublereal pref = fpValue(Mu0Node["Pref"]);
00202 
00203     doublereal h298 = 0.0;
00204     if (Mu0Node.hasChild("H298")) {
00205       h298 = getFloat(Mu0Node, "H298", "actEnergy");
00206     }
00207 
00208     int numPoints = 1;
00209     if (Mu0Node.hasChild("numPoints")) {
00210       numPoints = getInteger(Mu0Node, "numPoints");
00211     }
00212 
00213     vector_fp cValues(numPoints);
00214     const XML_Node *valNode_ptr = 
00215       getByTitle(const_cast<XML_Node&>(Mu0Node), "Mu0Values");
00216     if (!valNode_ptr) {
00217       throw CanteraError("installMu0ThermoFromXML",
00218                          "missing required while processing "
00219                          + speciesName);
00220     }
00221     getFloatArray(*valNode_ptr, cValues, true, "actEnergy");
00222     /*
00223      * Check to see whether the Mu0's were input in a dimensionless
00224      * form. If they were, then the assumed temperature needs to be
00225      * adjusted from the assumed T = 273.15
00226      */
00227     string uuu = (*valNode_ptr)["units"];
00228     if (uuu == "Dimensionless") {
00229       dimensionlessMu0Values = true;
00230     }
00231     int ns = cValues.size();
00232     if (ns != numPoints) {
00233       throw CanteraError("installMu0ThermoFromXML",
00234                          "numPoints inconsistent while processing "
00235                          + speciesName);
00236     }
00237         
00238     vector_fp cTemperatures(numPoints);
00239     const XML_Node *tempNode_ptr = 
00240       getByTitle(const_cast<XML_Node&>(Mu0Node), "Mu0Temperatures");
00241     if (!tempNode_ptr) {
00242       throw CanteraError("installMu0ThermoFromXML",
00243                          "missing required while processing + "
00244                          + speciesName);
00245     }
00246     getFloatArray(*tempNode_ptr, cTemperatures, false);
00247     ns = cTemperatures.size();
00248     if (ns != numPoints) {
00249       throw CanteraError("installMu0ThermoFromXML",
00250                          "numPoints inconsistent while processing "
00251                          + speciesName);
00252     }
00253         
00254     /*
00255      * Fix up dimensionless Mu0 values if input
00256      */
00257     if (dimensionlessMu0Values) {
00258       for (int i = 0; i < numPoints; i++) {
00259         cValues[i] *= cTemperatures[i] / 273.15;
00260       }
00261     }
00262 
00263 
00264     vector_fp c(2 + 2 * numPoints);
00265      
00266     c[0] = numPoints;
00267     c[1] = h298;
00268     for (int i = 0; i < numPoints; i++) {
00269       c[2+i*2]   = cTemperatures[i];
00270       c[2+i*2+1] = cValues[i];
00271     }
00272       
00273     sp.install(speciesName, k, MU0_INTERP, &c[0], tmin, tmax, pref);
00274   }
00275 
00276   /*
00277    * Mu0Poly():
00278    *
00279    * In the constructor, we calculate and store the
00280    * piecewise linear approximation to the thermodynamic
00281    * functions.
00282    *
00283    *  coeffs[0] = number of points (integer)
00284    *         1  = H298(J/kmol)
00285    *         2  = T1  (Kelvin)
00286    *         3  = mu1 (J/kmol) 
00287    *         4  = T2  (Kelvin)
00288    *         5  = mu2 (J/kmol) 
00289    *         6  = T3  (Kelvin)
00290    *         7  = mu3 (J/kmol)
00291    *         ........
00292    */
00293   void Mu0Poly::processCoeffs(const doublereal* coeffs)  {
00294 
00295     int i, iindex;
00296     double T1, T2;
00297     int nPoints = (int) coeffs[0];
00298     if (nPoints < 2) {
00299       throw CanteraError("Mu0Poly", 
00300                          "nPoints must be >= 2");
00301     }
00302     m_numIntervals = nPoints - 1;
00303     m_H298       = coeffs[1] / GasConstant;
00304     int iT298 = 0;
00305     /*
00306      * Resize according to the number of points
00307      */
00308     m_t0_int.resize(nPoints);
00309     m_h0_R_int.resize(nPoints);
00310     m_s0_R_int.resize(nPoints);
00311     m_cp0_R_int.resize(nPoints);
00312     m_mu0_R_int.resize(nPoints);
00313     /*
00314      * Calculate the T298 interval and make sure that
00315      * the temperatures are strictly monotonic.
00316      * Also distribute the data into the internal arrays.
00317      */
00318     bool ifound = false;
00319     for (i = 0, iindex = 2; i < nPoints; i++) {
00320       T1 = coeffs[iindex];
00321       m_t0_int[i] = T1;
00322       m_mu0_R_int[i] =  coeffs[iindex+1] / GasConstant;
00323       if (T1 == 298.15) {
00324         iT298 = i;
00325         ifound = true;
00326       }
00327       if (i < nPoints - 1) {
00328         T2 = coeffs[iindex+2];
00329         if (T2 <= T1) {
00330           throw CanteraError("Mu0Poly", 
00331                              "Temperatures are not monotonic increasing");
00332         }
00333       }
00334       iindex += 2;
00335     }
00336     if (!ifound) {
00337       throw CanteraError("Mu0Poly",
00338                          "One temperature has to be 298.15");
00339     }
00340 
00341     /*
00342      * Starting from the interval with T298, we go up
00343      */
00344     doublereal mu2, s1, s2, h1, h2, cpi, deltaMu, deltaT;
00345     T1 = m_t0_int[iT298];
00346     doublereal mu1 = m_mu0_R_int[iT298];
00347     m_h0_R_int[iT298] = m_H298;
00348     m_s0_R_int[iT298] = - (mu1 - m_h0_R_int[iT298]) / T1;
00349     for (i = iT298; i < m_numIntervals; i++) {
00350       T1      = m_t0_int[i];
00351       s1      = m_s0_R_int[i];
00352       h1      = m_h0_R_int[i];
00353       mu1     = m_mu0_R_int[i];
00354       T2      = m_t0_int[i+1];
00355       mu2     = m_mu0_R_int[i+1];
00356       deltaMu = mu2 - mu1;
00357       deltaT  = T2 - T1;
00358       cpi = (deltaMu - T1 * s1 + T2 * s1) / (deltaT - T2 * log(T2/T1));
00359       h2 = h1 + cpi * deltaT;
00360       s2 = s1 + cpi * log(T2/T1);
00361       m_cp0_R_int[i]   = cpi;
00362       m_h0_R_int[i+1]  = h2;
00363       m_s0_R_int[i+1]  = s2;
00364       m_cp0_R_int[i+1] = cpi;
00365     }
00366 
00367     /*
00368      * Starting from the interval with T298, we go down
00369      */
00370     if (iT298 > 0) {
00371       T2 = m_t0_int[iT298];
00372       mu2 = m_mu0_R_int[iT298];
00373       m_h0_R_int[iT298] = m_H298;
00374       m_s0_R_int[iT298] = - (mu2 - m_h0_R_int[iT298]) / T2;
00375       for (i = iT298 - 1; i >= 0; i--) {
00376         T1      = m_t0_int[i];
00377         mu1     = m_mu0_R_int[i];
00378         T2      = m_t0_int[i+1];
00379         mu2     = m_mu0_R_int[i+1];
00380         s2      = m_s0_R_int[i+1];
00381         h2      = m_h0_R_int[i+1];
00382         deltaMu = mu2 - mu1;
00383         deltaT  = T2 - T1;
00384         cpi = (deltaMu - T1 * s2 + T2 * s2) / (deltaT - T1 * log(T2/T1)); 
00385         h1 = h2 - cpi * deltaT;
00386         s1 = s2 - cpi * log(T2/T1);
00387         m_cp0_R_int[i]   = cpi;
00388         m_h0_R_int[i]    = h1;
00389         m_s0_R_int[i]    = s1;
00390         if (i == (m_numIntervals-1)) {
00391           m_cp0_R_int[i+1] = cpi;
00392         }
00393       }
00394     }
00395 #ifdef DEBUG_HKM_NOT
00396     printf("    Temp     mu0(J/kmol)   cp0(J/kmol/K)   "
00397            " h0(J/kmol)   s0(J/kmol/K) \n");
00398     for (i = 0; i < nPoints; i++) {
00399       printf("%12.3g %12.5g %12.5g %12.5g %12.5g\n",
00400              m_t0_int[i],  m_mu0_R_int[i] * GasConstant,
00401              m_cp0_R_int[i]* GasConstant, 
00402              m_h0_R_int[i]* GasConstant,
00403              m_s0_R_int[i]* GasConstant);
00404       fflush(stdout);
00405     }
00406 #endif
00407   }
00408 
00409 }
00410 
00411 
00412 
00413 
00414 
Generated by  doxygen 1.6.3