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

This class contains methods to solve the algebraic system in GeochemicalSystem. More...

#include <GeochemicalSolver.h>

Public Member Functions

 GeochemicalSolver (unsigned num_basis, unsigned num_kin, GeochemistryIonicStrength &is, Real abs_tol, Real rel_tol, unsigned max_iter, Real max_initial_residual, Real swap_threshold, unsigned max_swaps_allowed, const std::vector< std::string > &prevent_precipitation, Real max_ionic_strength, unsigned ramp_max_ionic_strength, bool evaluate_kin_always)
 Construct and check for sensible arguments.
 
void solveSystem (GeochemicalSystem &egs, std::stringstream &ss, unsigned &tot_iter, Real &abs_residual, Real dt, DenseVector< Real > &mole_additions, DenseMatrix< Real > &dmole_additions)
 Solve the system.
 
void setMaxInitialResidual (Real max_initial_residual)
 Set value for max_initial_residual.
 
Real getMaxInitialResidual () const
 Get value for max_initial_residual.
 
void setRampMaxIonicStrength (unsigned ramp_max_ionic_strength)
 Sets the value of _ramp_max_ionic_strength.
 
unsigned getRampMaxIonicStrength () const
 Gets the value of _ramp_max_ionic_strength.
 

Private Member Functions

Real computeResidual (const GeochemicalSystem &egs, DenseVector< Real > &residual, const DenseVector< Real > &mole_additions) const
 Builds the residual of the algebraic system.
 
void solveAndUnderrelax (const GeochemicalSystem &egs, DenseMatrix< Real > &jacobian, DenseVector< Real > &new_mol) const
 Solves _jacobian * neg_change_mol = _residual for neg_change_mol, then performs an underrelaxation to get new_mol.
 
bool swapNeeded (const GeochemicalSystem &egs, unsigned &swap_out_of_basis, unsigned &swap_into_basis, std::stringstream &ss) const
 Check if a basis swap is needed.
 
bool reduceInitialResidual (GeochemicalSystem &egs, Real dt, DenseVector< Real > &mole_additions, DenseMatrix< Real > &dmole_additions)
 Progressively alter the initial-guess molalities for the algebraic system to attempt to reduce the residual.
 

Private Attributes

GeochemistryIonicStrength_is
 The ionic-strength calculator.
 
const unsigned _num_basis
 Number of species in the basis.
 
const unsigned _num_kin
 Number of kinetic species.
 
unsigned _num_basis_in_algebraic_system
 Number of basis molalities (and potentially solvent water mass) in the algebraic system.
 
unsigned _num_in_algebraic_system
 Number of unknowns (molalities and surface potentials) in the algebraic system.
 
DenseVector< Real > _residual
 residual of the algebraic system we wish to solve
 
Real _abs_residual
 L1 norm of residual.
 
DenseMatrix< Real > _jacobian
 jacobian of the algebraic system
 
DenseVector< Real > _new_mol
 the new molality after finding the solution of _jacobian * neg_change_mol = _residual
 
const Real _abs_tol
 If the residual of the algebraic system falls below this value, the Newton process has converged.
 
const Real _rel_tol
 If the residual of the algebraic system falls below this value times the initial residual, the Newton process has converged.
 
Real _res0_times_rel
 _res0_times_rel = _rel_tol * initial residual
 
const unsigned _max_iter
 maximum number of iterations allowed during an inner solve
 
Real _max_initial_residual
 maximum desired initial residual
 
const Real _swap_threshold
 If a basis molality < swap_threshold, we attempt to swap it out of the basis.
 
const unsigned _max_swaps_allowed
 Maximum number of swaps allowed before the solve aborts.
 
const std::vector< std::string > _prevent_precipitation
 The minerals named in this list can have positive saturation indices and will not precipitate.
 
const Real _max_ionic_strength
 Maximum ionic strength allowed.
 
unsigned _ramp_max_ionic_strength
 Number of iterations over which to increase the maximum ionic strength to _max_ionic_strength.
 
bool _evaluate_kin_always
 When to compute the kinetic rates: if true then evaluate before every residual calculation, otherwise evaluate only at the start of the solve process (using, eg, the old molality values)
 
DenseVector< Real > _input_mole_additions
 the mole_additions for the basis and kinetic species as specified in the argument of solveSystem
 
DenseMatrix< Real > _input_dmole_additions
 d(mole_additions)/d(species) as specified in the argument of solveSystem
 

Detailed Description

This class contains methods to solve the algebraic system in GeochemicalSystem.

Definition at line 18 of file GeochemicalSolver.h.

Constructor & Destructor Documentation

◆ GeochemicalSolver()

GeochemicalSolver::GeochemicalSolver ( unsigned  num_basis,
unsigned  num_kin,
GeochemistryIonicStrength is,
Real  abs_tol,
Real  rel_tol,
unsigned  max_iter,
Real  max_initial_residual,
Real  swap_threshold,
unsigned  max_swaps_allowed,
const std::vector< std::string > &  prevent_precipitation,
Real  max_ionic_strength,
unsigned  ramp_max_ionic_strength,
bool  evaluate_kin_always 
)

