https://mooseframework.inl.gov
Loading...
Searching...
No Matches
GeochemistryActivityCoefficientsDebyeHuckelTest.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "gtest/gtest.h"
11
14
15const GeochemicalDatabaseReader database("database/moose_testdb.json", true, true, false);
16// The following system has secondary species: (O-phth)--, CO2(aq), CO3--, CaCO3, CaOH+, OH-,
17// >(s)FeO-, Calcite, seq_radius_neg1
20 {"H2O", "H+", "HCO3-", "O2(aq)", "Ca++", ">(s)FeOH", "radius_neg1", "radius_neg1.5"},
21 {"Calcite"},
22 {},
23 {"Calcite_asdf"},
24 {"CH4(aq)"},
25 {">(s)FeOCa+"},
26 "O2(aq)",
27 "e-");
29
31TEST(GeochemistryActivityCoefficientsDebyeHuckelTest, notDH)
32{
33 const GeochemicalDatabaseReader database_notDH(
34 "database/faultydbs/notDH.json", true, true, false);
35 GeochemistryIonicStrength is(1.0E9, 2.0E9, false, false);
36 try
37 {
38 GeochemistryActivityCoefficientsDebyeHuckel ac_notDH(is, database_notDH);
39 FAIL() << "Missing expected exception.";
40 }
41 catch (const std::exception & e)
42 {
43 std::string msg(e.what());
44 ASSERT_TRUE(msg.find("Attempted to get Debye-Huckel activity parameters but the activity model "
45 "is NOTdebye-huckel") != std::string::npos)
46 << "Failed with unexpected error message: " << msg;
47 }
48}
49
51TEST(GeochemistryActivityCoefficientsDebyeHuckelTest, noNeutral)
52{
53 const GeochemicalDatabaseReader database_noNeutral(
54 "database/faultydbs/missing_DH.json", true, true, false);
55 GeochemistryIonicStrength is(1.0E9, 2.0E9, false, false);
56 GeochemistryActivityCoefficientsDebyeHuckel ac_noNeutral(is, database_noNeutral);
57 ac_noNeutral.setInternalParameters(
58 25.0, mgd, std::vector<Real>(8, 1.0), std::vector<Real>(9), std::vector<Real>(3));
59 const DebyeHuckelParameters dh = ac_noNeutral.getDebyeHuckel();
60
61 EXPECT_EQ(dh.A, 0.5555);
62 EXPECT_EQ(dh.B, 0.3333);
63 EXPECT_EQ(dh.Bdot, 0.0444);
64 EXPECT_EQ(dh.a_water, 0.0);
65 EXPECT_EQ(dh.b_water, 0.0);
66 EXPECT_EQ(dh.c_water, 0.0);
67 EXPECT_EQ(dh.d_water, 0.0);
68 EXPECT_EQ(dh.a_neutral, 0.0);
69 EXPECT_EQ(dh.b_neutral, 0.0);
70 EXPECT_EQ(dh.c_neutral, 0.0);
71 EXPECT_EQ(dh.d_neutral, 0.0);
72}
73
75TEST(GeochemistryActivityCoefficientsDebyeHuckelTest, ionicStrengthInterface)
76{
77 GeochemistryIonicStrength is(1.0E9, 2.0E9, false, false);
79
80 is.setUseOnlyBasisMolality(true);
81 is.setMaxStoichiometricIonicStrength(2.0E-8);
82
83 Real gold_ionic_str = 0.0;
84 std::vector<Real> basis_m(8);
85 basis_m[mgd.basis_species_index.at("H2O")] = 1.0;
86 basis_m[mgd.basis_species_index.at("H+")] = 2.0;
87 gold_ionic_str += 2.0;
88 basis_m[mgd.basis_species_index.at("HCO3-")] = 3.0;
89 gold_ionic_str += 3.0;
90 basis_m[mgd.basis_species_index.at("O2(aq)")] = 4.0;
91 basis_m[mgd.basis_species_index.at("Ca++")] = 5.0;
92 gold_ionic_str += 4 * 5.0;
93 basis_m[mgd.basis_species_index.at(">(s)FeOH")] = 6.0;
94 basis_m[mgd.basis_species_index.at("radius_neg1")] = 7.0;
95 basis_m[mgd.basis_species_index.at("radius_neg1.5")] = 8.0;
96
97 // the equilibrium and kinetic molalities do not make any difference due to ionic strength using
98 // only basis molalities
100 25.0, mgd, basis_m, std::vector<Real>(9, 1.1), std::vector<Real>(3, 2.2));
101
102 EXPECT_NEAR(ac.getIonicStrength(), 0.5 * gold_ionic_str, 1E-8);
103 EXPECT_EQ(ac.getStoichiometricIonicStrength(), 2.0E-8);
104}
105
107TEST(GeochemistryActivityCoefficientsDebyeHuckelTest, getDebyeHuckel)
108{
109 GeochemistryIonicStrength is(1.0E9, 2.0E9, false, false);
112 25.0, mgd, std::vector<Real>(8, 1.0), std::vector<Real>(9), std::vector<Real>(3));
114
115 EXPECT_EQ(dh.A, 0.5092);
116 EXPECT_EQ(dh.B, 0.3283);
117 EXPECT_EQ(dh.Bdot, 0.041);
118 EXPECT_EQ(dh.a_water, 1.45397);
119 EXPECT_EQ(dh.b_water, 0.022357);
120 EXPECT_EQ(dh.c_water, 0.0093804);
121 EXPECT_EQ(dh.d_water, -0.0005362);
122 EXPECT_EQ(dh.a_neutral, 0.1127);
123 EXPECT_EQ(dh.b_neutral, -0.01049);
124 EXPECT_EQ(dh.c_neutral, 0.001545);
125 EXPECT_EQ(dh.d_neutral, 0.0);
126}
127
129TEST(GeochemistryActivityCoefficientsDebyeHuckelTest, buildActivityCoefficientsDebyeHuckel)
130{
131 GeochemistryIonicStrength is(1.0E9, 2.0E9, false, false);
134 25.0, mgd, std::vector<Real>(8, 1.0), std::vector<Real>(9), std::vector<Real>(3));
135
136 const Real ionic_str = ac.getIonicStrength();
137
138 std::vector<Real> basis_ac;
139 std::vector<Real> eqm_ac;
140 ac.buildActivityCoefficients(mgd, basis_ac, eqm_ac);
141
142 EXPECT_EQ(basis_ac.size(), (std::size_t)8);
143 EXPECT_EQ(eqm_ac.size(), (std::size_t)9);
144
146
147 // Note that GeochemistryActivity has been tested elsewhere: here we're just checking the slots
148 // get filled correctly
149 for (unsigned i = 1; i < 8; ++i) // don't loop over water
150 {
151 Real gold = 0.0;
152 if (i == 3) // O2(aq)
153 gold = std::pow(10.0,
155 ionic_str, dh.a_neutral, dh.b_neutral, dh.c_neutral, dh.d_neutral));
156 else if (i == 5) // >(s)FeOH
157 gold = 1.0;
158 else if (i == 6) // radius_neg1
159 gold = std::pow(
160 10.0,
162 else if (i == 7) // radius_neg1.5
163 gold = 1.0;
164 else
165 gold =
166 std::pow(10.0,
169 std::sqrt(ionic_str),
170 dh.A,
171 dh.B,
172 dh.Bdot));
173 ASSERT_NEAR(basis_ac[i], gold, 1.0E-8);
174 }
175
176 for (unsigned j = 0; j < 9; ++j)
177 {
178 Real gold = 0.0;
179 const std::string nm = mgd.eqm_species_name[j];
180 if (nm == "Calcite")
181 continue;
182 else if (nm == "CO2(aq)" || nm == "CaCO3" || nm == ">(s)FeO-")
183 gold = 1.0;
184 else if (nm == "seq_radius_neg1")
185 gold = std::pow(
186 10.0,
188 else
189 gold =
190 std::pow(10.0,
193 std::sqrt(ionic_str),
194 dh.A,
195 dh.B,
196 dh.Bdot));
197 ASSERT_NEAR(eqm_ac[j], gold, 1.0E-8);
198 }
199}
200
202TEST(GeochemistryActivityCoefficientsDebyeHuckelTest, waterActivity)
203{
204 GeochemistryIonicStrength is(1.0E9, 2.0E9, false, false);
207 25.0, mgd, std::vector<Real>(8, 1.0), std::vector<Real>(9), std::vector<Real>(3));
208
210 const Real stoi_ionic_str = ac.getStoichiometricIonicStrength();
211
212 // note that GeochemistryActivityCalculators::lnActivityDHBdotWater has been tested elsewhere:
213 // this is just testing the information gets passed through to
214 // GeochemistryActivityCoefficientsDebyeHuckel
215 EXPECT_NEAR(ac.waterActivity(),
217 stoi_ionic_str, dh.A, dh.a_water, dh.b_water, dh.c_water, dh.d_water)),
218 1.0E-8);
219}
const PertinentGeochemicalSystem model(database, {"H2O", "H+", "HCO3-", "O2(aq)", "Ca++", ">(s)FeOH", "radius_neg1", "radius_neg1.5"}, {"Calcite"}, {}, {"Calcite_asdf"}, {"CH4(aq)"}, {">(s)FeOCa+"}, "O2(aq)", "e-")
TEST(GeochemistryActivityCoefficientsDebyeHuckelTest, notDH)
Test errors when a non-DebyeHuckel database is read.
const GeochemicalDatabaseReader database("database/moose_testdb.json", true, true, false)
const ModelGeochemicalDatabase mgd
Class for reading geochemical reactions from a MOOSE geochemical database.
Computes activity coefficients for non-minerals and non-gases (since these species do not have activi...
Real getStoichiometricIonicStrength() const
Return the current value of stoichiometric ionic strength.
void setInternalParameters(Real temperature, const ModelGeochemicalDatabase &mgd, const std::vector< Real > &basis_species_molality, const std::vector< Real > &eqm_species_molality, const std::vector< Real > &kin_species_molality) override
Sets internal parameters, such as the ionic strength and Debye-Huckel parameters, prior to computing ...
void buildActivityCoefficients(const ModelGeochemicalDatabase &mgd, std::vector< Real > &basis_activity_coef, std::vector< Real > &eqm_activity_coef) const override
Compute the activity coefficients and store them in basis_activity_coef and eqm_activity_coef Note:
Real getIonicStrength() const
Return the current value of ionic strength.
Real waterActivity() const override
Computes and returns the activity of water.
Calculators to compute ionic strength and stoichiometric ionic strength.
Constructs and stores a minimal amount of information that is pertinent to the user-defined geochemic...
const ModelGeochemicalDatabase & modelGeochemicalDatabase() const
Return a reference to the ModelGeochemicalDatabase structure.
Real log10ActCoeffDHBdot(Real charge, Real ion_size, Real sqrt_ionic_strength, Real A, Real B, Real Bdot)
log10(activity coefficient) according to the Debye-Huckel B-dot model
Real log10ActCoeffDHBdotAlternative(Real ionic_strength, Real Bdot)
log10(activity coefficient) alternative expression that is sometimes used in conjunction with the Deb...
Real log10ActCoeffDHBdotNeutral(Real ionic_strength, Real a, Real b, Real c, Real d)
log10(activity coefficient) for neutral species according to the Debye-Huckel B-dot model
Real lnActivityDHBdotWater(Real stoichiometric_ionic_strength, Real A, Real atilde, Real btilde, Real ctilde, Real dtilde)
ln(activity of water) according to the Debye-Huckel B-dot model
Data structure to hold all relevant information from the database file.
std::vector< Real > eqm_species_radius
all quantities have an ionic radius (Angstrom) for computing activity (mineral radius = 0,...
std::vector< Real > basis_species_radius
all quantities have an ionic radius (Angstrom) for computing activity (mineral radius = 0,...
std::vector< Real > basis_species_charge
all quantities have a charge (mineral charge = 0, gas charge = 0, oxide charge = 0)
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
std::vector< std::string > eqm_species_name
eqm_species_name[i] = name of the i^th eqm species
std::vector< Real > eqm_species_charge
all quantities have a charge (mineral charge = 0, gas charge = 0, oxide charge = 0)