PDSS_HKFT.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file PDSS_HKFT.cpp
00003  *    Definitions for the class PDSS_HKFT (pressure dependent standard state)
00004  *    which handles calculations for a single species in a phase using the
00005  *    HKFT standard state
00006  *    (see \ref pdssthermo and class \link Cantera::PDSS_HKFT PDSS_HKFT\endlink).
00007  */
00008 
00009 /*
00010  * $Id: PDSS_HKFT.cpp 444 2010-04-21 18:05:44Z hkmoffa $
00011  */
00012 
00013 /*
00014  * Copywrite (2006) Sandia Corporation. Under the terms of 
00015  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
00016  * U.S. Government retains certain rights in this software.
00017  */
00018 
00019 #include "ctml.h"
00020 #include "PDSS_HKFT.h"
00021 #include "WaterProps.h"
00022 #include "PDSS_Water.h"
00023 
00024 #include <cstdlib>
00025 
00026 using namespace std;
00027 
00028 namespace Cantera {
00029  
00030   /*
00031    * Basic list of constructors and duplicators
00032    */
00033   PDSS_HKFT::PDSS_HKFT(VPStandardStateTP *tp, int spindex) :
00034     PDSS(tp, spindex),
00035     m_waterSS(0),
00036     m_densWaterSS(-1.0),
00037     m_waterProps(0),
00038     m_born_coeff_j(-1.0),
00039     m_r_e_j(-1.0),
00040     m_deltaG_formation_tr_pr(0.0),
00041     m_deltaH_formation_tr_pr(0.0),
00042     m_Mu0_tr_pr(0.0),
00043     m_Entrop_tr_pr(0.0),
00044     m_a1(0.0),
00045     m_a2(0.0),
00046     m_a3(0.0),
00047     m_a4(0.0),
00048     m_c1(0.0),
00049     m_c2(0.0),
00050     m_omega_pr_tr(0.0),
00051     m_Y_pr_tr(0.0),
00052     m_Z_pr_tr(0.0),
00053     m_presR_bar(0.0),
00054     m_domega_jdT_prtr(0.0),
00055     m_charge_j(0.0)
00056   {
00057     m_pres = OneAtm;
00058     m_pdssType = cPDSS_MOLAL_HKFT;
00059     m_presR_bar = OneAtm * 1.0E-5;
00060   }
00061 
00062 
00063   PDSS_HKFT::PDSS_HKFT(VPStandardStateTP *tp, int spindex, std::string inputFile, std::string id) :
00064     PDSS(tp, spindex),
00065     m_waterSS(0),
00066     m_densWaterSS(-1.0),
00067     m_waterProps(0),
00068     m_born_coeff_j(-1.0),
00069     m_r_e_j(-1.0),
00070     m_deltaG_formation_tr_pr(0.0),
00071     m_deltaH_formation_tr_pr(0.0),
00072     m_Mu0_tr_pr(0.0),
00073     m_Entrop_tr_pr(0.0),
00074     m_a1(0.0),
00075     m_a2(0.0),
00076     m_a3(0.0),
00077     m_a4(0.0),
00078     m_c1(0.0),
00079     m_c2(0.0),
00080     m_omega_pr_tr(0.0),
00081     m_Y_pr_tr(0.0),
00082     m_Z_pr_tr(0.0),
00083     m_presR_bar(0.0),
00084     m_domega_jdT_prtr(0.0),
00085     m_charge_j(0.0)
00086   {
00087     m_pres = OneAtm;
00088     m_pdssType = cPDSS_MOLAL_HKFT;
00089     m_presR_bar = OneAtm * 1.0E-5;
00090     constructPDSSFile(tp, spindex, inputFile, id);
00091   }
00092 
00093   PDSS_HKFT::PDSS_HKFT(VPStandardStateTP *tp, int spindex, const XML_Node& speciesNode,
00094                        const XML_Node& phaseRoot, bool spInstalled) :
00095     PDSS(tp, spindex),
00096     m_waterSS(0),
00097     m_densWaterSS(-1.0),
00098     m_waterProps(0),
00099     m_born_coeff_j(-1.0),
00100     m_r_e_j(-1.0),
00101     m_deltaG_formation_tr_pr(0.0),
00102     m_deltaH_formation_tr_pr(0.0),
00103     m_Mu0_tr_pr(0.0),
00104     m_Entrop_tr_pr(0.0),
00105     m_a1(0.0),
00106     m_a2(0.0),
00107     m_a3(0.0),
00108     m_a4(0.0),
00109     m_c1(0.0),
00110     m_c2(0.0),
00111     m_omega_pr_tr(0.0),
00112     m_Y_pr_tr(0.0),
00113     m_Z_pr_tr(0.0),
00114     m_presR_bar(0.0),
00115     m_domega_jdT_prtr(0.0),
00116     m_charge_j(0.0)
00117   {
00118     m_pres = OneAtm;
00119     m_pdssType = cPDSS_MOLAL_HKFT;
00120     m_presR_bar = OneAtm * 1.0E-5;
00121     // We have to read the info from here
00122     constructPDSSXML(tp, spindex, speciesNode, phaseRoot, spInstalled); 
00123   }
00124 
00125   PDSS_HKFT::PDSS_HKFT(const PDSS_HKFT &b) :
00126     PDSS(b),
00127     m_waterSS(0),
00128     m_densWaterSS(-1.0),
00129     m_waterProps(0),
00130     m_born_coeff_j(-1.0),
00131     m_r_e_j(-1.0),
00132     m_deltaG_formation_tr_pr(0.0),
00133     m_deltaH_formation_tr_pr(0.0),
00134     m_Mu0_tr_pr(0.0),
00135     m_Entrop_tr_pr(0.0),
00136     m_a1(0.0),
00137     m_a2(0.0),
00138     m_a3(0.0),
00139     m_a4(0.0),
00140     m_c1(0.0),
00141     m_c2(0.0),
00142     m_omega_pr_tr(0.0),
00143     m_Y_pr_tr(0.0),
00144     m_Z_pr_tr(0.0),
00145     m_presR_bar(0.0),
00146     m_domega_jdT_prtr(0.0),
00147     m_charge_j(0.0)
00148   {
00149     m_pdssType = cPDSS_MOLAL_HKFT;
00150     m_presR_bar = OneAtm * 1.0E-5;
00151     /*
00152      * Use the assignment operator to do the brunt
00153      * of the work for the copy construtor.
00154      */
00155     *this = b;
00156   }
00157 
00158   /*
00159    * Assignment operator
00160    */
00161   PDSS_HKFT& PDSS_HKFT::operator=(const PDSS_HKFT& b) {
00162     if (&b == this) return *this;
00163     /*
00164      * Call the base class operator
00165      */
00166     PDSS::operator=(b);
00167 
00168     //! Need to call initAllPtrs AFTER, to get the correct m_waterSS
00169     m_waterSS        = 0;
00170     m_densWaterSS               = b.m_densWaterSS;
00171     //! Need to call initAllPtrs AFTER, to get the correct m_waterProps
00172     if (m_waterProps) {
00173       delete m_waterProps;
00174     }
00175     m_waterProps                = 0;
00176     m_born_coeff_j              = b.m_born_coeff_j;
00177     m_r_e_j                     = b.m_r_e_j;
00178     m_deltaG_formation_tr_pr    = b.m_deltaG_formation_tr_pr;
00179     m_deltaH_formation_tr_pr    = b.m_deltaH_formation_tr_pr;
00180     m_Mu0_tr_pr                 = b.m_Mu0_tr_pr;
00181     m_Entrop_tr_pr              = b.m_Entrop_tr_pr;
00182     m_a1                        = b.m_a1;
00183     m_a2                        = b.m_a2; 
00184     m_a3                        = b.m_a3;   
00185     m_a4                        = b.m_a4;
00186     m_c1                        = b.m_c1;
00187     m_c2                        = b.m_c2; 
00188     m_omega_pr_tr               = b.m_omega_pr_tr;
00189     m_Y_pr_tr                   = b.m_Y_pr_tr;
00190     m_Z_pr_tr                   = b.m_Z_pr_tr;
00191     m_presR_bar                 = b.m_presR_bar;
00192     m_domega_jdT_prtr           = b.m_domega_jdT_prtr;
00193     m_charge_j                  = b.m_charge_j;
00194 
00195     // Here we just fill these in so that local copies within the VPSS object work.
00196     m_waterSS                  = b.m_waterSS;
00197     m_waterProps               = new WaterProps(m_waterSS);
00198    
00199     return *this;
00200   }
00201   
00202   /*
00203    * Destructor for the PDSS_HKFT class
00204    */
00205   PDSS_HKFT::~PDSS_HKFT() { 
00206     delete m_waterProps;
00207   }
00208   
00209   // Duplicator
00210   PDSS* PDSS_HKFT::duplMyselfAsPDSS() const {
00211     PDSS_HKFT * idg = new PDSS_HKFT(*this);
00212     return (PDSS *) idg;
00213   }
00214 
00215   /*
00216    * Return the molar enthalpy in units of J kmol-1
00217    */
00218   doublereal PDSS_HKFT::enthalpy_mole() const {
00219     // Ok we may change this evaluation method in the future.
00220     doublereal GG = gibbs_mole();
00221     doublereal SS = entropy_mole();
00222     doublereal h = GG + m_temp * SS;
00223 
00224 #ifdef DEBUG_MODE_NOT
00225     doublereal h2 = enthalpy_mole2();
00226     if (fabs(h - h2) > 1.0E-1) {
00227       printf("we are here, h = %g, h2 = %g, k = %d, T = %g, P = %g p0 = %g\n",
00228              h, h2, m_spindex, m_temp, m_pres,
00229              m_p0);
00230     }
00231 #endif
00232     return h;
00233   }
00234 
00235   doublereal PDSS_HKFT::enthalpy_RT() const {
00236     doublereal hh = enthalpy_mole();
00237     doublereal RT = GasConstant * m_temp;
00238     return hh / RT;
00239   }
00240 
00241 #ifdef DEBUG_MODE
00242   doublereal PDSS_HKFT::enthalpy_mole2() const {
00243     doublereal delH = deltaH();
00244     double enthTRPR = m_Mu0_tr_pr + 298.15 * m_Entrop_tr_pr * 1.0E3 * 4.184;
00245     double res = delH + enthTRPR;
00246     return res;
00247   }
00248 #endif
00249 
00250   /*
00251    * Calculate the internal energy in mks units of
00252    * J kmol-1 
00253    */
00254   doublereal PDSS_HKFT::intEnergy_mole() const {
00255     doublereal hh = enthalpy_RT();
00256     doublereal mv = molarVolume();
00257     return (hh - mv * m_pres);
00258   }
00259 
00260   /*
00261    * Calculate the entropy in mks units of 
00262    * J kmol-1 K-1
00263    */
00264   doublereal PDSS_HKFT::entropy_mole() const {
00265     doublereal delS = deltaS();
00266     return (m_Entrop_tr_pr * 1.0E3 * 4.184 + delS);
00267   }
00268 
00269   /*
00270    * Calculate the Gibbs free energy in mks units of
00271    * J kmol-1
00272    */
00273   doublereal PDSS_HKFT::gibbs_mole() const {
00274     doublereal delG = deltaG();
00275     return (m_Mu0_tr_pr + delG);
00276   }
00277 
00278   /*
00279    * Calculate the constant pressure heat capacity
00280    * in mks units of J kmol-1 K-1
00281    */
00282   doublereal PDSS_HKFT::cp_mole() const {
00283 
00284     doublereal pbar = m_pres * 1.0E-5;
00285     doublereal c1term = m_c1;
00286 
00287     doublereal c2term = m_c2 / (m_temp - 228.) / (m_temp - 228.);
00288     
00289     doublereal a3term = -m_a3 / (m_temp - 228.) / (m_temp - 228.) / (m_temp - 228.) * 2.0 * m_temp * (pbar - m_presR_bar);
00290 
00291     doublereal a4term = -m_a4 / (m_temp - 228.) / (m_temp - 228.) / (m_temp - 228.) * 2.0 * m_temp 
00292       * log((2600. + pbar)/(2600. + m_presR_bar));
00293 
00294     doublereal omega_j;
00295     doublereal domega_jdT;
00296     doublereal d2omega_jdT2;
00297     if (m_charge_j == 0.0) {
00298       omega_j = m_omega_pr_tr;
00299       domega_jdT = 0.0;
00300       d2omega_jdT2 = 0.0;
00301     } else {
00302       doublereal nu = 166027;
00303       doublereal r_e_j_pr_tr = m_charge_j * m_charge_j / (m_omega_pr_tr/nu + m_charge_j/3.082);
00304   
00305       doublereal gval = gstar(m_temp, m_pres, 0);
00306 
00307       doublereal dgvaldT = gstar(m_temp, m_pres, 1);
00308       doublereal d2gvaldT2 = gstar(m_temp, m_pres, 2);
00309 
00310       doublereal r_e_j = r_e_j_pr_tr + fabs(m_charge_j) * gval;
00311       doublereal dr_e_jdT = fabs(m_charge_j) * dgvaldT;
00312       doublereal d2r_e_jdT2 =  fabs(m_charge_j) * d2gvaldT2;
00313 
00314       doublereal r_e_j2 = r_e_j * r_e_j;
00315 
00316       doublereal charge2 = m_charge_j * m_charge_j;
00317 
00318       doublereal r_e_H = 3.082 + gval;
00319       doublereal r_e_H2 = r_e_H * r_e_H;
00320 
00321       omega_j = nu * (charge2 / r_e_j - m_charge_j / r_e_H);
00322 
00323       domega_jdT =  nu * (-(charge2    / r_e_j2 * dr_e_jdT)
00324                           +(m_charge_j / r_e_H2 * dgvaldT ));
00325 
00326       d2omega_jdT2 = nu * ( 2.0*charge2*dr_e_jdT*dr_e_jdT/(r_e_j2*r_e_j) - charge2*d2r_e_jdT2/r_e_j2
00327                            -2.0*m_charge_j*dgvaldT*dgvaldT/(r_e_H2*r_e_H) + m_charge_j*d2gvaldT2 /r_e_H2);      
00328     }
00329 
00330     doublereal relepsilon = m_waterProps->relEpsilon(m_temp, m_pres, 0);
00331     doublereal drelepsilondT = m_waterProps->relEpsilon(m_temp, m_pres, 1);
00332 
00333     doublereal Y = drelepsilondT / (relepsilon * relepsilon);
00334 
00335     doublereal d2relepsilondT2 = m_waterProps->relEpsilon(m_temp, m_pres, 2);
00336 
00337 #ifdef DEBUG_MODE_NOT
00338     doublereal d1 = m_waterProps->relEpsilon(m_temp, m_pres, 1);
00339     doublereal d2 = m_waterProps->relEpsilon(m_temp + 0.0001, m_pres, 1);
00340     doublereal d3 = (d2 - d1) / 0.0001;
00341     if (fabs ( d2relepsilondT2 - d3) > 1.0E-6) {
00342       printf("we are here\n");
00343     }
00344 #endif
00345 
00346     doublereal X = d2relepsilondT2 / (relepsilon* relepsilon) - 2.0 * relepsilon * Y * Y;
00347 
00348     doublereal Z = -1.0 / relepsilon;
00349 
00350     doublereal yterm = 2.0 * m_temp * Y * domega_jdT;
00351 
00352     doublereal xterm = omega_j * m_temp * X;
00353 
00354     doublereal otterm = m_temp * d2omega_jdT2 * (Z + 1.0);
00355 
00356     doublereal rterm =  - m_domega_jdT_prtr * (m_Z_pr_tr + 1.0);
00357  
00358     doublereal Cp_calgmol = c1term + c2term + a3term + a4term + yterm + xterm + otterm + rterm;
00359 
00360     // Convert to Joules / kmol
00361     doublereal Cp = Cp_calgmol * 1.0E3 * 4.184;
00362 
00363 #ifdef DEBUG_MODE_NOT
00364     double e1 = enthalpy_mole();
00365     m_temp = m_temp - 0.001;
00366     double e2 = enthalpy_mole();
00367     m_temp = m_temp + 0.001;
00368     double cpd = (e1 - e2) / 0.001;
00369     if (fabs(Cp - cpd) > 10.0) {
00370       printf("Cp difference : raw: %g, delta: %g, k = %d, T = %g, m_pres = %g\n",
00371              Cp, cpd, m_spindex, m_temp, m_pres);
00372     }
00373 #endif
00374     return Cp;   
00375   }
00376 
00377   /*
00378    * Calculate the constant volume heat capacity
00379    * in mks units of J kmol-1 K-1
00380    */
00381   doublereal 
00382   PDSS_HKFT::cv_mole() const {
00383     throw CanteraError("PDSS_HKFT::cv_mole()", "unimplemented");
00384     return (0.0);
00385   }
00386 
00387   doublereal  PDSS_HKFT::molarVolume() const {
00388      
00389     // Initially do all calculations in (cal/gmol/Pa)
00390    
00391     doublereal a1term = m_a1 * 1.0E-5;
00392 
00393     doublereal a2term = m_a2 / (2600.E5 + m_pres);
00394 
00395     doublereal a3term = m_a3 * 1.0E-5/ (m_temp - 228.);
00396 
00397     doublereal a4term = m_a4 / (m_temp - 228.) / (2600.E5 + m_pres);
00398 
00399     doublereal omega_j;
00400     doublereal domega_jdP;
00401     if (m_charge_j == 0.0) {
00402       omega_j = m_omega_pr_tr;
00403       domega_jdP = 0.0;
00404     } else {
00405       doublereal nu = 166027.;
00406       doublereal charge2 = m_charge_j * m_charge_j;
00407       doublereal r_e_j_pr_tr = charge2 / (m_omega_pr_tr/nu + m_charge_j/3.082);
00408   
00409       doublereal gval    = gstar(m_temp, m_pres, 0);
00410       doublereal dgvaldP = gstar(m_temp, m_pres, 3);
00411 
00412       doublereal r_e_j = r_e_j_pr_tr + fabs(m_charge_j) * gval;
00413       doublereal r_e_H = 3.082 + gval;
00414 
00415       omega_j = nu * (charge2 / r_e_j - m_charge_j / r_e_H );
00416     
00417       doublereal dr_e_jdP = fabs(m_charge_j) * dgvaldP;
00418 
00419       domega_jdP = -  nu * (charge2 / (r_e_j * r_e_j) * dr_e_jdP)
00420         + nu * m_charge_j / (r_e_H * r_e_H) * dgvaldP;
00421     }
00422 
00423     doublereal drelepsilondP = m_waterProps->relEpsilon(m_temp, m_pres, 3);
00424 
00425     doublereal relepsilon = m_waterProps->relEpsilon(m_temp, m_pres, 0);
00426  
00427     doublereal Q = drelepsilondP / (relepsilon * relepsilon);
00428 
00429     doublereal Z = -1.0 / relepsilon;
00430 
00431     doublereal wterm = - domega_jdP * (Z + 1.0);
00432 
00433     doublereal qterm = - omega_j * Q;
00434 
00435     doublereal molVol_calgmolPascal = a1term + a2term +  a3term + a4term + wterm + qterm;
00436 
00437     // Convert to m**3 / kmol from (cal/gmol/Pa)
00438     doublereal molVol = molVol_calgmolPascal * 4.184 * 1.0E3;
00439     return molVol;
00440   }
00441 
00442   doublereal 
00443   PDSS_HKFT::density() const {
00444     doublereal val = molarVolume();
00445     return (m_mw/val);
00446   }
00447 
00448   doublereal 
00449   PDSS_HKFT::gibbs_RT_ref() const {
00450     doublereal m_psave = m_pres;
00451     m_pres = m_waterSS->pref_safe(m_temp);
00452     doublereal ee = gibbs_RT();
00453     m_pres = m_psave;
00454     return ee;
00455   }
00456 
00457   doublereal 
00458   PDSS_HKFT::enthalpy_RT_ref() const {
00459     doublereal m_psave = m_pres;
00460     m_pres = m_waterSS->pref_safe(m_temp);
00461     doublereal hh = enthalpy_RT();
00462     m_pres = m_psave;
00463     return hh;
00464   }
00465 
00466   doublereal 
00467   PDSS_HKFT::entropy_R_ref() const {
00468     doublereal m_psave = m_pres;
00469     m_pres = m_waterSS->pref_safe(m_temp);
00470     doublereal ee = entropy_R();
00471     m_pres = m_psave;
00472     return ee;
00473   }
00474 
00475   doublereal 
00476   PDSS_HKFT::cp_R_ref() const {
00477     doublereal m_psave = m_pres;
00478     m_pres = m_waterSS->pref_safe(m_temp);
00479     doublereal ee = cp_R();
00480     m_pres = m_psave;
00481     return ee;
00482   }
00483   
00484   doublereal
00485   PDSS_HKFT::molarVolume_ref() const {
00486     doublereal m_psave = m_pres;
00487     m_pres = m_waterSS->pref_safe(m_temp);
00488     doublereal ee = molarVolume();
00489     m_pres = m_psave;
00490     return ee;
00491   }
00492   
00493   /*
00494    * Calculate the pressure (Pascals), given the temperature and density
00495    *  Temperature: kelvin
00496    *  rho: density in kg m-3
00497    */
00498   doublereal
00499   PDSS_HKFT::pressure() const {
00500     return m_pres;
00501   }
00502         
00503   void 
00504   PDSS_HKFT::setPressure(doublereal p) {
00505     m_pres = p;
00506   }
00507  
00508   void PDSS_HKFT::setTemperature(doublereal temp) {
00509     m_temp = temp;
00510   }
00511 
00512   doublereal PDSS_HKFT::temperature() const {
00513     return m_temp;
00514   }
00515 
00516   void PDSS_HKFT::setState_TP(doublereal temp, doublereal pres) {
00517     setTemperature(temp);
00518     setPressure(pres);
00519   }
00520 
00521   // critical temperature 
00522   doublereal 
00523   PDSS_HKFT::critTemperature() const { 
00524     throw CanteraError("PDSS_HKFT::critTemperature()", "unimplemented");
00525     return (0.0);
00526   }
00527         
00528   // critical pressure
00529   doublereal PDSS_HKFT::critPressure() const {
00530     throw CanteraError("PDSS_HKFT::critPressure()", "unimplemented");
00531     return (0.0);
00532   }
00533         
00534   // critical density
00535   doublereal PDSS_HKFT::critDensity() const {
00536     throw CanteraError("PDSS_HKFT::critDensity()", "unimplemented");
00537     return (0.0);
00538   }
00539         
00540 
00541   void PDSS_HKFT::initThermo() {
00542     PDSS::initThermo();
00543   
00544     m_waterSS = (PDSS_Water *) m_tp->providePDSS(0);
00545     /*
00546      *  Section to initialize  m_Z_pr_tr and   m_Y_pr_tr
00547      */
00548     m_temp = 273.15 + 25.;
00549     m_pres = OneAtm;
00550     doublereal relepsilon = m_waterProps->relEpsilon(m_temp, m_pres, 0);
00551 
00552     m_waterSS->setState_TP(m_temp, m_pres);
00553     m_densWaterSS = m_waterSS->density();
00554     m_Z_pr_tr = -1.0 / relepsilon;
00555  
00556     doublereal drelepsilondT = m_waterProps->relEpsilon(m_temp, m_pres, 1);
00557 
00558     m_Y_pr_tr = drelepsilondT / (relepsilon * relepsilon);
00559  
00560     m_waterProps = new WaterProps(m_waterSS);
00561 
00562     m_presR_bar = OneAtm / 1.0E5;
00563     m_charge_j = m_tp->charge(m_spindex);
00564     convertDGFormation();
00565 
00566     //! Ok, we have mu. Let's check it against the input value
00567     // of DH_F to see that we have some internal consistency
00568 
00569     doublereal Hcalc = m_Mu0_tr_pr + 298.15 * (m_Entrop_tr_pr * 1.0E3 * 4.184);
00570 
00571     doublereal DHjmol = m_deltaH_formation_tr_pr * 1.0E3 * 4.184;
00572 
00573     // If the discrepency is greater than 100 cal gmol-1, print
00574     // an error and exit.
00575     if (fabs(Hcalc -DHjmol) > 100.* 1.0E3 * 4.184) {
00576       throw CanteraError(" PDSS_HKFT::initThermo()",
00577                          "DHjmol is not consistent with G and S: " + 
00578                          fp2str(Hcalc/(4.184E3)) + " vs " 
00579                          + fp2str(m_deltaH_formation_tr_pr) + "cal gmol-1");
00580     }
00581     doublereal nu = 166027;
00582 
00583     doublereal r_e_j_pr_tr;
00584     if (m_charge_j != 0.0) {
00585       r_e_j_pr_tr = m_charge_j * m_charge_j / (m_omega_pr_tr/nu + m_charge_j/3.082);
00586     } else {
00587       r_e_j_pr_tr = 0.0;
00588     }
00589     
00590     if (m_charge_j == 0.0) {
00591       m_domega_jdT_prtr = 0.0;
00592     } else {    
00593       doublereal gval = gstar(m_temp, m_pres, 0);
00594 
00595       doublereal dgvaldT = gstar(m_temp, m_pres, 1);
00596 
00597       doublereal r_e_j = r_e_j_pr_tr + fabs(m_charge_j) * gval;
00598       doublereal dr_e_jdT = fabs(m_charge_j) * dgvaldT;
00599 
00600       m_domega_jdT_prtr =  -  nu * (m_charge_j * m_charge_j / (r_e_j * r_e_j) * dr_e_jdT)
00601         + nu * m_charge_j / (3.082 + gval) / (3.082 + gval) * dgvaldT;
00602     }
00603   }
00604 
00605 
00606   void PDSS_HKFT::initThermoXML(const XML_Node& phaseNode, std::string& id) {
00607     PDSS::initThermoXML(phaseNode, id);
00608   }
00609 
00610   void PDSS_HKFT::initAllPtrs(VPStandardStateTP *vptp_ptr, VPSSMgr *vpssmgr_ptr, 
00611                               SpeciesThermo* spthermo_ptr) {
00612 
00613     PDSS::initAllPtrs(vptp_ptr, vpssmgr_ptr,  spthermo_ptr);
00614     m_waterSS = (PDSS_Water *) m_tp->providePDSS(0);
00615     if (m_waterProps) {
00616       delete m_waterProps;
00617     }
00618     m_waterProps = new WaterProps(m_waterSS);
00619   }
00620 
00621   void PDSS_HKFT::constructPDSSXML(VPStandardStateTP *tp, int spindex,
00622                                    const XML_Node& speciesNode, 
00623                                    const XML_Node& phaseNode, bool spInstalled) {
00624     int hasDGO = 0;
00625     int hasSO = 0;
00626     int hasDHO = 0;
00627    
00628     if (!spInstalled) {
00629       throw CanteraError("PDSS_HKFT::constructPDSSXML", "spInstalled false not handled");
00630     }
00631 
00632     const XML_Node *tn = speciesNode.findByName("thermo");
00633     if (!tn) {
00634       throw CanteraError("PDSS_HKFT::constructPDSSXML",
00635                          "no thermo Node for species " + speciesNode.name());
00636     }
00637     std::string model = lowercase((*tn)["model"]);
00638     if (model != "hkft") {
00639       throw CanteraError("PDSS_HKFT::initThermoXML",
00640                          "thermo model for species isn't hkft: "
00641                          + speciesNode.name());
00642     }
00643     const XML_Node *hh = tn->findByName("HKFT");
00644     if (!hh) {
00645       throw CanteraError("PDSS_HKFT::constructPDSSXML",
00646                          "no Thermo::HKFT Node for species " + speciesNode.name());
00647     }
00648 
00649     // go get the attributes
00650     m_p0 = OneAtm;
00651     std::string p0string = (*hh)["Pref"];
00652     if (p0string != "") {
00653       m_p0 = strSItoDbl(p0string);
00654     }
00655 
00656     std::string minTstring = (*hh)["Tmin"];
00657     if (minTstring != "") {
00658       m_minTemp = atofCheck(minTstring.c_str());
00659     }
00660 
00661     std::string maxTstring = (*hh)["Tmax"];
00662     if (maxTstring != "") {
00663       m_maxTemp = atofCheck(maxTstring.c_str());
00664     }
00665 
00666     if (hh->hasChild("DG0_f_Pr_Tr")) {
00667       doublereal val = getFloat(*hh, "DG0_f_Pr_Tr");
00668       m_deltaG_formation_tr_pr = val;
00669       hasDGO = 1;
00670     } else {
00671       // throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing DG0_f_Pr_Tr field");
00672     }
00673 
00674     if (hh->hasChild("DH0_f_Pr_Tr")) {
00675       doublereal val = getFloat(*hh, "DH0_f_Pr_Tr");
00676       m_deltaH_formation_tr_pr = val;
00677       hasDHO = 1;
00678     } else {
00679       //  throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing DH0_f_Pr_Tr field");
00680     }
00681 
00682     if (hh->hasChild("S0_Pr_Tr")) {
00683       doublereal val = getFloat(*hh, "S0_Pr_Tr");
00684       m_Entrop_tr_pr= val;
00685       hasSO = 1;
00686     } else {
00687       //  throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing S0_Pr_Tr field");
00688     }
00689 
00690     const XML_Node *ss = speciesNode.findByName("standardState");
00691     if (!ss) {
00692       throw CanteraError("PDSS_HKFT::constructPDSSXML",
00693                          "no standardState Node for species " + speciesNode.name());
00694     }
00695     model = lowercase((*ss)["model"]);
00696     if (model != "hkft") {
00697       throw CanteraError("PDSS_HKFT::initThermoXML",
00698                          "standardState model for species isn't hkft: "
00699                          + speciesNode.name());
00700     }
00701     if (ss->hasChild("a1")) {
00702       doublereal val = getFloat(*ss, "a1");
00703       m_a1 = val;
00704     } else {
00705       throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing a1 field");
00706     }
00707     if (ss->hasChild("a2")) {
00708       doublereal val = getFloat(*ss, "a2");
00709       m_a2 = val;
00710     } else {
00711       throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing a2 field");
00712     }
00713     if (ss->hasChild("a3")) {
00714       doublereal val = getFloat(*ss, "a3");
00715       m_a3 = val;
00716     } else {
00717       throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing a3 field");
00718     }
00719     if (ss->hasChild("a4")) {
00720       doublereal val = getFloat(*ss, "a4");
00721       m_a4 = val;
00722     } else {
00723       throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing a4 field");
00724     }
00725     
00726     if (ss->hasChild("c1")) {
00727       doublereal val = getFloat(*ss, "c1");
00728       m_c1 = val;
00729     } else {
00730       throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing c1 field");
00731     }
00732     if (ss->hasChild("c2")) {
00733       doublereal val = getFloat(*ss, "c2");
00734       m_c2 = val;
00735     } else {
00736       throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing c2 field");
00737     }
00738     if (ss->hasChild("omega_Pr_Tr")) {
00739       doublereal val = getFloat(*ss, "omega_Pr_Tr");
00740       m_omega_pr_tr = val;
00741     } else {
00742       throw CanteraError("PDSS_HKFT::constructPDSSXML", " missing omega_Pr_Tr field");
00743     }
00744 
00745 
00746     int isum = hasDGO + hasDHO + hasSO;
00747     if (isum < 2) {
00748       throw CanteraError("PDSS_HKFT::constructPDSSXML", 
00749                          "Missing 2 or more of DG0_f_Pr_Tr, DH0_f_Pr_Tr, or S0_f_Pr_Tr fields. "
00750                          "Need to supply at least two of these fields");
00751     }
00752     // Ok, if we are missing one, then we construct its value from the other two.
00753     // This code has been internally verified.
00754     if (hasDHO == 0) {
00755       m_charge_j = m_tp->charge(m_spindex);
00756       convertDGFormation();
00757       doublereal Hcalc = m_Mu0_tr_pr + 298.15 * (m_Entrop_tr_pr * 1.0E3 * 4.184);
00758       m_deltaH_formation_tr_pr = Hcalc / (1.0E3 * 4.184);
00759     }
00760     if (hasDGO == 0) {
00761       doublereal DHjmol = m_deltaH_formation_tr_pr * 1.0E3 * 4.184;
00762       m_Mu0_tr_pr = DHjmol -  298.15 * (m_Entrop_tr_pr * 1.0E3 * 4.184);
00763       m_deltaG_formation_tr_pr =   m_Mu0_tr_pr / (1.0E3 * 4.184);
00764       double tmp =   m_Mu0_tr_pr;
00765       m_charge_j = m_tp->charge(m_spindex);
00766       convertDGFormation();
00767       double totalSum =  m_Mu0_tr_pr - tmp;
00768       m_Mu0_tr_pr = tmp;
00769       m_deltaG_formation_tr_pr =   (m_Mu0_tr_pr - totalSum)/ (1.0E3 * 4.184);
00770     }
00771     if (hasSO == 0) {
00772       m_charge_j = m_tp->charge(m_spindex);
00773       convertDGFormation();
00774       doublereal DHjmol = m_deltaH_formation_tr_pr * 1.0E3 * 4.184;
00775       m_Entrop_tr_pr = (DHjmol - m_Mu0_tr_pr) / (298.15 * 1.0E3 * 4.184); 
00776     }
00777     
00778   }
00779 
00780   void PDSS_HKFT::constructPDSSFile(VPStandardStateTP *tp, int spindex,
00781                                     std::string inputFile, std::string id) {
00782 
00783     if (inputFile.size() == 0) {
00784       throw CanteraError("PDSS_HKFT::initThermo",
00785                          "input file is null");
00786     }
00787     std::string path = findInputFile(inputFile);
00788     ifstream fin(path.c_str());
00789     if (!fin) {
00790       throw CanteraError("PDSS_HKFT::initThermo","could not open "
00791                          +path+" for reading.");
00792     }
00793     /*
00794      * The phase object automatically constructs an XML object.
00795      * Use this object to store information.
00796      */
00797 
00798     XML_Node *fxml = new XML_Node();
00799     fxml->build(fin);
00800     XML_Node *fxml_phase = findXMLPhase(fxml, id);
00801     if (!fxml_phase) {
00802       throw CanteraError("PDSS_HKFT::initThermo",
00803                          "ERROR: Can not find phase named " +
00804                          id + " in file named " + inputFile);
00805     }
00806 
00807     XML_Node& speciesList = fxml_phase->child("speciesArray");
00808     XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"],
00809                                          &(fxml_phase->root()));
00810     const vector<string>&sss = tp->speciesNames();
00811     const XML_Node* s =  speciesDB->findByAttr("name", sss[spindex]);
00812 
00813     constructPDSSXML(tp, spindex, *s, *fxml_phase, true);
00814     delete fxml;
00815   }
00816 
00817 #ifdef DEBUG_MODE
00818   doublereal PDSS_HKFT::deltaH() const {
00819     
00820     doublereal pbar = m_pres * 1.0E-5;
00821 
00822     doublereal c1term = m_c1 * (m_temp - 298.15);
00823 
00824     doublereal a1term = m_a1 * (pbar - m_presR_bar);
00825 
00826     doublereal a2term = m_a2 * log((2600. + pbar)/(2600. + m_presR_bar));
00827 
00828     doublereal c2term = -m_c2 * ( 1.0/(m_temp - 228.) - 1.0/(298.15 - 228.) );
00829 
00830     double a3tmp = (2.0 * m_temp - 228.)/ (m_temp - 228.) /(m_temp - 228.);
00831     
00832     doublereal a3term = m_a3 * a3tmp * (pbar - m_presR_bar);
00833 
00834     doublereal a4term = m_a4 * a3tmp * log((2600. + pbar)/(2600. + m_presR_bar));
00835 
00836     doublereal omega_j;
00837     doublereal  domega_jdT;
00838     if (m_charge_j == 0.0) {
00839       omega_j = m_omega_pr_tr;
00840       domega_jdT = 0.0;
00841     } else {
00842       doublereal nu = 166027;
00843       doublereal r_e_j_pr_tr = m_charge_j * m_charge_j / (m_omega_pr_tr/nu + m_charge_j/3.082);
00844       doublereal gval = gstar(m_temp, m_pres, 0);    
00845       doublereal r_e_j = r_e_j_pr_tr + fabs(m_charge_j) * gval;
00846 
00847       doublereal dgvaldT = gstar(m_temp, m_pres, 1);
00848       doublereal dr_e_jdT = fabs(m_charge_j) * dgvaldT;
00849 
00850       omega_j = nu * (m_charge_j * m_charge_j / r_e_j - m_charge_j / (3.082 + gval)  );
00851 
00852       domega_jdT = -  nu * (m_charge_j * m_charge_j / (r_e_j * r_e_j) * dr_e_jdT)
00853         + nu * m_charge_j / (3.082 + gval) / (3.082 + gval) * dgvaldT;
00854     }
00855 
00856     doublereal relepsilon = m_waterProps->relEpsilon(m_temp, m_pres, 0);
00857     doublereal drelepsilondT = m_waterProps->relEpsilon(m_temp, m_pres, 1);
00858 
00859     doublereal Y = drelepsilondT / (relepsilon * relepsilon);
00860 
00861     doublereal Z = -1.0 / relepsilon;
00862 
00863     doublereal yterm  =   m_temp * omega_j       * Y;
00864     doublereal yrterm = - 298.15 * m_omega_pr_tr * m_Y_pr_tr;
00865 
00866     doublereal wterm  = - omega_j * (Z + 1.0);
00867     doublereal wrterm = + m_omega_pr_tr * (m_Z_pr_tr + 1.0);
00868 
00869     doublereal otterm =    m_temp * domega_jdT        * (Z + 1.0);
00870     doublereal otrterm = - m_temp * m_domega_jdT_prtr * (m_Z_pr_tr + 1.0);
00871 
00872     doublereal deltaH_calgmol = c1term + a1term + a2term + c2term + a3term + a4term 
00873       + yterm + yrterm + wterm + wrterm + otterm + otrterm;
00874 
00875     // Convert to Joules / kmol
00876     doublereal deltaH = deltaH_calgmol * 1.0E3 * 4.184;
00877     return deltaH;
00878   }
00879 #endif
00880 
00881   doublereal PDSS_HKFT::deltaG() const {
00882     
00883     doublereal pbar = m_pres * 1.0E-5;
00884     //doublereal m_presR_bar = OneAtm * 1.0E-5;
00885 
00886     doublereal sterm = -  m_Entrop_tr_pr * (m_temp - 298.15);
00887 
00888     doublereal c1term = -m_c1 * (m_temp * log(m_temp/298.15) - (m_temp - 298.15));
00889     doublereal a1term = m_a1 * (pbar - m_presR_bar);
00890 
00891     doublereal a2term = m_a2 * log((2600. + pbar)/(2600. + m_presR_bar));
00892 
00893     doublereal c2term = -m_c2 * (( 1.0/(m_temp - 228.) - 1.0/(298.15 - 228.) ) * (228. - m_temp)/228.
00894                              - m_temp / (228.*228.) * log( (298.15*(m_temp-228.)) / (m_temp*(298.15-228.)) ));
00895     
00896     doublereal a3term = m_a3 / (m_temp - 228.) * (pbar - m_presR_bar);
00897 
00898     doublereal a4term = m_a4 / (m_temp - 228.) * log((2600. + pbar)/(2600. + m_presR_bar));
00899 
00900     doublereal omega_j;
00901     if (m_charge_j == 0.0) {
00902       omega_j = m_omega_pr_tr;
00903     } else {
00904       doublereal nu = 166027;
00905       doublereal r_e_j_pr_tr = m_charge_j * m_charge_j / (m_omega_pr_tr/nu + m_charge_j/3.082);
00906       doublereal gval = gstar(m_temp, m_pres, 0);    
00907       doublereal r_e_j = r_e_j_pr_tr + fabs(m_charge_j) * gval;
00908       omega_j = nu * (m_charge_j * m_charge_j / r_e_j - m_charge_j / (3.082 + gval)  );
00909     }
00910 
00911     doublereal relepsilon = m_waterProps->relEpsilon(m_temp, m_pres, 0);
00912 
00913     doublereal Z = -1.0 / relepsilon;
00914 
00915     doublereal wterm = - omega_j * (Z + 1.0);
00916 
00917     doublereal wrterm = m_omega_pr_tr * (m_Z_pr_tr + 1.0);
00918 
00919     doublereal yterm = m_omega_pr_tr * m_Y_pr_tr * (m_temp - 298.15);
00920 
00921     doublereal deltaG_calgmol = sterm + c1term + a1term + a2term + c2term + a3term + a4term + wterm + wrterm + yterm;
00922 
00923     // Convert to Joules / kmol
00924     doublereal deltaG = deltaG_calgmol * 1.0E3 * 4.184;
00925     return deltaG;
00926   }
00927 
00928 
00929   doublereal PDSS_HKFT::deltaS() const {
00930     
00931     doublereal pbar = m_pres * 1.0E-5;
00932 
00933     doublereal c1term = m_c1 * log(m_temp/298.15);
00934 
00935     doublereal c2term = -m_c2 / 228. * (( 1.0/(m_temp - 228.) - 1.0/(298.15 - 228.) )
00936                                     + 1.0 / 228. * log( (298.15*(m_temp-228.)) / (m_temp*(298.15-228.)) ));
00937     
00938     doublereal a3term = m_a3 / (m_temp - 228.) / (m_temp - 228.) * (pbar - m_presR_bar);
00939 
00940     doublereal a4term = m_a4 / (m_temp - 228.) / (m_temp - 228.) * log((2600. + pbar)/(2600. + m_presR_bar));
00941 
00942     doublereal omega_j;
00943     doublereal domega_jdT;
00944     if (m_charge_j == 0.0) {
00945       omega_j = m_omega_pr_tr;
00946       domega_jdT = 0.0;
00947     } else {
00948 
00949       doublereal nu = 166027;
00950       doublereal r_e_j_pr_tr = m_charge_j * m_charge_j / (m_omega_pr_tr/nu + m_charge_j/3.082);
00951   
00952       doublereal gval = gstar(m_temp, m_pres, 0);
00953 
00954       doublereal dgvaldT = gstar(m_temp, m_pres, 1);
00955 
00956       doublereal r_e_j = r_e_j_pr_tr + fabs(m_charge_j) * gval;
00957       doublereal dr_e_jdT = fabs(m_charge_j) * dgvaldT;
00958 
00959       omega_j = nu * (m_charge_j * m_charge_j / r_e_j - m_charge_j / (3.082 + gval)  );
00960     
00961       domega_jdT = -  nu * (m_charge_j * m_charge_j / (r_e_j * r_e_j) * dr_e_jdT)
00962         + nu * m_charge_j / (3.082 + gval) / (3.082 + gval) * dgvaldT;
00963     }
00964 
00965     doublereal relepsilon = m_waterProps->relEpsilon(m_temp, m_pres, 0);
00966     doublereal drelepsilondT = m_waterProps->relEpsilon(m_temp, m_pres, 1);
00967 
00968     doublereal Y = drelepsilondT / (relepsilon * relepsilon);
00969 
00970     doublereal Z = -1.0 / relepsilon;
00971 
00972     doublereal wterm = omega_j * Y;
00973 
00974     doublereal wrterm = - m_omega_pr_tr * m_Y_pr_tr;
00975 
00976     doublereal otterm = domega_jdT * (Z + 1.0);
00977 
00978     doublereal otrterm = - m_domega_jdT_prtr * (m_Z_pr_tr + 1.0);
00979    
00980     doublereal deltaS_calgmol = c1term + c2term + a3term + a4term + wterm + wrterm  + otterm + otrterm;
00981 
00982     // Convert to Joules / kmol
00983     doublereal deltaS = deltaS_calgmol * 1.0E3 * 4.184;
00984     return deltaS;
00985   }
00986    
00987 
00988   // Internal formula for the calculation of a_g()
00989   /*
00990    * The output of this is in units of Angstroms
00991    */
00992   doublereal PDSS_HKFT::ag(const doublereal temp, const int ifunc) const {
00993     static doublereal ag_coeff[3] = { -2.037662,  5.747000E-3,  -6.557892E-6};
00994     if (ifunc == 0) {
00995       doublereal t2 = temp * temp;
00996       doublereal val = ag_coeff[0] + ag_coeff[1] * temp + ag_coeff[2] * t2;
00997       return val;
00998     } else if (ifunc == 1) {
00999       return  ag_coeff[1] + ag_coeff[2] * 2.0 * temp;
01000     }
01001     if (ifunc != 2) {
01002       return 0.0;
01003     }
01004     return ag_coeff[2] * 2.0;
01005   }
01006 
01007 
01008   // Internal formula for the calculation of b_g()
01009   /*
01010    * the output of this is unitless
01011    */
01012   doublereal PDSS_HKFT::bg(const doublereal temp, const int ifunc) const {
01013     static doublereal bg_coeff[3] = { 6.107361, -1.074377E-2,  1.268348E-5};
01014     if (ifunc == 0) {
01015       doublereal t2 = temp * temp;
01016       doublereal val = bg_coeff[0] + bg_coeff[1] * temp + bg_coeff[2] * t2;
01017       return val;
01018     }   else if (ifunc == 1) {
01019       return bg_coeff[1] + bg_coeff[2] * 2.0 * temp;
01020     }
01021     if (ifunc != 2) {
01022       return 0.0;
01023     }
01024     return bg_coeff[2] * 2.0;
01025   }
01026 
01027 
01028   doublereal PDSS_HKFT::f(const doublereal temp, const doublereal pres, const int ifunc) const {
01029     
01030     static doublereal af_coeff[3] = { 3.666666E1, -0.1504956E-9, 0.5107997E-13};
01031     doublereal TC = temp - 273.15;
01032     doublereal presBar = pres / 1.0E5;
01033 
01034     if (TC < 155.0) return 0.0;
01035     if (TC > 355.0) TC = 355.0;
01036     if (presBar > 1000.) return 0.0;
01037     
01038 
01039     doublereal T1 = (TC-155.0)/300.;
01040     doublereal fac1;
01041 
01042     doublereal p2 = (1000. - presBar) * (1000. - presBar);
01043     doublereal p3 = (1000. - presBar) * p2;
01044     doublereal p4 = p2 * p2;
01045     doublereal fac2 = af_coeff[1] * p3 + af_coeff[2] * p4;
01046     if (ifunc == 0) {
01047       fac1 = pow(T1,4.8) + af_coeff[0] * pow(T1, 16.0);
01048       return fac1 * fac2;
01049     } else if (ifunc == 1) {
01050       fac1 =  (4.8 * pow(T1,3.8) + 16.0 * af_coeff[0] * pow(T1, 15.0)) / 300.;
01051       return fac1 * fac2;
01052     } else if (ifunc == 2) {
01053       fac1 =  (4.8 * 3.8 * pow(T1,2.8) + 16.0 * 15.0 * af_coeff[0] * pow(T1, 14.0)) / (300. * 300.);
01054       return fac1 * fac2;
01055     } else if (ifunc == 3) {
01056       fac1 = pow(T1,4.8) + af_coeff[0] * pow(T1, 16.0);
01057       fac2 = - (3.0 * af_coeff[1] * p2 + 4.0 * af_coeff[2] * p3 )/ 1.0E5;
01058       return fac1 * fac2;
01059     } else {
01060       throw CanteraError("HKFT_PDSS::gg", "unimplemented");
01061     }
01062     return 0.0;
01063   }
01064 
01065 
01066   doublereal PDSS_HKFT::g(const doublereal temp, const doublereal pres, const int ifunc) const {
01067     doublereal afunc = ag(temp, 0);
01068     doublereal bfunc = bg(temp, 0);
01069     m_waterSS->setState_TP(temp, pres);
01070     m_densWaterSS = m_waterSS->density();
01071     // density in gm cm-3
01072     doublereal dens = m_densWaterSS * 1.0E-3;
01073     doublereal gval = afunc * pow((1.0-dens), bfunc);
01074     if (dens >= 1.0) {
01075       return 0.0;
01076     }
01077     if (ifunc == 0) {  
01078       return gval;
01079 
01080     } else if (ifunc == 1 || ifunc == 2) {
01081       doublereal afuncdT = ag(temp, 1);
01082       doublereal bfuncdT = bg(temp, 1);
01083       doublereal alpha   = m_waterSS->thermalExpansionCoeff();
01084 
01085       doublereal fac1 = afuncdT * gval / afunc;
01086       doublereal fac2 = bfuncdT * gval * log(1.0 - dens);
01087       doublereal fac3 = gval * alpha * bfunc * dens / (1.0 - dens);
01088 
01089       doublereal dgdt = fac1 + fac2 + fac3;
01090       if (ifunc == 1) {
01091         return dgdt;
01092       }
01093 
01094       doublereal afuncdT2 = ag(temp, 2);
01095       doublereal bfuncdT2 = bg(temp, 2);
01096 
01097       doublereal dfac1dT = dgdt * afuncdT / afunc + afuncdT2 * gval / afunc 
01098         -  afuncdT * afuncdT * gval / (afunc * afunc);
01099 
01100       doublereal ddensdT = - alpha * dens;
01101       doublereal dfac2dT =  bfuncdT2 * gval * log(1.0 - dens) 
01102         + bfuncdT * dgdt * log(1.0 - dens) 
01103         - bfuncdT * gval /(1.0 - dens) * ddensdT;
01104 
01105       doublereal dalphadT = m_waterSS->dthermalExpansionCoeffdT();
01106       
01107       doublereal dfac3dT = dgdt * alpha * bfunc * dens / (1.0 - dens)
01108         + gval * dalphadT * bfunc * dens / (1.0 - dens)
01109         + gval * alpha * bfuncdT * dens / (1.0 - dens)
01110         + gval * alpha * bfunc * ddensdT / (1.0 - dens)
01111         + gval * alpha * bfunc * dens / ((1.0 - dens) * (1.0 - dens)) * ddensdT;
01112 
01113       return dfac1dT + dfac2dT + dfac3dT;
01114 
01115     } else if (ifunc == 3) {
01116       doublereal beta   = m_waterSS->isothermalCompressibility();
01117 
01118       doublereal dgdp = - bfunc * gval * dens * beta / (1.0 - dens); 
01119       
01120       return dgdp;
01121     } else {
01122       throw CanteraError("HKFT_PDSS::g", "unimplemented");
01123     }
01124     return 0.0;
01125   }
01126 
01127 
01128  doublereal PDSS_HKFT::gstar(const doublereal temp, const doublereal pres, const int ifunc) const {
01129     doublereal gval = g(temp, pres, ifunc);
01130     doublereal fval = f(temp, pres, ifunc);
01131     double res = gval - fval;
01132 #ifdef DEBUG_MODE_NOT
01133     if (ifunc == 2) {
01134       double gval1  = g(temp, pres, 1);
01135       double fval1  = f(temp, pres, 1);
01136       double gval2  = g(temp + 0.001, pres, 1);
01137       double fval2  = f(temp + 0.001, pres, 1);
01138       double gvalT  = (gval2 - gval1) / 0.001;
01139       double fvalT  = (fval2 - fval1) / 0.001;
01140       if (fabs(gvalT - gval) > 1.0E-9) {
01141         printf("we are here\n");
01142       }
01143       if (fabs(fvalT - fval) > 1.0E-9) {
01144         printf("we are here\n");
01145       }
01146       // return gvalT - fvalT;
01147     }
01148 #endif
01149     return res;
01150   }
01151 
01152 
01153 #ifdef OLDWAY
01154 
01155   /* awData structure */
01156   /*!
01157    * Database for atomic molecular weights
01158    *
01159    *  Values are taken from the 1989 Standard Atomic Weights, CRC
01160    *
01161    *  awTable[] is a static function with scope limited to this file.
01162    *  It can only be referenced via the static Elements class function,
01163    *  LookupWtElements().
01164    *
01165    *  units = kg / kg-mol (or equivalently gm / gm-mol)
01166    *
01167    * (note: this structure was picked because it's simple, compact,
01168    *          and extensible).
01169    *
01170    */
01171   struct GeData {
01172     char name[4];     ///< Null Terminated name, First letter capitalized
01173     doublereal GeValue;   /// < Gibbs free energies of elements J kmol-1
01174   };
01175 
01176   //! Values of G_elements(T=298.15,1atm) 
01177   /*!
01178    *  all units are Joules kmol-1
01179    */
01180 
01181   static struct GeData geDataTable[] = {
01182     {"H",   -19.48112E6}, // NIST Webbook - Cox, Wagman 1984
01183     {"Na",  -15.29509E6}, // NIST Webbook - Cox, Wagman 1984
01184     {"O",   -30.58303E6}, // NIST Webbook - Cox, Wagman 1984
01185     {"Cl",  -33.25580E6}, // NIST Webbook - Cox, Wagman 1984
01186     {"Si",   -5.61118E6}, // Janaf
01187     {"C",    -1.71138E6}, // barin, Knack, NBS Bulletin 1971
01188     {"S",    -9.55690E6}, // Yellow - webbook
01189     {"Al",   -8.42870E6}, // Webbook polynomial
01190     {"K",   -19.26943E6}, // Webbook
01191     {"Fe",   -8.142476E6}, // Nist  Webbook - Cox, Wagman 1984
01192     {"E",    0.0}         // Don't overcount
01193   };
01194 #endif
01195   //!  Static function to look up Element Free Energies
01196   /*!
01197    *
01198    *   This static function looks up the argument string in the
01199    *   database above and returns the associated Gibbs Free energies.
01200    *
01201    *  @param  elemName  String. Only the first 3 characters are significant
01202    *
01203    *  @return
01204    *    Return value contains the Gibbs free energy for that element
01205    *
01206    *  @exception CanteraError
01207    *    If a match is not found, a CanteraError is thrown as well
01208    */
01209   doublereal PDSS_HKFT::LookupGe(const std::string& elemName) {
01210 #ifdef OLDWAY
01211     int num = sizeof(geDataTable) / sizeof(struct GeData);
01212     string s3 = elemName.substr(0,3);
01213     for (int i = 0; i < num; i++) {
01214       //if (!std::strncmp(elemName.c_str(), aWTable[i].name, 3)) {
01215       if (s3 == geDataTable[i].name) {
01216         return (geDataTable[i].GeValue);
01217       }
01218     }
01219     throw CanteraError("LookupGe", "element " + s + " not found");
01220     return -1.0;
01221 #else
01222     int iE = m_tp->elementIndex(elemName);
01223     if (iE < 0) {
01224       throw CanteraError("PDSS_HKFT::LookupGe", "element " + elemName + " not found");
01225     }
01226     doublereal geValue = m_tp->entropyElement298(iE);
01227     if (geValue == ENTROPY298_UNKNOWN) {
01228       throw CanteraError("PDSS_HKFT::LookupGe", 
01229                          "element " + elemName + " doesn not have a supplied entropy298");
01230     }
01231     geValue *= (-298.15);
01232     return geValue;
01233 #endif
01234   }
01235 
01236  void PDSS_HKFT::convertDGFormation() {
01237     /*
01238      * Ok let's get the element compositions and conversion factors.
01239      */
01240     int ne = m_tp->nElements();
01241     doublereal na;
01242     doublereal ge;
01243     string ename;
01244 
01245     doublereal totalSum = 0.0;
01246     for (int m = 0; m < ne; m++) {
01247       na = m_tp->nAtoms(m_spindex, m);
01248       if (na > 0.0) {
01249         ename = m_tp->elementName(m);
01250         ge = LookupGe(ename);
01251         totalSum += na * ge;
01252       }
01253     }
01254     // Add in the charge
01255     if (m_charge_j != 0.0) {
01256       ename = "H";
01257       ge = LookupGe(ename);
01258       totalSum -= m_charge_j * ge;
01259     }
01260     // Ok, now do the calculation. Convert to joules kmol-1
01261     doublereal dg = m_deltaG_formation_tr_pr * 4.184 * 1.0E3;
01262     //! Store the result into an internal variable.
01263     m_Mu0_tr_pr = dg + totalSum;
01264   }
01265   
01266   // This utility function reports back the type of
01267   // parameterization and all of the parameters for the
01268   // species, index.
01269   /*
01270    *
01271    * @param index     Species index
01272    * @param type      Integer type of the standard type
01273    * @param c         Vector of coefficients used to set the
01274    *                  parameters for the standard state.
01275    * @param minTemp   output - Minimum temperature
01276    * @param maxTemp   output - Maximum temperature
01277    * @param refPressure output - reference pressure (Pa).
01278    *
01279    */
01280   void PDSS_HKFT::reportParams(int &kindex, int &type,
01281                             doublereal * const c,
01282                             doublereal &minTemp,
01283                             doublereal &maxTemp,
01284                             doublereal &refPressure) const {
01285 
01286     // Fill in the first part
01287     PDSS::reportParams(kindex, type, c, minTemp, maxTemp,
01288                        refPressure);
01289 
01290 
01291     c[0] = m_deltaG_formation_tr_pr;
01292     c[1] = m_deltaH_formation_tr_pr;
01293     c[2] = m_Mu0_tr_pr;
01294     c[3] = m_Entrop_tr_pr;
01295     c[4] =  m_a1;
01296     c[5] =  m_a2;
01297     c[6] =  m_a3;
01298     c[7] =  m_a4;
01299     c[8] =  m_c1;
01300     c[9] =  m_c2;
01301     c[10] = m_omega_pr_tr;
01302 
01303   }
01304 
01305 
01306 
01307 }
Generated by  doxygen 1.6.3