HMWSoln.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file HMWSoln.cpp
00003  *    Definitions for the %HMWSoln ThermoPhase object, which 
00004  *    models concentrated electrolyte solutions
00005  *    (see \ref thermoprops and \link Cantera::HMWSoln HMWSoln \endlink) .
00006  *
00007  * Class %HMWSoln represents a concentrated liquid electrolyte phase which
00008  * obeys the Pitzer formulation for nonideality using molality-based
00009  * standard states.
00010  *
00011  * This version of the code was modified to have the binary Beta2 Pitzer 
00012  * parameter consistent with the temperature expansions used for Beta0, 
00013  * Beta1, and Cphi.(CFJC, SNL)
00014  */
00015 /*
00016  * Copywrite (2006) Sandia Corporation. Under the terms of 
00017  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
00018  * U.S. Government retains certain rights in this software.
00019  */
00020 /*
00021  * $Id: HMWSoln.cpp 398 2010-02-09 20:24:11Z hkmoffa $
00022  */
00023 //@{
00024 #ifndef MAX
00025 #define MAX(x,y)    (( (x) > (y) ) ? (x) : (y))
00026 #endif
00027 //@}
00028 #include "HMWSoln.h"
00029 #include "ThermoFactory.h"
00030 #include "WaterProps.h"
00031 #include "PDSS_Water.h"
00032 
00033 #include <cmath>
00034 #include <cstdlib>
00035 
00036 namespace Cantera {
00037 
00038   /*
00039    * Default constructor
00040    */
00041   HMWSoln::HMWSoln() :
00042     MolalityVPSSTP(),
00043     m_formPitzer(PITZERFORM_BASE),
00044     m_formPitzerTemp(PITZER_TEMP_CONSTANT),
00045     m_formGC(2),
00046     m_IionicMolality(0.0),
00047     m_maxIionicStrength(100.0),
00048     m_TempPitzerRef(298.15),
00049     m_IionicMolalityStoich(0.0),
00050     m_form_A_Debye(A_DEBYE_WATER),
00051     m_A_Debye(1.172576),   // units = sqrt(kg/gmol)
00052     m_waterSS(0),
00053     m_densWaterSS(1000.),
00054     m_waterProps(0),
00055     m_molalitiesAreCropped(false),
00056     IMS_typeCutoff_(0),
00057     IMS_X_o_cutoff_(0.2),
00058     IMS_gamma_o_min_(1.0E-5),
00059     IMS_gamma_k_min_(10.0),
00060     IMS_cCut_(0.05),
00061     IMS_slopefCut_(0.6),
00062     IMS_dfCut_(0.0),
00063     IMS_efCut_(0.0),
00064     IMS_afCut_(0.0),
00065     IMS_bfCut_(0.0),
00066     IMS_slopegCut_(0.0),
00067     IMS_dgCut_(0.0),
00068     IMS_egCut_(0.0),
00069     IMS_agCut_(0.0),
00070     IMS_bgCut_(0.0),
00071     MC_X_o_cutoff_(0.0),
00072     MC_X_o_min_(0.0),
00073     MC_slopepCut_(0.0),
00074     MC_dpCut_(0.0),
00075     MC_epCut_(0.0),
00076     MC_apCut_(0.0),
00077     MC_bpCut_(0.0),
00078     MC_cpCut_(0.0),
00079     CROP_ln_gamma_o_min(-6.0),
00080     CROP_ln_gamma_o_max(3.0),
00081     CROP_ln_gamma_k_min(-5.0),
00082     CROP_ln_gamma_k_max(15.0),
00083     m_debugCalc(0)
00084   {
00085     for (int i = 0; i < 17; i++) {
00086       elambda[i] = 0.0;
00087       elambda1[i] = 0.0;
00088     }
00089   }
00090   /*
00091    * Working constructors
00092    *
00093    *  The two constructors below are the normal way
00094    *  the phase initializes itself. They are shells that call
00095    *  the routine initThermo(), with a reference to the
00096    *  XML database to get the info for the phase.
00097    */
00098   HMWSoln::HMWSoln(std::string inputFile, std::string id) :
00099     MolalityVPSSTP(),
00100     m_formPitzer(PITZERFORM_BASE),
00101     m_formPitzerTemp(PITZER_TEMP_CONSTANT),
00102     m_formGC(2),
00103     m_IionicMolality(0.0),
00104     m_maxIionicStrength(100.0),
00105     m_TempPitzerRef(298.15),
00106     m_IionicMolalityStoich(0.0),
00107     m_form_A_Debye(A_DEBYE_WATER),
00108     m_A_Debye(1.172576),   // units = sqrt(kg/gmol)
00109     m_waterSS(0),
00110     m_densWaterSS(1000.),
00111     m_waterProps(0),
00112     m_molalitiesAreCropped(false),
00113     IMS_typeCutoff_(0),
00114     IMS_X_o_cutoff_(0.2),
00115     IMS_gamma_o_min_(1.0E-5),
00116     IMS_gamma_k_min_(10.0),
00117     IMS_cCut_(0.05),
00118     IMS_slopefCut_(0.6),
00119     IMS_dfCut_(0.0),
00120     IMS_efCut_(0.0),
00121     IMS_afCut_(0.0),
00122     IMS_bfCut_(0.0),
00123     IMS_slopegCut_(0.0),
00124     IMS_dgCut_(0.0),
00125     IMS_egCut_(0.0),
00126     IMS_agCut_(0.0),
00127     IMS_bgCut_(0.0),
00128     MC_X_o_cutoff_(0.0),
00129     MC_X_o_min_(0.0),
00130     MC_slopepCut_(0.0),
00131     MC_dpCut_(0.0),
00132     MC_epCut_(0.0),
00133     MC_apCut_(0.0),
00134     MC_bpCut_(0.0),
00135     MC_cpCut_(0.0),
00136     CROP_ln_gamma_o_min(-6.0),
00137     CROP_ln_gamma_o_max(3.0),
00138     CROP_ln_gamma_k_min(-5.0),
00139     CROP_ln_gamma_k_max(15.0),
00140     m_debugCalc(0)
00141   {
00142     for (int i = 0; i < 17; i++) {
00143       elambda[i] = 0.0;
00144       elambda1[i] = 0.0;
00145     }
00146     constructPhaseFile(inputFile, id);
00147   }
00148 
00149   HMWSoln::HMWSoln(XML_Node& phaseRoot, std::string id) :
00150     MolalityVPSSTP(),
00151     m_formPitzer(PITZERFORM_BASE),
00152     m_formPitzerTemp(PITZER_TEMP_CONSTANT),
00153     m_formGC(2),
00154     m_IionicMolality(0.0),
00155     m_maxIionicStrength(100.0),
00156     m_TempPitzerRef(298.15),
00157     m_IionicMolalityStoich(0.0),
00158     m_form_A_Debye(A_DEBYE_WATER),
00159     m_A_Debye(1.172576),   // units = sqrt(kg/gmol)
00160     m_waterSS(0),
00161     m_densWaterSS(1000.),
00162     m_waterProps(0),
00163     m_molalitiesAreCropped(false),
00164     IMS_typeCutoff_(0),
00165     IMS_X_o_cutoff_(0.2),
00166     IMS_gamma_o_min_(1.0E-5),
00167     IMS_gamma_k_min_(10.0),
00168     IMS_cCut_(0.05),
00169     IMS_slopefCut_(0.6),
00170     IMS_dfCut_(0.0),
00171     IMS_efCut_(0.0),
00172     IMS_afCut_(0.0),
00173     IMS_bfCut_(0.0),
00174     IMS_slopegCut_(0.0),
00175     IMS_dgCut_(0.0),
00176     IMS_egCut_(0.0),
00177     IMS_agCut_(0.0),
00178     IMS_bgCut_(0.0),
00179     MC_X_o_cutoff_(0.0),
00180     MC_X_o_min_(0.0),
00181     MC_slopepCut_(0.0),
00182     MC_dpCut_(0.0),
00183     MC_epCut_(0.0),
00184     MC_apCut_(0.0),
00185     MC_bpCut_(0.0),
00186     MC_cpCut_(0.0),
00187     CROP_ln_gamma_o_min(-6.0),
00188     CROP_ln_gamma_o_max(3.0),
00189     CROP_ln_gamma_k_min(-5.0),
00190     CROP_ln_gamma_k_max(15.0),
00191     m_debugCalc(0)
00192   {
00193     for (int i = 0; i < 17; i++) {
00194       elambda[i] = 0.0;
00195       elambda1[i] = 0.0;
00196     }
00197     constructPhaseXML(phaseRoot, id);
00198   }
00199  
00200   /*
00201    * Copy Constructor:
00202    *
00203    *  Note this stuff will not work until the underlying phase
00204    *  has a working copy constructor
00205    */
00206   HMWSoln::HMWSoln(const HMWSoln &b) :
00207     MolalityVPSSTP(),
00208     m_formPitzer(PITZERFORM_BASE),
00209     m_formPitzerTemp(PITZER_TEMP_CONSTANT),
00210     m_formGC(2),
00211     m_IionicMolality(0.0),
00212     m_maxIionicStrength(100.0),
00213     m_TempPitzerRef(298.15),
00214     m_IionicMolalityStoich(0.0),
00215     m_form_A_Debye(A_DEBYE_WATER),
00216     m_A_Debye(1.172576),   // units = sqrt(kg/gmol)
00217     m_waterSS(0),
00218     m_densWaterSS(1000.),
00219     m_waterProps(0),
00220     m_molalitiesAreCropped(false),
00221     IMS_typeCutoff_(0),
00222     IMS_X_o_cutoff_(0.2),
00223     IMS_gamma_o_min_(1.0E-5),
00224     IMS_gamma_k_min_(10.0),
00225     IMS_cCut_(0.05),
00226     IMS_slopefCut_(0.6),
00227     IMS_dfCut_(0.0),
00228     IMS_efCut_(0.0),
00229     IMS_afCut_(0.0),
00230     IMS_bfCut_(0.0),
00231     IMS_slopegCut_(0.0),
00232     IMS_dgCut_(0.0),
00233     IMS_egCut_(0.0),
00234     IMS_agCut_(0.0),
00235     IMS_bgCut_(0.0),
00236     MC_X_o_cutoff_(0.0),
00237     MC_X_o_min_(0.0),
00238     MC_slopepCut_(0.0),
00239     MC_dpCut_(0.0),
00240     MC_epCut_(0.0),
00241     MC_apCut_(0.0),
00242     MC_bpCut_(0.0),
00243     MC_cpCut_(0.0),
00244     CROP_ln_gamma_o_min(-6.0),
00245     CROP_ln_gamma_o_max(3.0),
00246     CROP_ln_gamma_k_min(-5.0),
00247     CROP_ln_gamma_k_max(15.0),
00248     m_debugCalc(0)
00249   {
00250     /*
00251      * Use the assignment operator to do the brunt
00252      * of the work for the copy construtor.
00253      */
00254     *this = b;
00255   }
00256 
00257   /*
00258    * operator=()
00259    *
00260    *  Note this stuff will not work until the underlying phase
00261    *  has a working assignment operator
00262    */
00263   HMWSoln& HMWSoln::
00264   operator=(const HMWSoln &b) {
00265     if (&b != this) {
00266       MolalityVPSSTP::operator=(b);
00267       m_formPitzer          = b.m_formPitzer;
00268       m_formPitzerTemp      = b.m_formPitzerTemp;
00269       m_formGC              = b.m_formGC;
00270       m_Aionic              = b.m_Aionic;
00271       m_IionicMolality      = b.m_IionicMolality;
00272       m_maxIionicStrength   = b.m_maxIionicStrength;
00273       m_TempPitzerRef       = b.m_TempPitzerRef;
00274       m_IionicMolalityStoich= b.m_IionicMolalityStoich;
00275       m_form_A_Debye        = b.m_form_A_Debye;
00276       m_A_Debye             = b.m_A_Debye;
00277     
00278       // This is an internal shallow copy of the PDSS_Water pointer
00279       m_waterSS = providePDSS(0);
00280       if (!m_waterSS) {
00281         throw CanteraError("HMWSoln::operator=()", "Dynamic cast to PDSS_Water failed");
00282       }
00283     
00284       m_densWaterSS         = b.m_densWaterSS;
00285 
00286       if (m_waterProps) {
00287         delete m_waterProps;
00288         m_waterProps = 0;
00289       }
00290       if (b.m_waterProps) {
00291         m_waterProps = new WaterProps(dynamic_cast<PDSS_Water*>(m_waterSS));
00292       }
00293 
00294       m_expg0_RT            = b.m_expg0_RT;
00295       m_pe                  = b.m_pe;
00296       m_pp                  = b.m_pp;
00297       m_tmpV                = b.m_tmpV;
00298       m_speciesCharge_Stoich= b.m_speciesCharge_Stoich;
00299       m_Beta0MX_ij          = b.m_Beta0MX_ij;
00300       m_Beta0MX_ij_L        = b.m_Beta0MX_ij_L;
00301       m_Beta0MX_ij_LL       = b.m_Beta0MX_ij_LL;
00302       m_Beta0MX_ij_P        = b.m_Beta0MX_ij_P;
00303       m_Beta0MX_ij_coeff    = b.m_Beta0MX_ij_coeff;
00304       m_Beta1MX_ij          = b.m_Beta1MX_ij;
00305       m_Beta1MX_ij_L        = b.m_Beta1MX_ij_L;
00306       m_Beta1MX_ij_LL       = b.m_Beta1MX_ij_LL;
00307       m_Beta1MX_ij_P        = b.m_Beta1MX_ij_P;
00308       m_Beta1MX_ij_coeff    = b.m_Beta1MX_ij_coeff;
00309       m_Beta2MX_ij          = b.m_Beta2MX_ij;
00310       m_Beta2MX_ij_L        = b.m_Beta2MX_ij_L;
00311       m_Beta2MX_ij_LL       = b.m_Beta2MX_ij_LL;
00312       m_Beta2MX_ij_P        = b.m_Beta2MX_ij_P;
00313       m_Beta2MX_ij_coeff    = b.m_Beta2MX_ij_coeff;
00314       m_Alpha1MX_ij         = b.m_Alpha1MX_ij;
00315       m_Alpha2MX_ij         = b.m_Alpha2MX_ij;
00316       m_CphiMX_ij           = b.m_CphiMX_ij;
00317       m_CphiMX_ij_L         = b.m_CphiMX_ij_L;
00318       m_CphiMX_ij_LL        = b.m_CphiMX_ij_LL;
00319       m_CphiMX_ij_P         = b.m_CphiMX_ij_P;
00320       m_CphiMX_ij_coeff     = b.m_CphiMX_ij_coeff;
00321       m_Theta_ij            = b.m_Theta_ij;
00322       m_Theta_ij_L          = b.m_Theta_ij_L;
00323       m_Theta_ij_LL         = b.m_Theta_ij_LL;
00324       m_Theta_ij_P          = b.m_Theta_ij_P;
00325       m_Theta_ij_coeff      = b.m_Theta_ij_coeff;
00326       m_Psi_ijk             = b.m_Psi_ijk;
00327       m_Psi_ijk_L           = b.m_Psi_ijk_L;
00328       m_Psi_ijk_LL          = b.m_Psi_ijk_LL;
00329       m_Psi_ijk_P           = b.m_Psi_ijk_P;
00330       m_Psi_ijk_coeff       = b.m_Psi_ijk_coeff;
00331       m_Lambda_nj           = b.m_Lambda_nj;
00332       m_Lambda_nj_L         = b.m_Lambda_nj_L;
00333       m_Lambda_nj_LL        = b.m_Lambda_nj_LL;
00334       m_Lambda_nj_P         = b.m_Lambda_nj_P;
00335       m_Lambda_nj_coeff     = b.m_Lambda_nj_coeff;
00336       m_lnActCoeffMolal_Scaled       = b.m_lnActCoeffMolal_Scaled;
00337       m_lnActCoeffMolal_Unscaled     = b.m_lnActCoeffMolal_Unscaled;
00338       m_dlnActCoeffMolaldT_Unscaled  = b.m_dlnActCoeffMolaldT_Unscaled;
00339       m_d2lnActCoeffMolaldT2_Unscaled= b.m_d2lnActCoeffMolaldT2_Unscaled;
00340       m_dlnActCoeffMolaldP_Unscaled  = b.m_dlnActCoeffMolaldP_Unscaled;
00341       m_dlnActCoeffMolaldT_Scaled    = b.m_dlnActCoeffMolaldT_Unscaled;
00342       m_d2lnActCoeffMolaldT2_Scaled  = b.m_d2lnActCoeffMolaldT2_Unscaled;
00343       m_dlnActCoeffMolaldP_Scaled    = b.m_dlnActCoeffMolaldP_Unscaled;
00344 
00345       m_gfunc_IJ            = b.m_gfunc_IJ;
00346       m_g2func_IJ           = b.m_g2func_IJ;
00347       m_hfunc_IJ            = b.m_hfunc_IJ;
00348       m_h2func_IJ           = b.m_h2func_IJ;
00349       m_BMX_IJ              = b.m_BMX_IJ;
00350       m_BMX_IJ_L            = b.m_BMX_IJ_L;
00351       m_BMX_IJ_LL           = b.m_BMX_IJ_LL;
00352       m_BMX_IJ_P            = b.m_BMX_IJ_P;
00353       m_BprimeMX_IJ         = b.m_BprimeMX_IJ;
00354       m_BprimeMX_IJ_L       = b.m_BprimeMX_IJ_L;
00355       m_BprimeMX_IJ_LL      = b.m_BprimeMX_IJ_LL;
00356       m_BprimeMX_IJ_P       = b.m_BprimeMX_IJ_P;
00357       m_BphiMX_IJ           = b.m_BphiMX_IJ;
00358       m_BphiMX_IJ_L         = b.m_BphiMX_IJ_L;
00359       m_BphiMX_IJ_LL        = b.m_BphiMX_IJ_LL;
00360       m_BphiMX_IJ_P         = b.m_BphiMX_IJ_P;
00361       m_Phi_IJ              = b.m_Phi_IJ;
00362       m_Phi_IJ_L            = b.m_Phi_IJ_L;
00363       m_Phi_IJ_LL           = b.m_Phi_IJ_LL;
00364       m_Phi_IJ_P            = b.m_Phi_IJ_P;
00365       m_Phiprime_IJ         = b.m_Phiprime_IJ;
00366       m_PhiPhi_IJ           = b.m_PhiPhi_IJ;
00367       m_PhiPhi_IJ_L         = b.m_PhiPhi_IJ_L;
00368       m_PhiPhi_IJ_LL        = b.m_PhiPhi_IJ_LL;
00369       m_PhiPhi_IJ_P         = b.m_PhiPhi_IJ_P;
00370       m_CMX_IJ              = b.m_CMX_IJ;
00371       m_CMX_IJ_L            = b.m_CMX_IJ_L;
00372       m_CMX_IJ_LL           = b.m_CMX_IJ_LL;
00373       m_CMX_IJ_P            = b.m_CMX_IJ_P;
00374       m_gamma_tmp           = b.m_gamma_tmp;
00375 
00376       IMS_lnActCoeffMolal_  = b.IMS_lnActCoeffMolal_;
00377       IMS_typeCutoff_       = b.IMS_typeCutoff_;
00378       IMS_X_o_cutoff_       = b.IMS_X_o_cutoff_;
00379       IMS_gamma_o_min_      = b.IMS_gamma_o_min_;
00380       IMS_gamma_k_min_      = b.IMS_gamma_k_min_;
00381       IMS_cCut_             = b.IMS_cCut_;
00382       IMS_slopefCut_        = b.IMS_slopefCut_;
00383       IMS_dfCut_            = b.IMS_dfCut_;
00384       IMS_efCut_            = b.IMS_efCut_;
00385       IMS_afCut_            = b.IMS_afCut_;
00386       IMS_bfCut_            = b.IMS_bfCut_;
00387       IMS_slopegCut_        = b.IMS_slopegCut_;
00388       IMS_dgCut_            = b.IMS_dgCut_;
00389       IMS_egCut_            = b.IMS_egCut_;
00390       IMS_agCut_            = b.IMS_agCut_;
00391       IMS_bgCut_            = b.IMS_bgCut_;
00392       MC_X_o_cutoff_        = b.MC_X_o_cutoff_;
00393       MC_X_o_min_           = b.MC_X_o_min_;
00394       MC_slopepCut_         = b.MC_slopepCut_;
00395       MC_dpCut_             = b.MC_dpCut_;
00396       MC_epCut_             = b.MC_epCut_;
00397       MC_apCut_             = b.MC_apCut_;
00398       MC_bpCut_             = b.MC_bpCut_;
00399       MC_cpCut_             = b.MC_cpCut_;
00400       CROP_ln_gamma_o_min   = b.CROP_ln_gamma_o_min;
00401       CROP_ln_gamma_o_max   = b.CROP_ln_gamma_o_max;
00402       CROP_ln_gamma_k_min   = b.CROP_ln_gamma_k_min;
00403       CROP_ln_gamma_k_max   = b.CROP_ln_gamma_k_max;
00404       CROP_speciesCropped_  = b.CROP_speciesCropped_;
00405       m_CounterIJ           = b.m_CounterIJ;
00406       m_molalitiesCropped   = b.m_molalitiesCropped;
00407       m_molalitiesAreCropped= b.m_molalitiesAreCropped;
00408       m_debugCalc           = b.m_debugCalc;
00409     }
00410     return *this;
00411   }
00412 
00413 
00414   
00415   /*  
00416    *
00417    *
00418    *  test problems:
00419    *  1 = NaCl problem - 5 species -
00420    *   the thermo is read in from an XML file
00421    *
00422    * speci   molality                        charge
00423    *  Cl-     6.0954          6.0997E+00      -1
00424    *  H+      1.0000E-08      2.1628E-09      1
00425    *  Na+     6.0954E+00      6.0997E+00      1
00426    *  OH-     7.5982E-07      1.3977E-06     -1
00427    *  HMW_params____beta0MX__beta1MX__beta2MX__CphiMX_____alphaMX__thetaij
00428    * 10
00429    * 1  2          0.1775  0.2945   0.0      0.00080    2.0      0.0
00430    * 1  3          0.0765  0.2664   0.0      0.00127    2.0      0.0
00431    * 1  4          0.0     0.0      0.0      0.0        0.0     -0.050
00432    * 2  3          0.0     0.0      0.0      0.0        0.0      0.036
00433    * 2  4          0.0     0.0      0.0      0.0        0.0      0.0
00434    * 3  4          0.0864  0.253    0.0      0.0044     2.0      0.0
00435    * Triplet_interaction_parameters_psiaa'_or_psicc'
00436    * 2
00437    * 1  2  3   -0.004
00438    * 1  3  4   -0.006
00439    */
00440   HMWSoln::HMWSoln(int testProb) :
00441     MolalityVPSSTP(),
00442     m_formPitzer(PITZERFORM_BASE),
00443     m_formPitzerTemp(PITZER_TEMP_CONSTANT),
00444     m_formGC(2),
00445     m_IionicMolality(0.0),
00446     m_maxIionicStrength(100.0),
00447     m_TempPitzerRef(298.15),
00448     m_IionicMolalityStoich(0.0),
00449     m_form_A_Debye(A_DEBYE_WATER),
00450     m_A_Debye(1.172576),   // units = sqrt(kg/gmol)
00451     m_waterSS(0),
00452     m_densWaterSS(1000.),
00453     m_waterProps(0),
00454     m_molalitiesAreCropped(false),
00455     IMS_typeCutoff_(0),
00456     IMS_X_o_cutoff_(0.2),
00457     IMS_gamma_o_min_(1.0E-5),
00458     IMS_gamma_k_min_(10.0),
00459     IMS_cCut_(0.05),
00460     IMS_slopefCut_(0.6),
00461     IMS_dfCut_(0.0),
00462     IMS_efCut_(0.0),
00463     IMS_afCut_(0.0),
00464     IMS_bfCut_(0.0),
00465     IMS_slopegCut_(0.0),
00466     IMS_dgCut_(0.0),
00467     IMS_egCut_(0.0),
00468     IMS_agCut_(0.0),
00469     IMS_bgCut_(0.0),
00470     MC_X_o_cutoff_(0.0),
00471     MC_X_o_min_(0.0),
00472     MC_slopepCut_(0.0),
00473     MC_dpCut_(0.0),
00474     MC_epCut_(0.0),
00475     MC_apCut_(0.0),
00476     MC_bpCut_(0.0),
00477     MC_cpCut_(0.0),
00478     CROP_ln_gamma_o_min(-6.0),
00479     CROP_ln_gamma_o_max(3.0),
00480     CROP_ln_gamma_k_min(-5.0),
00481     CROP_ln_gamma_k_max(15.0),
00482     m_debugCalc(0)
00483   {
00484     if (testProb != 1) {
00485       printf("unknown test problem\n");
00486       exit(EXIT_FAILURE);
00487     }
00488 
00489     constructPhaseFile("HMW_NaCl.xml", "");
00490 
00491     int i = speciesIndex("Cl-");
00492     int j = speciesIndex("H+");
00493     int n = i * m_kk + j;
00494     int ct = m_CounterIJ[n];
00495     m_Beta0MX_ij[ct] = 0.1775;
00496     m_Beta1MX_ij[ct] = 0.2945;
00497     m_CphiMX_ij[ct]  = 0.0008;
00498     m_Alpha1MX_ij[ct]= 2.000;
00499 
00500 
00501     i = speciesIndex("Cl-");
00502     j = speciesIndex("Na+");
00503     n = i * m_kk + j;
00504     ct = m_CounterIJ[n];
00505     m_Beta0MX_ij[ct] = 0.0765;
00506     m_Beta1MX_ij[ct] = 0.2664;
00507     m_CphiMX_ij[ct]  = 0.00127;
00508     m_Alpha1MX_ij[ct]= 2.000;
00509 
00510 
00511     i = speciesIndex("Cl-");
00512     j = speciesIndex("OH-");
00513     n = i * m_kk + j;
00514     ct = m_CounterIJ[n];
00515     m_Theta_ij[ct] = -0.05;
00516 
00517     i = speciesIndex("H+");
00518     j = speciesIndex("Na+");
00519     n = i * m_kk + j;
00520     ct = m_CounterIJ[n];
00521     m_Theta_ij[ct] = 0.036;
00522 
00523     i = speciesIndex("Na+");
00524     j = speciesIndex("OH-");
00525     n = i * m_kk + j;
00526     ct = m_CounterIJ[n];
00527     m_Beta0MX_ij[ct] = 0.0864;
00528     m_Beta1MX_ij[ct] = 0.253;
00529     m_CphiMX_ij[ct]  = 0.0044;
00530     m_Alpha1MX_ij[ct]= 2.000;
00531 
00532     i = speciesIndex("Cl-");
00533     j = speciesIndex("H+");
00534     int k = speciesIndex("Na+");
00535     double param = -0.004;
00536     n = i * m_kk *m_kk + j * m_kk + k ;
00537     m_Psi_ijk[n] = param;
00538     m_Psi_ijk_coeff(0,n) = param;
00539     n = i * m_kk *m_kk + k * m_kk + j ;
00540     m_Psi_ijk[n] = param;
00541     m_Psi_ijk_coeff(0,n) = param;
00542     n = j * m_kk *m_kk + i * m_kk + k ;
00543     m_Psi_ijk[n] = param;
00544     m_Psi_ijk_coeff(0,n) = param;
00545     n = j * m_kk *m_kk + k * m_kk + i ;
00546     m_Psi_ijk[n] = param;
00547     m_Psi_ijk_coeff(0,n) = param;
00548     n = k * m_kk *m_kk + j * m_kk + i ;
00549     m_Psi_ijk[n] = param;
00550     m_Psi_ijk_coeff(0,n) = param;
00551     n = k * m_kk *m_kk + i * m_kk + j ;
00552     m_Psi_ijk[n] = param;
00553     m_Psi_ijk_coeff(0,n) = param;
00554 
00555     i = speciesIndex("Cl-");
00556     j = speciesIndex("Na+");
00557     k = speciesIndex("OH-");
00558     param = -0.006;
00559     n = i * m_kk *m_kk + j * m_kk + k ;
00560     m_Psi_ijk[n] = param;
00561     m_Psi_ijk_coeff(0,n) = param;
00562     n = i * m_kk *m_kk + k * m_kk + j ;
00563     m_Psi_ijk[n] = param;
00564     m_Psi_ijk_coeff(0,n) = param;
00565     n = j * m_kk *m_kk + i * m_kk + k ;
00566     m_Psi_ijk[n] = param;
00567     m_Psi_ijk_coeff(0,n) = param;
00568     n = j * m_kk *m_kk + k * m_kk + i ;
00569     m_Psi_ijk[n] = param;
00570     m_Psi_ijk_coeff(0,n) = param;
00571     n = k * m_kk *m_kk + j * m_kk + i ;
00572     m_Psi_ijk[n] = param;
00573     m_Psi_ijk_coeff(0,n) = param;
00574     n = k * m_kk *m_kk + i * m_kk + j ;
00575     m_Psi_ijk[n] = param;
00576     m_Psi_ijk_coeff(0,n) = param;
00577 
00578     printCoeffs();
00579   }
00580 
00581   /*
00582    * ~HMWSoln():   (virtual)
00583    *
00584    *     Destructor: does nothing:
00585    */
00586   HMWSoln::~HMWSoln() {
00587     if (m_waterProps) {
00588       delete m_waterProps; m_waterProps = 0;
00589     }
00590   }
00591 
00592   /*
00593    *  duplMyselfAsThermoPhase():
00594    *
00595    *  This routine operates at the ThermoPhase level to 
00596    *  duplicate the current object. It uses the copy constructor
00597    *  defined above.
00598    */
00599   ThermoPhase* HMWSoln::duplMyselfAsThermoPhase() const {
00600     HMWSoln* mtp = new HMWSoln(*this);
00601     return (ThermoPhase *) mtp;
00602   }
00603 
00604   /*
00605    * Equation of state type flag. The base class returns
00606    * zero. Subclasses should define this to return a unique
00607    * non-zero value. Constants defined for this purpose are
00608    * listed in mix_defs.h.
00609    */
00610   int HMWSoln::eosType() const {
00611     int res;
00612     switch (m_formGC) {
00613     case 0:
00614       res = cHMWSoln0;
00615       break;
00616     case 1:
00617       res = cHMWSoln1;
00618       break;
00619     case 2:
00620       res = cHMWSoln2;
00621       break;
00622     default:
00623       throw CanteraError("eosType", "Unknown type");
00624     }
00625     return res;
00626   }
00627 
00628   //
00629   // -------- Molar Thermodynamic Properties of the Solution --------------- 
00630   //
00631   /*
00632    * Molar enthalpy of the solution. Units: J/kmol.
00633    */
00634   doublereal HMWSoln::enthalpy_mole() const {
00635     getPartialMolarEnthalpies(DATA_PTR(m_tmpV));
00636     getMoleFractions(DATA_PTR(m_pp));
00637     double val = mean_X(DATA_PTR(m_tmpV));
00638     return val;
00639   }
00640 
00641   doublereal HMWSoln::relative_enthalpy() const {
00642     getPartialMolarEnthalpies(DATA_PTR(m_tmpV));
00643     double hbar = mean_X(DATA_PTR(m_tmpV));
00644     getEnthalpy_RT(DATA_PTR(m_gamma_tmp));
00645     double RT = GasConstant * temperature();
00646     for (int k = 0; k < m_kk; k++) {
00647       m_gamma_tmp[k] *= RT;
00648     }
00649     double h0bar = mean_X(DATA_PTR(m_gamma_tmp));
00650     return (hbar - h0bar);
00651   }
00652 
00653 
00654 
00655   doublereal HMWSoln::relative_molal_enthalpy() const {
00656     double L = relative_enthalpy();
00657     getMoleFractions(DATA_PTR(m_tmpV));
00658     double xanion = 0.0;
00659     int kcation = -1;
00660     double xcation = 0.0;
00661     int kanion = -1;
00662     const double *charge =  DATA_PTR(m_speciesCharge);
00663     for (int k = 0; k < m_kk; k++) {
00664       if (charge[k] > 0.0) {
00665         if (m_tmpV[k] > xanion) {
00666           xanion = m_tmpV[k];
00667           kanion = k;
00668         }
00669       } else if (charge[k] < 0.0) {
00670         if (m_tmpV[k] > xcation) {
00671           xcation = m_tmpV[k];
00672           kcation = k;
00673         }
00674       }
00675     }
00676     if (kcation < 0 || kanion < 0) {
00677       return L;
00678     }
00679     double xuse = xcation;
00680     int kuse = kcation;
00681     double factor = 1;
00682     if (xanion < xcation) {
00683       xuse = xanion;
00684       kuse = kanion;
00685       if (charge[kcation] != 1.0) {
00686         factor = charge[kcation];
00687       }
00688     } else {
00689       if (charge[kanion] != 1.0) {
00690         factor = charge[kanion];
00691       }
00692     }
00693     xuse = xuse / factor;
00694     L = L / xuse;
00695     return L;
00696   }
00697 
00698   /*
00699    * Molar internal energy of the solution. Units: J/kmol.
00700    *
00701    * This is calculated from the soln enthalpy and then
00702    * subtracting pV.
00703    */
00704   doublereal HMWSoln::intEnergy_mole() const {
00705     double hh = enthalpy_mole();
00706     double pres = pressure();
00707     double molarV = 1.0/molarDensity();
00708     double uu = hh - pres * molarV;
00709     return uu;
00710   }
00711 
00712   /*
00713    *  Molar soln entropy at constant pressure. Units: J/kmol/K. 
00714    *
00715    *  This is calculated from the partial molar entropies.
00716    */
00717   doublereal HMWSoln::entropy_mole() const {
00718     getPartialMolarEntropies(DATA_PTR(m_tmpV));
00719     return mean_X(DATA_PTR(m_tmpV));
00720   }
00721 
00722   /// Molar Gibbs function. Units: J/kmol. 
00723   doublereal HMWSoln::gibbs_mole() const {
00724     getChemPotentials(DATA_PTR(m_tmpV));
00725     return mean_X(DATA_PTR(m_tmpV));
00726   }
00727 
00728   /* Molar heat capacity at constant pressure. Units: J/kmol/K.
00729    *
00730    * Returns the solution heat capacition at constant pressure. 
00731    * This is calculated from the partial molar heat capacities.
00732    */ 
00733   doublereal HMWSoln::cp_mole() const {
00734     getPartialMolarCp(DATA_PTR(m_tmpV));
00735     double val = mean_X(DATA_PTR(m_tmpV));
00736     return val;
00737   }
00738 
00739   // Molar heat capacity at constant volume. Units: J/kmol/K. 
00740   doublereal HMWSoln::cv_mole() const {
00741     //getPartialMolarCv(m_tmpV.begin());
00742     //return mean_X(m_tmpV.begin());
00743     err("not implemented");
00744     return 0.0;
00745   }
00746 
00747   //
00748   // ------- Mechanical Equation of State Properties ------------------------
00749   //
00750 
00751   /**
00752    * Pressure. Units: Pa.
00753    * For this incompressible system, we return the internally storred
00754    * independent value of the pressure.
00755    */
00756   doublereal HMWSoln::pressure() const {
00757     return m_Pcurrent;
00758   }
00759 
00760   /*
00761    * Set the pressure at constant temperature. Units: Pa.
00762    * This method sets a constant within the object.
00763    * The mass density is not a function of pressure.
00764    */
00765   void HMWSoln::setPressure(doublereal p) {
00766     setState_TP(temperature(), p);
00767   }
00768 
00769   void HMWSoln::calcDensity() {
00770     double *vbar = &m_pp[0];
00771     getPartialMolarVolumes(vbar);
00772     double *x = &m_tmpV[0];
00773     getMoleFractions(x);
00774     doublereal vtotal = 0.0;
00775     for (int i = 0; i < m_kk; i++) {
00776       vtotal += vbar[i] * x[i];
00777     }
00778     doublereal dd = meanMolecularWeight() / vtotal;
00779     State::setDensity(dd);
00780   }
00781 
00782   /*
00783    * The isothermal compressibility. Units: 1/Pa.
00784    * The isothermal compressibility is defined as
00785    * \f[
00786    * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T
00787    * \f]
00788    *
00789    *  It's equal to zero for this model, since the molar volume
00790    *  doesn't change with pressure or temperature.
00791    */
00792   doublereal HMWSoln::isothermalCompressibility() const {
00793     throw CanteraError("HMWSoln::isothermalCompressibility",
00794                        "unimplemented");
00795     return 0.0;
00796   }
00797 
00798   /*
00799    * The thermal expansion coefficient. Units: 1/K.
00800    * The thermal expansion coefficient is defined as
00801    *
00802    * \f[
00803    * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P
00804    * \f]
00805    *
00806    *  It's equal to zero for this model, since the molar volume
00807    *  doesn't change with pressure or temperature.
00808    */
00809   doublereal HMWSoln::thermalExpansionCoeff() const {
00810     throw CanteraError("HMWSoln::thermalExpansionCoeff",
00811                        "unimplemented");
00812     return 0.0;
00813   }
00814    
00815   double HMWSoln::density() const{
00816     //    calcDensity();
00817     return State::density();
00818   }
00819 
00820   /*
00821    * Overwritten setDensity() function is necessary because the
00822    * density is not an indendent variable.
00823    *
00824    * This function will now throw an error condition
00825    *
00826    * Note, in general, setting the phase density is now a nonlinear
00827    * calculation. P and T are the fundamental variables. This
00828    * routine should be revamped to do the nonlinear problem
00829    *
00830    * @internal May have to adjust the strategy here to make
00831    * the eos for these materials slightly compressible, in order
00832    * to create a condition where the density is a function of
00833    * the pressure.
00834    *
00835    * This function will now throw an error condition.
00836    *
00837    *  NOTE: This is an overwritten function from the State.h
00838    *        class
00839    */
00840   void HMWSoln::setDensity(const doublereal rho) {
00841     double dens_old = density();
00842 
00843     if (rho != dens_old) {
00844       throw CanteraError("HMWSoln::setDensity",
00845                          "Density is not an independent variable");
00846     }
00847   }     
00848 
00849   /*
00850    * Overwritten setMolarDensity() function is necessary because the
00851    * density is not an indendent variable.
00852    *
00853    * This function will now throw an error condition.
00854    *
00855    *  NOTE: This is an overwritten function from the State.h
00856    *        class
00857    */
00858   void HMWSoln::setMolarDensity(const doublereal rho) {
00859     throw CanteraError("HMWSoln::setMolarDensity",
00860                        "Density is not an independent variable");
00861   }
00862 
00863   /*
00864    * Overwritten setTemperature(double) from State.h. This
00865    * function sets the temperature, and makes sure that
00866    * the value propagates to underlying objects.
00867    */
00868   void HMWSoln::setTemperature(const doublereal temp) {
00869     setState_TP(temp, m_Pcurrent);
00870   }
00871 
00872   /*
00873    * Overwritten setTemperature(double) from State.h. This
00874    * function sets the temperature, and makes sure that
00875    * the value propagates to underlying objects.
00876    */
00877   void HMWSoln::setState_TP(doublereal temp, doublereal pres) {
00878     State::setTemperature(temp);
00879     /*
00880      * Store the current pressure
00881      */
00882     m_Pcurrent = pres;
00883   
00884     /*
00885      * update the standard state thermo
00886      * -> This involves calling the water function and setting the pressure
00887      */
00888     updateStandardStateThermo();
00889     /*
00890      * Store the internal density of the water SS.
00891      * Note, we would have to do this for all other
00892      * species if they had pressure dependent properties.
00893      */
00894     m_densWaterSS = m_waterSS->density();
00895     /*
00896      * Calculate all of the other standard volumes
00897      * -> note these are constant for now
00898      */
00899     calcDensity();
00900   }
00901 
00902   //
00903   // ------- Activities and Activity Concentrations
00904   //
00905 
00906   /*
00907    * This method returns an array of generalized concentrations
00908    * \f$ C_k\f$ that are defined such that 
00909    * \f$ a_k = C_k / C^0_k, \f$ where \f$ C^0_k \f$ 
00910    * is a standard concentration
00911    * defined below.  These generalized concentrations are used
00912    * by kinetics manager classes to compute the forward and
00913    * reverse rates of elementary reactions. 
00914    *
00915    * @param c Array of generalized concentrations. The 
00916    *           units depend upon the implementation of the
00917    *           reaction rate expressions within the phase.
00918    */
00919   void HMWSoln::getActivityConcentrations(doublereal* c) const {
00920     double cs_solvent = standardConcentration();
00921     getActivities(c);
00922     c[0] *= cs_solvent;
00923     if (m_kk > 1) {
00924       double cs_solute = standardConcentration(1);
00925       for (int k = 1; k < m_kk; k++) {
00926         c[k] *= cs_solute;
00927       }
00928     }
00929   }
00930 
00931   /*
00932    * The standard concentration \f$ C^0_k \f$ used to normalize
00933    * the generalized concentration. In many cases, this quantity
00934    * will be the same for all species in a phase - for example,
00935    * for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this
00936    * reason, this method returns a single value, instead of an
00937    * array.  However, for phases in which the standard
00938    * concentration is species-specific (e.g. surface species of
00939    * different sizes), this method may be called with an
00940    * optional parameter indicating the species.
00941    *
00942    * For the time being we will use the concentration of pure
00943    * solvent for the the standard concentration of the solvent.
00944    * We will use the concentration of the pure solvent
00945    * multipled by Mnaught (kg solvent / gmol solvent) for
00946    * the standard concentration of all solute species.
00947    * This has the effect of making reaction rates
00948    * based on the molality of species proportional to the
00949    * molality of the species, but have units based on assuming
00950    * all species concentrations have units of kmol/m3.
00951    *
00952    */
00953   doublereal HMWSoln::standardConcentration(int k) const {
00954     getStandardVolumes(DATA_PTR(m_tmpV));
00955     double mvSolvent = m_tmpV[m_indexSolvent];
00956     if (k > 0) {
00957       return m_Mnaught / mvSolvent;
00958     }
00959     return 1.0 / mvSolvent;
00960   }
00961     
00962   /*
00963    * Returns the natural logarithm of the standard 
00964    * concentration of the kth species
00965    */
00966   doublereal HMWSoln::logStandardConc(int k) const {
00967     double c_solvent = standardConcentration(k);
00968     return log(c_solvent);
00969   }
00970     
00971   /*
00972    * Returns the units of the standard and general concentrations
00973    * Note they have the same units, as their divisor is 
00974    * defined to be equal to the activity of the kth species
00975    * in the solution, which is unitless.
00976    *
00977    * This routine is used in print out applications where the
00978    * units are needed. Usually, MKS units are assumed throughout
00979    * the program and in the XML input files. 
00980    *
00981    * On return uA contains the powers of the units (MKS assumed)
00982    * of the standard concentrations and generalized concentrations
00983    * for the kth species.
00984    *
00985    *  uA[0] = kmol units - default  = 1
00986    *  uA[1] = m    units - default  = -nDim(), the number of spatial
00987    *                                dimensions in the Phase class.
00988    *  uA[2] = kg   units - default  = 0;
00989    *  uA[3] = Pa(pressure) units - default = 0;
00990    *  uA[4] = Temperature units - default = 0;
00991    *  uA[5] = time units - default = 0
00992    */
00993   void HMWSoln::getUnitsStandardConc(double *uA, int k, int sizeUA) const {
00994     for (int i = 0; i < sizeUA; i++) {
00995       if (i == 0) uA[0] = 1.0;
00996       if (i == 1) uA[1] = -nDim();
00997       if (i == 2) uA[2] = 0.0;
00998       if (i == 3) uA[3] = 0.0;
00999       if (i == 4) uA[4] = 0.0;
01000       if (i == 5) uA[5] = 0.0;
01001     }
01002   }    
01003 
01004   /*
01005    * Get the array of non-dimensional activities at
01006    * the current solution temperature, pressure, and
01007    * solution concentration.
01008    * (note solvent activity coefficient is on the molar scale).
01009    *
01010    */
01011   void HMWSoln::getActivities(doublereal* ac) const {
01012     updateStandardStateThermo();
01013     /*
01014      * Update the molality array, m_molalities()
01015      *   This requires an update due to mole fractions
01016      */
01017     s_update_lnMolalityActCoeff();
01018     /*
01019      * Now calculate the array of activities.
01020      */
01021     for (int k = 0; k < m_kk; k++) {
01022       if (k != m_indexSolvent) {
01023         ac[k] = m_molalities[k] * exp(m_lnActCoeffMolal_Scaled[k]);
01024       }
01025     }
01026     double xmolSolvent = moleFraction(m_indexSolvent);
01027     ac[m_indexSolvent] =
01028       exp(m_lnActCoeffMolal_Scaled[m_indexSolvent]) * xmolSolvent;
01029     /*
01030      * Apply the pH scale
01031      */
01032     //applyphScale(ac);
01033   }
01034 
01035   /*
01036    * getUnscaledMolalityActivityCoefficients()             (virtual, const)
01037    *
01038    * Get the array of non-dimensional Molality based
01039    * activity coefficients at
01040    * the current solution temperature, pressure, and
01041    * solution concentration.
01042    * (note solvent activity coefficient is on the molar scale).
01043    *
01044    *  Note, most of the work is done in an internal private routine
01045    */
01046   void HMWSoln::
01047   getUnscaledMolalityActivityCoefficients(doublereal* acMolality) const {
01048     updateStandardStateThermo();
01049     A_Debye_TP(-1.0, -1.0);
01050     s_update_lnMolalityActCoeff();
01051     std::copy(m_lnActCoeffMolal_Unscaled.begin(), m_lnActCoeffMolal_Unscaled.end(), acMolality);
01052     for (int k = 0; k < m_kk; k++) {
01053       acMolality[k] = exp(acMolality[k]);
01054     }
01055   }
01056 
01057   //
01058   // ------ Partial Molar Properties of the Solution -----------------
01059   //
01060   /*
01061    * Get the species chemical potentials. Units: J/kmol.
01062    *
01063    * This function returns a vector of chemical potentials of the 
01064    * species in solution.
01065    *
01066    * \f[
01067    *    \mu_k = \mu^{o}_k(T,P) + R T ln(m_k)
01068    * \f]
01069    *
01070    * \f[
01071    *    \mu_solvent = \mu^{o}_solvent(T,P) +
01072    *            R T ((X_solvent - 1.0) / X_solvent)
01073    * \f]
01074    */
01075   void HMWSoln::getChemPotentials(doublereal* mu) const{
01076     double xx;
01077     const double xxSmall = 1.0E-150; 
01078     /*
01079      * First get the standard chemical potentials in
01080      * molar form.
01081      *  -> this requires updates of standard state as a function
01082      *     of T and P
01083      */
01084     getStandardChemPotentials(mu);
01085     /*
01086      * Update the activity coefficients
01087      * This also updates the internal molality array.
01088      */
01089     s_update_lnMolalityActCoeff();
01090     /*
01091      *   
01092      */
01093     doublereal RT = GasConstant * temperature();
01094     double xmolSolvent = moleFraction(m_indexSolvent);
01095     for (int k = 0; k < m_kk; k++) {
01096       if (m_indexSolvent != k) {
01097         xx = MAX(m_molalities[k], xxSmall);
01098         mu[k] += RT * (log(xx) + m_lnActCoeffMolal_Scaled[k]);
01099       }
01100     }
01101     xx = MAX(xmolSolvent, xxSmall);
01102     mu[m_indexSolvent] +=  
01103       RT * (log(xx) + m_lnActCoeffMolal_Scaled[m_indexSolvent]);
01104   }
01105 
01106 
01107   /*
01108    * Returns an array of partial molar enthalpies for the species
01109    * in the mixture.
01110    * Units (J/kmol)
01111    *
01112    * For this phase, the partial molar enthalpies are equal to the
01113    * standard state enthalpies modified by the derivative of the
01114    * molality-based activity coefficent wrt temperature
01115    *
01116    *  \f[
01117    * \bar h_k(T,P) = h^{\triangle}_k(T,P) - R T^2 \frac{d \ln(\gamma_k^\triangle)}{dT}
01118    * \f]
01119    * The solvent partial molar enthalpy is equal to 
01120    *  \f[
01121    * \bar h_o(T,P) = h^{o}_o(T,P) - R T^2 \frac{d \ln(a_o)}{dT}
01122    * \f]
01123    *
01124    *
01125    */
01126   void HMWSoln::getPartialMolarEnthalpies(doublereal* hbar) const {
01127     /*
01128      * Get the nondimensional standard state enthalpies
01129      */
01130     getEnthalpy_RT(hbar);
01131     /*
01132      * dimensionalize it.
01133      */
01134     double T = temperature();
01135     double RT = GasConstant * T;
01136     for (int k = 0; k < m_kk; k++) {
01137       hbar[k] *= RT;
01138     }
01139     /*
01140      * Update the activity coefficients, This also update the
01141      * internally storred molalities.
01142      */
01143     s_update_lnMolalityActCoeff();
01144     s_update_dlnMolalityActCoeff_dT();
01145     double RTT = RT * T;
01146     for (int k = 0; k < m_kk; k++) {
01147       hbar[k] -= RTT * m_dlnActCoeffMolaldT_Scaled[k];
01148     }
01149   }
01150 
01151   /*
01152    * getPartialMolarEntropies()        (virtual, const)
01153    *
01154    * Returns an array of partial molar entropies of the species in the
01155    * solution. Units: J/kmol.
01156    *
01157    * Maxwell's equations provide an insight in how to calculate this
01158    * (p.215 Smith and Van Ness)
01159    *
01160    *      d(chemPot_i)/dT = -sbar_i
01161    *   
01162    * Combining this with the expression H = G + TS yields:
01163    *
01164    *  \f[
01165    *     \bar s_k(T,P) =  s^{\triangle}_k(T,P) 
01166    *             - R \ln( \gamma^{\triangle}_k \frac{m_k}{m^{\triangle}}))
01167    *                    - R T \frac{d \ln(\gamma^{\triangle}_k) }{dT}
01168    * \f]
01169    * \f[
01170    *      \bar s_o(T,P) = s^o_o(T,P) - R \ln(a_o)
01171    *                    - R T \frac{d \ln(a_o)}{dT}
01172    * \f]  
01173    *
01174    * The reference-state pure-species entropies,\f$ \hat s^0_k(T) \f$,
01175    * at the reference pressure, \f$ P_{ref} \f$,  are computed by the
01176    * species thermodynamic
01177    * property manager. They are polynomial functions of temperature.
01178    * @see SpeciesThermo
01179    */
01180   void HMWSoln::
01181   getPartialMolarEntropies(doublereal* sbar) const {
01182     int k;
01183     /*
01184      * Get the standard state entropies at the temperature
01185      * and pressure of the solution.
01186      */
01187     getEntropy_R(sbar);
01188     /*
01189      * Dimensionalize the entropies
01190      */
01191     doublereal R = GasConstant;
01192     for (k = 0; k < m_kk; k++) {
01193       sbar[k] *= R;
01194     }
01195     /*
01196      * Update the activity coefficients, This also update the
01197      * internally stored molalities.
01198      */
01199     s_update_lnMolalityActCoeff();
01200     /*
01201      * First we will add in the obvious dependence on the T
01202      * term out front of the log activity term
01203      */
01204     doublereal mm;
01205     for (k = 0; k < m_kk; k++) {
01206       if (k != m_indexSolvent) {
01207         mm = fmaxx(SmallNumber, m_molalities[k]);
01208         sbar[k] -= R * (log(mm) + m_lnActCoeffMolal_Scaled[k]);
01209       }
01210     }
01211     double xmolSolvent = moleFraction(m_indexSolvent);
01212     mm = fmaxx(SmallNumber, xmolSolvent);
01213     sbar[m_indexSolvent] -= R *(log(mm) + m_lnActCoeffMolal_Scaled[m_indexSolvent]);
01214     /*
01215      * Check to see whether activity coefficients are temperature
01216      * dependent. If they are, then calculate the their temperature
01217      * derivatives and add them into the result.
01218      */
01219     s_update_dlnMolalityActCoeff_dT();
01220     double RT = R * temperature();
01221     for (k = 0; k < m_kk; k++) {
01222       sbar[k] -= RT * m_dlnActCoeffMolaldT_Scaled[k];
01223     }
01224   }
01225 
01226   /*
01227    * getPartialMolarVolumes()                (virtual, const)
01228    *
01229    * Returns an array of partial molar volumes of the species
01230    * in the solution. Units: m^3 kmol-1.
01231    *
01232    * For this solution, the partial molar volumes are a
01233    * complex function of pressure.
01234    *
01235    * The general relation is 
01236    *
01237    *       vbar_i = d(chemPot_i)/dP at const T, n
01238    *
01239    *              = V0_i + d(Gex)/dP)_T,M
01240    *
01241    *              = V0_i + RT d(lnActCoeffi)dP _T,M
01242    *
01243    */
01244   void HMWSoln::getPartialMolarVolumes(doublereal* vbar) const {
01245     /*
01246      * Get the standard state values in m^3 kmol-1
01247      */
01248     getStandardVolumes(vbar);
01249     /*
01250      * Update the derivatives wrt the activity coefficients.
01251      */
01252     s_update_lnMolalityActCoeff();
01253     s_update_dlnMolalityActCoeff_dP();
01254     double T = temperature();
01255     double RT = GasConstant * T;
01256     for (int k = 0; k < m_kk; k++) {
01257       vbar[k] += RT * m_dlnActCoeffMolaldP_Scaled[k];
01258     }
01259   }
01260 
01261   /*
01262    * Partial molar heat capacity of the solution:
01263    *   The kth partial molar heat capacity is  equal to 
01264    *   the temperature derivative of the partial molar
01265    *   enthalpy of the kth species in the solution at constant
01266    *   P and composition (p. 220 Smith and Van Ness).
01267    *
01268    *  \f[
01269    *     \bar C_{p,k}(T,P) =  C^{\triangle}_{p,k}(T,P) 
01270    *             - 2 R T \frac{d \ln( \gamma^{\triangle}_k)}{dT}
01271    *                    - R T^2 \frac{d^2 \ln(\gamma^{\triangle}_k) }{{dT}^2}
01272    * \f]
01273    * \f[
01274    *      \bar C_{p,o}(T,P) = C^o_{p,o}(T,P) 
01275    *                   - 2 R T \frac{d \ln(a_o)}{dT}
01276    *                    - R T^2 \frac{d^2 \ln(a_o)}{{dT}^2}
01277    * \f]
01278    */
01279   void HMWSoln::getPartialMolarCp(doublereal* cpbar) const {
01280     /*
01281      * Get the nondimensional gibbs standard state of the
01282      * species at the T and P of the solution.
01283      */
01284     getCp_R(cpbar);
01285         
01286     for (int k = 0; k < m_kk; k++) {
01287       cpbar[k] *= GasConstant;
01288     }
01289     /*
01290      * Update the activity coefficients, This also update the
01291      * internally storred molalities.
01292      */
01293     s_update_lnMolalityActCoeff();
01294     s_update_dlnMolalityActCoeff_dT();
01295     s_update_d2lnMolalityActCoeff_dT2();
01296     double T = temperature();
01297     double RT = GasConstant * T;
01298     double RTT = RT * T;
01299     for (int k = 0; k < m_kk; k++) {
01300       cpbar[k] -= (2.0 * RT * m_dlnActCoeffMolaldT_Scaled[k] +
01301                    RTT * m_d2lnActCoeffMolaldT2_Scaled[k]);
01302     }
01303   }
01304 
01305   /*
01306    * Updates the standard state thermodynamic functions at the current T and 
01307    * P of the solution.
01308    *
01309    * @internal
01310    *
01311    * This function gets called for every call to functions in this
01312    * class. It checks to see whether the temperature or pressure has changed and
01313    * thus the ss thermodynamics functions for all of the species
01314    * must be recalculated.
01315    */                    
01316   //  void HMWSoln::_updateStandardStateThermo() const {
01317   //doublereal tnow = temperature();
01318   // doublereal pnow = m_Pcurrent;
01319   // if (m_waterSS) {
01320   //   m_waterSS->setTempPressure(tnow, pnow);
01321   // }
01322   // m_VPSS_ptr->setState_TP(tnow, pnow);
01323     // VPStandardStateTP::updateStandardStateThermo();
01324   //}
01325 
01326   /*
01327    * ------ Thermodynamic Values for the Species Reference States ---
01328    */
01329 
01330   // -> This is handled by VPStandardStatesTP
01331 
01332   /*
01333    *  -------------- Utilities -------------------------------
01334    */
01335 
01336   /*
01337    * @internal
01338    * Set equation of state parameters. The number and meaning of
01339    * these depends on the subclass. 
01340    * @param n number of parameters
01341    * @param c array of <I>n</I> coefficients
01342    * 
01343    */
01344   void HMWSoln::setParameters(int n, doublereal* const c) {
01345   }
01346 
01347   void HMWSoln::getParameters(int &n, doublereal * const c) const {
01348   }
01349   /*
01350    * Set equation of state parameter values from XML
01351    * entries. This method is called by function importPhase in
01352    * file importCTML.cpp when processing a phase definition in
01353    * an input file. It should be overloaded in subclasses to set
01354    * any parameters that are specific to that particular phase
01355    * model.
01356    *
01357    * @param eosdata An XML_Node object corresponding to
01358    * the "thermo" entry for this phase in the input file.
01359    *
01360    * HKM -> Right now, the parameters are set elsewhere (initThermoXML)
01361    *        It just didn't seem to fit.
01362    */
01363   void HMWSoln::setParametersFromXML(const XML_Node& eosdata) {
01364   }
01365     
01366   /*
01367    * Get the saturation pressure for a given temperature. 
01368    * Note the limitations of this function. Stability considerations
01369    * concernting multiphase equilibrium are ignored in this 
01370    * calculation. Therefore, the call is made directly to the SS of 
01371    * water underneath. The object is put back into its original
01372    * state at the end of the call.
01373    */
01374   doublereal HMWSoln::satPressure(doublereal t) const {
01375     double p_old = pressure();
01376     double t_old = temperature();
01377     double pres = m_waterSS->satPressure(t);
01378     /*
01379      * Set the underlying object back to its original state.
01380      */
01381     m_waterSS->setState_TP(t_old, p_old);
01382     return pres;
01383   }
01384 
01385   /*
01386    * Report the molar volume of species k
01387    *
01388    * units - \f$ m^3 kmol^-1 \f$
01389    */
01390   double HMWSoln::speciesMolarVolume(int k) const {
01391     double vol = m_speciesSize[k];
01392     if (k == 0) {
01393       double dd = m_waterSS->density();
01394       vol = molecularWeight(0)/dd;
01395     }
01396     return vol;
01397   }
01398  
01399   /*
01400    * A_Debye_TP()                              (virtual)
01401    *
01402    *   Returns the A_Debye parameter as a function of temperature
01403    *  and pressure. This function also sets the internal value
01404    *  of the parameter within the object, if it is changeable. 
01405    *
01406    *  The default is to assume that it is constant, given
01407    *  in the initialization process and storred in the
01408    *  member double, m_A_Debye
01409    *
01410    *            A_Debye = (1/(8 Pi)) sqrt(2 Na dw /1000) 
01411    *                          (e e/(epsilon R T))^3/2
01412    *
01413    *                    where epsilon = e_rel * e_naught
01414    *
01415    * Note, this is si units. Frequently, gaussian units are
01416    * used in Pitzer's papers where D is used, D = epsilon/(4 Pi)
01417    * units = A_Debye has units of sqrt(gmol kg-1).
01418    */
01419   double HMWSoln::A_Debye_TP(double tempArg, double presArg) const {
01420     double T = temperature(); 
01421     double A;
01422     if (tempArg != -1.0) {
01423       T = tempArg;
01424     }
01425     double P = pressure();
01426     if (presArg != -1.0) {
01427       P = presArg;
01428     }
01429 
01430     switch (m_form_A_Debye) {
01431     case A_DEBYE_CONST:
01432       A = m_A_Debye;
01433       break;
01434     case A_DEBYE_WATER:
01435       A = m_waterProps->ADebye(T, P, 0);
01436       m_A_Debye = A;
01437       break;
01438     default:
01439       printf("shouldn't be here\n");
01440       exit(EXIT_FAILURE);
01441     }
01442     return A;
01443   }
01444 
01445   /*
01446    * dA_DebyedT_TP()                              (virtual)
01447    *
01448    *  Returns the derivative of the A_Debye parameter with
01449    *  respect to temperature as a function of temperature
01450    *  and pressure. 
01451    *
01452    * units = A_Debye has units of sqrt(gmol kg-1).
01453    *         Temp has units of Kelvin.
01454    */
01455   double HMWSoln::dA_DebyedT_TP(double tempArg, double presArg) const {
01456     doublereal T = temperature();
01457     if (tempArg != -1.0) {
01458       T = tempArg;
01459     }
01460     doublereal P = pressure();
01461     if (presArg != -1.0) {
01462       P = presArg;
01463     }
01464     doublereal dAdT;
01465     switch (m_form_A_Debye) {
01466     case A_DEBYE_CONST:
01467       dAdT = 0.0;
01468       break;
01469     case A_DEBYE_WATER:
01470       dAdT = m_waterProps->ADebye(T, P, 1);
01471       //dAdT = WaterProps::ADebye(T, P, 1);
01472       break;
01473     default:
01474       printf("shouldn't be here\n");
01475       exit(EXIT_FAILURE);
01476     }
01477     return dAdT;
01478   }
01479 
01480   /*
01481    * dA_DebyedP_TP()                              (virtual)
01482    *
01483    *  Returns the derivative of the A_Debye parameter with
01484    *  respect to pressure, as a function of temperature
01485    *  and pressure. 
01486    *
01487    * units = A_Debye has units of sqrt(gmol kg-1).
01488    *         Pressure has units of pascals.
01489    */
01490   double HMWSoln::dA_DebyedP_TP(double tempArg, double presArg) const {
01491     double T = temperature();
01492     if (tempArg != -1.0) {
01493       T = tempArg;
01494     }
01495     double P = pressure();
01496     if (presArg != -1.0) {
01497       P = presArg;
01498     }
01499     double dAdP;
01500     switch (m_form_A_Debye) {
01501     case A_DEBYE_CONST:
01502       dAdP = 0.0;
01503       break;
01504     case A_DEBYE_WATER:
01505       dAdP = m_waterProps->ADebye(T, P, 3);
01506       break;
01507     default:
01508       printf("shouldn't be here\n");
01509       exit(EXIT_FAILURE);
01510     }
01511     return dAdP;
01512   }
01513 
01514 
01515   /*
01516    *  Calculate the DH Parameter used for the Enthalpy calcalations
01517    *
01518    *      ADebye_L = 4 R T**2 d(Aphi) / dT
01519    *
01520    *   where   Aphi = A_Debye/3
01521    *
01522    *   units -> J / (kmolK) * sqrt( kg/gmol)
01523    * 
01524    */
01525   double HMWSoln::ADebye_L(double tempArg, double presArg) const {
01526     double dAdT = dA_DebyedT_TP();
01527     double dAphidT = dAdT /3.0;
01528     double T = temperature();
01529     if (tempArg != -1.0) {
01530       T = tempArg;
01531     }
01532     double retn = dAphidT * (4.0 * GasConstant * T * T);
01533     return retn;
01534   }
01535 
01536   /*
01537    *  Calculate the DH Parameter used for the Volume calcalations
01538    *
01539    *      ADebye_V = - 4 R T d(Aphi) / dP
01540    *
01541    *   where   Aphi = A_Debye/3
01542    *
01543    *   units -> J / (kmolK) * sqrt( kg/gmol)
01544    * 
01545    */
01546   double HMWSoln::ADebye_V(double tempArg, double presArg) const {
01547     double dAdP = dA_DebyedP_TP();
01548     double dAphidP = dAdP /3.0;
01549     double T = temperature();
01550     if (tempArg != -1.0) {
01551       T = tempArg;
01552     }
01553     double retn = - dAphidP * (4.0 * GasConstant * T);
01554     return retn;
01555   }
01556 
01557   /*
01558    * Return Pitzer's definition of A_J. This is basically the
01559    * temperature derivative of A_L, and the second derivative
01560    * of Aphi
01561    * It's the DH parameter used in heat capacity calculations
01562    *  
01563    *  A_J = 2 A_L/T + 4 * R * T * T * d2(A_phi)/dT2
01564    *
01565    *    Units = sqrt(kg/gmol) (R)
01566    *  
01567    *   where
01568    *      ADebye_L = 4 R T**2 d(Aphi) / dT
01569    *
01570    *   where   Aphi = A_Debye/3
01571    *
01572    *   units -> J / (kmolK) * sqrt( kg/gmol)
01573    * 
01574    */
01575   double HMWSoln::ADebye_J(double tempArg, double presArg) const {
01576     double T = temperature();
01577     if (tempArg != -1.0) {
01578       T = tempArg;
01579     }
01580     double A_L = ADebye_L(T, presArg);
01581     double d2 = d2A_DebyedT2_TP(T, presArg);
01582     double d2Aphi = d2 / 3.0;
01583     double retn = 2.0 * A_L / T + 4.0 * GasConstant * T * T *d2Aphi;
01584     return retn;
01585   }
01586 
01587   /*
01588    * d2A_DebyedT2_TP()                              (virtual)
01589    *
01590    *  Returns the 2nd derivative of the A_Debye parameter with
01591    *  respect to temperature as a function of temperature
01592    *  and pressure. 
01593    *
01594    * units = A_Debye has units of sqrt(gmol kg-1).
01595    *         Temp has units of Kelvin.
01596    */
01597   double HMWSoln::d2A_DebyedT2_TP(double tempArg, double presArg) const {
01598     double T = temperature();
01599     if (tempArg != -1.0) {
01600       T = tempArg;
01601     }
01602     double P = pressure();
01603     if (presArg != -1.0) {
01604       P = presArg;
01605     }
01606     double d2AdT2;
01607     switch (m_form_A_Debye) {
01608     case A_DEBYE_CONST:
01609       d2AdT2 = 0.0;
01610       break;
01611     case A_DEBYE_WATER:
01612       d2AdT2 = m_waterProps->ADebye(T, P, 2);
01613       break;
01614     default:
01615       printf("shouldn't be here\n");
01616       exit(EXIT_FAILURE);
01617     }
01618     return d2AdT2;
01619   }
01620 
01621   /*
01622    * ----------- Critical State Properties --------------------------
01623    */
01624 
01625   /*
01626    * ---------- Other Property Functions
01627    */
01628   double HMWSoln::AionicRadius(int k) const {
01629     return m_Aionic[k];
01630   }
01631 
01632   /*
01633    * ------------ Private and Restricted Functions ------------------
01634    */
01635 
01636   /**
01637    * Bail out of functions with an error exit if they are not
01638    * implemented.
01639    */
01640   doublereal HMWSoln::err(std::string msg) const {
01641     throw CanteraError("HMWSoln",
01642                        "Unfinished func called: " + msg );
01643     return 0.0;
01644   }
01645 
01646 
01647 
01648   /*
01649    * initLengths():
01650    *
01651    * This internal function adjusts the lengths of arrays based on
01652    * the number of species. This is done before these arrays are
01653    * populated with parameter values.
01654    */
01655   void HMWSoln::initLengths() {
01656     m_kk = nSpecies();
01657  
01658     /*
01659      * Resize lengths equal to the number of species in
01660      * the phase.
01661      */
01662     int leng = m_kk;
01663     m_electrolyteSpeciesType.resize(m_kk, cEST_polarNeutral);
01664     m_speciesSize.resize(leng);
01665     m_speciesCharge_Stoich.resize(leng, 0.0);
01666     m_Aionic.resize(leng, 0.0);
01667 
01668     m_expg0_RT.resize(leng, 0.0);
01669     m_pe.resize(leng, 0.0);
01670     m_pp.resize(leng, 0.0);
01671     m_tmpV.resize(leng, 0.0);
01672     m_molalitiesCropped.resize(leng, 0.0);
01673 
01674     int maxCounterIJlen = 1 + (leng-1) * (leng-2) / 2;
01675 
01676     /*
01677      * Figure out the size of the temperature coefficient
01678      * arrays
01679      */
01680     int TCoeffLength = 1;
01681     if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
01682       TCoeffLength = 2;
01683     } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
01684       TCoeffLength = 5;
01685     }
01686 
01687     m_Beta0MX_ij.resize(maxCounterIJlen, 0.0);
01688     m_Beta0MX_ij_L.resize(maxCounterIJlen, 0.0);
01689     m_Beta0MX_ij_LL.resize(maxCounterIJlen, 0.0);
01690     m_Beta0MX_ij_P.resize(maxCounterIJlen, 0.0);
01691     m_Beta0MX_ij_coeff.resize(TCoeffLength, maxCounterIJlen, 0.0);
01692         
01693     m_Beta1MX_ij.resize(maxCounterIJlen, 0.0);
01694     m_Beta1MX_ij_L.resize(maxCounterIJlen, 0.0);
01695     m_Beta1MX_ij_LL.resize(maxCounterIJlen, 0.0);
01696     m_Beta1MX_ij_P.resize(maxCounterIJlen, 0.0);
01697     m_Beta1MX_ij_coeff.resize(TCoeffLength, maxCounterIJlen, 0.0);
01698 
01699     m_Beta2MX_ij.resize(maxCounterIJlen, 0.0);
01700     m_Beta2MX_ij_L.resize(maxCounterIJlen, 0.0);
01701     m_Beta2MX_ij_LL.resize(maxCounterIJlen, 0.0);
01702     m_Beta2MX_ij_P.resize(maxCounterIJlen, 0.0);
01703     m_Beta2MX_ij_coeff.resize(TCoeffLength, maxCounterIJlen, 0.0);
01704 
01705     m_CphiMX_ij.resize(maxCounterIJlen, 0.0);
01706     m_CphiMX_ij_L.resize(maxCounterIJlen, 0.0);
01707     m_CphiMX_ij_LL.resize(maxCounterIJlen, 0.0);
01708     m_CphiMX_ij_P.resize(maxCounterIJlen, 0.0);
01709     m_CphiMX_ij_coeff.resize(TCoeffLength, maxCounterIJlen, 0.0);
01710 
01711     m_Alpha1MX_ij.resize(maxCounterIJlen, 2.0);
01712     m_Alpha2MX_ij.resize(maxCounterIJlen, 12.0);
01713     m_Theta_ij.resize(maxCounterIJlen, 0.0);
01714     m_Theta_ij_L.resize(maxCounterIJlen, 0.0);
01715     m_Theta_ij_LL.resize(maxCounterIJlen, 0.0);
01716     m_Theta_ij_P.resize(maxCounterIJlen, 0.0);
01717     m_Theta_ij_coeff.resize(TCoeffLength, maxCounterIJlen, 0.0);
01718 
01719     int n = m_kk*m_kk*m_kk;
01720     m_Psi_ijk.resize(m_kk*m_kk*m_kk, 0.0);
01721     m_Psi_ijk_L.resize(m_kk*m_kk*m_kk, 0.0);
01722     m_Psi_ijk_LL.resize(m_kk*m_kk*m_kk, 0.0);
01723     m_Psi_ijk_P.resize(m_kk*m_kk*m_kk, 0.0);
01724     m_Psi_ijk_coeff.resize(TCoeffLength, n, 0.0);
01725 
01726     m_Lambda_nj.resize(leng, leng, 0.0);
01727     m_Lambda_nj_L.resize(leng, leng, 0.0);
01728     m_Lambda_nj_LL.resize(leng, leng, 0.0);
01729     m_Lambda_nj_P.resize(leng, leng, 0.0); 
01730     m_Lambda_nj_coeff.resize(TCoeffLength, leng * leng, 0.0);
01731 
01732     m_Mu_nnn.resize(leng,    0.0);
01733     m_Mu_nnn_L.resize(leng,  0.0);
01734     m_Mu_nnn_LL.resize(leng, 0.0);
01735     m_Mu_nnn_P.resize(leng,  0.0); 
01736     m_Mu_nnn_coeff.resize(TCoeffLength, leng, 0.0);
01737 
01738     m_lnActCoeffMolal_Scaled.resize(leng, 0.0);
01739     m_dlnActCoeffMolaldT_Scaled.resize(leng, 0.0);
01740     m_d2lnActCoeffMolaldT2_Scaled.resize(leng, 0.0);
01741     m_dlnActCoeffMolaldP_Scaled.resize(leng, 0.0);
01742 
01743     m_lnActCoeffMolal_Unscaled.resize(leng, 0.0);
01744     m_dlnActCoeffMolaldT_Unscaled.resize(leng, 0.0);
01745     m_d2lnActCoeffMolaldT2_Unscaled.resize(leng, 0.0);
01746     m_dlnActCoeffMolaldP_Unscaled.resize(leng, 0.0);
01747 
01748     m_CounterIJ.resize(m_kk*m_kk, 0);
01749 
01750     m_gfunc_IJ.resize(maxCounterIJlen, 0.0);
01751     m_g2func_IJ.resize(maxCounterIJlen, 0.0);
01752     m_hfunc_IJ.resize(maxCounterIJlen, 0.0);
01753     m_h2func_IJ.resize(maxCounterIJlen, 0.0);
01754     m_BMX_IJ.resize(maxCounterIJlen, 0.0);
01755     m_BMX_IJ_L.resize(maxCounterIJlen, 0.0);
01756     m_BMX_IJ_LL.resize(maxCounterIJlen, 0.0);
01757     m_BMX_IJ_P.resize(maxCounterIJlen, 0.0);
01758     m_BprimeMX_IJ.resize(maxCounterIJlen, 0.0);
01759     m_BprimeMX_IJ_L.resize(maxCounterIJlen, 0.0);
01760     m_BprimeMX_IJ_LL.resize(maxCounterIJlen, 0.0);
01761     m_BprimeMX_IJ_P.resize(maxCounterIJlen, 0.0);
01762     m_BphiMX_IJ.resize(maxCounterIJlen, 0.0);
01763     m_BphiMX_IJ_L.resize(maxCounterIJlen, 0.0);
01764     m_BphiMX_IJ_LL.resize(maxCounterIJlen, 0.0);
01765     m_BphiMX_IJ_P.resize(maxCounterIJlen, 0.0);
01766     m_Phi_IJ.resize(maxCounterIJlen, 0.0);
01767     m_Phi_IJ_L.resize(maxCounterIJlen, 0.0);
01768     m_Phi_IJ_LL.resize(maxCounterIJlen, 0.0);
01769     m_Phi_IJ_P.resize(maxCounterIJlen, 0.0);
01770     m_Phiprime_IJ.resize(maxCounterIJlen, 0.0);
01771     m_PhiPhi_IJ.resize(maxCounterIJlen, 0.0);
01772     m_PhiPhi_IJ_L.resize(maxCounterIJlen, 0.0);
01773     m_PhiPhi_IJ_LL.resize(maxCounterIJlen, 0.0);
01774     m_PhiPhi_IJ_P.resize(maxCounterIJlen, 0.0);
01775     m_CMX_IJ.resize(maxCounterIJlen, 0.0);
01776     m_CMX_IJ_L.resize(maxCounterIJlen, 0.0);
01777     m_CMX_IJ_LL.resize(maxCounterIJlen, 0.0);
01778     m_CMX_IJ_P.resize(maxCounterIJlen, 0.0);
01779 
01780     m_gamma_tmp.resize(leng, 0.0);
01781 
01782     IMS_lnActCoeffMolal_.resize(m_kk, 0.0);
01783     CROP_speciesCropped_.resize(m_kk, 0);
01784 
01785     counterIJ_setup();
01786   }
01787 
01788   /**
01789    * Calcuate the natural log of the molality-based
01790    * activity coefficients.
01791    *
01792    */
01793   void HMWSoln::s_update_lnMolalityActCoeff() const {
01794 
01795     /*
01796      * Calculate the molalities. Currently, the molalities
01797      * may not be current with respect to the contents of the
01798      * State objects' data.
01799      */
01800     calcMolalities();
01801     /*
01802      *  Calculate a cropped set of molalities that will be used
01803      *  in all activity coefficent calculations.
01804      */
01805     calcMolalitiesCropped();
01806     /*
01807      * Calculate the stoichiometric ionic charge. This isn't used in the
01808      * Pitzer formulation.
01809      */
01810     m_IionicMolalityStoich = 0.0;
01811     for (int k = 0; k < m_kk; k++) {
01812       double z_k = m_speciesCharge[k];
01813       double zs_k1 =  m_speciesCharge_Stoich[k];
01814       if (z_k == zs_k1) {
01815         m_IionicMolalityStoich += m_molalities[k] * z_k * z_k;
01816       } else {
01817         double zs_k2 = z_k - zs_k1;
01818         m_IionicMolalityStoich
01819           += m_molalities[k] * (zs_k1 * zs_k1 + zs_k2 * zs_k2);
01820       }
01821     }
01822 
01823 
01824     /*
01825      * Update the temperature dependence of the pitzer coefficients
01826      * and their derivatives
01827      */
01828     s_updatePitzer_CoeffWRTemp();
01829 
01830     /*
01831      * Calculate the IMS cutoff factors
01832      */
01833     s_updateIMS_lnMolalityActCoeff();
01834 
01835     /*
01836      * Now do the main calculation.
01837      */
01838     s_updatePitzer_lnMolalityActCoeff();
01839 
01840     double xmolSolvent = moleFraction(m_indexSolvent);
01841     double xx = MAX(m_xmolSolventMIN, xmolSolvent);
01842     double lnActCoeffMolal0 = - log(xx) + (xx - 1.0)/xx;
01843     double lnxs = log(xx);
01844 
01845     for (int k = 1; k < m_kk; k++) {
01846       CROP_speciesCropped_[k] = 0;
01847       m_lnActCoeffMolal_Unscaled[k] += IMS_lnActCoeffMolal_[k];
01848       if (m_lnActCoeffMolal_Unscaled[k] > (CROP_ln_gamma_k_max- 2.5 *lnxs)) {
01849         CROP_speciesCropped_[k] = 2;
01850         m_lnActCoeffMolal_Unscaled[k] = CROP_ln_gamma_k_max - 2.5 * lnxs;
01851       }
01852       if (m_lnActCoeffMolal_Unscaled[k] < (CROP_ln_gamma_k_min - 2.5 *lnxs)) {
01853         // -1.0 and -1.5 caused multiple solutions
01854         CROP_speciesCropped_[k] = 2;
01855         m_lnActCoeffMolal_Unscaled[k] = CROP_ln_gamma_k_min - 2.5 * lnxs;
01856       }
01857     }
01858     CROP_speciesCropped_[0] = 0;
01859     m_lnActCoeffMolal_Unscaled[0] += (IMS_lnActCoeffMolal_[0] - lnActCoeffMolal0);
01860     if (m_lnActCoeffMolal_Unscaled[0] < CROP_ln_gamma_o_min) {
01861       CROP_speciesCropped_[0] = 2;
01862       m_lnActCoeffMolal_Unscaled[0] = CROP_ln_gamma_o_min;
01863     }
01864     if (m_lnActCoeffMolal_Unscaled[0] > CROP_ln_gamma_o_max) {
01865       CROP_speciesCropped_[0] = 2;
01866         // -0.5 caused multiple solutions
01867       m_lnActCoeffMolal_Unscaled[0] = CROP_ln_gamma_o_max;
01868     }
01869     if (m_lnActCoeffMolal_Unscaled[0] > CROP_ln_gamma_o_max - 0.5 * lnxs) {
01870       CROP_speciesCropped_[0] = 2;
01871       m_lnActCoeffMolal_Unscaled[0] = CROP_ln_gamma_o_max - 0.5 * lnxs;
01872     }
01873 
01874     /*
01875      * Now do the pH Scaling
01876      */
01877     s_updateScaling_pHScaling();
01878   }
01879 
01880 
01881   /*
01882    * Calculate cropped molalities
01883    */
01884   void HMWSoln::calcMolalitiesCropped() const {
01885     int i, j, k;
01886     doublereal Imax = 0.0, Itmp;
01887     doublereal Iac_max;
01888     m_molalitiesAreCropped = false;
01889 
01890     for (k = 0; k < m_kk; k++) {
01891       m_molalitiesCropped[k] = m_molalities[k];
01892       double charge = m_speciesCharge[k];
01893       Itmp = m_molalities[k] * charge * charge;
01894       if (Itmp > Imax) {
01895         Imax = Itmp;
01896       }
01897     }
01898 
01899     int cropMethod = 1;
01900 
01901 
01902     if (cropMethod == 0) {
01903 
01904       /*
01905        * Quick return
01906        */
01907       if (Imax < m_maxIionicStrength) {
01908         return;
01909       }
01910 
01911       m_molalitiesAreCropped = true;
01912 
01913       for (i = 1; i < (m_kk - 1); i++) {
01914         double charge_i = m_speciesCharge[i];
01915         double abs_charge_i = fabs(charge_i);
01916         if (charge_i == 0.0) {
01917           continue;
01918         }
01919         for (j = (i+1); j < m_kk; j++) {
01920           double charge_j = m_speciesCharge[j];
01921           double abs_charge_j = fabs(charge_j);
01922           /*
01923            * Find the counterIJ for the symmetric binary interaction
01924            */
01925           //  n = m_kk*i + j;
01926           //  counterIJ = m_CounterIJ[n];
01927           /*
01928            * Only loop over oppositely charge species
01929            */
01930           if (charge_i * charge_j < 0) {
01931             Iac_max = m_maxIionicStrength;
01932 
01933             if (m_molalitiesCropped[i] > m_molalitiesCropped[j]) {
01934               Imax = m_molalitiesCropped[i] * abs_charge_i * abs_charge_i;
01935               if (Imax > Iac_max) {
01936                 m_molalitiesCropped[i] = Iac_max / (abs_charge_i * abs_charge_i);
01937               }
01938               Imax = m_molalitiesCropped[j] * fabs(abs_charge_j * abs_charge_i);
01939               if (Imax > Iac_max) {
01940                 m_molalitiesCropped[j] = Iac_max / (abs_charge_j * abs_charge_i);
01941               }
01942             } else {
01943               Imax = m_molalitiesCropped[j] * abs_charge_j * abs_charge_j; 
01944               if (Imax > Iac_max) {
01945                 m_molalitiesCropped[j] = Iac_max / (abs_charge_j * abs_charge_j);
01946               }
01947               Imax = m_molalitiesCropped[i] * abs_charge_j * abs_charge_i;
01948               if (Imax > Iac_max) {
01949                 m_molalitiesCropped[i] = Iac_max / (abs_charge_j * abs_charge_i);
01950               }
01951             }
01952           }
01953         }
01954       }
01955 
01956       /*
01957        * Do this loop 10 times until we have achieved charge neutrality
01958        * in the cropped molalities
01959        */
01960       for (int times = 0; times< 10; times++) {
01961         double anion_charge = 0.0;
01962         double cation_charge = 0.0;
01963         int anion_contrib_max_i = -1;
01964         double anion_contrib_max = -1.0;
01965         int cation_contrib_max_i = -1;
01966         double cation_contrib_max = -1.0;
01967         for (i = 0; i < m_kk; i++) {
01968           double charge_i = m_speciesCharge[i];
01969           if (charge_i < 0.0) {
01970             double anion_contrib =  - m_molalitiesCropped[i] * charge_i;
01971             anion_charge += anion_contrib ;
01972             if (anion_contrib > anion_contrib_max) {
01973               anion_contrib_max = anion_contrib;
01974               anion_contrib_max_i = i;
01975             }
01976           } else if (charge_i > 0.0) {
01977             double cation_contrib = m_molalitiesCropped[i] * charge_i;
01978             cation_charge += cation_contrib ;
01979             if (cation_contrib > cation_contrib_max) {
01980               cation_contrib_max = cation_contrib;
01981               cation_contrib_max_i = i;
01982             }
01983           }
01984         }
01985         double total_charge = cation_charge - anion_charge;
01986         if (total_charge > 1.0E-8) {
01987           double desiredCrop = total_charge/m_speciesCharge[cation_contrib_max_i];
01988           double maxCrop =  0.66 * m_molalitiesCropped[cation_contrib_max_i];
01989           if (desiredCrop < maxCrop) {
01990             m_molalitiesCropped[cation_contrib_max_i] -= desiredCrop;
01991             break;
01992           } else {
01993             m_molalitiesCropped[cation_contrib_max_i] -= maxCrop;
01994           }
01995         } else if (total_charge < -1.0E-8) {
01996           double desiredCrop = total_charge/m_speciesCharge[anion_contrib_max_i];
01997           double maxCrop =  0.66 * m_molalitiesCropped[anion_contrib_max_i];
01998           if (desiredCrop < maxCrop) {
01999             m_molalitiesCropped[anion_contrib_max_i] -= desiredCrop;
02000             break;
02001           } else {
02002             m_molalitiesCropped[anion_contrib_max_i] -= maxCrop;
02003           }
02004         } else {
02005           break;
02006         }
02007       }
02008     }
02009     
02010     if (cropMethod == 1) {
02011       double *molF = DATA_PTR(m_gamma_tmp);
02012       getMoleFractions(molF);
02013       double xmolSolvent = molF[m_indexSolvent];
02014       if (xmolSolvent >= MC_X_o_cutoff_) {
02015         return;
02016       }
02017 
02018       m_molalitiesAreCropped = true;
02019 
02020       double poly = MC_apCut_ + MC_bpCut_ * xmolSolvent + MC_dpCut_* xmolSolvent * xmolSolvent;
02021       double  p =  xmolSolvent + MC_epCut_ + exp(- xmolSolvent/ MC_cpCut_) * poly;
02022       double denomInv = 1.0/ (m_Mnaught * p);
02023 
02024       for (k = 0; k < m_kk; k++) {
02025         m_molalitiesCropped[k] = molF[k] * denomInv ; 
02026       }
02027 
02028       // Do a further check to see if the Ionic strength is below a max value
02029       // Reduce the molalities to enforce this. Note, this algorithm preserves
02030       // the charge neutrality of the solution after cropping.
02031       Itmp = 0.0;
02032       for (k = 0; k < m_kk; k++) {
02033         double charge = m_speciesCharge[k];
02034         Itmp += m_molalitiesCropped[k] * charge * charge;
02035       }
02036       if (Itmp > m_maxIionicStrength) {
02037         double ratio = Itmp / m_maxIionicStrength;
02038         for (k = 0; k < m_kk; k++) {
02039           double charge = m_speciesCharge[k];
02040           if (charge != 0.0) {
02041             m_molalitiesCropped[k] *= ratio;
02042           }
02043         }
02044       }
02045     }
02046 
02047   }
02048 
02049   /*
02050    * Set up a counter variable for keeping track of symmetric binary
02051    * interactions amongst the solute species.
02052    *
02053    * n = m_kk*i + j 
02054    * m_Counter[n] = counter
02055    */
02056   void HMWSoln::counterIJ_setup(void) const {
02057     int n, nc, i, j;
02058     m_CounterIJ.resize(m_kk * m_kk);
02059     int counter = 0;
02060     for (i = 0; i < m_kk; i++) {
02061       n = i;
02062       nc = m_kk * i;
02063       m_CounterIJ[n] = 0;
02064       m_CounterIJ[nc] = 0;
02065     }
02066     for (i = 1; i < (m_kk - 1); i++) {
02067       n = m_kk * i + i;
02068       m_CounterIJ[n] = 0;
02069       for (j = (i+1); j < m_kk; j++) {
02070         n = m_kk * j + i;
02071         nc = m_kk * i + j;
02072         counter++;
02073         m_CounterIJ[n] = counter;
02074         m_CounterIJ[nc] = counter;
02075       }
02076     }
02077   }
02078 
02079   /*
02080    * Calculates the Pitzer coefficients' dependence on the
02081    * temperature. It will also calculate the temperature
02082    * derivatives of the coefficients, as they are important
02083    * in the calculation of the latent heats and the
02084    * heat capacities of the mixtures.
02085    *
02086    * @param doDerivs If >= 1, then the routine will calculate
02087    *                 the first derivative. If >= 2, the 
02088    *                 routine will calculate the first and second
02089    *                 temperature derivative.
02090    *                 default = 2
02091    */
02092   void HMWSoln::s_updatePitzer_CoeffWRTemp(int doDerivs) const {
02093 
02094     int i, j, n, counterIJ;
02095     const double *beta0MX_coeff;
02096     const double *beta1MX_coeff;
02097     const double *beta2MX_coeff;
02098     const double *CphiMX_coeff;
02099     const double *Theta_coeff;
02100     double T = temperature();
02101     double Tr = m_TempPitzerRef;
02102     double tinv = 0.0, tln = 0.0, tlin = 0.0, tquad = 0.0;
02103     if (m_formPitzerTemp == PITZER_TEMP_LINEAR) {
02104       tlin = T - Tr;
02105     } else if (m_formPitzerTemp == PITZER_TEMP_COMPLEX1) {
02106       tlin = T - Tr;
02107       tquad = T * T - Tr * Tr;
02108       tln = log(T/ Tr);
02109       tinv = 1.0/T - 1.0/Tr;
02110     }
02111 
02112     for (i = 1; i < (m_kk - 1); i++) {
02113       for (j = (i+1); j < m_kk; j++) {
02114 
02115         /*
02116          * Find the counterIJ for the symmetric binary interaction
02117          */
02118         n = m_kk*i + j;
02119         counterIJ = m_CounterIJ[n];
02120             
02121         beta0MX_coeff = m_Beta0MX_ij_coeff.ptrColumn(counterIJ);
02122         beta1MX_coeff = m_Beta1MX_ij_coeff.ptrColumn(counterIJ);
02123         beta2MX_coeff = m_Beta2MX_ij_coeff.ptrColumn(counterIJ);
02124         CphiMX_coeff = m_CphiMX_ij_coeff.ptrColumn(counterIJ);
02125         Theta_coeff = m_Theta_ij_coeff.ptrColumn(counterIJ);
02126 
02127         switch (m_formPitzerTemp) {
02128         case PITZER_TEMP_CONSTANT:
02129           break;
02130         case PITZER_TEMP_LINEAR:
02131 
02132           m_Beta0MX_ij[counterIJ] = beta0MX_coeff[0] 
02133             + beta0MX_coeff[1]*tlin;
02134           m_Beta0MX_ij_L[counterIJ] = beta0MX_coeff[1];
02135           m_Beta0MX_ij_LL[counterIJ] = 0.0;
02136 
02137           m_Beta1MX_ij[counterIJ]   = beta1MX_coeff[0]
02138             + beta1MX_coeff[1]*tlin;
02139           m_Beta1MX_ij_L[counterIJ] = beta1MX_coeff[1];
02140           m_Beta1MX_ij_LL[counterIJ] = 0.0;
02141 
02142           m_Beta2MX_ij[counterIJ]    = beta2MX_coeff[0]
02143             + beta2MX_coeff[1]*tlin;
02144           m_Beta2MX_ij_L[counterIJ]  = beta2MX_coeff[1];
02145           m_Beta2MX_ij_LL[counterIJ] = 0.0;
02146 
02147           m_CphiMX_ij[counterIJ]     = CphiMX_coeff[0]
02148             + CphiMX_coeff[1]*tlin;
02149           m_CphiMX_ij_L[counterIJ]   = CphiMX_coeff[1];
02150           m_CphiMX_ij_LL[counterIJ]  = 0.0;
02151 
02152           m_Theta_ij[counterIJ]      = Theta_coeff[0] + Theta_coeff[1]*tlin;
02153           m_Theta_ij_L[counterIJ]    = Theta_coeff[1];
02154           m_Theta_ij_LL[counterIJ]   = 0.0;
02155 
02156           break;
02157 
02158         case PITZER_TEMP_COMPLEX1:
02159           m_Beta0MX_ij[counterIJ] = beta0MX_coeff[0] 
02160             + beta0MX_coeff[1]*tlin
02161             + beta0MX_coeff[2]*tquad
02162             + beta0MX_coeff[3]*tinv
02163             + beta0MX_coeff[4]*tln;
02164                 
02165           m_Beta1MX_ij[counterIJ] = beta1MX_coeff[0] 
02166             + beta1MX_coeff[1]*tlin
02167             + beta1MX_coeff[2]*tquad
02168             + beta1MX_coeff[3]*tinv
02169             + beta1MX_coeff[4]*tln;
02170 
02171           m_Beta2MX_ij[counterIJ] = beta2MX_coeff[0] 
02172             + beta2MX_coeff[1]*tlin
02173             + beta2MX_coeff[2]*tquad
02174             + beta2MX_coeff[3]*tinv
02175             + beta2MX_coeff[4]*tln;
02176 
02177           m_CphiMX_ij[counterIJ] = CphiMX_coeff[0] 
02178             + CphiMX_coeff[1]*tlin
02179             + CphiMX_coeff[2]*tquad
02180             + CphiMX_coeff[3]*tinv
02181             + CphiMX_coeff[4]*tln;
02182 
02183           m_Theta_ij[counterIJ] = Theta_coeff[0] 
02184             + Theta_coeff[1]*tlin
02185             + Theta_coeff[2]*tquad
02186             + Theta_coeff[3]*tinv
02187             + Theta_coeff[4]*tln;
02188 
02189           m_Beta0MX_ij_L[counterIJ] =  beta0MX_coeff[1]
02190             + beta0MX_coeff[2]*2.0*T
02191             - beta0MX_coeff[3]/(T*T)
02192             + beta0MX_coeff[4]/T;
02193 
02194           m_Beta1MX_ij_L[counterIJ] =  beta1MX_coeff[1]
02195             + beta1MX_coeff[2]*2.0*T
02196             - beta1MX_coeff[3]/(T*T)
02197             + beta1MX_coeff[4]/T;
02198 
02199           m_Beta2MX_ij_L[counterIJ] =  beta2MX_coeff[1]
02200             + beta2MX_coeff[2]*2.0*T
02201             - beta2MX_coeff[3]/(T*T)
02202             + beta2MX_coeff[4]/T;
02203 
02204           m_CphiMX_ij_L[counterIJ] =  CphiMX_coeff[1]
02205             + CphiMX_coeff[2]*2.0*T
02206             - CphiMX_coeff[3]/(T*T)
02207             + CphiMX_coeff[4]/T;
02208 
02209           m_Theta_ij_L[counterIJ] =   Theta_coeff[1]
02210             + Theta_coeff[2]*2.0*T
02211             - Theta_coeff[3]/(T*T)
02212             + Theta_coeff[4]/T;
02213         
02214           doDerivs = 2;
02215           if (doDerivs > 1) {
02216             m_Beta0MX_ij_LL[counterIJ] = 
02217               + beta0MX_coeff[2]*2.0
02218               + 2.0*beta0MX_coeff[3]/(T*T*T)
02219               - beta0MX_coeff[4]/(T*T);
02220                   
02221             m_Beta1MX_ij_LL[counterIJ] =
02222               + beta1MX_coeff[2]*2.0
02223               + 2.0*beta1MX_coeff[3]/(T*T*T)
02224               - beta1MX_coeff[4]/(T*T);
02225                   
02226             m_Beta2MX_ij_LL[counterIJ] =
02227               + beta2MX_coeff[2]*2.0
02228               + 2.0*beta2MX_coeff[3]/(T*T*T)
02229               - beta2MX_coeff[4]/(T*T);
02230 
02231             m_CphiMX_ij_LL[counterIJ] = 
02232               + CphiMX_coeff[2]*2.0
02233               + 2.0*CphiMX_coeff[3]/(T*T*T)
02234               - CphiMX_coeff[4]/(T*T);
02235 
02236             m_Theta_ij_LL[counterIJ] = 
02237               + Theta_coeff[2]*2.0
02238               + 2.0*Theta_coeff[3]/(T*T*T)
02239               - Theta_coeff[4]/(T*T);
02240           }
02241 
02242 #ifdef DEBUG_HKM
02243           /*
02244            * Turn terms off for debugging
02245            */
02246           //m_Beta0MX_ij_L[counterIJ] = 0;
02247           //m_Beta0MX_ij_LL[counterIJ] = 0;
02248           //m_Beta1MX_ij_L[counterIJ] = 0;
02249           //m_Beta1MX_ij_LL[counterIJ] = 0;
02250           //m_CphiMX_ij_L[counterIJ] = 0;
02251           //m_CphiMX_ij_LL[counterIJ] = 0;
02252 #endif
02253           break;
02254         }
02255       }
02256     }
02257 
02258     // Lambda interactions and Mu_nnn
02259     // i must be neutral for this term to be nonzero. We take advantage of this
02260     // here to lower the operation count.
02261     for (i = 1; i < m_kk; i++) {
02262       if (m_speciesCharge[i] == 0.0) {
02263         for (j = 1; j < m_kk; j++) {
02264           n = i * m_kk + j;
02265           const double *Lambda_coeff = m_Lambda_nj_coeff.ptrColumn(n);
02266           switch (m_formPitzerTemp) {
02267           case PITZER_TEMP_CONSTANT:
02268             m_Lambda_nj(i,j) = Lambda_coeff[0];
02269             break;
02270           case PITZER_TEMP_LINEAR:
02271             m_Lambda_nj(i,j)      = Lambda_coeff[0] + Lambda_coeff[1]*tlin;
02272             m_Lambda_nj_L(i,j)    = Lambda_coeff[1];
02273             m_Lambda_nj_LL(i,j)   = 0.0;
02274           case PITZER_TEMP_COMPLEX1:
02275             m_Lambda_nj(i,j) = Lambda_coeff[0] 
02276               + Lambda_coeff[1]*tlin
02277               + Lambda_coeff[2]*tquad
02278               + Lambda_coeff[3]*tinv
02279               + Lambda_coeff[4]*tln;
02280             
02281             m_Lambda_nj_L(i,j) = Lambda_coeff[1]
02282               + Lambda_coeff[2]*2.0*T
02283               - Lambda_coeff[3]/(T*T)
02284               + Lambda_coeff[4]/T;
02285 
02286             m_Lambda_nj_LL(i,j) = 
02287               Lambda_coeff[2]*2.0
02288               + 2.0*Lambda_coeff[3]/(T*T*T)
02289               - Lambda_coeff[4]/(T*T);
02290           }
02291 
02292           if (j == i) {
02293             const double *Mu_coeff = m_Mu_nnn_coeff.ptrColumn(i);
02294             switch (m_formPitzerTemp) {
02295             case PITZER_TEMP_CONSTANT:
02296               m_Mu_nnn[i] = Mu_coeff[0];
02297               break;
02298             case PITZER_TEMP_LINEAR:
02299               m_Mu_nnn[i]      = Mu_coeff[0] + Mu_coeff[1]*tlin;
02300               m_Mu_nnn_L[i]    = Mu_coeff[1];
02301               m_Mu_nnn_LL[i]   = 0.0;
02302             case PITZER_TEMP_COMPLEX1:
02303               m_Mu_nnn[i] = Mu_coeff[0] 
02304                 + Mu_coeff[1]*tlin
02305                 + Mu_coeff[2]*tquad
02306                 + Mu_coeff[3]*tinv
02307                 + Mu_coeff[4]*tln;
02308             
02309               m_Mu_nnn_L[i] = Mu_coeff[1]
02310                 + Mu_coeff[2]*2.0*T
02311                 - Mu_coeff[3]/(T*T)
02312                 + Mu_coeff[4]/T;
02313 
02314               m_Mu_nnn_LL[i] = 
02315                 Mu_coeff[2]*2.0
02316                 + 2.0*Mu_coeff[3]/(T*T*T)
02317                 - Mu_coeff[4]/(T*T);
02318             }
02319           }
02320         }
02321       }
02322     }
02323   
02324 
02325     for (i = 1; i < m_kk; i++) {
02326       for (j = 1; j < m_kk; j++) {
02327         for (int k = 1; k < m_kk; k++) {
02328           n = i * m_kk *m_kk + j * m_kk + k ;
02329           const double *Psi_coeff = m_Psi_ijk_coeff.ptrColumn(n);
02330           switch (m_formPitzerTemp) {
02331           case PITZER_TEMP_CONSTANT:
02332             m_Psi_ijk[n] = Psi_coeff[0];
02333             break;
02334           case PITZER_TEMP_LINEAR:
02335             m_Psi_ijk[n]      = Psi_coeff[0] + Psi_coeff[1]*tlin;
02336             m_Psi_ijk_L[n]    = Psi_coeff[1];
02337             m_Psi_ijk_LL[n]   = 0.0;
02338           case PITZER_TEMP_COMPLEX1:
02339             m_Psi_ijk[n] = Psi_coeff[0] 
02340               + Psi_coeff[1]*tlin
02341               + Psi_coeff[2]*tquad
02342               + Psi_coeff[3]*tinv
02343               + Psi_coeff[4]*tln;
02344             
02345             m_Psi_ijk_L[n] = Psi_coeff[1]
02346               + Psi_coeff[2]*2.0*T
02347               - Psi_coeff[3]/(T*T)
02348               + Psi_coeff[4]/T;
02349 
02350             m_Psi_ijk_LL[n] = 
02351                 Psi_coeff[2]*2.0
02352               + 2.0*Psi_coeff[3]/(T*T*T)
02353               - Psi_coeff[4]/(T*T);
02354           }
02355         }
02356       }
02357     }
02358 
02359   }
02360 
02361   /*
02362    * Calculate the Pitzer portion of the activity coefficients.
02363    *
02364    * This is the main routine in the whole module. It calculates the
02365    * molality based activity coefficients for the solutes, and
02366    * the activity of water.
02367    */
02368   void HMWSoln::
02369   s_updatePitzer_lnMolalityActCoeff() const {
02370 
02371     /*
02372      * HKM -> Assumption is made that the solvent is
02373      *        species 0.
02374      */
02375     if (m_indexSolvent != 0) {
02376       printf("Wrong index solvent value!\n");
02377       exit(EXIT_FAILURE);
02378     }
02379 
02380 #ifdef DEBUG_MODE
02381     int printE = 0;
02382     if (temperature() == 323.15) {
02383       printE = 0;
02384     }
02385 #endif
02386     double wateract;
02387     std::string sni,  snj, snk; 
02388 
02389     /*
02390      * Use the CROPPED molality of the species in solution. 
02391      */
02392     const double *molality = DATA_PTR(m_molalitiesCropped);
02393     /*
02394      * These are the charges of the species accessed from Constituents.h
02395      */
02396     const double *charge = DATA_PTR(m_speciesCharge);
02397 
02398     /*
02399      * These are data inputs about the Pitzer correlation. They come
02400      * from the input file for the Pitzer model.
02401      */
02402     const double *beta0MX =  DATA_PTR(m_Beta0MX_ij);
02403     const double *beta1MX =  DATA_PTR(m_Beta1MX_ij);
02404     const double *beta2MX =  DATA_PTR(m_Beta2MX_ij);
02405     const double *CphiMX  =  DATA_PTR(m_CphiMX_ij);
02406     const double *thetaij =  DATA_PTR(m_Theta_ij);
02407     const double *alpha1MX =  DATA_PTR(m_Alpha1MX_ij);
02408     const double *alpha2MX =  DATA_PTR(m_Alpha2MX_ij);
02409 
02410     const double *psi_ijk =  DATA_PTR(m_Psi_ijk);
02411     //n = k + j * m_kk + i * m_kk * m_kk;
02412 
02413 
02414     double *gamma_Unscaled = DATA_PTR(m_gamma_tmp);
02415     /*
02416      * Local variables defined by Coltrin
02417      */
02418     double etheta[5][5], etheta_prime[5][5], sqrtIs;
02419     /*
02420      * Molality based ionic strength of the solution
02421      */
02422     double Is = 0.0;
02423     /*
02424      * Molarcharge of the solution: In Pitzer's notation, 
02425      * this is his variable called "Z".
02426      */
02427     double molarcharge = 0.0;
02428     /*
02429      * molalitysum is the sum of the molalities over all solutes,
02430      * even those with zero charge.
02431      */
02432     double molalitysumUncropped = 0.0;
02433 
02434     double *gfunc    =  DATA_PTR(m_gfunc_IJ);
02435     double *g2func   =  DATA_PTR(m_g2func_IJ);
02436     double *hfunc    =  DATA_PTR(m_hfunc_IJ);
02437     double *h2func   =  DATA_PTR(m_h2func_IJ);
02438     double *BMX      =  DATA_PTR(m_BMX_IJ);
02439     double *BprimeMX =  DATA_PTR(m_BprimeMX_IJ);
02440     double *BphiMX   =  DATA_PTR(m_BphiMX_IJ);
02441     double *Phi      =  DATA_PTR(m_Phi_IJ);
02442     double *Phiprime =  DATA_PTR(m_Phiprime_IJ);
02443     double *Phiphi   =  DATA_PTR(m_PhiPhi_IJ);
02444     double *CMX      =  DATA_PTR(m_CMX_IJ);
02445 
02446  
02447     double x1, x2;
02448     double Aphi, F, zsqF;
02449     double sum1, sum2, sum3, sum4, sum5, term1;
02450     double sum_m_phi_minus_1, osmotic_coef, lnwateract;
02451 
02452     int z1, z2;
02453     int n, i, j, k, m, counterIJ,  counterIJ2;
02454 
02455 #ifdef DEBUG_MODE
02456     if (m_debugCalc) {
02457       printf("\n Debugging information from hmw_act \n");
02458     }
02459 #endif
02460     /*
02461      * Make sure the counter variables are setup
02462      */
02463     counterIJ_setup();
02464 
02465     /*
02466      * ---------- Calculate common sums over solutes ---------------------
02467      */
02468     for (n = 1; n < m_kk; n++) {
02469       //      ionic strength
02470       Is += charge[n] * charge[n] * molality[n];
02471       //      total molar charge
02472       molarcharge +=  fabs(charge[n]) * molality[n];
02473       molalitysumUncropped += m_molalities[n];
02474     }
02475     Is *= 0.5;
02476  
02477     /*
02478      * Store the ionic molality in the object for reference.
02479      */
02480     m_IionicMolality = Is;
02481     sqrtIs = sqrt(Is);
02482 #ifdef DEBUG_MODE
02483     if (m_debugCalc) {
02484       printf(" Step 1: \n");
02485       printf(" ionic strenth      = %14.7le \n total molar "
02486              "charge = %14.7le \n", Is, molarcharge);
02487     }
02488 #endif
02489 
02490     /*
02491      * The following call to calc_lambdas() calculates all 16 elements
02492      * of the elambda and elambda1 arrays, given the value of the 
02493      * ionic strength (Is)
02494      */
02495     calc_lambdas(Is);
02496 
02497     /*
02498      * ----- Step 2:  Find the coefficients E-theta and -------------------
02499      *                E-thetaprime for all combinations of positive 
02500      *                unlike charges up to 4
02501      */
02502 #ifdef DEBUG_MODE
02503     if (m_debugCalc) {
02504       printf(" Step 2: \n");
02505     }
02506 #endif
02507     for (z1 = 1; z1 <=4; z1++) {
02508       for (z2 =1; z2 <=4; z2++) {
02509         calc_thetas(z1, z2, &etheta[z1][z2], &etheta_prime[z1][z2]);
02510 #ifdef DEBUG_MODE
02511         if (m_debugCalc) {
02512           printf(" z1=%3d z2=%3d E-theta(I) = %f, E-thetaprime(I) = %f\n", 
02513                  z1, z2, etheta[z1][z2], etheta_prime[z1][z2]);
02514         }
02515 #endif
02516       }
02517     }
02518 
02519 #ifdef DEBUG_MODE
02520     if (m_debugCalc) {
02521       printf(" Step 3: \n");
02522       printf(" Species          Species            g(x) "
02523              " hfunc(x)   \n");
02524     }
02525 #endif
02526         
02527     /*
02528      *
02529      *  calculate g(x) and hfunc(x) for each cation-anion pair MX
02530      *   In the original literature, hfunc, was called gprime. However,
02531      *   it's not the derivative of g(x), so I renamed it.
02532      */
02533     for (i = 1; i < (m_kk - 1); i++) {
02534       for (j = (i+1); j < m_kk; j++) {
02535         /*
02536          * Find the counterIJ for the symmetric binary interaction
02537          */
02538         n = m_kk*i + j;
02539         counterIJ = m_CounterIJ[n];
02540 
02541         /*
02542          * Only loop over oppositely charge species
02543          */
02544         if (charge[i]*charge[j] < 0) {
02545           /*
02546            * x is a reduced function variable
02547            */
02548           x1 = sqrtIs * alpha1MX[counterIJ];
02549           if (x1 > 1.0E-100) {
02550             gfunc[counterIJ] =  2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 * x1);
02551             hfunc[counterIJ] = -2.0 *
02552               (1.0-(1.0 + x1 + 0.5 * x1 * x1) * exp(-x1)) / (x1 * x1);
02553           }
02554           else {
02555             gfunc[counterIJ] = 0.0;
02556             hfunc[counterIJ] = 0.0;
02557           }
02558           
02559           if (beta2MX[counterIJ] != 0.0) {
02560             x2 = sqrtIs * alpha2MX[counterIJ];
02561             if (x2 > 1.0E-100) {
02562               g2func[counterIJ] =  2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
02563               h2func[counterIJ] = -2.0 *
02564                 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
02565             } else {
02566               g2func[counterIJ] = 0.0;
02567               h2func[counterIJ] = 0.0;
02568             }
02569           }
02570         } 
02571         else {
02572           gfunc[counterIJ] = 0.0;
02573           hfunc[counterIJ] = 0.0;
02574         }
02575 #ifdef DEBUG_MODE
02576         if (m_debugCalc) {
02577           sni = speciesName(i);
02578           snj = speciesName(j);
02579           printf(" %-16s %-16s %9.5f %9.5f \n", sni.c_str(), snj.c_str(), 
02580                  gfunc[counterIJ], hfunc[counterIJ]);
02581         }
02582 #endif
02583       }
02584     }
02585 
02586     /*
02587      * --------- SUBSECTION TO CALCULATE BMX, BprimeMX, BphiMX ----------
02588      * --------- Agrees with Pitzer, Eq. (49), (51), (55)
02589      */
02590 #ifdef DEBUG_MODE
02591     if (m_debugCalc) {
02592       printf(" Step 4: \n");
02593       printf(" Species          Species            BMX    "
02594              "BprimeMX    BphiMX   \n");
02595     }
02596 #endif
02597 
02598     for (i = 1; i < m_kk - 1; i++) {
02599       for (j = i+1; j < m_kk; j++) {
02600         /*
02601          * Find the counterIJ for the symmetric binary interaction
02602          */
02603         n = m_kk*i + j;
02604         counterIJ = m_CounterIJ[n];
02605 
02606 #ifdef DEBUG_MODE
02607         if (printE) {
02608           if (counterIJ == 2) {
02609             printf("%s %s\n", speciesName(i).c_str(),
02610                    speciesName(j).c_str());
02611             printf("beta0MX[%d] = %g\n", counterIJ, beta0MX[counterIJ]);
02612             printf("beta1MX[%d] = %g\n", counterIJ, beta1MX[counterIJ]);
02613             printf("beta2MX[%d] = %g\n", counterIJ, beta2MX[counterIJ]);
02614           }
02615         }
02616 #endif
02617         /*
02618          *      both species have a non-zero charge, and one is positive
02619          *  and the other is negative
02620          */
02621         if (charge[i]*charge[j] < 0.0) {        
02622           BMX[counterIJ]  = beta0MX[counterIJ]
02623             + beta1MX[counterIJ] * gfunc[counterIJ]
02624             + beta2MX[counterIJ] * g2func[counterIJ];
02625 #ifdef DEBUG_MODE
02626           if (m_debugCalc) {
02627             printf("%d %g: %g %g %g %g\n",
02628                    counterIJ,  BMX[counterIJ], beta0MX[counterIJ],
02629                    beta1MX[counterIJ], beta2MX[counterIJ], gfunc[counterIJ]);
02630           }
02631 #endif
02632           if (Is > 1.0E-150) {
02633             BprimeMX[counterIJ] = (beta1MX[counterIJ] * hfunc[counterIJ]/Is +
02634                                    beta2MX[counterIJ] * h2func[counterIJ]/Is);
02635           } else {
02636             BprimeMX[counterIJ] = 0.0;
02637           }
02638           BphiMX[counterIJ]   = BMX[counterIJ] + Is*BprimeMX[counterIJ];
02639         } 
02640         else {
02641           BMX[counterIJ]      = 0.0;
02642           BprimeMX[counterIJ] = 0.0;
02643           BphiMX[counterIJ]   = 0.0;
02644         }
02645 #ifdef DEBUG_MODE
02646         if (m_debugCalc) {
02647           sni = speciesName(i);
02648           snj = speciesName(j);
02649           printf(" %-16s %-16s %11.7f %11.7f %11.7f \n", 
02650                  sni.c_str(), snj.c_str(), 
02651                  BMX[counterIJ], BprimeMX[counterIJ], BphiMX[counterIJ] );
02652         }
02653 #endif
02654       }
02655     }   
02656 
02657     /*
02658      * --------- SUBSECTION TO CALCULATE CMX ----------
02659      * --------- Agrees with Pitzer, Eq. (53).
02660      */
02661 #ifdef DEBUG_MODE
02662     if (m_debugCalc) {
02663       printf(" Step 5: \n");
02664       printf(" Species          Species            CMX \n");
02665     }
02666 #endif
02667     for (i = 1; i < m_kk-1; i++) {
02668       for (j = i+1; j < m_kk; j++) {
02669         /*
02670          * Find the counterIJ for the symmetric binary interaction
02671          */
02672         n = m_kk*i + j;
02673         counterIJ = m_CounterIJ[n];
02674         /*
02675          *      both species have a non-zero charge, and one is positive
02676          *  and the other is negative
02677          */
02678         if (charge[i]*charge[j] < 0.0) {
02679           CMX[counterIJ] = CphiMX[counterIJ]/ 
02680             (2.0* sqrt(fabs(charge[i]*charge[j])));
02681         } 
02682         else {
02683           CMX[counterIJ] = 0.0;
02684         }
02685 #ifdef DEBUG_MODE
02686         if (printE) {
02687           if (counterIJ == 2) {
02688             printf("%s %s\n", speciesName(i).c_str(), 
02689                    speciesName(j).c_str());
02690             printf("CphiMX[%d] = %g\n", counterIJ, CphiMX[counterIJ]);
02691           }
02692         }
02693 #endif
02694 #ifdef DEBUG_MODE
02695         if (m_debugCalc) {
02696           sni = speciesName(i);
02697           snj = speciesName(j);
02698           printf(" %-16s %-16s %11.7f \n", sni.c_str(), snj.c_str(),
02699                  CMX[counterIJ]);
02700         }
02701 #endif
02702       }
02703     }
02704 
02705     /*
02706      * ------- SUBSECTION TO CALCULATE Phi, PhiPrime, and PhiPhi ----------
02707      * --------- Agrees with Pitzer, Eq. 72, 73, 74
02708      */
02709 #ifdef DEBUG_MODE
02710     if (m_debugCalc) {
02711       printf(" Step 6: \n");
02712       printf(" Species          Species            Phi_ij "
02713              " Phiprime_ij  Phi^phi_ij \n");
02714     }
02715 #endif
02716     for (i = 1; i < m_kk-1; i++) {
02717       for (j = i+1; j < m_kk; j++) {
02718         /*
02719          * Find the counterIJ for the symmetric binary interaction
02720          */
02721         n = m_kk*i + j;
02722         counterIJ = m_CounterIJ[n];
02723         /*
02724          *      both species have a non-zero charge, and one is positive
02725          *  and the other is negative
02726          */
02727         if (charge[i]*charge[j] > 0) {
02728           z1 = (int) fabs(charge[i]);
02729           z2 = (int) fabs(charge[j]);
02730           Phi[counterIJ] = thetaij[counterIJ] + etheta[z1][z2];
02731           Phiprime[counterIJ] = etheta_prime[z1][z2];
02732           Phiphi[counterIJ] = Phi[counterIJ] + Is * Phiprime[counterIJ];
02733         } 
02734         else {
02735           Phi[counterIJ]      = 0.0;
02736           Phiprime[counterIJ] = 0.0;
02737           Phiphi[counterIJ]   = 0.0;
02738         }
02739 #ifdef DEBUG_MODE
02740         if (m_debugCalc) {
02741           sni = speciesName(i);
02742           snj = speciesName(j);
02743           printf(" %-16s %-16s %10.6f %10.6f %10.6f \n", 
02744                  sni.c_str(), snj.c_str(),
02745                  Phi[counterIJ], Phiprime[counterIJ], Phiphi[counterIJ] );
02746         }
02747 #endif
02748       }
02749     }
02750 
02751     /*
02752      * ------------- SUBSECTION FOR CALCULATION OF F ----------------------
02753      * ------------ Agrees with Pitzer Eqn. (65) --------------------------
02754      */
02755 #ifdef DEBUG_MODE
02756     if (m_debugCalc) {
02757       printf(" Step 7: \n");
02758     }
02759 #endif
02760     // A_Debye_Huckel = 0.5092; (units = sqrt(kg/gmol))
02761     // A_Debye_Huckel = 0.5107; <- This value is used to match GWB data
02762     //                             ( A * ln(10) = 1.17593)
02763     // Aphi = A_Debye_Huckel * 2.30258509 / 3.0;
02764     Aphi = m_A_Debye / 3.0;
02765     F = -Aphi * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
02766                   + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
02767 #ifdef DEBUG_MODE
02768     if (printE) {
02769       printf("Aphi = %20.13g\n", Aphi);
02770     }
02771 #endif
02772 #ifdef DEBUG_MODE
02773     if (m_debugCalc) {
02774       printf(" initial value of F = %10.6f \n", F );            
02775     }
02776 #endif
02777     for (i = 1; i < m_kk-1; i++) {
02778       for (j = i+1; j < m_kk; j++) {
02779         /*
02780          * Find the counterIJ for the symmetric binary interaction
02781          */
02782         n = m_kk*i + j;
02783         counterIJ = m_CounterIJ[n];
02784         /*
02785          *      both species have a non-zero charge, and one is positive
02786          *  and the other is negative
02787          */
02788         if (charge[i]*charge[j] < 0) {
02789           F = F + molality[i]*molality[j] * BprimeMX[counterIJ];
02790         }
02791         /*
02792          * Both species have a non-zero charge, and they
02793          * have the same sign
02794          */
02795         if (charge[i]*charge[j] > 0) {
02796           F = F + molality[i]*molality[j] * Phiprime[counterIJ];
02797         }
02798 #ifdef DEBUG_MODE
02799         if (m_debugCalc) printf(" F = %10.6f \n", F );
02800 #endif
02801       }
02802     }
02803 #ifdef DEBUG_MODE
02804     if (m_debugCalc) {
02805       printf(" Step 8: Summing in All Contributions to Activity Coefficients \n");
02806     }
02807 #endif
02808 
02809     for (i = 1; i < m_kk; i++) {
02810 
02811       /*
02812        * -------- SUBSECTION FOR CALCULATING THE ACTCOEFF FOR CATIONS -----
02813        * -------- -> equations agree with my notes, Eqn. (118).
02814        *          -> Equations agree with Pitzer, eqn.(63)
02815        */
02816       if (charge[i] > 0.0 ) {
02817 
02818 #ifdef DEBUG_MODE
02819         if (m_debugCalc) {
02820           sni = speciesName(i);
02821           printf("  Contributions to ln(ActCoeff_%s):\n", sni.c_str());
02822         }
02823 #endif
02824         // species i is the cation (positive) to calc the actcoeff
02825         zsqF = charge[i]*charge[i]*F;
02826 #ifdef DEBUG_MODE
02827         if (m_debugCalc) {
02828           printf("      Unary term:                                      z*z*F = %10.5f\n", zsqF);
02829         }
02830 #endif
02831         sum1 = 0.0;
02832         sum2 = 0.0;
02833         sum3 = 0.0;
02834         sum4 = 0.0;
02835         sum5 = 0.0;
02836         for (j = 1; j < m_kk; j++) {
02837           /*
02838            * Find the counterIJ for the symmetric binary interaction
02839            */
02840           n = m_kk*i + j;
02841           counterIJ = m_CounterIJ[n];
02842 
02843           if (charge[j] < 0.0) {
02844             // sum over all anions
02845             sum1 = sum1 + molality[j]*
02846               (2.0*BMX[counterIJ] + molarcharge*CMX[counterIJ]);
02847 #ifdef DEBUG_MODE
02848             if (m_debugCalc) {
02849               snj = speciesName(j) + ":";
02850               printf("      Bin term with %-13s                  2 m_j BMX = %10.5f\n", snj.c_str(),
02851                      molality[j]*2.0*BMX[counterIJ]);
02852               printf("                                                   m_j Z CMX = %10.5f\n",
02853                      molality[j]* molarcharge*CMX[counterIJ]);
02854             }
02855 #endif
02856             if (j < m_kk-1) {
02857               /*
02858                * This term is the ternary interaction involving the 
02859                * non-duplicate sum over double anions, j, k, with
02860                * respect to the cation, i.
02861                */
02862               for (k = j+1; k < m_kk; k++) {
02863                 // an inner sum over all anions
02864                 if (charge[k] < 0.0) {
02865                   n = k + j * m_kk + i * m_kk * m_kk;
02866                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk[n];
02867 #ifdef DEBUG_MODE
02868                   if (m_debugCalc) {
02869                     if (psi_ijk[n] != 0.0) {
02870                       snj = speciesName(j) + "," + speciesName(k) + ":";
02871                       printf("      Psi term on %-16s           m_j m_k psi_ijk = %10.5f\n", snj.c_str(),
02872                              molality[j]*molality[k]*psi_ijk[n]);
02873                     }
02874                   }
02875 #endif
02876                 }
02877               }
02878             }
02879           }
02880 
02881              
02882           if (charge[j] > 0.0) {
02883             // sum over all cations
02884             if (j != i) {
02885               sum2 = sum2 + molality[j]*(2.0*Phi[counterIJ]);
02886 #ifdef DEBUG_MODE
02887               if (m_debugCalc) {
02888                 if ((molality[j] * Phi[counterIJ])!= 0.0) {
02889                   snj = speciesName(j) + ":";
02890                   printf("      Phi term with %-12s                2 m_j Phi_cc = %10.5f\n", snj.c_str(),
02891                          molality[j]*(2.0*Phi[counterIJ]));
02892                 }
02893               }
02894 #endif
02895             }
02896             for (k = 1; k < m_kk; k++) {
02897               if (charge[k] < 0.0) {
02898                 // two inner sums over anions
02899 
02900                 n = k + j * m_kk + i * m_kk * m_kk;
02901                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk[n];
02902 #ifdef DEBUG_MODE
02903                 if (m_debugCalc) {
02904                   if (psi_ijk[n] != 0.0) {
02905                     snj = speciesName(j) + "," + speciesName(k) + ":";
02906                     printf("      Psi term on %-16s           m_j m_k psi_ijk = %10.5f\n", snj.c_str(),
02907                            molality[j]*molality[k]*psi_ijk[n]);
02908                   }
02909                 }
02910 #endif
02911                 /*
02912                  * Find the counterIJ for the j,k interaction
02913                  */
02914                 n = m_kk*j + k;
02915                 counterIJ2 = m_CounterIJ[n];
02916                 sum4 = sum4 + (fabs(charge[i])*
02917                                molality[j]*molality[k]*CMX[counterIJ2]);
02918 #ifdef DEBUG_MODE
02919                 if (m_debugCalc) {
02920                   if ((molality[j]*molality[k]*CMX[counterIJ2]) != 0.0) {
02921                     snj = speciesName(j) + "," + speciesName(k) + ":";
02922                     printf("      Tern CMX term on %-16s abs(z_i) m_j m_k CMX = %10.5f\n", snj.c_str(),
02923                            fabs(charge[i])* molality[j]*molality[k]*CMX[counterIJ2]);
02924                   }
02925                 }
02926 #endif
02927               }
02928             }
02929           }
02930 
02931           /*
02932            * Handle neutral j species
02933            */
02934           if (charge[j] == 0) {
02935             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj(j,i);
02936 #ifdef DEBUG_MODE
02937             if (m_debugCalc) {
02938               if ((molality[j]*2.0*m_Lambda_nj(j,i)) != 0.0) {
02939                 snj = speciesName(j) + ":";
02940                 printf("      Lambda term with %-12s                 2 m_j lam_ji = %10.5f\n", snj.c_str(),
02941                        molality[j]*2.0*m_Lambda_nj(j,i));
02942               }
02943             }
02944 #endif
02945             /*
02946              * Zeta interaction term
02947              */
02948             for (int k = 1; k < m_kk; k++) {
02949               if (charge[k] < 0.0) {
02950                 int izeta = j;
02951                 int jzeta = i;
02952                 n = izeta * m_kk * m_kk + jzeta * m_kk + k;
02953                 double zeta = psi_ijk[n];
02954                 if (zeta != 0.0) {
02955                   sum5 = sum5 + molality[j]*molality[k]*zeta;
02956 #ifdef DEBUG_MODE
02957                   if (m_debugCalc) {
02958                     snj = speciesName(j) + "," + speciesName(k) + ":";
02959                     printf("      Zeta term on %-16s         m_n m_a zeta_nMa = %10.5f\n", snj.c_str(),
02960                            molality[j]*molality[k]*psi_ijk[n]);
02961                   }
02962 #endif
02963                 }
02964               }
02965             }
02966           }
02967         }
02968         /*
02969          * Add all of the contributions up to yield the log of the
02970          * solute activity coefficients (molality scale)
02971          */
02972         m_lnActCoeffMolal_Unscaled[i] = zsqF + sum1 + sum2 + sum3 + sum4 + sum5;
02973         gamma_Unscaled[i] = exp(m_lnActCoeffMolal_Unscaled[i]);
02974 #ifdef DEBUG_MODE
02975         if (m_debugCalc) {
02976           sni = speciesName(i);
02977           printf("      Net %-16s                        lngamma[i] =  %9.5f         gamma[i]=%10.6f \n", 
02978                  sni.c_str(), m_lnActCoeffMolal_Unscaled[i], gamma_Unscaled[i]);
02979         }
02980 #endif
02981       }
02982 
02983       /*
02984        * -------- SUBSECTION FOR CALCULATING THE ACTCOEFF FOR ANIONS ------
02985        * -------- -> equations agree with my notes, Eqn. (119).
02986        *          -> Equations agree with Pitzer, eqn.(64)
02987        */
02988       if (charge[i] < 0 ) {
02989 
02990 #ifdef DEBUG_MODE
02991         if (m_debugCalc) {
02992           sni = speciesName(i);
02993           printf("  Contributions to ln(ActCoeff_%s):\n", sni.c_str());
02994         }
02995 #endif
02996 
02997         //          species i is an anion (negative)
02998         zsqF = charge[i]*charge[i]*F;
02999 #ifdef DEBUG_MODE
03000         if (m_debugCalc) {
03001           printf("      Unary term:                                      z*z*F = %10.5f\n", zsqF);
03002         }
03003 #endif
03004         sum1 = 0.0;
03005         sum2 = 0.0;
03006         sum3 = 0.0;
03007         sum4 = 0.0;
03008         sum5 = 0.0;
03009         for (j = 1; j < m_kk; j++) {
03010           /*
03011            * Find the counterIJ for the symmetric binary interaction
03012            */
03013           n = m_kk*i + j;
03014           counterIJ = m_CounterIJ[n];
03015 
03016           /*
03017            * For Anions, do the cation interactions.
03018            */
03019           if (charge[j] > 0) {
03020             sum1 = sum1 + molality[j]*
03021               (2.0*BMX[counterIJ]+molarcharge*CMX[counterIJ]);
03022 #ifdef DEBUG_MODE
03023             if (m_debugCalc) {
03024               snj = speciesName(j) + ":";
03025               printf("      Bin term with %-13s                  2 m_j BMX = %10.5f\n", snj.c_str(),
03026                      molality[j]*2.0*BMX[counterIJ]);
03027               printf("                                                   m_j Z CMX = %10.5f\n",
03028                      molality[j]* molarcharge*CMX[counterIJ]);
03029             }
03030 #endif
03031             if (j < m_kk-1) {
03032               for (k = j+1; k < m_kk; k++) {
03033                 // an inner sum over all cations
03034                 if (charge[k] > 0) {
03035                   n = k + j * m_kk + i * m_kk * m_kk;
03036                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk[n];
03037 #ifdef DEBUG_MODE
03038                   if (m_debugCalc) {
03039                     if (psi_ijk[n] != 0.0) {
03040                       snj = speciesName(j) + "," + speciesName(k) + ":";
03041                       printf("      Psi term on %-16s           m_j m_k psi_ijk = %10.5f\n", snj.c_str(),
03042                              molality[j]*molality[k]*psi_ijk[n]);
03043                     }
03044                   }
03045 #endif
03046                 }
03047               }
03048             }
03049           }
03050 
03051           /*
03052            * For Anions, do the other anion interactions.
03053            */
03054           if (charge[j] < 0.0) {
03055             //  sum over all anions
03056             if (j != i) {
03057               sum2 = sum2 + molality[j]*(2.0*Phi[counterIJ]);
03058 #ifdef DEBUG_MODE
03059               if (m_debugCalc) {
03060                 if ((molality[j] * Phi[counterIJ])!= 0.0) {
03061                   snj = speciesName(j) + ":";
03062                   printf("      Phi term with %-12s                2 m_j Phi_aa = %10.5f\n", snj.c_str(),
03063                          molality[j]*(2.0*Phi[counterIJ]));
03064                 }
03065               }
03066 #endif
03067             }
03068             for (k = 1; k < m_kk; k++) {
03069               if (charge[k] > 0.0) {
03070                 // two inner sums over cations
03071                 n = k + j * m_kk + i * m_kk * m_kk;
03072                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk[n];
03073 #ifdef DEBUG_MODE
03074                 if (m_debugCalc) {
03075                   if (psi_ijk[n] != 0.0) {
03076                     snj = speciesName(j) + "," + speciesName(k) + ":";
03077                     printf("      Psi term on %-16s           m_j m_k psi_ijk = %10.5f\n", snj.c_str(),
03078                            molality[j]*molality[k]*psi_ijk[n]);
03079                   }
03080                 }
03081 #endif
03082                 /*
03083                  * Find the counterIJ for the symmetric binary interaction
03084                  */
03085                 n = m_kk*j + k;
03086                 counterIJ2 = m_CounterIJ[n];
03087                 sum4 = sum4 + 
03088                   (fabs(charge[i])*
03089                    molality[j]*molality[k]*CMX[counterIJ2]);
03090 #ifdef DEBUG_MODE
03091                 if (m_debugCalc) {
03092                   if ((molality[j]*molality[k]*CMX[counterIJ2]) != 0.0) {
03093                     snj = speciesName(j) + "," + speciesName(k) + ":";
03094                     printf("      Tern CMX term on %-16s abs(z_i) m_j m_k CMX = %10.5f\n", snj.c_str(),
03095                            fabs(charge[i])* molality[j]*molality[k]*CMX[counterIJ2]);
03096                   }
03097                 }
03098 #endif
03099               }
03100             }
03101           }
03102 
03103           /*
03104            * for Anions, do the neutral species interaction
03105            */
03106           if (charge[j] == 0.0) {
03107             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj(j,i);
03108 #ifdef DEBUG_MODE
03109             if (m_debugCalc) {
03110               if ((molality[j]*2.0*m_Lambda_nj(j,i)) != 0.0) {
03111                 snj = speciesName(j) + ":";
03112                 printf("      Lambda term with %-12s                 2 m_j lam_ji = %10.5f\n", snj.c_str(),
03113                        molality[j]*2.0*m_Lambda_nj(j,i));
03114               }
03115             }
03116 #endif
03117             /*
03118              * Zeta interaction term
03119              */
03120             for (int k = 1; k < m_kk; k++) {
03121               if (charge[k] > 0.0) {
03122                 int izeta = j;
03123                 int jzeta = k;
03124                 int kzeta = i;
03125                 n = izeta * m_kk * m_kk + jzeta * m_kk + kzeta;
03126                 double zeta = psi_ijk[n];
03127                 if (zeta != 0.0) {
03128                   sum5 = sum5 + molality[j]*molality[k]*zeta;
03129 #ifdef DEBUG_MODE
03130                   if (m_debugCalc) {
03131                     snj = speciesName(j) + "," + speciesName(k) + ":";
03132                     printf("      Zeta term on %-16s         m_n m_c zeta_ncX = %10.5f\n", snj.c_str(),
03133                            molality[j]*molality[k]*psi_ijk[n]);
03134                   }
03135 #endif
03136                 }
03137               }
03138             }
03139           }
03140         }
03141         m_lnActCoeffMolal_Unscaled[i] = zsqF + sum1 + sum2 + sum3 + sum4 + sum5;
03142         gamma_Unscaled[i] = exp(m_lnActCoeffMolal_Unscaled[i]);
03143 #ifdef DEBUG_MODE
03144         if (m_debugCalc) {
03145           sni = speciesName(i);
03146           printf("      Net %-16s                        lngamma[i] =  %9.5f             gamma[i]=%10.6f\n", 
03147                  sni.c_str(), m_lnActCoeffMolal_Unscaled[i], gamma_Unscaled[i]);
03148         }
03149 #endif
03150       }
03151       /*
03152        * ------ SUBSECTION FOR CALCULATING NEUTRAL SOLUTE ACT COEFF -------
03153        * ------ -> equations agree with my notes,
03154        *        -> Equations agree with Pitzer,
03155        */
03156       if (charge[i] == 0.0) {
03157 #ifdef DEBUG_MODE
03158         if (m_debugCalc) {
03159           sni = speciesName(i);
03160           printf("  Contributions to ln(ActCoeff_%s):\n", sni.c_str());
03161         }
03162 #endif
03163         sum1 = 0.0;
03164         sum3 = 0.0;
03165         for (j = 1; j < m_kk; j++) {
03166           sum1 = sum1 + molality[j]*2.0*m_Lambda_nj(i,j);
03167 #ifdef DEBUG_MODE
03168           if (m_debugCalc) {
03169             if (m_Lambda_nj(i,j) != 0.0) {
03170               snj = speciesName(j) + ":";
03171               printf("      Lambda_n term on %-16s     2 m_j lambda_n_j = %10.5f\n", snj.c_str(),
03172                      molality[j]*2.0*m_Lambda_nj(i,j));
03173             }
03174           }
03175 #endif
03176 
03177           /*
03178            * Zeta term -> we piggyback on the psi term
03179            */
03180           if (charge[j] > 0.0) {
03181             for (k = 1; k < m_kk; k++) {
03182               if (charge[k] < 0.0) {
03183                 n = k + j * m_kk + i * m_kk * m_kk;
03184                 sum3 = sum3 + molality[j]*molality[k]*psi_ijk[n];
03185 #ifdef DEBUG_MODE
03186                 if (m_debugCalc) {
03187                   if (psi_ijk[n] != 0.0) {
03188                     snj = speciesName(j) + "," + speciesName(k) + ":";
03189                     printf("      Zeta term on %-16s           m_j m_k psi_ijk = %10.5f\n", snj.c_str(),
03190                            molality[j]*molality[k]*psi_ijk[n]);
03191                   }
03192                 }
03193 #endif
03194               }
03195             }
03196           }
03197         }
03198         sum2 = 3.0 * molality[i]* molality[i] * m_Mu_nnn[i];
03199 #ifdef DEBUG_MODE
03200         if (m_debugCalc) {
03201           if (m_Mu_nnn[i] != 0.0) {
03202             printf("      Mu_nnn term              3 m_n m_n Mu_n_n = %10.5f\n", 
03203                    3.0 * molality[i]* molality[i] * m_Mu_nnn[i]);
03204           }
03205         }
03206 #endif
03207         
03208         m_lnActCoeffMolal_Unscaled[i] = sum1 + sum2 + sum3;
03209         gamma_Unscaled[i] = exp(m_lnActCoeffMolal_Unscaled[i]);
03210 #ifdef DEBUG_MODE
03211         if (m_debugCalc) {
03212           sni = speciesName(i);
03213           printf("      Net %-16s                        lngamma[i] =  %9.5f             gamma[i]=%10.6f\n", 
03214                  sni.c_str(), m_lnActCoeffMolal_Unscaled[i], gamma_Unscaled[i]);
03215         }
03216 #endif
03217       }
03218 
03219     }
03220 #ifdef DEBUG_MODE
03221     if (m_debugCalc) {
03222       printf(" Step 9: \n");
03223     }
03224 #endif
03225     /*
03226      * -------- SUBSECTION FOR CALCULATING THE OSMOTIC COEFF ---------
03227      * -------- -> equations agree with my notes, Eqn. (117).
03228      *          -> Equations agree with Pitzer, eqn.(62)
03229      */
03230     sum1 = 0.0;
03231     sum2 = 0.0;
03232     sum3 = 0.0;
03233     sum4 = 0.0;
03234     sum5 = 0.0;
03235     double sum6 = 0.0;
03236     double sum7 = 0.0;
03237     /*
03238      * term1 is the DH term in the osmotic coefficient expression
03239      * b = 1.2 sqrt(kg/gmol) <- arbitrarily set in all Pitzer 
03240      *                          implementations.
03241      * Is = Ionic strength on the molality scale (units of (gmol/kg))
03242      * Aphi = A_Debye / 3   (units of sqrt(kg/gmol))
03243      */
03244     term1 = -Aphi * pow(Is,1.5) / (1.0 + 1.2 * sqrt(Is));
03245 
03246     for (j = 1; j < m_kk; j++) {
03247       /*
03248        * Loop Over Cations
03249        */
03250       if (charge[j] > 0.0) {
03251         for (k = 1; k < m_kk; k++){
03252           if (charge[k] < 0.0) {
03253             /*
03254              * Find the counterIJ for the symmetric j,k binary interaction
03255              */
03256             n = m_kk*j + k;
03257             counterIJ = m_CounterIJ[n];
03258         
03259             sum1 = sum1 + molality[j]*molality[k]*
03260               (BphiMX[counterIJ] + molarcharge*CMX[counterIJ]);
03261           }
03262         }
03263 
03264         for (k = j+1; k < m_kk; k++) {
03265           if (j == (m_kk-1)) {
03266             // we should never reach this step
03267             printf("logic error 1 in Step 9 of hmw_act");
03268             exit(EXIT_FAILURE);
03269           }
03270           if (charge[k] > 0.0) {
03271             /*
03272              * Find the counterIJ for the symmetric j,k binary interaction
03273              * between 2 cations.
03274              */
03275             n = m_kk*j + k;
03276             counterIJ = m_CounterIJ[n];
03277             sum2 = sum2 + molality[j]*molality[k]*Phiphi[counterIJ];
03278             for (m = 1; m < m_kk; m++) {
03279               if (charge[m] < 0.0) {
03280                 // species m is an anion
03281                 n = m + k * m_kk + j * m_kk * m_kk;
03282                 sum2 = sum2 + 
03283                   molality[j]*molality[k]*molality[m]*psi_ijk[n];
03284               }
03285             }
03286           }
03287         }
03288       }
03289           
03290       /*
03291        * Loop Over Anions
03292        */
03293       if (charge[j] < 0) {
03294         for (k = j+1; k < m_kk; k++) {
03295           if (j == m_kk-1) {
03296             // we should never reach this step
03297             printf("logic error 2 in Step 9 of hmw_act");
03298             exit(EXIT_FAILURE);
03299           }
03300           if (charge[k] < 0) {
03301             /*
03302              * Find the counterIJ for the symmetric j,k binary interaction
03303              * between two anions
03304              */
03305             n = m_kk*j + k;
03306             counterIJ = m_CounterIJ[n];
03307 
03308             sum3 = sum3 + molality[j]*molality[k]*Phiphi[counterIJ];
03309             for (m = 1; m < m_kk; m++) {
03310               if (charge[m] > 0.0) {
03311                 n = m + k * m_kk + j * m_kk * m_kk;
03312                 sum3 = sum3 + 
03313                   molality[j]*molality[k]*molality[m]*psi_ijk[n];
03314               }
03315             }
03316           }
03317         }
03318       }
03319           
03320       /*
03321        * Loop Over Neutral Species
03322        */
03323       if (charge[j] == 0) {
03324         for (k = 1; k < m_kk; k++) {
03325           if (charge[k] < 0.0) {
03326             sum4 = sum4 + molality[j]*molality[k]*m_Lambda_nj(j,k);
03327           }
03328           if (charge[k] > 0.0) {
03329             sum5 = sum5 + molality[j]*molality[k]*m_Lambda_nj(j,k);
03330           }
03331           if (charge[k] == 0.0) {
03332             if (k > j) {
03333               sum6 = sum6 + molality[j]*molality[k]*m_Lambda_nj(j,k);
03334             } else if (k == j) {
03335               sum6 = sum6 + 0.5 * molality[j]*molality[k]*m_Lambda_nj(j,k);
03336             }
03337           }
03338           if (charge[k] < 0.0) {
03339             int izeta = j;
03340             for (m = 1; m < m_kk; m++) {
03341               if (charge[m] > 0.0) {
03342                 int jzeta = m;
03343                 n = k + jzeta * m_kk + izeta * m_kk * m_kk;
03344                 double zeta = psi_ijk[n];
03345                 if (zeta != 0.0) {
03346                   sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta;
03347                 }
03348               }
03349             }
03350           }
03351         }
03352         sum7 += molality[j]*molality[j]*molality[j]*m_Mu_nnn[j];
03353       }
03354     }
03355     sum_m_phi_minus_1 = 2.0 * 
03356       (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
03357     /*
03358      * Calculate the osmotic coefficient from 
03359      *       osmotic_coeff = 1 + dGex/d(M0noRT) / sum(molality_i)
03360      */
03361     if (molalitysumUncropped > 1.0E-150) {
03362       osmotic_coef = 1.0 + (sum_m_phi_minus_1 / molalitysumUncropped);
03363     } else {
03364       osmotic_coef = 1.0;
03365     }
03366 #ifdef DEBUG_MODE
03367     if (printE) {
03368       printf("OsmCoef - 1 = %20.13g\n", osmotic_coef - 1.0);
03369     }
03370 #endif
03371 #ifdef DEBUG_MODE
03372     if (m_debugCalc) {
03373       printf(" term1=%10.6f sum1=%10.6f sum2=%10.6f "
03374              "sum3=%10.6f sum4=%10.6f sum5=%10.6f\n",
03375              term1, sum1, sum2, sum3, sum4, sum5);
03376       printf("     sum_m_phi_minus_1=%10.6f        osmotic_coef=%10.6f\n", 
03377              sum_m_phi_minus_1, osmotic_coef);
03378     }
03379 
03380     if (m_debugCalc) {
03381       printf(" Step 10: \n");
03382     }
03383 #endif
03384     lnwateract = -(m_weightSolvent/1000.0) * molalitysumUncropped * osmotic_coef;
03385     wateract = exp(lnwateract);
03386 
03387     /*
03388      * In Cantera, we define the activity coefficient of the solvent as
03389      *
03390      *     act_0 = actcoeff_0 * Xmol_0
03391      *
03392      * We have just computed act_0. However, this routine returns
03393      *  ln(actcoeff[]). Therefore, we must calculate ln(actcoeff_0).
03394      */
03395     double xmolSolvent = moleFraction(m_indexSolvent);
03396     double xx = MAX(m_xmolSolventMIN, xmolSolvent);
03397     m_lnActCoeffMolal_Unscaled[0] = lnwateract - log(xx);
03398 #ifdef DEBUG_MODE
03399     if (m_debugCalc) {
03400       printf(" Weight of Solvent = %16.7g\n", m_weightSolvent);
03401       printf(" molalitySumUncropped = %16.7g\n", molalitysumUncropped);
03402       printf(" ln_a_water=%10.6f a_water=%10.6f\n\n", 
03403              lnwateract, wateract);
03404     }
03405 #endif
03406   }
03407 
03408   /**
03409    * s_update_dlnMolalityActCoeff_dT()         (private, const )
03410    *
03411    *   Using internally stored values, this function calculates
03412    *   the temperature derivative of the logarithm of the
03413    *   activity coefficient for all species in the mechanism.
03414    *
03415    *   We assume that the activity coefficients are current.
03416    *
03417    *   solvent activity coefficient is on the molality
03418    *   scale. It's derivative is too.
03419    */
03420   void HMWSoln::s_update_dlnMolalityActCoeff_dT() const {
03421     /*
03422      *  Zero the unscaled 2nd derivatives
03423      */
03424     fbo_zero_dbl_1(DATA_PTR(m_dlnActCoeffMolaldT_Unscaled), m_kk);
03425     /*
03426      *  Do the actual calculation of the unscaled temperature derivatives
03427      */
03428     s_updatePitzer_dlnMolalityActCoeff_dT();
03429 
03430     //double xmolSolvent = moleFraction(m_indexSolvent);
03431     //double xx = MAX(m_xmolSolventMIN, xmolSolvent);
03432     //    double lnxs = log(xx);
03433 
03434     for (int k = 1; k < m_kk; k++) {
03435       if (CROP_speciesCropped_[k] == 2) {
03436         m_dlnActCoeffMolaldT_Unscaled[k] = 0.0;
03437       }
03438     }
03439 
03440     if (CROP_speciesCropped_[0]) {
03441       m_dlnActCoeffMolaldT_Unscaled[0] = 0.0;
03442     }
03443 
03444     /*
03445      *  Do the pH scaling to the derivatives 
03446      */
03447     s_updateScaling_pHScaling_dT();
03448 
03449 
03450   }
03451 
03452   /*************************************************************************************/
03453 
03454   /*
03455    * Calculate the Pitzer portion of the temperature
03456    * derivative of the log activity coefficients.
03457    * This is an internal routine.
03458    *
03459    * It may be assumed that the 
03460    * Pitzer activity coefficient routine is called immediately
03461    * preceding the calling of this routine. Therefore, some
03462    * quantities do not need to be recalculated in this routine.
03463    *
03464    */
03465   void HMWSoln::s_updatePitzer_dlnMolalityActCoeff_dT() const {
03466 
03467     /*
03468      * HKM -> Assumption is made that the solvent is
03469      *        species 0.
03470      */
03471 #ifdef DEBUG_MODE
03472     m_debugCalc = 0;
03473 #endif
03474     if (m_indexSolvent != 0) {
03475       printf("Wrong index solvent value!\n");
03476       exit(EXIT_FAILURE);
03477     }
03478 
03479     double d_wateract_dT;
03480     std::string sni, snj, snk; 
03481 
03482     const double *molality  =  DATA_PTR(m_molalitiesCropped);
03483     const double *charge    =  DATA_PTR(m_speciesCharge);
03484     const double *beta0MX_L =  DATA_PTR(m_Beta0MX_ij_L);
03485     const double *beta1MX_L =  DATA_PTR(m_Beta1MX_ij_L);
03486     const double *beta2MX_L =  DATA_PTR(m_Beta2MX_ij_L);
03487     const double *CphiMX_L  =  DATA_PTR(m_CphiMX_ij_L);
03488     const double *thetaij_L =  DATA_PTR(m_Theta_ij_L);
03489     const double *alpha1MX   =  DATA_PTR(m_Alpha1MX_ij);
03490     const double *alpha2MX   =  DATA_PTR(m_Alpha2MX_ij);
03491     const double *psi_ijk_L =  DATA_PTR(m_Psi_ijk_L);
03492     double *d_gamma_dT_Unscaled   =  DATA_PTR(m_gamma_tmp);
03493     /*
03494      * Local variables defined by Coltrin
03495      */
03496     double etheta[5][5], etheta_prime[5][5], sqrtIs;
03497     /*
03498      * Molality based ionic strength of the solution
03499      */
03500     double Is = 0.0;
03501     /*
03502      * Molarcharge of the solution: In Pitzer's notation, 
03503      * this is his variable called "Z".
03504      */
03505     double molarcharge = 0.0;
03506     /*
03507      * molalitysum is the sum of the molalities over all solutes,
03508      * even those with zero charge.
03509      */
03510     double molalitysum = 0.0;
03511 
03512     double *gfunc    =  DATA_PTR(m_gfunc_IJ);
03513     double *g2func   =  DATA_PTR(m_g2func_IJ);
03514     double *hfunc    =  DATA_PTR(m_hfunc_IJ);
03515     double *h2func   =  DATA_PTR(m_h2func_IJ);
03516     double *BMX_L    =  DATA_PTR(m_BMX_IJ_L);
03517     double *BprimeMX_L= DATA_PTR(m_BprimeMX_IJ_L);
03518     double *BphiMX_L =  DATA_PTR(m_BphiMX_IJ_L);
03519     double *Phi_L    =  DATA_PTR(m_Phi_IJ_L);
03520     double *Phiprime =  DATA_PTR(m_Phiprime_IJ);
03521     double *Phiphi_L =  DATA_PTR(m_PhiPhi_IJ_L);
03522     double *CMX_L    =  DATA_PTR(m_CMX_IJ_L);
03523 
03524     double x1, x2;
03525     double Aphi, dFdT, zsqdFdT;
03526     double sum1, sum2, sum3, sum4, sum5, term1;
03527     double sum_m_phi_minus_1, d_osmotic_coef_dT, d_lnwateract_dT;
03528 
03529     int z1, z2;
03530     int n, i, j, k, m, counterIJ,  counterIJ2;
03531 
03532 #ifdef DEBUG_MODE
03533     if (m_debugCalc) {
03534       printf("\n Debugging information from "
03535              "s_Pitzer_dlnMolalityActCoeff_dT()\n");
03536     }
03537 #endif
03538     /*
03539      * Make sure the counter variables are setup
03540      */
03541     counterIJ_setup();
03542 
03543     /*
03544      * ---------- Calculate common sums over solutes ---------------------
03545      */
03546     for (n = 1; n < m_kk; n++) {
03547       //      ionic strength
03548       Is += charge[n] * charge[n] * molality[n];
03549       //      total molar charge
03550       molarcharge +=  fabs(charge[n]) * molality[n];
03551       molalitysum += molality[n];
03552     }
03553     Is *= 0.5;
03554  
03555     /*
03556      * Store the ionic molality in the object for reference.
03557      */
03558     m_IionicMolality = Is;
03559     sqrtIs = sqrt(Is);
03560 #ifdef DEBUG_MODE
03561     if (m_debugCalc) {
03562       printf(" Step 1: \n");
03563       printf(" ionic strenth      = %14.7le \n total molar "
03564              "charge = %14.7le \n", Is, molarcharge);
03565     }
03566 #endif
03567 
03568     /*
03569      * The following call to calc_lambdas() calculates all 16 elements
03570      * of the elambda and elambda1 arrays, given the value of the 
03571      * ionic strength (Is)
03572      */
03573     calc_lambdas(Is);
03574 
03575     /*
03576      * ----- Step 2:  Find the coefficients E-theta and -------------------
03577      *                E-thetaprime for all combinations of positive 
03578      *                unlike charges up to 4
03579      */
03580 #ifdef DEBUG_MODE
03581     if (m_debugCalc) {
03582       printf(" Step 2: \n");
03583     }
03584 #endif
03585     for (z1 = 1; z1 <=4; z1++) {
03586       for (z2 =1; z2 <=4; z2++) {
03587         calc_thetas(z1, z2, &etheta[z1][z2], &etheta_prime[z1][z2]);
03588 #ifdef DEBUG_MODE
03589         if (m_debugCalc) {
03590           printf(" z1=%3d z2=%3d E-theta(I) = %f, E-thetaprime(I) = %f\n", 
03591                  z1, z2, etheta[z1][z2], etheta_prime[z1][z2]);
03592         }
03593 #endif
03594       }
03595     }
03596 
03597 #ifdef DEBUG_MODE
03598     if (m_debugCalc) {
03599       printf(" Step 3: \n");
03600       printf(" Species          Species            g(x) "
03601              " hfunc(x)   \n");
03602     }
03603 #endif
03604         
03605     /*
03606      *
03607      *  calculate g(x) and hfunc(x) for each cation-anion pair MX
03608      *   In the original literature, hfunc, was called gprime. However,
03609      *   it's not the derivative of g(x), so I renamed it.
03610      */
03611     for (i = 1; i < (m_kk - 1); i++) {
03612       for (j = (i+1); j < m_kk; j++) {
03613         /*
03614          * Find the counterIJ for the symmetric binary interaction
03615          */
03616         n = m_kk*i + j;
03617         counterIJ = m_CounterIJ[n];
03618         /*
03619          * Only loop over oppositely charge species
03620          */
03621         if (charge[i]*charge[j] < 0) {
03622           /*
03623            * x is a reduced function variable
03624            */
03625           x1 = sqrtIs * alpha1MX[counterIJ];
03626           if (x1 > 1.0E-100) {
03627             gfunc[counterIJ]     =  2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 * x1);
03628             hfunc[counterIJ] = -2.0 *
03629               (1.0-(1.0 + x1 + 0.5 * x1 *x1) * exp(-x1)) / (x1 * x1);
03630           }
03631           else {
03632             gfunc[counterIJ] = 0.0;
03633             hfunc[counterIJ] = 0.0;
03634           }
03635           
03636           if (beta2MX_L[counterIJ] != 0.0) {
03637             x2 = sqrtIs * alpha2MX[counterIJ];
03638             if (x2 > 1.0E-100) {
03639               g2func[counterIJ] =  2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
03640               h2func[counterIJ] = -2.0 *
03641                 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
03642             } else {
03643               g2func[counterIJ] = 0.0;
03644               h2func[counterIJ] = 0.0;
03645             }
03646           }
03647         } 
03648         else {
03649           gfunc[counterIJ] = 0.0;
03650           hfunc[counterIJ] = 0.0;
03651         }
03652 #ifdef DEBUG_MODE
03653         if (m_debugCalc) {
03654           sni = speciesName(i);
03655           snj = speciesName(j);
03656           printf(" %-16s %-16s %9.5f %9.5f \n", sni.c_str(), snj.c_str(), 
03657                  gfunc[counterIJ], hfunc[counterIJ]);
03658         }
03659 #endif
03660       }
03661     }
03662 
03663     /*
03664      * ------- SUBSECTION TO CALCULATE BMX_L, BprimeMX_L, BphiMX_L ----------
03665      * ------- These are now temperature derivatives of the
03666      *         previously calculated quantities.
03667      */
03668 #ifdef DEBUG_MODE
03669     if (m_debugCalc) {
03670       printf(" Step 4: \n");
03671       printf(" Species          Species            BMX    "
03672              "BprimeMX    BphiMX   \n");
03673     }
03674 #endif
03675 
03676     for (i = 1; i < m_kk - 1; i++) {
03677       for (j = i+1; j < m_kk; j++) {
03678         /*
03679          * Find the counterIJ for the symmetric binary interaction
03680          */
03681         n = m_kk*i + j;
03682         counterIJ = m_CounterIJ[n];
03683         /*
03684          *      both species have a non-zero charge, and one is positive
03685          *  and the other is negative
03686          */
03687         if (charge[i]*charge[j] < 0.0) {        
03688           BMX_L[counterIJ]  = beta0MX_L[counterIJ]
03689             + beta1MX_L[counterIJ] * gfunc[counterIJ]
03690             + beta2MX_L[counterIJ] * gfunc[counterIJ];
03691 #ifdef DEBUG_MODE
03692           if (m_debugCalc) {
03693             printf("%d %g: %g %g %g %g\n",
03694                    counterIJ,  BMX_L[counterIJ], beta0MX_L[counterIJ],
03695                    beta1MX_L[counterIJ],  beta2MX_L[counterIJ], gfunc[counterIJ]);
03696           }
03697 #endif
03698           if (Is > 1.0E-150) {
03699             BprimeMX_L[counterIJ] = (beta1MX_L[counterIJ] * hfunc[counterIJ]/Is +
03700                                      beta2MX_L[counterIJ] * h2func[counterIJ]/Is);
03701           } else {
03702             BprimeMX_L[counterIJ] = 0.0;
03703           }
03704           BphiMX_L[counterIJ] = BMX_L[counterIJ] + Is*BprimeMX_L[counterIJ];
03705         } 
03706         else {
03707           BMX_L[counterIJ]      = 0.0;
03708           BprimeMX_L[counterIJ] = 0.0;
03709           BphiMX_L[counterIJ]     = 0.0;
03710         }
03711 #ifdef DEBUG_MODE
03712         if (m_debugCalc) {
03713           sni = speciesName(i);
03714           snj = speciesName(j);
03715           printf(" %-16s %-16s %11.7f %11.7f %11.7f \n", 
03716                  sni.c_str(), snj.c_str(), 
03717                  BMX_L[counterIJ], BprimeMX_L[counterIJ], BphiMX_L[counterIJ]);
03718         }
03719 #endif
03720       }
03721     }   
03722 
03723     /*
03724      * --------- SUBSECTION TO CALCULATE CMX_L ----------
03725      * ---------
03726      */
03727 #ifdef DEBUG_MODE
03728     if (m_debugCalc) {
03729       printf(" Step 5: \n");
03730       printf(" Species          Species            CMX \n");
03731     }
03732 #endif
03733     for (i = 1; i < m_kk-1; i++) {
03734       for (j = i+1; j < m_kk; j++) {
03735         /*
03736          * Find the counterIJ for the symmetric binary interaction
03737          */
03738         n = m_kk*i + j;
03739         counterIJ = m_CounterIJ[n];
03740         /*
03741          *      both species have a non-zero charge, and one is positive
03742          *  and the other is negative
03743          */
03744         if (charge[i]*charge[j] < 0.0) {
03745           CMX_L[counterIJ] = CphiMX_L[counterIJ]/ 
03746             (2.0* sqrt(fabs(charge[i]*charge[j])));
03747         } 
03748         else {
03749           CMX_L[counterIJ] = 0.0;
03750         }
03751 #ifdef DEBUG_MODE
03752         if (m_debugCalc) {
03753           sni = speciesName(i);
03754           snj = speciesName(j);
03755           printf(" %-16s %-16s %11.7f \n", sni.c_str(), snj.c_str(),
03756                  CMX_L[counterIJ]);
03757         }
03758 #endif
03759       }
03760     }
03761 
03762     /*
03763      * ------- SUBSECTION TO CALCULATE Phi, PhiPrime, and PhiPhi ----------
03764      * --------
03765      */
03766 #ifdef DEBUG_MODE
03767     if (m_debugCalc) {
03768       printf(" Step 6: \n");
03769       printf(" Species          Species            Phi_ij "
03770              " Phiprime_ij  Phi^phi_ij \n");
03771     }
03772 #endif
03773     for (i = 1; i < m_kk-1; i++) {
03774       for (j = i+1; j < m_kk; j++) {
03775         /*
03776          * Find the counterIJ for the symmetric binary interaction
03777          */
03778         n = m_kk*i + j;
03779         counterIJ = m_CounterIJ[n];
03780         /*
03781          *      both species have a non-zero charge, and one is positive
03782          *  and the other is negative
03783          */
03784         if (charge[i]*charge[j] > 0) {
03785           z1 = (int) fabs(charge[i]);
03786           z2 = (int) fabs(charge[j]);
03787           //Phi[counterIJ] = thetaij_L[counterIJ] + etheta[z1][z2];
03788           Phi_L[counterIJ] = thetaij_L[counterIJ];
03789           //Phiprime[counterIJ] = etheta_prime[z1][z2];
03790           Phiprime[counterIJ] = 0.0;
03791           Phiphi_L[counterIJ] = Phi_L[counterIJ] + Is * Phiprime[counterIJ];
03792         } 
03793         else {
03794           Phi_L[counterIJ]      = 0.0;
03795           Phiprime[counterIJ] = 0.0;
03796           Phiphi_L[counterIJ]   = 0.0;
03797         }
03798 #ifdef DEBUG_MODE
03799         if (m_debugCalc) {
03800           sni = speciesName(i);
03801           snj = speciesName(j);
03802           printf(" %-16s %-16s %10.6f %10.6f %10.6f \n", 
03803                  sni.c_str(), snj.c_str(),
03804                  Phi_L[counterIJ], Phiprime[counterIJ], Phiphi_L[counterIJ] );
03805         }
03806 #endif
03807       }
03808     }
03809 
03810     /*
03811      * ----------- SUBSECTION FOR CALCULATION OF dFdT ---------------------
03812      */
03813 #ifdef DEBUG_MODE
03814     if (m_debugCalc) {
03815       printf(" Step 7: \n");
03816     }
03817 #endif
03818     // A_Debye_Huckel = 0.5092; (units = sqrt(kg/gmol))
03819     // A_Debye_Huckel = 0.5107; <- This value is used to match GWB data
03820     //                             ( A * ln(10) = 1.17593)
03821     // Aphi = A_Debye_Huckel * 2.30258509 / 3.0;
03822     Aphi = m_A_Debye / 3.0;
03823 
03824     double dA_DebyedT = dA_DebyedT_TP();
03825     double dAphidT = dA_DebyedT /3.0;
03826 #ifdef DEBUG_HKM
03827     //dAphidT = 0.0;
03828 #endif
03829     //F = -Aphi * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
03830     //      + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
03831     //dAphidT = Al / (4.0 * GasConstant * T * T);
03832     dFdT = -dAphidT * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
03833                         + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
03834 #ifdef DEBUG_MODE
03835     if (m_debugCalc) {
03836       printf(" initial value of dFdT = %10.6f \n", dFdT );              
03837     }
03838 #endif
03839     for (i = 1; i < m_kk-1; i++) {
03840       for (j = i+1; j < m_kk; j++) {
03841         /*
03842          * Find the counterIJ for the symmetric binary interaction
03843          */
03844         n = m_kk*i + j;
03845         counterIJ = m_CounterIJ[n];
03846         /*
03847          *      both species have a non-zero charge, and one is positive
03848          *  and the other is negative
03849          */
03850         if (charge[i]*charge[j] < 0) {
03851           dFdT = dFdT + molality[i]*molality[j] * BprimeMX_L[counterIJ];
03852         }
03853         /*
03854          * Both species have a non-zero charge, and they
03855          * have the same sign, e.g., both positive or both negative.
03856          */
03857         if (charge[i]*charge[j] > 0) {
03858           dFdT = dFdT + molality[i]*molality[j] * Phiprime[counterIJ];
03859         }
03860 #ifdef DEBUG_MODE
03861         if (m_debugCalc) printf(" dFdT = %10.6f \n", dFdT);
03862 #endif
03863       }
03864     }
03865 #ifdef DEBUG_MODE
03866     if (m_debugCalc) {
03867       printf(" Step 8: \n");
03868     }
03869 #endif
03870 
03871     for (i = 1; i < m_kk; i++) {
03872 
03873       /*
03874        * -------- SUBSECTION FOR CALCULATING THE dACTCOEFFdT FOR CATIONS -----
03875        * --
03876        */
03877       if (charge[i] > 0 ) {
03878         // species i is the cation (positive) to calc the actcoeff
03879         zsqdFdT = charge[i]*charge[i]*dFdT;
03880         sum1 = 0.0;
03881         sum2 = 0.0;
03882         sum3 = 0.0;
03883         sum4 = 0.0;
03884         sum5 = 0.0;
03885         for (j = 1; j < m_kk; j++) {
03886           /*
03887            * Find the counterIJ for the symmetric binary interaction
03888            */
03889           n = m_kk*i + j;
03890           counterIJ = m_CounterIJ[n];
03891 
03892           if (charge[j] < 0.0) {
03893             // sum over all anions
03894             sum1 = sum1 + molality[j]*
03895               (2.0*BMX_L[counterIJ] + molarcharge*CMX_L[counterIJ]);
03896             if (j < m_kk-1) {
03897               /*
03898                * This term is the ternary interaction involving the 
03899                * non-duplicate sum over double anions, j, k, with
03900                * respect to the cation, i.
03901                */
03902               for (k = j+1; k < m_kk; k++) {
03903                 // an inner sum over all anions
03904                 if (charge[k] < 0.0) {
03905                   n = k + j * m_kk + i * m_kk * m_kk;
03906                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk_L[n];
03907                 }
03908               }
03909             }
03910           }
03911 
03912              
03913           if (charge[j] > 0.0) {
03914             // sum over all cations
03915             if (j != i) {
03916               sum2 = sum2 + molality[j]*(2.0*Phi_L[counterIJ]);
03917             }
03918             for (k = 1; k < m_kk; k++) {
03919               if (charge[k] < 0.0) {
03920                 // two inner sums over anions
03921 
03922                 n = k + j * m_kk + i * m_kk * m_kk;
03923                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk_L[n];
03924                 /*
03925                  * Find the counterIJ for the j,k interaction
03926                  */
03927                 n = m_kk*j + k;
03928                 counterIJ2 = m_CounterIJ[n];
03929                 sum4 = sum4 + (fabs(charge[i])*
03930                                molality[j]*molality[k]*CMX_L[counterIJ2]);
03931               }
03932             }
03933           }
03934 
03935           /*
03936            * Handle neutral j species
03937            */
03938           if (charge[j] == 0) {
03939             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj_L(j,i);
03940           }
03941           /*
03942            * Zeta interaction term
03943            */
03944           for (int k = 1; k < m_kk; k++) {
03945             if (charge[k] < 0.0) {
03946               int izeta = j;
03947               int jzeta = i;
03948               n = izeta * m_kk * m_kk + jzeta * m_kk + k;
03949               double zeta_L = psi_ijk_L[n];
03950               if (zeta_L != 0.0) {
03951                 sum5 = sum5 + molality[j]*molality[k]*zeta_L;
03952               }
03953             }
03954           }
03955         }
03956         /*
03957          * Add all of the contributions up to yield the log of the
03958          * solute activity coefficients (molality scale)
03959          */
03960         m_dlnActCoeffMolaldT_Unscaled[i] =
03961           zsqdFdT + sum1 + sum2 + sum3 + sum4 + sum5;
03962         d_gamma_dT_Unscaled[i] = exp(m_dlnActCoeffMolaldT_Unscaled[i]);
03963 #ifdef DEBUG_MODE
03964         if (m_debugCalc) {
03965           sni = speciesName(i);
03966           printf(" %-16s lngamma[i]=%10.6f gamma[i]=%10.6f \n", 
03967                  sni.c_str(), m_dlnActCoeffMolaldT_Unscaled[i], d_gamma_dT_Unscaled[i]);
03968           printf("                   %12g %12g %12g %12g %12g %12g\n",
03969                  zsqdFdT, sum1, sum2, sum3, sum4, sum5);
03970         }
03971 #endif
03972       }
03973 
03974       /*
03975        * ------ SUBSECTION FOR CALCULATING THE dACTCOEFFdT FOR ANIONS ------
03976        *
03977        */
03978       if (charge[i] < 0 ) {
03979         //          species i is an anion (negative)
03980         zsqdFdT = charge[i]*charge[i]*dFdT;
03981         sum1 = 0.0;
03982         sum2 = 0.0;
03983         sum3 = 0.0;
03984         sum4 = 0.0;
03985         sum5 = 0.0;
03986         for (j = 1; j < m_kk; j++) {
03987           /*
03988            * Find the counterIJ for the symmetric binary interaction
03989            */
03990           n = m_kk*i + j;
03991           counterIJ = m_CounterIJ[n];
03992 
03993           /*
03994            * For Anions, do the cation interactions.
03995            */
03996           if (charge[j] > 0) {
03997             sum1 = sum1 + molality[j]*
03998               (2.0*BMX_L[counterIJ] + molarcharge*CMX_L[counterIJ]);
03999             if (j < m_kk-1) {
04000               for (k = j+1; k < m_kk; k++) {
04001                 // an inner sum over all cations
04002                 if (charge[k] > 0) {
04003                   n = k + j * m_kk + i * m_kk * m_kk;
04004                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk_L[n];
04005                 }
04006               }
04007             }
04008           }
04009 
04010           /*
04011            * For Anions, do the other anion interactions.
04012            */
04013           if (charge[j] < 0.0) {
04014             //  sum over all anions
04015             if (j != i) {
04016               sum2 = sum2 + molality[j]*(2.0*Phi_L[counterIJ]);
04017             }
04018             for (k = 1; k < m_kk; k++) {
04019               if (charge[k] > 0.0) {
04020                 // two inner sums over cations
04021                 n = k + j * m_kk + i * m_kk * m_kk;
04022                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk_L[n];
04023                 /*
04024                  * Find the counterIJ for the symmetric binary interaction
04025                  */
04026                 n = m_kk*j + k;
04027                 counterIJ2 = m_CounterIJ[n];
04028                 sum4 = sum4 + 
04029                   (fabs(charge[i])*
04030                    molality[j]*molality[k]*CMX_L[counterIJ2]);
04031               }
04032             }
04033           }
04034 
04035           /*
04036            * for Anions, do the neutral species interaction
04037            */
04038           if (charge[j] == 0.0) {
04039             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj_L(j,i);
04040             for (int k = 1; k < m_kk; k++) {
04041               if (charge[k] > 0.0) {
04042                 int izeta = j;
04043                 int jzeta = k;
04044                 int kzeta = i;
04045                 n = izeta * m_kk * m_kk + jzeta * m_kk + kzeta;
04046                 double zeta_L = psi_ijk_L[n];
04047                 if (zeta_L != 0.0) {
04048                   sum5 = sum5 + molality[j]*molality[k]*zeta_L;
04049                 }
04050               }
04051             }
04052           }
04053         }
04054         m_dlnActCoeffMolaldT_Unscaled[i] = 
04055           zsqdFdT + sum1 + sum2 + sum3 + sum4 + sum5;
04056         d_gamma_dT_Unscaled[i] = exp(m_dlnActCoeffMolaldT_Unscaled[i]);
04057 #ifdef DEBUG_MODE
04058         if (m_debugCalc) {
04059           sni = speciesName(i);
04060           printf(" %-16s lngamma[i]=%10.6f gamma[i]=%10.6f\n", 
04061                  sni.c_str(), m_dlnActCoeffMolaldT_Unscaled[i], d_gamma_dT_Unscaled[i]);
04062           printf("                   %12g %12g %12g %12g %12g %12g\n",
04063                  zsqdFdT, sum1, sum2, sum3, sum4, sum5);
04064         }
04065 #endif
04066       }
04067       /*
04068        * ------ SUBSECTION FOR CALCULATING NEUTRAL SOLUTE ACT COEFF -------
04069        * ------ -> equations agree with my notes,
04070        *        -> Equations agree with Pitzer,
04071        */
04072       if (charge[i] == 0.0 ) {
04073         sum1 = 0.0;
04074         sum3 = 0.0;
04075         for (j = 1; j < m_kk; j++) {
04076           sum1 = sum1 + molality[j]*2.0*m_Lambda_nj_L(i,j);
04077           /*
04078            * Zeta term -> we piggyback on the psi term
04079            */
04080           if (charge[j] > 0.0) {
04081             for (k = 1; k < m_kk; k++) {
04082               if (charge[k] < 0.0) {
04083                 n = k + j * m_kk + i * m_kk * m_kk;
04084                 sum3 = sum3 + molality[j]*molality[k]*psi_ijk_L[n];
04085               }
04086             }
04087           }
04088         }
04089         sum2 = 3.0 * molality[i] * molality[i] * m_Mu_nnn_L[i];
04090         m_dlnActCoeffMolaldT_Unscaled[i] = sum1 + sum2 + sum3;
04091         d_gamma_dT_Unscaled[i] = exp(m_dlnActCoeffMolaldT_Unscaled[i]);
04092 #ifdef DEBUG_MODE
04093         if (m_debugCalc) {
04094           sni = speciesName(i);
04095           printf(" %-16s lngamma[i]=%10.6f gamma[i]=%10.6f \n", 
04096                  sni.c_str(), m_dlnActCoeffMolaldT_Unscaled[i], d_gamma_dT_Unscaled[i]);
04097         }
04098 #endif
04099       }
04100 
04101     }
04102 #ifdef DEBUG_MODE
04103     if (m_debugCalc) {
04104       printf(" Step 9: \n");
04105     }
04106 #endif
04107     /*
04108      * ------ SUBSECTION FOR CALCULATING THE d OSMOTIC COEFF dT ---------
04109      *
04110      */
04111     sum1 = 0.0;
04112     sum2 = 0.0;
04113     sum3 = 0.0;
04114     sum4 = 0.0;
04115     sum5 = 0.0;
04116     double sum6 = 0.0;
04117     double sum7 = 0.0;
04118     /*
04119      * term1 is the temperature derivative of the
04120      * DH term in the osmotic coefficient expression
04121      * b = 1.2 sqrt(kg/gmol) <- arbitrarily set in all Pitzer 
04122      *                          implementations.
04123      * Is = Ionic strength on the molality scale (units of (gmol/kg))
04124      * Aphi = A_Debye / 3   (units of sqrt(kg/gmol))
04125      */
04126     term1 = -dAphidT * Is * sqrt(Is) / (1.0 + 1.2 * sqrt(Is));
04127 
04128     for (j = 1; j < m_kk; j++) {
04129       /*
04130        * Loop Over Cations
04131        */
04132       if (charge[j] > 0.0) {
04133         for (k = 1; k < m_kk; k++){
04134           if (charge[k] < 0.0) {
04135             /*
04136              * Find the counterIJ for the symmetric j,k binary interaction
04137              */
04138             n = m_kk*j + k;
04139             counterIJ = m_CounterIJ[n];
04140         
04141             sum1 = sum1 + molality[j]*molality[k]*
04142               (BphiMX_L[counterIJ] + molarcharge*CMX_L[counterIJ]);
04143           }
04144         }
04145 
04146         for (k = j+1; k < m_kk; k++) {
04147           if (j == (m_kk-1)) {
04148             // we should never reach this step
04149             printf("logic error 1 in Step 9 of hmw_act");
04150             exit(EXIT_FAILURE);
04151           }
04152           if (charge[k] > 0.0) {
04153             /*
04154              * Find the counterIJ for the symmetric j,k binary interaction
04155              * between 2 cations.
04156              */
04157             n = m_kk*j + k;
04158             counterIJ = m_CounterIJ[n];
04159             sum2 = sum2 + molality[j]*molality[k]*Phiphi_L[counterIJ];
04160             for (m = 1; m < m_kk; m++) {
04161               if (charge[m] < 0.0) {
04162                 // species m is an anion
04163                 n = m + k * m_kk + j * m_kk * m_kk;
04164                 sum2 = sum2 + 
04165                   molality[j]*molality[k]*molality[m]*psi_ijk_L[n];
04166               }
04167             }
04168           }
04169         }
04170       }
04171           
04172       /*
04173        * Loop Over Anions
04174        */
04175       if (charge[j] < 0) {
04176         for (k = j+1; k < m_kk; k++) {
04177           if (j == m_kk-1) {
04178             // we should never reach this step
04179             printf("logic error 2 in Step 9 of hmw_act");
04180             exit(EXIT_FAILURE);
04181           }
04182           if (charge[k] < 0) {
04183             /*
04184              * Find the counterIJ for the symmetric j,k binary interaction
04185              * between two anions
04186              */
04187             n = m_kk*j + k;
04188             counterIJ = m_CounterIJ[n];
04189 
04190             sum3 = sum3 + molality[j]*molality[k]*Phiphi_L[counterIJ];
04191             for (m = 1; m < m_kk; m++) {
04192               if (charge[m] > 0.0) {
04193                 n = m + k * m_kk + j * m_kk * m_kk;
04194                 sum3 = sum3 + 
04195                   molality[j]*molality[k]*molality[m]*psi_ijk_L[n];
04196               }
04197             }
04198           }
04199         }
04200       }
04201           
04202       /*
04203        * Loop Over Neutral Species
04204        */
04205       if (charge[j] == 0) {
04206         for (k = 1; k < m_kk; k++) {
04207           if (charge[k] < 0.0) {
04208             sum4 = sum4 + molality[j]*molality[k]*m_Lambda_nj_L(j,k);
04209           }
04210           if (charge[k] > 0.0) {
04211             sum5 = sum5 + molality[j]*molality[k]*m_Lambda_nj_L(j,k);
04212           }
04213           if (charge[k] == 0.0) {
04214             if (k > j) {
04215               sum6 = sum6 + molality[j]*molality[k]*m_Lambda_nj_L(j,k);
04216             } else if (k == j) {
04217               sum6 = sum6 + 0.5 * molality[j]*molality[k]*m_Lambda_nj_L(j,k);
04218             }
04219           }
04220           if (charge[k] < 0.0) {
04221             int izeta = j;
04222             for (m = 1; m < m_kk; m++) {
04223               if (charge[m] > 0.0) {
04224                 int jzeta = m;
04225                 n = k + jzeta * m_kk + izeta * m_kk * m_kk;
04226                 double zeta_L = psi_ijk_L[n];
04227                 if (zeta_L != 0.0) {
04228                   sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta_L;
04229                 }
04230               }
04231             }
04232           }
04233         }
04234         sum7 += molality[j]*molality[j]*molality[j]*m_Mu_nnn_L[j];
04235       }
04236     }
04237     sum_m_phi_minus_1 = 2.0 * 
04238       (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
04239     /*
04240      * Calculate the osmotic coefficient from 
04241      *       osmotic_coeff = 1 + dGex/d(M0noRT) / sum(molality_i)
04242      */
04243     if (molalitysum > 1.0E-150) {
04244       d_osmotic_coef_dT = 0.0 + (sum_m_phi_minus_1 / molalitysum);
04245     } else {
04246       d_osmotic_coef_dT = 0.0;
04247     }
04248 #ifdef DEBUG_MODE
04249     if (m_debugCalc) {
04250       printf(" term1=%10.6f sum1=%10.6f sum2=%10.6f "
04251              "sum3=%10.6f sum4=%10.6f sum5=%10.6f\n",
04252              term1, sum1, sum2, sum3, sum4, sum5);
04253       printf("     sum_m_phi_minus_1=%10.6f        d_osmotic_coef_dT =%10.6f\n", 
04254              sum_m_phi_minus_1, d_osmotic_coef_dT);
04255     }
04256 
04257     if (m_debugCalc) {
04258       printf(" Step 10: \n");
04259     }
04260 #endif
04261     d_lnwateract_dT = -(m_weightSolvent/1000.0) * molalitysum * d_osmotic_coef_dT;
04262     d_wateract_dT = exp(d_lnwateract_dT);
04263 
04264     /*
04265      * In Cantera, we define the activity coefficient of the solvent as
04266      *
04267      *     act_0 = actcoeff_0 * Xmol_0
04268      *
04269      * We have just computed act_0. However, this routine returns
04270      *  ln(actcoeff[]). Therefore, we must calculate ln(actcoeff_0).
04271      */
04272     //double xmolSolvent = moleFraction(m_indexSolvent);
04273     m_dlnActCoeffMolaldT_Unscaled[0] = d_lnwateract_dT;
04274 #ifdef DEBUG_MODE
04275     if (m_debugCalc) {
04276       printf(" d_ln_a_water_dT = %10.6f d_a_water_dT=%10.6f\n\n", 
04277              d_lnwateract_dT, d_wateract_dT); 
04278     }
04279 #endif
04280   }
04281 
04282   /**
04283    * This function calculates the temperature second derivative
04284    * of the natural logarithm of the molality activity 
04285    * coefficients.
04286    */
04287   void HMWSoln::s_update_d2lnMolalityActCoeff_dT2() const {
04288     /*
04289      *  Zero the unscaled 2nd derivatives
04290      */
04291     fbo_zero_dbl_1(DATA_PTR(m_d2lnActCoeffMolaldT2_Unscaled), m_kk);
04292     /*
04293      * Calculate the unscaled 2nd derivatives
04294      */
04295     s_updatePitzer_d2lnMolalityActCoeff_dT2();
04296 
04297     //double xmolSolvent = moleFraction(m_indexSolvent);
04298     //double xx = MAX(m_xmolSolventMIN, xmolSolvent);
04299     //double lnxs = log(xx);
04300 
04301     for (int k = 1; k < m_kk; k++) {
04302       if (CROP_speciesCropped_[k] == 2) {
04303         m_d2lnActCoeffMolaldT2_Unscaled[k] = 0.0;
04304       }
04305     }
04306 
04307     if (CROP_speciesCropped_[0]) {
04308       m_d2lnActCoeffMolaldT2_Unscaled[0] = 0.0;
04309     }    
04310 
04311     /*
04312      * Scale the 2nd derivatives 
04313      */
04314     s_updateScaling_pHScaling_dT2();
04315   }
04316 
04317   /*************************************************************************************/
04318 
04319   /*
04320    * s_updatePitzer_d2lnMolalityActCoeff_dT2()         (private, const )
04321    *
04322    *   Using internally stored values, this function calculates
04323    *   the temperature 2nd derivative of the logarithm of the
04324    *   activity coefficient for all species in the mechanism.
04325    *   This is an internal routine
04326    *
04327    *   We assume that the activity coefficients and first temperature
04328    *   derivatives of the activity coefficients  are current.
04329    *
04330    * It may be assumed that the 
04331    * Pitzer activity coefficient and first deriv routine are called immediately
04332    * preceding the calling of this routine. Therefore, some
04333    * quantities do not need to be recalculated in this routine.
04334    *
04335    *   solvent activity coefficient is on the molality
04336    *   scale. It's derivatives are too.
04337    */
04338   void HMWSoln::s_updatePitzer_d2lnMolalityActCoeff_dT2() const {
04339 
04340     /*
04341      * HKM -> Assumption is made that the solvent is
04342      *        species 0.
04343      */
04344 #ifdef DEBUG_MODE
04345     m_debugCalc = 0;
04346 #endif
04347     if (m_indexSolvent != 0) {
04348       printf("Wrong index solvent value!\n");
04349       exit(EXIT_FAILURE);
04350     }
04351 
04352     std::string sni, snj, snk; 
04353 
04354     const double *molality  =  DATA_PTR(m_molalitiesCropped);
04355     const double *charge    =  DATA_PTR(m_speciesCharge);
04356     const double *beta0MX_LL=  DATA_PTR(m_Beta0MX_ij_LL);
04357     const double *beta1MX_LL=  DATA_PTR(m_Beta1MX_ij_LL);
04358     const double *beta2MX_LL=  DATA_PTR(m_Beta2MX_ij_LL);
04359     const double *CphiMX_LL =  DATA_PTR(m_CphiMX_ij_LL);
04360     const double *thetaij_LL=  DATA_PTR(m_Theta_ij_LL);
04361     const double *alpha1MX  =  DATA_PTR(m_Alpha1MX_ij);
04362     const double *alpha2MX  =  DATA_PTR(m_Alpha2MX_ij);
04363     const double *psi_ijk_LL=  DATA_PTR(m_Psi_ijk_LL);
04364 
04365     /*
04366      * Local variables defined by Coltrin
04367      */
04368     double etheta[5][5], etheta_prime[5][5], sqrtIs;
04369     /*
04370      * Molality based ionic strength of the solution
04371      */
04372     double Is = 0.0;
04373     /*
04374      * Molarcharge of the solution: In Pitzer's notation, 
04375      * this is his variable called "Z".
04376      */
04377     double molarcharge = 0.0;
04378     /*
04379      * molalitysum is the sum of the molalities over all solutes,
04380      * even those with zero charge.
04381      */
04382     double molalitysum = 0.0;
04383 
04384     double *gfunc    =  DATA_PTR(m_gfunc_IJ);
04385     double *g2func   =  DATA_PTR(m_g2func_IJ);
04386     double *hfunc    =  DATA_PTR(m_hfunc_IJ);
04387     double *h2func   =  DATA_PTR(m_h2func_IJ);
04388     double *BMX_LL   =  DATA_PTR(m_BMX_IJ_LL);
04389     double *BprimeMX_LL=DATA_PTR(m_BprimeMX_IJ_LL);
04390     double *BphiMX_LL=  DATA_PTR(m_BphiMX_IJ_LL);
04391     double *Phi_LL   =  DATA_PTR(m_Phi_IJ_LL);
04392     double *Phiprime =  DATA_PTR(m_Phiprime_IJ);
04393     double *Phiphi_LL=  DATA_PTR(m_PhiPhi_IJ_LL);
04394     double *CMX_LL   =  DATA_PTR(m_CMX_IJ_LL);
04395 
04396 
04397     double x1, x2;
04398     double d2FdT2, zsqd2FdT2;
04399     double sum1, sum2, sum3, sum4, sum5, term1;
04400     double sum_m_phi_minus_1, d2_osmotic_coef_dT2, d2_lnwateract_dT2;
04401 
04402     int z1, z2;
04403     int n, i, j, k, m, counterIJ,  counterIJ2;
04404 
04405 #ifdef DEBUG_MODE
04406     if (m_debugCalc) {
04407       printf("\n Debugging information from "
04408              "s_Pitzer_d2lnMolalityActCoeff_dT2()\n");
04409     }
04410 #endif
04411     /*
04412      * Make sure the counter variables are setup
04413      */
04414     counterIJ_setup();
04415 
04416 
04417     /*
04418      * ---------- Calculate common sums over solutes ---------------------
04419      */
04420     for (n = 1; n < m_kk; n++) {
04421       //      ionic strength
04422       Is += charge[n] * charge[n] * molality[n];
04423       //      total molar charge
04424       molarcharge +=  fabs(charge[n]) * molality[n];
04425       molalitysum += molality[n];
04426     }
04427     Is *= 0.5;
04428 
04429     /*
04430      * Store the ionic molality in the object for reference.
04431      */
04432     m_IionicMolality = Is;
04433     sqrtIs = sqrt(Is);
04434 #ifdef DEBUG_MODE
04435     if (m_debugCalc) {
04436       printf(" Step 1: \n");
04437       printf(" ionic strenth      = %14.7le \n total molar "
04438              "charge = %14.7le \n", Is, molarcharge);
04439     }
04440 #endif
04441 
04442     /*
04443      * The following call to calc_lambdas() calculates all 16 elements
04444      * of the elambda and elambda1 arrays, given the value of the 
04445      * ionic strength (Is)
04446      */
04447     calc_lambdas(Is);
04448 
04449     /*
04450      * ----- Step 2:  Find the coefficients E-theta and -------------------
04451      *                E-thetaprime for all combinations of positive 
04452      *                unlike charges up to 4
04453      */
04454 #ifdef DEBUG_MODE
04455     if (m_debugCalc) {
04456       printf(" Step 2: \n");
04457     }
04458 #endif
04459     for (z1 = 1; z1 <=4; z1++) {
04460       for (z2 =1; z2 <=4; z2++) {
04461         calc_thetas(z1, z2, &etheta[z1][z2], &etheta_prime[z1][z2]);
04462 #ifdef DEBUG_MODE
04463         if (m_debugCalc) {
04464           printf(" z1=%3d z2=%3d E-theta(I) = %f, E-thetaprime(I) = %f\n", 
04465                  z1, z2, etheta[z1][z2], etheta_prime[z1][z2]);
04466         }
04467 #endif
04468       }
04469     }
04470 
04471 #ifdef DEBUG_MODE
04472     if (m_debugCalc) {
04473       printf(" Step 3: \n");
04474       printf(" Species          Species            g(x) "
04475              " hfunc(x)   \n");
04476     }
04477 #endif
04478         
04479     /*
04480      *
04481      *  calculate gfunc(x) and hfunc(x) for each cation-anion pair MX
04482      *   In the original literature, hfunc, was called gprime. However,
04483      *   it's not the derivative of gfunc(x), so I renamed it.
04484      */
04485     for (i = 1; i < (m_kk - 1); i++) {
04486       for (j = (i+1); j < m_kk; j++) {
04487         /*
04488          * Find the counterIJ for the symmetric binary interaction
04489          */
04490         n = m_kk*i + j;
04491         counterIJ = m_CounterIJ[n];
04492         /*
04493          * Only loop over oppositely charge species
04494          */
04495         if (charge[i]*charge[j] < 0) {
04496           /*
04497            * x is a reduced function variable
04498            */
04499           x1 = sqrtIs * alpha1MX[counterIJ];
04500           if (x1 > 1.0E-100) {
04501             gfunc[counterIJ] =  2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 *x1);
04502             hfunc[counterIJ] = -2.0*
04503               (1.0-(1.0 + x1 + 0.5*x1 * x1) * exp(-x1)) / (x1 * x1);
04504           }
04505           else {
04506             gfunc[counterIJ] = 0.0;
04507             hfunc[counterIJ] = 0.0;
04508           }
04509           
04510           if (beta2MX_LL[counterIJ] != 0.0) {
04511             x2 = sqrtIs * alpha2MX[counterIJ];
04512             if (x2 > 1.0E-100) {
04513               g2func[counterIJ] =  2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
04514               h2func[counterIJ] = -2.0 *
04515                 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
04516             } else {
04517               g2func[counterIJ] = 0.0;
04518               h2func[counterIJ] = 0.0;
04519             }
04520           }
04521         } 
04522         else {
04523           gfunc[counterIJ] = 0.0;
04524           hfunc[counterIJ] = 0.0;
04525         }
04526 #ifdef DEBUG_MODE
04527         if (m_debugCalc) {
04528           sni = speciesName(i);
04529           snj = speciesName(j);
04530           printf(" %-16s %-16s %9.5f %9.5f \n", sni.c_str(), snj.c_str(), 
04531                  gfunc[counterIJ], hfunc[counterIJ]);
04532         }
04533 #endif
04534       }
04535     }
04536     /*
04537      * ------- SUBSECTION TO CALCULATE BMX_L, BprimeMX_LL, BphiMX_L ----------
04538      * ------- These are now temperature derivatives of the
04539      *         previously calculated quantities.
04540      */
04541 #ifdef DEBUG_MODE
04542     if (m_debugCalc) {
04543       printf(" Step 4: \n");
04544       printf(" Species          Species            BMX    "
04545              "BprimeMX    BphiMX   \n");
04546     }
04547 #endif
04548   
04549     for (i = 1; i < m_kk - 1; i++) {
04550       for (j = i+1; j < m_kk; j++) {
04551         /*
04552          * Find the counterIJ for the symmetric binary interaction
04553          */
04554         n = m_kk*i + j;
04555         counterIJ = m_CounterIJ[n];
04556         /*
04557          *      both species have a non-zero charge, and one is positive
04558          *  and the other is negative
04559          */
04560         if (charge[i]*charge[j] < 0.0) {
04561           BMX_LL[counterIJ]  = beta0MX_LL[counterIJ]
04562             + beta1MX_LL[counterIJ] * gfunc[counterIJ]
04563             + beta2MX_LL[counterIJ] * g2func[counterIJ];
04564 #ifdef DEBUG_MODE
04565           if (m_debugCalc) {
04566             printf("%d %g: %g %g %g %g\n",
04567                    counterIJ,  BMX_LL[counterIJ], beta0MX_LL[counterIJ],
04568                    beta1MX_LL[counterIJ], beta2MX_LL[counterIJ], gfunc[counterIJ]);
04569           }
04570 #endif
04571           if (Is > 1.0E-150) {
04572             BprimeMX_LL[counterIJ] = (beta1MX_LL[counterIJ] * hfunc[counterIJ]/Is +
04573                                       beta2MX_LL[counterIJ] * h2func[counterIJ]/Is);
04574           } else {
04575             BprimeMX_LL[counterIJ] = 0.0;
04576           }
04577           BphiMX_LL[counterIJ] = BMX_LL[counterIJ] + Is*BprimeMX_LL[counterIJ];
04578         } 
04579         else {
04580           BMX_LL[counterIJ]      = 0.0;
04581           BprimeMX_LL[counterIJ] = 0.0;
04582           BphiMX_LL[counterIJ]     = 0.0;
04583         }
04584 #ifdef DEBUG_MODE
04585         if (m_debugCalc) {
04586           sni = speciesName(i);
04587           snj = speciesName(j);
04588           printf(" %-16s %-16s %11.7f %11.7f %11.7f \n", 
04589                  sni.c_str(), snj.c_str(), 
04590                  BMX_LL[counterIJ], BprimeMX_LL[counterIJ], BphiMX_LL[counterIJ]);
04591         }
04592 #endif
04593       }
04594     }   
04595 
04596     /*
04597      * --------- SUBSECTION TO CALCULATE CMX_LL ----------
04598      * ---------
04599      */
04600 #ifdef DEBUG_MODE
04601     if (m_debugCalc) {
04602       printf(" Step 5: \n");
04603       printf(" Species          Species            CMX \n");
04604     }
04605 #endif
04606     for (i = 1; i < m_kk-1; i++) {
04607       for (j = i+1; j < m_kk; j++) {
04608         /*
04609          * Find the counterIJ for the symmetric binary interaction
04610          */
04611         n = m_kk*i + j;
04612         counterIJ = m_CounterIJ[n];
04613         /*
04614          *      both species have a non-zero charge, and one is positive
04615          *  and the other is negative
04616          */
04617         if (charge[i]*charge[j] < 0.0) {
04618           CMX_LL[counterIJ] = CphiMX_LL[counterIJ]/ 
04619             (2.0* sqrt(fabs(charge[i]*charge[j])));
04620         } else {
04621           CMX_LL[counterIJ] = 0.0;
04622         }
04623 #ifdef DEBUG_MODE
04624         if (m_debugCalc) {
04625           sni = speciesName(i);
04626           snj = speciesName(j);
04627           printf(" %-16s %-16s %11.7f \n", sni.c_str(), snj.c_str(),
04628                  CMX_LL[counterIJ]);
04629         }
04630 #endif
04631       }
04632     }
04633 
04634     /*
04635      * ------- SUBSECTION TO CALCULATE Phi, PhiPrime, and PhiPhi ----------
04636      * --------
04637      */
04638 #ifdef DEBUG_MODE
04639     if (m_debugCalc) {
04640       printf(" Step 6: \n");
04641       printf(" Species          Species            Phi_ij "
04642              " Phiprime_ij  Phi^phi_ij \n");
04643     }
04644 #endif
04645     for (i = 1; i < m_kk-1; i++) {
04646       for (j = i+1; j < m_kk; j++) {
04647         /*
04648          * Find the counterIJ for the symmetric binary interaction
04649          */
04650         n = m_kk*i + j;
04651         counterIJ = m_CounterIJ[n];
04652         /*
04653          *      both species have a non-zero charge, and one is positive
04654          *  and the other is negative
04655          */
04656         if (charge[i]*charge[j] > 0) {
04657           z1 = (int) fabs(charge[i]);
04658           z2 = (int) fabs(charge[j]);
04659           //Phi[counterIJ] = thetaij[counterIJ] + etheta[z1][z2];
04660           //Phi_L[counterIJ] = thetaij_L[counterIJ];
04661           Phi_LL[counterIJ] = thetaij_LL[counterIJ];
04662           //Phiprime[counterIJ] = etheta_prime[z1][z2];
04663           Phiprime[counterIJ] = 0.0;
04664           //Phiphi[counterIJ] = Phi[counterIJ] + Is * Phiprime[counterIJ];
04665           //Phiphi_L[counterIJ] = Phi_L[counterIJ] + Is * Phiprime[counterIJ];
04666           Phiphi_LL[counterIJ] = Phi_LL[counterIJ];
04667         } 
04668         else {
04669           Phi_LL[counterIJ]      = 0.0;
04670           Phiprime[counterIJ] = 0.0;
04671           Phiphi_LL[counterIJ]   = 0.0;
04672         }
04673 #ifdef DEBUG_MODE
04674         if (m_debugCalc) {
04675           sni = speciesName(i);
04676           snj = speciesName(j);
04677           //printf(" %-16s %-16s %10.6f %10.6f %10.6f \n", 
04678           //         sni.c_str(), snj.c_str(),
04679           //     Phi_L[counterIJ], Phiprime[counterIJ], Phiphi_L[counterIJ] );
04680           printf(" %-16s %-16s %10.6f %10.6f %10.6f \n", 
04681                  sni.c_str(), snj.c_str(),
04682                  Phi_LL[counterIJ], Phiprime[counterIJ], Phiphi_LL[counterIJ] );
04683         }
04684 #endif
04685       }
04686     }
04687 
04688     /*
04689      * ----------- SUBSECTION FOR CALCULATION OF d2FdT2 ---------------------
04690      */
04691 #ifdef DEBUG_MODE
04692     if (m_debugCalc) {
04693       printf(" Step 7: \n");
04694     }
04695 #endif
04696     // A_Debye_Huckel = 0.5092; (units = sqrt(kg/gmol))
04697     // A_Debye_Huckel = 0.5107; <- This value is used to match GWB data
04698     //                             ( A * ln(10) = 1.17593)
04699     // Aphi = A_Debye_Huckel * 2.30258509 / 3.0;
04700     // Aphi = m_A_Debye / 3.0;
04701 
04702     //double dA_DebyedT = dA_DebyedT_TP();
04703     //double dAphidT = dA_DebyedT /3.0;
04704     double d2AphidT2 = d2A_DebyedT2_TP() / 3.0;
04705 #ifdef DEBUG_HKM
04706     //d2AphidT2 = 0.0;
04707 #endif
04708     //F = -Aphi * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
04709     //      + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
04710     //dAphidT = Al / (4.0 * GasConstant * T * T);
04711     //dFdT = -dAphidT * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
04712     //              + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
04713     d2FdT2 = -d2AphidT2 * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
04714                             + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
04715 #ifdef DEBUG_MODE
04716     if (m_debugCalc) {  
04717       printf(" initial value of d2FdT2 = %10.6f \n", d2FdT2 );          
04718     }
04719 #endif
04720     for (i = 1; i < m_kk-1; i++) {
04721       for (j = i+1; j < m_kk; j++) {
04722         /*
04723          * Find the counterIJ for the symmetric binary interaction
04724          */
04725         n = m_kk*i + j;
04726         counterIJ = m_CounterIJ[n];
04727         /*
04728          *      both species have a non-zero charge, and one is positive
04729          *  and the other is negative
04730          */
04731         if (charge[i]*charge[j] < 0) {
04732           d2FdT2 = d2FdT2 + molality[i]*molality[j] * BprimeMX_LL[counterIJ];
04733         }
04734         /*
04735          * Both species have a non-zero charge, and they
04736          * have the same sign, e.g., both positive or both negative.
04737          */
04738         if (charge[i]*charge[j] > 0) {
04739           d2FdT2 = d2FdT2 + molality[i]*molality[j] * Phiprime[counterIJ];
04740         }
04741 #ifdef DEBUG_MODE
04742         if (m_debugCalc) printf(" d2FdT2 = %10.6f \n", d2FdT2);
04743 #endif
04744       }
04745     }
04746 #ifdef DEBUG_MODE
04747     if (m_debugCalc) {
04748       printf(" Step 8: \n");
04749     }
04750 #endif
04751 
04752     for (i = 1; i < m_kk; i++) {
04753 
04754       /*
04755        * -------- SUBSECTION FOR CALCULATING THE dACTCOEFFdT FOR CATIONS -----
04756        * --
04757        */
04758       if (charge[i] > 0 ) {
04759         // species i is the cation (positive) to calc the actcoeff
04760         zsqd2FdT2 = charge[i]*charge[i]*d2FdT2;
04761         sum1 = 0.0;
04762         sum2 = 0.0;
04763         sum3 = 0.0;
04764         sum4 = 0.0;
04765         sum5 = 0.0;
04766         for (j = 1; j < m_kk; j++) {
04767           /*
04768            * Find the counterIJ for the symmetric binary interaction
04769            */
04770           n = m_kk*i + j;
04771           counterIJ = m_CounterIJ[n];
04772 
04773           if (charge[j] < 0.0) {
04774             // sum over all anions
04775             sum1 = sum1 + molality[j]*
04776               (2.0*BMX_LL[counterIJ] + molarcharge*CMX_LL[counterIJ]);
04777             if (j < m_kk-1) {
04778               /*
04779                * This term is the ternary interaction involving the 
04780                * non-duplicate sum over double anions, j, k, with
04781                * respect to the cation, i.
04782                */
04783               for (k = j+1; k < m_kk; k++) {
04784                 // an inner sum over all anions
04785                 if (charge[k] < 0.0) {
04786                   n = k + j * m_kk + i * m_kk * m_kk;
04787                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk_LL[n];
04788                 }
04789               }
04790             }
04791           }
04792 
04793              
04794           if (charge[j] > 0.0) {
04795             // sum over all cations
04796             if (j != i) {
04797               sum2 = sum2 + molality[j]*(2.0*Phi_LL[counterIJ]);
04798             }
04799             for (k = 1; k < m_kk; k++) {
04800               if (charge[k] < 0.0) {
04801                 // two inner sums over anions
04802 
04803                 n = k + j * m_kk + i * m_kk * m_kk;
04804                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk_LL[n];
04805                 /*
04806                  * Find the counterIJ for the j,k interaction
04807                  */
04808                 n = m_kk*j + k;
04809                 counterIJ2 = m_CounterIJ[n];
04810                 sum4 = sum4 + (fabs(charge[i])*
04811                                molality[j]*molality[k]*CMX_LL[counterIJ2]);
04812               }
04813             }
04814           }
04815 
04816           /*
04817            * Handle neutral j species
04818            */
04819           if (charge[j] == 0) {
04820             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj_LL(j,i);
04821             /*
04822              * Zeta interaction term
04823              */
04824             for (int k = 1; k < m_kk; k++) {
04825               if (charge[k] < 0.0) {
04826                 int izeta = j;
04827                 int jzeta = i;
04828                 n = izeta * m_kk * m_kk + jzeta * m_kk + k;
04829                 double zeta_LL = psi_ijk_LL[n];
04830                 if (zeta_LL != 0.0) {
04831                   sum5 = sum5 + molality[j]*molality[k]*zeta_LL;
04832                 }
04833               }
04834             }
04835           }
04836         }
04837         /*
04838          * Add all of the contributions up to yield the log of the
04839          * solute activity coefficients (molality scale)
04840          */
04841         m_d2lnActCoeffMolaldT2_Unscaled[i] =
04842           zsqd2FdT2 + sum1 + sum2 + sum3 + sum4 + sum5;
04843 #ifdef DEBUG_MODE
04844         if (m_debugCalc) {
04845           sni = speciesName(i);
04846           printf(" %-16s d2lngammadT2[i]=%10.6f \n", 
04847                  sni.c_str(), m_d2lnActCoeffMolaldT2_Unscaled[i]);
04848           printf("                   %12g %12g %12g %12g %12g %12g\n",
04849                  zsqd2FdT2, sum1, sum2, sum3, sum4, sum5);
04850         }
04851 #endif
04852       }
04853 
04854 
04855       /*
04856        * ------ SUBSECTION FOR CALCULATING THE d2ACTCOEFFdT2 FOR ANIONS ------
04857        *
04858        */
04859       if (charge[i] < 0 ) {
04860         //          species i is an anion (negative)
04861         zsqd2FdT2 = charge[i]*charge[i]*d2FdT2;
04862         sum1 = 0.0;
04863         sum2 = 0.0;
04864         sum3 = 0.0;
04865         sum4 = 0.0;
04866         sum5 = 0.0;
04867         for (j = 1; j < m_kk; j++) {
04868           /*
04869            * Find the counterIJ for the symmetric binary interaction
04870            */
04871           n = m_kk*i + j;
04872           counterIJ = m_CounterIJ[n];
04873 
04874           /*
04875            * For Anions, do the cation interactions.
04876            */
04877           if (charge[j] > 0) {
04878             sum1 = sum1 + molality[j]*
04879               (2.0*BMX_LL[counterIJ] + molarcharge*CMX_LL[counterIJ]);
04880             if (j < m_kk-1) {
04881               for (k = j+1; k < m_kk; k++) {
04882                 // an inner sum over all cations
04883                 if (charge[k] > 0) {
04884                   n = k + j * m_kk + i * m_kk * m_kk;
04885                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk_LL[n];
04886                 }
04887               }
04888             }
04889           }
04890 
04891           /*
04892            * For Anions, do the other anion interactions.
04893            */
04894           if (charge[j] < 0.0) {
04895             //  sum over all anions
04896             if (j != i) {
04897               sum2 = sum2 + molality[j]*(2.0*Phi_LL[counterIJ]);
04898             }
04899             for (k = 1; k < m_kk; k++) {
04900               if (charge[k] > 0.0) {
04901                 // two inner sums over cations
04902                 n = k + j * m_kk + i * m_kk * m_kk;
04903                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk_LL[n];
04904                 /*
04905                  * Find the counterIJ for the symmetric binary interaction
04906                  */
04907                 n = m_kk*j + k;
04908                 counterIJ2 = m_CounterIJ[n];
04909                 sum4 = sum4 + 
04910                   (fabs(charge[i])*
04911                    molality[j]*molality[k]*CMX_LL[counterIJ2]);
04912               }
04913             }
04914           }
04915 
04916           /*
04917            * for Anions, do the neutral species interaction
04918            */
04919           if (charge[j] == 0.0) {
04920             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj_LL(j,i);
04921             /*
04922              * Zeta interaction term
04923              */
04924             for (int k = 1; k < m_kk; k++) {
04925               if (charge[k] > 0.0) {
04926                 int izeta = j;
04927                 int jzeta = k;
04928                 int kzeta = i;
04929                 n = izeta * m_kk * m_kk + jzeta * m_kk + kzeta;
04930                 double zeta_LL = psi_ijk_LL[n];
04931                 if (zeta_LL != 0.0) {
04932                   sum5 = sum5 + molality[j]*molality[k]*zeta_LL;
04933                 }
04934               }
04935             }
04936           }
04937         }
04938         m_d2lnActCoeffMolaldT2_Unscaled[i] = 
04939           zsqd2FdT2 + sum1 + sum2 + sum3 + sum4 + sum5;
04940 #ifdef DEBUG_MODE
04941         if (m_debugCalc) {
04942           sni = speciesName(i);
04943           printf(" %-16s d2lngammadT2[i]=%10.6f\n", 
04944                  sni.c_str(), m_d2lnActCoeffMolaldT2_Unscaled[i]);
04945           printf("                   %12g %12g %12g %12g %12g %12g\n",
04946                  zsqd2FdT2, sum1, sum2, sum3, sum4, sum5);
04947         }
04948 #endif
04949       }
04950       /*
04951        * ------ SUBSECTION FOR CALCULATING NEUTRAL SOLUTE ACT COEFF -------
04952        * ------ -> equations agree with my notes,
04953        *        -> Equations agree with Pitzer,
04954        */
04955       if (charge[i] == 0.0 ) {
04956         sum1 = 0.0;
04957         sum3 = 0.0;
04958         for (j = 1; j < m_kk; j++) {
04959           sum1 = sum1 + molality[j]*2.0*m_Lambda_nj_LL(i,j);
04960           /*
04961            * Zeta term -> we piggyback on the psi term
04962            */
04963           if (charge[j] > 0.0) {
04964             for (k = 1; k < m_kk; k++) {
04965               if (charge[k] < 0.0) {
04966                 n = k + j * m_kk + i * m_kk * m_kk;
04967                 sum3 = sum3 + molality[j]*molality[k]*psi_ijk_LL[n];
04968               }
04969             }
04970           }
04971         }
04972         sum2 = 3.0 * molality[i] * molality[i] * m_Mu_nnn_LL[i];
04973         m_d2lnActCoeffMolaldT2_Unscaled[i] = sum1 + sum2 + sum3;
04974 #ifdef DEBUG_MODE
04975         if (m_debugCalc) {
04976           sni = speciesName(i);
04977           printf(" %-16s d2lngammadT2[i]=%10.6f \n", 
04978                  sni.c_str(), m_d2lnActCoeffMolaldT2_Unscaled[i]);
04979         }
04980 #endif
04981       }
04982 
04983     }
04984 #ifdef DEBUG_MODE
04985     if (m_debugCalc) {
04986       printf(" Step 9: \n");
04987     }
04988 #endif
04989 
04990     /*
04991      * ------ SUBSECTION FOR CALCULATING THE d2 OSMOTIC COEFF dT2 ---------
04992      *
04993      */
04994     sum1 = 0.0;
04995     sum2 = 0.0;
04996     sum3 = 0.0;
04997     sum4 = 0.0;
04998     sum5 = 0.0;
04999     double sum6 = 0.0;
05000     double sum7 = 0.0;
05001     /*
05002      * term1 is the temperature derivative of the
05003      * DH term in the osmotic coefficient expression
05004      * b = 1.2 sqrt(kg/gmol) <- arbitrarily set in all Pitzer 
05005      *                          implementations.
05006      * Is = Ionic strength on the molality scale (units of (gmol/kg))
05007      * Aphi = A_Debye / 3   (units of sqrt(kg/gmol))
05008      */
05009     term1 = -d2AphidT2 * Is * sqrt(Is) / (1.0 + 1.2 * sqrt(Is));
05010 
05011     for (j = 1; j < m_kk; j++) {
05012       /*
05013        * Loop Over Cations
05014        */
05015       if (charge[j] > 0.0) {
05016         for (k = 1; k < m_kk; k++){
05017           if (charge[k] < 0.0) {
05018             /*
05019              * Find the counterIJ for the symmetric j,k binary interaction
05020              */
05021             n = m_kk*j + k;
05022             counterIJ = m_CounterIJ[n];
05023         
05024             sum1 = sum1 + molality[j]*molality[k]*
05025               (BphiMX_LL[counterIJ] + molarcharge*CMX_LL[counterIJ]);
05026           }
05027         }
05028 
05029         for (k = j+1; k < m_kk; k++) {
05030           if (j == (m_kk-1)) {
05031             // we should never reach this step
05032             printf("logic error 1 in Step 9 of hmw_act");
05033             exit(EXIT_FAILURE);
05034           }
05035           if (charge[k] > 0.0) {
05036             /*
05037              * Find the counterIJ for the symmetric j,k binary interaction
05038              * between 2 cations.
05039              */
05040             n = m_kk*j + k;
05041             counterIJ = m_CounterIJ[n];
05042             sum2 = sum2 + molality[j]*molality[k]*Phiphi_LL[counterIJ];
05043             for (m = 1; m < m_kk; m++) {
05044               if (charge[m] < 0.0) {
05045                 // species m is an anion
05046                 n = m + k * m_kk + j * m_kk * m_kk;
05047                 sum2 = sum2 + 
05048                   molality[j]*molality[k]*molality[m]*psi_ijk_LL[n];
05049               }
05050             }
05051           }
05052         }
05053       }
05054           
05055       /*
05056        * Loop Over Anions
05057        */
05058       if (charge[j] < 0) {
05059         for (k = j+1; k < m_kk; k++) {
05060           if (j == m_kk-1) {
05061             // we should never reach this step
05062             printf("logic error 2 in Step 9 of hmw_act");
05063             exit(EXIT_FAILURE);
05064           }
05065           if (charge[k] < 0) {
05066             /*
05067              * Find the counterIJ for the symmetric j,k binary interaction
05068              * between two anions
05069              */
05070             n = m_kk*j + k;
05071             counterIJ = m_CounterIJ[n];
05072 
05073             sum3 = sum3 + molality[j]*molality[k]*Phiphi_LL[counterIJ];
05074             for (m = 1; m < m_kk; m++) {
05075               if (charge[m] > 0.0) {
05076                 n = m + k * m_kk + j * m_kk * m_kk;
05077                 sum3 = sum3 + 
05078                   molality[j]*molality[k]*molality[m]*psi_ijk_LL[n];
05079               }
05080             }
05081           }
05082         }
05083       }
05084           
05085       /*
05086        * Loop Over Neutral Species
05087        */
05088       if (charge[j] == 0) {
05089         for (k = 1; k < m_kk; k++) {
05090           if (charge[k] < 0.0) {
05091             sum4 = sum4 + molality[j]*molality[k]*m_Lambda_nj_LL(j,k);
05092           }
05093           if (charge[k] > 0.0) {
05094             sum5 = sum5 + molality[j]*molality[k]*m_Lambda_nj_LL(j,k);
05095           }
05096           if (charge[k] == 0.0) {
05097             if (k > j) {
05098               sum6 = sum6 + molality[j]*molality[k]*m_Lambda_nj_LL(j,k);
05099             } else if (k == j) {
05100               sum6 = sum6 + 0.5 * molality[j]*molality[k]*m_Lambda_nj_LL(j,k);
05101             }
05102           }
05103           if (charge[k] < 0.0) {
05104             int izeta = j;
05105             for (m = 1; m < m_kk; m++) {
05106               if (charge[m] > 0.0) {
05107                 int jzeta = m;
05108                 n = k + jzeta * m_kk + izeta * m_kk * m_kk;
05109                 double zeta_LL = psi_ijk_LL[n];
05110                 if (zeta_LL != 0.0) {
05111                   sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta_LL;
05112                 }
05113               }
05114             }
05115           }
05116         }
05117 
05118         sum7 += molality[j] * molality[j] * molality[j] * m_Mu_nnn_LL[j];
05119       }
05120     }
05121     sum_m_phi_minus_1 = 2.0 * 
05122       (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
05123     /*
05124      * Calculate the osmotic coefficient from 
05125      *       osmotic_coeff = 1 + dGex/d(M0noRT) / sum(molality_i)
05126      */
05127     if (molalitysum > 1.0E-150) {
05128       d2_osmotic_coef_dT2 = 0.0 + (sum_m_phi_minus_1 / molalitysum);
05129     } else {
05130       d2_osmotic_coef_dT2 = 0.0;
05131     }
05132 #ifdef DEBUG_MODE
05133     if (m_debugCalc) {
05134       printf(" term1=%10.6f sum1=%10.6f sum2=%10.6f "
05135              "sum3=%10.6f sum4=%10.6f sum5=%10.6f\n",
05136              term1, sum1, sum2, sum3, sum4, sum5);
05137       printf("     sum_m_phi_minus_1=%10.6f        d2_osmotic_coef_dT2=%10.6f\n", 
05138              sum_m_phi_minus_1, d2_osmotic_coef_dT2);
05139     }
05140 
05141     if (m_debugCalc) {
05142       printf(" Step 10: \n");
05143     }
05144 #endif
05145     d2_lnwateract_dT2 = -(m_weightSolvent/1000.0) * molalitysum * d2_osmotic_coef_dT2;
05146 
05147     /*
05148      * In Cantera, we define the activity coefficient of the solvent as
05149      *
05150      *     act_0 = actcoeff_0 * Xmol_0
05151      *
05152      * We have just computed act_0. However, this routine returns
05153      *  ln(actcoeff[]). Therefore, we must calculate ln(actcoeff_0).
05154      */
05155     m_d2lnActCoeffMolaldT2_Unscaled[0] = d2_lnwateract_dT2;
05156 
05157 #ifdef DEBUG_MODE
05158     if (m_debugCalc) {
05159       double d2_wateract_dT2 = exp(d2_lnwateract_dT2);
05160       printf(" d2_ln_a_water_dT2 = %10.6f d2_a_water_dT2=%10.6f\n\n", 
05161              d2_lnwateract_dT2, d2_wateract_dT2); 
05162     }
05163 #endif
05164   }
05165 
05166   /********************************************************************************************/
05167 
05168   /*
05169    * s_update_dlnMolalityActCoeff_dP()         (private, const )
05170    *
05171    *   Using internally stored values, this function calculates
05172    *   the pressure derivative of the logarithm of the
05173    *   activity coefficient for all species in the mechanism.
05174    *
05175    *   We assume that the activity coefficients are current.
05176    *
05177    *   solvent activity coefficient is on the molality
05178    *   scale. It's derivative is too.
05179    */
05180   void HMWSoln::s_update_dlnMolalityActCoeff_dP() const {
05181  
05182     fbo_zero_dbl_1(DATA_PTR(m_dlnActCoeffMolaldP_Unscaled), m_kk);
05183   
05184     s_updatePitzer_dlnMolalityActCoeff_dP();
05185 
05186 
05187     for (int k = 1; k < m_kk; k++) {
05188       if (CROP_speciesCropped_[k] == 2) {
05189         m_dlnActCoeffMolaldP_Unscaled[k] = 0.0;
05190       }
05191     }
05192 
05193     if (CROP_speciesCropped_[0]) {
05194       m_dlnActCoeffMolaldP_Unscaled[0] = 0.0;
05195     }
05196 
05197 
05198     s_updateScaling_pHScaling_dP();
05199   }
05200 
05201   /*
05202    * s_updatePitzer_dlnMolalityActCoeff_dP()         (private, const )
05203    *
05204    *   Using internally stored values, this function calculates
05205    *   the pressure derivative of the logarithm of the
05206    *   activity coefficient for all species in the mechanism.
05207    *   This is an internal routine
05208    *
05209    *   We assume that the activity coefficients are current.
05210    *
05211    * It may be assumed that the 
05212    * Pitzer activity coefficient and first deriv routine are called immediately
05213    * preceding the calling of this routine. Therefore, some
05214    * quantities do not need to be recalculated in this routine.
05215    *
05216    *   solvent activity coefficient is on the molality
05217    *   scale. It's derivatives are too.
05218    */
05219   void HMWSoln::s_updatePitzer_dlnMolalityActCoeff_dP() const {
05220    
05221     /*
05222      * HKM -> Assumption is made that the solvent is
05223      *        species 0.
05224      */
05225 #ifdef DEBUG_MODE
05226     m_debugCalc = 0;
05227 #endif
05228     if (m_indexSolvent != 0) {
05229       printf("Wrong index solvent value!\n");
05230       exit(EXIT_FAILURE);
05231     }
05232 
05233     double d_wateract_dP;
05234     std::string sni, snj, snk; 
05235 
05236     const double *molality  =  DATA_PTR(m_molalitiesCropped);
05237     const double *charge    =  DATA_PTR(m_speciesCharge);
05238     const double *beta0MX_P =  DATA_PTR(m_Beta0MX_ij_P);
05239     const double *beta1MX_P =  DATA_PTR(m_Beta1MX_ij_P);
05240     const double *beta2MX_P =  DATA_PTR(m_Beta2MX_ij_P);
05241     const double *CphiMX_P  =  DATA_PTR(m_CphiMX_ij_P);
05242     const double *thetaij_P =  DATA_PTR(m_Theta_ij_P);
05243     const double *alpha1MX  =  DATA_PTR(m_Alpha1MX_ij);
05244     const double *alpha2MX  =  DATA_PTR(m_Alpha2MX_ij);
05245     const double *psi_ijk_P =  DATA_PTR(m_Psi_ijk_P);
05246 
05247     /*
05248      * Local variables defined by Coltrin
05249      */
05250     double etheta[5][5], etheta_prime[5][5], sqrtIs;
05251     /*
05252      * Molality based ionic strength of the solution
05253      */
05254     double Is = 0.0;
05255     /*
05256      * Molarcharge of the solution: In Pitzer's notation, 
05257      * this is his variable called "Z".
05258      */
05259     double molarcharge = 0.0;
05260     /*
05261      * molalitysum is the sum of the molalities over all solutes,
05262      * even those with zero charge.
05263      */
05264     double molalitysum = 0.0;
05265 
05266     double *gfunc    =  DATA_PTR(m_gfunc_IJ);
05267     double *g2func   =  DATA_PTR(m_g2func_IJ);
05268     double *hfunc    =  DATA_PTR(m_hfunc_IJ);
05269     double *h2func   =  DATA_PTR(m_h2func_IJ);
05270     double *BMX_P    =  DATA_PTR(m_BMX_IJ_P);
05271     double *BprimeMX_P= DATA_PTR(m_BprimeMX_IJ_P);
05272     double *BphiMX_P =  DATA_PTR(m_BphiMX_IJ_P);
05273     double *Phi_P    =  DATA_PTR(m_Phi_IJ_P);
05274     double *Phiprime =  DATA_PTR(m_Phiprime_IJ);
05275     double *Phiphi_P =  DATA_PTR(m_PhiPhi_IJ_P);
05276     double *CMX_P    =  DATA_PTR(m_CMX_IJ_P);
05277 
05278     double x1, x2;
05279     double Aphi, dFdP, zsqdFdP;
05280     double sum1, sum2, sum3, sum4, sum5, term1;
05281     double sum_m_phi_minus_1, d_osmotic_coef_dP, d_lnwateract_dP;
05282 
05283     int z1, z2;
05284     int n, i, j, k, m, counterIJ,  counterIJ2;
05285 
05286     double currTemp = temperature();
05287     double currPres = pressure();
05288 
05289 #ifdef DEBUG_MODE
05290     if (m_debugCalc) {
05291       printf("\n Debugging information from "
05292              "s_Pitzer_dlnMolalityActCoeff_dP()\n");
05293     }
05294 #endif
05295     /*
05296      * Make sure the counter variables are setup
05297      */
05298     counterIJ_setup();
05299 
05300     /*
05301      * ---------- Calculate common sums over solutes ---------------------
05302      */
05303     for (n = 1; n < m_kk; n++) {
05304       //      ionic strength
05305       Is += charge[n] * charge[n] * molality[n];
05306       //      total molar charge
05307       molarcharge +=  fabs(charge[n]) * molality[n];
05308       molalitysum += molality[n];
05309     }
05310     Is *= 0.5;
05311 
05312     /*
05313      * Store the ionic molality in the object for reference.
05314      */
05315     m_IionicMolality = Is;
05316     sqrtIs = sqrt(Is);
05317 #ifdef DEBUG_MODE
05318     if (m_debugCalc) {
05319       printf(" Step 1: \n");
05320       printf(" ionic strenth      = %14.7le \n total molar "
05321              "charge = %14.7le \n", Is, molarcharge);
05322     }
05323 #endif
05324 
05325     /*
05326      * The following call to calc_lambdas() calculates all 16 elements
05327      * of the elambda and elambda1 arrays, given the value of the 
05328      * ionic strength (Is)
05329      */
05330     calc_lambdas(Is);
05331 
05332 
05333     /*
05334      * ----- Step 2:  Find the coefficients E-theta and -------------------
05335      *                E-thetaprime for all combinations of positive 
05336      *                unlike charges up to 4
05337      */
05338 #ifdef DEBUG_MODE
05339     if (m_debugCalc) {
05340       printf(" Step 2: \n");
05341     }
05342 #endif
05343     for (z1 = 1; z1 <=4; z1++) {
05344       for (z2 =1; z2 <=4; z2++) {
05345         calc_thetas(z1, z2, &etheta[z1][z2], &etheta_prime[z1][z2]);
05346 #ifdef DEBUG_MODE
05347         if (m_debugCalc) {
05348           printf(" z1=%3d z2=%3d E-theta(I) = %f, E-thetaprime(I) = %f\n", 
05349                  z1, z2, etheta[z1][z2], etheta_prime[z1][z2]);
05350         }
05351 #endif
05352       }
05353     }
05354 
05355 #ifdef DEBUG_MODE
05356     if (m_debugCalc) {
05357       printf(" Step 3: \n");
05358       printf(" Species          Species            g(x) "
05359              " hfunc(x)   \n");
05360     }
05361 #endif
05362    
05363     /*
05364      *
05365      *  calculate g(x) and hfunc(x) for each cation-anion pair MX
05366      *   In the original literature, hfunc, was called gprime. However,
05367      *   it's not the derivative of g(x), so I renamed it.
05368      */
05369     for (i = 1; i < (m_kk - 1); i++) {
05370       for (j = (i+1); j < m_kk; j++) {
05371         /*
05372          * Find the counterIJ for the symmetric binary interaction
05373          */
05374         n = m_kk*i + j;
05375         counterIJ = m_CounterIJ[n];
05376         /*
05377          * Only loop over oppositely charge species
05378          */
05379         if (charge[i]*charge[j] < 0) {
05380           /*
05381            * x is a reduced function variable
05382            */
05383           x1 = sqrtIs * alpha1MX[counterIJ];
05384           if (x1 > 1.0E-100) {
05385             gfunc[counterIJ] =  2.0*(1.0-(1.0 + x1) * exp(-x1)) / (x1 * x1);
05386             hfunc[counterIJ] = -2.0*
05387               (1.0-(1.0 + x1 + 0.5 * x1 * x1) * exp(-x1)) / (x1 * x1);
05388           }
05389           else {
05390             gfunc[counterIJ] = 0.0;
05391             hfunc[counterIJ] = 0.0;
05392           }
05393           
05394           if (beta2MX_P[counterIJ] != 0.0) {
05395             x2 = sqrtIs * alpha2MX[counterIJ];
05396             if (x2 > 1.0E-100) {
05397               g2func[counterIJ] =  2.0*(1.0-(1.0 + x2) * exp(-x2)) / (x2 * x2);
05398               h2func[counterIJ] = -2.0 *
05399                 (1.0-(1.0 + x2 + 0.5 * x2 * x2) * exp(-x2)) / (x2 * x2);
05400             } else {
05401               g2func[counterIJ] = 0.0;
05402               h2func[counterIJ] = 0.0;
05403             }
05404           }
05405         } 
05406         else {
05407           gfunc[counterIJ] = 0.0;
05408           hfunc[counterIJ] = 0.0;
05409         }
05410 #ifdef DEBUG_MODE
05411         if (m_debugCalc) {
05412           sni = speciesName(i);
05413           snj = speciesName(j);
05414           printf(" %-16s %-16s %9.5f %9.5f \n", sni.c_str(), snj.c_str(), 
05415                  gfunc[counterIJ], hfunc[counterIJ]);
05416         }
05417 #endif
05418       }
05419     }
05420 
05421     /*
05422      * ------- SUBSECTION TO CALCULATE BMX_P, BprimeMX_P, BphiMX_P ----------
05423      * ------- These are now temperature derivatives of the
05424      *         previously calculated quantities.
05425      */
05426 #ifdef DEBUG_MODE
05427     if (m_debugCalc) {
05428       printf(" Step 4: \n");
05429       printf(" Species          Species            BMX    "
05430              "BprimeMX    BphiMX   \n");
05431     }
05432 #endif
05433 
05434     for (i = 1; i < m_kk - 1; i++) {
05435       for (j = i+1; j < m_kk; j++) {
05436         /*
05437          * Find the counterIJ for the symmetric binary interaction
05438          */
05439         n = m_kk*i + j;
05440         counterIJ = m_CounterIJ[n];
05441         /*
05442          *      both species have a non-zero charge, and one is positive
05443          *  and the other is negative
05444          */
05445         if (charge[i]*charge[j] < 0.0) {        
05446           BMX_P[counterIJ]  = beta0MX_P[counterIJ]
05447             + beta1MX_P[counterIJ] * gfunc[counterIJ]
05448             + beta2MX_P[counterIJ] * g2func[counterIJ];
05449 #ifdef DEBUG_MODE
05450           if (m_debugCalc) {
05451             printf("%d %g: %g %g %g %g\n",
05452                    counterIJ,  BMX_P[counterIJ], beta0MX_P[counterIJ],
05453                    beta1MX_P[counterIJ], beta2MX_P[counterIJ], gfunc[counterIJ]);
05454           }
05455 #endif
05456           if (Is > 1.0E-150) {
05457             BprimeMX_P[counterIJ] = (beta1MX_P[counterIJ] * hfunc[counterIJ]/Is +
05458                                      beta2MX_P[counterIJ] * h2func[counterIJ]/Is);
05459           } else {
05460             BprimeMX_P[counterIJ] = 0.0;
05461           }
05462           BphiMX_P[counterIJ] = BMX_P[counterIJ] + Is*BprimeMX_P[counterIJ];
05463         } 
05464         else {
05465           BMX_P[counterIJ]      = 0.0;
05466           BprimeMX_P[counterIJ] = 0.0;
05467           BphiMX_P[counterIJ]     = 0.0;
05468         }
05469 #ifdef DEBUG_MODE
05470         if (m_debugCalc) {
05471           sni = speciesName(i);
05472           snj = speciesName(j);
05473           printf(" %-16s %-16s %11.7f %11.7f %11.7f \n", 
05474                  sni.c_str(), snj.c_str(), 
05475                  BMX_P[counterIJ], BprimeMX_P[counterIJ], BphiMX_P[counterIJ]);
05476         }
05477 #endif
05478       }
05479     }
05480 
05481     /*
05482      * --------- SUBSECTION TO CALCULATE CMX_P ----------
05483      * ---------
05484      */
05485 #ifdef DEBUG_MODE
05486     if (m_debugCalc) {
05487       printf(" Step 5: \n");
05488       printf(" Species          Species            CMX \n");
05489     }
05490 #endif
05491     for (i = 1; i < m_kk-1; i++) {
05492       for (j = i+1; j < m_kk; j++) {
05493         /*
05494          * Find the counterIJ for the symmetric binary interaction
05495          */
05496         n = m_kk*i + j;
05497         counterIJ = m_CounterIJ[n];
05498         /*
05499          *      both species have a non-zero charge, and one is positive
05500          *  and the other is negative
05501          */
05502         if (charge[i]*charge[j] < 0.0) {
05503           CMX_P[counterIJ] = CphiMX_P[counterIJ]/ 
05504             (2.0* sqrt(fabs(charge[i]*charge[j])));
05505         } 
05506         else {
05507           CMX_P[counterIJ] = 0.0;
05508         }
05509 #ifdef DEBUG_MODE
05510         if (m_debugCalc) {
05511           sni = speciesName(i);
05512           snj = speciesName(j);
05513           printf(" %-16s %-16s %11.7f \n", sni.c_str(), snj.c_str(),
05514                  CMX_P[counterIJ]);
05515         }
05516 #endif
05517       }
05518     }
05519 
05520     /*
05521      * ------- SUBSECTION TO CALCULATE Phi, PhiPrime, and PhiPhi ----------
05522      * --------
05523      */
05524 #ifdef DEBUG_MODE
05525     if (m_debugCalc) {
05526       printf(" Step 6: \n");
05527       printf(" Species          Species            Phi_ij "
05528              " Phiprime_ij  Phi^phi_ij \n");
05529     }
05530 #endif
05531     for (i = 1; i < m_kk-1; i++) {
05532       for (j = i+1; j < m_kk; j++) {
05533         /*
05534          * Find the counterIJ for the symmetric binary interaction
05535          */
05536         n = m_kk*i + j;
05537         counterIJ = m_CounterIJ[n];
05538         /*
05539          *      both species have a non-zero charge, and one is positive
05540          *  and the other is negative
05541          */
05542         if (charge[i]*charge[j] > 0) {
05543           z1 = (int) fabs(charge[i]);
05544           z2 = (int) fabs(charge[j]);
05545           //Phi[counterIJ] = thetaij_L[counterIJ] + etheta[z1][z2];
05546           Phi_P[counterIJ] = thetaij_P[counterIJ];
05547           //Phiprime[counterIJ] = etheta_prime[z1][z2];
05548           Phiprime[counterIJ] = 0.0;
05549           Phiphi_P[counterIJ] = Phi_P[counterIJ] + Is * Phiprime[counterIJ];
05550         } 
05551         else {
05552           Phi_P[counterIJ]      = 0.0;
05553           Phiprime[counterIJ] = 0.0;
05554           Phiphi_P[counterIJ]   = 0.0;
05555         }
05556 #ifdef DEBUG_MODE
05557         if (m_debugCalc) {
05558           sni = speciesName(i);
05559           snj = speciesName(j);
05560           printf(" %-16s %-16s %10.6f %10.6f %10.6f \n", 
05561                  sni.c_str(), snj.c_str(),
05562                  Phi_P[counterIJ], Phiprime[counterIJ], Phiphi_P[counterIJ] );
05563         }
05564 #endif
05565       }
05566     }
05567 
05568     /*
05569      * ----------- SUBSECTION FOR CALCULATION OF dFdT ---------------------
05570      */
05571 #ifdef DEBUG_MODE
05572     if (m_debugCalc) {
05573       printf(" Step 7: \n");
05574     }
05575 #endif
05576     // A_Debye_Huckel = 0.5092; (units = sqrt(kg/gmol))
05577     // A_Debye_Huckel = 0.5107; <- This value is used to match GWB data
05578     //                             ( A * ln(10) = 1.17593)
05579     // Aphi = A_Debye_Huckel * 2.30258509 / 3.0;
05580     Aphi = m_A_Debye / 3.0;
05581 
05582     double dA_DebyedP = dA_DebyedP_TP(currTemp, currPres);
05583     double dAphidP = dA_DebyedP /3.0;
05584 #ifdef DEBUG_MODE
05585     //dAphidT = 0.0;
05586 #endif
05587     //F = -Aphi * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
05588     //      + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
05589     //dAphidT = Al / (4.0 * GasConstant * T * T);
05590     dFdP = -dAphidP * ( sqrt(Is) / (1.0 + 1.2*sqrt(Is)) 
05591                         + (2.0/1.2) * log(1.0+1.2*(sqrtIs)));
05592 #ifdef DEBUG_MODE
05593     if (m_debugCalc) {
05594       printf(" initial value of dFdP = %10.6f \n", dFdP );              
05595     }
05596 #endif
05597     for (i = 1; i < m_kk-1; i++) {
05598       for (j = i+1; j < m_kk; j++) {
05599         /*
05600          * Find the counterIJ for the symmetric binary interaction
05601          */
05602         n = m_kk*i + j;
05603         counterIJ = m_CounterIJ[n];
05604         /*
05605          *      both species have a non-zero charge, and one is positive
05606          *  and the other is negative
05607          */
05608         if (charge[i]*charge[j] < 0) {
05609           dFdP = dFdP + molality[i]*molality[j] * BprimeMX_P[counterIJ];
05610         }
05611         /*
05612          * Both species have a non-zero charge, and they
05613          * have the same sign, e.g., both positive or both negative.
05614          */
05615         if (charge[i]*charge[j] > 0) {
05616           dFdP = dFdP + molality[i]*molality[j] * Phiprime[counterIJ];
05617         }
05618 #ifdef DEBUG_MODE
05619         if (m_debugCalc) printf(" dFdP = %10.6f \n", dFdP);
05620 #endif
05621       }
05622     }
05623 #ifdef DEBUG_MODE
05624     if (m_debugCalc) {
05625       printf(" Step 8: \n");
05626     }
05627 #endif
05628 
05629 
05630     for (i = 1; i < m_kk; i++) {
05631 
05632       /*
05633        * -------- SUBSECTION FOR CALCULATING THE dACTCOEFFdP FOR CATIONS -----
05634        * --
05635        */
05636       if (charge[i] > 0 ) {
05637         // species i is the cation (positive) to calc the actcoeff
05638         zsqdFdP = charge[i]*charge[i]*dFdP;
05639         sum1 = 0.0;
05640         sum2 = 0.0;
05641         sum3 = 0.0;
05642         sum4 = 0.0;
05643         sum5 = 0.0;
05644         for (j = 1; j < m_kk; j++) {
05645           /*
05646            * Find the counterIJ for the symmetric binary interaction
05647            */
05648           n = m_kk*i + j;
05649           counterIJ = m_CounterIJ[n];
05650 
05651           if (charge[j] < 0.0) {
05652             // sum over all anions
05653             sum1 = sum1 + molality[j]*
05654               (2.0*BMX_P[counterIJ] + molarcharge*CMX_P[counterIJ]);
05655             if (j < m_kk-1) {
05656               /*
05657                * This term is the ternary interaction involving the 
05658                * non-duplicate sum over double anions, j, k, with
05659                * respect to the cation, i.
05660                */
05661               for (k = j+1; k < m_kk; k++) {
05662                 // an inner sum over all anions
05663                 if (charge[k] < 0.0) {
05664                   n = k + j * m_kk + i * m_kk * m_kk;
05665                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk_P[n];
05666                 }
05667               }
05668             }
05669           }
05670 
05671              
05672           if (charge[j] > 0.0) {
05673             // sum over all cations
05674             if (j != i) {
05675               sum2 = sum2 + molality[j]*(2.0*Phi_P[counterIJ]);
05676             }
05677             for (k = 1; k < m_kk; k++) {
05678               if (charge[k] < 0.0) {
05679                 // two inner sums over anions
05680 
05681                 n = k + j * m_kk + i * m_kk * m_kk;
05682                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk_P[n];
05683                 /*
05684                  * Find the counterIJ for the j,k interaction
05685                  */
05686                 n = m_kk*j + k;
05687                 counterIJ2 = m_CounterIJ[n];
05688                 sum4 = sum4 + (fabs(charge[i])*
05689                                molality[j]*molality[k]*CMX_P[counterIJ2]);
05690               }
05691             }
05692           }
05693 
05694           /*
05695            * for Anions, do the neutral species interaction
05696            */
05697           if (charge[j] == 0) {
05698             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj_P(j,i);
05699             /*
05700              * Zeta interaction term
05701              */
05702             for (int k = 1; k < m_kk; k++) {
05703               if (charge[k] < 0.0) {
05704                 int izeta = j;
05705                 int jzeta = i;
05706                 n = izeta * m_kk * m_kk + jzeta * m_kk + k;
05707                 double zeta_P = psi_ijk_P[n];
05708                 if (zeta_P != 0.0) {
05709                   sum5 = sum5 + molality[j]*molality[k]*zeta_P;
05710                 }
05711               }
05712             }
05713           }
05714         }
05715 
05716         /*
05717          * Add all of the contributions up to yield the log of the
05718          * solute activity coefficients (molality scale)
05719          */
05720         m_dlnActCoeffMolaldP_Unscaled[i] =
05721           zsqdFdP + sum1 + sum2 + sum3 + sum4 + sum5;
05722 
05723 #ifdef DEBUG_MODE
05724         if (m_debugCalc) {
05725           sni = speciesName(i);
05726           printf(" %-16s lngamma[i]=%10.6f \n", 
05727                  sni.c_str(), m_dlnActCoeffMolaldP_Unscaled[i]);
05728           printf("                   %12g %12g %12g %12g %12g %12g\n",
05729                  zsqdFdP, sum1, sum2, sum3, sum4, sum5);
05730         }
05731 #endif
05732       }
05733 
05734 
05735       /*
05736        * ------ SUBSECTION FOR CALCULATING THE dACTCOEFFdP FOR ANIONS ------
05737        *
05738        */
05739       if (charge[i] < 0) {
05740         //          species i is an anion (negative)
05741         zsqdFdP = charge[i]*charge[i]*dFdP;
05742         sum1 = 0.0;
05743         sum2 = 0.0;
05744         sum3 = 0.0;
05745         sum4 = 0.0;
05746         sum5 = 0.0;
05747         for (j = 1; j < m_kk; j++) {
05748           /*
05749            * Find the counterIJ for the symmetric binary interaction
05750            */
05751           n = m_kk*i + j;
05752           counterIJ = m_CounterIJ[n];
05753 
05754           /*
05755            * For Anions, do the cation interactions.
05756            */
05757           if (charge[j] > 0) {
05758             sum1 = sum1 + molality[j]*
05759               (2.0*BMX_P[counterIJ] + molarcharge*CMX_P[counterIJ]);
05760             if (j < m_kk-1) {
05761               for (k = j+1; k < m_kk; k++) {
05762                 // an inner sum over all cations
05763                 if (charge[k] > 0) {
05764                   n = k + j * m_kk + i * m_kk * m_kk;
05765                   sum3 = sum3 + molality[j]*molality[k]*psi_ijk_P[n];
05766                 }
05767               }
05768             }
05769           }
05770 
05771           /*
05772            * For Anions, do the other anion interactions.
05773            */
05774           if (charge[j] < 0.0) {
05775             //  sum over all anions
05776             if (j != i) {
05777               sum2 = sum2 + molality[j]*(2.0*Phi_P[counterIJ]);
05778             }
05779             for (k = 1; k < m_kk; k++) {
05780               if (charge[k] > 0.0) {
05781                 // two inner sums over cations
05782                 n = k + j * m_kk + i * m_kk * m_kk;
05783                 sum2 = sum2 + molality[j]*molality[k]*psi_ijk_P[n];
05784                 /*
05785                  * Find the counterIJ for the symmetric binary interaction
05786                  */
05787                 n = m_kk*j + k;
05788                 counterIJ2 = m_CounterIJ[n];
05789                 sum4 = sum4 + 
05790                   (fabs(charge[i])*
05791                    molality[j]*molality[k]*CMX_P[counterIJ2]);
05792               }
05793             }
05794           }
05795 
05796           /*
05797            * for Anions, do the neutral species interaction
05798            */
05799           if (charge[j] == 0.0) {
05800             sum5 = sum5 + molality[j]*2.0*m_Lambda_nj_P(j,i);
05801             /*
05802              * Zeta interaction term
05803              */
05804             for (int k = 1; k < m_kk; k++) {
05805               if (charge[k] > 0.0) {
05806                 int izeta = j;
05807                 int jzeta = k;
05808                 int kzeta = i;
05809                 n = izeta * m_kk * m_kk + jzeta * m_kk + kzeta;
05810                 double zeta_P = psi_ijk_P[n];
05811                 if (zeta_P != 0.0) {
05812                   sum5 = sum5 + molality[j]*molality[k]*zeta_P;
05813                 }
05814               }
05815             }
05816           }
05817         }
05818         m_dlnActCoeffMolaldP_Unscaled[i] = 
05819           zsqdFdP + sum1 + sum2 + sum3 + sum4 + sum5;
05820 #ifdef DEBUG_MODE
05821         if (m_debugCalc) {
05822           sni = speciesName(i);
05823           printf(" %-16s lndactcoeffmolaldP[i]=%10.6f \n", 
05824                  sni.c_str(), m_dlnActCoeffMolaldP_Unscaled[i]);
05825           printf("                   %12g %12g %12g %12g %12g %12g\n",
05826                  zsqdFdP, sum1, sum2, sum3, sum4, sum5);
05827         }
05828 #endif
05829       }
05830 
05831       /*
05832        * ------ SUBSECTION FOR CALCULATING d NEUTRAL SOLUTE ACT COEFF dP -------
05833        */
05834       if (charge[i] == 0.0) {
05835         sum1 = 0.0;
05836         sum3 = 0.0;
05837         for (j = 1; j < m_kk; j++) {
05838           sum1 +=  molality[j]*2.0*m_Lambda_nj_P(i,j);
05839           /*
05840            * Zeta term -> we piggyback on the psi term
05841            */
05842           if (charge[j] > 0.0) {
05843             for (k = 1; k < m_kk; k++) {
05844               if (charge[k] < 0.0) {
05845                 n = k + j * m_kk + i * m_kk * m_kk;
05846                 sum3 = sum3 + molality[j]*molality[k]*psi_ijk_P[n];
05847               }
05848             }
05849           }
05850         }
05851         sum2 = 3.0 * molality[i] * molality[i] * m_Mu_nnn_P[i];
05852         m_dlnActCoeffMolaldP_Unscaled[i] = sum1 + sum2 + sum3;
05853 #ifdef DEBUG_MODE
05854         if (m_debugCalc) {
05855           sni = speciesName(i);
05856           printf(" %-16s dlnActCoeffMolaldP[i]=%10.6f \n", 
05857                  sni.c_str(), m_dlnActCoeffMolaldP_Unscaled[i]);
05858         }
05859 #endif
05860       }
05861 
05862     }
05863 #ifdef DEBUG_MODE
05864     if (m_debugCalc) {
05865       printf(" Step 9: \n");
05866     }
05867 #endif
05868 
05869     /*
05870      * ------ SUBSECTION FOR CALCULATING THE d OSMOTIC COEFF dP ---------
05871      *
05872      */
05873     sum1 = 0.0;
05874     sum2 = 0.0;
05875     sum3 = 0.0;
05876     sum4 = 0.0;
05877     sum5 = 0.0;
05878     double sum6 = 0.0;
05879     double sum7 = 0.0;
05880     /*
05881      * term1 is the temperature derivative of the
05882      * DH term in the osmotic coefficient expression
05883      * b = 1.2 sqrt(kg/gmol) <- arbitrarily set in all Pitzer 
05884      *                          implementations.
05885      * Is = Ionic strength on the molality scale (units of (gmol/kg))
05886      * Aphi = A_Debye / 3   (units of sqrt(kg/gmol))
05887      */
05888     term1 = -dAphidP * Is * sqrt(Is) / (1.0 + 1.2 * sqrt(Is));
05889 
05890     for (j = 1; j < m_kk; j++) {
05891       /*
05892        * Loop Over Cations
05893        */
05894       if (charge[j] > 0.0) {
05895         for (k = 1; k < m_kk; k++){
05896           if (charge[k] < 0.0) {
05897             /*
05898              * Find the counterIJ for the symmetric j,k binary interaction
05899              */
05900             n = m_kk*j + k;
05901             counterIJ = m_CounterIJ[n];
05902         
05903             sum1 = sum1 + molality[j]*molality[k]*
05904               (BphiMX_P[counterIJ] + molarcharge*CMX_P[counterIJ]);
05905           }
05906         }
05907 
05908         for (k = j+1; k < m_kk; k++) {
05909           if (j == (m_kk-1)) {
05910             // we should never reach this step
05911             printf("logic error 1 in Step 9 of hmw_act");
05912             exit(EXIT_FAILURE);
05913           }
05914           if (charge[k] > 0.0) {
05915             /*
05916              * Find the counterIJ for the symmetric j,k binary interaction
05917              * between 2 cations.
05918              */
05919             n = m_kk*j + k;
05920             counterIJ = m_CounterIJ[n];
05921             sum2 = sum2 + molality[j]*molality[k]*Phiphi_P[counterIJ];
05922             for (m = 1; m < m_kk; m++) {
05923               if (charge[m] < 0.0) {
05924                 // species m is an anion
05925                 n = m + k * m_kk + j * m_kk * m_kk;
05926                 sum2 = sum2 + 
05927                   molality[j]*molality[k]*molality[m]*psi_ijk_P[n];
05928               }
05929             }
05930           }
05931         }
05932       }
05933          
05934       
05935       /*
05936        * Loop Over Anions
05937        */
05938       if (charge[j] < 0) {
05939         for (k = j+1; k < m_kk; k++) {
05940           if (j == m_kk-1) {
05941             // we should never reach this step
05942             printf("logic error 2 in Step 9 of hmw_act");
05943             exit(EXIT_FAILURE);
05944           }
05945           if (charge[k] < 0) {
05946             /*
05947              * Find the counterIJ for the symmetric j,k binary interaction
05948              * between two anions
05949              */
05950             n = m_kk*j + k;
05951             counterIJ = m_CounterIJ[n];
05952 
05953             sum3 = sum3 + molality[j]*molality[k]*Phiphi_P[counterIJ];
05954             for (m = 1; m < m_kk; m++) {
05955               if (charge[m] > 0.0) {
05956                 n = m + k * m_kk + j * m_kk * m_kk;
05957                 sum3 = sum3 + 
05958                   molality[j]*molality[k]*molality[m]*psi_ijk_P[n];
05959               }
05960             }
05961           }
05962         }
05963       }
05964           
05965       /*
05966        * Loop Over Neutral Species
05967        */
05968       if (charge[j] == 0) {
05969         for (k = 1; k < m_kk; k++) {
05970           if (charge[k] < 0.0) {
05971             sum4 = sum4 + molality[j]*molality[k]*m_Lambda_nj_P(j,k);
05972           }
05973           if (charge[k] > 0.0) {
05974             sum5 = sum5 + molality[j]*molality[k]*m_Lambda_nj_P(j,k);
05975           }
05976           if (charge[k] == 0.0) {
05977             if (k > j) {
05978               sum6 = sum6 + molality[j]*molality[k]*m_Lambda_nj_P(j,k);
05979             } else if (k == j) {
05980               sum6 = sum6 + 0.5 * molality[j]*molality[k]*m_Lambda_nj_P(j,k);
05981             }
05982           }
05983           if (charge[k] < 0.0) {
05984             int izeta = j;
05985             for (m = 1; m < m_kk; m++) {
05986               if (charge[m] > 0.0) {
05987                 int jzeta = m;
05988                 n = k + jzeta * m_kk + izeta * m_kk * m_kk;
05989                 double zeta_P = psi_ijk_P[n];
05990                 if (zeta_P != 0.0) {
05991                   sum7 += molality[izeta]*molality[jzeta]*molality[k]*zeta_P;
05992                 }
05993               }
05994             }
05995           }
05996         }
05997 
05998         sum7 += molality[j] * molality[j] * molality[j] * m_Mu_nnn_P[j];
05999       }
06000     }
06001     sum_m_phi_minus_1 = 2.0 * 
06002       (term1 + sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7);
06003 
06004     /*
06005      * Calculate the osmotic coefficient from 
06006      *       osmotic_coeff = 1 + dGex/d(M0noRT) / sum(molality_i)
06007      */
06008     if (molalitysum > 1.0E-150) {
06009       d_osmotic_coef_dP = 0.0 + (sum_m_phi_minus_1 / molalitysum);
06010     } else {
06011       d_osmotic_coef_dP = 0.0;
06012     }
06013 #ifdef DEBUG_MODE
06014     if (m_debugCalc) {
06015       printf(" term1=%10.6f sum1=%10.6f sum2=%10.6f "
06016              "sum3=%10.6f sum4=%10.6f sum5=%10.6f\n",
06017              term1, sum1, sum2, sum3, sum4, sum5);
06018       printf("     sum_m_phi_minus_1=%10.6f        d_osmotic_coef_dP =%10.6f\n", 
06019              sum_m_phi_minus_1, d_osmotic_coef_dP);
06020     }
06021 
06022     if (m_debugCalc) {
06023       printf(" Step 10: \n");
06024     }
06025 #endif
06026     d_lnwateract_dP = -(m_weightSolvent/1000.0) * molalitysum * d_osmotic_coef_dP;
06027     d_wateract_dP = exp(d_lnwateract_dP);
06028 
06029     /*
06030      * In Cantera, we define the activity coefficient of the solvent as
06031      *
06032      *     act_0 = actcoeff_0 * Xmol_0
06033      *
06034      * We have just computed act_0. However, this routine returns
06035      *  ln(actcoeff[]). Therefore, we must calculate ln(actcoeff_0).
06036      */
06037     //double xmolSolvent = moleFraction(m_indexSolvent);
06038     m_dlnActCoeffMolaldP_Unscaled[0] = d_lnwateract_dP;
06039 #ifdef DEBUG_MODE
06040     if (m_debugCalc) {
06041       printf(" d_ln_a_water_dP = %10.6f d_a_water_dP=%10.6f\n\n", 
06042              d_lnwateract_dP, d_wateract_dP); 
06043     }
06044 #endif
06045 
06046   }
06047 
06048   /**********************************************************************************************/
06049 
06050   /*
06051    * Calculate the lambda interactions. 
06052    *
06053    * Calculate E-lambda terms for charge combinations of like sign,
06054    *   using method of Pitzer (1975).
06055    *
06056    *  This code snipet is included from Bethke, Appendix 2.
06057    */
06058   void HMWSoln::calc_lambdas(double is) const {
06059     double aphi, dj, jfunc, jprime, t, x, zprod;
06060     int i, ij, j;
06061     /*
06062      * Coefficients c1-c4 are used to approximate 
06063      * the integral function "J";
06064      * aphi is the Debye-Huckel constant at 25 C
06065      */
06066 
06067     double c1 = 4.581, c2 = 0.7237, c3 = 0.0120, c4 = 0.528;
06068 
06069     aphi = 0.392;   /* Value at 25 C */
06070 #ifdef DEBUG_MODE
06071     if (m_debugCalc) {
06072       printf(" Is = %g\n", is);
06073     }
06074 #endif
06075     if (is < 1.0E-150) {
06076       for (i = 0; i < 17; i++) {
06077         elambda[i] = 0.0;
06078         elambda1[i] = 0.0;
06079       }
06080       return;
06081     }
06082     /*
06083      * Calculate E-lambda terms for charge combinations of like sign,
06084      * using method of Pitzer (1975). Charges up to 4 are calculated.
06085      */
06086 
06087     for (i=1; i<=4; i++) {
06088       for (j=i; j<=4; j++) {
06089         ij = i*j;
06090         /*
06091          * calculate the product of the charges
06092          */
06093         zprod = (double)ij;
06094         /*
06095          * calculate Xmn (A1) from Harvie, Weare (1980).
06096          */
06097         x = 6.0* zprod * aphi * sqrt(is);                      /* eqn 23 */
06098             
06099         jfunc = x / (4.0 + c1*pow(x,-c2)*exp(-c3*pow(x,c4)));  /* eqn 47 */
06100 
06101         t = c3 * c4 * pow(x,c4);
06102         dj = c1* pow(x,(-c2-1.0)) * (c2+t) * exp(-c3*pow(x,c4));
06103         jprime = (jfunc/x)*(1.0 + jfunc*dj);
06104 
06105         elambda[ij] = zprod*jfunc / (4.0*is);                  /* eqn 14 */
06106         elambda1[ij] = (3.0*zprod*zprod*aphi*jprime/(4.0*sqrt(is))
06107                         - elambda[ij])/is;
06108 #ifdef DEBUG_MODE
06109         if (m_debugCalc) {
06110           printf(" ij = %d, elambda = %g, elambda1 = %g\n",
06111                  ij, elambda[ij], elambda1[ij]);
06112         }
06113 #endif
06114       }
06115     }
06116   }
06117 
06118   /*
06119    * Calculate the etheta interaction. 
06120    * This interaction accounts for the mixing effects of like-signed
06121    * ions with different charges. There is fairly extensive literature
06122    * on this effect. See the notes.
06123    * This interaction will be nonzero for species with the same charge.
06124    *
06125    *  This code snipet is included from Bethke, Appendix 2.
06126    */
06127   void HMWSoln::calc_thetas(int z1, int z2,
06128                             double *etheta, double *etheta_prime) const {
06129     int i, j;
06130     double f1, f2;
06131         
06132     /*
06133      * Calculate E-theta(i) and E-theta'(I) using method of
06134      * Pitzer (1987) 
06135      */
06136     i = abs(z1);
06137     j = abs(z2);
06138 
06139 #ifdef DEBUG_MODE
06140     if (i > 4 || j > 4) {
06141       printf("we shouldn't be here\n");
06142       exit(EXIT_FAILURE);
06143     }
06144 #endif
06145 
06146     if ((i == 0) || (j == 0)) {
06147       printf("ERROR calc_thetas called with one species being neutral\n");
06148       exit(EXIT_FAILURE);
06149     }
06150 
06151     /*
06152      *  Check to see if the charges are of opposite sign. If they are of 
06153      *  opposite sign then their etheta interaction is zero.
06154      */
06155     if (z1*z2 < 0) {
06156       *etheta = 0.0;
06157       *etheta_prime = 0.0;
06158     }
06159     /*
06160      * Actually calculate the interaction.
06161      */
06162     else {
06163       f1 = (double)i / (2.0  * j);
06164       f2 = (double)j / (2.0  * i);
06165       *etheta = elambda[i*j] - f1*elambda[j*j] - f2*elambda[i*i];
06166       *etheta_prime = elambda1[i*j] - f1*elambda1[j*j] - f2*elambda1[i*i];
06167     }
06168   }
06169 
06170   // This function will be called to update the internally storred
06171   // natural logarithm of the molality activity coefficients
06172   /*
06173    * Normally they are all one. However, sometimes they are not,
06174    * due to stability schemes
06175    *
06176    *    gamma_k_molar =  gamma_k_molal / Xmol_solvent
06177    *
06178    *    gamma_o_molar = gamma_o_molal
06179    */
06180   void  HMWSoln::s_updateIMS_lnMolalityActCoeff() const {
06181     int k;
06182     double tmp;
06183     /*
06184      * Calculate the molalities. Currently, the molalities
06185      * may not be current with respect to the contents of the
06186      * State objects' data.
06187      */
06188     calcMolalities();
06189 
06190     double xmolSolvent = moleFraction(m_indexSolvent);
06191     double xx = MAX(m_xmolSolventMIN, xmolSolvent);
06192     if (IMS_typeCutoff_ == 0) {
06193       for (k = 1; k < m_kk; k++) {
06194         IMS_lnActCoeffMolal_[k]= 0.0;
06195       }
06196       IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
06197       return;
06198     } else if (IMS_typeCutoff_ == 1) {
06199       if (xmolSolvent > 3.0 * IMS_X_o_cutoff_/2.0 ) {
06200         for (k = 1; k < m_kk; k++) {
06201           IMS_lnActCoeffMolal_[k]= 0.0;
06202         }
06203         IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
06204         return;
06205       } else if (xmolSolvent < IMS_X_o_cutoff_/2.0) {
06206         tmp = log(xx * IMS_gamma_k_min_);
06207         for (k = 1; k < m_kk; k++) {
06208           IMS_lnActCoeffMolal_[k]= tmp;
06209         }
06210         IMS_lnActCoeffMolal_[m_indexSolvent] = log(IMS_gamma_o_min_);
06211         return;
06212       } else {
06213         /*
06214          * If we are in the middle region, calculate the connecting polynomials
06215          */
06216         double xminus  = xmolSolvent - IMS_X_o_cutoff_/2.0;
06217         double xminus2 = xminus * xminus;
06218         double xminus3 = xminus2 * xminus;
06219         double x_o_cut2 = IMS_X_o_cutoff_ * IMS_X_o_cutoff_;
06220         double x_o_cut3 =  x_o_cut2 * IMS_X_o_cutoff_;
06221 
06222         double h2 = 3.5 * xminus2 /  IMS_X_o_cutoff_ - 2.0 * xminus3 / x_o_cut2;
06223         double h2_prime = 7.0 * xminus /  IMS_X_o_cutoff_ - 6.0 * xminus2 /  x_o_cut2;
06224 
06225         double h1 =   (1.0 - 3.0 * xminus2 /  x_o_cut2 + 2.0 *  xminus3/ x_o_cut3);
06226         double h1_prime = (- 6.0 * xminus /  x_o_cut2 + 6.0 *  xminus2/ x_o_cut3);
06227 
06228         double h1_g = h1 / IMS_gamma_o_min_;
06229         double h1_g_prime  = h1_prime / IMS_gamma_o_min_;
06230 
06231         double alpha = 1.0 / ( exp(1.0) * IMS_gamma_k_min_);
06232         double h1_f = h1 * alpha;
06233         double h1_f_prime  = h1_prime * alpha;
06234 
06235         double f = h2 + h1_f;
06236         double f_prime = h2_prime + h1_f_prime;
06237 
06238         double g = h2 + h1_g;
06239         double g_prime = h2_prime + h1_g_prime;
06240 
06241         tmp = (xmolSolvent/ g * g_prime + (1.0-xmolSolvent) / f * f_prime);
06242         double lngammak = -1.0 - log(f) + tmp * xmolSolvent;
06243         double lngammao =-log(g) - tmp * (1.0-xmolSolvent);
06244 
06245         tmp = log(xmolSolvent) + lngammak;
06246         for (k = 1; k < m_kk; k++) {
06247           IMS_lnActCoeffMolal_[k]= tmp;
06248         }
06249         IMS_lnActCoeffMolal_[m_indexSolvent] = lngammao;
06250       }
06251     }
06252     // Exponentials - trial 2
06253     else if (IMS_typeCutoff_ == 2) {
06254       if (xmolSolvent > IMS_X_o_cutoff_) {
06255         for (k = 1; k < m_kk; k++) {
06256           IMS_lnActCoeffMolal_[k]= 0.0;
06257         }
06258         IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
06259         return;
06260       } else {
06261 
06262         double xoverc = xmolSolvent/IMS_cCut_;
06263         double eterm = std::exp(-xoverc);
06264 
06265         double fptmp = IMS_bfCut_  - IMS_afCut_ / IMS_cCut_ - IMS_bfCut_*xoverc
06266           + 2.0*IMS_dfCut_*xmolSolvent - IMS_dfCut_*xmolSolvent*xoverc;
06267         double f_prime = 1.0 + eterm*fptmp;
06268         double f = xmolSolvent + IMS_efCut_ 
06269           + eterm * (IMS_afCut_ + xmolSolvent * (IMS_bfCut_ + IMS_dfCut_*xmolSolvent));
06270 
06271         double gptmp = IMS_bgCut_  - IMS_agCut_ / IMS_cCut_ - IMS_bgCut_*xoverc
06272           + 2.0*IMS_dgCut_*xmolSolvent - IMS_dgCut_*xmolSolvent*xoverc;
06273         double g_prime = 1.0 + eterm*gptmp;
06274         double g = xmolSolvent + IMS_egCut_ 
06275           + eterm * (IMS_agCut_ + xmolSolvent * (IMS_bgCut_ + IMS_dgCut_*xmolSolvent));
06276 
06277         tmp = (xmolSolvent / g * g_prime + (1.0 - xmolSolvent) / f * f_prime);
06278         double lngammak = -1.0 - log(f) + tmp * xmolSolvent;
06279         double lngammao =-log(g) - tmp * (1.0-xmolSolvent);
06280 
06281         tmp = log(xx) + lngammak;
06282         for (k = 1; k < m_kk; k++) {
06283           IMS_lnActCoeffMolal_[k]= tmp;
06284         }
06285         IMS_lnActCoeffMolal_[m_indexSolvent] = lngammao;
06286       }
06287     }
06288     return;
06289   }
06290 
06291     
06292   /**
06293    * This routine prints out the input pitzer coefficients for the 
06294    * current mechanism
06295    */
06296   void HMWSoln::printCoeffs() const {
06297     int i, j, k;
06298     std::string sni, snj;
06299     calcMolalities();
06300     const double *charge = DATA_PTR(m_speciesCharge);
06301     double *molality = DATA_PTR(m_molalitiesCropped);
06302     double *moleF = DATA_PTR(m_tmpV);
06303     /*
06304      * Update the coefficients wrt Temperature
06305      * Calculate the derivatives as well
06306      */
06307     s_updatePitzer_CoeffWRTemp(2);
06308     getMoleFractions(moleF);
06309 
06310     printf("Index  Name                  MoleF   MolalityCropped  Charge\n");
06311     for (k = 0; k < m_kk; k++) {
06312       sni = speciesName(k);
06313       printf("%2d     %-16s %14.7le %14.7le %5.1f \n",
06314              k, sni.c_str(), moleF[k], molality[k], charge[k]);
06315     }
06316 
06317     printf("\n Species          Species            beta0MX  "
06318            "beta1MX   beta2MX   CphiMX    alphaMX thetaij    \n");
06319     for (i = 1; i < m_kk - 1; i++) {
06320       sni = speciesName(i);
06321       for (j = i+1; j < m_kk; j++) {
06322         snj = speciesName(j);
06323         int n  = i * m_kk + j;
06324         int ct = m_CounterIJ[n];
06325         printf(" %-16s %-16s %9.5f %9.5f %9.5f %9.5f %9.5f %9.5f \n",
06326                sni.c_str(), snj.c_str(),
06327                m_Beta0MX_ij[ct], m_Beta1MX_ij[ct],
06328                m_Beta2MX_ij[ct], m_CphiMX_ij[ct],
06329                m_Alpha1MX_ij[ct], m_Theta_ij[ct] );
06330 
06331 
06332       }
06333     }
06334 
06335     printf("\n Species          Species          Species       "
06336            "psi   \n");
06337     for (i = 1; i < m_kk; i++) {
06338       sni = speciesName(i);
06339       for (j = 1; j < m_kk; j++) {
06340         snj = speciesName(j);
06341         for (k = 1; k < m_kk; k++) {
06342           std::string snk = speciesName(k);
06343           int n = k + j * m_kk + i * m_kk * m_kk;
06344           if (m_Psi_ijk[n] != 0.0) {
06345             printf(" %-16s %-16s %-16s %9.5f \n",
06346                    sni.c_str(), snj.c_str(), 
06347                    snk.c_str(), m_Psi_ijk[n]);
06348           }
06349         }
06350       }
06351     }
06352   }
06353 
06354   //! Apply the current phScale to a set of activity Coefficients or activities
06355   /*!
06356      *  See the Eq3/6 Manual for a thorough discussion.
06357      *
06358      * @param acMolality input/Output vector containing the molality based 
06359      *                   activity coefficients. length: m_kk.
06360      */
06361   void HMWSoln::applyphScale(doublereal *acMolality) const {
06362     if (m_pHScalingType == PHSCALE_PITZER) {
06363       return;
06364     }
06365     AssertTrace(m_pHScalingType == PHSCALE_NBS);
06366     doublereal lnGammaClMs2 = s_NBS_CLM_lnMolalityActCoeff();
06367     doublereal lnGammaCLMs1 = m_lnActCoeffMolal_Unscaled[m_indexCLM];
06368     doublereal afac = -1.0 *(lnGammaClMs2 - lnGammaCLMs1);
06369     for (int k = 0; k < m_kk; k++) {
06370       acMolality[k] *= exp(m_speciesCharge[k] * afac);
06371     }
06372   }
06373 
06374   //  Apply the current phScale to a set of activity Coefficients or activities
06375   /* 
06376    *  See the Eq3/6 Manual for a thorough discussion.
06377    *
06378    * @param acMolality input/Output vector containing the molality based 
06379    *                   activity coefficients. length: m_kk.
06380    */
06381   void HMWSoln::s_updateScaling_pHScaling() const {
06382     if (m_pHScalingType == PHSCALE_PITZER) {
06383       fvo_copy_dbl_1(m_lnActCoeffMolal_Scaled, m_lnActCoeffMolal_Unscaled, m_kk);
06384       return;
06385     }
06386     AssertTrace(m_pHScalingType == PHSCALE_NBS);
06387     doublereal lnGammaClMs2 = s_NBS_CLM_lnMolalityActCoeff();
06388     doublereal lnGammaCLMs1 = m_lnActCoeffMolal_Unscaled[m_indexCLM];
06389     doublereal afac = -1.0 *(lnGammaClMs2 - lnGammaCLMs1);
06390     for (int k = 0; k < m_kk; k++) {
06391       m_lnActCoeffMolal_Scaled[k] = m_lnActCoeffMolal_Unscaled[k] + m_speciesCharge[k] * afac;
06392     }
06393   }
06394 
06395   //  Apply the current phScale to a set of derivativies of the activity Coefficients
06396   //  wrt temperature
06397   /* 
06398    *  See the Eq3/6 Manual for a thorough discussion of the need
06399    *
06400    */
06401   void HMWSoln::s_updateScaling_pHScaling_dT() const {
06402     if (m_pHScalingType == PHSCALE_PITZER) {
06403       fvo_copy_dbl_1(m_dlnActCoeffMolaldT_Scaled, m_dlnActCoeffMolaldT_Unscaled, m_kk);
06404       return;
06405     }
06406     AssertTrace(m_pHScalingType == PHSCALE_NBS);
06407     doublereal dlnGammaClM_dT_s2 = s_NBS_CLM_dlnMolalityActCoeff_dT();
06408     doublereal dlnGammaCLM_dT_s1 = m_dlnActCoeffMolaldT_Unscaled[m_indexCLM];
06409     doublereal afac = -1.0 *(dlnGammaClM_dT_s2 - dlnGammaCLM_dT_s1);
06410     for (int k = 0; k < m_kk; k++) {
06411       m_dlnActCoeffMolaldT_Scaled[k] = m_dlnActCoeffMolaldT_Unscaled[k] + m_speciesCharge[k] * afac;
06412     }
06413   }
06414 
06415   //  Apply the current phScale to a set of 2nd derivatives of the activity Coefficients
06416   //  wrt temperature
06417   /* 
06418    *  See the Eq3/6 Manual for a thorough discussion of the need
06419    *
06420    */
06421   void HMWSoln::s_updateScaling_pHScaling_dT2() const {
06422     if (m_pHScalingType == PHSCALE_PITZER) {
06423       fvo_copy_dbl_1(m_d2lnActCoeffMolaldT2_Scaled, m_d2lnActCoeffMolaldT2_Unscaled, m_kk);
06424       return;
06425     }
06426     AssertTrace(m_pHScalingType == PHSCALE_NBS);
06427     doublereal d2lnGammaClM_dT2_s2 = s_NBS_CLM_d2lnMolalityActCoeff_dT2();
06428     doublereal d2lnGammaCLM_dT2_s1 = m_d2lnActCoeffMolaldT2_Unscaled[m_indexCLM];
06429     doublereal afac = -1.0 *(d2lnGammaClM_dT2_s2 - d2lnGammaCLM_dT2_s1);
06430     for (int k = 0; k < m_kk; k++) {
06431       m_d2lnActCoeffMolaldT2_Scaled[k] = m_d2lnActCoeffMolaldT2_Unscaled[k] + m_speciesCharge[k] * afac;
06432     }
06433   }
06434 
06435   //   Apply the current phScale to a set of derivatives of the activity Coefficients
06436   //   wrt pressure
06437   /*  
06438    *  See the Eq3/6 Manual for a thorough discussion of the need
06439    */
06440   void HMWSoln::s_updateScaling_pHScaling_dP() const {
06441     if (m_pHScalingType == PHSCALE_PITZER) {
06442       fvo_copy_dbl_1(m_dlnActCoeffMolaldP_Scaled, m_dlnActCoeffMolaldP_Unscaled, m_kk);
06443       return;
06444     }
06445     AssertTrace(m_pHScalingType == PHSCALE_NBS);
06446     doublereal dlnGammaClM_dP_s2 = s_NBS_CLM_dlnMolalityActCoeff_dP();
06447     doublereal dlnGammaCLM_dP_s1 = m_dlnActCoeffMolaldP_Unscaled[m_indexCLM];
06448     doublereal afac = -1.0 *(dlnGammaClM_dP_s2 - dlnGammaCLM_dP_s1);
06449     for (int k = 0; k < m_kk; k++) {
06450       m_dlnActCoeffMolaldP_Scaled[k] = m_dlnActCoeffMolaldP_Unscaled[k] + m_speciesCharge[k] * afac;
06451     }
06452   }
06453 
06454   //  Calculate the temperature derivative of the Chlorine activity coefficient
06455   /* 
06456    *  We assume here that the m_IionicMolality variable is up to date.
06457    */
06458   doublereal HMWSoln::s_NBS_CLM_lnMolalityActCoeff() const {
06459     doublereal sqrtIs = sqrt(m_IionicMolality);
06460     doublereal A = m_A_Debye;
06461     doublereal lnGammaClMs2 = - A * sqrtIs /(1.0 + 1.5 * sqrtIs); 
06462     return  lnGammaClMs2;
06463   }
06464 
06465   //  Calculate the temperature derivative of the Chlorine activity coefficient
06466   /* 
06467    *  We assume here that the m_IionicMolality variable is up to date.
06468    */
06469   doublereal HMWSoln::s_NBS_CLM_dlnMolalityActCoeff_dT() const {
06470     doublereal sqrtIs = sqrt(m_IionicMolality);
06471     doublereal dAdT = dA_DebyedT_TP();
06472     doublereal d_lnGammaClM_dT = - dAdT * sqrtIs /(1.0 + 1.5 * sqrtIs); 
06473     return d_lnGammaClM_dT;
06474   }  
06475 
06476   //  Calculate the second temperature derivative of the Chlorine activity coefficient
06477   /* 
06478    *  We assume here that the m_IionicMolality variable is up to date.
06479    */
06480   doublereal HMWSoln::s_NBS_CLM_d2lnMolalityActCoeff_dT2() const {
06481     doublereal sqrtIs = sqrt(m_IionicMolality);
06482     doublereal d2AdT2 = d2A_DebyedT2_TP();
06483     doublereal d_lnGammaClM_dT2 = - d2AdT2 * sqrtIs /(1.0 + 1.5 * sqrtIs); 
06484     return d_lnGammaClM_dT2;
06485   }
06486 
06487   //  Calculate the pressure derivative of the Chlorine activity coefficient
06488   /* 
06489    *  We assume here that the m_IionicMolality variable is up to date.
06490    */
06491   doublereal HMWSoln::s_NBS_CLM_dlnMolalityActCoeff_dP() const {
06492     doublereal sqrtIs = sqrt(m_IionicMolality);
06493     doublereal dAdP = dA_DebyedP_TP();
06494     doublereal d_lnGammaClM_dP = - dAdP * sqrtIs /(1.0 + 1.5 * sqrtIs); 
06495     return d_lnGammaClM_dP;
06496   }
06497 
06498   int HMWSoln::debugPrinting() {
06499 #ifdef DEBUG_MODE
06500     return m_debugCalc;
06501 #else
06502     return 0;
06503 #endif
06504   }
06505   
06506 }
06507 /*****************************************************************************/
Generated by  doxygen 1.6.3