From 1183479f882661d7e1d92cdd9fbf91c673942537 Mon Sep 17 00:00:00 2001 From: pwcnorthrop Date: Sun, 14 Feb 2016 12:53:40 -0600 Subject: [PATCH] Add RedlichKister tests and sample case for LiC6 electrode See #293 --- samples/cxx/LiC6_electrode/LiC6_electrode.cpp | 72 +++++++++ .../cxx/LiC6_electrode/LiC6_electrodebulk.xml | 80 ++++++++++ .../cxx/LiC6_electrode/potentials_blessed.dat | 10 ++ test/data/RedlichKisterVPSSTP_valid.xml | 80 ++++++++++ test/thermo/RedlichKisterTest.cpp | 147 ++++++++++++++++++ 5 files changed, 389 insertions(+) create mode 100644 samples/cxx/LiC6_electrode/LiC6_electrode.cpp create mode 100644 samples/cxx/LiC6_electrode/LiC6_electrodebulk.xml create mode 100644 samples/cxx/LiC6_electrode/potentials_blessed.dat create mode 100644 test/data/RedlichKisterVPSSTP_valid.xml create mode 100644 test/thermo/RedlichKisterTest.cpp diff --git a/samples/cxx/LiC6_electrode/LiC6_electrode.cpp b/samples/cxx/LiC6_electrode/LiC6_electrode.cpp new file mode 100644 index 000000000..b83cc79bc --- /dev/null +++ b/samples/cxx/LiC6_electrode/LiC6_electrode.cpp @@ -0,0 +1,72 @@ +#include "cantera/thermo.h" +#include "cantera/thermo/RedlichKisterVPSSTP.h" +#include + +using namespace Cantera; + +void calc_potentials() +{ + suppress_deprecation_warnings(); + double Tk = 273.15 + 25.0; + + std::string filename = "LiC6_electrodebulk.xml"; + std::string phasename = "LiC6_and_Vacancies"; + std::unique_ptr electrodebulk(newPhase(filename,phasename)); + std::string intercalatingSpeciesName("Li(C6)"); + size_t intercalatingSpeciesIdx = electrodebulk->speciesIndex(intercalatingSpeciesName); + size_t nsp_tot = electrodebulk->nSpecies(); + + std::ofstream fout("potentials_output.dat", std::ofstream::out); + fout << "x[LiC6] ChemPotential[LiC6] ChemPotential[C6] Uref ActCoeff[LiC6] ActCoeff[C6] dlnActCoeffdx[LiC6] dlnActCoeffdx[C6]" << std::endl; + + vector_fp spvals(nsp_tot); + vector_fp actCoeff(nsp_tot); + vector_fp dlnActCoeffdlnX_diag(nsp_tot); + double xmin = 0.6; + double xmax = 0.9; + + int numSteps = 9; + double dx = (xmax-xmin)/(numSteps-1); + + size_t nsp_electrodeBulk = electrodebulk->nSpecies(); + vector_fp xv(nsp_electrodeBulk, 0.0); + + for (int i = 0; i < numSteps; ++i) { + double x = xmin + i*dx; + + vector_fp xv(nsp_electrodeBulk, 0.0); + //Set the fraction of intercalted lithium + xv[intercalatingSpeciesIdx] = x; + + //Set so that mole fractions sum to 1 + for (size_t j = 0; j < nsp_electrodeBulk; ++j) { + if (j != intercalatingSpeciesIdx) { + xv[j] = (1.0 - xv[intercalatingSpeciesIdx]); + } + } + + electrodebulk->setState_TX(Tk, &xv[0]); + electrodebulk->getChemPotentials(spvals.data()); + + //Calulate the open circuit potential + double Uref = (spvals[1] - spvals[0])/Faraday; + + electrodebulk->getdlnActCoeffdlnX_diag(dlnActCoeffdlnX_diag.data()); + electrodebulk->getActivityCoefficients(actCoeff.data()); + + fout << fmt::format("{} {} {} {} {} {} {} {}\n", + xv[0], spvals[0], spvals[1], Uref, actCoeff[0], + actCoeff[1], dlnActCoeffdlnX_diag[0], dlnActCoeffdlnX_diag[1]); + } +} + +int main(int argc, char** argv) +{ + try { + calc_potentials(); + return 0; + } catch (CanteraError& err) { + std::cout << err.what() << std::endl; + return 0; + } +} diff --git a/samples/cxx/LiC6_electrode/LiC6_electrodebulk.xml b/samples/cxx/LiC6_electrode/LiC6_electrodebulk.xml new file mode 100644 index 000000000..572d1439c --- /dev/null +++ b/samples/cxx/LiC6_electrode/LiC6_electrodebulk.xml @@ -0,0 +1,80 @@ + + + + + + + Li C + Li(C6) V(C6) + + 298.15 + 101325.0 + Li(C6):0.6,V(C6):0.4 + + + 2000.0 + + + + + + -3.268E6, + 3.955E6, + -4.573E6, + 6.147E6, + -3.339E6, + 1.117E7, + 2.997E5, + -4.866E7, + 1.362E5, + 1.373E8, + -2.129E7, + -1.722E8, + 3.956E7, + 9.302E7, + -3.280E7 + + + 0.0 + + + + + + + + + + + + + + + + + C:6 Li:1 + + + 298.15 + -11.65 + 0.0 + 0.0 + + + + + + + C:6 + + + 298.15 + 0.0 + 0.0 + 0.0 + + + + + + diff --git a/samples/cxx/LiC6_electrode/potentials_blessed.dat b/samples/cxx/LiC6_electrode/potentials_blessed.dat new file mode 100644 index 000000000..f7dcfa279 --- /dev/null +++ b/samples/cxx/LiC6_electrode/potentials_blessed.dat @@ -0,0 +1,10 @@ +x[LiC6] ChemPotential[LiC6] ChemPotential[C6] Uref ActCoeff[LiC6] ActCoeff[C6] dlnActCoeffdx[LiC6] dlnActCoeffdx[C6] +0.6 -1.27915e+07 -4.0265e+06 0.0908429 1.05164 0.492638 0.0907127 0.0907127 +0.6375 -1.26186e+07 -4.30768e+06 0.0861362 1.0613 0.48531 0.200612 0.200612 +0.675 -1.24454e+07 -4.63856e+06 0.0809124 1.07484 0.473671 0.229316 0.229316 +0.7125 -1.22826e+07 -5.00757e+06 0.0754005 1.08739 0.461396 0.193278 0.193278 +0.75 -1.21341e+07 -5.41192e+06 0.0696706 1.0968 0.450748 0.142257 0.142257 +0.7875 -1.19995e+07 -5.85996e+06 0.0636315 1.10287 0.442609 0.0766133 0.0766133 +0.825 -1.18827e+07 -6.34599e+06 0.0573836 1.10353 0.441766 -0.0712113 -0.0712113 +0.8625 -1.1793e+07 -6.82907e+06 0.0514475 1.09443 0.462697 -0.309379 -0.309379 +0.9 -1.17309e+07 -7.28939e+06 0.046033 1.07544 0.528389 -0.492206 -0.492206 diff --git a/test/data/RedlichKisterVPSSTP_valid.xml b/test/data/RedlichKisterVPSSTP_valid.xml new file mode 100644 index 000000000..572d1439c --- /dev/null +++ b/test/data/RedlichKisterVPSSTP_valid.xml @@ -0,0 +1,80 @@ + + + + + + + Li C + Li(C6) V(C6) + + 298.15 + 101325.0 + Li(C6):0.6,V(C6):0.4 + + + 2000.0 + + + + + + -3.268E6, + 3.955E6, + -4.573E6, + 6.147E6, + -3.339E6, + 1.117E7, + 2.997E5, + -4.866E7, + 1.362E5, + 1.373E8, + -2.129E7, + -1.722E8, + 3.956E7, + 9.302E7, + -3.280E7 + + + 0.0 + + + + + + + + + + + + + + + + + C:6 Li:1 + + + 298.15 + -11.65 + 0.0 + 0.0 + + + + + + + C:6 + + + 298.15 + 0.0 + 0.0 + 0.0 + + + + + + diff --git a/test/thermo/RedlichKisterTest.cpp b/test/thermo/RedlichKisterTest.cpp new file mode 100644 index 000000000..6192cd01c --- /dev/null +++ b/test/thermo/RedlichKisterTest.cpp @@ -0,0 +1,147 @@ +#include "gtest/gtest.h" +#include "cantera/thermo/RedlichKisterVPSSTP.h" +#include "cantera/thermo/ThermoFactory.h" + +namespace Cantera +{ + +class RedlichKister_Test : public testing::Test +{ +public: + RedlichKister_Test() { + test_phase.reset(newPhase("../data/RedlichKisterVPSSTP_valid.xml")); + } + + void set_r(const double r) { + vector_fp moleFracs(2); + moleFracs[0] = r; + moleFracs[1] = 1-r; + test_phase->setMoleFractions(&moleFracs[0]); + } + + std::unique_ptr test_phase; +}; + +TEST_F(RedlichKister_Test, construct_from_xml) +{ + RedlichKisterVPSSTP* redlich_kister_phase = dynamic_cast(test_phase.get()); + EXPECT_TRUE(redlich_kister_phase != NULL); +} + +TEST_F(RedlichKister_Test, chem_potentials) +{ + test_phase->setState_TP(298.15, 101325.); + + const double expected_result[9] = { + -1.2791500420236044e+007, + -1.2618554504124604e+007, + -1.2445418272766629e+007, + -1.2282611679165890e+007, + -1.2134110753109487e+007, + -1.1999465396970615e+007, + -1.1882669410525253e+007, + -1.1792994839484975e+007, + -1.1730895987035934e+007 + }; + + double xmin = 0.6; + double xmax = 0.9; + int numSteps = 9; + double dx = (xmax-xmin)/(numSteps-1); + vector_fp chemPotentials(2); + for(int i=0; i < 9; ++i) + { + set_r(xmin + i*dx); + test_phase->getChemPotentials(&chemPotentials[0]); + EXPECT_NEAR(expected_result[i], chemPotentials[0], 1.e-6); + } +} + +TEST_F(RedlichKister_Test, dlnActivities) +{ + test_phase->setState_TP(298.15, 101325.); + + const double expected_result[9] = { + 0.0907127, + 0.200612, + 0.229316, + 0.193278, + 0.142257, + 0.0766133, + -0.0712113, + -0.309379, + -0.492206 + }; + + double xmin = 0.6; + double xmax = 0.9; + int numSteps = 9; + double dx = (xmax-xmin)/(numSteps-1); + vector_fp dlnActCoeffdx(2); + for(int i=0; i < 9; ++i) + { + const double r = xmin + i*dx; + set_r(r); + test_phase->getdlnActCoeffdlnX_diag(&dlnActCoeffdx[0]); + EXPECT_NEAR(expected_result[i], dlnActCoeffdx[0], 1.e-6); + } +} + +TEST_F(RedlichKister_Test, activityCoeffs) +{ + test_phase->setState_TP(298., 1.); + + // Test that mu0 + RT log(activityCoeff * MoleFrac) == mu + const double RT = GasConstant * 298.; + vector_fp mu0(2); + vector_fp activityCoeffs(2); + vector_fp chemPotentials(2); + double xmin = 0.6; + double xmax = 0.9; + int numSteps = 9; + double dx = (xmax-xmin)/(numSteps-1); + + for(int i=0; i < numSteps; ++i) + { + const double r = xmin + i*dx; + set_r(r); + test_phase->getChemPotentials(&chemPotentials[0]); + test_phase->getActivityCoefficients(&activityCoeffs[0]); + test_phase->getStandardChemPotentials(&mu0[0]); + EXPECT_NEAR(chemPotentials[0], mu0[0] + RT*std::log(activityCoeffs[0] * r), 1.e-6); + EXPECT_NEAR(chemPotentials[1], mu0[1] + RT*std::log(activityCoeffs[1] * (1-r)), 1.e-6); + } +} + +TEST_F(RedlichKister_Test, standardConcentrations) +{ + EXPECT_DOUBLE_EQ(1.0, test_phase->standardConcentration(0)); + EXPECT_DOUBLE_EQ(1.0, test_phase->standardConcentration(1)); +} + +TEST_F(RedlichKister_Test, activityConcentrations) +{ + // Check to make sure activityConcentration_i == standardConcentration_i * gamma_i * X_i + vector_fp standardConcs(2); + vector_fp activityCoeffs(2); + vector_fp activityConcentrations(2); + double xmin = 0.6; + double xmax = 0.9; + int numSteps = 9; + double dx = (xmax-xmin)/(numSteps-1); + + for(int i=0; i < 9; ++i) + { + const double r = xmin + i*dx; + set_r(r); + test_phase->getActivityCoefficients(&activityCoeffs[0]); + standardConcs[0] = test_phase->standardConcentration(0); + standardConcs[1] = test_phase->standardConcentration(1); + test_phase->getActivityConcentrations(&activityConcentrations[0]); + + EXPECT_NEAR(standardConcs[0] * r * activityCoeffs[0], activityConcentrations[0], 1.e-6); + EXPECT_NEAR(standardConcs[1] * (1-r) * activityCoeffs[1], activityConcentrations[1], 1.e-6); + } +} + +};