Construct and check for sensible arguments.

Parameters
num_basisNumber of basis species in the system
mum_kinNumber of kinetic species in the system
isThe object to compute ionic strengths. GeochemicalSolver changes the maximum value of ionic strength as it progresses towards the solution
abs_tolThe Newton solution process is deemed to have converged if the L1 norm of the residual < abs_tol
rel_tolThe Newton solution process is deemed to have converged if the L1 norm of the residual < rel_tol * residual_0
max_iterOnly max_iter Newton iterations are allowed in solving the system
max_initial_residualegs guesses the initial configuration, but sometimes this results in a very large initial residual. GeochemicalSolver will attempt to alter the initial guesses for molalities so that the initial residual is less than max_initial_residual. This parameter may be varied during runtime which might be useful in time-dependent simulations if the first residual is poor but the remainder are deemed likely to be OK
swap_thresholdIf a basis molality < swap_threshold at the end of the Newton process, GeochemicalSolver attempts to swap it out of the basis
max_swaps_allowedMaximum number of swaps allowed before the solve process aborts
prevent_precipitationThe minerals named in this vector will not be allowed to precipitate, even if their saturation indices are positive
max_ionic_strengthMaximum ionic strength ever allowed
ramp_max_ionic_strengthThe maximum ionic strength is ramped from 0 to max_ionic_strength over the course of the first ramp_max_ionic_strength Newton iterations. This can help with convergence.
evaluate_kin_alwaysIf true then evaluate the kinetic rates before each residual calculation, otherwise evaluate them only at the start of the solve process (which will be using the molalities, etc from the previous time-step)

Definition at line 13 of file GeochemicalSolver.C.

26 : _is(is),
27 _num_basis(num_basis),
28 _num_kin(num_kin),
32 _abs_residual(0.0),
35 _abs_tol(abs_tol),
36 _rel_tol(rel_tol),
37 _res0_times_rel(0.0),
38 _max_iter(max_iter),
39 _max_initial_residual(max_initial_residual),
40 _swap_threshold(swap_threshold),
41 _max_swaps_allowed(max_swaps_allowed),
42 _prevent_precipitation(prevent_precipitation),
43 _max_ionic_strength(max_ionic_strength),
44 _ramp_max_ionic_strength(ramp_max_ionic_strength),
45 _evaluate_kin_always(evaluate_kin_always),
48{
50 mooseError("GeochemicalSolver: ramp_max_ionic_strength must be less than max_iter");
51 if (max_initial_residual <= 0.0)
52 mooseError("GeochemicalSolver: max_initial_residual must be positive");
53 if (max_ionic_strength < 0.0)
54 mooseError("GeochemicalSolver: max_ionic_strength must not be negative");
55 if (abs_tol < 0.0)
56 mooseError("GeochemicalSolver: abs_tol must not be negative");
57 if (rel_tol < 0.0)
58 mooseError("GeochemicalSolver: rel_tol must not be negative");
59 if (rel_tol == 0.0 && abs_tol == 0.0)
60 mooseError("GeochemicalSolver: either rel_tol or abs_tol must be positive");
61}
void mooseError(Args &&... args)
unsigned _ramp_max_ionic_strength
Number of iterations over which to increase the maximum ionic strength to _max_ionic_strength.
DenseVector< Real > _new_mol
the new molality after finding the solution of _jacobian * neg_change_mol = _residual
DenseMatrix< Real > _input_dmole_additions
d(mole_additions)/d(species) as specified in the argument of solveSystem
Real _max_initial_residual
maximum desired initial residual
const unsigned _max_iter
maximum number of iterations allowed during an inner solve
bool _evaluate_kin_always
When to compute the kinetic rates: if true then evaluate before every residual calculation,...
const unsigned _num_basis
Number of species in the basis.
const std::vector< std::string > _prevent_precipitation
The minerals named in this list can have positive saturation indices and will not precipitate.
DenseVector< Real > _input_mole_additions
the mole_additions for the basis and kinetic species as specified in the argument of solveSystem
DenseVector< Real > _residual
residual of the algebraic system we wish to solve
DenseMatrix< Real > _jacobian
jacobian of the algebraic system
const Real _rel_tol
If the residual of the algebraic system falls below this value times the initial residual,...
const Real _max_ionic_strength
Maximum ionic strength allowed.
const Real _swap_threshold
If a basis molality < swap_threshold, we attempt to swap it out of the basis.
Real _abs_residual
L1 norm of residual.
Real _res0_times_rel
_res0_times_rel = _rel_tol * initial residual
unsigned _num_basis_in_algebraic_system
Number of basis molalities (and potentially solvent water mass) in the algebraic system.
const Real _abs_tol
If the residual of the algebraic system falls below this value, the Newton process has converged.
const unsigned _num_kin
Number of kinetic species.
GeochemistryIonicStrength & _is
The ionic-strength calculator.
const unsigned _max_swaps_allowed
Maximum number of swaps allowed before the solve aborts.
unsigned _num_in_algebraic_system
Number of unknowns (molalities and surface potentials) in the algebraic system.

