00001 /** 00002 * @file DebyeHuckel.h 00003 * Headers for the %DebyeHuckel ThermoPhase object, which models dilute 00004 * electrolyte solutions 00005 * (see \ref thermoprops and \link Cantera::DebyeHuckel DebyeHuckel \endlink) . 00006 * 00007 * Class %DebyeHuckel represents a dilute liquid electrolyte phase which 00008 * obeys the Debye Huckel formulation for nonideality. 00009 */ 00010 00011 /* 00012 * Copywrite (2006) Sandia Corporation. Under the terms of 00013 * Contract DE-AC04-94AL85000 with Sandia Corporation, the 00014 * U.S. Government retains certain rights in this software. 00015 */ 00016 00017 /* 00018 * $Id: DebyeHuckel.h 279 2009-12-05 19:08:43Z hkmoffa $ 00019 */ 00020 00021 #ifndef CT_DEBYEHUCKEL_H 00022 #define CT_DEBYEHUCKEL_H 00023 00024 #include "MolalityVPSSTP.h" 00025 #include "electrolytes.h" 00026 #include "Array.h" 00027 00028 namespace Cantera { 00029 00030 /*! 00031 * @name Formats for the Activity Coefficients 00032 * 00033 * These are possible formats for the molality-based activity coefficients. 00034 */ 00035 //@{ 00036 #define DHFORM_DILUTE_LIMIT 0 00037 #define DHFORM_BDOT_AK 1 00038 #define DHFORM_BDOT_ACOMMON 2 00039 #define DHFORM_BETAIJ 3 00040 #define DHFORM_PITZER_BETAIJ 4 00041 //@} 00042 /* 00043 * @name Acceptable ways to calculate the value of A_Debye 00044 */ 00045 //@{ 00046 #define A_DEBYE_CONST 0 00047 #define A_DEBYE_WATER 1 00048 //@} 00049 00050 class WaterProps; 00051 class PDSS_Water; 00052 00053 /** 00054 * @ingroup thermoprops 00055 * 00056 * Class %DebyeHuckel represents a dilute liquid electrolyte phase which 00057 * obeys the Debye Huckel formulation for nonideality. 00058 * 00059 * The concentrations of the ionic species are assumed to obey the electroneutrality 00060 * condition. 00061 * 00062 * <HR> 00063 * <H2> Specification of Species Standard %State Properties </H2> 00064 * <HR> 00065 * 00066 * The standard states are on the unit molality basis. Therefore, in the 00067 * documentation below, the normal \f$ o \f$ superscript is replaced with 00068 * the \f$ \triangle \f$ symbol. The reference state symbol is now 00069 * \f$ \triangle, ref \f$. 00070 * 00071 * 00072 * It is assumed that the reference state thermodynamics may be 00073 * obtained by a pointer to a populated species thermodynamic property 00074 * manager class (see ThermoPhase::m_spthermo). How to relate pressure 00075 * changes to the reference state thermodynamics is resolved at this level. 00076 * 00077 * For an incompressible, 00078 * stoichiometric substance, the molar internal energy is 00079 * independent of pressure. Since the thermodynamic properties 00080 * are specified by giving the standard-state enthalpy, the 00081 * term \f$ P_0 \hat v\f$ is subtracted from the specified molar 00082 * enthalpy to compute the molar internal energy. The entropy is 00083 * assumed to be independent of the pressure. 00084 * 00085 * The enthalpy function is given by the following relation. 00086 * 00087 * \f[ 00088 * \raggedright h^\triangle_k(T,P) = h^{\triangle,ref}_k(T) 00089 * + \tilde v \left( P - P_{ref} \right) 00090 * \f] 00091 * 00092 * For an incompressible, 00093 * stoichiometric substance, the molar internal energy is 00094 * independent of pressure. Since the thermodynamic properties 00095 * are specified by giving the standard-state enthalpy, the 00096 * term \f$ P_{ref} \tilde v\f$ is subtracted from the specified reference molar 00097 * enthalpy to compute the molar internal energy. 00098 * 00099 * \f[ 00100 * u^\triangle_k(T,P) = h^{\triangle,ref}_k(T) - P_{ref} \tilde v 00101 * \f] 00102 * 00103 * The standard state heat capacity and entropy are independent 00104 * of pressure. The standard state gibbs free energy is obtained 00105 * from the enthalpy and entropy functions. 00106 * 00107 * The vector Constituents::m_speciesSize[] is used to hold the 00108 * base values of species sizes. These are defined as the 00109 * molar volumes of species at infinite dilution at 300 K and 1 atm 00110 * of water. m_speciesSize are calculated during the initialization of the 00111 * %DebyeHuckel object and are then not touched. 00112 * 00113 * The current model assumes that an incompressible molar volume for 00114 * all solutes. The molar volume for the water solvent, however, 00115 * is obtained from a pure water equation of state, waterSS. 00116 * Therefore, the water standard state varies with both T and P. 00117 * It is an error to request standard state water properties at a T and P 00118 * where the water phase is not a stable phase, i.e., beyond its 00119 * spinodal curve. 00120 * 00121 * <HR> 00122 * <H2> Specification of Solution Thermodynamic Properties </H2> 00123 * <HR> 00124 * 00125 * Chemical potentials 00126 * of the solutes, \f$ \mu_k \f$, and the solvent, \f$ \mu_o \f$, which are based 00127 * on the molality form, have the following general format: 00128 * 00129 * \f[ 00130 * \mu_k = \mu^{\triangle}_k(T,P) + R T ln(\gamma_k^{\triangle} \frac{m_k}{m^\triangle}) 00131 * \f] 00132 * \f[ 00133 * \mu_o = \mu^o_o(T,P) + RT ln(a_o) 00134 * \f] 00135 * 00136 * where \f$ \gamma_k^{\triangle} \f$ is the molality based activity coefficient for species 00137 * \f$k\f$. 00138 * 00139 * Individual activity coefficients of ions can not be independently measured. Instead, 00140 * only binary pairs forming electroneutral solutions can be measured. 00141 00142 * 00143 * <H3> Ionic Strength </H3> 00144 * 00145 * Most of the parameterizations within the model use the ionic strength 00146 * as a key variable. The ionic strength, \f$ I\f$ is defined as follows 00147 * 00148 * \f[ 00149 * I = \frac{1}{2} \sum_k{m_k z_k^2} 00150 * \f] 00151 * 00152 * \f$ m_k \f$ is the molality of the kth species. \f$ z_k \f$ is the charge 00153 * of the kth species. Note, the ionic strength is a defined units quantity. 00154 * The molality has defined units of gmol kg-1, and therefore the ionic 00155 * strength has units of sqrt( gmol kg-1). 00156 * 00157 * In some instances, from some authors, a different 00158 * formulation is used for the ionic strength in the equations below. The different 00159 * formulation is due to the possibility of the existence of weak acids and how 00160 * association wrt to the weak acid equilibrium relation affects the calculation 00161 * of the activity coefficients via the assumed value of the ionic strength. 00162 * 00163 * If we are to assume that the association reaction doesn't have an effect 00164 * on the ionic strength, then we will want to consider the associated weak 00165 * acid as in effect being fully dissociated, when we calculate an effective 00166 * value for the ionic strength. We will call this calculated value, the 00167 * stoichiometric ionic strength, \f$ I_s \f$, putting a subscript s to denote 00168 * it from the more straightforward calculation of \f$ I \f$. 00169 * 00170 * \f[ 00171 * I_s = \frac{1}{2} \sum_k{m_k^s z_k^2} 00172 * \f] 00173 * 00174 * Here, \f$ m_k^s \f$ is the value of the molalities calculated assuming that 00175 * all weak acid-base pairs are in their fully dissociated states. This calculation may 00176 * be simplified by considering that the weakly associated acid may be made up of two 00177 * charged species, k1 and k2, each with their own charges, obeying the following relationship: 00178 * 00179 * \f[ 00180 * z_k = z_{k1} + z_{k2} 00181 * \f] 00182 * Then, we may only need to specify one charge value, say, \f$ z_{k1}\f$, 00183 * the cation charge number, 00184 * in order to get both numbers, since we have already specified \f$ z_k \f$ 00185 * in the definition of original species. 00186 * Then, the stoichiometric ionic strength may be calculated via the following formula. 00187 * 00188 * \f[ 00189 * I_s = \frac{1}{2} \left(\sum_{k,ions}{m_k z_k^2}+ 00190 * \sum_{k,weak_assoc}(m_k z_{k1}^2 + m_k z_{k2}^2) \right) 00191 * \f] 00192 * 00193 * The specification of which species are weakly associated acids is made in the input 00194 * file via the 00195 * <TT> stoichIsMods </TT> XML block, where the charge for k1 is also specified. 00196 * An example is given below: 00197 * 00198 * @code 00199 * <stoichIsMods> 00200 * NaCl(aq):-1.0 00201 * </stoichIsMods> 00202 * @endcode 00203 * 00204 * Because we need the concept of a weakly associated acid in order to calculated 00205 * \f$ I_s \f$ we need to 00206 * catalog all species in the phase. This is done using the following categories: 00207 * 00208 * - <B>cEST_solvent</B> : Solvent species (neutral) 00209 * - <B>cEST_chargedSpecies</B> Charged species (charged) 00210 * - <B>cEST_weakAcidAssociated</B> Species which can break apart into charged species. 00211 * It may or may not be charged. These may or 00212 * may not be be included in the 00213 * species solution vector. 00214 * - <B>cEST_strongAcidAssociated</B> Species which always breaksapart into charged species. 00215 * It may or may not be charged. Normally, these aren't included 00216 * in the speciation vector. 00217 * - <B>cEST_polarNeutral </B> Polar neutral species 00218 * - <B>cEST_nonpolarNeutral</B> Non poloar neutral species 00219 * 00220 * Polar and non-polar neutral species are differentiated, because some additions 00221 * to the activity 00222 * coefficient expressions distinguish between these two types of solutes. This is the so-called 00223 * salt-out effect. 00224 * 00225 * The type of species is specified in the <TT>electrolyteSpeciesType</TT> XML block. 00226 * Note, this is not 00227 * considered a part of the specification of the standard state for the species, 00228 * at this time. Therefore, 00229 * this information is put under the <TT>activityCoefficient</TT> XML block. An example 00230 * is given below 00231 * 00232 * @code 00233 * <electrolyteSpeciesType> 00234 * H2L(L):solvent 00235 * H+:chargedSpecies 00236 * NaOH(aq):weakAcidAssociated 00237 * NaCl(aq):strongAcidAssociated 00238 * NH3(aq):polarNeutral 00239 * O2(aq):nonpolarNeutral 00240 * </electrolyteSpeciesType> 00241 * @endcode 00242 * 00243 * Much of the species electrolyte type information is infered from other information in the 00244 * input file. For example, as species which is charged is given the "chargedSpecies" default 00245 * category. A neutral solute species is put into the "nonpolarNeutral" category by default. 00246 * 00247 * The specification of solute activity coefficients depends on the model 00248 * assumed for the Debye-Huckel term. The model is set by the 00249 * internal parameter #m_formDH. We will now describe each category in its own section. 00250 * 00251 * 00252 * <H3> Debye-Huckel Dilute Limit </H3> 00253 * 00254 * DHFORM_DILUTE_LIMIT = 0 00255 * 00256 * This form assumes a dilute limit to DH, and is mainly 00257 * for informational purposes: 00258 * \f[ 00259 * \ln(\gamma_k^\triangle) = - z_k^2 A_{Debye} \sqrt{I} 00260 * \f] 00261 * where \f$ I\f$ is the ionic strength 00262 * \f[ 00263 * I = \frac{1}{2} \sum_k{m_k z_k^2} 00264 * \f] 00265 * 00266 * The activity for the solvent water,\f$ a_o \f$, is not independent and must be 00267 * determined from the Gibbs-Duhem relation. 00268 * 00269 * \f[ 00270 * \ln(a_o) = \frac{X_o - 1.0}{X_o} + \frac{ 2 A_{Debye} \tilde{M}_o}{3} (I)^{3/2} 00271 * \f] 00272 * 00273 * 00274 * <H3> Bdot Formulation </H3> 00275 * 00276 * DHFORM_BDOT_AK = 1 00277 * 00278 * This form assumes Bethke's format for the Debye Huckel activity coefficient: 00279 * 00280 * \f[ 00281 * \ln(\gamma_k^\triangle) = -z_k^2 \frac{A_{Debye} \sqrt{I}}{ 1 + B_{Debye} a_k \sqrt{I}} 00282 * + \log(10) B^{dot}_k I 00283 * \f] 00284 * 00285 * Note, this particular form where \f$ a_k \f$ can differ in 00286 * multielectrolyte 00287 * solutions has problems with respect to a Gibbs-Duhem analysis. However, 00288 * we include it here because there is a lot of data fit to it. 00289 * 00290 * The activity for the solvent water,\f$ a_o \f$, is not independent and must be 00291 * determined from the Gibbs-Duhem relation. Here, we use: 00292 * 00293 * \f[ 00294 * \ln(a_o) = \frac{X_o - 1.0}{X_o} 00295 * + \frac{ 2 A_{Debye} \tilde{M}_o}{3} (I)^{1/2} 00296 * \left[ \sum_k{\frac{1}{2} m_k z_k^2 \sigma( B_{Debye} a_k \sqrt{I} ) } \right] 00297 * - \frac{\log(10)}{2} \tilde{M}_o I \sum_k{ B^{dot}_k m_k} 00298 * \f] 00299 * where 00300 * \f[ 00301 * \sigma (y) = \frac{3}{y^3} \left[ (1+y) - 2 \ln(1 + y) - \frac{1}{1+y} \right] 00302 * \f] 00303 * 00304 * Additionally, Helgeson's formulation for the water activity is offered as an 00305 * alternative. 00306 * 00307 * 00308 * <H3> Bdot Formulation with Uniform Size Parameter in the Denominator </H3> 00309 * 00310 * DHFORM_BDOT_AUNIFORM = 2 00311 * 00312 * This form assumes Bethke's format for the Debye-Huckel activity coefficient 00313 * 00314 * \f[ 00315 * \ln(\gamma_k^\triangle) = -z_k^2 \frac{A_{Debye} \sqrt{I}}{ 1 + B_{Debye} a \sqrt{I}} 00316 * + \log(10) B^{dot}_k I 00317 * \f] 00318 * 00319 * The value of a is determined at the beginning of the 00320 * calculation, and not changed. 00321 * 00322 * \f[ 00323 * \ln(a_o) = \frac{X_o - 1.0}{X_o} 00324 * + \frac{ 2 A_{Debye} \tilde{M}_o}{3} (I)^{3/2} \sigma( B_{Debye} a \sqrt{I} ) 00325 * - \frac{\log(10)}{2} \tilde{M}_o I \sum_k{ B^{dot}_k m_k} 00326 * \f] 00327 * 00328 * 00329 * <H3> Beta_IJ formulation </H3> 00330 * 00331 * DHFORM_BETAIJ = 3 00332 * 00333 * This form assumes a linear expansion in a virial coefficient form 00334 * It is used extensively in the book by Newmann, "Electrochemistry Systems", 00335 * and is the beginning of 00336 * more complex treatments for stronger electrolytes, fom Pitzer 00337 * and from Harvey, Moller, and Weire. 00338 * 00339 * \f[ 00340 * \ln(\gamma_k^\triangle) = -z_k^2 \frac{A_{Debye} \sqrt{I}}{ 1 + B_{Debye} a \sqrt{I}} 00341 * + 2 \sum_j \beta_{j,k} m_j 00342 * \f] 00343 * 00344 * In the current treatment the binary interaction coefficients, \f$ \beta_{j,k}\f$, are 00345 * independent of temperature and pressure. 00346 * 00347 * \f[ 00348 * \ln(a_o) = \frac{X_o - 1.0}{X_o} 00349 * + \frac{ 2 A_{Debye} \tilde{M}_o}{3} (I)^{3/2} \sigma( B_{Debye} a \sqrt{I} ) 00350 * - \tilde{M}_o \sum_j \sum_k \beta_{j,k} m_j m_k 00351 * \f] 00352 * 00353 * In this formulation the ionic radius, \f$ a \f$, is a constant. This must be supplied to the 00354 * model, in an <DFN> ionicRadius </DFN> XML block. 00355 * 00356 * The \f$ \beta_{j,k} \f$ parameters are binary interaction parameters. They are supplied to 00357 * the object in an <TT> DHBetaMatrix </TT> XML block. There are in principle \f$ N (N-1) /2 \f$ 00358 * different, symmetric interaction parameters, where \f$ N \f$ are the number of solute species in the 00359 * mechanism. 00360 * An example is given below. 00361 * 00362 * An example <TT> activityCoefficients </TT> XML block for this formulation is supplied below 00363 * 00364 * @code 00365 * <activityCoefficients model="Beta_ij"> 00366 * <!-- A_Debye units = sqrt(kg/gmol) --> 00367 * <A_Debye> 1.172576 </A_Debye> 00368 * <!-- B_Debye units = sqrt(kg/gmol)/m --> 00369 * <B_Debye> 3.28640E9 </B_Debye> 00370 * <ionicRadius default="3.042843" units="Angstroms"> 00371 * </ionicRadius> 00372 * <DHBetaMatrix> 00373 * H+:Cl-:0.27 00374 * Na+:Cl-:0.15 00375 * Na+:OH-:0.06 00376 * </DHBetaMatrix> 00377 * <stoichIsMods> 00378 * NaCl(aq):-1.0 00379 * </stoichIsMods> 00380 * <electrolyteSpeciesType> 00381 * H+:chargedSpecies 00382 * NaCl(aq):weakAcidAssociated 00383 * </electrolyteSpeciesType> 00384 * </activityCoefficients> 00385 * @endcode 00386 * 00387 * <H3> Pitzer Beta_IJ formulation </H3> 00388 * 00389 * DHFORM_PITZER_BETAIJ = 4 00390 * 00391 * This form assumes an activity coefficient formulation consistent 00392 * with a truncated form of Pitzer's formulation. Pitzer's formulation is equivalent 00393 * to the formulations above in the dilute limit, where rigorous theory may be applied. 00394 * 00395 * \f[ 00396 * \ln(\gamma_k^\triangle) = -z_k^2 \frac{A_{Debye}}{3} \frac{\sqrt{I}}{ 1 + B_{Debye} a \sqrt{I}} 00397 * -2 z_k^2 \frac{A_{Debye}}{3} \frac{\ln(1 + B_{Debye} a \sqrt{I})}{ B_{Debye} a} 00398 * + 2 \sum_j \beta_{j,k} m_j 00399 * \f] 00400 * 00401 * 00402 * \f[ 00403 * \ln(a_o) = \frac{X_o - 1.0}{X_o} 00404 * + \frac{ 2 A_{Debye} \tilde{M}_o}{3} \frac{(I)^{3/2} }{1 + B_{Debye} a \sqrt{I} } 00405 * - \tilde{M}_o \sum_j \sum_k \beta_{j,k} m_j m_k 00406 * \f] 00407 * 00408 * <H3> Specification of the Debye Huckel Constants </H3> 00409 * 00410 * In the equations above, the formulas for \f$ A_{Debye} \f$ and \f$ B_{Debye} \f$ 00411 * are needed. The %DebyeHuckel object uses two methods for specifying these quantities. 00412 * The default method is to assume that \f$ A_{Debye} \f$ is a constant, given 00413 * in the initialization process, and storred in the 00414 * member double, m_A_Debye. Optionally, a full water treatment may be employed that makes 00415 * \f$ A_{Debye} \f$ a full function of <I>T</I> and <I>P</I>. 00416 * 00417 * \f[ 00418 * A_{Debye} = \frac{F e B_{Debye}}{8 \pi \epsilon R T} {\left( C_o \tilde{M}_o \right)}^{1/2} 00419 * \f] 00420 * where 00421 * 00422 * \f[ 00423 * B_{Debye} = \frac{F} {{(\frac{\epsilon R T}{2})}^{1/2}} 00424 * \f] 00425 * Therefore: 00426 * \f[ 00427 * A_{Debye} = \frac{1}{8 \pi} 00428 * {\left(\frac{2 N_a \rho_o}{1000}\right)}^{1/2} 00429 * {\left(\frac{N_a e^2}{\epsilon R T }\right)}^{3/2} 00430 * \f] 00431 * 00432 * Units = sqrt(kg/gmol) 00433 * 00434 * where 00435 * - \f$ N_a \f$ is Avrogadro's number 00436 * - \f$ \rho_w \f$ is the density of water 00437 * - \f$ e \f$ is the electronic charge 00438 * - \f$ \epsilon = K \epsilon_o \f$ is the permitivity of water 00439 * where \f$ K \f$ is the dielectric condstant of water, 00440 * and \f$ \epsilon_o \f$ is the permitivity of free space. 00441 * - \f$ \rho_o \f$ is the density of the solvent in its standard state. 00442 * 00443 * Nominal value at 298 K and 1 atm = 1.172576 (kg/gmol)<SUP>1/2</SUP> 00444 * based on: 00445 * - \f$ \epsilon / \epsilon_0 \f$ = 78.54 00446 * (water at 25C) 00447 * - \f$ \epsilon_0 \f$= 8.854187817E-12 C<SUP>2</SUP> N<SUP>-1</SUP> m<SUP>-2</SUP> 00448 * - e = 1.60217653E-19 C 00449 * - F = 9.6485309E7 C kmol<SUP>-1</SUP> 00450 * - R = 8.314472E3 kg m<SUP>2</SUP> s<SUP>-2</SUP> kmol<SUP>-1</SUP> K<SUP>-1</SUP> 00451 * - T = 298.15 K 00452 * - B_Debye = 3.28640E9 (kg/gmol)<SUP>1/2</SUP> m<SUP>-1</SUP> 00453 * - \f$N_a\f$ = 6.0221415E26 kmol<SUP>-1</SUP> 00454 * 00455 * An example of a fixed value implementation is given below. 00456 * @code 00457 * <activityCoefficients model="Beta_ij"> 00458 * <!-- A_Debye units = sqrt(kg/gmol) --> 00459 * <A_Debye> 1.172576 </A_Debye> 00460 * <!-- B_Debye units = sqrt(kg/gmol)/m --> 00461 * <B_Debye> 3.28640E9 </B_Debye> 00462 * </activityCoefficients> 00463 * @endcode 00464 * 00465 * An example of a variable value implementation is given below. 00466 * 00467 * @code 00468 * <activityCoefficients model="Beta_ij"> 00469 * <A_Debye model="water" /> 00470 * <!-- B_Debye units = sqrt(kg/gmol)/m --> 00471 * <B_Debye> 3.28640E9 </B_Debye> 00472 * </activityCoefficients> 00473 * @endcode 00474 * 00475 * Currently, \f$ B_{Debye} \f$ is a constant in the model, specified either by a default 00476 * water value, or through the input file. This may have to be looked at, in the future. 00477 * 00478 * <HR> 00479 * <H2> %Application within %Kinetics Managers </H2> 00480 * <HR> 00481 * 00482 * For the time being, we have set the standard concentration for all species in 00483 * this phase equal to the default concentration of the solvent at 298 K and 1 atm. 00484 * This means that the 00485 * kinetics operator essentially works on an activities basis, with units specified 00486 * as if it were on a concentration basis. 00487 * 00488 * For example, a bulk-phase binary reaction between liquid species j and k, producing 00489 * a new liquid species l would have the 00490 * following equation for its rate of progress variable, \f$ R^1 \f$, which has 00491 * units of kmol m-3 s-1. 00492 * 00493 * \f[ 00494 * R^1 = k^1 C_j^a C_k^a = k^1 (C_o a_j) (C_o a_k) 00495 * \f] 00496 * where 00497 * \f[ 00498 * C_j^a = C_o a_j \quad and \quad C_k^a = C_o a_k 00499 * \f] 00500 * 00501 * \f$ C_j^a \f$ is the activity concentration of species j, and 00502 * \f$ C_k^a \f$ is the activity concentration of species k. \f$ C_o \f$ 00503 * is the concentration of water at 298 K and 1 atm. \f$ a_j \f$ is 00504 * the activity of species j at the current temperature and pressure 00505 * and concentration of the liquid phase. \f$k^1 \f$ has units of m3 kmol-1 s-1. 00506 * 00507 * The reverse rate constant can then be obtained from the law of microscopic reversibility 00508 * and the equilibrium expression for the system. 00509 * 00510 * \f[ 00511 * \frac{a_j a_k}{ a_l} = K^{o,1} = \exp(\frac{\mu^o_l - \mu^o_j - \mu^o_k}{R T} ) 00512 * \f] 00513 * 00514 * \f$ K^{o,1} \f$ is the dimensionless form of the equilibrium constant. 00515 * 00516 * \f[ 00517 * R^{-1} = k^{-1} C_l^a = k^{-1} (C_o a_l) 00518 * \f] 00519 * 00520 * where 00521 * 00522 * \f[ 00523 * k^{-1} = k^1 K^{o,1} C_o 00524 * \f] 00525 * 00526 * \f$k^{-1} \f$ has units of s-1. 00527 * 00528 * Note, this treatment may be modified in the future, as events dictate. 00529 * 00530 * <HR> 00531 * <H2> Instantiation of the Class </H2> 00532 * <HR> 00533 * 00534 * The constructor for this phase is NOT located in the default ThermoFactory 00535 * for %Cantera. However, a new %DebyeHuckel object may be created by 00536 * the following code snippets: 00537 * 00538 * @code 00539 * DebyeHuckel *DH = new DebyeHuckel("DH_NaCl.xml", "NaCl_electrolyte"); 00540 * @endcode 00541 * 00542 * or 00543 * 00544 * @code 00545 * char iFile[80], file_ID[80]; 00546 * strcpy(iFile, "DH_NaCl.xml"); 00547 * sprintf(file_ID,"%s#NaCl_electrolyte", iFile); 00548 * XML_Node *xm = get_XML_NameID("phase", file_ID, 0); 00549 * DebyeHuckel *dh = new DebyeHuckel(*xm); 00550 * @endcode 00551 * 00552 * or by the following call to importPhase(): 00553 * 00554 * @code 00555 * char iFile[80], file_ID[80]; 00556 * strcpy(iFile, "DH_NaCl.xml"); 00557 * sprintf(file_ID,"%s#NaCl_electrolyte", iFile); 00558 * XML_Node *xm = get_XML_NameID("phase", file_ID, 0); 00559 * DebyeHuckel dhphase; 00560 * importPhase(*xm, &dhphase); 00561 * @endcode 00562 * 00563 * <HR> 00564 * <H2> XML Example </H2> 00565 * <HR> 00566 * 00567 * The phase model name for this is called StoichSubstance. It must be supplied 00568 * as the model attribute of the thermo XML element entry. 00569 * Within the phase XML block, 00570 * the density of the phase must be specified. An example of an XML file 00571 * this phase is given below. 00572 * 00573 * @verbatim 00574 <phase id="NaCl_electrolyte" dim="3"> 00575 <speciesArray datasrc="#species_waterSolution"> 00576 H2O(L) Na+ Cl- H+ OH- NaCl(aq) NaOH(aq) 00577 </speciesArray> 00578 <state> 00579 <temperature units="K"> 300 </temperature> 00580 <pressure units="Pa">101325.0</pressure> 00581 <soluteMolalities> 00582 Na+:3.0 00583 Cl-:3.0 00584 H+:1.0499E-8 00585 OH-:1.3765E-6 00586 NaCl(aq):0.98492 00587 NaOH(aq):3.8836E-6 00588 </soluteMolalities> 00589 </state> 00590 <!-- thermo model identifies the inherited class 00591 from ThermoPhase that will handle the thermodynamics. 00592 --> 00593 <thermo model="DebyeHuckel"> 00594 <standardConc model="solvent_volume" /> 00595 <activityCoefficients model="Beta_ij"> 00596 <!-- A_Debye units = sqrt(kg/gmol) --> 00597 <A_Debye> 1.172576 </A_Debye> 00598 <!-- B_Debye units = sqrt(kg/gmol)/m --> 00599 <B_Debye> 3.28640E9 </B_Debye> 00600 <ionicRadius default="3.042843" units="Angstroms"> 00601 </ionicRadius> 00602 <DHBetaMatrix> 00603 H+:Cl-:0.27 00604 Na+:Cl-:0.15 00605 Na+:OH-:0.06 00606 </DHBetaMatrix> 00607 <stoichIsMods> 00608 NaCl(aq):-1.0 00609 </stoichIsMods> 00610 <electrolyteSpeciesType> 00611 H+:chargedSpecies 00612 NaCl(aq):weakAcidAssociated 00613 </electrolyteSpeciesType> 00614 </activityCoefficients> 00615 <solvent> H2O(L) </solvent> 00616 </thermo> 00617 <elementArray datasrc="elements.xml"> O H Na Cl </elementArray> 00618 </phase> 00619 @endverbatim 00620 * 00621 * 00622 */ 00623 class DebyeHuckel : public MolalityVPSSTP { 00624 00625 public: 00626 00627 //! Empty Constructor 00628 DebyeHuckel(); 00629 00630 //! Copy constructor 00631 DebyeHuckel(const DebyeHuckel &); 00632 00633 //! Assignment operator 00634 DebyeHuckel& operator=(const DebyeHuckel&); 00635 00636 //! Full constructor for creating the phase. 00637 /*! 00638 * @param inputFile File name containing the XML description of the phase 00639 * @param id id attribute containing the name of the phase. 00640 * (default is the empty string) 00641 */ 00642 DebyeHuckel(std::string inputFile, std::string id = ""); 00643 00644 //! Full constructor for creating the phase. 00645 /*! 00646 * @param phaseRef XML phase node containing the description of the phase 00647 * @param id id attribute containing the name of the phase. 00648 * (default is the empty string) 00649 */ 00650 DebyeHuckel(XML_Node& phaseRef, std::string id = ""); 00651 00652 /// Destructor. 00653 virtual ~DebyeHuckel(); 00654 00655 //! Duplicator from the ThermoPhase parent class 00656 /*! 00657 * Given a pointer to a ThermoPhase object, this function will 00658 * duplicate the ThermoPhase object and all underlying structures. 00659 * This is basically a wrapper around the copy constructor. 00660 * 00661 * @return returns a pointer to a ThermoPhase 00662 */ 00663 ThermoPhase *duplMyselfAsThermoPhase() const; 00664 00665 /** 00666 * 00667 * @name Utilities 00668 * @{ 00669 */ 00670 00671 /** 00672 * Equation of state type flag. The base class returns 00673 * zero. Subclasses should define this to return a unique 00674 * non-zero value. Constants defined for this purpose are 00675 * listed in mix_defs.h. 00676 */ 00677 virtual int eosType() const; 00678 00679 /** 00680 * @} 00681 * @name Molar Thermodynamic Properties of the Solution -------------- 00682 * @{ 00683 */ 00684 00685 /// Molar enthalpy. Units: J/kmol. 00686 /** 00687 * Molar enthalpy of the solution. Units: J/kmol. 00688 * (HKM -> Bump up to Parent object) 00689 */ 00690 virtual doublereal enthalpy_mole() const; 00691 00692 /// Molar internal energy. Units: J/kmol. 00693 /** 00694 * Molar internal energy of the solution. Units: J/kmol. 00695 * (HKM -> Bump up to Parent object) 00696 */ 00697 virtual doublereal intEnergy_mole() const; 00698 00699 /// Molar entropy. Units: J/kmol/K. 00700 /** 00701 * Molar entropy of the solution. Units: J/kmol/K. 00702 * For an ideal, constant partial molar volume solution mixture with 00703 * pure species phases which exhibit zero volume expansivity: 00704 * \f[ 00705 * \hat s(T, P, X_k) = \sum_k X_k \hat s^0_k(T) 00706 * - \hat R \sum_k X_k log(X_k) 00707 * \f] 00708 * The reference-state pure-species entropies 00709 * \f$ \hat s^0_k(T,p_{ref}) \f$ are computed by the 00710 * species thermodynamic 00711 * property manager. The pure species entropies are independent of 00712 * temperature since the volume expansivities are equal to zero. 00713 * @see SpeciesThermo 00714 * 00715 * (HKM -> Bump up to Parent object) 00716 */ 00717 virtual doublereal entropy_mole() const; 00718 00719 /// Molar Gibbs function. Units: J/kmol. 00720 /* 00721 * (HKM -> Bump up to Parent object) 00722 */ 00723 virtual doublereal gibbs_mole() const; 00724 00725 /// Molar heat capacity at constant pressure. Units: J/kmol/K. 00726 /* 00727 * 00728 */ 00729 virtual doublereal cp_mole() const; 00730 00731 //! Molar heat capacity at constant volume. Units: J/kmol/K. 00732 /* 00733 * (HKM -> Bump up to Parent object) 00734 */ 00735 virtual doublereal cv_mole() const; 00736 00737 //@} 00738 /** @name Mechanical Equation of State Properties ------------------------- 00739 //@{ 00740 * 00741 * In this equation of state implementation, the density is a 00742 * function only of the mole fractions. Therefore, it can't be 00743 * an independent variable. Instead, the pressure is used as the 00744 * independent variable. Functions which try to set the thermodynamic 00745 * state by calling setDensity() may cause an exception to be 00746 * thrown. 00747 */ 00748 00749 //! Return the thermodynamic pressure (Pa). 00750 /*! 00751 * For this incompressible system, we return the internally storred 00752 * independent value of the pressure. 00753 */ 00754 virtual doublereal pressure() const; 00755 00756 //! Set the internally storred pressure (Pa) at constant 00757 //! temperature and composition 00758 /*! 00759 * This method sets the pressure within the object. 00760 * The water model is a completely compressible model. 00761 * Also, the dielectric constant is pressure dependent. 00762 * 00763 * @param p input Pressure (Pa) 00764 * 00765 * @todo Implement a variable pressure capability 00766 */ 00767 virtual void setPressure(doublereal p); 00768 00769 protected: 00770 //! Calculate the density of the mixture using the partial 00771 //! molar volumes and mole fractions as input 00772 /*! 00773 * The formula for this is 00774 * 00775 * \f[ 00776 * \rho = \frac{\sum_k{X_k W_k}}{\sum_k{X_k V_k}} 00777 * \f] 00778 * 00779 * where \f$X_k\f$ are the mole fractions, \f$W_k\f$ are 00780 * the molecular weights, and \f$V_k\f$ are the pure species 00781 * molar volumes. 00782 * 00783 * Note, the basis behind this formula is that in an ideal 00784 * solution the partial molar volumes are equal to the pure 00785 * species molar volumes. We have additionally specified 00786 * in this class that the pure species molar volumes are 00787 * independent of temperature and pressure. 00788 */ 00789 virtual void calcDensity(); 00790 00791 public: 00792 //! Set the internally storred density (gm/m^3) of the phase. 00793 /*! 00794 * Overwritten setDensity() function is necessary because the 00795 * density is not an indendent variable. 00796 * 00797 * This function will now throw an error condition 00798 * 00799 * @internal May have to adjust the strategy here to make 00800 * the eos for these materials slightly compressible, in order 00801 * to create a condition where the density is a function of 00802 * the pressure. 00803 * 00804 * This function will now throw an error condition if the 00805 * input isn't exactly equal to the current density. 00806 * 00807 * 00808 * @todo Now have a compressible ss equation for liquid water. 00809 * Therefore, this phase is compressible. May still 00810 * want to change the independent variable however. 00811 * 00812 * NOTE: This is an overwritten function from the State.h 00813 * class 00814 * 00815 * @param rho Input density (kg/m^3). 00816 */ 00817 void setDensity(const doublereal rho); 00818 00819 //! Set the internally storred molar density (kmol/m^3) of the phase. 00820 /** 00821 * Overwritten setMolarDensity() function is necessary because the 00822 * density is not an indendent variable. 00823 * 00824 * This function will now throw an error condition if the input 00825 * isn't exactly equal to the current molar density. 00826 * 00827 * NOTE: This is a virtual function overwritten from the State.h 00828 * class 00829 * 00830 * @param conc Input molar density (kmol/m^3). 00831 */ 00832 virtual void setMolarDensity(const doublereal conc); 00833 00834 //! Set the temperature (K) 00835 /*! 00836 * Overwritten setTemperature(double) from State.h. This 00837 * function sets the temperature, and makes sure that 00838 * the value propagates to underlying objects, such as 00839 * the water standard state model. 00840 * 00841 * @todo Make State::setTemperature a virtual function 00842 * 00843 * @param temp Temperature in kelvin 00844 */ 00845 virtual void setTemperature(const doublereal temp); 00846 00847 //! Set the temperature (K) and pressure (Pa) 00848 /*! 00849 * Set the temperature and pressure. 00850 * 00851 * @param t Temperature (K) 00852 * @param p Pressure (Pa) 00853 */ 00854 virtual void setState_TP(doublereal t, doublereal p); 00855 00856 /** 00857 * The isothermal compressibility. Units: 1/Pa. 00858 * The isothermal compressibility is defined as 00859 * \f[ 00860 * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T 00861 * \f] 00862 */ 00863 virtual doublereal isothermalCompressibility() const; 00864 00865 /** 00866 * The thermal expansion coefficient. Units: 1/K. 00867 * The thermal expansion coefficient is defined as 00868 * 00869 * \f[ 00870 * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P 00871 * \f] 00872 */ 00873 virtual doublereal thermalExpansionCoeff() const; 00874 00875 /** 00876 * @} 00877 * @name Potential Energy 00878 * 00879 * Species may have an additional potential energy due to the 00880 * presence of external gravitation or electric fields. These 00881 * methods allow specifying a potential energy for individual 00882 * species. 00883 * @{ 00884 */ 00885 00886 /** 00887 * @} 00888 * @name Activities, Standard States, and Activity Concentrations 00889 * 00890 * The activity \f$a_k\f$ of a species in solution is 00891 * related to the chemical potential by \f[ \mu_k = \mu_k^0(T) 00892 * + \hat R T \log a_k. \f] The quantity \f$\mu_k^0(T,P)\f$ is 00893 * the chemical potential at unit activity, which depends only 00894 * on temperature and the pressure. 00895 * Activity is assumed to be molality-based here. 00896 * @{ 00897 */ 00898 00899 //! This method returns an array of generalized concentrations 00900 /*! 00901 * \f$ C_k\f$ that are defined such that 00902 * \f$ a_k = C_k / C^0_k, \f$ where \f$ C^0_k \f$ 00903 * is a standard concentration 00904 * defined below. These generalized concentrations are used 00905 * by kinetics manager classes to compute the forward and 00906 * reverse rates of elementary reactions. 00907 * 00908 * @param c Array of generalized concentrations. The 00909 * units depend upon the implementation of the 00910 * reaction rate expressions within the phase. 00911 */ 00912 virtual void getActivityConcentrations(doublereal* c) const; 00913 00914 //! Return the standard concentration for the kth species 00915 /*! 00916 * The standard concentration \f$ C^0_k \f$ used to normalize 00917 * the activity (i.e., generalized) concentration in 00918 * kinetics calculations. 00919 * 00920 * For the time being, we will use the concentration of pure 00921 * solvent for the the standard concentration of all species. 00922 * This has the effect of making reaction rates 00923 * based on the molality of species proportional to the 00924 * molality of the species. 00925 * 00926 * @param k Optional parameter indicating the species. The default 00927 * is to assume this refers to species 0. 00928 * @return 00929 * Returns the standard Concentration in units of 00930 * m<SUP>3</SUP> kmol<SUP>-1</SUP>. 00931 */ 00932 virtual doublereal standardConcentration(int k=0) const; 00933 00934 //! Natural logarithm of the standard concentration of the kth species. 00935 /*! 00936 * @param k index of the species (defaults to zero) 00937 */ 00938 virtual doublereal logStandardConc(int k=0) const; 00939 00940 //! Returns the units of the standard and generalized concentrations. 00941 /*! 00942 * Note they have the same units, as their 00943 * ratio is defined to be equal to the activity of the kth 00944 * species in the solution, which is unitless. 00945 * 00946 * This routine is used in print out applications where the 00947 * units are needed. Usually, MKS units are assumed throughout 00948 * the program and in the XML input files. 00949 * 00950 * The base %ThermoPhase class assigns the default quantities 00951 * of (kmol/m3) for all species. 00952 * Inherited classes are responsible for overriding the default 00953 * values if necessary. 00954 * 00955 * @param uA Output vector containing the units 00956 * uA[0] = kmol units - default = 1 00957 * uA[1] = m units - default = -nDim(), the number of spatial 00958 * dimensions in the Phase class. 00959 * uA[2] = kg units - default = 0; 00960 * uA[3] = Pa(pressure) units - default = 0; 00961 * uA[4] = Temperature units - default = 0; 00962 * uA[5] = time units - default = 0 00963 * @param k species index. Defaults to 0. 00964 * @param sizeUA output int containing the size of the vector. 00965 * Currently, this is equal to 6. 00966 */ 00967 virtual void getUnitsStandardConc(double *uA, int k = 0, 00968 int sizeUA = 6) const; 00969 00970 //! Get the array of non-dimensional activities at 00971 //! the current solution temperature, pressure, and solution concentration. 00972 /*! 00973 * 00974 * We resolve this function at this level by calling 00975 * on the activityConcentration function. However, 00976 * derived classes may want to override this default 00977 * implementation. 00978 * 00979 * (note solvent is on molar scale). 00980 * 00981 * @param ac Output vector of activities. Length: m_kk. 00982 */ 00983 virtual void getActivities(doublereal* ac) const; 00984 00985 //! Get the array of non-dimensional molality-based 00986 //! activity coefficients at 00987 //! the current solution temperature, pressure, and solution concentration. 00988 /*! 00989 * note solvent is on molar scale. The solvent molar 00990 * based activity coefficient is returned. 00991 * 00992 * @param acMolality Vector of Molality-based activity coefficients 00993 * Length: m_kk 00994 */ 00995 virtual void 00996 getMolalityActivityCoefficients(doublereal* acMolality) const; 00997 00998 //@} 00999 /// @name Partial Molar Properties of the Solution ----------------- 01000 //@{ 01001 01002 01003 //! Get the species chemical potentials. Units: J/kmol. 01004 /*! 01005 * 01006 * This function returns a vector of chemical potentials of the 01007 * species in solution. 01008 * 01009 * \f[ 01010 * \mu_k = \mu^{\triangle}_k(T,P) + R T ln(\gamma_k^{\triangle} m_k) 01011 * \f] 01012 * or another way to phrase this is 01013 * 01014 * where 01015 * 01016 * @param mu Output vector of species chemical 01017 * potentials. Length: m_kk. Units: J/kmol 01018 */ 01019 virtual void getChemPotentials(doublereal* mu) const; 01020 01021 //! Returns an array of partial molar enthalpies for the species 01022 //! in the mixture. Units (J/kmol) 01023 /*! 01024 * For this phase, the partial molar enthalpies are equal to the 01025 * standard state enthalpies modified by the derivative of the 01026 * molality-based activity coefficent wrt temperature 01027 * 01028 * \f[ 01029 * \bar h_k(T,P) = h^{\triangle}_k(T,P) - R T^2 \frac{d \ln(\gamma_k^\triangle)}{dT} 01030 * \f] 01031 * The solvent partial molar enthalpy is equal to 01032 * \f[ 01033 * \bar h_o(T,P) = h^{o}_o(T,P) - R T^2 \frac{d \ln(a_o}{dT} 01034 * \f] 01035 * 01036 * The temperature dependence of the activity coefficients currently 01037 * only occurs through the temperature dependence of the Debye constant. 01038 * 01039 * @param hbar Output vector of species partial molar enthalpies. 01040 * Length: m_kk. units are J/kmol. 01041 */ 01042 virtual void getPartialMolarEnthalpies(doublereal* hbar) const; 01043 01044 //! Returns an array of partial molar entropies of the species in the 01045 //! solution. Units: J/kmol/K. 01046 /** 01047 * Maxwell's equations provide an insight in how to calculate this 01048 * (p.215 Smith and Van Ness) 01049 * 01050 * d(chemPot_i)/dT = -sbar_i 01051 * 01052 * For this phase, the partial molar entropies are equal to the 01053 * SS species entropies plus the ideal solution contribution.following 01054 * contribution: 01055 * \f[ 01056 * \bar s_k(T,P) = \hat s^0_k(T) - R log(M0 * molality[k]) 01057 * \f] 01058 * \f[ 01059 * \bar s_solvent(T,P) = \hat s^0_solvent(T) 01060 * - R ((xmolSolvent - 1.0) / xmolSolvent) 01061 * \f] 01062 * 01063 * The reference-state pure-species entropies,\f$ \hat s^0_k(T) \f$, 01064 * at the reference pressure, \f$ P_{ref} \f$, are computed by the 01065 * species thermodynamic 01066 * property manager. They are polynomial functions of temperature. 01067 * @see SpeciesThermo 01068 * 01069 * @param sbar Output vector of species partial molar entropies. 01070 * Length = m_kk. units are J/kmol/K. 01071 */ 01072 virtual void getPartialMolarEntropies(doublereal* sbar) const; 01073 01074 //! Return an array of partial molar heat capacities for the 01075 //! species in the mixture. Units: J/kmol/K 01076 /*! 01077 * @param cpbar Output vector of species partial molar heat 01078 * capacities at constant pressure. 01079 * Length = m_kk. units are J/kmol/K. 01080 */ 01081 virtual void getPartialMolarCp(doublereal* cpbar) const; 01082 01083 //! Return an array of partial molar volumes for the 01084 //! species in the mixture. Units: m^3/kmol. 01085 /*! 01086 * For this solution, the partial molar volumes are equal to the 01087 * constant species molar volumes. 01088 * 01089 * @param vbar Output vector of speciar partial molar volumes. 01090 * Length = m_kk. units are m^3/kmol. 01091 */ 01092 virtual void getPartialMolarVolumes(doublereal* vbar) const; 01093 01094 //@} 01095 01096 01097 protected: 01098 01099 //! Updates the standard state thermodynamic functions at the current T and P of the solution. 01100 /*! 01101 * @internal 01102 * 01103 * This function gets called for every call to a public function in this 01104 * class. It checks to see whether the temperature or pressure has changed and 01105 * thus whether the ss thermodynamics functions must be recalculated. 01106 * 01107 * @param pres Pressure at which to evaluate the standard states. 01108 * The default, indicated by a -1.0, is to use the current pressure 01109 */ 01110 //virtual void _updateStandardStateThermo() const; 01111 01112 //@} 01113 /// @name Thermodynamic Values for the Species Reference States --- 01114 //@{ 01115 01116 01117 /////////////////////////////////////////////////////// 01118 // 01119 // The methods below are not virtual, and should not 01120 // be overloaded. 01121 // 01122 ////////////////////////////////////////////////////// 01123 01124 /** 01125 * @name Specific Properties 01126 * @{ 01127 */ 01128 01129 01130 /** 01131 * @name Setting the State 01132 * 01133 * These methods set all or part of the thermodynamic 01134 * state. 01135 * @{ 01136 */ 01137 01138 //@} 01139 01140 /** 01141 * @name Chemical Equilibrium 01142 * Chemical equilibrium. 01143 * @{ 01144 */ 01145 01146 //!This method is used by the ChemEquil equilibrium solver. 01147 /*! 01148 * It sets the state such that the chemical potentials satisfy 01149 * \f[ \frac{\mu_k}{\hat R T} = \sum_m A_{k,m} 01150 * \left(\frac{\lambda_m} {\hat R T}\right) \f] where 01151 * \f$ \lambda_m \f$ is the element potential of element m. The 01152 * temperature is unchanged. Any phase (ideal or not) that 01153 * implements this method can be equilibrated by ChemEquil. 01154 * 01155 * @param lambda_RT Input vector of dimensionless element potentials 01156 * The length is equal to nElements(). 01157 */ 01158 public: 01159 virtual void setToEquilState(const doublereal* lambda_RT) { 01160 err("setToEquilState"); 01161 } 01162 01163 01164 //@} 01165 01166 01167 //! Set the equation of state parameters 01168 /*! 01169 * @internal 01170 * The number and meaning of these depends on the subclass. 01171 * 01172 * @param n number of parameters 01173 * @param c array of \a n coefficients 01174 */ 01175 virtual void setParameters(int n, doublereal* const c); 01176 01177 //! Get the equation of state parameters in a vector 01178 /*! 01179 * @internal 01180 * The number and meaning of these depends on the subclass. 01181 * 01182 * @param n number of parameters 01183 * @param c array of \a n coefficients 01184 */ 01185 virtual void getParameters(int &n, doublereal * const c) const; 01186 01187 //! Set equation of state parameter values from XML entries. 01188 /*! 01189 * 01190 * This method is called by function importPhase() in 01191 * file importCTML.cpp when processing a phase definition in 01192 * an input file. It should be overloaded in subclasses to set 01193 * any parameters that are specific to that particular phase 01194 * model. Note, this method is called before the phase is 01195 * initialzed with elements and/or species. 01196 * 01197 * @param eosdata An XML_Node object corresponding to 01198 * the "thermo" entry for this phase in the input file. 01199 */ 01200 virtual void setParametersFromXML(const XML_Node& eosdata); 01201 01202 //--------------------------------------------------------- 01203 /// @name Critical state properties. 01204 /// These methods are only implemented by some subclasses. 01205 01206 //@{ 01207 01208 01209 01210 //@} 01211 01212 /// @name Saturation properties. 01213 /// These methods are only implemented by subclasses that 01214 /// implement full liquid-vapor equations of state. 01215 /// 01216 virtual doublereal satTemperature(doublereal p) const { 01217 err("satTemperature"); return -1.0; 01218 } 01219 01220 //! Get the saturation pressure for a given temperature. 01221 /*! 01222 * Note the limitations of this function. Stability considerations 01223 * concernting multiphase equilibrium are ignored in this 01224 * calculation. Therefore, the call is made directly to the SS of 01225 * water underneath. The object is put back into its original 01226 * state at the end of the call. 01227 * 01228 * @todo This is probably not implemented correctly. The stability 01229 * of the salt should be added into this calculation. The 01230 * underlying water model may be called to get the stability 01231 * of the pure water solution, if needed. 01232 * 01233 * @param T Temperature (kelvin) 01234 */ 01235 virtual doublereal satPressure(doublereal T) const { 01236 err("satPressure"); return -1.0; 01237 } 01238 01239 virtual doublereal vaporFraction() const { 01240 err("vaprFraction"); return -1.0; 01241 } 01242 01243 virtual void setState_Tsat(doublereal t, doublereal x) { 01244 err("setState_sat"); 01245 } 01246 01247 virtual void setState_Psat(doublereal p, doublereal x) { 01248 err("setState_sat"); 01249 } 01250 01251 //@} 01252 01253 01254 /* 01255 * -------------- Utilities ------------------------------- 01256 */ 01257 01258 01259 /** 01260 * Return a reference to the species thermodynamic property 01261 * manager. @todo This method will fail if no species thermo 01262 * manager has been installed. 01263 */ 01264 SpeciesThermo& speciesThermo() { return *m_spthermo; } 01265 01266 //! Initialize the object's internal lengths after species are set 01267 /** 01268 * @internal Initialize. This method is provided to allow 01269 * subclasses to perform any initialization required after all 01270 * species have been added. For example, it might be used to 01271 * resize internal work arrays that must have an entry for 01272 * each species. The base class implementation does nothing, 01273 * and subclasses that do not require initialization do not 01274 * need to overload this method. When importing a CTML phase 01275 * description, this method is called just prior to returning 01276 * from function importPhase(). 01277 * 01278 * Cascading call sequence downwards starting with Parent. 01279 * 01280 * @internal 01281 * 01282 * @see importCTML.cpp 01283 */ 01284 virtual void initThermo(); 01285 01286 01287 //! Initialization of a DebyeHuckel phase using an xml file 01288 /*! 01289 * This routine is a precursor to initThermo(XML_Node*) 01290 * routine, which does most of the work. 01291 * 01292 * @param infile XML file containing the description of the 01293 * phase 01294 * 01295 * @param id Optional parameter identifying the name of the 01296 * phase. If none is given, the first XML 01297 * phase element will be used. 01298 */ 01299 void constructPhaseFile(std::string infile, std::string id=""); 01300 01301 //! Import and initialize a DebyeHuckel phase 01302 //! specification in an XML tree into the current object. 01303 /*! 01304 * Here we read an XML description of the phase. 01305 * We import descriptions of the elements that make up the 01306 * species in a phase. 01307 * We import information about the species, including their 01308 * reference state thermodynamic polynomials. We then freeze 01309 * the state of the species. 01310 * 01311 * Then, we read the species molar volumes from the xml 01312 * tree to finish the initialization. 01313 * 01314 * @param phaseNode This object must be the phase node of a 01315 * complete XML tree 01316 * description of the phase, including all of the 01317 * species data. In other words while "phase" must 01318 * point to an XML phase object, it must have 01319 * sibling nodes "speciesData" that describe 01320 * the species in the phase. 01321 * 01322 * @param id ID of the phase. If nonnull, a check is done 01323 * to see if phaseNode is pointing to the phase 01324 * with the correct id. 01325 */ 01326 void constructPhaseXML(XML_Node& phaseNode, std::string id=""); 01327 01328 //! Process the XML file after species are set up. 01329 /*! 01330 * This gets called from importPhase(). It processes the XML file 01331 * after the species are set up. This is the main routine for 01332 * reading in activity coefficient parameters. 01333 * 01334 * @param phaseNode This object must be the phase node of a 01335 * complete XML tree 01336 * description of the phase, including all of the 01337 * species data. In other words while "phase" must 01338 * point to an XML phase object, it must have 01339 * sibling nodes "speciesData" that describe 01340 * the species in the phase. 01341 * @param id ID of the phase. If nonnull, a check is done 01342 * to see if phaseNode is pointing to the phase 01343 * with the correct id. 01344 */ 01345 virtual void initThermoXML(XML_Node& phaseNode, std::string id); 01346 01347 //! Return the Debye Huckel constant as a function of temperature 01348 //! and pressure (Units = sqrt(kg/gmol)) 01349 /*! 01350 * The default is to assume that it is constant, given 01351 * in the initialization process, and storred in the 01352 * member double, m_A_Debye. Optionally, a full water treatment may be employed that makes 01353 * \f$ A_{Debye} \f$ a full function of T and P. 01354 * 01355 * \f[ 01356 * A_{Debye} = \frac{F e B_{Debye}}{8 \pi \epsilon R T} {\left( C_o \tilde{M}_o \right)}^{1/2} 01357 * \f] 01358 * where 01359 * 01360 * \f[ 01361 * B_{Debye} = \frac{F} {{(\frac{\epsilon R T}{2})}^{1/2}} 01362 * \f] 01363 * Therefore: 01364 * \f[ 01365 * A_{Debye} = \frac{1}{8 \pi} 01366 * {\left(\frac{2 N_a \rho_o}{1000}\right)}^{1/2} 01367 * {\left(\frac{N_a e^2}{\epsilon R T }\right)}^{3/2} 01368 * \f] 01369 * 01370 * Units = sqrt(kg/gmol) 01371 * 01372 * where 01373 * - \f$ N_a \f$ is Avrogadro's number 01374 * - \f$ \rho_w \f$ is the density of water 01375 * - \f$ e \f$ is the electronic charge 01376 * - \f$ \epsilon = K \epsilon_o \f$ is the permitivity of water 01377 * where \f$ K \f$ is the dielectric condstant of water, 01378 * and \f$ \epsilon_o \f$ is the permitivity of free space. 01379 * = \f$ \rho_o \f$ is the density of the solvent in its standard state. 01380 * 01381 * Nominal value at 298 K and 1 atm = 1.172576 (kg/gmol)<SUP>1/2</SUP> 01382 * based on: 01383 * - \f$ \epsilon / \epsilon_0 \f$ = 78.54 01384 * (water at 25C) 01385 * - \f$ \epsilon_0 \f$= 8.854187817E-12 C<SUP>2</SUP> N<SUP>-1</SUP> m<SUP>-2</SUP> 01386 * - e = 1.60217653E-19 C 01387 * - F = 9.6485309E7 C kmol<SUP>-1</SUP> 01388 * - R = 8.314472E3 kg m<SUP>2</SUP> s<SUP>-2</SUP> kmol<SUP>-1</SUP> K<SUP>-1</SUP> 01389 * - T = 298.15 K 01390 * - B_Debye = 3.28640E9 (kg/gmol)<SUP>1/2</SUP> m<SUP>-1</SUP> 01391 * - \f$N_a\f$ = 6.0221415E26 kmol<SUP>-1</SUP> 01392 * 01393 * @param temperature Temperature in kelvin. Defaults to -1, in which 01394 * case the temperature of the phase is assumed. 01395 * 01396 * @param pressure Pressure (Pa). Defaults to -1, in which 01397 * case the pressure of the phase is assumed. 01398 */ 01399 virtual double A_Debye_TP(double temperature = -1.0, 01400 double pressure = -1.0) const; 01401 01402 01403 //! Value of the derivative of the Debye Huckel constant with 01404 //! respect to temperature. 01405 /*! 01406 * This is a function of temperature and pressure. See A_Debye_TP() for 01407 * a definition of \f$ A_{Debye} \f$. 01408 * 01409 * Units = sqrt(kg/gmol) K-1 01410 * 01411 * @param temperature Temperature in kelvin. Defaults to -1, in which 01412 * case the temperature of the phase is assumed. 01413 * 01414 * @param pressure Pressure (Pa). Defaults to -1, in which 01415 * case the pressure of the phase is assumed. 01416 */ 01417 virtual double dA_DebyedT_TP(double temperature = -1.0, 01418 double pressure = -1.0) const; 01419 01420 //! Value of the 2nd derivative of the Debye Huckel constant with 01421 //! respect to temperature as a function of temperature and pressure. 01422 /*! 01423 * This is a function of temperature and pressure. See A_Debye_TP() for 01424 * a definition of \f$ A_{Debye} \f$. 01425 * 01426 * Units = sqrt(kg/gmol) K-2 01427 * 01428 * @param temperature Temperature in kelvin. Defaults to -1, in which 01429 * case the temperature of the phase is assumed. 01430 * 01431 * @param pressure Pressure (Pa). Defaults to -1, in which 01432 * case the pressure of the phase is assumed. 01433 */ 01434 virtual double d2A_DebyedT2_TP(double temperature = -1.0, 01435 double pressure = -1.0) const; 01436 01437 //! Value of the derivative of the Debye Huckel constant with 01438 //! respect to pressure, as a function of temperature and pressure. 01439 /*! 01440 * This is a function of temperature and pressure. See A_Debye_TP() for 01441 * a definition of \f$ A_{Debye} \f$. 01442 * 01443 * Units = sqrt(kg/gmol) Pa-1 01444 * 01445 * @param temperature Temperature in kelvin. Defaults to -1, in which 01446 * case the temperature of the phase is assumed. 01447 * 01448 * @param pressure Pressure (Pa). Defaults to -1, in which 01449 * case the pressure of the phase is assumed. 01450 */ 01451 virtual double dA_DebyedP_TP(double temperature = -1.0, 01452 double pressure = -1.0) const; 01453 01454 //!Reports the ionic radius of the kth species 01455 /*! 01456 * @param k species index. 01457 */ 01458 double AionicRadius(int k = 0) const; 01459 01460 //! Returns the form of the Debye-Huckel parameterization used 01461 int formDH() const { return m_formDH; } 01462 01463 //! Returns a reference to M_Beta_ij 01464 Array2D& get_Beta_ij() { return m_Beta_ij; } 01465 01466 private: 01467 01468 01469 //! Static function that implements the non-polar species 01470 //! salt-out modifications. 01471 /*! 01472 * Returns the calculated activity coefficients. 01473 * 01474 * @param IionicMolality Value of the ionic molality (sqrt(gmol/kg)) 01475 */ 01476 double _nonpolarActCoeff(double IionicMolality) const; 01477 01478 01479 //! Formula for the osmotic coefficient that occurs in the GWB. 01480 /*! 01481 * It is originally from Helgeson for a variable 01482 * NaCl brine. It's to be used with extreme caution. 01483 */ 01484 double _osmoticCoeffHelgesonFixedForm() const; 01485 01486 //! Formula for the log of the water activity that occurs in the GWB. 01487 /*! 01488 * It is originally from Helgeson for a variable 01489 * NaCl brine. It's to be used with extreme caution. 01490 */ 01491 double _lnactivityWaterHelgesonFixedForm() const; 01492 01493 01494 //@} 01495 01496 01497 protected: 01498 01499 01500 //! form of the Debye-Huckel parameterization used in the model. 01501 /*! 01502 * The options are described at the top of this document, 01503 * and in the general documentation. 01504 * The list is repeated here: 01505 * 01506 * DHFORM_DILUTE_LIMIT = 0 (default) 01507 * DHFORM_BDOT_AK = 1 01508 * DHFORM_BDOT_AUNIFORM = 2 01509 * DHFORM_BETAIJ = 3 01510 * DHFORM_PITZER_BETAIJ = 4 01511 */ 01512 int m_formDH; 01513 01514 /** 01515 * Format for the generalized concentration: 01516 * 01517 * 0 = unity 01518 * 1 = molar_volume 01519 * 2 = solvent_volume (default) 01520 * 01521 * The generalized concentrations can have three different forms 01522 * depending on the value of the member attribute m_formGC, which 01523 * is supplied in the constructor. 01524 * <TABLE> 01525 * <TR><TD> m_formGC </TD><TD> GeneralizedConc </TD><TD> StandardConc </TD></TR> 01526 * <TR><TD> 0 </TD><TD> X_k </TD><TD> 1.0 </TD></TR> 01527 * <TR><TD> 1 </TD><TD> X_k / V_k </TD><TD> 1.0 / V_k </TD></TR> 01528 * <TR><TD> 2 </TD><TD> X_k / V_N </TD><TD> 1.0 / V_N </TD></TR> 01529 * </TABLE> 01530 * 01531 * The value and form of the generalized concentration will affect 01532 * reaction rate constants involving species in this phase. 01533 * 01534 * (HKM Note: Using option #1 may lead to spurious results and 01535 * has been included only with warnings. The reason is that it 01536 * molar volumes of electrolytes may often be negative. The 01537 * molar volume of H+ is defined to be zero too. Either options 01538 * 0 or 2 are the appropriate choice. Option 0 leads to 01539 * bulk reaction rate constants which have units of s-1. 01540 * Option 2 leads to bulk reaction rate constants for 01541 * bimolecular rxns which have units of m-3 kmol-1 s-1.) 01542 */ 01543 int m_formGC; 01544 01545 //! Vector containing the electrolyte species type 01546 /*! 01547 * The possible types are: 01548 * - solvent 01549 * - Charged Species 01550 * - weakAcidAssociated 01551 * - strongAcidAssociated 01552 * - polarNeutral 01553 * - nonpolarNeutral 01554 * . 01555 */ 01556 vector_int m_electrolyteSpeciesType; 01557 01558 /** 01559 * Species molar volumes \f$ m^3 kmol^-1 \f$ 01560 * -> m_speciesSize in Constituents.h 01561 */ 01562 //array_fp m_speciesMolarVolume; 01563 01564 /** 01565 * a_k = Size of the ionic species in the DH formulation 01566 * units = meters 01567 */ 01568 array_fp m_Aionic; 01569 01570 /** 01571 * Current value of the ionic strength on the molality scale 01572 */ 01573 mutable double m_IionicMolality; 01574 01575 /** 01576 * Maximum value of the ionic strength allowed in the 01577 * calculation of the activity coefficients. 01578 */ 01579 double m_maxIionicStrength; 01580 01581 public: 01582 01583 /** 01584 * If true, then the fixed for of Helgeson's activity 01585 * for water is used instead of the rigoruous form 01586 * obtained from Gibbs-Duhem relation. This should be 01587 * used with caution, and is really only included as a 01588 * validation exercise. 01589 */ 01590 bool m_useHelgesonFixedForm; 01591 protected: 01592 01593 //! Stoichiometric ionic strength on the molality scale 01594 mutable double m_IionicMolalityStoich; 01595 01596 public: 01597 01598 /** 01599 * Form of the constant outside the Debye-Huckel term 01600 * called A. It's normally a function of temperature 01601 * and pressure. However, it can be set from the 01602 * input file in order to aid in numerical comparisons. 01603 * Acceptable forms: 01604 * 01605 * A_DEBYE_CONST 0 01606 * A_DEBYE_WATER 1 01607 * 01608 * The A_DEBYE_WATER form may be used for water solvents 01609 * with needs to cover varying temperatures and pressures. 01610 * Note, the dielectric constant of water is a relatively 01611 * strong function of T, and its variability must be 01612 * accounted for, 01613 */ 01614 int m_form_A_Debye; 01615 01616 protected: 01617 01618 //! Current value of the Debye Constant, A_Debye 01619 /** 01620 * A_Debye -> this expression appears on the top of the 01621 * ln actCoeff term in the general Debye-Huckel 01622 * expression 01623 * It depends on temperature and pressure. 01624 * 01625 * A_Debye = (F e B_Debye) / (8 Pi epsilon R T) 01626 * 01627 * Units = sqrt(kg/gmol) 01628 * 01629 * Nominal value(298K, atm) = 1.172576 sqrt(kg/gmol) 01630 * based on: 01631 * epsilon/epsilon_0 = 78.54 01632 * (water at 25C) 01633 * epsilon_0 = 8.854187817E12 C2 N-1 m-2 01634 * e = 8.314472E3 kg m2 s-2 kmol-1 K-1 01635 * F = 9.6485309E7 C kmol-1 01636 * R = 8.314472E3 kg m2 s-2 kmol-1 K-1 01637 * T = 298.15 K 01638 * B_Debye = 3.28640E9 sqrt(kg/gmol)/m 01639 * 01640 * note in Pitzer's nomenclature, A_phi = A_Debye/3.0 01641 */ 01642 mutable double m_A_Debye; 01643 01644 //! Current value of the constant that appears in the denominator 01645 /** 01646 * B_Debye -> this expression appears on the bottom of the 01647 * ln actCoeff term in the general Debye-Huckel 01648 * expression 01649 * It depends on temperature 01650 * 01651 * B_Bebye = F / sqrt( epsilon R T / 2 ) 01652 * 01653 * Units = sqrt(kg/gmol) / m 01654 * 01655 * Nominal value = 3.28640E9 sqrt(kg/gmol) / m 01656 * based on: 01657 * epsilon/epsilon_0 = 78.54 01658 * (water at 25C) 01659 * epsilon_0 = 8.854187817E12 C2 N-1 m-2 01660 * e = 8.314472E3 kg m2 s-2 kmol-1 K-1 01661 * F = 9.6485309E7 C kmol-1 01662 * R = 8.314472E3 kg m2 s-2 kmol-1 K-1 01663 * T = 298.15 K 01664 */ 01665 double m_B_Debye; 01666 01667 //! Array of B_Dot valyes 01668 /** 01669 * B_Dot -> This expression is an extension of the 01670 * Debye-Huckel expression used in some formulations 01671 * to extend DH to higher molalities. 01672 * B_dot is specific to the major ionic pair. 01673 */ 01674 array_fp m_B_Dot; 01675 01676 /** 01677 * m_npActCoeff -> These are coefficients to describe 01678 * the increase in activity coeff for non-polar molecules 01679 * due to the electrolyte becoming stronger (the so-called 01680 * salt-out effect) 01681 */ 01682 array_fp m_npActCoeff; 01683 01684 01685 //! Pointer to the Water standard state object 01686 /*! 01687 * derived from the equation of state for water. 01688 */ 01689 PDSS_Water *m_waterSS; 01690 01691 //! Storage for the density of water's standard state 01692 /*! 01693 * Density depends on temperature and pressure. 01694 */ 01695 double m_densWaterSS; 01696 01697 /** 01698 * Pointer to the water property calculator 01699 */ 01700 WaterProps *m_waterProps; 01701 01702 /** 01703 * Vector containing the species reference exp(-G/RT) functions 01704 * at T = m_tlast 01705 */ 01706 mutable vector_fp m_expg0_RT; 01707 01708 /** 01709 * Vector of potential energies for the species. 01710 */ 01711 mutable vector_fp m_pe; 01712 01713 /** 01714 * Temporary array used in equilibrium calculations 01715 */ 01716 mutable vector_fp m_pp; 01717 01718 /** 01719 * vector of size m_kk, used as a temporary holding area. 01720 */ 01721 mutable vector_fp m_tmpV; 01722 01723 /** 01724 * Stoichiometric species charge -> This is for calculations 01725 * of the ionic strength which ignore ion-ion pairing into 01726 * neutral molecules. The Stoichiometric species charge is the 01727 * charge of one of the ion that would occur if the species broke 01728 * into two charged ion pairs. 01729 * NaCl -> m_speciesCharge_Stoich = -1; 01730 * HSO4- -> H+ + SO42- = -2 01731 * -> The other charge is calculated. 01732 * For species that aren't ion pairs, its equal to the 01733 * m_speciesCharge[] value. 01734 */ 01735 vector_fp m_speciesCharge_Stoich; 01736 01737 /** 01738 * Array of 2D data used in the DHFORM_BETAIJ formulation 01739 * Beta_ij.value(i,j) is the coefficient of the jth species 01740 * for the specification of the chemical potential of the ith 01741 * species. 01742 */ 01743 Array2D m_Beta_ij; 01744 01745 //! Logarithm of the activity coefficients on the molality scale. 01746 /*! 01747 * mutable because we change this if the composition 01748 * or temperature or pressure changes. 01749 */ 01750 mutable array_fp m_lnActCoeffMolal; 01751 01752 //! Derivative of log act coeff wrt T 01753 mutable array_fp m_dlnActCoeffMolaldT; 01754 01755 //! 2nd Derivative of log act coeff wrt T 01756 mutable array_fp m_d2lnActCoeffMolaldT2; 01757 01758 //! Derivative of log act coeff wrt P 01759 mutable array_fp m_dlnActCoeffMolaldP; 01760 01761 private: 01762 doublereal err(std::string msg) const; 01763 01764 //! Initialize the internal lengths. 01765 /*! 01766 * This internal function adjusts the lengths of arrays based on 01767 * the number of species. 01768 */ 01769 void initLengths(); 01770 01771 private: 01772 //! Calculate the log activity coefficients 01773 /*! 01774 * This function updates the internally storred 01775 * natural logarithm of the molality activity coefficients 01776 */ 01777 void s_update_lnMolalityActCoeff() const; 01778 01779 //! Calculation of temperatue derivative of activity coefficient 01780 /*! 01781 * Using internally stored values, this function calculates 01782 * the temperature derivative of the logarithm of the 01783 * activity coefficient for all species in the mechanism. 01784 * 01785 * We assume that the activity coefficients are current in this routine 01786 * 01787 * 01788 * 01789 * The solvent activity coefficient is on the molality scale. It's derivative is too. 01790 */ 01791 void s_update_dlnMolalityActCoeff_dT() const; 01792 01793 //! Calculate the temperature 2nd derivative of the activity coefficient 01794 /*! 01795 * Using internally stored values, this function calculates 01796 * the temperature 2nd derivative of the logarithm of the 01797 * activity coefficient for all species in the mechanism. 01798 * 01799 * We assume that the activity coefficients are current in this routine 01800 * 01801 * solvent activity coefficient is on the molality 01802 * scale. It's derivatives are too. 01803 * 01804 * note: private routine 01805 */ 01806 void s_update_d2lnMolalityActCoeff_dT2() const; 01807 01808 //! Calculate the pressure derivative of the activity coefficient 01809 /*! 01810 * Using internally stored values, this function calculates 01811 * the pressure derivative of the logarithm of the 01812 * activity coefficient for all species in the mechanism. 01813 * 01814 * We assume that the activity coefficients, molalities, 01815 * and A_Debye are current. 01816 * 01817 * solvent activity coefficient is on the molality 01818 * scale. It's derivatives are too. 01819 */ 01820 void s_update_dlnMolalityActCoeff_dP() const; 01821 }; 01822 01823 } 01824 01825 #endif 01826 01827 01828 01829 01830