/* * Create a new ThermoPhase object and initializes it according to * the XML tree database. This routine first looks up the * identity of the model for the solution thermodynamics in the * model attribute of the thermo child of the xml phase * node. Then, it does a string lookup on the model to figure out * what ThermoPhase derived class is assigned. It creates a new * instance of that class, and then calls importPhase() to * populate that class with the correct parameters from the XML * tree. */ ThermoPhase* newPhase(XML_Node& xmlphase) { const XML_Node& th = xmlphase.child("thermo"); string model = th["model"]; ThermoPhase* t = newThermoPhase(model); #ifdef WITH_ELECTROLYTES if (model == "HMW") { HMWSoln* p = (HMWSoln*)t; p->constructPhaseXML(xmlphase,""); } else #endif importPhase(xmlphase, t); return t; }
ThermoPhase* newPhase(XML_Node& xmlphase) { string model = xmlphase.child("thermo")["model"]; ThermoPhase* t = newThermoPhase(model); if (model == "singing cows") { throw CanteraError("ThermoPhase::newPhase", "Cows don't sing"); } else if (model == "HMW") { HMWSoln* p = dynamic_cast<HMWSoln*>(t); p->constructPhaseXML(xmlphase,""); } else if (model == "IonsFromNeutralMolecule") { IonsFromNeutralVPSSTP* p = dynamic_cast<IonsFromNeutralVPSSTP*>(t); p->constructPhaseXML(xmlphase,""); } else { importPhase(xmlphase, t); } return t; }
static void set_hmw_interactions(HMWSoln& p) { double beta0_nacl[] = {0.0765, 0.008946, -3.3158E-6, -777.03, -4.4706}; double beta1_nacl[] = {0.2664, 6.1608E-5, 1.0715E-6, 0.0, 0.0}; double beta2_nacl[] = {0.0, 0.0, 0.0, 0.0, 0.0}; double cphi_nacl[] = {0.00127, -4.655E-5, 0.0, 33.317, 0.09421}; p.setBinarySalt("Na+", "Cl-", 5, beta0_nacl, beta1_nacl, beta2_nacl, cphi_nacl, 2.0, 0.0); double beta0_hcl[] = {0.1775, 0.0, 0.0, 0.0, 0.0}; double beta1_hcl[] = {0.2945, 0.0, 0.0, 0.0, 0.0}; double beta2_hcl[] = {0.0, 0.0, 0.0, 0.0, 0.0}; double cphi_hcl[] = {0.0008, 0.0, 0.0, 0.0, 0.0}; p.setBinarySalt("H+", "Cl-", 5, beta0_hcl, beta1_hcl, beta2_hcl, cphi_hcl, 2.0, 0.0); double beta0_naoh[] = {0.0864, 0.0, 0.0, 0.0, 0.0}; double beta1_naoh[] = {0.253, 0.0, 0.0, 0.0, 0.0}; double beta2_naoh[] = {0.0, 0.0, 0.0, 0.0, 0.0}; double cphi_naoh[] = {0.0044, 0.0, 0.0, 0.0, 0.0}; p.setBinarySalt("Na+", "OH-", 5, beta0_naoh, beta1_naoh, beta2_naoh, cphi_naoh, 2.0, 0.0); double theta_cloh[] = {-0.05, 0.0, 0.0, 0.0, 0.0}; double psi_nacloh[] = {-0.006, 0.0, 0.0, 0.0, 0.0}; double theta_nah[] = {0.036, 0.0, 0.0, 0.0, 0.0}; double psi_clnah[] = {-0.004, 0.0, 0.0, 0.0, 0.0}; p.setTheta("Cl-", "OH-", 5, theta_cloh); p.setPsi("Na+", "Cl-", "OH-", 5, psi_nacloh); p.setTheta("Na+", "H+", 5, theta_nah); p.setPsi("Cl-", "Na+", "H+", 5, psi_clnah); }
/* * Create a new ThermoPhase object and initializes it according to * the XML tree database. This routine first looks up the * identity of the model for the solution thermodynamics in the * model attribute of the thermo child of the xml phase * node. Then, it does a string lookup on the model to figure out * what ThermoPhase derived class is assigned. It creates a new * instance of that class, and then calls importPhase() to * populate that class with the correct parameters from the XML * tree. */ ThermoPhase* newPhase(XML_Node& xmlphase) { const XML_Node& th = xmlphase.child("thermo"); string model = th["model"]; ThermoPhase* t = newThermoPhase(model); if (model == "singing cows") { throw CanteraError(" newPhase", "Cows don't sing"); } #ifdef WITH_ELECTROLYTES else if (model == "HMW") { HMWSoln* p = dynamic_cast<HMWSoln*>(t); p->constructPhaseXML(xmlphase,""); } #endif #ifdef WITH_IDEAL_SOLUTIONS else if (model == "IonsFromNeutralMolecule") { IonsFromNeutralVPSSTP* p = dynamic_cast<IonsFromNeutralVPSSTP*>(t); p->constructPhaseXML(xmlphase,""); } #endif else { importPhase(xmlphase, t); } return t; }
int main(int argc, char** argv) { int retn = 0; size_t i; try { std::string iFile = (argc > 1) ? argv[1] : "HMW_NaCl.xml"; double V0[20], pmV[20]; HMWSoln* HMW = new HMWSoln(iFile, "NaCl_electrolyte"); /* * Load in and initialize the */ Cantera::thermo_t* solid = newPhase<doublereal>("NaCl_Solid.xml","NaCl(S)"); size_t nsp = HMW->nSpecies(); //double acMol[100]; //double act[100]; double mf[100]; double moll[100]; HMW->getMoleFractions(mf); string sName; TemperatureTable TTable(15, false, 273.15, 25., 0, 0); HMW->setState_TP(298.15, 1.01325E5); size_t i1 = HMW->speciesIndex("Na+"); size_t i2 = HMW->speciesIndex("Cl-"); //int i3 = HMW->speciesIndex("H2O(L)"); for (i = 0; i < nsp; i++) { moll[i] = 0.0; } HMW->setMolalities(moll); /* * Set the Pressure */ double pres = OneAtm; /* * Fix the molality */ double Is = 6.146; moll[i1] = Is; moll[i2] = Is; HMW->setState_TPM(298.15, pres, moll); double Xmol[30]; HMW->getMoleFractions(Xmol); double meanMW = HMW->meanMolecularWeight(); /* * ThermoUnknowns */ double T; double V0_NaCl = 0.0, V0_Naplus = 0.0, V0_Clminus = 0.0, Delta_V0s = 0.0, V0_H2O = 0.0; double V_NaCl = 0.0, V_Naplus = 0.0, V_Clminus = 0.0, V_H2O = 0.0; double molarV0; #ifdef DEBUG_HKM FILE* ttt = fopen("table.csv","w"); #endif printf("A_V : Comparison to Pitzer's book, p. 99, can be made.\n"); printf(" Agreement to 3 sig digits \n"); printf("\n"); printf("Delta_V0: Heat Capacity of Solution per mole of salt (standard states)\n"); printf(" rxn for the ss heat of soln: " "NaCl(s) -> Na+(aq) + Cl-(aq)\n"); printf("\n"); printf("Delta_Vs: Delta volume of Solution per mole of salt\n"); printf(" rxn for heat of soln: " " n1 H2O(l,pure) + n2 NaCl(s) -> n2 MX(aq) + n1 H2O(l) \n"); printf(" Delta_Hs = (n1 h_H2O_bar + n2 h_MX_bar " "- n1 h_H2O_0 - n2 h_MX_0)/n2\n"); printf("\n"); printf("phiV: phiV, calculated from the program, is checked\n"); printf(" against analytical formula in V_standalone program.\n"); printf(" (comparison against Pitzer book, p. 97, eqn. 96)\n"); /* * Create a Table of NaCl Enthalpy Properties as a Function * of the Temperature */ printf("\n\n"); printf(" T, Pres, Aphi, A_V," " Delta_V0," " Delta_Vs, Vex, phiV," " MolarV, MolarV0\n"); printf(" Kelvin, bar, sqrt(kg/gmol),sqrt(kg/gmol)cm3/gmol," "cm**3/gmolSalt," "cm**3/gmolSalt,cm**3/gmolSoln,cm**3/gmolSalt," "cm**3/gmol, cm**3/gmol\n"); #ifdef DEBUG_HKM fprintf(ttt,"T, Pres, A_V, Vex, phiV, MolarV, MolarV0\n"); fprintf(ttt,"Kelvin, bar, sqrt(kg/gmol)cm3/gmol, cm3/gmolSoln, cm3/gmolSalt, kJ/gmolSoln," "kJ/gmolSoln\n"); #endif for (i = 0; i < TTable.NPoints + 1; i++) { if (i == TTable.NPoints) { T = 323.15; } else { T = TTable.T[i]; } /* * RT is in units of J/kmolK */ //double RT = GasConstant * T; /* * Make sure we are at the saturation pressure or above. */ double psat = HMW->satPressure(T); pres = OneAtm; if (psat > pres) { pres = psat; } HMW->setState_TPM(T, pres, moll); solid->setState_TP(T, pres); /* * Get the Standard State volumes m3/kmol */ solid->getStandardVolumes(V0); V0_NaCl = V0[0]; HMW->getStandardVolumes(V0); V0_H2O = V0[0]; V0_Naplus = V0[i1]; V0_Clminus = V0[i2]; /* * Calculate the standard state volume change of solution * for NaCl(s) -> Na+ + Cl- * units: m3 / kmol */ Delta_V0s = V0_Naplus + V0_Clminus - V0_NaCl; double dd = solid->density(); double MW_NaCl = solid->meanMolecularWeight(); V_NaCl = MW_NaCl / dd; //printf("V_NaCl = %g , V0_NaCl = %g %g\n", V_NaCl, V0_NaCl, 1.0/solid->molarDensity()); /* * Get the partial molar volumes */ HMW->getPartialMolarVolumes(pmV); V_H2O = pmV[0]; V_Naplus = pmV[i1]; V_Clminus = pmV[i2]; //double Delta_V_Salt = V_NaCl - (V_Naplus + V_Clminus); /* * Calculate the molar volume of solution */ double dsoln = HMW->density(); meanMW = HMW->meanMolecularWeight(); double molarV = meanMW / dsoln; //double md = HMW->molarDensity(); //printf("compare %g %g\n", molarV, 1.0/md); /* * Calculate the delta volume of solution for the reaction * NaCl(s) -> Na+ + Cl- */ double Delta_Vs = (Xmol[0] * V_H2O + Xmol[i1] * V_Naplus + Xmol[i2] * V_Clminus - Xmol[0] * V0_H2O - Xmol[i1] * V_NaCl); Delta_Vs /= Xmol[i1]; /* * Calculate the apparent molar volume, J, from the * partial molar quantities, units m3/kmol */ double Vex = (Xmol[0] * (V_H2O - V0_H2O) + Xmol[i1] * (V_Naplus - V0_Naplus) + Xmol[i2] * (V_Clminus - V0_Clminus)); /* * Calculate the apparent relative molal volume, phiV, * units of m3/kmol */ double phiV = Vex / Xmol[i1]; double Aphi = HMW->A_Debye_TP(T, pres) / 3.0; //double AL = HMW->ADebye_L(T,pres); double Av = HMW->ADebye_V(T, pres) * 1.0E3; molarV0 = 0.0; for (size_t k = 0; k < nsp; k++) { molarV0 += Xmol[k] * V0[k]; } if (i != TTable.NPoints+1) { printf("%13.4g, %13.4g, %13.4g, %13.4g, %13.4g, %13.4g, " "%13.5g, %13.4g, %13.4g, %13.4g\n", T, pres*1.0E-5, Aphi, Av, Delta_V0s*1.0E3, Delta_Vs*1.0E3, Vex*1.0E3, phiV*1.0E3, molarV*1.0E3 , molarV0*1.0E3); #ifdef DEBUG_HKM fprintf(ttt,"%g, %g, %g, %g, %g, %g, %g\n", T, pres*1.0E-5, Av, Vex*1.0E3, phiV*1.0E3, molarV*1.0E3 , molarV0*1.0E3); #endif } } printf("Breakdown of Volume Calculation at 323.15 K, 1atm:\n"); printf(" Species MoleFrac Molal V0 " " partV (partV - V0)\n"); printf(" H2O(L)"); printf("%13.4g %13.4g %13.4g %13.4g %13.4g\n", Xmol[0], moll[0], V0_H2O*1.E3, V_H2O*1.E3, (V_H2O-V0_H2O)*1.E3); printf(" Na+ "); printf("%13.4g %13.4g %13.4g %13.4g %13.4g\n", Xmol[i1], moll[i1], V0_Naplus*1.E3 , V_Naplus*1.E3, (V_Naplus -V0_Naplus)*1.E3); printf(" Cl- "); printf("%13.4g %13.4g %13.4g %13.4g %13.4g\n", Xmol[i2], moll[i2], V0_Clminus*1.E3, V_Clminus*1.E3, (V_Clminus - V0_Clminus)*1.E3); printf(" NaCl(s)"); double dd = V_NaCl*1.E3 - V0_NaCl*1.E3; if (fabs(dd) < 1.0E-12) { dd = 0.0; } printf("%13.4g %13.4g %13.4g %13.4g\n", 1.0, V0_NaCl*1.E3 , V_NaCl*1.E3, dd); delete HMW; HMW = 0; delete solid; solid = 0; Cantera::appdelete(); #ifdef DEBUG_HKM fclose(ttt); #endif return retn; } catch (CanteraError& err) { std::cout << err.what() << std::endl; Cantera::appdelete(); return -1; } }
int main(int argc, char** argv) { int retn = 0; size_t i; try { std::string iFile = (argc > 1) ? argv[1] : "HMW_NaCl.xml"; double Cp0_R[20], pmCp[20]; HMWSoln* HMW = new HMWSoln(iFile, "NaCl_electrolyte"); /* * Load in and initialize the */ Cantera::thermo_t* solid = newPhase<doublereal>("NaCl_Solid.xml","NaCl(S)"); size_t nsp = HMW->nSpecies(); double mf[100]; double moll[100]; for (i = 0; i < 100; i++) { mf[i] = 0.0; } HMW->getMoleFractions(mf); string sName; TemperatureTable TTable(15, false, 273.15, 25., 0, 0); HMW->setState_TP(298.15, 1.01325E5); size_t i1 = HMW->speciesIndex("Na+"); size_t i2 = HMW->speciesIndex("Cl-"); //int i3 = HMW->speciesIndex("H2O(L)"); for (i = 0; i < nsp; i++) { moll[i] = 0.0; } HMW->setMolalities(moll); double Is = 0.0; /* * Set the Pressure */ double pres = OneAtm; /* * Fix the molality */ Is = 6.146; moll[i1] = Is; moll[i2] = Is; HMW->setState_TPM(298.15, pres, moll); double Xmol[30]; HMW->getMoleFractions(Xmol); /* * ThermoUnknowns */ double T; double Cp0_NaCl = 0.0, Cp0_Naplus = 0.0, Cp0_Clminus = 0.0, Delta_Cp0s = 0.0, Cp0_H2O = 0.0; double Cp_NaCl = 0.0, Cp_Naplus = 0.0, Cp_Clminus = 0.0, Cp_H2O = 0.0; double molarCp0; #ifdef DEBUG_HKM FILE* ttt = fopen("table.csv","w"); #endif printf("A_J/R: Comparison to Pitzer's book, p. 99, can be made.\n"); printf(" Agreement is within 12 pc \n"); printf("\n"); printf("Delta_Cp0: Heat Capacity of Solution per mole of salt (standard states)\n"); printf(" rxn for the ss heat of soln: " "NaCl(s) -> Na+(aq) + Cl-(aq)\n"); printf("\n"); printf("Delta_Cps: Delta heat Capacity of Solution per mole of salt\n"); printf(" rxn for heat of soln: " " n1 H2O(l,pure) + n2 NaCl(s) -> n2 MX(aq) + n1 H2O(l) \n"); printf(" Delta_Hs = (n1 h_H2O_bar + n2 h_MX_bar " "- n1 h_H2O_0 - n2 h_MX_0)/n2\n"); printf("\n"); printf("phiJ: phiJ, calculated from the program, is checked\n"); printf(" against analytical formula in J_standalone program.\n"); printf(" (comparison against Eq. 12, Silvester and Pitzer)\n"); /* * Create a Table of NaCl Enthalpy Properties as a Function * of the Temperature */ printf("\n\n"); printf(" T, Pres, Aphi, A_J/R," " Delta_Cp0," " Delta_Cps, J, phiJ," " MolarCp, MolarCp0\n"); printf(" Kelvin, bar, sqrt(kg/gmol), sqrt(kg/gmol)," " kJ/gmolSalt," " kJ/gmolSalt, kJ/gmolSoln, kJ/gmolSalt," " kJ/gmol, kJ/gmol\n"); #ifdef DEBUG_HKM fprintf(ttt,"T, Pres, A_J/R, Delta_Cp0, Delta_Cps, J, phiJ\n"); fprintf(ttt,"Kelvin, bar, sqrt(kg/gmol), kJ/gmolSalt, kJ/gmolSalt, kJ/gmolSoln," "kJ/gmolSalt\n"); #endif for (i = 0; i < TTable.NPoints + 1; i++) { if (i == TTable.NPoints) { T = 323.15; } else { T = TTable.T[i]; } /* * RT is in units of J/kmolK */ //double RT = GasConstant * T; /* * Make sure we are at the saturation pressure or above. */ double psat = HMW->satPressure(T); pres = OneAtm; if (psat > pres) { pres = psat; } HMW->setState_TPM(T, pres, moll); solid->setState_TP(T, pres); /* * Get the Standard State DeltaH */ solid->getCp_R(Cp0_R); Cp0_NaCl = Cp0_R[0] * GasConstant * 1.0E-6; HMW->getCp_R(Cp0_R); Cp0_H2O = Cp0_R[0] * GasConstant * 1.0E-6; Cp0_Naplus = Cp0_R[i1] * GasConstant * 1.0E-6; Cp0_Clminus = Cp0_R[i2] * GasConstant * 1.0E-6; /* * Calculate the standard state heat of solution * for NaCl(s) -> Na+ + Cl- * units: kJ/gmolSalt */ Delta_Cp0s = Cp0_Naplus + Cp0_Clminus - Cp0_NaCl; pmCp[0] = solid->cp_mole(); Cp_NaCl = pmCp[0] * 1.0E-6; HMW->getPartialMolarCp(pmCp); Cp_H2O = pmCp[0] * 1.0E-6; Cp_Naplus = pmCp[i1] * 1.0E-6; Cp_Clminus = pmCp[i2] * 1.0E-6; //double Delta_Cp_Salt = Cp_NaCl - (Cp_Naplus + Cp_Clminus); double molarCp = HMW->cp_mole() * 1.0E-6; /* * Calculate the heat capacity of solution for the reaction * NaCl(s) -> Na+ + Cl- */ double Delta_Cps = (Xmol[0] * Cp_H2O + Xmol[i1] * Cp_Naplus + Xmol[i2] * Cp_Clminus - Xmol[0] * Cp0_H2O - Xmol[i1] * Cp_NaCl); Delta_Cps /= Xmol[i1]; /* * Calculate the relative heat capacity, J, from the * partial molar quantities, units J/gmolSolutionK */ double J = (Xmol[0] * (Cp_H2O - Cp0_H2O) + Xmol[i1] * (Cp_Naplus - Cp0_Naplus) + Xmol[i2] * (Cp_Clminus - Cp0_Clminus)); /* * Calculate the apparent relative molal heat capacity, phiJ, * units of J/gmolSaltAddedK */ double phiJ = J / Xmol[i1]; double Aphi = HMW->A_Debye_TP(T, pres) / 3.0; //double AL = HMW->ADebye_L(T,pres); double AJ = HMW->ADebye_J(T, pres); for (size_t k = 0; k < nsp; k++) { Cp0_R[k] *= GasConstant * 1.0E-6; } molarCp0 = 0.0; for (size_t k = 0; k < nsp; k++) { molarCp0 += Xmol[k] * Cp0_R[k]; } if (i != TTable.NPoints+1) { printf("%13.5g, %13.5g, %13.5g, %13.5g, %13.5g, %13.5g, " "%13.5g, %13.5g, %13.5g, %13.5g\n", T, pres*1.0E-5, Aphi, AJ/GasConstant, Delta_Cp0s, Delta_Cps, J, phiJ, molarCp , molarCp0); #ifdef DEBUG_HKM fprintf(ttt,"%g, %g, %g, %g, %g, %g, %g\n", T, pres*1.0E-5, AJ/GasConstant, Delta_Cp0s, Delta_Cps, J, phiJ); #endif } } printf("Breakdown of Heat Capacity Calculation at 323.15 K, 1atm:\n"); printf(" Species MoleFrac Molal Cp0 " " partCp (partCp - Cp0)\n"); printf(" H2O(L)"); printf("%13.5g %13.5g %13.5g %13.5g %13.5g\n", Xmol[0], moll[0], Cp0_H2O , Cp_H2O, Cp_H2O-Cp0_H2O); printf(" Na+ "); printf("%13.5g %13.5g %13.5g %13.5g %13.5g\n", Xmol[i1], moll[i1], Cp0_Naplus , Cp_Naplus, Cp_Naplus -Cp0_Naplus); printf(" Cl- "); printf("%13.5g %13.5g %13.5g %13.5g %13.5g\n", Xmol[i2], moll[i2], Cp0_Clminus , Cp_Clminus, Cp_Clminus - Cp0_Clminus); printf(" NaCl(s)"); printf("%13.5g %13.5g %13.5g %13.5g\n", 1.0, Cp0_NaCl , Cp_NaCl, Cp_NaCl - Cp0_NaCl); delete HMW; HMW = 0; delete solid; solid = 0; Cantera::appdelete(); #ifdef DEBUG_HKM fclose(ttt); #endif return retn; } catch (CanteraError& err) { std::cout << err.what() << std::endl; Cantera::appdelete(); return -1; } }
int main(int argc, char **argv) { #ifdef _MSC_VER _set_output_format(_TWO_DIGIT_EXPONENT); #endif int retn = 0; try { HMWSoln *HMW = new HMWSoln(1); #ifdef DEBUG_MODE CHECK_DEBUG_MODE = 1; #endif if (CHECK_DEBUG_MODE == 1) { HMW->m_debugCalc = 1; if (HMW->debugPrinting()) { FILE *ff = fopen("CheckDebug.txt", "w"); fprintf(ff,"%1d\n", 1); fclose(ff); } HMW->m_debugCalc = 0; } int nsp = HMW->nSpecies(); double a1 = HMW->AionicRadius(1); printf("a1 = %g\n", a1); double a2 = HMW->AionicRadius(2); printf("a2 = %g\n", a2); double mu0[100]; double moll[100]; string sName; HMW->getMolalities(moll); moll[1] = 6.0997; moll[2] = 2.1628E-9; moll[3] = 6.0997; moll[4] =1.3977E-6; /* * Equalize charge balance and dump into Cl- */ double sum = -moll[1] + moll[2] + moll[3] - moll[4]; moll[1] += sum; HMW->setMolalities(moll); HMW->setState_TP(298.15, 1.01325E5); pAtable(HMW); HMW->setState_TP(298.15, 1.01325E5); HMW->getStandardChemPotentials(mu0); // translate from J/kmol to kJ/gmol int k; for (k = 0; k < nsp; k++) { mu0[k] *= 1.0E-6; } printf(" Species Standard chemical potentials (kJ/gmol) \n"); printf("------------------------------------------------------------\n"); for (k = 0; k < nsp; k++) { sName = HMW->speciesName(k); printf("%16s %16.9g\n", sName.c_str(), mu0[k]); } printf("------------------------------------------------------------\n"); printf(" Some DeltaSS values: Delta(mu_0)\n"); double deltaG; int i1, i2, j1; double RT = 8.314472E-3 * 298.15; i1 = HMW->speciesIndex("Na+"); i2 = HMW->speciesIndex("Cl-"); deltaG = -432.6304 - mu0[i1] - mu0[i2]; printf(" NaCl(S): Na+ + Cl- -> NaCl(S): %14.7g kJ/gmol \n", deltaG); printf(" : %14.7g (dimensionless) \n", deltaG/RT); printf(" : %14.7g (dimensionless/ln10) \n", deltaG/(RT * log(10.0))); printf(" G0(NaCl(S)) = %14.7g (fixed)\n", -432.6304); printf(" G0(Na+) = %14.7g\n", mu0[i1]); printf(" G0(Cl-) = %14.7g\n", mu0[i2]); i1 = HMW->speciesIndex("H+"); i2 = HMW->speciesIndex("H2O(L)"); j1 = HMW->speciesIndex("OH-"); if (i1 < 0 || i2 < 0 || j1 < 0) { printf("problems\n"); exit(-1); } deltaG = mu0[j1] + mu0[i1] - mu0[i2]; printf(" OH-: H2O(L) - H+ -> OH-: %14.7g kJ/gmol \n", deltaG); printf(" : %14.7g (dimensionless) \n", deltaG/RT); printf(" : %14.7g (dimensionless/ln10) \n", deltaG/(RT * log(10.0))); printf(" G0(OH-) = %14.7g\n", mu0[j1]); printf(" G0(H+) = %14.7g\n", mu0[i1]); printf(" G0(H2O(L)) = %14.7g\n", mu0[i2]); printf("------------------------------------------------------------\n"); delete HMW; HMW = 0; Cantera::appdelete(); return retn; } catch (CanteraError) { showErrors(); return -1; } }
int main(int argc, char** argv) { #if defined(_MSC_VER) && _MSC_VER < 1900 _set_output_format(_TWO_DIGIT_EXPONENT); #endif int retn = 0; try { HMWSoln* HMW = new HMWSoln("HMW_NaCl.xml"); HMW->printCoeffs(); size_t nsp = HMW->nSpecies(); double a1 = HMW->AionicRadius(1); printf("a1 = %g\n", a1); double a2 = HMW->AionicRadius(2); printf("a2 = %g\n", a2); double mu0[100]; double moll[100]; string sName; HMW->getMolalities(moll); moll[1] = 6.0997; moll[2] = 2.1628E-9; moll[3] = 6.0997; moll[4] =1.3977E-6; /* * Equalize charge balance and dump into Cl- */ double sum = -moll[1] + moll[2] + moll[3] - moll[4]; moll[1] += sum; HMW->setMolalities(moll); HMW->setState_TP(298.15, 1.01325E5); pAtable(HMW); HMW->setState_TP(298.15, 1.01325E5); HMW->getStandardChemPotentials(mu0); // translate from J/kmol to kJ/gmol for (size_t k = 0; k < nsp; k++) { mu0[k] *= 1.0E-6; } printf(" Species Standard chemical potentials (kJ/gmol) \n"); printf("------------------------------------------------------------\n"); for (size_t k = 0; k < nsp; k++) { sName = HMW->speciesName(k); printf("%16s %16.9g\n", sName.c_str(), mu0[k]); } printf("------------------------------------------------------------\n"); printf(" Some DeltaSS values: Delta(mu_0)\n"); double deltaG; size_t i1, i2, j1; double RT = 8.314472E-3 * 298.15; i1 = HMW->speciesIndex("Na+"); i2 = HMW->speciesIndex("Cl-"); deltaG = -432.6304 - mu0[i1] - mu0[i2]; printf(" NaCl(S): Na+ + Cl- -> NaCl(S): %14.7g kJ/gmol \n", deltaG); printf(" : %14.7g (dimensionless) \n", deltaG/RT); printf(" : %14.7g (dimensionless/ln10) \n", deltaG/(RT * log(10.0))); printf(" G0(NaCl(S)) = %14.7g (fixed)\n", -432.6304); printf(" G0(Na+) = %14.7g\n", mu0[i1]); printf(" G0(Cl-) = %14.7g\n", mu0[i2]); i1 = HMW->speciesIndex("H+"); i2 = HMW->speciesIndex("H2O(L)"); j1 = HMW->speciesIndex("OH-"); if (i1 == npos || i2 == npos || j1 == npos) { printf("problems\n"); exit(-1); } deltaG = mu0[j1] + mu0[i1] - mu0[i2]; printf(" OH-: H2O(L) - H+ -> OH-: %14.7g kJ/gmol \n", deltaG); printf(" : %14.7g (dimensionless) \n", deltaG/RT); printf(" : %14.7g (dimensionless/ln10) \n", deltaG/(RT * log(10.0))); printf(" G0(OH-) = %14.7g\n", mu0[j1]); printf(" G0(H+) = %14.7g\n", mu0[i1]); printf(" G0(H2O(L)) = %14.7g\n", mu0[i2]); printf("------------------------------------------------------------\n"); delete HMW; HMW = 0; Cantera::appdelete(); return retn; } catch (CanteraError& err) { std::cout << err.what() << std::endl; return -1; } }
TEST(HMWSoln, fromScratch_HKFT) { HMWSoln p; auto sH2O = make_species("H2O(l)", "H:2, O:1", h2oliq_nasa_coeffs); auto sNa = make_species("Na+", "Na:1, E:-1", 0.0, 298.15, -125.5213, 333.15, -125.5213, 1e5); sNa->charge = 1; auto sCl = make_species("Cl-", "Cl:1, E:1", 0.0, 298.15, -52.8716, 333.15, -52.8716, 1e5); sCl->charge = -1; auto sH = make_species("H+", "H:1, E:-1", 0.0, 298.15, 0.0, 333.15, 0.0, 1e5); sH->charge = 1; auto sOH = make_species("OH-", "O:1, H:1, E:1", 0.0, 298.15, -91.523, 333.15, -91.523, 1e5); sOH->charge = -1; for (auto& s : {sH2O, sNa, sCl, sH, sOH}) { p.addSpecies(s); } double h0[] = {-57433, Undef, 0.0, -54977}; double g0[] = {Undef, -31379, 0.0, -37595}; double s0[] = {13.96, 13.56, Undef, -2.56}; double a[][4] = {{0.1839, -228.5, 3.256, -27260}, {0.4032, 480.1, 5.563, -28470}, {0.0, 0.0, 0.0, 0.0}, {0.12527, 7.38, 1.8423, -27821}}; double c[][2] = {{18.18, -29810}, {-4.4, -57140}, {0.0, 0.0}, {4.15, -103460}}; double omega[] = {33060, 145600, 0.0, 172460}; std::unique_ptr<PDSS_Water> ss(new PDSS_Water()); p.installPDSS(0, std::move(ss)); for (size_t k = 0; k < 4; k++) { std::unique_ptr<PDSS_HKFT> ss(new PDSS_HKFT()); if (h0[k] != Undef) { ss->setDeltaH0(h0[k] * toSI("cal/gmol")); } if (g0[k] != Undef) { ss->setDeltaG0(g0[k] * toSI("cal/gmol")); } if (s0[k] != Undef) { ss->setS0(s0[k] * toSI("cal/gmol/K")); } a[k][0] *= toSI("cal/gmol/bar"); a[k][1] *= toSI("cal/gmol"); a[k][2] *= toSI("cal-K/gmol/bar"); a[k][3] *= toSI("cal-K/gmol"); c[k][0] *= toSI("cal/gmol/K"); c[k][1] *= toSI("cal-K/gmol"); ss->set_a(a[k]); ss->set_c(c[k]); ss->setOmega(omega[k] * toSI("cal/gmol")); p.installPDSS(k+1, std::move(ss)); } p.setPitzerTempModel("complex"); p.setA_Debye(-1); p.initThermo(); set_hmw_interactions(p); p.setMolalitiesByName("Na+:6.0954 Cl-:6.0954 H+:2.1628E-9 OH-:1.3977E-6"); p.setState_TP(50 + 273.15, 101325); size_t N = p.nSpecies(); vector_fp mv(N), h(N), mu(N), ac(N), acoeff(N); p.getPartialMolarVolumes(mv.data()); p.getPartialMolarEnthalpies(h.data()); p.getChemPotentials(mu.data()); p.getActivities(ac.data()); p.getActivityCoefficients(acoeff.data()); double mvRef[] = {0.01815224, 0.00157182, 0.01954605, 0.00173137, -0.0020266}; for (size_t k = 0; k < N; k++) { EXPECT_NEAR(mv[k], mvRef[k], 2e-8); } }
TEST(HMWSoln, fromScratch) { // Regression test based on HMW_test_3 HMWSoln p; auto sH2O = make_species("H2O(l)", "H:2, O:1", h2oliq_nasa_coeffs); auto sCl = make_species("Cl-", "Cl:1, E:1", 0.0, 298.15, -52.8716, 333.15, -52.8716, 1e5); sCl->charge = -1; auto sH = make_species("H+", "H:1, E:-1", 0.0, 298.15, 0.0, 333.15, 0.0, 1e5); sH->charge = 1; auto sNa = make_species("Na+", "Na:1, E:-1", 0.0, 298.15, -125.5213, 333.15, -125.5213, 1e5); sNa->charge = 1; auto sOH = make_species("OH-", "O:1, H:1, E:1", 0.0, 298.15, -91.523, 333.15, -91.523, 1e5); sOH->charge = -1; for (auto& s : {sH2O, sCl, sH, sNa, sOH}) { p.addSpecies(s); } std::unique_ptr<PDSS_Water> ss(new PDSS_Water()); p.installPDSS(0, std::move(ss)); size_t k = 1; for (double v : {1.3, 1.3, 1.3, 1.3}) { std::unique_ptr<PDSS_ConstVol> ss(new PDSS_ConstVol()); ss->setMolarVolume(v); p.installPDSS(k++, std::move(ss)); } p.setPitzerTempModel("complex"); p.setA_Debye(1.175930); p.initThermo(); set_hmw_interactions(p); p.setMolalitiesByName("Na+:6.0997 Cl-:6.0996986044628 H+:2.1628E-9 OH-:1.3977E-6"); p.setState_TP(150 + 273.15, 101325); size_t N = p.nSpecies(); vector_fp acMol(N), mf(N), activities(N), moll(N), mu0(N); p.getMolalityActivityCoefficients(acMol.data()); p.getMoleFractions(mf.data()); p.getActivities(activities.data()); p.getMolalities(moll.data()); p.getStandardChemPotentials(mu0.data()); double acMolRef[] = {0.9341, 1.0191, 3.9637, 1.0191, 0.4660}; double mfRef[] = {0.8198, 0.0901, 0.0000, 0.0901, 0.0000}; double activitiesRef[] = {0.7658, 6.2164, 0.0000, 6.2164, 0.0000}; double mollRef[] = {55.5084, 6.0997, 0.0000, 6.0997, 0.0000}; double mu0Ref[] = {-317.175788, -186.014558, 0.0017225, -441.615429, -322.000412}; // kJ/gmol for (size_t k = 0 ; k < N; k++) { EXPECT_NEAR(acMol[k], acMolRef[k], 2e-4); EXPECT_NEAR(mf[k], mfRef[k], 2e-4); EXPECT_NEAR(activities[k], activitiesRef[k], 2e-4); EXPECT_NEAR(moll[k], mollRef[k], 2e-4); EXPECT_NEAR(mu0[k]/1e6, mu0Ref[k], 2e-6); } }
int main(int argc, char** argv) { int retn = 0; size_t i; string commandFile; try { char iFile[80]; strcpy(iFile, "HMW_NaCl.xml"); if (argc > 1) { strcpy(iFile, argv[1]); } double Temp = 273.15 + 275.; double aTemp[7]; aTemp[0] = 298.15; aTemp[1] = 273.15 + 100.; aTemp[2] = 273.15 + 150.; aTemp[3] = 273.15 + 200.; aTemp[4] = 273.15 + 250.; aTemp[5] = 273.15 + 275.; aTemp[6] = 273.15 + 300.; HMWSoln* HMW = new HMWSoln(iFile, "NaCl_electrolyte"); size_t nsp = HMW->nSpecies(); double acMol[100]; double act[100]; double mf[100]; double moll[100]; for (i = 0; i < 100; i++) { acMol[i] = 1.0; act[i] = 1.0; mf[i] = 0.0; moll[i] = 0.0; } HMW->getMoleFractions(mf); string sName; FILE* ff; char fname[64]; for (int jTemp = 0; jTemp < 7; jTemp++) { Temp = aTemp[jTemp]; sprintf(fname, "T%3.0f.csv", Temp); ff = fopen(fname, "w"); HMW->setState_TP(Temp, 1.01325E5); printf(" Temperature = %g K\n", Temp); size_t i1 = HMW->speciesIndex("Na+"); size_t i2 = HMW->speciesIndex("Cl-"); size_t i3 = HMW->speciesIndex("H2O(L)"); for (i = 1; i < nsp; i++) { moll[i] = 0.0; } HMW->setState_TPM(Temp, OneAtm, moll); double Itop = 10.; double Ibot = 0.0; double ISQRTtop = sqrt(Itop); double ISQRTbot = sqrt(Ibot); double ISQRT; double Is = 0.0; size_t its = 100; bool doneSp = false; fprintf(ff," Is, sqrtIs, meanAc," " log10(meanAC), acMol_Na+," " acMol_Cl-, ac_Water, act_Water, OsmoticCoeff\n"); for (i = 0; i < its; i++) { ISQRT = ISQRTtop*((double)i)/(its - 1.0) + ISQRTbot*(1.0 - (double)i/(its - 1.0)); Is = ISQRT * ISQRT; if (!doneSp) { if (Is > 6.146) { Is = 6.146; doneSp = true; i = i - 1; } } moll[i1] = Is; moll[i2] = Is; HMW->setMolalities(moll); HMW->getMolalityActivityCoefficients(acMol); HMW->getActivities(act); double oc = HMW->osmoticCoefficient(); double meanAC = sqrt(acMol[i1] * acMol[i2]); fprintf(ff,"%15g, %15g, %15g, %15g, %15g, %15g, %15g, %15g, %15g\n", Is, ISQRT, meanAC, log10(meanAC), acMol[i1], acMol[i2], acMol[i3], act[i3], oc); } fclose(ff); } delete HMW; HMW = 0; Cantera::appdelete(); return retn; } catch (CanteraError& err) { std::cout << err.what() << std::endl; return -1; } }