https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | List of all members
GeochemistrySpeciesSwapper Class Reference

Class to swap basis species with equilibrium species. More...

#include <GeochemistrySpeciesSwapper.h>

Public Member Functions

 GeochemistrySpeciesSwapper (unsigned basis_size, Real stoi_tol)
 
bool operator== (const GeochemistrySpeciesSwapper &rhs) const
 
void checkSwap (const ModelGeochemicalDatabase &mgd, const std::string &replace_this, const std::string &with_this)
 Check that replacing the named basis species with the named equilibrium species is valid.
 
void checkSwap (const ModelGeochemicalDatabase &mgd, unsigned basis_index_to_replace, unsigned eqm_index_to_insert)
 Check that replacing the indexed basis species with the indexed equilibrium species is valid.
 
void performSwap (ModelGeochemicalDatabase &mgd, const std::string &replace_this, const std::string &with_this)
 Check that replacing the named basis species with the named equilibrium species is valid, and then perform this swap by altering the mgd data structure.
 
void performSwap (ModelGeochemicalDatabase &mgd, unsigned basis_index_to_replace, unsigned eqm_index_to_insert)
 Check that replacing the indexed basis species with the indexed equilibrium species is valid, and then perform this swap by altering the mgd data structure.
 
void performSwap (ModelGeochemicalDatabase &mgd, DenseVector< Real > &bulk_composition, const std::string &replace_this, const std::string &with_this)
 Check that replacing the named basis species with the named equilibrium species is valid, and then perform this swap by altering the mgd data structure, and calculate the bulk composition of the new system.
 
void performSwap (ModelGeochemicalDatabase &mgd, DenseVector< Real > &bulk_composition, unsigned basis_index_to_replace, unsigned eqm_index_to_insert)
 Check that replacing the indexed basis species with the indexed equilibrium species is valid, and then perform this swap by altering the mgd data structure, and calculate the bulk composition of the new system.
 
bool findBestEqmSwap (unsigned basis_ind, const ModelGeochemicalDatabase &mgd, const std::vector< Real > &eqm_molality, bool minerals_allowed, bool gas_allowed, bool sorption_allowed, unsigned &best_eqm_species) const
 For the the given basis index, find the equilibrium index that it should be swapped with.
 

Private Member Functions

void constructInverseMatrix (const ModelGeochemicalDatabase &mgd, unsigned basis_index_to_replace, unsigned eqm_index_to_insert)
 Construct the swap matrix, and its inverse, that describes the swap between the indexed basis species and the indexed equilibrium index.
 
void alterMGD (ModelGeochemicalDatabase &mgd, unsigned basis_index_to_replace, unsigned eqm_index_to_insert)
 Modify the ModelGeochemicalDatabase mgd to swap the indexed basis species and the indexed equilibrium index.
 
void alterBulkComposition (unsigned basis_size, DenseVector< Real > &bulk_composition) const
 Calculate the bulk composition in the new basis based on the bulk composition in the original basis.
 

Private Attributes

Real _stoi_tol
 tolerance for matrix inversion and stoichiometric coefficients
 
DenseMatrix< Real > _swap_matrix
 swap matrix
 
DenseMatrix< Real > _true_swap_matrix
 Before _swap_matrix.svd (a non-const method) is called, we copy _true_swap_matrix = _swap_matrix.
 
DenseMatrix< Real > _inv_swap_matrix
 inverse of swap matrix
 
DenseVector< Real > _swap_sigma
 used in SVD decomposition of swap matrix
 
DenseMatrix< Real > _swap_U
 used in SVD decomposition of swap matrix
 
DenseMatrix< Real > _swap_VT
 used in SVD decomposition of swap matrix
 

Detailed Description

Class to swap basis species with equilibrium species.

Definition at line 19 of file GeochemistrySpeciesSwapper.h.

Constructor & Destructor Documentation

◆ GeochemistrySpeciesSwapper()

GeochemistrySpeciesSwapper::GeochemistrySpeciesSwapper ( unsigned  basis_size,
Real  stoi_tol 
)
Parameters
basis_sizeNumber of basis species in the geochemical model
stoi_tolSwapping involves inverting matrices via a singular value decomposition. During this process: (1) if abs(singular value) < stoi_tol * L1norm(singular values), then the matrix is deemed singular (so the basis swap is deemed invalid); (2) if abs(any stoichiometric coefficient) < stoi_tol then it is set to zero. A suggested reasonable value is stoi_tol=1E-6

Definition at line 12 of file GeochemistrySpeciesSwapper.C.

