MolalityVPSSTP.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file MolalityVPSSTP.cpp
00003  *   Definitions for intermediate ThermoPhase object for phases which
00004  *   employ molality based activity coefficient formulations
00005  *  (see \ref thermoprops 
00006  * and class \link Cantera::MolalityVPSSTP MolalityVPSSTP\endlink).
00007  *
00008  * Header file for a derived class of ThermoPhase that handles
00009  * variable pressure standard state methods for calculating
00010  * thermodynamic properties that are further based upon activities
00011  * based on the molality scale.  These include most of the methods for
00012  * calculating liquid electrolyte thermodynamics.
00013  */
00014 /*
00015  * Copywrite (2005) Sandia Corporation. Under the terms of 
00016  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
00017  * U.S. Government retains certain rights in this software.
00018  */
00019 /*
00020  *  $Author: hkmoffa $
00021  *  $Date: 2009-12-05 14:08:43 -0500 (Sat, 05 Dec 2009) $
00022  *  $Revision: 279 $
00023  */
00024 
00025 
00026 #include "MolalityVPSSTP.h"
00027 using namespace std;
00028 
00029 namespace Cantera {
00030 
00031   /*
00032    * Default constructor.
00033    *
00034    * This doesn't do much more than initialize constants with
00035    * default values for water at 25C. Water molecular weight 
00036    * comes from the default elements.xml file. It actually
00037    * differs slightly from the IAPWS95 value of 18.015268. However,
00038    * density conservation and therefore element conservation
00039    * is the more important principle to follow.
00040    */
00041   MolalityVPSSTP::MolalityVPSSTP() :
00042     VPStandardStateTP(),
00043     m_indexSolvent(0),
00044     m_pHScalingType(PHSCALE_PITZER),
00045     m_indexCLM(-1),
00046     m_weightSolvent(18.01528),
00047     m_xmolSolventMIN(0.01),
00048     m_Mnaught(18.01528E-3)
00049   {
00050     /*
00051      * Change the default to be that charge neutrality in the
00052      * phase is necessary condition for the proper specification
00053      * of thermodynamic functions within the phase
00054      */
00055     m_chargeNeutralityNecessary = true;
00056   }
00057 
00058   /*
00059    * Copy Constructor:
00060    *
00061    *  Note this stuff will not work until the underlying phase
00062    *  has a working copy constructor
00063    */
00064   MolalityVPSSTP::MolalityVPSSTP(const MolalityVPSSTP &b) :
00065     VPStandardStateTP(),
00066     m_indexSolvent(b.m_indexSolvent),
00067     m_pHScalingType(b.m_pHScalingType),
00068     m_indexCLM(b.m_indexCLM),
00069     m_xmolSolventMIN(b.m_xmolSolventMIN),
00070     m_Mnaught(b.m_Mnaught),
00071     m_molalities(b.m_molalities)
00072   {
00073     *this = operator=(b);
00074   }
00075 
00076   /*
00077    * operator=()
00078    *
00079    *  Note this stuff will not work until the underlying phase
00080    *  has a working assignment operator
00081    */
00082   MolalityVPSSTP& MolalityVPSSTP::
00083   operator=(const MolalityVPSSTP &b) {
00084     if (&b != this) {
00085       VPStandardStateTP::operator=(b);
00086       m_indexSolvent     = b.m_indexSolvent;
00087       m_pHScalingType    = b.m_pHScalingType;
00088       m_indexCLM         = b.m_indexCLM;
00089       m_weightSolvent    = b.m_weightSolvent;
00090       m_xmolSolventMIN   = b.m_xmolSolventMIN;
00091       m_Mnaught          = b.m_Mnaught;
00092       m_molalities       = b.m_molalities;
00093     }
00094     return *this;
00095   }
00096 
00097   /**
00098    *
00099    * ~MolalityVPSSTP():   (virtual)
00100    *
00101    * Destructor: does nothing:
00102    *
00103    */
00104   MolalityVPSSTP::~MolalityVPSSTP() {
00105   }
00106 
00107   /*
00108    * This routine duplicates the current object and returns
00109    * a pointer to ThermoPhase.
00110    */
00111   ThermoPhase* 
00112   MolalityVPSSTP::duplMyselfAsThermoPhase() const {
00113     MolalityVPSSTP* mtp = new MolalityVPSSTP(*this);
00114     return (ThermoPhase *) mtp;
00115   }
00116 
00117   /*
00118    *  -------------- Utilities -------------------------------
00119    */
00120 
00121   // Equation of state type flag.
00122   /*
00123    * The ThermoPhase base class returns
00124    * zero. Subclasses should define this to return a unique
00125    * non-zero value. Known constants defined for this purpose are
00126    * listed in mix_defs.h. The MolalityVPSSTP class also returns
00127    * zero, as it is a non-complete class.
00128    */
00129   int MolalityVPSSTP::eosType() const { 
00130     return 0;
00131   }
00132 
00133   // Set the pH scale, which determines the scale for single-ion activity 
00134   // coefficients.
00135   /*
00136    *  Single ion activity coefficients are not unique in terms of the
00137    *  representing actual measureable quantities. 
00138    */
00139   void MolalityVPSSTP::setpHScale(const int pHscaleType) {
00140     m_pHScalingType = pHscaleType;
00141     if (pHscaleType !=  PHSCALE_PITZER && pHscaleType !=  PHSCALE_NBS) {
00142       throw CanteraError("MolalityVPSSTP::setpHScale",
00143                          "Unknown scale type: " + int2str(pHscaleType));
00144     }
00145   }
00146 
00147   // Reports the pH scale, which determines the scale for single-ion activity 
00148   // coefficients.
00149   /*
00150    *  Single ion activity coefficients are not unique in terms of the
00151    *  representing actual measureable quantities. 
00152    */
00153   int MolalityVPSSTP::pHScale() const {
00154     return m_pHScalingType;
00155   }
00156 
00157   /*
00158    * setSolvent():
00159    *  Utilities for Solvent ID and Molality 
00160    *  Here we also calculate and store the molecular weight
00161    *  of the solvent and the m_Mnaught parameter.
00162    *  @param k index of the solvent.
00163    */
00164   void MolalityVPSSTP::setSolvent(int k) {
00165     if (k < 0 || k >= m_kk) {
00166       throw CanteraError("MolalityVPSSTP::setSolute ", 
00167                          "bad value");
00168     }
00169     m_indexSolvent = k;
00170     AssertThrowMsg(m_indexSolvent==0, "MolalityVPSSTP::setSolvent",
00171                    "Molality-based methods limit solvent id to being 0"); 
00172     m_weightSolvent = molecularWeight(k);
00173     m_Mnaught = m_weightSolvent / 1000.;
00174   }
00175     
00176   /*
00177    * return the solvent id index number.
00178    */
00179   int MolalityVPSSTP::solventIndex() const {
00180     return m_indexSolvent;
00181   }
00182 
00183   /*
00184    * Sets the minimum mole fraction in the molality formulation. The
00185    * minimum mole fraction must be in the range 0 to 0.9.
00186    */
00187   void  MolalityVPSSTP::
00188   setMoleFSolventMin(doublereal xmolSolventMIN) {
00189     if (xmolSolventMIN <= 0.0) {
00190       throw CanteraError("MolalityVPSSTP::setSolute ", "trouble");
00191     } else if (xmolSolventMIN > 0.9) {
00192       throw CanteraError("MolalityVPSSTP::setSolute ", "trouble");
00193     }
00194     m_xmolSolventMIN = xmolSolventMIN;
00195   }
00196 
00197   /**
00198    * Returns the minimum mole fraction in the molality formulation.
00199    */
00200   doublereal MolalityVPSSTP::moleFSolventMin() const {
00201     return m_xmolSolventMIN;
00202   }
00203 
00204   /*
00205    * calcMolalities():
00206    *   We calculate the vector of molalities of the species
00207    *   in the phase and store the result internally:
00208    * \f[
00209    *     m_i = (n_i) / (1000 * M_o * n_{o,p})
00210    * \f]
00211    *    where 
00212    *    - \f$ M_o \f$ is the molecular weight of the solvent
00213    *    - \f$ n_o \f$ is the mole fraction of the solvent
00214    *    - \f$ n_i \f$ is the mole fraction of the solute.
00215    *    - \f$ n_{o,p} = max (n_{o, min}, n_o) \f$
00216    *    - \f$ n_{o,min} \f$ = minimum mole fraction of solvent allowed
00217    *              in the denominator.
00218    */
00219   void MolalityVPSSTP::calcMolalities() const {
00220     getMoleFractions(DATA_PTR(m_molalities));
00221     double xmolSolvent = m_molalities[m_indexSolvent];
00222     if (xmolSolvent < m_xmolSolventMIN) {
00223       xmolSolvent = m_xmolSolventMIN;
00224     }
00225     double denomInv = 1.0/ (m_Mnaught * xmolSolvent);
00226     for (int k = 0; k < m_kk; k++) {
00227       m_molalities[k] *= denomInv;
00228     }
00229   }
00230 
00231   /*
00232    * getMolalities():
00233    *   We calculate the vector of molalities of the species
00234    *   in the phase
00235    * \f[
00236    *     m_i = (n_i) / (1000 * M_o * n_{o,p})
00237    * \f]
00238    *    where 
00239    *    - \f$ M_o \f$ is the molecular weight of the solvent
00240    *    - \f$ n_o \f$ is the mole fraction of the solvent
00241    *    - \f$ n_i \f$ is the mole fraction of the solute.
00242    *    - \f$ n_{o,p} = max (n_{o, min}, n_o) \f$
00243    *    - \f$ n_{o,min} \f$ = minimum mole fraction of solvent allowed
00244    *              in the denominator.
00245    */
00246   void MolalityVPSSTP::getMolalities(doublereal * const molal) const {
00247     calcMolalities();
00248     for (int k = 0; k < m_kk; k++) {
00249       molal[k] = m_molalities[k];
00250     }
00251   }
00252 
00253   /*
00254    * setMolalities():
00255    *   We are supplied with the molalities of all of the
00256    *   solute species. We then calculate the mole fractions of all
00257    *   species and update the ThermoPhase object.
00258    *
00259    *     m_i = (n_i) / (W_o/1000 * n_o_p)
00260    *
00261    *    where M_o is the molecular weight of the solvent
00262    *    n_o is the mole fraction of the solvent
00263    *    n_i is the mole fraction of the solute.
00264    *    n_o_p = max (n_o_min, n_o)
00265    *    n_o_min = minimum mole fraction of solvent allowed
00266    *              in the denominator.
00267    */
00268   void MolalityVPSSTP::setMolalities(const doublereal * const molal) {
00269         
00270     double Lsum = 1.0 / m_Mnaught;
00271     for (int k = 1; k < m_kk; k++) {
00272       m_molalities[k] = molal[k];
00273       Lsum += molal[k];
00274     }
00275     double tmp = 1.0 / Lsum;
00276     m_molalities[m_indexSolvent] = tmp / m_Mnaught;
00277     double sum = m_molalities[m_indexSolvent];
00278     for (int k = 1; k < m_kk; k++) {
00279       m_molalities[k] = tmp * molal[k];
00280       sum += m_molalities[k];
00281     }
00282     if (sum != 1.0) {
00283       tmp = 1.0 / sum;
00284       for (int k = 0; k < m_kk; k++) {
00285         m_molalities[k] *= tmp;
00286       }
00287     }
00288     setMoleFractions(DATA_PTR(m_molalities));
00289     /*
00290      * Essentially we don't trust the input: We calculate
00291      * the molalities from the mole fractions that we 
00292      * just obtained.
00293      */
00294     calcMolalities();
00295   }
00296     
00297   /*
00298    * setMolalitiesByName()
00299    *
00300    *  This routine sets the molalities by name
00301    *  HKM -> Might need to be more complicated here, setting
00302    *         neutrals so that the existing mole fractions are
00303    *         preserved.
00304    */
00305   void MolalityVPSSTP::setMolalitiesByName(compositionMap& mMap) {
00306     int kk = nSpecies();
00307     doublereal x;
00308     /*
00309      * Get a vector of mole fractions
00310      */
00311     vector_fp mf(kk, 0.0);
00312     getMoleFractions(DATA_PTR(mf));
00313     double xmolS = mf[m_indexSolvent];
00314     double xmolSmin = max(xmolS, m_xmolSolventMIN);
00315     compositionMap::iterator p;
00316     for (int k = 0; k < kk; k++) {
00317       p = mMap.find(speciesName(k));
00318       if (p != mMap.end()) {
00319         x = mMap[speciesName(k)];
00320         if (x > 0.0) {
00321           mf[k] = x * m_Mnaught * xmolSmin;
00322         }
00323       }
00324     }
00325     /*
00326      * check charge neutrality
00327      */
00328     int largePos = -1;
00329     double cPos = 0.0;
00330     int largeNeg = -1;
00331     double cNeg = 0.0;
00332     double sum = 0.0;
00333     for (int k = 0; k < kk; k++) {
00334       double ch = charge(k);
00335       if (mf[k] > 0.0) {
00336         if (ch > 0.0) {
00337           if (ch * mf[k] > cPos) {
00338             largePos = k;
00339             cPos = ch * mf[k];
00340           }
00341         }
00342         if (ch < 0.0) {
00343           if (fabs(ch) * mf[k] > cNeg) {
00344             largeNeg = k;
00345             cNeg = fabs(ch) * mf[k];
00346           }
00347         }
00348       }
00349       sum += mf[k] * ch;
00350     }
00351     if (sum != 0.0) {
00352       if (sum > 0.0) {
00353         if (cPos > sum) {
00354           mf[largePos] -= sum / charge(largePos);
00355         } else {
00356           throw CanteraError("MolalityVPSSTP:setMolalitiesbyName",
00357                              "unbalanced charges");
00358         }
00359       } else {
00360         if (cNeg > (-sum)) {
00361           mf[largeNeg] -= (-sum) / fabs(charge(largeNeg));
00362         } else {
00363           throw CanteraError("MolalityVPSSTP:setMolalitiesbyName",
00364                              "unbalanced charges");
00365         }
00366       }
00367             
00368     }
00369     sum = 0.0;
00370     for (int k = 0; k < kk; k++) {
00371       sum += mf[k];
00372     }
00373     sum = 1.0/sum;
00374     for (int k = 0; k < kk; k++) {
00375       mf[k] *= sum;
00376     }
00377     setMoleFractions(DATA_PTR(mf));
00378     /*
00379      * After we formally set the mole fractions, we
00380      * calculate the molalities again and store it in
00381      * this object.
00382      */
00383     calcMolalities();
00384   }
00385 
00386   /*
00387    * setMolalitiesByNames()
00388    *
00389    *   Set the molalities of the solutes by name
00390    */
00391   void MolalityVPSSTP::setMolalitiesByName(const std::string& x) {
00392     compositionMap xx;
00393     int kk = nSpecies();
00394     for (int k = 0; k < kk; k++) {
00395       xx[speciesName(k)] = -1.0;
00396     }
00397     parseCompString(x, xx);
00398     setMolalitiesByName(xx);
00399   }
00400 
00401 
00402   /*
00403    * ------------ Molar Thermodynamic Properties ----------------------
00404    */
00405 
00406 
00407   /*
00408    * - Activities, Standard States, Activity Concentrations -----------
00409    */
00410 
00411   /*
00412    * This method returns the activity convention.
00413    * Currently, there are two activity conventions
00414    *  Molar-based activities
00415    *       Unit activity of species at either a hypothetical pure
00416    *       solution of the species or at a hypothetical
00417    *       pure ideal solution at infinite dilution
00418    *   cAC_CONVENTION_MOLAR 0
00419    *      - default
00420    *  
00421    *  Molality based activities
00422    *       (unit activity of solutes at a hypothetical 1 molal
00423    *        solution referenced to infinite dilution at all
00424    *        pressures and temperatures).
00425    *       (solvent is still on molar basis).
00426    *   cAC_CONVENTION_MOLALITY 1
00427    *
00428    *  We set the convention to molality here.
00429    */
00430   int MolalityVPSSTP::activityConvention() const {
00431     return cAC_CONVENTION_MOLALITY;
00432   }
00433 
00434   void MolalityVPSSTP::getActivityConcentrations(doublereal* c) const {
00435       err("getActivityConcentrations");
00436   }
00437 
00438   doublereal MolalityVPSSTP::standardConcentration(int k) const {
00439     err("standardConcentration");
00440     return -1.0;
00441   }
00442 
00443   doublereal MolalityVPSSTP::logStandardConc(int k) const {
00444     err("logStandardConc");
00445     return -1.0;
00446   }
00447 
00448   void MolalityVPSSTP::getActivities(doublereal* ac) const {
00449     err("getActivities");
00450   }
00451 
00452   /*
00453    * Get the array of non-dimensional activity coefficients at
00454    * the current solution temperature, pressure, and
00455    * solution concentration.
00456    * These are mole fraction based activity coefficients. In this
00457    * object, their calculation is based on translating the values
00458    * of Molality based activity coefficients.
00459    *  See Denbigh p. 278 for a thorough discussion.
00460    *
00461    * Note, the solvent is treated differently. getMolalityActivityCoeff()
00462    * returns the molar based solvent activity coefficient already.
00463    * Therefore, we do not have to divide by x_s here.
00464    */
00465   void MolalityVPSSTP::getActivityCoefficients(doublereal* ac) const {
00466     getMolalityActivityCoefficients(ac);
00467     AssertThrow(m_indexSolvent==0, "MolalityVPSSTP::getActivityCoefficients");
00468     double xmolSolvent = moleFraction(m_indexSolvent);
00469     if (xmolSolvent < m_xmolSolventMIN) {
00470       xmolSolvent = m_xmolSolventMIN;
00471     }
00472     for (int k = 1; k < m_kk; k++) {
00473       ac[k] /= xmolSolvent;
00474     }
00475   }
00476 
00477   // Get the array of non-dimensional molality based 
00478   //  activity coefficients at the current solution temperature, 
00479   //  pressure, and  solution concentration.
00480   /*
00481    *  See Denbigh p. 278 for a thorough discussion. This class must be overwritten in
00482    *  classes which derive from %MolalityVPSSTP. This function takes over from the
00483    *  molar-based activity coefficient calculation, getActivityCoefficients(), in
00484    *  derived classes.
00485    *
00486    *  Note these activity coefficients have the current pH scale applied to them.
00487    *
00488    * @param acMolality Output vector containing the molality based activity coefficients.
00489    *                   length: m_kk.
00490    */
00491   void MolalityVPSSTP::getMolalityActivityCoefficients(doublereal *acMolality) const {
00492     getUnscaledMolalityActivityCoefficients(acMolality);
00493     applyphScale(acMolality);
00494   }
00495   
00496   /*
00497    * osmotic coefficient:
00498    * 
00499    *  Calculate the osmotic coefficient of the solvent. Note there
00500    *  are lots of definitions of the osmotic coefficient floating
00501    *  around. We use the one defined in the Pitzer's book:
00502    *  (Activity Coeff in Electrolyte Solutions, K. S. Pitzer
00503    *   CRC Press, Boca Raton, 1991, p. 85, Eqn. 28).
00504    *
00505    *        Definition:
00506    *         - sum(m_i) * Mnaught * oc = ln(activity_solvent)
00507    */
00508   doublereal MolalityVPSSTP::osmoticCoefficient() const {
00509     /*
00510      * First, we calculate the activities all over again
00511      */
00512     vector_fp act(m_kk);
00513     getActivities(DATA_PTR(act));
00514     /*
00515      * Then, we calculate the sum of the solvent molalities
00516      */
00517     double sum = 0;
00518     for (int k = 1; k < m_kk; k++) {
00519       sum += fmaxx(m_molalities[k], 0.0);
00520     }
00521     double oc = 1.0;
00522     double lac = log(act[m_indexSolvent]);
00523     if (sum > 1.0E-200) {
00524       oc = - lac / (m_Mnaught * sum);
00525     }
00526     return oc;
00527   }
00528 
00529 
00530   void MolalityVPSSTP::getElectrochemPotentials(doublereal* mu) const {
00531     getChemPotentials(mu);
00532     double ve = Faraday * electricPotential();
00533     for (int k = 0; k < m_kk; k++) {
00534       mu[k] += ve*charge(k);
00535     }
00536   }
00537   
00538   /*
00539    * ------------ Partial Molar Properties of the Solution ------------
00540    */
00541 
00542 
00543   doublereal MolalityVPSSTP::err(std::string msg) const {
00544     throw CanteraError("MolalityVPSSTP","Base class method "
00545                        +msg+" called. Equation of state type: "+int2str(eosType()));
00546     return 0;
00547   }
00548 
00549   /*
00550    * Returns the units of the standard and general concentrations
00551    * Note they have the same units, as their divisor is 
00552    * defined to be equal to the activity of the kth species
00553    * in the solution, which is unitless.
00554    *
00555    * This routine is used in print out applications where the
00556    * units are needed. Usually, MKS units are assumed throughout
00557    * the program and in the XML input files. 
00558    *
00559    * On return uA contains the powers of the units (MKS assumed)
00560    * of the standard concentrations and generalized concentrations
00561    * for the kth species.
00562    *
00563    *  uA[0] = kmol units - default  = 1
00564    *  uA[1] = m    units - default  = -nDim(), the number of spatial
00565    *                                dimensions in the Phase class.
00566    *  uA[2] = kg   units - default  = 0;
00567    *  uA[3] = Pa(pressure) units - default = 0;
00568    *  uA[4] = Temperature units - default = 0;
00569    *  uA[5] = time units - default = 0
00570    */
00571   void MolalityVPSSTP::getUnitsStandardConc(double *uA, int k, int sizeUA) const {
00572     for (int i = 0; i < sizeUA; i++) {
00573       if (i == 0) uA[0] = 1.0;
00574       if (i == 1) uA[1] = -nDim();
00575       if (i == 2) uA[2] = 0.0;
00576       if (i == 3) uA[3] = 0.0;
00577       if (i == 4) uA[4] = 0.0;
00578       if (i == 5) uA[5] = 0.0;
00579     }
00580   }
00581 
00582   void MolalityVPSSTP::setToEquilState(const doublereal* lambda_RT) {
00583     updateStandardStateThermo();
00584     err("setToEquilState");
00585   }
00586 
00587   /*
00588    * Set the thermodynamic state.
00589    */
00590   void MolalityVPSSTP::setStateFromXML(const XML_Node& state) {
00591     VPStandardStateTP::setStateFromXML(state);
00592     string comp = getChildValue(state,"soluteMolalities");
00593     if (comp != "") {
00594       setMolalitiesByName(comp);
00595     }
00596     if (state.hasChild("pressure")) {
00597       double p = getFloat(state, "pressure", "pressure");
00598       setPressure(p);
00599     }
00600   }
00601 
00602   /*
00603    * Set the temperature (K), pressure (Pa), and molalities
00604    * (gmol kg-1) of the solutes
00605    */
00606   void MolalityVPSSTP::setState_TPM(doublereal t, doublereal p, 
00607                                     const doublereal * const molalities) {
00608     setMolalities(molalities);
00609     setState_TP(t, p);
00610   }
00611 
00612   /*
00613    * Set the temperature (K), pressure (Pa), and molalities.
00614    */
00615   void MolalityVPSSTP::setState_TPM(doublereal t, doublereal p, compositionMap& m) {
00616     setMolalitiesByName(m);
00617     setState_TP(t, p);
00618   }
00619 
00620   /*
00621    * Set the temperature (K), pressure (Pa), and molality.  
00622    */
00623   void MolalityVPSSTP::setState_TPM(doublereal t, doublereal p, const std::string& m) {
00624     setMolalitiesByName(m);
00625     setState_TP(t, p);
00626   }
00627 
00628 
00629   /*
00630    * @internal Initialize. This method is provided to allow
00631    * subclasses to perform any initialization required after all
00632    * species have been added. For example, it might be used to
00633    * resize internal work arrays that must have an entry for
00634    * each species.  The base class implementation does nothing,
00635    * and subclasses that do not require initialization do not
00636    * need to overload this method.  When importing a CTML phase
00637    * description, this method is called just prior to returning
00638    * from function importPhase.
00639    *
00640    * @see importCTML.cpp
00641    */
00642   void MolalityVPSSTP::initThermo() {
00643     initLengths();
00644     VPStandardStateTP::initThermo();
00645 
00646     /*
00647      * The solvent defaults to species 0
00648      */
00649     setSolvent(0);
00650     /*
00651      * Find the Cl- species
00652      */
00653     m_indexCLM = findCLMIndex();
00654   }
00655 
00656   //  Get the array of unscaled non-dimensional molality based 
00657   //  activity coefficients at the current solution temperature, 
00658   //  pressure, and  solution concentration.
00659   /*
00660    *  See Denbigh p. 278 for a thorough discussion. This class must be overwritten in
00661    *  classes which derive from %MolalityVPSSTP. This function takes over from the
00662    *  molar-based activity coefficient calculation, getActivityCoefficients(), in
00663    *  derived classes.
00664    *
00665    * @param acMolality Output vector containing the molality based activity coefficients.
00666    *                   length: m_kk.
00667    */
00668   void MolalityVPSSTP::getUnscaledMolalityActivityCoefficients(doublereal *acMolality) const {
00669    err("getUnscaledMolalityActivityCoefficients");
00670   }
00671   
00672   //  Apply the current phScale to a set of activity Coefficients or activities
00673   /*
00674    *  See the Eq3/6 Manual for a thorough discussion.
00675    *
00676    * @param acMolality input/Output vector containing the molality based 
00677    *                   activity coefficients. length: m_kk.
00678    */
00679   void MolalityVPSSTP::applyphScale(doublereal *acMolality) const {
00680     err("applyphScale");
00681   }
00682   
00683   //  Returns the index of the Cl- species.
00684   /*
00685    *  The Cl- species is special in the sense that it's single ion
00686    *  molalality-based activity coefficient is used in the specification
00687    *  of the pH scale for single ions. Therefore, we need to know
00688    *  what species index Cl- is. If the species isn't in the species
00689    *  list then this routine returns -1, and we can't use the NBS
00690    *  pH scale. 
00691    *   
00692    *  Right now we use a restrictive interpretation. The species
00693    *  must be named "Cl-". It must consist of exactly one Cl and one E 
00694    *  atom. 
00695    */
00696   int MolalityVPSSTP::findCLMIndex() const {
00697     int indexCLM = -1;
00698     int eCl = -1;
00699     int eE = -1;
00700     int ne= nElements();
00701     string sn;
00702     for (int e = 0; e < ne; e++) {
00703       sn = elementName(e);
00704       if (sn == "Cl" || sn == "CL") {
00705         eCl = e;
00706         break;
00707       }
00708     }
00709     // We have failed if we can't find the Cl element index
00710     if (eCl == -1) {
00711       return -1;
00712     }
00713     for (int e = 0; e < ne; e++) {
00714       sn = elementName(e);
00715       if (sn == "E" || sn == "e") {
00716         eE = e;
00717         break;
00718       }
00719     }
00720     // We have failed if we can't find the E element index
00721     if (eE == -1) {
00722       return -1;
00723     }
00724     for (int k = 1; k < m_kk; k++) {
00725       doublereal nCl = nAtoms(k, eCl);
00726       if (nCl != 1.0) {
00727         continue;
00728       }
00729       doublereal nE = nAtoms(k, eE);
00730       if (nE != 1.0) {
00731         continue;
00732       }
00733       for (int e = 0; e < ne; e++) {
00734         if (e != eE && e != eCl) {
00735           doublereal nA = nAtoms(k, e);
00736           if (nA != 0.0) {
00737             continue;
00738           }
00739         }
00740       }
00741       sn = speciesName(k);
00742       if (sn != "Cl-" && sn != "CL-") {
00743         continue;
00744       }
00745 
00746       indexCLM = k;
00747       break;
00748     }
00749     return indexCLM;
00750   }
00751 
00752   //   Initialize lengths of local variables after all species have
00753   //   been identified.
00754   void  MolalityVPSSTP::initLengths() {
00755     m_kk = nSpecies();
00756     m_molalities.resize(m_kk);
00757   }
00758 
00759   /*
00760    * initThermoXML()                (virtual from ThermoPhase)
00761    *   Import and initialize a ThermoPhase object
00762    *
00763    * @param phaseNode This object must be the phase node of a
00764    *             complete XML tree
00765    *             description of the phase, including all of the
00766    *             species data. In other words while "phase" must
00767    *             point to an XML phase object, it must have
00768    *             sibling nodes "speciesData" that describe
00769    *             the species in the phase.
00770    * @param id   ID of the phase. If nonnull, a check is done
00771    *             to see if phaseNode is pointing to the phase
00772    *             with the correct id. 
00773    */
00774   void MolalityVPSSTP::initThermoXML(XML_Node& phaseNode, std::string id) {
00775 
00776     initLengths();
00777     /*
00778      * The solvent defaults to species 0
00779      */
00780     setSolvent(0);
00781 
00782     VPStandardStateTP::initThermoXML(phaseNode, id);
00783   }
00784   
00785  /**
00786    * Format a summary of the mixture state for output.
00787    */           
00788   std::string MolalityVPSSTP::report(bool show_thermo) const {
00789 
00790 
00791     char p[800];
00792     string s = "";
00793     try {
00794       if (name() != "") {
00795         sprintf(p, " \n  %s:\n", name().c_str());
00796         s += p;
00797       }
00798       sprintf(p, " \n       temperature    %12.6g  K\n", temperature());
00799       s += p;
00800       sprintf(p, "          pressure    %12.6g  Pa\n", pressure());
00801       s += p;
00802       sprintf(p, "           density    %12.6g  kg/m^3\n", density());
00803       s += p;
00804       sprintf(p, "  mean mol. weight    %12.6g  amu\n", meanMolecularWeight());
00805       s += p;
00806 
00807       doublereal phi = electricPotential();
00808       sprintf(p, "         potential    %12.6g  V\n", phi);
00809       s += p;
00810 
00811       int kk = nSpecies();
00812       array_fp x(kk);
00813       array_fp molal(kk);
00814       array_fp mu(kk);
00815       array_fp muss(kk);
00816       array_fp acMolal(kk);
00817       array_fp actMolal(kk);
00818       getMoleFractions(&x[0]);
00819       getMolalities(&molal[0]);
00820       getChemPotentials(&mu[0]);
00821       getStandardChemPotentials(&muss[0]);
00822       getMolalityActivityCoefficients(&acMolal[0]);
00823       getActivities(&actMolal[0]);
00824  
00825       int iHp = speciesIndex("H+");
00826       if (iHp >= 0) {
00827         double pH = -log(actMolal[iHp]) / log(10.0);
00828         sprintf(p, "                pH    %12.4g  \n", pH);
00829         s += p;
00830       }
00831 
00832       if (show_thermo) {
00833         sprintf(p, " \n");
00834         s += p;
00835         sprintf(p, "                          1 kg            1 kmol\n");
00836         s += p;
00837         sprintf(p, "                       -----------      ------------\n");
00838         s += p;
00839         sprintf(p, "          enthalpy    %12.6g     %12.4g     J\n", 
00840                 enthalpy_mass(), enthalpy_mole());
00841         s += p;
00842         sprintf(p, "   internal energy    %12.6g     %12.4g     J\n", 
00843                 intEnergy_mass(), intEnergy_mole());
00844         s += p;
00845         sprintf(p, "           entropy    %12.6g     %12.4g     J/K\n", 
00846                 entropy_mass(), entropy_mole());
00847         s += p;
00848         sprintf(p, "    Gibbs function    %12.6g     %12.4g     J\n", 
00849                 gibbs_mass(), gibbs_mole());
00850         s += p;
00851         sprintf(p, " heat capacity c_p    %12.6g     %12.4g     J/K\n", 
00852                 cp_mass(), cp_mole());
00853         s += p;
00854         try {
00855           sprintf(p, " heat capacity c_v    %12.6g     %12.4g     J/K\n", 
00856                   cv_mass(), cv_mole());
00857           s += p;
00858         }
00859         catch(CanteraError) {
00860           sprintf(p, " heat capacity c_v    <not implemented>       \n");
00861           s += p;
00862         }
00863       }
00864 
00865    
00866       //doublereal rt = GasConstant * temperature(); 
00867       int k;
00868 
00869    
00870       sprintf(p, " \n");
00871       s += p;
00872       if (show_thermo) {
00873         sprintf(p, "                           X        "
00874                 "   Molalities         Chem.Pot.    ChemPotSS    ActCoeffMolal\n");
00875         s += p;
00876         sprintf(p, "                                    "
00877                 "                      (J/kmol)      (J/kmol)                 \n");
00878         s += p;
00879         sprintf(p, "                     -------------  "
00880                 "  ------------     ------------  ------------    ------------\n");
00881         s += p;
00882         for (k = 0; k < kk; k++) {
00883           if (x[k] > SmallNumber) {
00884             sprintf(p, "%18s  %12.6g     %12.6g     %12.6g   %12.6g   %12.6g\n", 
00885                     speciesName(k).c_str(), x[k], molal[k], mu[k], muss[k], acMolal[k]);
00886           }
00887           else {
00888             sprintf(p, "%18s  %12.6g     %12.6g          N/A      %12.6g   %12.6g \n", 
00889                     speciesName(k).c_str(), x[k], molal[k], muss[k], acMolal[k]);
00890           }
00891           s += p;
00892         }
00893       }
00894       else {
00895         sprintf(p, "                           X"
00896                 "Molalities\n");
00897         s += p;
00898         sprintf(p, "                     -------------"
00899                 "     ------------\n");
00900         s += p;
00901         for (k = 0; k < kk; k++) {
00902           sprintf(p, "%18s   %12.6g     %12.6g\n", 
00903                   speciesName(k).c_str(), x[k], molal[k]);
00904           s += p;
00905         }
00906       }
00907     } catch (CanteraError) {
00908       ;
00909     }
00910     return s;
00911   }
00912 
00913  
00914 }
00915 
Generated by  doxygen 1.6.3