SpeciesThermoFactory.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file SpeciesThermoFactory.cpp
00003  *    Definitions for factory to build instances of classes that manage the
00004  *    standard-state thermodynamic properties of a set of species 
00005  *    (see \ref spthermo and class \link Cantera::SpeciesThermoFactory SpeciesThermoFactory\endlink);
00006  */
00007 /* 
00008  * $Revision: 385 $
00009  * $Date: 2010-01-17 12:05:46 -0500 (Sun, 17 Jan 2010) $
00010  */
00011 
00012 // Copyright 2001  California Institute of Technology
00013 
00014 #ifdef WIN32
00015 #pragma warning(disable:4786)
00016 #endif
00017 
00018 
00019 #include "SpeciesThermoFactory.h"
00020 using namespace std;
00021 
00022 #include "SpeciesThermo.h"
00023 #include "NasaThermo.h"
00024 #include "ShomateThermo.h"
00025 #include "SimpleThermo.h"
00026 #include "GeneralSpeciesThermo.h"
00027 #include "Mu0Poly.h"
00028 #include "Nasa9PolyMultiTempRegion.h"
00029 #include "Nasa9Poly1.h"
00030 
00031 #ifdef WITH_ADSORBATE
00032 #include "AdsorbateThermo.h"
00033 #endif
00034 
00035 #include "SpeciesThermoMgr.h"
00036 #include "speciesThermoTypes.h"
00037 #include "VPSSMgr.h"
00038 #include "VPStandardStateTP.h"
00039 
00040 #include "xml.h"
00041 #include "ctml.h"
00042 
00043 #include <cmath>
00044 
00045 using namespace ctml;
00046 
00047 
00048 namespace Cantera {
00049 
00050   SpeciesThermoFactory* SpeciesThermoFactory::s_factory = 0;
00051 
00052 #if defined(THREAD_SAFE_CANTERA)
00053   boost::mutex SpeciesThermoFactory::species_thermo_mutex ;
00054 #endif
00055  
00056 
00057   
00058   //! Examine the types of species thermo parameterizations,
00059   //! and return a flag indicating the type of reference state thermo manager
00060   //! that will be needed in order to evaluate them all.
00061   /*!
00062    * 
00063    *  @param spDataNodeList, This vector contains a list
00064    *                         of species XML nodes that will be in the phase
00065    * 
00066    * @todo Make sure that spDadta_node is species Data XML node by checking its name is speciesData
00067    */
00068   static void getSpeciesThermoTypes(std::vector<XML_Node *> & spDataNodeList, 
00069                                     int& has_nasa, int& has_shomate, int& has_simple,
00070                                     int &has_other) {
00071     size_t ns = spDataNodeList.size();
00072     for (size_t n = 0; n < ns; n++) {
00073       XML_Node* spNode = spDataNodeList[n];
00074       if (spNode->hasChild("standardState")) {
00075         const XML_Node& ss = spNode->child("standardState");
00076         string mname = ss["model"];
00077         if (mname == "water" || mname == "waterIAPWS") {
00078           has_other = 1;
00079           continue;
00080         }
00081       }
00082       if (spNode->hasChild("thermo")) {
00083         const XML_Node& th = spNode->child("thermo");
00084         if (th.hasChild("NASA")) {
00085           has_nasa = 1;
00086         } else if (th.hasChild("Shomate")) {
00087           has_shomate = 1;
00088         } else if (th.hasChild("MinEQ3")) {
00089           has_shomate = 1;
00090         } else if (th.hasChild("const_cp")) {
00091           has_simple = 1;
00092         } else if (th.hasChild("poly")) {
00093           if (th.child("poly")["order"] == "1") has_simple = 1;
00094           else throw CanteraError("newSpeciesThermo",
00095                                   "poly with order > 1 not yet supported");
00096         }
00097         else if (th.hasChild("Mu0")) {
00098           has_other = 1;
00099         } else if (th.hasChild("NASA9")) {
00100           has_other = 1;
00101         } else if (th.hasChild("NASA9MULTITEMP")) {
00102           has_other = 1;
00103         } else if (th.hasChild("adsorbate")) {
00104           has_other = 1;
00105         } else {
00106           has_other = 1;
00107           //throw UnknownSpeciesThermoModel("getSpeciesThermoTypes:",
00108           //                                spNode->attrib("name"), "missing");
00109         }
00110       } else {
00111         throw CanteraError("getSpeciesThermoTypes:",
00112                            spNode->attrib("name") + " is missing the thermo XML node");
00113       }
00114     }
00115   }
00116 
00117   //! Static method to return an instance of this class
00118   /*!
00119    * This class is implemented as a singleton -- one in which
00120    * only one instance is needed.  The recommended way to access
00121    * the factory is to call this static method, which
00122    * instantiates the class if it is the first call, but
00123    * otherwise simply returns the pointer to the existing
00124    * instance.
00125    */
00126   SpeciesThermoFactory* SpeciesThermoFactory::factory() {
00127 #if defined(THREAD_SAFE_CANTERA)
00128      boost::mutex::scoped_lock lock(species_thermo_mutex);
00129 #endif
00130      if (!s_factory) s_factory = new SpeciesThermoFactory;
00131      return s_factory;
00132   }
00133 
00134   // Delete static instance of this class
00135   /*
00136    * If it is necessary to explicitly delete the factory before
00137    * the process terminates (for example, when checking for
00138    * memory leaks) then this method can be called to delete it.
00139    */
00140   void SpeciesThermoFactory::deleteFactory() {
00141 #if defined(THREAD_SAFE_CANTERA)
00142     boost::mutex::scoped_lock lock(species_thermo_mutex);
00143 #endif
00144     if (s_factory) {
00145       delete s_factory;
00146       s_factory = 0;
00147     }
00148   }
00149 
00150   // Destructor
00151   /*
00152    * Doesn't do anything. We do not delete statically
00153    * created single instance of this class here, because it would
00154    * create an infinite loop if destructor is called for that
00155    * single instance.
00156    */
00157   SpeciesThermoFactory::~SpeciesThermoFactory() {
00158   }
00159 
00160   /*
00161    * Return a species thermo manager to handle the parameterizations
00162    * specified in a CTML phase specification.
00163    */
00164   SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(std::vector<XML_Node*> & spDataNodeList) const {
00165     int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
00166     try {
00167       getSpeciesThermoTypes(spDataNodeList, inasa, ishomate, isimple, iother);
00168     } catch (UnknownSpeciesThermoModel) {
00169       iother = 1;
00170       popError();
00171     }
00172     if (iother) {
00173       //writelog("returning new GeneralSpeciesThermo");
00174       return new GeneralSpeciesThermo();
00175     }
00176     return newSpeciesThermo(NASA*inasa
00177                             + SHOMATE*ishomate + SIMPLE*isimple);
00178   }
00179 
00180 
00181   /*
00182    * @todo is this used? 
00183    */
00184   SpeciesThermo* SpeciesThermoFactory::
00185   newSpeciesThermoOpt(std::vector<XML_Node*> & spDataNodeList) const {
00186     int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
00187     try {
00188       getSpeciesThermoTypes(spDataNodeList, inasa, ishomate, isimple, iother);
00189     } catch (UnknownSpeciesThermoModel) {
00190       iother = 1;
00191       popError();
00192     }
00193     
00194     if (iother) {
00195       return new GeneralSpeciesThermo();
00196     }
00197     return newSpeciesThermo(NASA*inasa
00198                             + SHOMATE*ishomate + SIMPLE*isimple);
00199   }
00200 
00201   SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(int type) const {
00202     switch (type) {
00203     case NASA:
00204       return new NasaThermo;
00205     case SHOMATE:
00206       return new ShomateThermo;
00207     case SIMPLE:
00208       return new SimpleThermo;
00209     case NASA + SHOMATE:
00210       return new SpeciesThermoDuo<NasaThermo, ShomateThermo>;
00211     case NASA + SIMPLE:
00212       return new SpeciesThermoDuo<NasaThermo, SimpleThermo>;
00213     case SHOMATE + SIMPLE:
00214       return new SpeciesThermoDuo<ShomateThermo, SimpleThermo>;
00215     default:
00216       throw UnknownSpeciesThermo("SpeciesThermoFactory::newSpeciesThermo",
00217                                  type);
00218       return 0; 
00219     }
00220   }
00221 
00222   SpeciesThermo* SpeciesThermoFactory::newSpeciesThermoManager(std::string &stype) const {
00223     std::string ltype = lowercase(stype);
00224     if (ltype == "nasa") {
00225       return new NasaThermo;
00226     } else if (ltype == "shomate") {
00227       return new ShomateThermo;
00228     } else if (ltype ==  "simple" || ltype == "constant_cp") {
00229       return new SimpleThermo;
00230     } else if (ltype ==  "nasa_shomate_duo") {
00231       return new SpeciesThermoDuo<NasaThermo, ShomateThermo>;
00232     } else if (ltype ==  "nasa_simple_duo") {
00233       return new SpeciesThermoDuo<NasaThermo, SimpleThermo>;
00234     } else if (ltype ==  "shomate_simple_duo") {
00235       return new SpeciesThermoDuo<ShomateThermo, SimpleThermo>;
00236     } else if (ltype ==   "general") {
00237       return new GeneralSpeciesThermo();
00238     } else if (ltype ==  "") {
00239       return (SpeciesThermo*) 0;
00240     } else {
00241       throw UnknownSpeciesThermo("SpeciesThermoFactory::newSpeciesThermoManager",
00242                                  stype);
00243     }
00244     return (SpeciesThermo*) 0;
00245   }
00246 
00247   /*
00248    * Check the continuity of properties at the midpoint
00249    * temperature.
00250    */
00251   void NasaThermo::checkContinuity(std::string name, double tmid, const doublereal* clow,
00252                                    doublereal* chigh) {
00253     // heat capacity
00254     doublereal cplow = poly4(tmid, clow);
00255     doublereal cphigh = poly4(tmid, chigh);
00256     doublereal delta = cplow - cphigh;
00257     if (fabs(delta/(fabs(cplow)+1.0E-4)) > 0.001) {
00258       writelog("\n\n**** WARNING ****\nFor species "+name+
00259                ", discontinuity in cp/R detected at Tmid = "
00260                +fp2str(tmid)+"\n");
00261       writelog("\tValue computed using low-temperature polynomial:  "
00262                +fp2str(cplow)+".\n");
00263       writelog("\tValue computed using high-temperature polynomial: "
00264                +fp2str(cphigh)+".\n");
00265     }
00266 
00267     // enthalpy
00268     doublereal hrtlow = enthalpy_RT(tmid, clow);
00269     doublereal hrthigh = enthalpy_RT(tmid, chigh);
00270     delta = hrtlow - hrthigh;
00271     if (fabs(delta/(fabs(hrtlow)+cplow*tmid)) > 0.001) {
00272       writelog("\n\n**** WARNING ****\nFor species "+name+
00273                ", discontinuity in h/RT detected at Tmid = "
00274                +fp2str(tmid)+"\n");
00275       writelog("\tValue computed using low-temperature polynomial:  "
00276                +fp2str(hrtlow)+".\n");
00277       writelog("\tValue computed using high-temperature polynomial: "
00278                +fp2str(hrthigh)+".\n");
00279     }
00280 
00281     // entropy
00282     doublereal srlow = entropy_R(tmid, clow);
00283     doublereal srhigh = entropy_R(tmid, chigh);
00284     delta = srlow - srhigh;
00285     if (fabs(delta/(fabs(srlow)+cplow)) > 0.001) {
00286       writelog("\n\n**** WARNING ****\nFor species "+name+
00287                ", discontinuity in s/R detected at Tmid = "
00288                +fp2str(tmid)+"\n");
00289       writelog("\tValue computed using low-temperature polynomial:  "
00290                +fp2str(srlow)+".\n");
00291       writelog("\tValue computed using high-temperature polynomial: "
00292                +fp2str(srhigh)+".\n");
00293     }
00294   }
00295 
00296 
00297   /** 
00298    * Install a NASA polynomial thermodynamic property
00299    * parameterization for species k into a SpeciesThermo instance.
00300    * This is called by method installThermoForSpecies if a NASA
00301    * block is found in the XML input.
00302    */
00303   static void installNasaThermoFromXML(std::string speciesName,
00304                                        SpeciesThermo& sp, int k, 
00305                                        const XML_Node* f0ptr, const XML_Node* f1ptr) {
00306     doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
00307 
00308     const XML_Node& f0 = *f0ptr;
00309 
00310     // default to a single temperature range
00311     bool dualRange = false;
00312 
00313     // but if f1ptr is suppled, then it is a two-range
00314     // parameterization
00315     if (f1ptr) {dualRange = true;}
00316 
00317     tmin0 = fpValue(f0["Tmin"]);
00318     tmax0 = fpValue(f0["Tmax"]);
00319 
00320     doublereal p0 = OneAtm;
00321     if (f0.hasAttrib("P0")) {
00322       p0 = fpValue(f0["P0"]);
00323     }
00324     if (f0.hasAttrib("Pref")) {
00325       p0 = fpValue(f0["Pref"]);
00326     }
00327     p0 = OneAtm;
00328 
00329     tmin1 = tmax0;
00330     tmax1 = tmin1 + 0.0001;
00331     if (dualRange) {
00332       tmin1 = fpValue((*f1ptr)["Tmin"]);
00333       tmax1 = fpValue((*f1ptr)["Tmax"]);
00334     }
00335 
00336     vector_fp c0, c1;
00337     if (fabs(tmax0 - tmin1) < 0.01) {
00338       // f0 has the lower T data, and f1 the higher T data
00339       tmin = tmin0;
00340       tmid = tmax0;
00341       tmax = tmax1;
00342       getFloatArray(f0.child("floatArray"), c0, false);
00343       if (dualRange)
00344         getFloatArray(f1ptr->child("floatArray"), c1, false);
00345       else {
00346         // if there is no higher range data, then copy c0 to c1.
00347         c1.resize(7,0.0);
00348         copy(c0.begin(), c0.end(), c1.begin());
00349       }
00350     }
00351     else if (fabs(tmax1 - tmin0) < 0.01) {
00352       // f1 has the lower T data, and f0 the higher T data
00353       tmin = tmin1;
00354       tmid = tmax1;
00355       tmax = tmax0;
00356       getFloatArray(f1ptr->child("floatArray"), c0, false);
00357       getFloatArray(f0.child("floatArray"), c1, false);
00358     }
00359     else {
00360       throw CanteraError("installNasaThermo",
00361                          "non-continuous temperature ranges.");
00362     }
00363 
00364     // The NasaThermo species property manager expects the
00365     // coefficients in a different order, so rearrange them.
00366     array_fp c(15);
00367     c[0] = tmid;
00368    
00369     c[1] = c0[5];
00370     c[2] = c0[6];
00371     copy(c0.begin(), c0.begin()+5, c.begin() + 3);
00372     c[8] = c1[5];
00373     c[9] = c1[6];
00374     copy(c1.begin(), c1.begin()+5, c.begin() + 10);
00375     sp.install(speciesName, k, NASA, &c[0], tmin, tmax, p0);
00376   }
00377 
00378 #ifdef INCL_NASA96
00379 
00380   /** 
00381    * Install a NASA96 polynomial thermodynamic property
00382    * parameterization for species k into a SpeciesThermo instance.
00383    */
00384   static void installNasa96ThermoFromXML(std::string speciesName,
00385                                          SpeciesThermo& sp, int k, 
00386                                          const XML_Node* f0ptr, const XML_Node* f1ptr) {
00387     doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
00388 
00389     const XML_Node& f0 = *f0ptr;
00390     bool dualRange = false;
00391     if (f1ptr) {dualRange = true;}
00392     tmin0 = fpValue(f0["Tmin"]);
00393     tmax0 = fpValue(f0["Tmax"]);
00394     tmin1 = tmax0;
00395     tmax1 = tmin1 + 0.0001;
00396     if (dualRange) {
00397       tmin1 = fpValue((*f1ptr)["Tmin"]);
00398       tmax1 = fpValue((*f1ptr)["Tmax"]);
00399     }
00400 
00401 
00402     doublereal p0 = OneAtm;
00403     if (f0.hasAttrib("P0")) {
00404       p0 = fpValue(f0["P0"]);
00405     }
00406     if (f0.hasAttrib("Pref")) {
00407       p0 = fpValue(f0["Pref"]);
00408     }
00409 
00410     vector_fp c0, c1;
00411     if (fabs(tmax0 - tmin1) < 0.01) {
00412       tmin = tmin0;
00413       tmid = tmax0;
00414       tmax = tmax1;
00415       getFloatArray(f0.child("floatArray"), c0, false);
00416       if (dualRange)
00417         getFloatArray(f1ptr->child("floatArray"), c1, false);
00418       else {
00419         c1.resize(7,0.0);
00420         copy(c0.begin(), c0.end(), c1.begin());
00421       }
00422     }
00423     else if (fabs(tmax1 - tmin0) < 0.01) {
00424       tmin = tmin1;
00425       tmid = tmax1;
00426       tmax = tmax0;
00427       getFloatArray(f1ptr->child("floatArray"), c0, false);
00428       getFloatArray(f0.child("floatArray"), c1, false);
00429     }
00430     else {
00431       throw CanteraError("installNasaThermo",
00432                          "non-continuous temperature ranges.");
00433     }
00434     array_fp c(15);
00435     c[0] = tmid;
00436     c[1] = c0[5];
00437     c[2] = c0[6];
00438     copy(c0.begin(), c0.begin()+5, c.begin() + 3);
00439     c[8] = c1[5];
00440     c[9] = c1[6];
00441     copy(c1.begin(), c1.begin()+5, c.begin() + 10);
00442     sp.install(speciesName, k, NASA, &c[0], tmin, tmax, p0);
00443   }
00444 
00445 #endif
00446 
00447   static doublereal LookupGe(const std::string& elemName, ThermoPhase *th_ptr) {
00448 #ifdef OLDWAY
00449     int num = sizeof(geDataTable) / sizeof(struct GeData);
00450     string s3 = elemName.substr(0,3);
00451     for (int i = 0; i < num; i++) {
00452       //if (!std::strncmp(elemName.c_str(), aWTable[i].name, 3)) {
00453       if (s3 == geDataTable[i].name) {
00454         return (geDataTable[i].GeValue);
00455       }
00456     }
00457     throw CanteraError("LookupGe", "element " + s + " not found");
00458     return -1.0;
00459 #else
00460     int iE = th_ptr->elementIndex(elemName);
00461     if (iE < 0) {
00462       throw CanteraError("PDSS_HKFT::LookupGe", "element " + elemName + " not found");
00463     }
00464     doublereal geValue = th_ptr->entropyElement298(iE);
00465     if (geValue == ENTROPY298_UNKNOWN) {
00466       throw CanteraError("PDSS_HKFT::LookupGe",
00467                          "element " + elemName + " doesn not have a supplied entropy298");
00468     }
00469     geValue *= (-298.15);
00470     return geValue;
00471 #endif
00472   }
00473 
00474  static doublereal convertDGFormation(int k, ThermoPhase *th_ptr) {
00475     /*
00476      * Ok let's get the element compositions and conversion factors.
00477      */
00478     int ne = th_ptr->nElements();
00479     doublereal na;
00480     doublereal ge;
00481     string ename;
00482 
00483     doublereal totalSum = 0.0;
00484     for (int m = 0; m < ne; m++) {
00485       na = th_ptr->nAtoms(k, m);
00486       if (na > 0.0) {
00487         ename = th_ptr->elementName(m);
00488         ge = LookupGe(ename, th_ptr);
00489         totalSum += na * ge;
00490       }
00491     }
00492     return totalSum;
00493   }
00494 
00495 
00496 
00497   static void installMinEQ3asShomateThermoFromXML(std::string speciesName, 
00498                                                   ThermoPhase *th_ptr,
00499                                                   SpeciesThermo& sp, int k, 
00500                                                   const XML_Node* MinEQ3node) {
00501 
00502     array_fp coef(15), c0(7, 0.0);
00503     std::string astring = (*MinEQ3node)["Tmin"];
00504     doublereal tmin0 = strSItoDbl(astring);
00505     astring = (*MinEQ3node)["Tmax"];
00506     doublereal tmax0 = strSItoDbl(astring);
00507     astring = (*MinEQ3node)["Pref"];
00508     doublereal p0 = strSItoDbl(astring);
00509  
00510     doublereal deltaG_formation_pr_tr =
00511       getFloatDefaultUnits(*MinEQ3node, "DG0_f_Pr_Tr", "cal/gmol", "actEnergy");
00512     doublereal deltaH_formation_pr_tr =
00513       getFloatDefaultUnits(*MinEQ3node, "DH0_f_Pr_Tr", "cal/gmol", "actEnergy");
00514     doublereal Entrop_pr_tr = getFloatDefaultUnits(*MinEQ3node, "S0_Pr_Tr", "cal/gmol/K");
00515     doublereal a = getFloatDefaultUnits(*MinEQ3node, "a", "cal/gmol/K");
00516     doublereal b = getFloatDefaultUnits(*MinEQ3node, "b", "cal/gmol/K2");
00517     doublereal c = getFloatDefaultUnits(*MinEQ3node, "c", "cal-K/gmol");
00518     doublereal dg = deltaG_formation_pr_tr * 4.184 * 1.0E3;
00519     doublereal fac =  convertDGFormation(k, th_ptr);
00520     doublereal Mu0_tr_pr = fac + dg;
00521     doublereal e = Entrop_pr_tr * 1.0E3 * 4.184;
00522     doublereal Hcalc = Mu0_tr_pr + 298.15 * e;
00523     doublereal DHjmol = deltaH_formation_pr_tr * 1.0E3 * 4.184;
00524 
00525     // If the discrepency is greater than 100 cal gmol-1, print
00526     // an error and exit.
00527     if (fabs(Hcalc -DHjmol) > 10.* 1.0E6 * 4.184) {
00528       throw CanteraError("installMinEQ3asShomateThermoFromXML()",
00529                          "DHjmol is not consistent with G and S" +
00530                          fp2str(Hcalc) + " vs " + fp2str(DHjmol));
00531     }
00532 
00533     /*
00534      * Now calculate the shomate polynomials
00535      *
00536      * Cp first
00537      * 
00538      *  Shomate: (Joules / gmol / K)
00539      *    Cp = As + Bs * t + Cs * t*t + Ds * t*t*t + Es / (t*t)
00540      *     where
00541      *          t = temperature(Kelvin) / 1000
00542      */
00543     double As = a * 4.184;
00544     double Bs = b * 4.184 * 1000.;
00545     double Cs = 0.0;
00546     double Ds = 0.0;
00547     double Es = c * 4.184 / (1.0E6);
00548     
00549     double t = 298.15 / 1000.;
00550     double H298smFs = As * t + Bs * t * t / 2.0 - Es / t; 
00551     
00552     double HcalcS = Hcalc / 1.0E6;
00553     double Fs = HcalcS - H298smFs;
00554 
00555     double S298smGs = As * log(t) + Bs * t - Es/(2.0*t*t);
00556     double ScalcS = e / 1.0E3;
00557     double Gs = ScalcS - S298smGs;
00558 
00559     c0[0] = As;
00560     c0[1] = Bs;
00561     c0[2] = Cs;
00562     c0[3] = Ds;
00563     c0[4] = Es;
00564     c0[5] = Fs;
00565     c0[6] = Gs;
00566 
00567     coef[0] = tmax0 - 0.001;
00568     copy(c0.begin(), c0.begin()+7, coef.begin() + 1);
00569     copy(c0.begin(), c0.begin()+7, coef.begin() + 8);
00570     sp.install(speciesName, k, SHOMATE, &coef[0], tmin0, tmax0, p0);
00571   }
00572 
00573 
00574   /** 
00575    * Install a Shomate polynomial thermodynamic property
00576    * parameterization for species k.
00577    */
00578   static void installShomateThermoFromXML(std::string speciesName, 
00579                                           SpeciesThermo& sp, int k, 
00580                                           const XML_Node* f0ptr, const XML_Node* f1ptr) {
00581     doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
00582 
00583     const XML_Node& f0 = *f0ptr;
00584     bool dualRange = false;
00585     if (f1ptr) {dualRange = true;}
00586     tmin0 = fpValue(f0["Tmin"]);
00587     tmax0 = fpValue(f0["Tmax"]);
00588     tmin1 = tmax0;
00589     tmax1 = tmin1 + 0.0001;
00590     if (dualRange) {
00591       tmin1 = fpValue((*f1ptr)["Tmin"]);
00592       tmax1 = fpValue((*f1ptr)["Tmax"]);
00593     }
00594 
00595     vector_fp c0, c1;
00596     if (fabs(tmax0 - tmin1) < 0.01) {
00597       tmin = tmin0;
00598       tmid = tmax0;
00599       tmax = tmax1;
00600       getFloatArray(f0.child("floatArray"), c0, false);
00601       if (dualRange)
00602         getFloatArray(f1ptr->child("floatArray"), c1, false);
00603       else {
00604         c1.resize(7,0.0);
00605         copy(c0.begin(), c0.begin()+7, c1.begin());
00606       }
00607     }
00608     else if (fabs(tmax1 - tmin0) < 0.01) {
00609       tmin = tmin1;
00610       tmid = tmax1;
00611       tmax = tmax0;
00612       getFloatArray(f1ptr->child("floatArray"), c0, false);
00613       getFloatArray(f0.child("floatArray"), c1, false);
00614     }
00615     else {
00616       throw CanteraError("installShomateThermoFromXML",
00617                          "non-continuous temperature ranges.");
00618     }
00619     array_fp c(15);
00620     c[0] = tmid;
00621     doublereal p0 = OneAtm;
00622     copy(c0.begin(), c0.begin()+7, c.begin() + 1);
00623     copy(c1.begin(), c1.begin()+7, c.begin() + 8);
00624     sp.install(speciesName, k, SHOMATE, &c[0], tmin, tmax, p0);
00625   }
00626 
00627 
00628 
00629   /** 
00630    * Install a constant-cp thermodynamic property
00631    * parameterization for species k.
00632    */
00633   static void installSimpleThermoFromXML(std::string speciesName, 
00634                                          SpeciesThermo& sp, int k, 
00635                                          const XML_Node& f) {
00636     doublereal tmin, tmax;
00637     tmin = fpValue(f["Tmin"]);
00638     tmax = fpValue(f["Tmax"]);
00639     if (tmax == 0.0) tmax = 1.0e30;
00640 
00641     vector_fp c(4);
00642     c[0] = getFloat(f, "t0", "toSI");
00643     c[1] = getFloat(f, "h0", "toSI");
00644     c[2] = getFloat(f, "s0", "toSI");
00645     c[3] = getFloat(f, "cp0", "toSI");
00646     doublereal p0 = OneAtm;
00647     sp.install(speciesName, k, SIMPLE, &c[0], tmin, tmax, p0);
00648   }
00649 
00650   /** 
00651    * Install a NASA9 polynomial thermodynamic property
00652    * parameterization for species k into a SpeciesThermo instance.
00653    * This is called by method installThermoForSpecies if a NASA9
00654    * block is found in the XML input.
00655    */
00656   static void installNasa9ThermoFromXML(std::string speciesName,
00657                                         SpeciesThermo& sp, int k, 
00658                                         const std::vector<XML_Node*>& tp)
00659   {                             
00660     const XML_Node * fptr = tp[0];
00661     int nRegTmp = tp.size();
00662     int nRegions = 0;
00663     vector_fp cPoly;
00664     Nasa9Poly1 *np_ptr = 0; 
00665     std::vector<Nasa9Poly1 *> regionPtrs;
00666     doublereal tmin, tmax, pref = OneAtm;
00667     // Loop over all of the possible temperature regions
00668     for (int i = 0; i < nRegTmp; i++) {
00669       fptr = tp[i];
00670       if (fptr) {
00671         if (fptr->name() == "NASA9") {
00672           if (fptr->hasChild("floatArray")) {
00673 
00674             tmin = fpValue((*fptr)["Tmin"]);
00675             tmax = fpValue((*fptr)["Tmax"]);
00676             if ((*fptr).hasAttrib("P0")) {
00677               pref = fpValue((*fptr)["P0"]);
00678             }
00679             if ((*fptr).hasAttrib("Pref")) {
00680               pref = fpValue((*fptr)["Pref"]);
00681             }
00682 
00683             getFloatArray(fptr->child("floatArray"), cPoly, false);
00684             if (cPoly.size() != 9) {
00685               throw CanteraError("installNasa9ThermoFromXML",
00686                                  "Expected 9 coeff polynomial");
00687             }
00688             np_ptr = new Nasa9Poly1(k, tmin, tmax, pref,
00689                                     DATA_PTR(cPoly));
00690             regionPtrs.push_back(np_ptr);
00691             nRegions++;
00692           } 
00693         }
00694       }
00695     }
00696     if (nRegions == 0) {
00697       throw UnknownSpeciesThermoModel("installThermoForSpecies", 
00698                                       speciesName, "  " );
00699     } else if (nRegions == 1)  {
00700       sp.install_STIT(np_ptr);
00701     } else {
00702       Nasa9PolyMultiTempRegion*  npMulti_ptr = new  Nasa9PolyMultiTempRegion(regionPtrs);
00703       sp.install_STIT(npMulti_ptr);
00704     }
00705   }
00706 
00707 
00708   /** 
00709    * Install an Adsorbate thermodynamic property
00710    * parameterization for species k into a SpeciesThermo instance.
00711    * This is called by method installThermoForSpecies if a NASA9
00712    * block is found in the XML input.
00713    */
00714 #ifdef WITH_ADSORBATE
00715   static void installAdsorbateThermoFromXML(std::string speciesName,
00716                                             SpeciesThermo& sp, int k, 
00717                                             const XML_Node& f) {                
00718     vector_fp freqs;
00719     doublereal tmin, tmax, pref = OneAtm;
00720     int nfreq = 0;
00721     tmin = fpValue(f["Tmin"]);
00722     tmax = fpValue(f["Tmax"]);
00723     if (f.hasAttrib("P0")) {
00724       pref = fpValue(f["P0"]);
00725     }
00726     if (f.hasAttrib("Pref")) {
00727       pref = fpValue(f["Pref"]);
00728     }
00729     if (tmax == 0.0) tmax = 1.0e30;
00730 
00731     if (f.hasChild("floatArray")) {
00732       getFloatArray(f.child("floatArray"), freqs, false);
00733       nfreq = freqs.size(); 
00734     }
00735     for (int n = 0; n < nfreq; n++) {
00736       freqs[n] *= 3.0e10;
00737     }
00738     vector_fp coeffs(nfreq + 2);
00739     coeffs[0] = nfreq;
00740     coeffs[1] = getFloat(f, "binding_energy", "toSI");
00741     copy(freqs.begin(), freqs.end(), coeffs.begin() + 2);
00742     //posc = new Adsorbate(k, tmin, tmax, pref,  
00743     //    DATA_PTR(coeffs)); 
00744     (&sp)->install(speciesName, k, ADSORBATE, &coeffs[0], tmin, tmax, pref);
00745   }
00746 #endif
00747 
00748   //================================================================================================
00749   // Install a species thermodynamic property parameterization
00750   // for the reference state for one species into a species thermo manager.
00751   /*
00752    * @param k             Species number
00753    * @param speciesNode   Reference to the XML node specifying the species standard
00754    *                      state information
00755    * @param th_ptr        Pointer to the %ThermoPhase object for the species
00756    * @param spthermo      Species reference state thermo manager
00757    * @param phaseNode_ptr Optional pointer to the XML phase
00758    *                      information for the phase in which the species
00759    *                      resides
00760    */
00761   void SpeciesThermoFactory::
00762   installThermoForSpecies(int k, const XML_Node& speciesNode, ThermoPhase *th_ptr,
00763                           SpeciesThermo& spthermo,
00764                           const XML_Node *phaseNode_ptr) const {
00765     /*
00766      * Check to see that the species block has a thermo block
00767      * before processing. Throw an error if not there.
00768      */
00769     if (!(speciesNode.hasChild("thermo"))) {
00770       throw UnknownSpeciesThermoModel("installThermoForSpecies", 
00771                                       speciesNode["name"], "<nonexistent>");
00772     }
00773     const XML_Node& thermo = speciesNode.child("thermo");
00774     const std::vector<XML_Node*>& tp = thermo.children();
00775     int nc = static_cast<int>(tp.size());
00776     string mname = thermo["model"];
00777 
00778     if (mname == "MineralEQ3") {
00779       const XML_Node* f = tp[0];
00780       if (f->name() != "MinEQ3") {
00781         throw CanteraError("SpeciesThermoFactory::installThermoForSpecies",
00782                            "confused: expedted MinEQ3");
00783       }
00784       installMinEQ3asShomateThermoFromXML(speciesNode["name"], th_ptr, spthermo, k, f);
00785     } else {
00786       if (nc == 1) {
00787         const XML_Node* f = tp[0];
00788         if (f->name() == "Shomate") {
00789           installShomateThermoFromXML(speciesNode["name"], spthermo, k, f, 0);
00790         }
00791         else if (f->name() == "const_cp") {
00792           installSimpleThermoFromXML(speciesNode["name"], spthermo, k, *f);
00793         }
00794         else if (f->name() == "NASA") {
00795           installNasaThermoFromXML(speciesNode["name"], spthermo, k, f, 0);
00796         }
00797         else if (f->name() == "Mu0") {
00798           installMu0ThermoFromXML(speciesNode["name"], spthermo, k, f);
00799         }
00800         else if (f->name() == "NASA9") {
00801           installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp);
00802         }
00803         // else if (f->name() == "HKFT") {
00804         //      installHKFTThermoFromXML(s["name"], spthermo, k, tp);
00805         //}
00806 #ifdef WITH_ADSORBATE
00807         else if (f->name() == "adsorbate") {
00808           installAdsorbateThermoFromXML(speciesNode["name"], spthermo, k, *f);
00809         }
00810 #endif
00811         else {
00812           throw UnknownSpeciesThermoModel("installThermoForSpecies", 
00813                                           speciesNode["name"], f->name());
00814         }
00815       }
00816       else if (nc == 2) {
00817         const XML_Node* f0 = tp[0];
00818         const XML_Node* f1 = tp[1];
00819         if (f0->name() == "NASA" && f1->name() == "NASA") {
00820           installNasaThermoFromXML(speciesNode["name"], spthermo, k, f0, f1);
00821         } 
00822         else if (f0->name() == "Shomate" && f1->name() == "Shomate") {
00823           installShomateThermoFromXML(speciesNode["name"], spthermo, k, f0, f1);
00824         } 
00825         else if (f0->name() == "NASA9" && f1->name() == "NASA9") {
00826           installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp);
00827         } else {
00828           throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"], 
00829                                           f0->name() + " and " + f1->name());
00830         }
00831       }
00832       else if (nc >= 2) {
00833         const XML_Node* f0 = tp[0];
00834         if (f0->name() == "NASA9") {
00835           installNasa9ThermoFromXML(speciesNode["name"], spthermo, k, tp);
00836         } else {
00837           throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"], 
00838                                           "multiple");
00839         }
00840       } else {
00841         throw UnknownSpeciesThermoModel("installThermoForSpecies", speciesNode["name"], 
00842                                         "multiple");
00843       }
00844     }
00845   }
00846   //================================================================================================
00847   // Install a species thermodynamic property parameterization
00848   // for the standard state for one species into a species thermo manager, VPSSMgr
00849   /*
00850    * This is a wrapper around the createInstallVPSS() function in the 
00851    * VPStandardStateTP object.
00852    *
00853    * This serves to install the species into vpss_ptr, create a PDSS file. We also
00854    * read the xml database to extract the constants for these steps.
00855    *
00856    * @param k             species number
00857    * @param speciesNode   Reference to the XML node specifying the species standard
00858    *                      state information
00859    * @param vp_ptr        variable pressure ThermoPhase object 
00860    * @param vpss_ptr      Pointer to the Manager for calculating variable pressure
00861    *                      substances.
00862    * @param spthermo_ptr  Species reference state thermo manager
00863    * @param phaseNode_ptr Optional Pointer to the XML phase
00864    *                      information for the phase in which the species
00865    *                      resides
00866    */
00867   void SpeciesThermoFactory::
00868   installVPThermoForSpecies(int k, const XML_Node& speciesNode, 
00869                             VPStandardStateTP *vp_ptr,
00870                             VPSSMgr *vpssmgr_ptr,
00871                             SpeciesThermo *spthermo_ptr,
00872                             const XML_Node *phaseNode_ptr) const {
00873     
00874     // Call the VPStandardStateTP object to install the pressure dependent species
00875     // standard state into the object.
00876     //
00877     // We don't need to pass spthermo_ptr down, because it's already installed
00878     // into vp_ptr.
00879     //
00880     // We don't need to pass vpssmgr_ptr down, because it's already installed
00881     // into vp_ptr.
00882     vp_ptr->createInstallPDSS(k, speciesNode,  phaseNode_ptr);
00883   }
00884 
00885   // Create a new species thermo manager instance, by specifying
00886   // the type and (optionally) a pointer to the factory to use to create it.
00887   /*
00888    * This utility program  will look through species nodes. It will discover what
00889    * each species needs for its species property managers. Then,
00890    * it will malloc and return the proper species property manager to use.
00891    *
00892    *  These functions allow using a different factory class that
00893    *  derives from SpeciesThermoFactory.
00894    *
00895    * @param type         Species thermo type.
00896    * @param f            Pointer to a SpeciesThermoFactory. optional parameter. 
00897    *                    Defautls to NULL.
00898    */
00899   SpeciesThermo* newSpeciesThermoMgr(int type, SpeciesThermoFactory* f) {
00900     if (f == 0) {
00901       f = SpeciesThermoFactory::factory();
00902     }
00903     SpeciesThermo* sptherm = f->newSpeciesThermo(type);
00904     return sptherm;
00905   }
00906 
00907   // Create a new species thermo manager instance, by specifying
00908   //the type and (optionally) a pointer to the factory to use to create it.
00909   /*
00910    * This utility program is a basic factory operation for spawning a
00911    * new species reference-state thermo mananger
00912    *
00913    *  These functions allows for using a different factory class that
00914    *  derives from SpeciesThermoFactory. However, no applications of this
00915    *  have been done yet.
00916    *
00917    * @param stype       String specifying the species thermo type
00918    * @param f           Pointer to a SpeciesThermoFactory. optional parameter. 
00919    *                    Defaults to NULL.
00920    */
00921   SpeciesThermo* newSpeciesThermoMgr(std::string &stype, 
00922                                      SpeciesThermoFactory* f) {
00923     if (f == 0) {
00924       f = SpeciesThermoFactory::factory();
00925     }
00926     SpeciesThermo* sptherm = f->newSpeciesThermoManager(stype);
00927     return sptherm;
00928   }
00929   
00930   // Function to return SpeciesThermo manager
00931   /*
00932    * This utility program  will look through species nodes. It will discover what
00933    * each species needs for its species property managers. Then,
00934    * it will malloc and return the proper species property manager to use.
00935    *
00936    *  These functions allow using a different factory class that
00937    *  derives from SpeciesThermoFactory.
00938    *
00939    * @param spData_nodes Vector of XML_Nodes, each of which is a speciesData XML Node.
00940    *                     Each %speciesData node contains a list of XML species elements
00941    *                      e.g., <speciesData id="Species_Data">
00942    * @param f            Pointer to a SpeciesThermoFactory. optional parameter. 
00943    *                    Defautls to NULL.
00944    * @param opt         Boolean defaults to false.
00945    */
00946   SpeciesThermo* newSpeciesThermoMgr(std::vector<XML_Node*> spData_nodes, 
00947                                      SpeciesThermoFactory* f, bool opt) {
00948     if (f == 0) {
00949       f = SpeciesThermoFactory::factory();
00950     }
00951     SpeciesThermo* sptherm;
00952     if (opt) {
00953       sptherm = f->newSpeciesThermoOpt(spData_nodes);
00954     } else { 
00955       sptherm = f->newSpeciesThermo(spData_nodes);
00956     }
00957     return sptherm;
00958   }
00959 
00960 }
Generated by  doxygen 1.6.3