NasaThermo.h

Go to the documentation of this file.
00001 /**
00002  * @file NasaThermo.h
00003  *   Header for the 2 regime 7 coefficient Nasa thermodynamic
00004  *   polynomials for multiple species in a phase, derived from the
00005  *   \link Cantera::SpeciesThermo SpeciesThermo\endlink base class (see \ref mgrsrefcalc and
00006  *   \link Cantera::NasaThermo NasaThermo\endlink).
00007  */
00008 
00009 /*
00010  * $Revision: 306 $
00011  * $Date: 2009-12-09 12:29:23 -0500 (Wed, 09 Dec 2009) $
00012  */
00013 
00014 // Copyright 2003 California Institute of Technology
00015 
00016 #ifndef CT_NASATHERMO_H
00017 #define CT_NASATHERMO_H
00018 #include <string>
00019 
00020 #include "SpeciesThermoMgr.h"
00021 #include "NasaPoly1.h"
00022 #include "speciesThermoTypes.h"
00023 //#include "polyfit.h"
00024 #include "global.h"
00025 
00026 namespace Cantera {
00027 
00028   /**
00029    * A species thermodynamic property manager for the NASA
00030    * polynomial parameterization with two temperature ranges.
00031    *
00032    * This class is designed to efficiently evaluate the properties
00033    * of a large number of species with the NASA parameterization.
00034    *
00035    * The original NASA polynomial parameterization expressed the
00036    * heat capacity as a fourth-order polynomial in temperature, with
00037    * separate coefficients for each of two temperature ranges. (The
00038    * newer NASA format adds coefficients for 1/T and 1/T^2, and
00039    * allows multiple temperature ranges.) This class is designed for
00040    * use with the original parameterization, which is used, for
00041    * example, by the Chemkin software package.
00042    * 
00043    * In many cases, the midpoint temperature is the same for many
00044    * species.  To take advantage of this, class NasaThermo groups
00045    * species with a common midpoint temperature, so that checking
00046    * which range the desired temperature is in need be done only
00047    * once for each group.
00048    *
00049    * @note There is a special CTML element for entering the 
00050    * coefficients of this parameterization.
00051    * @see importCTML
00052    *
00053    * @ingroup mgrsrefcalc
00054    */
00055   class NasaThermo : public SpeciesThermo {
00056     
00057   public:
00058 
00059     //! Initialized to the type of parameterization
00060     /*!
00061      * Note, this value is used in some template functions
00062      */
00063     const int ID;
00064 
00065     //! constructor
00066     NasaThermo() :
00067       ID(NASA),  
00068       m_tlow_max(0.0), 
00069       m_thigh_min(1.e30),
00070       m_p0(-1.0),
00071       m_ngroups(0)
00072     {
00073       m_t.resize(6);
00074     }
00075 
00076     //! Copy constructor
00077     /*!
00078      *  @param right NasaThermo object to be copied.
00079      */
00080     NasaThermo(const NasaThermo &right) :
00081       ID(NASA),  
00082       m_tlow_max(0.0), 
00083       m_thigh_min(1.e30),
00084       m_p0(-1.0),
00085       m_ngroups(0)
00086     {
00087       *this = operator=(right);
00088     }
00089 
00090     //! Assignment operator
00091     /*!
00092      *  @param right NasaThermo object to be copied.
00093      */
00094     NasaThermo& operator=(const NasaThermo &right) {
00095       /*
00096        * Check for self assignment.
00097        */
00098       if (this == &right) return *this;
00099 
00100       m_high           = right.m_high;
00101       m_low            = right.m_low;
00102       m_index          = right.m_index;
00103       m_tmid           = right.m_tmid;
00104       m_tlow_max       = right.m_tlow_max;
00105       m_thigh_min      = right.m_thigh_min;
00106       m_tlow           = right.m_tlow;
00107       m_thigh          = right.m_thigh;
00108       m_p0             = right.m_p0;
00109       m_ngroups        = right.m_ngroups;
00110       m_t              = right.m_t;
00111       m_group_map      = right.m_group_map;
00112       m_posInGroup_map = right.m_posInGroup_map;
00113       m_name           = right.m_name;
00114 
00115       return *this;
00116     }
00117 
00118 
00119     //! destructor
00120     virtual ~NasaThermo() {}
00121 
00122     //! Duplication routine for objects which inherit from 
00123     //! %SpeciesThermo
00124     /*!
00125      *  This virtual routine can be used to duplicate %SpeciesThermo  objects
00126      *  inherited from %SpeciesThermo even if the application only has
00127      *  a pointer to %SpeciesThermo to work with.
00128      *  ->commented out because we first need to add copy constructors
00129      *   and assignment operators to all of the derived classes.
00130      */
00131     virtual SpeciesThermo *duplMyselfAsSpeciesThermo() const {
00132       NasaThermo *nt = new NasaThermo(*this);
00133       return (SpeciesThermo *) nt;
00134     }
00135 
00136     //! install a new species thermodynamic property
00137     //!  parameterization for one species.  
00138     /*!
00139      *
00140      * @param name      Name of the species
00141      * @param index     The 'update' method will update the property 
00142      *                  values for this species 
00143      *                  at position i index in the property arrays.  
00144      * @param type      int flag specifying the type of parameterization to be
00145      *                 installed. 
00146      * @param c        vector of coefficients for the parameterization. 
00147      * - c[0]          midpoint temperature
00148      * - c[1] - c[7]   coefficients for low T range
00149      * - c[8] - c[14]  coefficients for high T range
00150      * @param minTemp  minimum temperature for which this parameterization
00151      *                 is valid.
00152      * @param maxTemp  maximum temperature for which this parameterization
00153      *                 is valid.
00154      * @param refPressure standard-state pressure for this 
00155      *                    parameterization. 
00156      * @see speciesThermoTypes.h 
00157      */
00158     virtual void install(string name, int index, int type, 
00159                          const doublereal* c, 
00160                          doublereal minTemp, doublereal maxTemp,
00161                          doublereal refPressure) { 
00162 
00163       m_name[index] = name;
00164       int imid = int(c[0]);       // midpoint temp converted to integer
00165       int igrp = m_index[imid];   // has this value been seen before?
00166       if (igrp == 0) {            // if not, prepare new group
00167         vector<NasaPoly1> v;
00168         m_high.push_back(v);
00169         m_low.push_back(v);
00170         m_tmid.push_back(c[0]);
00171         m_index[imid] = igrp = static_cast<int>(m_high.size());
00172         m_ngroups++;
00173       }
00174 
00175       m_group_map[index] = igrp;
00176       m_posInGroup_map[index] = (int) m_low[igrp-1].size();
00177             
00178       doublereal tlow  = minTemp;
00179       doublereal tmid  = c[0];
00180       doublereal thigh = maxTemp;
00181       const doublereal* clow = c + 1;
00182 
00183       vector_fp chigh(7);
00184       copy(c + 8, c + 15, chigh.begin());
00185 
00186       m_high[igrp-1].push_back(NasaPoly1(index, tmid, thigh, 
00187                                          refPressure, &chigh[0]));
00188       m_low[igrp-1].push_back(NasaPoly1(index, tlow, tmid, 
00189                                         refPressure, clow));
00190 
00191       vector_fp clu(7), chu(7);
00192       clu[5] = clow[0];
00193       clu[6] = clow[1];
00194       copy(clow+2, clow+7, clu.begin());
00195       chu[5] = chigh[0];
00196       chu[6] = chigh[1];
00197       copy(chigh.begin()+2, chigh.begin()+7, chu.begin());
00198 
00199       checkContinuity(name, tmid, &clu[0], &chu[0]);
00200 
00201       if (tlow > m_tlow_max)    m_tlow_max = tlow;
00202       if (thigh < m_thigh_min)  m_thigh_min = thigh;
00203       if ((int) m_tlow.size() < index + 1) {
00204         m_tlow.resize(index + 1,  tlow);
00205         m_thigh.resize(index + 1, thigh);
00206       }
00207       m_tlow[index] = tlow;
00208       m_thigh[index] = thigh;
00209       if (m_p0 < 0.0) {
00210         m_p0 = refPressure;
00211       } else if (fabs(m_p0 - refPressure) > 0.1) {
00212         string logmsg =  " WARNING NasaThermo: New Species, " + name +  ", has a different reference pressure, "
00213           + fp2str(refPressure) + ", than existing reference pressure, "        + fp2str(m_p0) + "\n";
00214         writelog(logmsg);
00215         logmsg = "                  This may become a fatal error in the future \n";
00216         writelog(logmsg);
00217       }
00218       m_p0 = refPressure;
00219     }
00220 
00221     //! Install a new species thermodynamic property
00222     //! parameterization for one species.
00223     /*!
00224      * @param stit_ptr Pointer to the SpeciesThermoInterpType object
00225      *          This will set up the thermo for one species
00226      */
00227     virtual void install_STIT(SpeciesThermoInterpType *stit_ptr) {
00228       throw CanteraError("install_STIT", "not implemented");
00229     }
00230  
00231 
00232     //! Like update(), but only updates the single species k.
00233     /*!
00234      * @param k       species index
00235      * @param t       Temperature (Kelvin)
00236      * @param cp_R    Vector of Dimensionless heat capacities.
00237      *                (length m_kk).
00238      * @param h_RT    Vector of Dimensionless enthalpies.
00239      *                (length m_kk).
00240      * @param s_R     Vector of Dimensionless entropies.
00241      *                (length m_kk).
00242      *
00243      */
00244     virtual void update_one(int k, doublereal t, doublereal* cp_R, 
00245                             doublereal* h_RT, doublereal* s_R) const {
00246 
00247       m_t[0] = t;
00248       m_t[1] = t*t;
00249       m_t[2] = m_t[1]*t;
00250       m_t[3] = m_t[2]*t;
00251       m_t[4] = 1.0/t;
00252       m_t[5] = log(t);
00253  
00254       int grp = m_group_map[k];
00255       int pos = m_posInGroup_map[k];
00256       const vector<NasaPoly1> &mlg = m_low[grp-1];
00257       const NasaPoly1 *nlow = &(mlg[pos]);
00258 
00259       doublereal tmid = nlow->maxTemp();
00260       if (t < tmid) {
00261         nlow->updateProperties(&m_t[0], cp_R, h_RT, s_R);
00262       } else {
00263         const vector<NasaPoly1> &mhg = m_high[grp-1];
00264         const NasaPoly1 *nhigh = &(mhg[pos]);
00265         nhigh->updateProperties(&m_t[0], cp_R, h_RT, s_R);
00266       }
00267     }
00268 
00269     //! Compute the reference-state properties for all species.
00270     /*!
00271      * Given temperature T in K, this method updates the values of
00272      * the non-dimensional heat capacity at constant pressure,
00273      * enthalpy, and entropy, at the reference pressure, Pref
00274      * of each of the standard states.
00275      *
00276      * @param t       Temperature (Kelvin)
00277      * @param cp_R    Vector of Dimensionless heat capacities.
00278      *                (length m_kk).
00279      * @param h_RT    Vector of Dimensionless enthalpies.
00280      *                (length m_kk).
00281      * @param s_R     Vector of Dimensionless entropies.
00282      *                (length m_kk).
00283      */
00284     virtual void update(doublereal t, doublereal* cp_R, 
00285                         doublereal* h_RT, doublereal* s_R) const {
00286       int i;
00287 
00288       // load functions of temperature into m_t vector
00289       m_t[0] = t;
00290       m_t[1] = t*t;
00291       m_t[2] = m_t[1]*t;
00292       m_t[3] = m_t[2]*t;
00293       m_t[4] = 1.0/t;
00294       m_t[5] = log(t);
00295 
00296       // iterate over the groups
00297       vector<NasaPoly1>::const_iterator _begin, _end;
00298       for (i = 0; i != m_ngroups; i++) {
00299         if (t > m_tmid[i]) {
00300           _begin  = m_high[i].begin();
00301           _end    = m_high[i].end();
00302         }
00303         else {
00304           _begin  = m_low[i].begin();
00305           _end    = m_low[i].end();
00306         }
00307         for (; _begin != _end; ++_begin) 
00308           _begin->updateProperties(&m_t[0], cp_R, h_RT, s_R);
00309       }
00310     }
00311                 
00312     //! Minimum temperature.
00313     /*!
00314      * If no argument is supplied, this
00315      * method returns the minimum temperature for which \e all
00316      * parameterizations are valid. If an integer index k is
00317      * supplied, then the value returned is the minimum
00318      * temperature for species k in the phase.
00319      *
00320      * @param k    Species index
00321      */ 
00322     virtual doublereal minTemp(int k=-1) const {
00323       if (k < 0)
00324         return m_tlow_max;
00325       else
00326         return m_tlow[k];
00327     }
00328 
00329     //! Maximum temperature.
00330     /*!
00331      * If no argument is supplied, this
00332      * method returns the maximum temperature for which \e all
00333      * parameterizations are valid. If an integer index k is
00334      * supplied, then the value returned is the maximum
00335      * temperature for parameterization k.
00336      *
00337      * @param k Species index
00338      */
00339     virtual doublereal maxTemp(int k=-1) const {
00340       if (k < 0)
00341         return m_thigh_min;
00342       else
00343         return m_thigh[k];
00344     }
00345    
00346     //! The reference-state pressure for species k.
00347     /*!
00348      *
00349      * returns the reference state pressure in Pascals for
00350      * species k. If k is left out of the argument list,
00351      * it returns the reference state pressure for the first
00352      * species.
00353      * Note that some SpeciesThermo implementations, such
00354      * as those for ideal gases, require that all species
00355      * in the same phase have the same reference state pressures.
00356      *
00357      * @param k Species index
00358      */
00359     virtual doublereal refPressure(int k = -1) const {
00360       return m_p0;
00361     }
00362 
00363     //! This utility function reports the type of parameterization
00364     //! used for the species with index number index.
00365     /*!
00366      *
00367      * @param index  Species index
00368      */
00369     virtual int reportType(int index) const { return NASA; }
00370 
00371     /*!
00372      * This utility function reports back the type of 
00373      * parameterization and all of the parameters for the 
00374      * species, index.
00375      *
00376      * @param index     Species index
00377      * @param type      Integer type of the standard type
00378      * @param c         Vector of coefficients used to set the
00379      *                  parameters for the standard state.
00380      * For the NASA object, there are 15 coefficients.
00381      * @param minTemp   output - Minimum temperature
00382      * @param maxTemp   output - Maximum temperature
00383      * @param refPressure output - reference pressure (Pa).
00384      */
00385     virtual void reportParams(int index, int &type, 
00386                               doublereal * const c, 
00387                               doublereal &minTemp, 
00388                               doublereal &maxTemp, 
00389                               doublereal &refPressure) const {
00390       type = reportType(index);
00391       if (type == NASA) {
00392         int grp = m_group_map[index];
00393         int pos = m_posInGroup_map[index];
00394         const vector<NasaPoly1> &mlg = m_low[grp-1];
00395         const vector<NasaPoly1> &mhg = m_high[grp-1];
00396         const NasaPoly1 *lowPoly  = &(mlg[pos]);
00397         const NasaPoly1 *highPoly = &(mhg[pos]);
00398         int itype = NASA;
00399         doublereal tmid = lowPoly->maxTemp();
00400         c[0] = tmid;
00401         int n;
00402         double ttemp;
00403         lowPoly->reportParameters(n, itype, minTemp, ttemp, refPressure,
00404                                   c + 1);
00405         if (n != index) {
00406           throw CanteraError("  ", "confused");
00407         }
00408         if (itype != NASA1) {
00409           throw CanteraError("  ", "confused");
00410         }
00411         highPoly->reportParameters(n, itype, ttemp, maxTemp, refPressure,
00412                                    c + 8);
00413         if (n != index) {
00414           throw CanteraError("  ", "confused");
00415         }
00416         if (itype != NASA1) {
00417           throw CanteraError("  ", "confused");
00418         }
00419       } else {
00420         throw CanteraError(" ", "confused");
00421       }
00422     }
00423 
00424     //! Modify parameters for the standard state
00425     /*!  
00426      * This utility function modifies the array of coefficients.
00427      * The array is the same as that returned by reportParams, so
00428      * a call can first be made to reportParams to populate the
00429      * array, and then modifyParams can be called to alter
00430      * selected values.  For the NASA object, there are 15
00431      * coefficients.
00432 
00433      * @param index Species index
00434      * @param c     Vector of coefficients used to set the
00435      *              parameters for the standard state.
00436      */
00437     virtual void modifyParams(int index, doublereal *c) {
00438       int type = reportType(index);
00439       if (type == NASA) {
00440         int grp = m_group_map[index];
00441         int pos = m_posInGroup_map[index];
00442         vector<NasaPoly1> &mlg = m_low[grp-1];
00443         vector<NasaPoly1> &mhg = m_high[grp-1];
00444         NasaPoly1 *lowPoly  = &(mlg[pos]);
00445         NasaPoly1 *highPoly = &(mhg[pos]);
00446         doublereal tmid = lowPoly->maxTemp();
00447         if (c[0] != tmid) {
00448           throw CanteraError(" ", "Tmid cannot be changed");
00449         }
00450         lowPoly->modifyParameters(c + 1);
00451         highPoly->modifyParameters(c + 8);
00452         checkContinuity(m_name[index], c[0], c + 1, c + 8);
00453       } else {
00454         throw CanteraError(" ", "confused");
00455       }
00456     }
00457 
00458 #ifdef H298MODIFY_CAPABILITY 
00459     virtual doublereal reportOneHf298(const int k) const {
00460 
00461       int grp = m_group_map[k];
00462       int pos = m_posInGroup_map[k];
00463       const vector<NasaPoly1> &mlg = m_low[grp-1];
00464       const NasaPoly1 *nlow = &(mlg[pos]);
00465       doublereal tmid = nlow->maxTemp();
00466       double h;
00467       if (298.15 <= tmid) {
00468         h = nlow->reportHf298(0);
00469       } else {
00470         const vector<NasaPoly1> &mhg = m_high[grp-1];
00471         const NasaPoly1 *nhigh = &(mhg[pos]);
00472         h = nhigh->reportHf298(0);
00473       }
00474       return h;
00475     }
00476  
00477     virtual void modifyOneHf298(const int k, const doublereal Hf298New) {
00478       int grp = m_group_map[k];
00479       int pos = m_posInGroup_map[k];
00480       vector<NasaPoly1> &mlg = m_low[grp-1];
00481       NasaPoly1 *nlow = &(mlg[pos]);
00482       vector<NasaPoly1> &mhg = m_high[grp-1];
00483       NasaPoly1 *nhigh = &(mhg[pos]);
00484       doublereal tmid = nlow->maxTemp();
00485 
00486       double hnow = reportOneHf298(k);
00487       double delH =  Hf298New - hnow;
00488       if (298.15 <= tmid) {
00489         nlow->modifyOneHf298(k, Hf298New);
00490         double h = nhigh->reportHf298(0);
00491         double hnew = h + delH;
00492         nhigh->modifyOneHf298(k, hnew);
00493       } else {
00494         nhigh->modifyOneHf298(k, Hf298New);
00495         double h = nlow->reportHf298(0);
00496         double hnew = h + delH;
00497         nlow->modifyOneHf298(k, hnew);
00498       }
00499  
00500     }
00501 #endif
00502 
00503   protected:
00504     //! Vector of vector of NasaPoly1's for the high temp region.
00505     /*!
00506      * This is the high temp region representation.
00507      * The first Length is equal to the number of groups.
00508      * The second vector is equal to the number of species
00509      * in that particular group.
00510      */
00511     vector<vector<NasaPoly1> >         m_high;
00512  
00513     //! Vector of vector of NasaPoly1's for the low temp region.
00514     /*!
00515      * This is the low temp region representation.
00516      * The first Length is equal to the number of groups.
00517      * The second vector is equal to the number of species
00518      * in that particular group.
00519      */
00520     vector<vector<NasaPoly1> >         m_low;
00521 
00522     //! Map between the midpoint temperature, as an int, to the group number
00523     /*!
00524      * Length is equal to the number of groups. Only used in the setup.
00525      */
00526     map<int, int>                      m_index;
00527 
00528     //! Vector of log temperature limits
00529     /*!
00530      * Length is equal to the number of groups.
00531      */
00532     vector_fp                          m_tmid;
00533 
00534     //! Maximum value of the low temperature limit 
00535     doublereal                         m_tlow_max;
00536 
00537     //! Minimum value of the high temperature limit
00538     doublereal                         m_thigh_min;
00539 
00540     //! Vector of low temperature limits (species index)
00541     /*!
00542      * Length is equal to number of species
00543      */
00544     vector_fp                          m_tlow;
00545 
00546     //! Vector of low temperature limits (species index)
00547     /*!
00548      * Length is equal to number of species
00549      */
00550     vector_fp                          m_thigh;
00551 
00552     //! Reference pressure (Pa)
00553     /*!
00554      * all species must have the same reference pressure.
00555      */
00556     doublereal                         m_p0;
00557 
00558     //! number of groups
00559     int                                m_ngroups;
00560 
00561     //! Vector of temperature polynomials
00562     mutable vector_fp                  m_t;
00563 
00564     /*!
00565      * This map takes as its index, the species index in the phase.
00566      * It returns the group index, where the temperature polynomials
00567      * for that species are stored. group indecises start at 1,
00568      * so a decrement is always performed to access vectors.
00569      */
00570     mutable map<int, int>              m_group_map;
00571 
00572     /*!
00573      * This map takes as its index, the species index in the phase.
00574      * It returns the position index within the group, where the 
00575      * temperature polynomials for that species are storred.
00576      */
00577     mutable map<int, int>              m_posInGroup_map;
00578 
00579     //! Species name as a function of the species index
00580     mutable map<int, string>           m_name;
00581 
00582   private:
00583 
00584     //! see SpeciesThermoFactory.cpp for the definition
00585     /*!
00586      * @param name string name of species
00587      * @param tmid  Mid temperature, between the two temperature regions
00588      * @param clow  coefficients for lower temperature region
00589      * @param chigh coefficients for higher temperature region
00590      */
00591     void checkContinuity(std::string name, double tmid, const doublereal* clow,
00592                          doublereal* chigh);
00593 
00594     //! for internal use by checkContinuity
00595     /*!
00596      * @param t temperature 
00597      * @param c coefficient array
00598      */
00599     doublereal enthalpy_RT(double t, const doublereal* c) {
00600       return c[0] + 0.5*c[1]*t + OneThird*c[2]*t*t 
00601         + 0.25*c[3]*t*t*t + 0.2*c[4]*t*t*t*t
00602         + c[5]/t;
00603     }
00604 
00605     //! for internal use by checkContinuity
00606     /*!
00607      * @param t temperature 
00608      * @param c coefficient array
00609      */
00610     doublereal entropy_R(double t, const doublereal* c) {
00611       return c[0]*log(t) + c[1]*t + 0.5*c[2]*t*t 
00612         + OneThird*c[3]*t*t*t + 0.25*c[4]*t*t*t*t
00613         + c[6];
00614     }
00615 
00616 
00617 
00618   };
00619 
00620 }
00621 
00622 #endif
00623 
Generated by  doxygen 1.6.3