19 Real max_initial_residual,
21 unsigned max_swaps_allowed,
22 const std::vector<std::string> & prevent_precipitation,
23 Real max_ionic_strength,
24 unsigned ramp_max_ionic_strength,
25 bool evaluate_kin_always)
27 _num_basis(num_basis),
29 _num_basis_in_algebraic_system(_num_basis),
30 _num_in_algebraic_system(_num_basis + _num_kin),
31 _residual(_num_in_algebraic_system),
33 _jacobian(_num_in_algebraic_system, _num_in_algebraic_system),
34 _new_mol(_num_in_algebraic_system),
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),
46 _input_mole_additions(_num_basis + _num_kin),
47 _input_dmole_additions(_num_basis + _num_kin, _num_basis + _num_kin)
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");
56 mooseError(
"GeochemicalSolver: abs_tol must not be negative");
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");
66 if (max_initial_residual <= 0.0)
67 mooseError(
"GeochemicalSolver: max_initial_residual must be positive");
79 DenseVector<Real> & residual,
80 const DenseVector<Real> & mole_additions)
const
84 return residual.l1_norm();
89 DenseMatrix<Real> & jacobian,
90 DenseVector<Real> & new_mol)
const
97 Real one_over_delta = 1.0;
101 std::max(one_over_delta, new_mol(a_ind) * 2.0 / current_molality_and_pot[a_ind]);
103 new_mol(a_ind) = current_molality_and_pot[a_ind] - new_mol(a_ind) / one_over_delta;
108 unsigned & swap_out_of_basis,
109 unsigned & swap_into_basis,
110 std::stringstream & ss)
const
112 bool swap_needed =
false;
118 const std::vector<unsigned> molality_order =
124 for (
const auto & i : molality_order)
137 swap_out_of_basis = i;
145 if (legitimate_swap_found)
148 <<
" has very low molality of " << basis_molality[i] <<
" compared to "
162 for (
const auto & i : molality_order)
164 if (basis_molality[i] > 0.0)
173 swap_out_of_basis = i;
181 if (!legitimate_swap_found)
182 mooseException(
"Cannot find a legitimate swap for mineral ",
185 <<
" consumed. Swapping it with equilibrium species "
195 const std::vector<unsigned> mineral_SI_order =
198 for (
const auto & j : mineral_SI_order)
209 bool legitimate_swap_found =
false;
210 swap_out_of_basis = 0;
211 Real best_stoi = 0.0;
220 if (stoi > best_stoi)
222 legitimate_swap_found =
true;
224 swap_out_of_basis = i;
228 if (!legitimate_swap_found)
230 "Cannot find a legitimate swap for the supersaturated equilibrium species ",
233 <<
" supersaturated. Swapping it with basis species "
243 DenseVector<Real> & mole_additions,
244 DenseMatrix<Real> & dmole_additions)
251 const std::vector<unsigned> mol_order =
259 std::iota(res_order.begin(), res_order.end(), ind++);
260 std::sort(res_order.begin(),
262 [&](
int i,
int j) { return std::abs(_residual(i)) > std::abs(_residual(j)); });
265 DenseVector<Real> new_molality_and_pot(original_molality_and_pot);
266 for (
const auto &
a : res_order)
273 const Real multiplier = (original_molality_and_pot[
a] > median_molality) ? 0.5 : 2.0;
275 new_molality_and_pot(
a) = multiplier * original_molality_and_pot[
a];
288 new_molality_and_pot(
a) = original_molality_and_pot[
a] / multiplier;
302 new_molality_and_pot(
a) = original_molality_and_pot[
a];
317 std::stringstream & ss,
321 DenseVector<Real> & mole_additions,
322 DenseMatrix<Real> & dmole_additions)
326 unsigned num_swaps = 0;
334 bool still_swapping =
true;
355 const unsigned max_tries =
362 while (reducing_initial_molalities && ++tries <= max_tries)
365 ss <<
"iter = " << iter <<
" |R| = " <<
_abs_residual << std::endl;
380 ss <<
"Changed change balance species to "
389 ss <<
"iter = " << iter <<
" |R| = " <<
_abs_residual << std::endl;
395 ss << std::endl <<
"Warning: Number of iterations exceeds " <<
_max_iter << std::endl;
397 unsigned swap_out_of_basis = 0;
398 unsigned swap_into_basis = 0;
405 still_swapping =
swapNeeded(egs, swap_out_of_basis, swap_into_basis, ss);
409 mooseException(e.
what());
432 egs.
performSwap(swap_out_of_basis, swap_into_basis);
437 mooseException(e.
what());
444 mooseException(
"Maximum number of swaps performed during solve");
448 mooseException(
"Failed to converge");
455 mole_additions(i) = 0.0;
465 mooseError(
"GeochemicalSolver: ramp_max_ionic_strength must be less than max_iter");
const ModelGeochemicalDatabase mgd
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
Real getMaxInitialResidual() const
Get value for max_initial_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.
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.
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.
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.
Real computeResidual(const GeochemicalSystem &egs, DenseVector< Real > &residual, const DenseVector< Real > &mole_additions) const
Builds the residual of the algebraic system.
const std::vector< std::string > _prevent_precipitation
The minerals named in this list can have positive saturation indices and will not precipitate.
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.
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
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 setMaxInitialResidual(Real max_initial_residual)
Set value for max_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.
This class holds information about bulk composition, molalities, activities, activity coefficients,...
std::vector< Real > getSaturationIndices() const
Real getResidualComponent(unsigned algebraic_ind, const DenseVector< Real > &mole_additions) const
Return the residual of the algebraic system for the given algebraic index.
std::vector< Real > getAlgebraicBasisValues() const
void enforceChargeBalance()
Enforces charge balance by altering the constraint_value and bulk_moles_old of the charge-balance spe...
void setAlgebraicVariables(const DenseVector< Real > &algebraic_var)
Set the variables in the algebraic system (molalities and potentially the mass of solvent water,...
unsigned getNumBasisInAlgebraicSystem() const
return the number of basis species in the algebraic system
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,...
const GeochemistrySpeciesSwapper & getSwapper() const
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.
const std::vector< bool > & getBasisActivityKnown() const
unsigned getChargeBalanceBasisIndex() const
return the index of the charge-balance species in the basis list
const std::vector< bool > & getInAlgebraicSystem() const
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
const std::vector< Real > & getSolventMassAndFreeMolalityAndMineralMoles() const
unsigned getNumInAlgebraicSystem() const
std::vector< Real > getAlgebraicVariableValues() 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.
Real getEquilibriumMolality(unsigned j) const
Calculators to compute ionic strength and stoichiometric ionic strength.
void setMaxStoichiometricIonicStrength(Real max_stoichiometric_ionic_strength)
Set the maximum stoichiometric ionic strength.
void setMaxIonicStrength(Real max_ionic_strength)
Set the maximum ionic strength.
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.
virtual const char * what() 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-...
Data structure to hold all relevant information from the database file.
std::vector< bool > eqm_species_mineral
eqm_species_mineral[i] = true iff the i^th equilibrium species is a mineral
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< std::string > basis_species_name
basis_species_name[j] = name of the j^th basis species
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