13 : _stoi_tol(stoi_tol),
14 _swap_matrix(basis_size, basis_size),
15 _true_swap_matrix(basis_size, basis_size),
16 _inv_swap_matrix(basis_size, basis_size),
17 _swap_sigma(basis_size),
18 _swap_U(basis_size, basis_size),
19 _swap_VT(basis_size, basis_size)
20{
21}
DenseMatrix< Real > _swap_U
used in SVD decomposition of swap matrix
DenseMatrix< Real > _swap_matrix
swap matrix
DenseMatrix< Real > _swap_VT
used in SVD decomposition of swap matrix
Real _stoi_tol
tolerance for matrix inversion and stoichiometric coefficients
DenseMatrix< Real > _true_swap_matrix
Before _swap_matrix.svd (a non-const method) is called, we copy _true_swap_matrix = _swap_matrix.
DenseVector< Real > _swap_sigma
used in SVD decomposition of swap matrix
DenseMatrix< Real > _inv_swap_matrix
inverse of swap matrix

Member Function Documentation

◆ alterBulkComposition()

void GeochemistrySpeciesSwapper::alterBulkComposition ( unsigned  basis_size,
DenseVector< Real > &  bulk_composition 
) const
private

Calculate the bulk composition in the new basis based on the bulk composition in the original basis.

Parameters
basis_sizeSize of basis, which is only used for error checking
[in/out]bulk_composition Upon entry, the bulk composition in the original basis. Upon exit, the bulk composition in the basis after the swap

Definition at line 355 of file GeochemistrySpeciesSwapper.C.

357{
358 if (bulk_composition.size() != basis_size)
359 mooseError("GeochemistrySpeciesSwapper: bulk_composition has size ",
360 bulk_composition.size(),
361 " which differs from the basis size");
362 DenseVector<Real> result;
363 _inv_swap_matrix.vector_mult_transpose(result, bulk_composition);
364 bulk_composition = result;
365}
void mooseError(Args &&... args)
void vector_mult_transpose(DenseVector< T > &dest, const DenseVector< T > &arg) const

Referenced by performSwap(), and performSwap().

◆ alterMGD()

void GeochemistrySpeciesSwapper::alterMGD ( ModelGeochemicalDatabase mgd,
unsigned  basis_index_to_replace,
unsigned  eqm_index_to_insert 
)
private

Modify the ModelGeochemicalDatabase mgd to swap the indexed basis species and the indexed equilibrium index.

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
basis_index_to_replaceThe index of the basis component that will be removed from the basis and added to the equilibrium species list
eqm_index_to_insertThe index of the equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 162 of file GeochemistrySpeciesSwapper.C.

