IdealSolidSolnPhase.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file IdealSolidSolnPhase.cpp
00003  *      Implementation file for an ideal solid solution model
00004  *      with incompressible thermodynamics (see \ref thermoprops and
00005  *      \link Cantera::IdealSolidSolnPhase IdealSolidSolnPhase\endlink).
00006  */
00007 /*
00008  * $Id: IdealSolidSolnPhase.cpp 398 2010-02-09 20:24:11Z hkmoffa $
00009  */
00010 /*
00011  * Copywrite 2006 Sandia Corporation. Under the terms of Contract
00012  * DE-AC04-94AL85000, with Sandia Corporation, the U.S. Government
00013  * retains certain rights in this software.
00014  */
00015 
00016 #include "IdealSolidSolnPhase.h"
00017 #include <iostream>
00018 using namespace std;
00019 
00020 namespace Cantera {
00021 
00022   /*
00023    * Constructor for IdealSolidSolnPhase class:
00024    *  The default form for the generalized concentrations is 0
00025    * i.e., unity.
00026    */
00027   IdealSolidSolnPhase::IdealSolidSolnPhase(int formGC) :
00028     ThermoPhase(),
00029     m_formGC(formGC),
00030     m_mm(0),
00031     m_tmin(0.0),
00032     m_tmax(1000000.),
00033     m_Pref(OneAtm),
00034     m_Pcurrent(OneAtm),
00035     m_tlast(0.0)
00036   {
00037     if (formGC < 0 || formGC > 2) {
00038       throw CanteraError(" IdealSolidSolnPhase Constructor",
00039                          " Illegal value of formGC");
00040     }
00041   }
00042 
00043   IdealSolidSolnPhase::IdealSolidSolnPhase(std::string inputFile, std::string id,
00044                                            int formGC) :
00045     ThermoPhase(),
00046     m_formGC(formGC),
00047     m_mm(0),
00048     m_tmin(0.0),
00049     m_tmax(1000000.),
00050     m_Pref(OneAtm),
00051     m_Pcurrent(OneAtm),
00052     m_tlast(0.0)
00053   {     
00054     if (formGC < 0 || formGC > 2) {
00055       throw CanteraError(" IdealSolidSolnPhase Constructor",
00056                          " Illegal value of formGC");
00057     }
00058     constructPhaseFile(inputFile, id);
00059   }
00060 
00061   IdealSolidSolnPhase::IdealSolidSolnPhase(XML_Node& root, std::string id,
00062                                            int formGC) :
00063     ThermoPhase(),
00064     m_formGC(formGC),
00065     m_mm(0),
00066     m_tmin(0.0),
00067     m_tmax(1000000.),
00068     m_Pref(OneAtm),
00069     m_Pcurrent(OneAtm),
00070     m_tlast(0.0)
00071   {
00072     if (formGC < 0 || formGC > 2) {
00073       throw CanteraError(" IdealSolidSolnPhase Constructor",
00074                          " Illegal value of formGC");
00075     }
00076     constructPhaseXML(root, id);
00077   }
00078 
00079   IdealSolidSolnPhase::IdealSolidSolnPhase(const IdealSolidSolnPhase &b) 
00080   {
00081     *this = b;
00082   }
00083 
00084     
00085   IdealSolidSolnPhase& IdealSolidSolnPhase::
00086   operator=(const IdealSolidSolnPhase &b) {
00087     if (this != &b) {
00088       //ThermoPhase::operator=(b);
00089       // m_spthermo   = dupMyselfAsSpeciesThermo(b.m_spthermo);
00090       m_formGC     = b.m_formGC;
00091       m_mm         = b.m_mm;
00092       m_tmin       = b.m_tmin;
00093       m_tmax       = b.m_tmax;
00094       m_Pref       = b.m_Pref;
00095       m_Pcurrent   = b.m_Pcurrent;
00096       m_speciesMolarVolume = b.m_speciesMolarVolume;
00097       m_tlast      = b.m_tlast;
00098       m_h0_RT      = b.m_h0_RT;
00099       m_cp0_R      = b.m_cp0_R;
00100       m_g0_RT      = b.m_g0_RT; 
00101       m_s0_R       = b.m_s0_R;
00102       m_expg0_RT   = b.m_expg0_RT;
00103       m_pe         = b.m_pe;
00104       m_pp         = b.m_pp;
00105     }
00106     return *this;
00107   }
00108 
00109   /*
00110    * Base Class Duplication Function
00111    *  -> given a pointer to ThermoPhase, this function can
00112    *     duplicate the object. (note has to be a separate function
00113    *     not the copy constructor, because it has to be
00114    *     a virtual function)
00115    */
00116   ThermoPhase* IdealSolidSolnPhase::duplMyselfAsThermoPhase() const {
00117     IdealSolidSolnPhase *ii = new IdealSolidSolnPhase(*this);
00118     return (ThermoPhase*) ii;
00119   }
00120 
00121   /**
00122    * Equation of state flag. Returns the value cIdealGas, defined 
00123    * in mix_defs.h.
00124    */
00125   int IdealSolidSolnPhase::eosType() const {
00126     integer res;
00127     switch (m_formGC) {
00128     case 0:
00129       res = cIdealSolidSolnPhase0;
00130       break;
00131     case 1:
00132       res = cIdealSolidSolnPhase1;
00133       break;
00134     case 2:
00135       res = cIdealSolidSolnPhase2;
00136       break;
00137     default:
00138       throw CanteraError("eosType", "Unknown type");
00139       break;
00140     }
00141     return res;
00142   }
00143 
00144   /********************************************************************
00145    *            Molar Thermodynamic Properties of the Solution
00146    ********************************************************************/
00147   /**
00148    * Molar enthalpy of the solution. Units: J/kmol.
00149    * For an ideal, constant partial molar volume solution mixture with
00150    * pure species phases which exhibit zero volume expansivity and
00151    * zero isothermal compressibility:
00152    * \f[
00153    * \hat h(T,P) = \sum_k X_k \hat h^0_k(T) + (P - P_{ref}) (\sum_k X_k \hat V^0_k)
00154    * \f]
00155    * The reference-state pure-species enthalpies at the reference pressure Pref 
00156    * \f$ \hat h^0_k(T) \f$, are computed by the species thermodynamic 
00157    * property manager. They are polynomial functions of temperature.
00158    * @see SpeciesThermo
00159    */
00160   doublereal IdealSolidSolnPhase::
00161   enthalpy_mole() const {
00162     const double *eptr = &(enthalpy_RT_ref()[0]);
00163     doublereal htp = (GasConstant * temperature() * mean_X(eptr));
00164     return (htp + (pressure() - m_Pref)/molarDensity());
00165   }
00166 
00167   /**
00168    * Molar internal energy of the solution. J/kmol.
00169    * For an ideal, constant partial molar volume solution mixture with
00170    * pure species phases which exhibit zero volume expansivity and
00171    * zero isothermal compressibility:
00172    * \f[
00173    * \hat u(T) = \hat h(T,P) - p \hat V =  \sum_k X_k \hat h^0_k(T) 
00174    *              - P_{ref} (\sum_k X_k \hat V^0_k)
00175    * \f]
00176    * and is a function only of temperature.
00177    * The reference-state pure-species enthalpies 
00178    * \f$ \hat h^0_k(T) \f$ are computed by the species thermodynamic 
00179    * property manager.
00180    * @see SpeciesThermo
00181    */
00182   doublereal IdealSolidSolnPhase::intEnergy_mole() const {
00183     const double *eptr = DATA_PTR(enthalpy_RT_ref().begin());
00184     doublereal htp = (GasConstant * temperature() * 
00185                       mean_X(eptr));
00186     return (htp - m_Pref / molarDensity());
00187   }
00188 
00189   /**
00190    * Molar entropy of the solution. Units: J/kmol/K.
00191    * For an ideal, constant partial molar volume solution mixture with
00192    * pure species phases which exhibit zero volume expansivity:
00193    * \f[
00194    * \hat s(T, P, X_k) = \sum_k X_k \hat s^0_k(T)
00195    *                   - \hat R  \sum_k X_k log(X_k)
00196    * \f]
00197    * The reference-state pure-species entropies 
00198    * \f$ \hat s^0_k(T,p_{ref}) \f$ are computed by the species thermodynamic 
00199    * property manager. The pure species entropies are independent of 
00200    * temperature since the volume expansivities are equal to zero.
00201    * @see SpeciesThermo
00202    */
00203   doublereal IdealSolidSolnPhase::entropy_mole() const {
00204     const double *dptr = DATA_PTR(entropy_R_ref());
00205     return GasConstant * (mean_X(dptr) - sum_xlogx());
00206   }
00207 
00208   /**
00209    * Molar gibbs free energy of the solution. Units: J/kmol.
00210    * For an ideal, constant partial molar volume solution mixture with
00211    * pure species phases which exhibit zero volume expansivity:
00212    * \f[
00213    * \hat g(T, P) = \sum_k X_k \hat g^0_k(T,P) + \hat R T \sum_k X_k log(X_k)
00214    * \f]
00215    * The reference-state pure-species gibbs free energies
00216    * \f$ \hat g^0_k(T) \f$ are computed by the species thermodynamic 
00217    * property manager, while the standard state gibbs free energies
00218    * \f$ \hat g^0_k(T,P) \f$ are computed by the member function, gibbs_RT().
00219    * @see SpeciesThermo
00220    */
00221   doublereal IdealSolidSolnPhase::gibbs_mole() const {
00222     const double *dptr = DATA_PTR(gibbs_RT_ref());
00223     doublereal g = mean_X(dptr);
00224     return (GasConstant * temperature() * (g + sum_xlogx()));
00225   }
00226 
00227   /**
00228    * Molar heat capacity at constant pressure of the solution.
00229    * Units: J/kmol/K.
00230    * For an ideal, constant partial molar volume solution mixture with
00231    * pure species phases which exhibit zero volume expansivity:
00232    * \f[
00233    * \hat c_p(T,P) = \sum_k X_k \hat c^0_{p,k}(T) .
00234    * \f]
00235    * The heat capacity is independent of pressure. 
00236    * The reference-state pure-species heat capacities  
00237    * \f$ \hat c^0_{p,k}(T) \f$ are computed by the species thermodynamic 
00238    * property manager.
00239    * @see SpeciesThermo
00240    */
00241   doublereal IdealSolidSolnPhase::cp_mole() const {
00242     const double *dptr = DATA_PTR(cp_R_ref());
00243     return GasConstant * mean_X(dptr);
00244   }
00245 
00246   /********************************************************************
00247    *                  Mechanical Equation of State
00248    ********************************************************************/
00249   /**
00250    *
00251    * Calculate the density of the mixture using the partial 
00252    * molar volumes and mole fractions as input
00253    *
00254    * The formula for this is
00255    *
00256    * \f[ 
00257    * \rho = \frac{\sum_k{X_k W_k}}{\sum_k{X_k V_k}} 
00258    * \f]
00259    *
00260    * where \f$ X_k \f$ are the mole fractions, \f$W_k\f$ are
00261    * the molecular weights, and \f$V_k\f$ are the pure species
00262    * molar volumes.
00263    *
00264    * Note, the basis behind this formula is that in an ideal
00265    * solution the partial molar volumes are equal to the pure
00266    * species molar volumes. We have additionally specified that
00267    * in this class that the pure species molar volumes are
00268    * independent of temperature and pressure. 
00269    */
00270   void IdealSolidSolnPhase::calcDensity() {
00271     /*
00272      * Calculate the molarVolume of the solution (m**3 kmol-1)
00273      */
00274     const doublereal * const dtmp = moleFractdivMMW();
00275     double invDens = dot(m_speciesMolarVolume.begin(),
00276                          m_speciesMolarVolume.end(), dtmp);
00277     /*
00278      * Set the density in the parent State object directly,
00279      * by calling the State::setDensity() function.
00280      */
00281     double dens = 1.0/invDens;
00282     State::setDensity(dens);
00283   }
00284     
00285   /**
00286    * Overwritten setDensity() function is necessary because the
00287    * density is not an indendent variable.
00288    *
00289    * This function will now throw an error condition
00290    *
00291    * @internal May have to adjust the strategy here to make
00292    * the eos for these materials slightly compressible, in order
00293    * to create a condition where the density is a function of 
00294    * the pressure.
00295    *
00296    * This function will now throw an error condition.
00297    *
00298    *  NOTE: This is a virtual function that overwrites the State.h
00299    *        class
00300    */
00301   void IdealSolidSolnPhase::
00302   setDensity(const doublereal rho) {
00303     /*
00304      * Unless the input density is exactly equal to the density
00305      * calculated and storred in the State object, we throw an
00306      * exception. This is because the density is NOT an 
00307      * independent variable.
00308      */
00309     double dens = density();
00310     if (rho != dens) {
00311       throw CanteraError("IdealSolidSolnPhase::setDensity",
00312                          "Density is not an independent variable");
00313     }
00314   }
00315 
00316   /*
00317    * setPressure(double)               (virtual from ThermoPhase)
00318    *
00319    * Set the pressure at constant temperature. Units: Pa.
00320    * This method sets a constant within the object.
00321    * The mass density is not a function of pressure.
00322    * Note: This function overrides the setPressure() function
00323    *       in the ThermoPhase object.
00324    *       We calculate the density and store it in the
00325    *       State object, because this density is supposed to
00326    *       be current after setting the pressure, and is now
00327    *       a dependent variable.
00328    */
00329   void IdealSolidSolnPhase::setPressure(doublereal p) {
00330     m_Pcurrent = p;
00331     calcDensity();
00332   }
00333 
00334   /*
00335    * setMolarDensity()                    (virtual from State)
00336    * Overwritten setMolarDensity() function is necessary because the
00337    * density is not an indendent variable.
00338    *
00339    * This function will now throw an error condition.
00340    *
00341    *  NOTE: This is a virtual function that overrides the State.h
00342    *        class
00343    */  
00344   void IdealSolidSolnPhase::setMolarDensity(const doublereal n) {
00345     throw CanteraError("IdealSolidSolnPhase::setMolarDensity",
00346                        "Density is not an independent variable");
00347   }
00348 
00349   /*
00350    * setMoleFractions()                     (virtual from State)
00351    *
00352    * Sets the mole fractions and adjusts the internal density.
00353    */
00354   void IdealSolidSolnPhase::setMoleFractions(const doublereal * const x) {
00355     State::setMoleFractions(x);
00356     calcDensity();
00357   }
00358 
00359   /**
00360    * setMoleFractions_NoNorm()               (virtual from State)
00361    *
00362    * Sets the mole fractions and adjusts the internal density.
00363    */
00364   void IdealSolidSolnPhase::setMoleFractions_NoNorm(const doublereal * const x) {
00365     State::setMoleFractions(x);
00366     calcDensity();
00367   }
00368 
00369   /*
00370    * setMassFractions()                      (virtual from State)
00371    *
00372    * Sets the mass fractions and adjusts the internal density.
00373    */
00374   void IdealSolidSolnPhase::setMassFractions(const doublereal * const y) {
00375     State::setMassFractions(y);
00376     calcDensity();
00377   }
00378 
00379   /*
00380    * setMassFractions_NoNorm()               (virtual from State)
00381    *
00382    * Sets the mass fractions and adjusts the internal density.
00383    */
00384   void IdealSolidSolnPhase::setMassFractions_NoNorm(const doublereal * const y) {
00385     State::setMassFractions_NoNorm(y);
00386     calcDensity();
00387   }
00388 
00389   /*
00390    * setConcentrations                        (virtual from State)
00391    *
00392    * Sets the concentrations and adjusts the internal density
00393    */
00394   void IdealSolidSolnPhase::setConcentrations(const doublereal * const c) {
00395     State::setConcentrations(c);
00396     calcDensity();
00397   }
00398 
00399   /********************************************************************
00400    *        Chemical Potentials and Activities
00401    ********************************************************************/
00402 
00403   /********************************************************************
00404    *
00405    * getActivitConcentrations():
00406    *
00407    * This method returns the array of generalized
00408    * concentrations. The generalized concentrations are used
00409    * in the evaluation of the rates of progress for reactions
00410    * involving species in this phase. The generalized
00411    * concentration dividied by the standard concentration is also
00412    * equal to the activity of species.
00413    *
00414    * For this implentation the activity is defined to be the
00415    * mole fraction of the species. The generalized concentration
00416    * is defined to be equal to the mole fraction divided by
00417    * the partial molar volume. The generalized concentrations
00418    * for species in this phase therefore have units of
00419    * kmol m<SUP>-3</SUP>. Rate constants must reflect this fact.
00420    * 
00421    * On a general note, the following must be true.
00422    * For an ideal solution, the generalized concentration  must consist 
00423    * of the mole fraction multiplied by a constant. The constant may be
00424    * fairly arbitrarily chosen, with differences adsorbed into the
00425    * reaction rate expression. 1/V_N, 1/V_k, or 1 are equally good,
00426    * as long as the standard concentration is adjusted accordingly. 
00427    * However, it must be a constant (and not the concentration, btw,
00428    * which is a function of the mole fractions) in order for the
00429    * ideal solution properties to hold at the same time having the 
00430    * standard concentration to be independent of the mole fractions.
00431    *
00432    * In this implementation the form of the generalized concentrations
00433    * depend upon the member attribute, m_formGC:
00434    *
00435    *                          <TABLE>
00436    *  <TR><TD> m_formGC </TD><TD> GeneralizedConc </TD><TD> StandardConc </TD></TR>
00437    *  <TR><TD> 0        </TD><TD> X_k             </TD><TD> 1.0          </TD></TR>
00438    *  <TR><TD> 1        </TD><TD> X_k / V_k       </TD><TD> 1.0 / V_k    </TD></TR>
00439    *  <TR><TD> 2        </TD><TD> X_k / V_N       </TD><TD> 1.0 / V_N    </TD></TR>
00440    *                         </TABLE>
00441    *
00442    * HKM Note: We have absorbed the pressure dependence of the pure species
00443    *        state into the thermodynamics functions. Therefore the
00444    *        standard state on which the activities are based depend
00445    *        on both temperature and pressure. If we hadn't, it would have
00446    *        appeared in this function in a very awkwards exp[] format.
00447    *
00448    * @param c[] Pointer to array of doubles of length m_kk, which on exit
00449    *          will contain the generalized concentrations.
00450    */
00451   void IdealSolidSolnPhase::
00452   getActivityConcentrations(doublereal* c) const {
00453     const doublereal * const dtmp = moleFractdivMMW();
00454     const double mmw = meanMolecularWeight();
00455     switch (m_formGC) {
00456     case 0:
00457       for (int k = 0; k < m_kk; k++) {
00458         c[k] = dtmp[k] * mmw;
00459       }
00460       break;
00461     case 1:
00462       for (int k = 0; k < m_kk; k++) {
00463         c[k] = dtmp[k] * mmw / m_speciesMolarVolume[k];
00464       }
00465       break;
00466     case 2:
00467       double atmp = mmw / m_speciesMolarVolume[m_kk-1];
00468       for (int k = 0; k < m_kk; k++) {
00469         c[k] = dtmp[k] * atmp;
00470       }
00471       break;
00472     }
00473   }
00474 
00475   /*********************************************************************
00476    *
00477    * standardConcentration()
00478    *
00479    * The standard concentration \f$ C^0_k \f$ used to normalize
00480    * the generalized concentration.
00481    * In many cases, this quantity
00482    * will be the same for all species in a phase.
00483    * However, for this case, we will return a distinct concentration
00484    * for each species. This is the inverse of the species molar
00485    * volume. Units are m<SUP>3</SUP> kmol<SUP>-1</SUP>.
00486    *
00487    *
00488    * @param k Species number: this is a require parameter,
00489    * a change from the ThermoPhase base class, where it was
00490    * an optional parameter.
00491    */ 
00492   doublereal IdealSolidSolnPhase::
00493   standardConcentration(int k) const {
00494     switch (m_formGC) {
00495     case 0:
00496       return 1.0;
00497     case 1:
00498       return 1.0 / m_speciesMolarVolume[k];
00499     case 2:
00500       return 1.0/m_speciesMolarVolume[m_kk-1];
00501     }
00502     return 0.0;
00503   }
00504   doublereal IdealSolidSolnPhase::
00505   referenceConcentration(int k) const {
00506     switch (m_formGC) {
00507     case 0:
00508       return 1.0;
00509     case 1:
00510       return 1.0 / m_speciesMolarVolume[k];
00511     case 2:
00512       return 1.0 / m_speciesMolarVolume[m_kk-1];
00513     }
00514     return 0.0;
00515   }
00516 
00517   /*********************************************************************
00518    *
00519    * logStandardConc()
00520    *
00521    * Returns the log of the standard concentration
00522    *
00523    * @param k Species number: this is a require parameter,
00524    * a change from the ThermoPhase base class, where it was
00525    * an optional parameter.
00526    */ 
00527   doublereal IdealSolidSolnPhase::
00528   logStandardConc(int k) const {
00529     _updateThermo();
00530     double res;
00531     switch (m_formGC) {
00532     case 0:
00533       res = 0.0;
00534       break;
00535     case 1:
00536       res = log(1.0/m_speciesMolarVolume[k]);
00537       break;
00538     case 2:
00539       res =  log(1.0/m_speciesMolarVolume[m_kk-1]);
00540       break;
00541     default:
00542       throw CanteraError("eosType", "Unknown type");
00543       break;
00544     }
00545     return res;
00546   }
00547 
00548   /***********************************************************************
00549    *
00550    * getUnitsStandardConcentration()
00551    *
00552    * Returns the units of the standard and general concentrations
00553    * Note they have the same units, as their divisor is 
00554    * defined to be equal to the activity of the kth species
00555    * in the solution, which is unitless.
00556    *
00557    * This routine is used in print out applications where the
00558    * units are needed. Usually, MKS units are assumed throughout
00559    * the program and in the XML input files.
00560    *
00561    *  uA[0] = kmol units - default  = 1
00562    *  uA[1] = m    units - default  = -nDim(), the number of spatial
00563    *                                dimensions in the Phase class.
00564    *  uA[2] = kg   units - default  = 0;
00565    *  uA[3] = Pa(pressure) units - default = 0;
00566    *  uA[4] = Temperature units - default = 0;
00567    *  uA[5] = time units - default = 0
00568    *
00569    *  For EOS types other than cIdealSolidSolnPhase1, the default
00570    *  kmol/m3 holds for standard concentration units. For
00571    *  cIdealSolidSolnPhase0 type, the standard concentrtion is
00572    *  unitless.
00573    */
00574   void IdealSolidSolnPhase::
00575   getUnitsStandardConc(double *uA, int, int sizeUA) const {
00576     int eos = eosType();
00577     if (eos == cIdealSolidSolnPhase0) {
00578       for (int i = 0; i < sizeUA; i++) {
00579         uA[i] = 0.0;
00580       }
00581     } else {
00582       for (int i = 0; i < sizeUA; i++) {
00583         if (i == 0) uA[0] = 1.0;
00584         if (i == 1) uA[1] = -nDim();
00585         if (i == 2) uA[2] = 0.0;
00586         if (i == 3) uA[3] = 0.0;
00587         if (i == 4) uA[4] = 0.0;
00588         if (i == 5) uA[5] = 0.0;
00589       }
00590     }
00591   }
00592 
00593   /*
00594    * getActivityCoefficients():
00595    *
00596    */
00597   void IdealSolidSolnPhase::
00598   getActivityCoefficients(doublereal *ac) const {
00599     for (int k = 0; k < m_kk; k++) {
00600       ac[k] = 1.0;
00601     } 
00602   }
00603   //================================================================================================
00604   /*
00605    *
00606    * getChemPotentials():
00607    *
00608    * This function returns a vector of chemical potentials of the 
00609    * species.
00610    * \f[
00611    *    \mu_k = \mu^o_k(T) + V_k * (p - p_o) + R T ln(X_k)
00612    * \f]
00613    *  or another way to phrase this is
00614    * \f[
00615    *    \mu_k = \mu^o_k(T,p) + R T ln(X_k) 
00616    * \f]
00617    *  where \f$ \mu^o_k(T,p) = \mu^o_k(T) + V_k * (p - p_o)\f$
00618    * 
00619    */
00620   void IdealSolidSolnPhase::
00621   getChemPotentials(doublereal* mu) const {
00622     doublereal delta_p = m_Pcurrent - m_Pref;
00623     doublereal xx;
00624     doublereal RT = temperature() * GasConstant;
00625     const array_fp& g_RT = gibbs_RT_ref();
00626     for (int k = 0; k < m_kk; k++) {
00627       xx = fmaxx(SmallNumber, moleFraction(k));
00628       mu[k] = RT * (g_RT[k] + log(xx))
00629         + delta_p * m_speciesMolarVolume[k];
00630     }
00631   }
00632   //================================================================================================
00633   /*
00634    *
00635    * getChemPotentials_RT()
00636    *
00637    * Get the array of non-dimensional chemical potentials \f$
00638    * \mu_k / \hat R T \f$, where
00639    *
00640    * \f[
00641    *    \mu_k = \mu^o_k(T) + V_k * (p - p_o) + R T ln(X_k) 
00642    * \f]
00643    *  or another way to phrase this is
00644    * \f[
00645    *    \mu_k = \mu^o_k(T,p) + R T ln(X_k) 
00646    * \f]
00647    *  where \f$ \mu^o_k(T,p) = \mu^o_k(T) + V_k * (p - p_o)\f$
00648    *  
00649    */
00650   void IdealSolidSolnPhase::
00651   getChemPotentials_RT(doublereal* mu) const {
00652     doublereal RT = temperature() * GasConstant;
00653     doublereal delta_pdRT = (m_Pcurrent - m_Pref) / RT;
00654     doublereal xx;
00655     const array_fp& g_RT = gibbs_RT_ref();
00656     for (int k = 0; k < m_kk; k++) {
00657       xx = fmaxx(SmallNumber, moleFraction(k));
00658       mu[k] = (g_RT[k] + log(xx))
00659         + delta_pdRT * m_speciesMolarVolume[k];
00660     }
00661   }
00662 
00663   /********************************************************************
00664    *                    Partial Molar Properties
00665    ********************************************************************/
00666 
00667   /********************************************************************
00668    *
00669    * getPartialMolarEnthalpies()
00670    *
00671    * For this phase, the partial molar enthalpies are equal to the
00672    * pure species enthalpies.
00673    *  \f[
00674    * \hat h_k(T,P) = \sum_k X_k \hat h^0_k(T) + (p - p_{ref}) (\sum_k X_k \hat V^0_k)
00675    * \f]
00676    * The reference-state pure-species enthalpies at the reference 
00677    * pressure p_ref 
00678    * \f$ \hat h^0_k(T) \f$, are computed by the species thermodynamic 
00679    * property manager. They are polynomial functions of temperature.
00680    * @see SpeciesThermo 
00681    */
00682   void IdealSolidSolnPhase::
00683   getPartialMolarEnthalpies(doublereal* hbar) const {
00684     const array_fp& _h = enthalpy_RT_ref();
00685     doublereal rt = GasConstant * temperature();
00686     scale(_h.begin(), _h.end(), hbar, rt);
00687   }
00688 
00689   /********************************************************************
00690    *
00691    * getPartialMolarEntropies()
00692    *
00693    * Returns an array of partial molar entropies of the species in the
00694    * solution. Units: J/kmol.
00695    * For this phase, the partial molar entropies are equal to the
00696    * pure species entropies plus the ideal solution contribution.
00697    *  \f[
00698    * \bar s_k(T,P) =  \hat s^0_k(T) - R log(X_k)
00699    * \f]
00700    * The reference-state pure-species entropies,\f$ \hat s^0_k(T) \f$,
00701    * at the reference pressure, \f$ P_{ref} \f$,  are computed by the 
00702    * species thermodynamic 
00703    * property manager. They are polynomial functions of temperature.
00704    * @see SpeciesThermo
00705    */
00706   void IdealSolidSolnPhase::
00707   getPartialMolarEntropies(doublereal* sbar) const {
00708     const array_fp& _s = entropy_R_ref();
00709     doublereal r = GasConstant;
00710     doublereal xx;
00711     for (int k = 0; k < m_kk; k++) {
00712       xx = fmaxx(SmallNumber, moleFraction(k));
00713       sbar[k] = r * (_s[k] - log(xx));
00714     }
00715   }
00716 
00717   /********************************************************************
00718    *
00719    * getPartialMolarCp()
00720    *
00721    * For this phase, the partial molar heat capacities are equal
00722    * to the standard state heat capacities.
00723   
00724    */
00725   void IdealSolidSolnPhase::
00726   getPartialMolarCp(doublereal* cpbar) const {
00727     getCp_R(cpbar);
00728     for (int k = 0; k < m_kk; k++) {
00729       cpbar[k] *= GasConstant;
00730     }
00731   }
00732 
00733   /******************************************************************
00734    *
00735    *  getPartialMolarVolumes()
00736    *
00737    * returns an array of partial molar volumes of the species
00738    * in the solution. Units: m^3 kmol-1.
00739    *
00740    * For this solution, thepartial molar volumes are equal to the
00741    * constant species molar volumes.
00742    */  
00743   void IdealSolidSolnPhase::
00744   getPartialMolarVolumes(doublereal* vbar) const {
00745     getStandardVolumes(vbar);
00746   }
00747 
00748   /*****************************************************************
00749    *    Properties of the Standard State of the Species
00750    *    in the Solution
00751    *****************************************************************/
00752 
00753   /******************************************************************
00754    *
00755    * getPureGibbs()
00756    *
00757    * Get the Gibbs functions for the pure species
00758    * at the current <I>T</I> and <I>P</I> of the solution.
00759    * We assume an incompressible constant partial molar
00760    * volume here:
00761    * \f[
00762    *  \mu^0_k(T,p) = \mu^{ref}_k(T) + (P - P_{ref}) * V_k
00763    * \f]
00764    * where \f$V_k\f$ is the molar volume of pure species <I>k<\I>.
00765    * \f$ u^{ref}_k(T)\f$ is the chemical potential of pure
00766    * species <I>k<\I> at the reference pressure, \f$P_{ref}\f$.
00767    */
00768   void IdealSolidSolnPhase::
00769   getPureGibbs(doublereal* gpure) const {
00770     const array_fp& gibbsrt = gibbs_RT_ref();
00771     doublereal RT = _RT();
00772     const doublereal * const gk = DATA_PTR(gibbsrt);
00773     doublereal delta_p = (m_Pcurrent - m_Pref);
00774     for (int k = 0; k < m_kk; k++) {
00775       gpure[k] = RT * gk[k] + delta_p * m_speciesMolarVolume[k];
00776     }
00777   }
00778 
00779   /**
00780    * Get the nondimensional gibbs function for the species
00781    * standard states at the current T and P of the solution.
00782    *
00783    *  \f[
00784    *  \mu^0_k(T,P) = \mu^{ref}_k(T) + (P - P_{ref}) * V_k
00785    * \f]
00786    * where \f$V_k\f$ is the molar volume of pure species <I>k</I>.
00787    * \f$ \mu^{ref}_k(T)\f$ is the chemical potential of pure
00788    * species <I>k</I> at the reference pressure, \f$P_{ref}\f$.
00789    *
00790    * @param grt Vector of length m_kk, which on return sr[k]
00791    *           will contain the nondimensional 
00792    *           standard state gibbs function for species k. 
00793    */
00794   void IdealSolidSolnPhase::
00795   getGibbs_RT(doublereal* grt) const {
00796     const array_fp& gibbsrt = gibbs_RT_ref();
00797     doublereal RT = _RT();
00798     const doublereal * const gk = DATA_PTR(gibbsrt);
00799     doublereal delta_prt = (m_Pcurrent - m_Pref)/ RT;
00800     for (int k = 0; k < m_kk; k++) {
00801       grt[k] = gk[k] + delta_prt * m_speciesMolarVolume[k];
00802     }
00803   }
00804 
00805   /********************************************************************
00806    *
00807    * getEnthalpy_RT()
00808    *
00809    * Get the array of nondimensional Enthalpy functions for the ss
00810    * species at the current <I>T</I> and <I>P</I> of the solution.
00811    * We assume an incompressible constant partial molar
00812    * volume here:
00813    * \f[
00814    *  h^0_k(T,P) = h^{ref}_k(T) + (P - P_{ref}) * V_k
00815    * \f]
00816    * where \f$V_k\f$ is the molar volume of pure species <I>k<\I>.
00817    * \f$ h^{ref}_k(T)\f$ is the enthalpy of the pure
00818    * species <I>k<\I> at the reference pressure, \f$P_{ref}\f$.
00819    */
00820   void IdealSolidSolnPhase::
00821   getEnthalpy_RT(doublereal* hrt) const {
00822     const array_fp& _h = enthalpy_RT_ref();
00823     doublereal delta_prt = ((m_Pcurrent - m_Pref) / 
00824                             (GasConstant * temperature()));
00825     for (int k = 0; k < m_kk; k++) {
00826       hrt[k] = _h[k] + delta_prt * m_speciesMolarVolume[k];
00827     }
00828   }
00829 
00830   /**
00831    * Get the nondimensional Entropies for the species
00832    * standard states at the current T and P of the solution.
00833    *
00834    * Note, this is equal to the reference state entropies
00835    * due to the zero volume expansivity: 
00836    * i.e., (dS/dp)_T = (dV/dT)_P = 0.0
00837    *
00838    * @param sr Vector of length m_kk, which on return sr[k]
00839    *           will contain the nondimensional 
00840    *           standard state entropy of species k.  
00841    */
00842   void IdealSolidSolnPhase::getEntropy_R(doublereal* sr) const {
00843     const array_fp& _s = entropy_R_ref();
00844     copy(_s.begin(), _s.end(), sr);
00845   }
00846 
00847   /*
00848    *  Returns the vector of nondimensional
00849    *  internal Energies of the standard state at the current temperature
00850    *  of the solution and current pressure for each species.
00851    * \f[
00852    *  u^0_k(T,P) = h^{ref}_k(T)  - P_{ref} * V_k
00853    * \f]
00854    *
00855    *  The standard state internal energy is independent of 
00856    *  pressure in this equation of state.
00857    *  (inherited from ThermoPhase.h)
00858    */
00859   void IdealSolidSolnPhase::getIntEnergy_RT(doublereal *urt) const {
00860     const array_fp& _h = enthalpy_RT_ref();
00861     doublereal prefrt = m_Pref / (GasConstant * temperature());
00862     for (int k = 0; k < m_kk; k++) {
00863       urt[k] = _h[k] - prefrt * m_speciesMolarVolume[k];
00864     }
00865   }
00866 
00867   /*
00868    * Get the nondimensional heat capacity at constant pressure
00869    * function for the species
00870    * standard states at the current T and P of the solution.
00871    *
00872    *  \f[
00873    *  Cp^0_k(T,P) = Cp^{ref}_k(T)
00874    * \f]
00875    * where \f$V_k\f$ is the molar volume of pure species <I>k<\I>.
00876    * \f$ Cp^{ref}_k(T)\f$ is the constant pressure heat capacity
00877    * of species <I>k<\I> at the reference pressure, \f$P_{ref}\f$.
00878    *
00879    * @param cpr Vector of length m_kk, which on return cpr[k]
00880    *           will contain the nondimensional 
00881    *           constant pressure heat capacity for species k. 
00882    */
00883   void IdealSolidSolnPhase::getCp_R(doublereal* cpr) const {
00884     const array_fp& _cpr = cp_R_ref();
00885     copy(_cpr.begin(), _cpr.end(), cpr);
00886   }
00887 
00888   /*
00889    * Get the molar volumes of each species in their standard
00890    * states at the current
00891    * <I>T</I> and <I>P</I> of the solution.
00892    * units = m^3 / kmol
00893    */
00894   void IdealSolidSolnPhase::getStandardVolumes(doublereal *vol) const {
00895     copy(m_speciesMolarVolume.begin(),
00896          m_speciesMolarVolume.end(), vol);
00897   }
00898 
00899 
00900   /*********************************************************************
00901    *     Thermodynamic Values for the Species Reference States
00902    *********************************************************************/
00903 
00904   /*
00905    *  Returns the vector of non-dimensional Enthalpy function
00906    *  of the reference state at the current temperature
00907    *  of the solution and the reference pressure for the species.
00908    *  Units = unitless
00909    */
00910   void IdealSolidSolnPhase::getEnthalpy_RT_ref(doublereal *hrt) const {
00911     _updateThermo();
00912     for (int k = 0; k != m_kk; k++) {
00913       hrt[k] = m_h0_RT[k];
00914     }
00915   }
00916 
00917   /*
00918    *  Returns the vector of non-dimensional Gibbs function
00919    *  of the reference state at the current temperature
00920    *  of the solution and the reference pressure for the species.
00921    *  Units = unitless
00922    */
00923   void IdealSolidSolnPhase::getGibbs_RT_ref(doublereal *grt) const {
00924     _updateThermo();
00925     for (int k = 0; k != m_kk; k++) {
00926       grt[k] = m_g0_RT[k];
00927     }
00928   }
00929 
00930   /*
00931    *  Returns the vector of Gibbs function
00932    *  of the reference state at the current temperature
00933    *  of the solution and the reference pressure for the species.
00934    *  Units = J / kmol
00935    */
00936   void IdealSolidSolnPhase::getGibbs_ref(doublereal *g) const {
00937     _updateThermo();
00938     double tmp = GasConstant * temperature();
00939     for (int k = 0; k != m_kk; k++) {
00940       g[k] = tmp * m_g0_RT[k];
00941     }
00942   }
00943 
00944   /*
00945    *  Returns the vector of nondimensional
00946    *  internal Energies of the standard state at the current temperature
00947    *  of the solution and current pressure for each species.
00948    *  (inherited from ThermoPhase.h)
00949    */
00950   void IdealSolidSolnPhase::getIntEnergy_RT_ref(doublereal *urt) const {
00951     const array_fp& _h = enthalpy_RT_ref();
00952     doublereal prefrt = m_Pref / (GasConstant * temperature());
00953     for (int k = 0; k < m_kk; k++) {
00954       urt[k] = _h[k] - prefrt * m_speciesMolarVolume[k];
00955     }
00956   }
00957 
00958   /*
00959    *  Returns the vector of non-dimensional Entropy function
00960    *  of the reference state at the current temperature
00961    *  of the solution and the reference pressure for the species.
00962    *  Units = unitless
00963    */
00964   void IdealSolidSolnPhase::getEntropy_R_ref(doublereal *er) const {
00965     _updateThermo();
00966     for (int k = 0; k != m_kk; k++) {
00967       er[k] = m_s0_R[k];
00968     }
00969   }
00970 
00971   /*
00972    *  Returns the vector of non-dimensional Entropy function
00973    *  of the reference state at the current temperature
00974    *  of the solution and the reference pressure for the species.
00975    *  Units = unitless
00976    */
00977   void IdealSolidSolnPhase::getCp_R_ref(doublereal *cpr) const {
00978     _updateThermo();
00979     for (int k = 0; k != m_kk; k++) {
00980       cpr[k] = m_cp0_R[k];
00981     }
00982   }
00983     
00984   /*
00985    *  Returns a reference to the vector of nondimensional
00986    *  enthalpies of the reference state at the current temperature.
00987    *  Real reason for its existence is that it also checks
00988    *  to see if a recalculation of the reference thermodynamics
00989    *  functions needs to be done.
00990    */
00991   const array_fp& IdealSolidSolnPhase::enthalpy_RT_ref() const {
00992     _updateThermo();
00993     return m_h0_RT;
00994   }
00995 
00996   /*
00997    *  Returns a reference to the vector of nondimensional
00998    *  enthalpies of the reference state at the current temperature.
00999    *  Real reason for its existence is that it also checks
01000    *  to see if a recalculation of the reference thermodynamics
01001    *  functions needs to be done.
01002    */
01003   const array_fp& IdealSolidSolnPhase::expGibbs_RT_ref() const {
01004     _updateThermo();
01005     int k;
01006     for (k = 0; k != m_kk; k++) m_expg0_RT[k] = exp(m_g0_RT[k]);
01007     return m_expg0_RT;
01008   }
01009 
01010   /*
01011    *  Returns a reference to the vector of nondimensional
01012    *  enthalpies of the reference state at the current temperature.
01013    *  Real reason for its existence is that it also checks
01014    *  to see if a recalculation of the reference thermodynamics
01015    *  functions needs to be done.
01016    */
01017   const array_fp& IdealSolidSolnPhase::entropy_R_ref() const {
01018     _updateThermo();
01019     return m_s0_R;
01020   }
01021     
01022   /*********************************************************************
01023    *    Utility Functions
01024    *********************************************************************/
01025   /*
01026    * initThermo() function initializes the object for use.
01027    * 
01028    * Before its invokation, the class isn't ready for calculation.
01029    */
01030   void IdealSolidSolnPhase::initThermo() {
01031   }
01032 
01033   /*
01034    *   Import and initialize an IdealSolidSolnPhase phase 
01035    *   specification in an XML tree into the current object.
01036    *   Here we read an XML description of the phase.
01037    *   We import descriptions of the elements that make up the
01038    *   species in a phase.
01039    *   We import information about the species, including their
01040    *   reference state thermodynamic polynomials. We then freeze
01041    *   the state of the species.
01042    *
01043    *   This routine calls importPhase() to do most of its work.
01044    *   Then, importPhase() calls initThermoXML() to finish
01045    *   off the work.
01046    *
01047    * @param phaseNode This object must be the phase node of a
01048    *             complete XML tree
01049    *             description of the phase, including all of the
01050    *             species data. In other words while "phase" must
01051    *             point to an XML phase object, it must have
01052    *             sibling nodes "speciesData" that describe
01053    *             the species in the phase.
01054    * @param id   ID of the phase. If nonnull, a check is done
01055    *             to see if phaseNode is pointing to the phase
01056    *             with the correct id. 
01057    */
01058   void IdealSolidSolnPhase::
01059   constructPhaseXML(XML_Node& phaseNode, std::string id) {
01060     string subname = "IdealSolidSolnPhase::constructPhaseXML";
01061     if (id.size() > 0) {
01062       string idp = phaseNode.id();
01063       if (idp != id) {
01064         throw CanteraError(subname.c_str(), 
01065                            "phasenode and Id are incompatible");
01066       }
01067     }
01068 
01069     /*
01070      * Check on the thermo field. Must have:
01071      * <thermo model="IdealSolidSolution" />
01072      */
01073     if (phaseNode.hasChild("thermo")) {
01074       XML_Node& thNode = phaseNode.child("thermo");
01075       string mStringa = thNode.attrib("model");
01076       string mString = lowercase(mStringa);
01077       if (mString != "idealsolidsolution") {
01078         throw CanteraError(subname.c_str(),
01079                            "Unknown thermo model: " + mStringa);
01080       }
01081     } else {
01082       throw CanteraError(subname.c_str(),
01083                          "Unspecified thermo model");
01084     }
01085 
01086     /*
01087      * Form of the standard concentrations. Must have one of:
01088      * 
01089      *     <standardConc model="unity" />
01090      *     <standardConc model="molar_volume" />
01091      *     <standardConc model="solvent_volume" />
01092      */
01093     if (phaseNode.hasChild("standardConc")) {
01094       XML_Node& scNode = phaseNode.child("standardConc");
01095       string formStringa = scNode.attrib("model");
01096       string formString = lowercase(formStringa);
01097       if (formString == "unity") {
01098         m_formGC = 0;
01099       } else if (formString == "molar_volume") {
01100         m_formGC = 1;
01101       } else if (formString == "solvent_volume") {
01102         m_formGC = 2;
01103       } else {
01104         throw CanteraError(subname.c_str(),
01105                            "Unknown standardConc model: " + formStringa);
01106       }
01107     } else {
01108       throw CanteraError(subname.c_str(),
01109                          "Unspecified standardConc model");
01110     }
01111 
01112     bool m_ok = importPhase(phaseNode, this);
01113     if (!m_ok) {
01114       throw CanteraError(subname.c_str(),"importPhase failed "); 
01115     }
01116   }
01117 
01118   /*
01119    * Initialization of an IdealSolidSolnPhase phase using an
01120    * xml file
01121    *
01122    * This routine is a precursor to constructPhaseFile(XML_Node*)
01123    * routine, which does most of the work.
01124    *
01125    * @param infile XML file containing the description of the
01126    *        phase
01127    *
01128    * @param id  Optional parameter identifying the name of the
01129    *            phase. If none is given, the first XML
01130    *            phase element will be used.
01131    */
01132   void IdealSolidSolnPhase::
01133   constructPhaseFile(std::string inputFile, std::string id) {
01134     if (inputFile.size() == 0) {
01135       throw CanteraError("IdealSolidSolnPhase::constructPhaseFile",
01136                          "input file is null");
01137     }
01138     string path = findInputFile(inputFile);
01139     ifstream fin(path.c_str());
01140     if (!fin) {
01141       throw CanteraError("IdealSolidSolnPhase::constructPhaseFile","could not open "
01142                          +path+" for reading.");
01143     }
01144     /*
01145      * The phase object automatically constructs an XML object.
01146      * Use this object to store information.
01147      */
01148     XML_Node &phaseNode_XML = xml();
01149     XML_Node *fxml = new XML_Node();
01150     fxml->build(fin);
01151     XML_Node *fxml_phase = findXMLPhase(fxml, id);
01152     if (!fxml_phase) {
01153       throw CanteraError("IdealSolidSolnPhase::constructPhaseFile",
01154                          "ERROR: Can not find phase named " +
01155                          id + " in file named " + inputFile);
01156     }
01157     fxml_phase->copy(&phaseNode_XML);
01158         
01159     constructPhaseXML(*fxml_phase, id);
01160     delete fxml;
01161   }
01162 
01163   /*
01164    * @internal
01165    *   Import and initialize a ThermoPhase object
01166    *   using an XML tree.
01167    *   Here we read extra information about the XML description
01168    *   of a phase. Regular information about elements and species
01169    *   and their reference state thermodynamic information
01170    *   have already been read at this point.
01171    *   For example, we do not need to call this function for
01172    *   ideal gas equations of state.
01173    *   This function is called from importPhase()
01174    *   after the elements and the
01175    *   species are initialized with default ideal solution
01176    *   level data.
01177    *
01178    * @param phaseNode This object must be the phase node of a
01179    *             complete XML tree
01180    *             description of the phase, including all of the
01181    *             species data. In other words while "phase" must
01182    *             point to an XML phase object, it must have
01183    *             sibling nodes "speciesData" that describe
01184    *             the species in the phase.
01185    * @param id   ID of the phase. If nonnull, a check is done
01186    *             to see if phaseNode is pointing to the phase
01187    *             with the correct id.
01188    */
01189   void IdealSolidSolnPhase::initThermoXML(XML_Node& phaseNode, std::string id) {
01190     string subname = "IdealSolidSolnPhase::initThermoXML";
01191     /*
01192      * Check on the thermo field. Must have:
01193      * <thermo model="IdealSolidSolution" />
01194      */
01195     if (phaseNode.hasChild("thermo")) {
01196       XML_Node& thNode = phaseNode.child("thermo");
01197       string mStringa = thNode.attrib("model");
01198       string mString = lowercase(mStringa);
01199       if (mString != "idealsolidsolution") {
01200         throw CanteraError(subname.c_str(),
01201                            "Unknown thermo model: " + mStringa);
01202       }
01203     } else {
01204       throw CanteraError(subname.c_str(),
01205                          "Unspecified thermo model");
01206     }
01207 
01208     /*
01209      * Form of the standard concentrations. Must have one of:
01210      * 
01211      *     <standardConc model="unity" />
01212      *     <standardConc model="molar_volume" />
01213      *     <standardConc model="solvent_volume" />
01214      */
01215     if (phaseNode.hasChild("standardConc")) {
01216       XML_Node& scNode = phaseNode.child("standardConc");
01217       string formStringa = scNode.attrib("model");
01218       string formString = lowercase(formStringa);
01219       if (formString == "unity") {
01220         m_formGC = 0;
01221       } else if (formString == "molar_volume") {
01222         m_formGC = 1;
01223       } else if (formString == "solvent_volume") {
01224         m_formGC = 2;
01225       } else {
01226         throw CanteraError(subname.c_str(),
01227                            "Unknown standardConc model: " + formStringa);
01228       }
01229     } else {
01230       throw CanteraError(subname.c_str(),
01231                          "Unspecified standardConc model");
01232     }
01233 
01234     /*
01235      * Initialize all of the lengths now that we know how many species
01236      * there are in the phase.
01237      */
01238     initLengths();
01239     /*
01240      * Now go get the molar volumes
01241      */
01242     XML_Node& speciesList = phaseNode.child("speciesArray");
01243     XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"],
01244                                          &phaseNode.root());
01245     const vector<string>&sss = speciesNames();
01246 
01247     for (int k = 0; k < m_kk; k++) {
01248       XML_Node* s =  speciesDB->findByAttr("name", sss[k]);
01249       XML_Node *ss = s->findByName("standardState");
01250       m_speciesMolarVolume[k] = getFloat(*ss, "molarVolume", "toSI");
01251     }
01252 
01253     /*
01254      * Call the base initThermo, which handles setting the initial
01255      * state.
01256      */
01257     ThermoPhase::initThermoXML(phaseNode, id);
01258   }
01259 
01260   /*
01261    * This internal function adjusts the lengths of arrays
01262    */
01263   void IdealSolidSolnPhase::
01264   initLengths() {
01265     m_kk = nSpecies();
01266     m_mm = nElements();
01267 
01268     /*
01269      * Obtain the limits of the temperature from the species
01270      * thermo handler's limits.
01271      */
01272     doublereal tmin = m_spthermo->minTemp();
01273     doublereal tmax = m_spthermo->maxTemp();
01274     if (tmin > 0.0) m_tmin = tmin;
01275     if (tmax > 0.0) m_tmax = tmax;
01276 
01277     /*
01278      * Obtain the reference pressure by calling the ThermoPhase
01279      * function refPressure, which in turm calls the
01280      * species thermo reference pressure function of the
01281      * same name.
01282      */
01283     m_Pref = refPressure();
01284 
01285     int leng = m_kk;
01286     m_h0_RT.resize(leng);
01287     m_g0_RT.resize(leng);
01288     m_expg0_RT.resize(leng);
01289     m_cp0_R.resize(leng);
01290     m_s0_R.resize(leng);
01291     m_pe.resize(leng, 0.0);
01292     m_pp.resize(leng);
01293     m_speciesMolarVolume.resize(leng);
01294   }
01295 
01296   /*
01297    * Set mixture to an equilibrium state consistent with specified 
01298    * element potentials and temperature.
01299    *
01300    * @param lambda_RT vector of non-dimensional element potentials
01301    * \f$ \lambda_m/RT \f$.
01302    *
01303    */
01304   void IdealSolidSolnPhase::
01305   setToEquilState(const doublereal* lambda_RT) 
01306   {
01307     const array_fp& grt = gibbs_RT_ref();
01308 
01309     // set the pressure and composition to be consistent with
01310     // the temperature, 
01311     doublereal pres = 0.0;
01312     for (int k = 0; k < m_kk; k++) {
01313       m_pp[k] = -grt[k];
01314       for (int m = 0; m < m_mm; m++) {
01315         m_pp[k] += nAtoms(k,m)*lambda_RT[m];
01316       }
01317       m_pp[k] = m_Pref * exp(m_pp[k]);
01318       pres += m_pp[k];
01319     }
01320     doublereal *dptr = DATA_PTR(m_pp);
01321     setState_PX(pres, dptr);
01322   }
01323   //================================================================================================
01324   /*
01325    *
01326    * speciesMolarVolume()
01327    *
01328    * Report the molar volume of species k
01329    *
01330    * units - \f$ m^3 kmol^-1 \f$
01331    */
01332   double IdealSolidSolnPhase::
01333   speciesMolarVolume(int k) const
01334   {
01335     return  m_speciesMolarVolume[k];
01336   }
01337     
01338   /*
01339    *
01340    * getSpeciesMolarVolumes():
01341    *
01342    * Fill in a return vector containing the species molar volumes
01343    * units - \f$ m^3 kmol^-1 \f$
01344    */
01345   void IdealSolidSolnPhase::
01346   getSpeciesMolarVolumes(doublereal *smv) const
01347   {
01348     copy(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), smv);
01349   }
01350   //================================================================================================
01351   /*
01352    *
01353    * _updateThermo()
01354    *
01355    * This function gets called for every call to functions in this
01356    * class. It checks to see whether the temperature has changed and
01357    * thus the reference thermodynamics functions for all of the species
01358    * must be recalculated.
01359    * If the temperature has changed, the species thermo manager is called
01360    * to recalculate G, Cp, H, and S at the current temperature.
01361    */
01362   void IdealSolidSolnPhase::
01363   _updateThermo() const {
01364     doublereal tnow = temperature();
01365     if (m_tlast != tnow) {
01366       /*
01367        * Update the thermodynamic functions of the reference state.
01368        */
01369       m_spthermo->update(tnow, DATA_PTR(m_cp0_R), DATA_PTR(m_h0_RT), 
01370                          DATA_PTR(m_s0_R));
01371       m_tlast = tnow;
01372       doublereal rrt = 1.0 / (GasConstant * tnow);
01373       int k;
01374       doublereal deltaE;
01375       for (k = 0; k < m_kk; k++) {
01376         deltaE = rrt * m_pe[k];
01377         m_h0_RT[k] += deltaE;
01378         m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
01379       }
01380       m_tlast = tnow;
01381     }
01382   }
01383   //================================================================================================
01384 }  // end namespace Cantera
01385 //==================================================================================================
Generated by  doxygen 1.6.3