Member Function Documentation

◆ computeResidual()

Real GeochemicalSolver::computeResidual ( const GeochemicalSystem egs,
DenseVector< Real > &  residual,
const DenseVector< Real > &  mole_additions 
) const
private

Builds the residual of the algebraic system.

Parameters
egsThe geochemical system to use to compute the residual
residualThe residual components will be placed here
mole_additionsthe increment of mole number of each basis species and kinetic species since the last timestep.
Returns
the L1 norm of residual

Definition at line 78 of file GeochemicalSolver.C.

81{
82 for (unsigned a_ind = 0; a_ind < _num_in_algebraic_system; ++a_ind)
83 residual(a_ind) = egs.getResidualComponent(a_ind, mole_additions);
84 return residual.l1_norm();
85}
Real getResidualComponent(unsigned algebraic_ind, const DenseVector< Real > &mole_additions) const
Return the residual of the algebraic system for the given algebraic index.

Referenced by reduceInitialResidual(), and solveSystem().

◆ getMaxInitialResidual()

Real GeochemicalSolver::getMaxInitialResidual ( ) const

Get value for max_initial_residual.

Definition at line 72 of file GeochemicalSolver.C.

73{
75}

◆ getRampMaxIonicStrength()

unsigned GeochemicalSolver::getRampMaxIonicStrength ( ) const

Gets the value of _ramp_max_ionic_strength.

Definition at line 470 of file GeochemicalSolver.C.

471{
473}

◆ reduceInitialResidual()

bool GeochemicalSolver::reduceInitialResidual ( GeochemicalSystem egs,
Real  dt,
DenseVector< Real > &  mole_additions,
DenseMatrix< Real > &  dmole_additions 
)
private

Progressively alter the initial-guess molalities for the algebraic system to attempt to reduce the residual.

Parameters
egsThe GeochemicalSystem we're trying to solve
dttime-step size (used for determining kinetic rates)
mole_additionsthe increment of mole number of each basis species and kinetic species since the last timestep. This may change during this function as kinetic rates depend on molalities
dmole_additionsd(mole_additions)/(molality and kinetic moles)

Definition at line 241 of file GeochemicalSolver.C.

