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();
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,
251 const std::vector<unsigned> mol_order =
259 std::iota(res_order.begin(), res_order.end(), ind++);
260 std::sort(res_order.begin(),
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,
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 Real _max_ionic_strength
Maximum ionic strength allowed.
std::vector< Real > getAlgebraicBasisValues() const
const unsigned _num_kin
Number of kinetic species.
virtual const char * what() const
const Real _swap_threshold
If a basis molality < swap_threshold, we attempt to swap it out of the basis.
void mooseError(Args &&... args)
const unsigned _max_swaps_allowed
Maximum number of swaps allowed before the solve aborts.
const ModelGeochemicalDatabase mgd
void setMaxIonicStrength(Real max_ionic_strength)
Set the maximum ionic strength.
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
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...
DenseMatrix< Real > _jacobian
jacobian of the algebraic system
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.
void setMaxInitialResidual(Real max_initial_residual)
Set value for max_initial_residual.
unsigned getChargeBalanceBasisIndex() const
return the index of the charge-balance species in the basis list
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...
GeochemistryIonicStrength & _is
The ionic-strength calculator.
DenseVector< Real > _residual
residual of the algebraic system we wish to solve
DenseMatrix< Real > eqm_stoichiometry
eqm_stoichiometry(i, j) = stoichiometric coefficient for equilibrium species "i" in terms of the basi...
DenseMatrix< Real > _input_dmole_additions
d(mole_additions)/d(species) as specified in the argument of solveSystem
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...
unsigned _num_in_algebraic_system
Number of unknowns (molalities and surface potentials) in the algebraic system.
unsigned getNumInAlgebraicSystem() const
const Real _abs_tol
If the residual of the algebraic system falls below this value, the Newton process has converged...
Real getMaxInitialResidual() const
Get value for max_initial_residual.
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 ...
Calculators to compute ionic strength and stoichiometric ionic strength.
Real _abs_residual
L1 norm of residual.
const ModelGeochemicalDatabase & getModelGeochemicalDatabase() const
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, mole number, etc, and then, using dt, calculates the appropriate mole_additions and dmole_additions.
PetscErrorCode PetscInt const PetscInt IS * is
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...
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-...
unsigned _num_basis_in_algebraic_system
Number of basis molalities (and potentially solvent water mass) in the algebraic system.
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 enforceChargeBalance()
Enforces charge balance by altering the constraint_value and bulk_moles_old of the charge-balance spe...
unsigned getRampMaxIonicStrength() const
Gets the value of _ramp_max_ionic_strength.
bool alterChargeBalanceSpecies(Real threshold_molality)
If the molality of the charge-balance basis species is less than threshold molality, then attempt to change the charge-balance species, preferably to another component with opposite charge and big molality.
void lu_solve(const DenseVector< Real > &b, DenseVector< Real > &x)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
DenseVector< Real > _new_mol
the new molality after finding the solution of _jacobian * neg_change_mol = _residual ...
std::vector< Real > getAlgebraicVariableValues() const
Real computeResidual(const GeochemicalSystem &egs, DenseVector< Real > &residual, const DenseVector< Real > &mole_additions) const
Builds the residual of the algebraic system.
void setMaxStoichiometricIonicStrength(Real max_stoichiometric_ionic_strength)
Set the maximum stoichiometric ionic strength.
Real getEquilibriumMolality(unsigned j) const
void setRampMaxIonicStrength(unsigned ramp_max_ionic_strength)
Sets the value of _ramp_max_ionic_strength.
This class holds information about bulk composition, molalities, activities, activity coefficients...
Real getResidualComponent(unsigned algebraic_ind, const DenseVector< Real > &mole_additions) const
Return the residual of the algebraic system for the given algebraic index.
Real _max_initial_residual
maximum desired initial residual
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
const unsigned _max_iter
maximum number of iterations allowed during an inner solve
void setAlgebraicVariables(const DenseVector< Real > &algebraic_var)
Set the variables in the algebraic system (molalities and potentially the mass of solvent water...
Data structure to hold all relevant information from the database file.
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
const std::vector< Real > & getSolventMassAndFreeMolalityAndMineralMoles() 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.
const std::vector< bool > & getInAlgebraicSystem() const
const unsigned _num_basis
Number of species in the basis.
const GeochemistrySpeciesSwapper & getSwapper() 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...
const std::vector< bool > & getBasisActivityKnown() const
unsigned _ramp_max_ionic_strength
Number of iterations over which to increase the maximum ionic strength to _max_ionic_strength.
void performSwap(unsigned swap_out_of_basis, unsigned swap_into_basis)
Perform the basis swap, and ensure that the resulting system is consistent.
unsigned getNumBasisInAlgebraicSystem() const
return the number of basis species in the algebraic system
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)
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
std::vector< Real > getSaturationIndices() const
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.