https://mooseframework.inl.gov
GeochemicalSolver.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "GeochemicalSolver.h"
12 
14  unsigned num_kin,
16  Real abs_tol,
17  Real rel_tol,
18  unsigned max_iter,
19  Real max_initial_residual,
20  Real swap_threshold,
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)
26  : _is(is),
27  _num_basis(num_basis),
28  _num_kin(num_kin),
29  _num_basis_in_algebraic_system(_num_basis),
30  _num_in_algebraic_system(_num_basis + _num_kin),
31  _residual(_num_in_algebraic_system),
32  _abs_residual(0.0),
33  _jacobian(_num_in_algebraic_system, _num_in_algebraic_system),
34  _new_mol(_num_in_algebraic_system),
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),
46  _input_mole_additions(_num_basis + _num_kin),
47  _input_dmole_additions(_num_basis + _num_kin, _num_basis + _num_kin)
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 }
62 
63 void
64 GeochemicalSolver::setMaxInitialResidual(Real max_initial_residual)
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 }
70 
71 Real
73 {
74  return _max_initial_residual;
75 }
76 
77 Real
79  DenseVector<Real> & residual,
80  const DenseVector<Real> & mole_additions) const
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 }
86 
87 void
89  DenseMatrix<Real> & jacobian,
90  DenseVector<Real> & new_mol) const
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 }
105 
106 bool
108  unsigned & swap_out_of_basis,
109  unsigned & swap_into_basis,
110  std::stringstream & ss) const
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] &&
133  egs.getChargeBalanceBasisIndex() != 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)
201  if (std::find(_prevent_precipitation.begin(),
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 }
239 
240 bool
242  Real dt,
243  DenseVector<Real> & mole_additions,
244  DenseMatrix<Real> & dmole_additions)
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 }
314 
315 void
317  std::stringstream & ss,
318  unsigned & tot_iter,
319  Real & abs_residual,
320  Real dt,
321  DenseVector<Real> & mole_additions,
322  DenseMatrix<Real> & dmole_additions)
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);
457  egs.enforceChargeBalance();
458  }
459 }
460 
461 void
462 GeochemicalSolver::setRampMaxIonicStrength(unsigned ramp_max_ionic_strength)
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 }
468 
469 unsigned
471 {
473 }
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.