245{
246 const Real initial_r = _abs_residual;
247
248 // to get an indication of whether we should increase or decrease molalities in the algorithm
249 // below, find the median of the original molalities
250 const std::vector<Real> & original_molality = egs.getAlgebraicBasisValues();
251 const std::vector<unsigned> mol_order =
252 GeochemistrySortedIndices::sortedIndices(original_molality, false);
253 const Real median_molality = original_molality[mol_order[_num_basis_in_algebraic_system / 2]];
254
255 // get the index order of the residual vector (largest first): ignore residuals for surface
256 // potentials (we're only using _num_basis_in_algebraic_system, not _num_in_algebraic_system)
257 unsigned ind = 0;
258 std::vector<unsigned> res_order(_num_basis_in_algebraic_system);
259 std::iota(res_order.begin(), res_order.end(), ind++);
260 std::sort(res_order.begin(),
261 res_order.end(),
262 [&](int i, int j) { return std::abs(_residual(i)) > std::abs(_residual(j)); });
263
264 const std::vector<Real> & original_molality_and_pot = egs.getAlgebraicVariableValues();
265 DenseVector<Real> new_molality_and_pot(original_molality_and_pot);
266 for (const auto & a : res_order)
267 {
268 if (std::abs(_residual(a)) < _max_initial_residual)
269 return false; // haven't managed to find a suitable new molality, and all remaining residual
270 // components are less than the cutoff, so cannot appreciably reduce from now
271 // on
272
273 const Real multiplier = (original_molality_and_pot[a] > median_molality) ? 0.5 : 2.0;
274 // try using the multiplier
275 new_molality_and_pot(a) = multiplier * original_molality_and_pot[a];
276 egs.setAlgebraicVariables(new_molality_and_pot);
278 {
279 mole_additions = _input_mole_additions;
280 dmole_additions = _input_dmole_additions;
281 egs.addKineticRates(dt, mole_additions, dmole_additions);
282 }
283 _abs_residual = computeResidual(egs, _residual, mole_additions);
284 if (_abs_residual < initial_r)
285 return true; // success: found a new molality that decreases the initial |R|
286
287 // the above approach did not decrease |R|, so try using 1/multiplier
288 new_molality_and_pot(a) = original_molality_and_pot[a] / multiplier;
289 egs.setAlgebraicVariables(new_molality_and_pot);
291 {
292 mole_additions = _input_mole_additions;
293 dmole_additions = _input_dmole_additions;
294 egs.addKineticRates(dt, mole_additions, dmole_additions);
295 }
296 _abs_residual = computeResidual(egs, _residual, mole_additions);
297 if (_abs_residual < initial_r)
298 return true; // success: found a new molality that decreases the initial |R|
299
300 // the new molalities did not decrease |R|, so revert to the original molality, and move to
301 // next-biggest residual component
302 new_molality_and_pot(a) = original_molality_and_pot[a];
303 egs.setAlgebraicVariables(new_molality_and_pot);
305 {
306 mole_additions = _input_mole_additions;
307 dmole_additions = _input_dmole_additions;
308 egs.addKineticRates(dt, mole_additions, dmole_additions);
309 }
310 _abs_residual = computeResidual(egs, _residual, mole_additions);
311 }
312 return false;
313}
Real computeResidual(const GeochemicalSystem &egs, DenseVector< Real > &residual, const DenseVector< Real > &mole_additions) const
Builds the residual of the algebraic system.
std::vector< Real > getAlgebraicBasisValues() const
void setAlgebraicVariables(const DenseVector< Real > &algebraic_var)
Set the variables in the algebraic system (molalities and potentially the mass of solvent water,...
void addKineticRates(Real dt, DenseVector< Real > &mole_additions, DenseMatrix< Real > &dmole_additions)
Computes the kinetic rates and their derivatives based on the current values of molality,...
std::vector< Real > getAlgebraicVariableValues() const
std::vector< unsigned > sortedIndices(const std::vector< Real > &to_sort, bool ascending)
Produces a vector of indices corresponding to the smallest-to-biggest entries in to_sort (or biggest-...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

Referenced by solveSystem().

◆ setMaxInitialResidual()

void GeochemicalSolver::setMaxInitialResidual ( Real  max_initial_residual)

Set value for max_initial_residual.

Definition at line 64 of file GeochemicalSolver.C.

65{
66 if (max_initial_residual <= 0.0)
67 mooseError("GeochemicalSolver: max_initial_residual must be positive");
68 _max_initial_residual = max_initial_residual;
69}

Referenced by TEST().

◆ setRampMaxIonicStrength()

void GeochemicalSolver::setRampMaxIonicStrength ( unsigned  ramp_max_ionic_strength)

Sets the value of _ramp_max_ionic_strength.

Definition at line 462 of file GeochemicalSolver.C.

463{
464 if (ramp_max_ionic_strength > _max_iter)
465 mooseError("GeochemicalSolver: ramp_max_ionic_strength must be less than max_iter");
466 _ramp_max_ionic_strength = ramp_max_ionic_strength;
467}

Referenced by GeochemistrySpatialReactor::execute(), and GeochemistryTimeDependentReactor::execute().

◆ solveAndUnderrelax()

void GeochemicalSolver::solveAndUnderrelax ( const GeochemicalSystem egs,
DenseMatrix< Real > &  jacobian,
DenseVector< Real > &  new_mol 
) const
private

Solves _jacobian * neg_change_mol = _residual for neg_change_mol, then performs an underrelaxation to get new_mol.

Parameters
egsThe geochemical system that we're trying to solve
jacobianthe jacobian of the system
new_molupon exit, this will be the new molality (and surface potential values, if any) values according to the underrelaxed Newton process

Definition at line 88 of file GeochemicalSolver.C.

91{
92 jacobian.lu_solve(_residual, new_mol);
93
94 // at this point we want to do molality = molality - new_mol, but
95 // Bethke recommends underrelaxation - probably want to do PETSc variational bounds in the
96 // future
97 Real one_over_delta = 1.0;
98 const std::vector<Real> current_molality_and_pot = egs.getAlgebraicVariableValues();
99 for (unsigned a_ind = 0; a_ind < _num_in_algebraic_system; ++a_ind)
100 one_over_delta =
101 std::max(one_over_delta, new_mol(a_ind) * 2.0 / current_molality_and_pot[a_ind]);
102 for (unsigned a_ind = 0; a_ind < _num_in_algebraic_system; ++a_ind)
103 new_mol(a_ind) = current_molality_and_pot[a_ind] - new_mol(a_ind) / one_over_delta;
104}
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)

Referenced by solveSystem().

◆ solveSystem()

void GeochemicalSolver::solveSystem ( GeochemicalSystem egs,
std::stringstream &  ss,
unsigned &  tot_iter,
Real &  abs_residual,
Real  dt,
DenseVector< Real > &  mole_additions,
DenseMatrix< Real > &  dmole_additions 
)

Solve the system.

Parameters
egsThe geochemical system that needs to be solved. This gets modified as the solve progresses
ssTextual information such as (iteration, residual) and swap information is written to this stringstream
tot_iterThe total number of iterations used in the solve
abs_residualThe residual of the algebraic system as this method exits
mole_additionsthe increment of mole number of each basis species and kinetic species since the last timestep. This must have size _num_basis + _num_kin. For the basis species, this is the amount of each species being injected into the system over the timestep. For the kinetic species, this is -dt*reaction_rate. Please note: do not decompose the kinetic-species additions into basis components and add them to the first slots of mole_additions! This method does that decomposition automatically. The first _num_basis slots of mole_additions contain kinetic-independent additions, while the last _num_kin slots contain kinetic-rate contributions. This may change during the solution process as kinetic rates depend on molalities.
dmole_additionsdmole_additions(a, b) = d(mole_additions(a))/d(basis_molality(b)) for b < _num_basis and d(mole_additions(a))/d(kinetic_moles(b - _num_basis)) otherwise.

Definition at line 316 of file GeochemicalSolver.C.

323{
324 ss.str("");
325 tot_iter = 0;
326 unsigned num_swaps = 0;
327
328 // capture the inputs expressed in the current basis
329 _input_mole_additions = mole_additions;
330 _input_dmole_additions = dmole_additions;
331
333
334 bool still_swapping = true;
335 while (still_swapping && num_swaps <= _max_swaps_allowed)
336 {
339 _residual = DenseVector<Real>(_num_in_algebraic_system);
341 _new_mol = DenseVector<Real>(_num_in_algebraic_system);
342
343 unsigned iter = 0;
344 const Real max_is0 =
345 std::min(1.0, (iter + 1.0) / (_ramp_max_ionic_strength + 1.0)) * _max_ionic_strength;
346 _is.setMaxIonicStrength(max_is0);
348
349 mole_additions = _input_mole_additions;
350 dmole_additions = _input_dmole_additions;
351 egs.addKineticRates(dt, mole_additions, dmole_additions);
352
353 _abs_residual = computeResidual(egs, _residual, mole_additions);
354 bool reducing_initial_molalities = (_abs_residual > _max_initial_residual);
355 const unsigned max_tries =
356 _num_basis *
357 unsigned(
359 std::log(1.1)); // assume each successful call to reduceInitialResidual reduces residual
360 // by about 1.1, but that the correct basis species has to be chosen
361 unsigned tries = 0;
362 while (reducing_initial_molalities && ++tries <= max_tries)
363 reducing_initial_molalities = reduceInitialResidual(egs, dt, mole_additions, dmole_additions);
364
365 ss << "iter = " << iter << " |R| = " << _abs_residual << std::endl;
367 while ((_abs_residual >= _res0_times_rel && _abs_residual >= _abs_tol && iter < _max_iter) ||
369 {
370 iter += 1;
371 tot_iter += 1;
372 egs.computeJacobian(_residual, _jacobian, mole_additions, dmole_additions);
374 const Real max_is =
375 std::min(1.0, (iter + 1.0) / (_ramp_max_ionic_strength + 1.0)) * _max_ionic_strength;
376 _is.setMaxIonicStrength(max_is);
380 ss << "Changed change balance species to "
381 << mgd.basis_species_name.at(egs.getChargeBalanceBasisIndex()) << std::endl;
383 {
384 mole_additions = _input_mole_additions;
385 dmole_additions = _input_dmole_additions;
386 egs.addKineticRates(dt, mole_additions, dmole_additions);
387 }
388 _abs_residual = computeResidual(egs, _residual, mole_additions);
389 ss << "iter = " << iter << " |R| = " << _abs_residual << std::endl;
390 }
391
392 abs_residual = _abs_residual; // record the final residual
393
394 if (iter >= _max_iter)
395 ss << std::endl << "Warning: Number of iterations exceeds " << _max_iter << std::endl;
396
397 unsigned swap_out_of_basis = 0;
398 unsigned swap_into_basis = 0;
399 try
400 {
401 // to ensure basis molality is correct:
402 for (unsigned i = 0; i < _num_basis; ++i)
403 egs.addToBulkMoles(i, mole_additions(i));
404 // now check for small basis molalities, minerals consumed and minerals precipitated
405 still_swapping = swapNeeded(egs, swap_out_of_basis, swap_into_basis, ss);
406 }
407 catch (const MooseException & e)
408 {
409 mooseException(e.what());
410 }
411 if (still_swapping)
412 {
413 // need to do a swap and re-solve
414 try
415 {
416 // before swapping, remove any basis mole_additions that came from kinetics. The
417 // following loop over i, combined with the above egs.addToBulkMoles(mole_additions), where
418 // mole_additions = _input_mole_additions + kinetic_additions, means that the bulk
419 // moles in egs will have only been incremented by _input_mole_additions. Hence,
420 // _input_mole_additions can be set to zero in preparation for the next solve in the new
421 // basis.
422 // NOTE: if _input_mole_additions depend on molalities, this approach introduces error,
423 // because the following call to addToBulkMoles and subsequent _input_mole_additions = 0
424 // means the mole additions are FIXED
425 for (unsigned i = 0; i < _num_basis; ++i)
426 {
427 egs.addToBulkMoles(i, _input_mole_additions(i) - mole_additions(i));
428 _input_mole_additions(i) = 0.0;
429 for (unsigned j = 0; j < _num_basis + _num_kin; ++j)
430 _input_dmole_additions(i, j) = 0.0;
431 }
432 egs.performSwap(swap_out_of_basis, swap_into_basis);
433 num_swaps += 1;
434 }
435 catch (const MooseException & e)
436 {
437 mooseException(e.what());
438 }
439 }
440 }
441
442 if (num_swaps > _max_swaps_allowed)
443 {
444 mooseException("Maximum number of swaps performed during solve");
445 }
447 {
448 mooseException("Failed to converge");
449 }
450 else
451 {
452 // the basis species additions have been added above with addtoBulkMoles: now add the kinetic
453 // additions:
454 for (unsigned i = 0; i < _num_basis; ++i)
455 mole_additions(i) = 0.0;
456 egs.updateOldWithCurrent(mole_additions);
458 }
459}
const ModelGeochemicalDatabase mgd
bool swapNeeded(const GeochemicalSystem &egs, unsigned &swap_out_of_basis, unsigned &swap_into_basis, std::stringstream &ss) const
Check if a basis swap is needed.
bool reduceInitialResidual(GeochemicalSystem &egs, Real dt, DenseVector< Real > &mole_additions, DenseMatrix< Real > &dmole_additions)
Progressively alter the initial-guess molalities for the algebraic system to attempt to reduce the re...
void solveAndUnderrelax(const GeochemicalSystem &egs, DenseMatrix< Real > &jacobian, DenseVector< Real > &new_mol) const
Solves _jacobian * neg_change_mol = _residual for neg_change_mol, then performs an underrelaxation to...
void enforceChargeBalance()
Enforces charge balance by altering the constraint_value and bulk_moles_old of the charge-balance spe...
unsigned getNumBasisInAlgebraicSystem() const
return the number of basis species in the algebraic system
void updateOldWithCurrent(const DenseVector< Real > &mole_additions)
Usually used at the end of a solve, to provide correct initial conditions to the next time-step,...
void performSwap(unsigned swap_out_of_basis, unsigned swap_into_basis)
Perform the basis swap, and ensure that the resulting system is consistent.
unsigned getChargeBalanceBasisIndex() const
return the index of the charge-balance species in the basis list
void addToBulkMoles(unsigned basis_ind, Real value)
Add to the MOLES_BULK_SPECIES (or MOLES_BULK_WATER if basis_ind = 0) for the basis species.
bool alterChargeBalanceSpecies(Real threshold_molality)
If the molality of the charge-balance basis species is less than threshold molality,...
const ModelGeochemicalDatabase & getModelGeochemicalDatabase() const
unsigned getNumInAlgebraicSystem() const
void computeJacobian(const DenseVector< Real > &res, DenseMatrix< Real > &jac, const DenseVector< Real > &mole_additions, const DenseMatrix< Real > &dmole_additions) const
Compute the Jacobian for the algebraic system and put it in jac.
void setMaxStoichiometricIonicStrength(Real max_stoichiometric_ionic_strength)
Set the maximum stoichiometric ionic strength.
void setMaxIonicStrength(Real max_ionic_strength)
Set the maximum ionic strength.
virtual const char * what() const
Data structure to hold all relevant information from the database file.
std::vector< std::string > basis_species_name
basis_species_name[j] = name of the j^th basis species

Referenced by GeochemistrySpatialReactor::execute(), GeochemistryTimeDependentReactor::execute(), GeochemistrySpatialReactor::initialSetup(), GeochemistryTimeDependentReactor::initialSetup(), GeochemistryTimeIndependentReactor::initialSetup(), GeochemistryTimeDependentReactor::postSolveExchanger(), TEST(), and TEST().

◆ swapNeeded()

bool GeochemicalSolver::swapNeeded ( const GeochemicalSystem egs,
unsigned &  swap_out_of_basis,
unsigned &  swap_into_basis,
std::stringstream &  ss 
) const
private

Check if a basis swap is needed.

It is needed if:

  • the Newton process did not converge and some non-minerals have small molality
  • the free number of moles of a basis mineral is negative
  • the saturation index of an equilibrium mineral is positive (and it is not in the prevent_precipitation list)
    Parameters
    egsGeochemical system that we're trying to solve
    swap_out_of_basisthe index of the species in the basis that will be removed from the basis
    swap_into_basisthe index of the equilibrium mineneral that will be added to the basis
    Returns
    true if a swap is needed, false otherwise

Definition at line 107 of file GeochemicalSolver.C.

111{
112 bool swap_needed = false;
113
115
116 // check if any basis minerals have negative free number of moles
117 const std::vector<Real> & basis_molality = egs.getSolventMassAndFreeMolalityAndMineralMoles();
118 const std::vector<unsigned> molality_order =
119 GeochemistrySortedIndices::sortedIndices(basis_molality, true);
120
121 // if the Newton did not converge then check for small molalities in the non-minerals
123 {
124 for (const auto & i : molality_order)
125 {
126 if (basis_molality[i] >= _swap_threshold)
127 {
128 // since we're going through basis_molality in ascending order, as soon as we get >=
129 // _swap_threshold, we're safe
130 break;
131 }
132 else if (!mgd.basis_species_mineral[i] && egs.getInAlgebraicSystem()[i] &&
134 {
135 // a non-mineral in the algebraic system has super low molality: try to find a legitimate
136 // swap
137 swap_out_of_basis = i;
138 bool legitimate_swap_found = egs.getSwapper().findBestEqmSwap(swap_out_of_basis,
139 mgd,
141 true,
142 false,
143 false,
144 swap_into_basis);
145 if (legitimate_swap_found)
146 {
147 ss << "Basis species " << mgd.basis_species_name[swap_out_of_basis]
148 << " has very low molality of " << basis_molality[i] << " compared to "
149 << _swap_threshold << ". Swapping it with equilibrium species "
150 << mgd.eqm_species_name[swap_into_basis] << std::endl;
151 swap_needed = true;
152 break;
153 }
154 // if no legitimate swap is found, then loop around to the next basis species
155 }
156 }
157 }
158 if (swap_needed)
159 return swap_needed;
160
161 // now look through the molalities for minerals that are consumed
162 for (const auto & i : molality_order)
163 {
164 if (basis_molality[i] > 0.0)
165 {
166 // since we're going through basis_molality in ascending order, as soon as we get >0, we're
167 // safe
168 break;
169 }
170 else if (mgd.basis_species_mineral[i])
171 {
172 swap_needed = true;
173 swap_out_of_basis = i;
174 bool legitimate_swap_found = egs.getSwapper().findBestEqmSwap(swap_out_of_basis,
175 mgd,
177 false,
178 false,
179 false,
180 swap_into_basis);
181 if (!legitimate_swap_found)
182 mooseException("Cannot find a legitimate swap for mineral ",
183 mgd.basis_species_name[swap_out_of_basis]);
184 ss << "Mineral " << mgd.basis_species_name[swap_out_of_basis]
185 << " consumed. Swapping it with equilibrium species "
186 << mgd.eqm_species_name[swap_into_basis] << std::endl;
187 break;
188 }
189 }
190 if (swap_needed)
191 return swap_needed;
192
193 // check maximum saturation index is not positive
194 const std::vector<Real> & eqm_SI = egs.getSaturationIndices();
195 const std::vector<unsigned> mineral_SI_order =
197
198 for (const auto & j : mineral_SI_order)
199 if (eqm_SI[j] > 0.0)
200 if (mgd.eqm_species_mineral[j])
203 mgd.eqm_species_name[j]) == _prevent_precipitation.end())
204 {
205 // mineral has positive saturation index and user is not preventing its precipitation.
206 // determine the basis species to swap out
207 swap_needed = true;
208 swap_into_basis = j;
209 bool legitimate_swap_found = false;
210 swap_out_of_basis = 0;
211 Real best_stoi = 0.0;
212 for (unsigned i = 1; i < _num_basis; ++i) // never swap water (i=0)
213 {
214 if (basis_molality[i] > 0.0 && i != egs.getChargeBalanceBasisIndex() &&
216 {
217 // don't want to swap out the charge-balance species or any gases of fixed fugacity
218 // or any species with fixed activity
219 const Real stoi = std::abs(mgd.eqm_stoichiometry(j, i)) / basis_molality[i];
220 if (stoi > best_stoi)
221 {
222 legitimate_swap_found = true;
223 best_stoi = stoi;
224 swap_out_of_basis = i;
225 }
226 }
227 }
228 if (!legitimate_swap_found)
229 mooseException(
230 "Cannot find a legitimate swap for the supersaturated equilibrium species ",
232 ss << "Mineral " << mgd.eqm_species_name[j]
233 << " supersaturated. Swapping it with basis species "
234 << mgd.basis_species_name[swap_out_of_basis] << std::endl;
235 break;
236 }
237 return swap_needed;
238}
std::vector< Real > getSaturationIndices() const
const GeochemistrySpeciesSwapper & getSwapper() const
const std::vector< bool > & getBasisActivityKnown() const
const std::vector< bool > & getInAlgebraicSystem() const
const std::vector< Real > & getSolventMassAndFreeMolalityAndMineralMoles() const
Real getEquilibriumMolality(unsigned j) const
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.
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
if(subdm)
DenseMatrix< Real > eqm_stoichiometry
eqm_stoichiometry(i, j) = stoichiometric coefficient for equilibrium species "i" in terms of the basi...
std::vector< bool > basis_species_mineral
basis_species_mineral[j] = true iff the j^th basis species is a mineral
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

Referenced by solveSystem().

Member Data Documentation

◆ _abs_residual

Real GeochemicalSolver::_abs_residual
private

L1 norm of residual.

Definition at line 118 of file GeochemicalSolver.h.

Referenced by reduceInitialResidual(), solveSystem(), and swapNeeded().

◆ _abs_tol

const Real GeochemicalSolver::_abs_tol
private

If the residual of the algebraic system falls below this value, the Newton process has converged.

Definition at line 124 of file GeochemicalSolver.h.

Referenced by solveSystem(), and swapNeeded().

◆ _evaluate_kin_always

bool GeochemicalSolver::_evaluate_kin_always
private

When to compute the kinetic rates: if true then evaluate before every residual calculation, otherwise evaluate only at the start of the solve process (using, eg, the old molality values)

Definition at line 147 of file GeochemicalSolver.h.

Referenced by reduceInitialResidual(), and solveSystem().

◆ _input_dmole_additions

DenseMatrix<Real> GeochemicalSolver::_input_dmole_additions
private

d(mole_additions)/d(species) as specified in the argument of solveSystem

Definition at line 151 of file GeochemicalSolver.h.

Referenced by reduceInitialResidual(), and solveSystem().

◆ _input_mole_additions

DenseVector<Real> GeochemicalSolver::_input_mole_additions
private

the mole_additions for the basis and kinetic species as specified in the argument of solveSystem

Definition at line 149 of file GeochemicalSolver.h.

Referenced by reduceInitialResidual(), and solveSystem().

◆ _is

GeochemistryIonicStrength& GeochemicalSolver::_is
private

The ionic-strength calculator.

Definition at line 106 of file GeochemicalSolver.h.

Referenced by solveSystem().

◆ _jacobian

DenseMatrix<Real> GeochemicalSolver::_jacobian
private

jacobian of the algebraic system

Definition at line 120 of file GeochemicalSolver.h.

Referenced by solveSystem().

◆ _max_initial_residual

Real GeochemicalSolver::_max_initial_residual
private

maximum desired initial residual

Definition at line 132 of file GeochemicalSolver.h.

Referenced by getMaxInitialResidual(), reduceInitialResidual(), setMaxInitialResidual(), and solveSystem().

◆ _max_ionic_strength

const Real GeochemicalSolver::_max_ionic_strength
private

Maximum ionic strength allowed.

Definition at line 140 of file GeochemicalSolver.h.

Referenced by solveSystem().

◆ _max_iter

const unsigned GeochemicalSolver::_max_iter
private

maximum number of iterations allowed during an inner solve

Definition at line 130 of file GeochemicalSolver.h.

Referenced by GeochemicalSolver(), setRampMaxIonicStrength(), and solveSystem().

◆ _max_swaps_allowed

const unsigned GeochemicalSolver::_max_swaps_allowed
private

Maximum number of swaps allowed before the solve aborts.

Definition at line 136 of file GeochemicalSolver.h.

Referenced by solveSystem().

◆ _new_mol

DenseVector<Real> GeochemicalSolver::_new_mol
private

the new molality after finding the solution of _jacobian * neg_change_mol = _residual

Definition at line 122 of file GeochemicalSolver.h.

Referenced by solveSystem().

◆ _num_basis

const unsigned GeochemicalSolver::_num_basis
private

Number of species in the basis.

Definition at line 108 of file GeochemicalSolver.h.

Referenced by solveSystem(), and swapNeeded().

◆ _num_basis_in_algebraic_system

unsigned GeochemicalSolver::_num_basis_in_algebraic_system
private

Number of basis molalities (and potentially solvent water mass) in the algebraic system.

Definition at line 112 of file GeochemicalSolver.h.

Referenced by reduceInitialResidual(), and solveSystem().

◆ _num_in_algebraic_system

unsigned GeochemicalSolver::_num_in_algebraic_system
private

Number of unknowns (molalities and surface potentials) in the algebraic system.

Definition at line 114 of file GeochemicalSolver.h.

Referenced by computeResidual(), solveAndUnderrelax(), and solveSystem().

◆ _num_kin

const unsigned GeochemicalSolver::_num_kin
private

Number of kinetic species.

Definition at line 110 of file GeochemicalSolver.h.

Referenced by solveSystem().

◆ _prevent_precipitation

const std::vector<std::string> GeochemicalSolver::_prevent_precipitation
private

The minerals named in this list can have positive saturation indices and will not precipitate.

Definition at line 138 of file GeochemicalSolver.h.

Referenced by swapNeeded().

◆ _ramp_max_ionic_strength

unsigned GeochemicalSolver::_ramp_max_ionic_strength
private

Number of iterations over which to increase the maximum ionic strength to _max_ionic_strength.

Definition at line 142 of file GeochemicalSolver.h.

Referenced by GeochemicalSolver(), getRampMaxIonicStrength(), setRampMaxIonicStrength(), and solveSystem().

◆ _rel_tol

const Real GeochemicalSolver::_rel_tol
private

If the residual of the algebraic system falls below this value times the initial residual, the Newton process has converged.

Definition at line 126 of file GeochemicalSolver.h.

Referenced by solveSystem().

◆ _res0_times_rel

Real GeochemicalSolver::_res0_times_rel
private

_res0_times_rel = _rel_tol * initial residual

Definition at line 128 of file GeochemicalSolver.h.

Referenced by solveSystem(), and swapNeeded().

◆ _residual

DenseVector<Real> GeochemicalSolver::_residual
private

residual of the algebraic system we wish to solve

Definition at line 116 of file GeochemicalSolver.h.

Referenced by reduceInitialResidual(), solveAndUnderrelax(), and solveSystem().

◆ _swap_threshold

const Real GeochemicalSolver::_swap_threshold
private

If a basis molality < swap_threshold, we attempt to swap it out of the basis.

Definition at line 134 of file GeochemicalSolver.h.

Referenced by solveSystem(), and swapNeeded().


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