165{
166 const unsigned num_cols = mgd.basis_species_index.size();
167 const unsigned num_rows = mgd.eqm_species_index.size();
168 const unsigned num_temperatures = mgd.eqm_log10K.n();
169 const unsigned num_redox = mgd.redox_stoichiometry.m();
170 const unsigned kin_rows = mgd.kin_stoichiometry.m();
171 const unsigned num_rate = mgd.kin_rate.size();
172 const unsigned pro_ind_eqm =
173 num_cols + eqm_index_to_insert; // index of the (eqm species that is being swapped into the
174 // basis) in the kinetic-rate promoting_indices vectors
175
176 // change names
177 const std::string basis_name = mgd.basis_species_name[basis_index_to_replace];
178 const std::string eqm_name = mgd.eqm_species_name[eqm_index_to_insert];
179 mgd.basis_species_name[basis_index_to_replace] = eqm_name;
180 mgd.basis_species_index.erase(basis_name);
181 mgd.basis_species_index[eqm_name] = basis_index_to_replace;
182 mgd.eqm_species_name[eqm_index_to_insert] = basis_name;
183 mgd.eqm_species_index.erase(eqm_name);
184 mgd.eqm_species_index[basis_name] = eqm_index_to_insert;
185
186 // flag indicating whether the redox_lhs is the equilibrium species that is being put into the
187 // basis
188 const bool redox_lhs_going_to_basis = (eqm_name == mgd.redox_lhs);
189 mooseAssert(
190 !redox_lhs_going_to_basis,
191 "Should not be able to swap the redox LHS into the basis"); // At present, it is impossible to
192 // swap redox_lhs into the basis,
193 // since redox_lhs cannot be an
194 // equilibrium species, because it
195 // is explicitly excluded in
196 // PertinentGeochemicalSystem when
197 // building the secondary species.
198 /*
199 In past versions of the code, it was possible to swap the redox LHS into the basis.
200 If you want to make it possible again then mgd needs to be modified as follows
201 if (redox_lhs_going_to_basis)
202 {
203 // need to make the redox_lhs equal to the species that is being taken from the basis
204 mgd.redox_lhs = basis_name;
205 for (unsigned red = 0; red < num_redox; ++red)
206 {
207 const Real alpha = mgd.eqm_stoichiometry(
208 eqm_index_to_insert, basis_index_to_replace); // must be nonzero due to valid swap
209 const Real alpha_r = mgd.redox_stoichiometry(red, basis_index_to_replace);
210 mooseAssert(alpha != alpha_r,
211 "Cannot swap equilibrium species "
212 << eqm_name << " with basis species " << basis_name
213 << " because a redox reaction would result in 0 <-> 1");
214 const Real coef = 1.0 / (alpha - alpha_r);
215 for (unsigned i = 0; i < num_cols; ++i)
216 mgd.redox_stoichiometry(red, i) = coef * (mgd.redox_stoichiometry(red, i) -
217 mgd.eqm_stoichiometry(eqm_index_to_insert, i));
218 mgd.redox_stoichiometry(red, basis_index_to_replace) = 0.0;
219 for (unsigned t = 0; t < num_temperatures; ++t)
220 mgd.redox_log10K(red, t) =
221 coef * (mgd.redox_log10K(red, t) - mgd.eqm_log10K(eqm_index_to_insert, t));
222 }
223 }
224 */
225
226 // record that the swap has occurred
227 if (mgd.swap_to_original_basis.n() == 0)
229 else
231 mgd.have_swapped_out_of_basis.push_back(basis_index_to_replace);
232 mgd.have_swapped_into_basis.push_back(eqm_index_to_insert);
233
234 // express stoichiometry in new basis
235 for (unsigned i = 0; i < num_cols; ++i)
236 mgd.eqm_stoichiometry(eqm_index_to_insert, i) = 0.0;
237 mgd.eqm_stoichiometry(eqm_index_to_insert, basis_index_to_replace) =
238 1.0; // 1 * replace_this <-> 1 * replace_this
240 for (unsigned i = 0; i < num_rows; ++i)
241 for (unsigned j = 0; j < num_cols; ++j)
242 if (std::abs(mgd.eqm_stoichiometry(i, j)) < _stoi_tol)
243 mgd.eqm_stoichiometry(i, j) = 0.0;
244
245 // if the redox_lhs is not changed by the swap, alter the redox stoichiometry
246 if (!redox_lhs_going_to_basis)
248 for (unsigned red = 0; red < num_redox; ++red)
249 for (unsigned j = 0; j < num_cols; ++j)
250 if (std::abs(mgd.redox_stoichiometry(red, j)) < _stoi_tol)
251 mgd.redox_stoichiometry(red, j) = 0.0;
252
253 // express kinetic stoichiometry in new basis
255 for (unsigned i = 0; i < kin_rows; ++i)
256 for (unsigned j = 0; j < num_cols; ++j)
257 if (std::abs(mgd.kin_stoichiometry(i, j)) < _stoi_tol)
258 mgd.kin_stoichiometry(i, j) = 0.0;
259
260 // alter equilibrium constants for each temperature point
261 for (unsigned t = 0; t < num_temperatures; ++t)
262 {
263 const Real log10k_eqm_species = mgd.eqm_log10K(eqm_index_to_insert, t);
264 mgd.eqm_log10K(eqm_index_to_insert, t) =
265 0.0; // 1 * replace_this <-> 1 * replace_this with log10K = 0
266 for (unsigned row = 0; row < num_rows; ++row)
267 mgd.eqm_log10K(row, t) -=
268 mgd.eqm_stoichiometry(row, basis_index_to_replace) * log10k_eqm_species;
269
270 // similar for the redox equations
271 if (!redox_lhs_going_to_basis)
272 for (unsigned red = 0; red < num_redox; ++red)
273 mgd.redox_log10K(red, t) -=
274 mgd.redox_stoichiometry(red, basis_index_to_replace) * log10k_eqm_species;
275
276 // similar for kinetic
277 for (unsigned kin = 0; kin < kin_rows; ++kin)
278 mgd.kin_log10K(kin, t) -=
279 mgd.kin_stoichiometry(kin, basis_index_to_replace) * log10k_eqm_species;
280 }
281
282 // swap the "is mineral" information
283 const bool basis_was_mineral = mgd.basis_species_mineral[basis_index_to_replace];
284 mgd.basis_species_mineral[basis_index_to_replace] = mgd.eqm_species_mineral[eqm_index_to_insert];
285 mgd.eqm_species_mineral[eqm_index_to_insert] = basis_was_mineral;
286
287 // swap the "is gas" information
288 const bool basis_was_gas = mgd.basis_species_gas[basis_index_to_replace];
289 mgd.basis_species_gas[basis_index_to_replace] = mgd.eqm_species_gas[eqm_index_to_insert];
290 mgd.eqm_species_gas[eqm_index_to_insert] = basis_was_gas;
291
292 // swap the "is transported" information
293 const bool basis_was_transported = mgd.basis_species_transported[basis_index_to_replace];
294 mgd.basis_species_transported[basis_index_to_replace] =
295 mgd.eqm_species_transported[eqm_index_to_insert];
296 mgd.eqm_species_transported[eqm_index_to_insert] = basis_was_transported;
297
298 // swap the "charge" information
299 const Real basis_charge = mgd.basis_species_charge[basis_index_to_replace];
300 mgd.basis_species_charge[basis_index_to_replace] = mgd.eqm_species_charge[eqm_index_to_insert];
301 mgd.eqm_species_charge[eqm_index_to_insert] = basis_charge;
302
303 // swap the "radius" information
304 const Real basis_radius = mgd.basis_species_radius[basis_index_to_replace];
305 mgd.basis_species_radius[basis_index_to_replace] = mgd.eqm_species_radius[eqm_index_to_insert];
306 mgd.eqm_species_radius[eqm_index_to_insert] = basis_radius;
307
308 // swap the "molecular weight" information
309 const Real basis_molecular_weight = mgd.basis_species_molecular_weight[basis_index_to_replace];
310 mgd.basis_species_molecular_weight[basis_index_to_replace] =
311 mgd.eqm_species_molecular_weight[eqm_index_to_insert];
312 mgd.eqm_species_molecular_weight[eqm_index_to_insert] = basis_molecular_weight;
313
314 // swap the "molecular volume" information
315 const Real basis_molecular_volume = mgd.basis_species_molecular_volume[basis_index_to_replace];
316 mgd.basis_species_molecular_volume[basis_index_to_replace] =
317 mgd.eqm_species_molecular_volume[eqm_index_to_insert];
318 mgd.eqm_species_molecular_volume[eqm_index_to_insert] = basis_molecular_volume;
319
320 // No need to swap surface_complexation_info or gas_chi because they are not
321 // bound to basis or eqm species
322
323 // swap promoting indices in the rates
324 for (unsigned r = 0; r < num_rate; ++r)
325 {
326 const Real promoting_index_of_original_basis =
327 mgd.kin_rate[r].promoting_indices[basis_index_to_replace];
328 mgd.kin_rate[r].promoting_indices[basis_index_to_replace] =
329 mgd.kin_rate[r].promoting_indices[pro_ind_eqm];
330 mgd.kin_rate[r].promoting_indices[pro_ind_eqm] = promoting_index_of_original_basis;
331 const Real promoting_monod_index_of_original_basis =
332 mgd.kin_rate[r].promoting_monod_indices[basis_index_to_replace];
333 mgd.kin_rate[r].promoting_monod_indices[basis_index_to_replace] =
334 mgd.kin_rate[r].promoting_monod_indices[pro_ind_eqm];
335 mgd.kin_rate[r].promoting_monod_indices[pro_ind_eqm] = promoting_monod_index_of_original_basis;
336 const Real promoting_half_saturation_of_original_basis =
337 mgd.kin_rate[r].promoting_half_saturation[basis_index_to_replace];
338 mgd.kin_rate[r].promoting_half_saturation[basis_index_to_replace] =
339 mgd.kin_rate[r].promoting_half_saturation[pro_ind_eqm];
340 mgd.kin_rate[r].promoting_half_saturation[pro_ind_eqm] =
341 promoting_half_saturation_of_original_basis;
342 }
343
344 // swap progeny, if needed
345 for (unsigned r = 0; r < num_rate; ++r)
346 {
347 if (mgd.kin_rate[r].progeny_index == pro_ind_eqm)
348 mgd.kin_rate[r].progeny_index = basis_index_to_replace;
349 else if (mgd.kin_rate[r].progeny_index == basis_index_to_replace)
350 mgd.kin_rate[r].progeny_index = pro_ind_eqm;
351 }
352}
const ModelGeochemicalDatabase mgd
unsigned int n() const
unsigned int m() const
virtual void right_multiply(const DenseMatrixBase< T > &M2) override final
virtual void left_multiply(const DenseMatrixBase< T > &M2) override final
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< bool > eqm_species_mineral
eqm_species_mineral[i] = true iff the i^th equilibrium species is a mineral
std::vector< Real > eqm_species_radius
all quantities have an ionic radius (Angstrom) for computing activity (mineral radius = 0,...
DenseMatrix< Real > eqm_stoichiometry
eqm_stoichiometry(i, j) = stoichiometric coefficient for equilibrium species "i" in terms of the basi...
std::vector< Real > basis_species_molecular_weight
all quantities have a molecular weight (g)
DenseMatrix< Real > kin_stoichiometry
kin_stoichiometry(i, j) = stoichiometric coefficient for kinetic species "i" in terms of the basis sp...
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::vector< Real > eqm_species_molecular_volume
all quantities have a molecular volume (cm^3) (only nonzero for minerals, however)
std::string redox_lhs
the name of the species on the left-hand side of the redox equations.
std::vector< Real > eqm_species_molecular_weight
all quantities have a molecular weight (g)
std::vector< unsigned > have_swapped_into_basis
Species that have been swapped into the basis.
std::vector< bool > basis_species_transported
basis_species_transported[j] = true iff the j^th basis species is transported in reactive-transport s...
DenseMatrix< Real > redox_stoichiometry
redox_stoichiometry(i, j) = stoichiometric coefficients for i^th redox species that is in disequilibr...
DenseMatrix< Real > swap_to_original_basis
Swap matrix that allows expression in terms of the original basis.
std::vector< bool > basis_species_mineral
basis_species_mineral[j] = true iff the j^th basis species is a mineral
std::vector< KineticRateDefinition > kin_rate
rates given to kinetic species.
DenseMatrix< Real > redox_log10K
redox_log10K(i, j) = log10(equilibrium constant) for i^th redox species at the j^th temperature point
DenseMatrix< Real > kin_log10K
kin_log10K(i, j) = log10(equilibrium constant for the i^th kinetic species at the j^th temperature po...
std::vector< unsigned > have_swapped_out_of_basis
Species that have been swapped out of the basis.
std::vector< Real > basis_species_molecular_volume
all quantities have a molecular volume (cm^3) (only nonzero for minerals, however)
std::unordered_map< std::string, unsigned > eqm_species_index
eqm_species_index[name] = index of the equilibrium species (secondary aqueous species,...
std::vector< std::string > basis_species_name
basis_species_name[j] = name of the j^th basis species
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
DenseMatrix< Real > eqm_log10K
eqm_log10K(i, j) = log10(equilibrium constant) for i^th equilibrium species at the j^th temperature p...
std::vector< bool > basis_species_gas
basis_species_gas[j] = true iff the j^th basis species is a gas
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)
std::vector< bool > eqm_species_gas
eqm_species_gas[i] = true iff the i^th equilibrium species is a gas
std::vector< bool > eqm_species_transported
eqm_species_transported[i] = true iff the i^th eqm species is transported in reactive-transport sims

Referenced by performSwap(), and performSwap().

◆ checkSwap() [1/2]

void GeochemistrySpeciesSwapper::checkSwap ( const ModelGeochemicalDatabase mgd,
const std::string &  replace_this,
const std::string &  with_this 
)

Check that replacing the named basis species with the named equilibrium species is valid.

In performing this check, the "swap" matrix is inverted, so the check is somewhat expensive. Therefore, if the swap will be performed, assuming it's valid, the performSwap method should be used instead. A mooseError or mooseException will result if the swap is invalid

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
replace_thisThe basis component that will be removed from the basis and added to the equilibrium species list
with_thisThe equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 24 of file GeochemistrySpeciesSwapper.C.

27{
28 if (replace_this == "H2O")
29 mooseError("Cannot remove H2O from the basis");
30 if (mgd.basis_species_index.count(replace_this) == 0)
31 mooseError(replace_this + " is not in the basis, so cannot be removed from the basis");
32 if (mgd.eqm_species_index.count(with_this) == 0)
33 mooseError(with_this + " is not an equilibrium species, so cannot be "
34 "removed from the equilibrium species list");
35
36 checkSwap(mgd, mgd.basis_species_index.at(replace_this), mgd.eqm_species_index.at(with_this));
37}
void checkSwap(const ModelGeochemicalDatabase &mgd, const std::string &replace_this, const std::string &with_this)
Check that replacing the named basis species with the named equilibrium species is valid.

Referenced by checkSwap(), performSwap(), performSwap(), and TEST().

◆ checkSwap() [2/2]

void GeochemistrySpeciesSwapper::checkSwap ( const ModelGeochemicalDatabase mgd,
unsigned  basis_index_to_replace,
unsigned  eqm_index_to_insert 
)

Check that replacing the indexed basis species with the indexed equilibrium species is valid.

In performing this check, the "swap" matrix is inverted, so the check is somewhat expensive. Therefore, if the swap will be performed, assuming it's valid, the performSwap method should be used instead. A mooseError or mooseException will result if the swap is invalid

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
basis_index_to_replaceThe index of the basis component that will be removed from the basis and added to the equilibrium species list
eqm_index_to_insertThe index of the equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 40 of file GeochemistrySpeciesSwapper.C.

43{
44 const unsigned num_cols = mgd.basis_species_index.size();
45 const unsigned num_rows = mgd.eqm_species_index.size();
46 if (basis_index_to_replace == 0)
47 mooseError("Cannot remove H2O from the basis");
48 if (basis_index_to_replace >= num_cols)
49 mooseError(basis_index_to_replace, " exceeds the number of basis species in the problem");
50 if (eqm_index_to_insert >= num_rows)
51 mooseError(eqm_index_to_insert, " exceeds the number of equilibrium species in the problem");
52 if (mgd.surface_sorption_related[eqm_index_to_insert])
54 "Equilibrium species ",
55 mgd.eqm_species_name[eqm_index_to_insert],
56 " is involved in surface sorption so cannot be swapped into the basis. If this is truly "
57 "necessary, code enhancements will need to be made including: recording whether basis "
58 "species are involved in surface sorption, including them in the surface-potential "
59 "calculations, and carefully swapping surface-potential-modified equilibrium constants");
60
61 constructInverseMatrix(mgd, basis_index_to_replace, eqm_index_to_insert);
62}
void constructInverseMatrix(const ModelGeochemicalDatabase &mgd, unsigned basis_index_to_replace, unsigned eqm_index_to_insert)
Construct the swap matrix, and its inverse, that describes the swap between the indexed basis species...
std::vector< bool > surface_sorption_related
surface_sorption_related[j] = true iff the j^th equilibrium species is involved in surface sorption

◆ constructInverseMatrix()

void GeochemistrySpeciesSwapper::constructInverseMatrix ( const ModelGeochemicalDatabase mgd,
unsigned  basis_index_to_replace,
unsigned  eqm_index_to_insert 
)
private

Construct the swap matrix, and its inverse, that describes the swap between the indexed basis species and the indexed equilibrium index.

The inverse of the swap matrix is used in alterMGD to modify its datastructures to implement the swap. A mooseError or mooseException will result if the swap is invalid

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
basis_index_to_replaceThe index of the basis component that will be removed from the basis and added to the equilibrium species list
eqm_index_to_insertThe index of the equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 65 of file GeochemistrySpeciesSwapper.C.

68{
69 const unsigned num_cols = mgd.basis_species_index.size();
70
71 if (_swap_matrix.n() != num_cols)
72 mooseError("GeochemistrySpeciesSwapper constructed with incorrect "
73 "basis_species size");
74
75 // This is a private method, called from checkSwap, so we know that all the inputs have been
76 // sanity-checked. The only way the swap could be invalid is that the swap matrix is not
77 // invertible. This could be due to the solve algorithm attempting to perform an invalid swap, so
78 // only mooseExceptions are thrown below, instead of mooseError, to allow the solve algorithm a
79 // chance to attempt another swap.
80
81 // construct the swap matrix. new_basis = swap_matrix * old_basis
82 // We shove the equilibrium species into the "slot" of the basis species it is
83 // replacing
85 for (unsigned i = 0; i < num_cols; ++i)
86 _swap_matrix(i, i) = 1.0;
87 for (unsigned i = 0; i < num_cols; ++i)
88 _swap_matrix(basis_index_to_replace, i) = mgd.eqm_stoichiometry(eqm_index_to_insert, i);
89
90 // record the swap matrix since the SVD trashes it
92
93 // In order to invert _swap_matrix, perform the SVD: A = U * D * VT
94 // Although every matrix has a SVD, this process might fail due to numerical errors. Therefore
95 // the following could be wrapped in a try-catch block, but I have never been able to trigger a
96 // failure since _swap_matrix is always so well-formed due to all the checks on the database while
97 // parsing it
99 const Real l1norm = _swap_sigma.l1_norm();
100 for (unsigned i = 0; i < num_cols; ++i)
101 if (std::abs(_swap_sigma(i) / l1norm) < _stoi_tol)
102 mooseException("Matrix is not invertible, which signals an invalid basis swap");
103
104 // Find the inverse, which is VT^-1 * D^-1 * U^-1 = V * D^-1 * UT
105 for (unsigned i = 0; i < num_cols; ++i)
106 _swap_U.scale_column(i, 1.0 / _swap_sigma(i)); // (scale the columns of U)^T = D^-1 * UT
107 for (unsigned i = 0; i < num_cols; ++i)
108 for (unsigned j = 0; j < num_cols; ++j)
109 _inv_swap_matrix(i, j) = _swap_VT(j, i); // _inv_swap_matrix = V
110 _inv_swap_matrix.right_multiply_transpose(_swap_U); // V * (scale the columns of U)^T
111}
void scale_column(const unsigned int col, const T factor)
void right_multiply_transpose(const DenseMatrix< T > &A)
void svd(DenseVector< Real > &sigma)
virtual void zero() override final

Referenced by checkSwap().

◆ findBestEqmSwap()

bool GeochemistrySpeciesSwapper::findBestEqmSwap ( unsigned  basis_ind,
const ModelGeochemicalDatabase mgd,
const std::vector< Real > &  eqm_molality,
bool  minerals_allowed,
bool  gas_allowed,
bool  sorption_allowed,
unsigned &  best_eqm_species 
) const

For the the given basis index, find the equilibrium index that it should be swapped with.

Parameters
basis_indindex of basis species in mgd that we'd like to swap out of the basis
mgdthe model's geochemical databgase
eqm_molalitythe molality of all the equilibrium species
minerals_allowedif false, best_eqm_species will not correspond to a mineral. Since equilibrium minerals have molality=0 it is very unlikely that best_eqm_species will correspond to a mineral, even if this flag is true.
gases_allowedif false, best_eqm_species will not correspond to a gas. Since equilibrium gases have molality=0 it is very unlikely that best_eqm_species will correspond to a gas, even if this flag is true.
sorption_allowedif false, best_eqm_species will not be involved in sorption
[out]best_eqm_speciesthe index of the equilibrium species that should be swapped with basis_ind
Returns
true if a valid swap was found. if false, then best_eqm_species will be garbage

Definition at line 368 of file GeochemistrySpeciesSwapper.C.

375{
376 const unsigned num_eqm = mgd.eqm_species_name.size();
377 if (eqm_molality.size() != num_eqm)
378 mooseError("Size of eqm_molality is ",
379 eqm_molality.size(),
380 " which is not equal to the number of equilibrium species ",
381 num_eqm);
382 if (basis_ind >= mgd.basis_species_name.size())
383 mooseError("basis index ", basis_ind, " must be less than ", mgd.basis_species_name.size());
384 best_eqm_species = 0;
385 bool legitimate_swap_found = false;
386 Real best_stoi = 0.0;
387 for (unsigned j = 0; j < num_eqm; ++j)
388 {
389 if (mgd.eqm_stoichiometry(j, basis_ind) == 0.0)
390 continue;
391 if (!minerals_allowed && mgd.eqm_species_mineral[j])
392 continue;
393 if (!gas_allowed && mgd.eqm_species_gas[j])
394 continue;
395 if (!sorption_allowed && mgd.surface_sorption_related[j])
396 continue;
397 const Real stoi = std::abs(mgd.eqm_stoichiometry(j, basis_ind)) * eqm_molality[j];
398 if (stoi >= best_stoi)
399 {
400 best_stoi = stoi;
401 best_eqm_species = j;
402 legitimate_swap_found = true;
403 }
404 }
405 return legitimate_swap_found;
406}

Referenced by GeochemistryTimeDependentReactor::preSolveDump(), GeochemicalSolver::swapNeeded(), TEST(), and TEST().

◆ operator==()

bool GeochemistrySpeciesSwapper::operator== ( const GeochemistrySpeciesSwapper rhs) const
inline

Definition at line 31 of file GeochemistrySpeciesSwapper.h.

32 {
33 return (_stoi_tol == rhs._stoi_tol) && (_swap_matrix.m() == rhs._swap_matrix.m());
34 };

◆ performSwap() [1/4]

void GeochemistrySpeciesSwapper::performSwap ( ModelGeochemicalDatabase mgd,
const std::string &  replace_this,
const std::string &  with_this 
)

Check that replacing the named basis species with the named equilibrium species is valid, and then perform this swap by altering the mgd data structure.

A mooseError or mooseException will result if the swap is invalid

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
replace_thisThe basis component that will be removed from the basis and added to the equilibrium species list
with_thisThe equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 114 of file GeochemistrySpeciesSwapper.C.

117{
118 // check the swap is valid (if not then mooseError or mooseException)
119 // and if it's valid, create the inverse swap matrix
120 checkSwap(mgd, replace_this, with_this);
121
122 // perform the swap inside the MGD datastructure
123 alterMGD(mgd, mgd.basis_species_index.at(replace_this), mgd.eqm_species_index.at(with_this));
124}
void alterMGD(ModelGeochemicalDatabase &mgd, unsigned basis_index_to_replace, unsigned eqm_index_to_insert)
Modify the ModelGeochemicalDatabase mgd to swap the indexed basis species and the indexed equilibrium...

Referenced by GeochemicalSystem::checkAndInitialize(), GeochemicalModelInterrogator::output(), performSwap(), performSwap(), GeochemicalSystem::performSwapNoCheck(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), and TEST().

◆ performSwap() [2/4]

void GeochemistrySpeciesSwapper::performSwap ( ModelGeochemicalDatabase mgd,
DenseVector< Real > &  bulk_composition,
const std::string &  replace_this,
const std::string &  with_this 
)

Check that replacing the named basis species with the named equilibrium species is valid, and then perform this swap by altering the mgd data structure, and calculate the bulk composition of the new system.

A mooseError or mooseException will result if the swap is invalid

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
[in/out]bulk_composition Upon entry, the bulk composition in the original basis. Upon exit, the bulk composition in the basis after the swap
replace_thisThe basis component that will be removed from the basis and added to the equilibrium species list
with_thisThe equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 140 of file GeochemistrySpeciesSwapper.C.

144{
145 performSwap(mgd, replace_this, with_this);
146 // compute the bulk composition expressed in the new basis
147 alterBulkComposition(mgd.basis_species_index.size(), bulk_composition);
148}
void alterBulkComposition(unsigned basis_size, DenseVector< Real > &bulk_composition) const
Calculate the bulk composition in the new basis based on the bulk composition in the original basis.
void performSwap(ModelGeochemicalDatabase &mgd, const std::string &replace_this, const std::string &with_this)
Check that replacing the named basis species with the named equilibrium species is valid,...

◆ performSwap() [3/4]

void GeochemistrySpeciesSwapper::performSwap ( ModelGeochemicalDatabase mgd,
DenseVector< Real > &  bulk_composition,
unsigned  basis_index_to_replace,
unsigned  eqm_index_to_insert 
)

Check that replacing the indexed basis species with the indexed equilibrium species is valid, and then perform this swap by altering the mgd data structure, and calculate the bulk composition of the new system.

A mooseError or mooseException will result if the swap is invalid

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
[in/out]bulk_composition Upon entry, the bulk composition in the original basis. Upon exit, the bulk composition in the basis after the swap
basis_index_to_replaceThe index of the basis component that will be removed from the basis and added to the equilibrium species list
eqm_index_to_insertThe index of the equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 151 of file GeochemistrySpeciesSwapper.C.

155{
156 performSwap(mgd, basis_index_to_replace, eqm_index_to_insert);
157 // compute the bulk composition expressed in the new basis
158 alterBulkComposition(mgd.basis_species_index.size(), bulk_composition);
159}

◆ performSwap() [4/4]

void GeochemistrySpeciesSwapper::performSwap ( ModelGeochemicalDatabase mgd,
unsigned  basis_index_to_replace,
unsigned  eqm_index_to_insert 
)

Check that replacing the indexed basis species with the indexed equilibrium species is valid, and then perform this swap by altering the mgd data structure.

A mooseError or mooseException will result if the swap is invalid

Parameters
mgdThe ModelGeochemicalDatabase that holds all information regarding basis components, equilibrium species, stoichiometries, etc
basis_index_to_replaceThe index of the basis component that will be removed from the basis and added to the equilibrium species list
eqm_index_to_insertThe index of the equilibrium species that will be removed from the equilibrium species list and added to the basis component list

Definition at line 127 of file GeochemistrySpeciesSwapper.C.

130{
131 // check the swap is valid (if not then mooseError or mooseException)
132 // and if it's valid, create the inverse swap matrix
133 checkSwap(mgd, basis_index_to_replace, eqm_index_to_insert);
134
135 // perform the swap inside the MGD datastructure
136 alterMGD(mgd, basis_index_to_replace, eqm_index_to_insert);
137}

Member Data Documentation

◆ _inv_swap_matrix

DenseMatrix<Real> GeochemistrySpeciesSwapper::_inv_swap_matrix
private

inverse of swap matrix

Definition at line 216 of file GeochemistrySpeciesSwapper.h.

Referenced by alterBulkComposition(), alterMGD(), and constructInverseMatrix().

◆ _stoi_tol

Real GeochemistrySpeciesSwapper::_stoi_tol
private

tolerance for matrix inversion and stoichiometric coefficients

Definition at line 203 of file GeochemistrySpeciesSwapper.h.

Referenced by alterMGD(), constructInverseMatrix(), and operator==().

◆ _swap_matrix

DenseMatrix<Real> GeochemistrySpeciesSwapper::_swap_matrix
private

swap matrix

Definition at line 206 of file GeochemistrySpeciesSwapper.h.

Referenced by constructInverseMatrix(), and operator==().

◆ _swap_sigma

DenseVector<Real> GeochemistrySpeciesSwapper::_swap_sigma
private

used in SVD decomposition of swap matrix

Definition at line 219 of file GeochemistrySpeciesSwapper.h.

Referenced by constructInverseMatrix().

◆ _swap_U

DenseMatrix<Real> GeochemistrySpeciesSwapper::_swap_U
private

used in SVD decomposition of swap matrix

Definition at line 222 of file GeochemistrySpeciesSwapper.h.

Referenced by constructInverseMatrix().

◆ _swap_VT

DenseMatrix<Real> GeochemistrySpeciesSwapper::_swap_VT
private

used in SVD decomposition of swap matrix

Definition at line 225 of file GeochemistrySpeciesSwapper.h.

Referenced by constructInverseMatrix().

◆ _true_swap_matrix

DenseMatrix<Real> GeochemistrySpeciesSwapper::_true_swap_matrix
private

Before _swap_matrix.svd (a non-const method) is called, we copy _true_swap_matrix = _swap_matrix.

It is necessary to record _swap_matrix in this fashion so that mgd.swap_to_original_basis can be modified using it

Definition at line 213 of file GeochemistrySpeciesSwapper.h.

Referenced by alterMGD(), and constructInverseMatrix().


The documentation for this class was generated from the following files: