https://mooseframework.inl.gov
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 

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. More...
 
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. More...
 
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. More...
 

Private Attributes

Real _stoi_tol
 tolerance for matrix inversion and stoichiometric coefficients More...
 
DenseMatrix< Real_swap_matrix
 swap matrix More...
 
DenseMatrix< Real_true_swap_matrix
 Before _swap_matrix.svd (a non-const method) is called, we copy _true_swap_matrix = _swap_matrix. More...
 
DenseMatrix< Real_inv_swap_matrix
 inverse of swap matrix More...
 
DenseVector< Real_swap_sigma
 used in SVD decomposition of swap matrix More...
 
DenseMatrix< Real_swap_U
 used in SVD decomposition of swap matrix More...
 
DenseMatrix< Real_swap_VT
 used in SVD decomposition of swap matrix More...
 

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

Referenced by performSwap().

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 }
DenseMatrix< Real > _inv_swap_matrix
inverse of swap matrix
void mooseError(Args &&... args)
void vector_mult_transpose(DenseVector< Real > &dest, const DenseVector< Real > &arg) const

◆ 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.

Referenced by performSwap().

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 }
DenseMatrix< Real > redox_stoichiometry
redox_stoichiometry(i, j) = stoichiometric coefficients for i^th redox species that is in disequilibr...
std::vector< Real > eqm_species_molecular_weight
all quantities have a molecular weight (g)
std::string redox_lhs
the name of the species on the left-hand side of the redox equations.
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 > _inv_swap_matrix
inverse of swap matrix
std::vector< bool > eqm_species_gas
eqm_species_gas[i] = true iff the i^th equilibrium species is a gas
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
const ModelGeochemicalDatabase mgd
DenseMatrix< Real > kin_stoichiometry
kin_stoichiometry(i, j) = stoichiometric coefficient for kinetic species "i" in terms of the basis sp...
unsigned int m() const
std::unordered_map< std::string, unsigned > eqm_species_index
eqm_species_index[name] = index of the equilibrium species (secondary aqueous species, redox couples in equilibrium with the aqueous solution, minerals in equilibrium with the aqueous solution, gases in equilibrium with the aqueous solution) within all ModelGeochemicalDatabase internal datastrcutres, with given name
DenseMatrix< Real > redox_log10K
redox_log10K(i, j) = log10(equilibrium constant) for i^th redox species at the j^th temperature point...
DenseMatrix< Real > swap_to_original_basis
Swap matrix that allows expression in terms of the original basis.
DenseMatrix< Real > eqm_stoichiometry
eqm_stoichiometry(i, j) = stoichiometric coefficient for equilibrium species "i" in terms of the basi...
std::vector< Real > basis_species_radius
all quantities have an ionic radius (Angstrom) for computing activity (mineral radius = 0...
DenseMatrix< Real > _true_swap_matrix
Before _swap_matrix.svd (a non-const method) is called, we copy _true_swap_matrix = _swap_matrix...
Real _stoi_tol
tolerance for matrix inversion and stoichiometric coefficients
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< Real > eqm_species_radius
all quantities have an ionic radius (Angstrom) for computing activity (mineral radius = 0...
DenseMatrix< Real > eqm_log10K
eqm_log10K(i, j) = log10(equilibrium constant) for i^th equilibrium species at the j^th temperature p...
std::vector< Real > basis_species_molecular_weight
all quantities have a molecular weight (g)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< bool > eqm_species_transported
eqm_species_transported[i] = true iff the i^th eqm species is transported in reactive-transport sims ...
std::vector< Real > eqm_species_molecular_volume
all quantities have a molecular volume (cm^3) (only nonzero for minerals, however) ...
virtual void right_multiply(const DenseMatrixBase< Real > &M2) override final
std::vector< Real > basis_species_charge
all quantities have a charge (mineral charge = 0, gas charge = 0, oxide charge = 0) ...
std::vector< unsigned > have_swapped_into_basis
Species that have been swapped into the basis.
std::vector< bool > basis_species_gas
basis_species_gas[j] = true iff the j^th basis species is a gas
std::vector< bool > basis_species_mineral
basis_species_mineral[j] = true iff the j^th basis species is a mineral
std::vector< Real > eqm_species_charge
all quantities have a charge (mineral charge = 0, gas charge = 0, oxide charge = 0) ...
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< bool > eqm_species_mineral
eqm_species_mineral[i] = true iff the i^th equilibrium species is a mineral
std::vector< Real > basis_species_molecular_volume
all quantities have a molecular volume (cm^3) (only nonzero for minerals, however) ...
unsigned int n() const
std::vector< std::string > eqm_species_name
eqm_species_name[i] = name of the i^th eqm species
std::vector< std::string > basis_species_name
basis_species_name[j] = name of the j^th basis species
virtual void left_multiply(const DenseMatrixBase< Real > &M2) override final
std::vector< unsigned > have_swapped_out_of_basis
Species that have been swapped out of the basis.
std::vector< KineticRateDefinition > kin_rate
rates given to kinetic species.

◆ 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.

Referenced by performSwap(), and TEST().

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 mooseError(Args &&... args)
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
const ModelGeochemicalDatabase mgd
std::unordered_map< std::string, unsigned > eqm_species_index
eqm_species_index[name] = index of the equilibrium species (secondary aqueous species, redox couples in equilibrium with the aqueous solution, minerals in equilibrium with the aqueous solution, gases in equilibrium with the aqueous solution) within all ModelGeochemicalDatabase internal datastrcutres, with given name
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...

◆ 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])
53  mooseError(
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 }
std::vector< bool > surface_sorption_related
surface_sorption_related[j] = true iff the j^th equilibrium species is involved in surface sorption ...
void mooseError(Args &&... args)
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
const ModelGeochemicalDatabase mgd
std::unordered_map< std::string, unsigned > eqm_species_index
eqm_species_index[name] = index of the equilibrium species (secondary aqueous species, redox couples in equilibrium with the aqueous solution, minerals in equilibrium with the aqueous solution, gases in equilibrium with the aqueous solution) within all ModelGeochemicalDatabase internal datastrcutres, with given name
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< std::string > eqm_species_name
eqm_species_name[i] = name of the i^th eqm species

◆ 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.

Referenced by checkSwap().

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 }
DenseVector< Real > _swap_sigma
used in SVD decomposition of swap matrix
DenseMatrix< Real > _swap_VT
used in SVD decomposition of swap matrix
DenseMatrix< Real > _inv_swap_matrix
inverse of swap matrix
void mooseError(Args &&... args)
virtual void zero() override final
DenseMatrix< Real > _swap_U
used in SVD decomposition of swap matrix
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
const ModelGeochemicalDatabase mgd
DenseMatrix< Real > eqm_stoichiometry
eqm_stoichiometry(i, j) = stoichiometric coefficient for equilibrium species "i" in terms of the basi...
void scale_column(const unsigned int col, const Real factor)
DenseMatrix< Real > _true_swap_matrix
Before _swap_matrix.svd (a non-const method) is called, we copy _true_swap_matrix = _swap_matrix...
void svd(DenseVector< Real > &sigma)
Real _stoi_tol
tolerance for matrix inversion and stoichiometric coefficients
void right_multiply_transpose(const DenseMatrix< Real > &A)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
DenseMatrix< Real > _swap_matrix
swap matrix
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
unsigned int n() const

◆ 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.

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

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 }
std::vector< bool > surface_sorption_related
surface_sorption_related[j] = true iff the j^th equilibrium species is involved in surface sorption ...
void mooseError(Args &&... args)
std::vector< bool > eqm_species_gas
eqm_species_gas[i] = true iff the i^th equilibrium species is a gas
const ModelGeochemicalDatabase mgd
DenseMatrix< Real > eqm_stoichiometry
eqm_stoichiometry(i, j) = stoichiometric coefficient for equilibrium species "i" in terms of the basi...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< bool > eqm_species_mineral
eqm_species_mineral[i] = true iff the i^th equilibrium species is a mineral
std::vector< std::string > eqm_species_name
eqm_species_name[i] = name of the i^th eqm species
std::vector< std::string > basis_species_name
basis_species_name[j] = name of the j^th basis species

◆ 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  };
unsigned int m() const
Real _stoi_tol
tolerance for matrix inversion and stoichiometric coefficients
DenseMatrix< Real > _swap_matrix
swap matrix

◆ 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.

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

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...
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
const ModelGeochemicalDatabase mgd
std::unordered_map< std::string, unsigned > eqm_species_index
eqm_species_index[name] = index of the equilibrium species (secondary aqueous species, redox couples in equilibrium with the aqueous solution, minerals in equilibrium with the aqueous solution, gases in equilibrium with the aqueous solution) within all ModelGeochemicalDatabase internal datastrcutres, with given name
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...

◆ performSwap() [2/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 }
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...
const ModelGeochemicalDatabase mgd
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...

◆ performSwap() [3/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 }
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
const ModelGeochemicalDatabase mgd
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...
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...

◆ performSwap() [4/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 }
std::unordered_map< std::string, unsigned > basis_species_index
basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase internal ...
const ModelGeochemicalDatabase mgd
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...
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...

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: