LCOV - code coverage report
Current view: top level - include/utils - PertinentGeochemicalSystem.h (source / functions) Hit Total Coverage
Test: idaholab/moose geochemistry: 602416 Lines: 52 58 89.7 %
Date: 2025-07-18 11:37:48 Functions: 3 4 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #pragma once
      11             : 
      12             : #include "GeochemicalDatabaseReader.h"
      13             : #include "GeochemistryKineticRateCalculator.h"
      14             : #include <unordered_map>
      15             : #include "DenseMatrix.h"
      16             : #include <libmesh/dense_vector.h>
      17             : 
      18             : /**
      19             :  * Data structure designed to hold information related to sorption via surface complexation.
      20             :  * Since this is uncommon in geochemistry models, and this information only needs to be retrieved
      21             :  * once per node at the start of the Newton process, it uses an std::map, which is slow
      22             :  * compared with a std::vector, but saves memory compared with storing a lot of "zeroes" for every
      23             :  * non-sorbing species in the model
      24             :  */
      25         351 : struct SurfaceComplexationInfo
      26             : {
      27         216 :   SurfaceComplexationInfo(){};
      28             : 
      29             :   bool operator==(const SurfaceComplexationInfo & rhs) const
      30             :   {
      31           1 :     return surface_area == rhs.surface_area && sorption_sites == rhs.sorption_sites;
      32             :   };
      33             : 
      34             :   Real surface_area;
      35             :   std::map<std::string, Real> sorption_sites;
      36             : };
      37             : 
      38             : /**
      39             :  * A single rate expression for the kinetic species with index kinetic_species_index.
      40             :  * @param kinetic_species_index index of the kinetic species that is governed by this rate
      41             :  * @param promoting_indices the kinetic rate is multiplied by the produce over all basis and
      42             :  * equilibrium species of m^promoting_indices / (m^promoting_indices +
      43             :  * promoting_half_saturation^promoting_indices)^promoting_monod_indices, where m is the molality or
      44             :  * activity of the species
      45             :  * @param promoting_monod_indices the kinetic rate is multiplied by the produce over all basis and
      46             :  * equilibrium species of m^promoting_indices / (m^promoting_indices +
      47             :  * promoting_half_saturation^promoting_indices)^promoting_monod_indices, where m is the molality or
      48             :  * activity of the species
      49             :  * @param promoting_half_saturation the kinetic rate is multiplied by the produce over all basis and
      50             :  * equilibrium species of m^promoting_indices / (m^promoting_indices +
      51             :  * promoting_half_saturation^promoting_indices)^promoting_monod_indices, where m is the molality or
      52             :  * activity of the species
      53             :  * @param progeny_index the index of the basis or equilibrium species in the current basis that is
      54             :  * produced by the kinetic reaction (usually this is 0, and description.progeny_efficiency = 0, so
      55             :  * there are no progeny effects)
      56             :  * @param description the KineticRateUserDescription of this rate
      57             :  */
      58             : struct KineticRateDefinition
      59             : {
      60         108 :   KineticRateDefinition(unsigned kinetic_species_index,
      61             :                         const std::vector<Real> & promoting_indices,
      62             :                         const std::vector<Real> & promoting_monod_indices,
      63             :                         const std::vector<Real> & promoting_half_saturation,
      64             :                         unsigned progeny_index,
      65             :                         const KineticRateUserDescription & description)
      66         108 :     : kinetic_species_index(kinetic_species_index),
      67         108 :       promoting_indices(promoting_indices),
      68         108 :       promoting_monod_indices(promoting_monod_indices),
      69         108 :       promoting_half_saturation(promoting_half_saturation),
      70         108 :       progeny_index(progeny_index),
      71         108 :       description(description){};
      72             : 
      73           0 :   bool operator==(const KineticRateDefinition & rhs) const
      74             :   {
      75           0 :     return (kinetic_species_index == rhs.kinetic_species_index) &&
      76           0 :            (promoting_indices == rhs.promoting_indices) &&
      77           0 :            (promoting_monod_indices == rhs.promoting_monod_indices) &&
      78           0 :            (promoting_half_saturation == rhs.promoting_half_saturation) &&
      79           0 :            (progeny_index == rhs.progeny_index) && (description == rhs.description);
      80             :   };
      81             : 
      82             :   unsigned kinetic_species_index;
      83             :   std::vector<Real> promoting_indices;
      84             :   std::vector<Real> promoting_monod_indices;
      85             :   std::vector<Real> promoting_half_saturation;
      86             :   unsigned progeny_index;
      87             :   KineticRateUserDescription description;
      88             : };
      89             : 
      90             : /**
      91             :  * Data structure to hold all relevant information from the database file.
      92             :  * Generally, the database file contains information on a lot more species than any numerical model
      93             :  * considers.  The ModelGeochemicalDatabase only holds the minimal information required for the
      94             :  * numerical model.  It also holds the information as std::vector and DenseMatrix data structures
      95             :  * for numerical efficiency.  This makes the ModelGeochemicalDatabase a little more obscure compared
      96             :  * with the database file, but considering this information is used hundreds, maybe millions, of
      97             :  * times per node during a single timestep, numerical efficiency is paramount.
      98             :  */
      99             : struct ModelGeochemicalDatabase
     100             : {
     101             :   /**
     102             :    * Constructor sets original_database.  Also initializes swap_to_original_basis to "nothing" in an
     103             :    * attempt to reduce memory consumption
     104             :    */
     105        1178 :   ModelGeochemicalDatabase(const GeochemicalDatabaseReader & db)
     106        1178 :     : original_database(&db), swap_to_original_basis(DenseMatrix<Real>()){};
     107             : 
     108           2 :   bool operator==(const ModelGeochemicalDatabase & rhs) const
     109             :   {
     110           2 :     return (original_database == rhs.original_database) &&
     111           2 :            (basis_species_index == rhs.basis_species_index) &&
     112           2 :            (basis_species_name == rhs.basis_species_name) &&
     113           2 :            (basis_species_mineral == rhs.basis_species_mineral) &&
     114           2 :            (basis_species_gas == rhs.basis_species_gas) &&
     115           2 :            (basis_species_transported == rhs.basis_species_transported) &&
     116           2 :            (basis_species_charge == rhs.basis_species_charge) &&
     117           2 :            (basis_species_radius == rhs.basis_species_radius) &&
     118           2 :            (basis_species_molecular_weight == rhs.basis_species_molecular_weight) &&
     119           2 :            (basis_species_molecular_volume == rhs.basis_species_molecular_volume) &&
     120           2 :            (eqm_species_index == rhs.eqm_species_index) &&
     121           2 :            (eqm_species_name == rhs.eqm_species_name) &&
     122           2 :            (eqm_species_mineral == rhs.eqm_species_mineral) &&
     123           2 :            (eqm_species_gas == rhs.eqm_species_gas) &&
     124           2 :            (eqm_species_transported == rhs.eqm_species_transported) &&
     125           2 :            (eqm_species_charge == rhs.eqm_species_charge) &&
     126           2 :            (eqm_species_radius == rhs.eqm_species_radius) &&
     127           2 :            (eqm_species_molecular_weight == rhs.eqm_species_molecular_weight) &&
     128           2 :            (eqm_species_molecular_volume == rhs.eqm_species_molecular_volume) &&
     129           2 :            (eqm_stoichiometry == rhs.eqm_stoichiometry) && (eqm_log10K == rhs.eqm_log10K) &&
     130           2 :            (surface_sorption_name == rhs.surface_sorption_name) &&
     131           2 :            (surface_sorption_area == rhs.surface_sorption_area) &&
     132           2 :            (surface_sorption_related == rhs.surface_sorption_related) &&
     133           2 :            (surface_sorption_number == rhs.surface_sorption_number) &&
     134           2 :            (redox_lhs == rhs.redox_lhs) && (redox_stoichiometry == rhs.redox_stoichiometry) &&
     135           2 :            (redox_log10K == rhs.redox_log10K) &&
     136           2 :            (surface_complexation_info == rhs.surface_complexation_info) &&
     137           2 :            (gas_chi == rhs.gas_chi) && (kin_species_index == rhs.kin_species_index) &&
     138           2 :            (kin_species_name == rhs.kin_species_name) &&
     139           2 :            (kin_species_mineral == rhs.kin_species_mineral) &&
     140           2 :            (kin_species_transported == rhs.kin_species_transported) &&
     141           2 :            (kin_species_charge == rhs.kin_species_charge) &&
     142           2 :            (kin_species_molecular_weight == rhs.kin_species_molecular_weight) &&
     143           2 :            (kin_species_molecular_volume == rhs.kin_species_molecular_volume) &&
     144           2 :            (kin_log10K == rhs.kin_log10K) && (kin_stoichiometry == rhs.kin_stoichiometry) &&
     145           2 :            (kin_rate == rhs.kin_rate) &&
     146           2 :            (have_swapped_out_of_basis == rhs.have_swapped_out_of_basis) &&
     147           4 :            (have_swapped_into_basis == rhs.have_swapped_into_basis) &&
     148           2 :            (swap_to_original_basis == rhs.swap_to_original_basis);
     149             :   };
     150             : 
     151             :   /// a pointer to the original database used to build this ModelGeochemicalDatabase
     152             :   const GeochemicalDatabaseReader * original_database;
     153             : 
     154             :   /**
     155             :    * basis_species_index[name] = index of the basis species, within all ModelGeochemicalDatabase
     156             :    * internal datastrcutres, with given name
     157             :    */
     158             :   std::unordered_map<std::string, unsigned> basis_species_index;
     159             : 
     160             :   /// basis_species_name[j] = name of the j^th basis species
     161             :   std::vector<std::string> basis_species_name;
     162             : 
     163             :   /// basis_species_mineral[j] = true iff the j^th basis species is a mineral
     164             :   std::vector<bool> basis_species_mineral;
     165             : 
     166             :   /// basis_species_gas[j] = true iff the j^th basis species is a gas
     167             :   std::vector<bool> basis_species_gas;
     168             : 
     169             :   /// basis_species_transported[j] = true iff the j^th basis species is transported in reactive-transport sims
     170             :   std::vector<bool> basis_species_transported;
     171             : 
     172             :   /// all quantities have a charge (mineral charge = 0, gas charge = 0, oxide charge = 0)
     173             :   std::vector<Real> basis_species_charge;
     174             : 
     175             :   /// all quantities have an ionic radius (Angstrom) for computing activity (mineral radius = 0, gas radius = 0, surface species radius = 0)
     176             :   std::vector<Real> basis_species_radius;
     177             : 
     178             :   /// all quantities have a molecular weight (g)
     179             :   std::vector<Real> basis_species_molecular_weight;
     180             : 
     181             :   /// all quantities have a molecular volume (cm^3) (only nonzero for minerals, however)
     182             :   std::vector<Real> basis_species_molecular_volume;
     183             : 
     184             :   /**
     185             :    * eqm_species_index[name] = index of the equilibrium species (secondary aqueous species, redox
     186             :    * couples in equilibrium with the aqueous solution, minerals in equilibrium with the aqueous
     187             :    * solution, gases in equilibrium with the aqueous solution) within all ModelGeochemicalDatabase
     188             :    * internal datastrcutres, with given name
     189             :    */
     190             :   std::unordered_map<std::string, unsigned> eqm_species_index;
     191             : 
     192             :   /// eqm_species_name[i] = name of the i^th eqm species
     193             :   std::vector<std::string> eqm_species_name;
     194             : 
     195             :   /// eqm_species_mineral[i] = true iff the i^th equilibrium species is a mineral
     196             :   std::vector<bool> eqm_species_mineral;
     197             : 
     198             :   /// eqm_species_gas[i] = true iff the i^th equilibrium species is a gas
     199             :   std::vector<bool> eqm_species_gas;
     200             : 
     201             :   /// eqm_species_transported[i] = true iff the i^th eqm species is transported in reactive-transport sims
     202             :   std::vector<bool> eqm_species_transported;
     203             : 
     204             :   /// all quantities have a charge (mineral charge = 0, gas charge = 0, oxide charge = 0)
     205             :   std::vector<Real> eqm_species_charge;
     206             : 
     207             :   /// all quantities have an ionic radius (Angstrom) for computing activity (mineral radius = 0, gas radius = 0, surface species radius = 0)
     208             :   std::vector<Real> eqm_species_radius;
     209             : 
     210             :   /// all quantities have a molecular weight (g)
     211             :   std::vector<Real> eqm_species_molecular_weight;
     212             : 
     213             :   /// all quantities have a molecular volume (cm^3) (only nonzero for minerals, however)
     214             :   std::vector<Real> eqm_species_molecular_volume;
     215             : 
     216             :   /**
     217             :    * eqm_stoichiometry(i, j) = stoichiometric coefficient for equilibrium species "i" in terms of
     218             :    * the basis species "j"
     219             :    */
     220             :   DenseMatrix<Real> eqm_stoichiometry;
     221             : 
     222             :   /**
     223             :    * eqm_log10K(i, j) = log10(equilibrium constant) for i^th equilibrium species at the j^th
     224             :    * temperature point
     225             :    */
     226             :   DenseMatrix<Real> eqm_log10K;
     227             : 
     228             :   /**
     229             :    * surface_sorption_name[k] = name of the mineral involved in surface sorption.  Each of these
     230             :    * will be associated with a unique surface potential.
     231             :    */
     232             :   std::vector<std::string> surface_sorption_name;
     233             : 
     234             :   /**
     235             :    * surface_sorption_area[k] = specific surface area [m^2/g] for the k^th mineral involved in
     236             :    * surface sorption.  Each mineral involved in surface sorption must have a surface_sorption_area
     237             :    * prescribed it (in the database) and will be associated with a unique surface potential.
     238             :    */
     239             :   std::vector<Real> surface_sorption_area;
     240             : 
     241             :   /// surface_sorption_related[j] = true iff the j^th equilibrium species is involved in surface sorption
     242             :   std::vector<bool> surface_sorption_related;
     243             : 
     244             :   /**
     245             :    * surface_sorption_number[j] = the index of the surface potential that should be used to modify
     246             :    * the equilibrium constant for the j^th equilibrium species.  surface_sorption_number is only
     247             :    * meaningful if surface_sorption_related[j] = true.  0 <= surface_sorption_number[:] <
     248             :    * surface_sorption_name.size() = number of minerals involved in surface sorption = number of
     249             :    * surface potentials in the simulation = surface_sorption_area.size().
     250             :    */
     251             :   std::vector<unsigned> surface_sorption_number;
     252             : 
     253             :   /**
     254             :    * the name of the species on the left-hand side of the redox equations.  Upon creation of the
     255             :    * model this is e-, but it may change due to swaps
     256             :    */
     257             :   std::string redox_lhs;
     258             : 
     259             :   /**
     260             :    * redox_stoichiometry(i, j) = stoichiometric coefficients for i^th redox species that is in
     261             :    * disequilibrium in terms of the j basis species.  These equations are all written with their
     262             :    * left-hand sides being e-.
     263             :    * For instance, the database contains the reactions
     264             :    * Fe+++ = -0.5H20 + Fe++ + H+ + 0.25*O2(aq)
     265             :    * e- = 0.5H2O - 0.25O2(aq)- H+
     266             :    * The first is a redox reaction, and assume the user has specified it is in disquilibrium (by
     267             :    * specifying it is in the basis).  If Fe++, H+ and O2(aq) are also in the basis then the two
     268             :    * equations yield the single redox equation
     269             :    * e- = -Fe+++ + Fe++
     270             :    * Then redox_stoichiometry will be -1 for j = Fe+++, and +1 for j = Fe++.
     271             :    */
     272             :   DenseMatrix<Real> redox_stoichiometry;
     273             : 
     274             :   /**
     275             :    * redox_log10K(i, j) = log10(equilibrium constant) for i^th redox species at the j^th temperature
     276             :    * point
     277             :    */
     278             :   DenseMatrix<Real> redox_log10K;
     279             : 
     280             :   /**
     281             :    * Holds info on surface complexation, if any, in the model.  Note this is slow compared with
     282             :    * storing information in a std::vector or DenseMatrix, but it also saves memory over storing a
     283             :    * lot of "zeroes" for all species not involved in surface complexation
     284             :    */
     285             :   std::unordered_map<std::string, SurfaceComplexationInfo> surface_complexation_info;
     286             : 
     287             :   /**
     288             :    * Holds info on gas fugacity "chi" parameters.  Note this is slow compared with storing info in a
     289             :    * DenseMatrix, but it also saves memory over storing a lot of "zeroes" for non-gas species.  I
     290             :    * believe the slowness will not present a problem because fugacity parameters are typically only
     291             :    * queried at the start of the simulation, or at most once per timestep.  If the lookup becomes
     292             :    * burdensome, change from unordered_map to DenseMatrix
     293             :    */
     294             :   std::unordered_map<std::string, std::vector<Real>> gas_chi;
     295             : 
     296             :   /**
     297             :    * kin_species_index[name] = index of the kinetic species, within all ModelGeochemicalDatabase
     298             :    * internal datastrcutres, with given name
     299             :    */
     300             :   std::unordered_map<std::string, unsigned> kin_species_index;
     301             : 
     302             :   /// kin_species_name[j] = name of the j^th kinetic species
     303             :   std::vector<std::string> kin_species_name;
     304             : 
     305             :   /// kin_species_mineral[j] = true iff the j^th kinetic species is a mineral
     306             :   std::vector<bool> kin_species_mineral;
     307             : 
     308             :   /// kin_species_transported[j] = true iff the j^th kinetic species is transported in reactive-transport sims
     309             :   std::vector<bool> kin_species_transported;
     310             : 
     311             :   /// all kinetic quantities have a charge (mineral charge = 0)
     312             :   std::vector<Real> kin_species_charge;
     313             : 
     314             :   /// all quantities have a molecular weight (g/mol)
     315             :   std::vector<Real> kin_species_molecular_weight;
     316             : 
     317             :   /// all quantities have a molecular volume (cm^3/mol) (only nonzero for minerals, however)
     318             :   std::vector<Real> kin_species_molecular_volume;
     319             : 
     320             :   /**
     321             :    * kin_log10K(i, j) = log10(equilibrium constant for the i^th kinetic species at the j^th
     322             :    * temperature point
     323             :    */
     324             :   DenseMatrix<Real> kin_log10K;
     325             : 
     326             :   /**
     327             :    * kin_stoichiometry(i, j) = stoichiometric coefficient for kinetic species "i" in terms of
     328             :    * the basis species "j"
     329             :    */
     330             :   DenseMatrix<Real> kin_stoichiometry;
     331             : 
     332             :   /**
     333             :    * rates given to kinetic species.  See the method addKineticRate for a detailed description. This
     334             :    * quantity is organised in such a way that a solver can loop through kin_rate, calculting the
     335             :    * rates and applying them to the kin_rate[i].kinetic_species_index species
     336             :    */
     337             :   std::vector<KineticRateDefinition> kin_rate;
     338             : 
     339             :   /**
     340             :    * Species that have been swapped out of the basis.  Every time a swap is performed on the
     341             :    * ModelGeochemicalDatabase, the basis-index of the species removed from the basis is appended to
     342             :    * this list
     343             :    */
     344             :   std::vector<unsigned> have_swapped_out_of_basis;
     345             : 
     346             :   /**
     347             :    * Species that have been swapped into the basis.  Every time a swap is performed on the
     348             :    * ModelGeochemicalDatabase, the equilibrium-index of the species added to the basis is appended
     349             :    * to this list
     350             :    */
     351             :   std::vector<unsigned> have_swapped_into_basis;
     352             : 
     353             :   /**
     354             :    * Swap matrix that allows expression in terms of the original basis.  When a swap is performed
     355             :    * bulk_new = S^-1^T * bulk_old,
     356             :    * where S is the swap matrix (and S^-1^T is the transposed inverse of S)
     357             :    * Hence, upon multiple swaps (S_1 followed by S_2 followed by S_3, etc)
     358             :    * bulk_new = S_n^-1^T * S_{n-1}^-1^T * ... * S_1^-1^T * bulk_original
     359             :    * So
     360             :    * bulk_original = (S_n * S_{n-1} * ... * S_1)^T * bulk_new
     361             :    * swap_to_original_basis = S_n * S_{n-1} * ... * S_1
     362             :    * swap_to_original_basis is initialized to  DenseMatrix<Real>(), ie, a zero-sized matrix, to
     363             :    * reduce memory usage.  The first time a swap is performed, it is set to the swap matrix
     364             :    * generated in the GeochemistrySpeciesSwapper, and every time a swap is performed on the
     365             :    * ModelGeochemicalDatabase this is updated
     366             :    */
     367             :   DenseMatrix<Real> swap_to_original_basis;
     368             : };
     369             : 
     370             : /**
     371             :  * Constructs and stores a minimal amount of information that is pertinent to the user-defined
     372             :  * geochemical system.  Most importantly, all basis species, secondary species, mineral species,
     373             :  * etc, that are defined in the geochemical database but are irrelevant to the user-defined system
     374             :  * are eliminated from further consideration.  This reduces the amount of information considerably.
     375             :  * The final result is stored in a ModelGeochemicalDatabase structure.  This structure is designed
     376             :  * to be computationally efficient.  A "getter" that copies this structure is provided as a public
     377             :  * method.  It is intended that a MOOSE simulation will construct one PertinentGeochemicalSystem
     378             :  * object, and then copy the information to the nodes during the initial setup.  If different nodes
     379             :  * are allowed different swaps (likely to be the case) each node will need a different copy of the
     380             :  * ModelGeochemicalDatabase structure.
     381             :  */
     382             : class PertinentGeochemicalSystem
     383             : {
     384             : public:
     385             :   /**
     386             :    * @param db the database reader, which will have parsed the database file
     387             :    *
     388             :    * @param basis_species A list of basis components relevant to the aqueous-equilibrium problem.
     389             :    * "H2O" must appear first in this list.  No element must appear more than once in this list.
     390             :    * These components must be chosen from the "basis species" in the database, the sorbing sites (if
     391             :    * any) and the decoupled redox states that are in disequilibrium (if any).  Any redox pair that
     392             :    * is not in this list or the kinetic_redox list, will be assumed to be at equilibrium with the
     393             :    * aqueous solution and will be considered a secondary species.  All these species, except H2O,
     394             :    * may be later swapped out of this list, either by a manual user-prescribed swap (and replaced by
     395             :    * a mineral or a gas of fixed fugacity, for instance), or during the numerical solve.
     396             :    *
     397             :    * @param minerals A list of minerals that are in equilibrium with the aqueous solution.  This can
     398             :    * only include the "minerals" in the database file.  No element can appear more than once in this
     399             :    * list.  Their equilibrium reaction must consist of only the basis_species, and
     400             :    * secondary species and non-kinetically-controlled redox couples that can be expressed in terms
     401             :    * of the basis_species.  If they are also "sorbing minerals" in the database then their sorption
     402             :    * sites must consist of the basis_species only.  During simulation, the user can compute the
     403             :    * saturation index of these minerals, and these minerals can be "swapped" into the basis if
     404             :    * desired (or required during the numerical solve).  If the user performs a manual "swap" then an
     405             :    * initial condition must be provided for the mineral.  The user choose whether these minerals are
     406             :    * allowed to precipitate or not - that is, they can be "supressed".  This list, along with the
     407             :    * kinetic_minerals list, comprises the entire list of minerals in the problem: all others are
     408             :    * eliminated from consideration.
     409             :    *
     410             :    * @param gases A list of gases that are in equilibrium with the aqueous solution and can have
     411             :    * their fugacities fixed, at least at some time and spatial location.  All members of this list
     412             :    * must be a "gas" in the database file.  No gas must appear more than once in this list.  The
     413             :    * equilibrium reaction of each gas must involve only the basis_species, or secondary species or
     414             :    * non-kinetically-controlled redox couples that can be expressed in terms of the basis_species.
     415             :    *
     416             :    * @param kinetic_minerals A list of minerals that whose dynamics are governed by a rate law.
     417             :    * These are not in equilibrium with the aqueous solution.  This can only include the "minerals"
     418             :    * in the database file.  No element can appear more than once in this list.  Their equilibrium
     419             :    * reaction must involve only the basis_species, or secondary species or
     420             :    * non-kinetically-controlled redox couples that can be expressed in terms of the basis_species.
     421             :    * If they are also "sorbing minerals" in the database then their sorption sites must consist of
     422             :    * the basis_speices only.  No members of this list must be in the minerals list. They can never
     423             :    * be "swapped" into the basis, nor can they be "supressed".
     424             :    *
     425             :    * @param kinetic_redox A list of redox pairs whose dynamics are governed by a rate law.
     426             :    * These are not in equilibrium with the aqueous solution.  Each element of this list must appear
     427             :    * in the "redox couples" section of the database.  No element can appear more than once in this
     428             :    * list.  Their reaction must involve only the basis_species, or secondary species or
     429             :    * non-kinetically-controlled redox couples that can be expressed in terms of the basis_species.
     430             :    * No members of this list must be in the basis_species list.  They can never be "swapped" into
     431             :    * the basis.
     432             :    *
     433             :    * @param kinetic_surface_species A list of surface sorbing species whose dynamics are governed by
     434             :    * a rate law.  These are not in equilibrium with the aqueous solution.  All elements of this list
     435             :    * must appear as a "surface species" in the database.  No member must appear more than twice in
     436             :    * this list. Their reaction must involve only the basis_species, or secondary species or
     437             :    * non-kinetically-controlled redox couples that can be expressed in terms of the basis_species.
     438             :    * They can never be "swapped" into the basis.
     439             :    *
     440             :    * @param redox_ox The name of the oxygen species, eg O2(aq), that appears in redox reactions. For
     441             :    * redox pairs that are in disequilibrium to be correctly recorded, and hence their Nernst
     442             :    * potentials to be computed easily, redox_ox must be a basis_species and it must appear in the
     443             :    * reaction for each redox pair.
     444             :    *
     445             :    * @param redox_e The name of the free electron, eg e-.  For redox pairs that are in
     446             :    * disequilibrium to be correctly recorded, and hence their Nernst potentials to be computed
     447             :    * easily, the equilibrium reaction for redox_e must involve redox_ox, and the basis species must
     448             :    * be chosen so that redox_e is an equilibrium species according to the database reader
     449             :    */
     450             :   PertinentGeochemicalSystem(const GeochemicalDatabaseReader & db,
     451             :                              const std::vector<std::string> & basis_species,
     452             :                              const std::vector<std::string> & minerals,
     453             :                              const std::vector<std::string> & gases,
     454             :                              const std::vector<std::string> & kinetic_minerals,
     455             :                              const std::vector<std::string> & kinetic_redox,
     456             :                              const std::vector<std::string> & kinetic_surface_species,
     457             :                              const std::string & redox_ox,
     458             :                              const std::string & redox_e);
     459             : 
     460             :   /// Return a reference to the ModelGeochemicalDatabase structure
     461             :   const ModelGeochemicalDatabase & modelGeochemicalDatabase() const;
     462             : 
     463             :   /**
     464             :    * Adds a rate description for kinetic_species.  Note that a single kinetic species can have
     465             :    * multiple rates prescribed to it (by calling this method multiple times): they are added
     466             :    * together to give an overall rate.
     467             :    */
     468             :   void addKineticRate(const KineticRateUserDescription & description);
     469             : 
     470             :   /**
     471             :    * @param name species name
     472             :    * @return the index of the species in the original basis
     473             :    */
     474             :   unsigned getIndexOfOriginalBasisSpecies(const std::string & name) const;
     475             : 
     476             :   /**
     477             :    * @return a vector of names of the original basis species
     478             :    */
     479             :   std::vector<std::string> originalBasisNames() const;
     480             : 
     481             : private:
     482             :   /// The database
     483             :   GeochemicalDatabaseReader _db;
     484             : 
     485             :   /// given a species name, return its index in the corresponding "info" std::vector
     486             :   std::unordered_map<std::string, unsigned> _basis_index;
     487             : 
     488             :   /// a vector of all relevant species
     489             :   std::vector<GeochemistryBasisSpecies> _basis_info;
     490             : 
     491             :   /// given a species name, return its index in the corresponding "info" std::vector
     492             :   std::unordered_map<std::string, unsigned> _mineral_index;
     493             : 
     494             :   /// a vector of all relevant species
     495             :   std::vector<GeochemistryMineralSpecies> _mineral_info;
     496             : 
     497             :   /// given a species name, return its index in the corresponding "info" std::vector
     498             :   std::unordered_map<std::string, unsigned> _gas_index;
     499             : 
     500             :   /// a vector of all relevant species
     501             :   std::vector<GeochemistryGasSpecies> _gas_info;
     502             : 
     503             :   /// given a species name, return its index in the corresponding "info" std::vector
     504             :   std::unordered_map<std::string, unsigned> _kinetic_mineral_index;
     505             : 
     506             :   /// a vector of all relevant species
     507             :   std::vector<GeochemistryMineralSpecies> _kinetic_mineral_info;
     508             : 
     509             :   /// given a species name, return its index in the corresponding "info" std::vector
     510             :   std::unordered_map<std::string, unsigned> _kinetic_redox_index;
     511             : 
     512             :   /// a vector of all relevant species
     513             :   std::vector<GeochemistryRedoxSpecies> _kinetic_redox_info;
     514             : 
     515             :   /// given a species name, return its index in the corresponding "info" std::vector
     516             :   std::unordered_map<std::string, unsigned> _kinetic_surface_index;
     517             : 
     518             :   /// a vector of all relevant species
     519             :   std::vector<GeochemistrySurfaceSpecies> _kinetic_surface_info;
     520             : 
     521             :   /// given a species name, return its index in the corresponding "info" std::vector
     522             :   std::unordered_map<std::string, unsigned> _secondary_index;
     523             : 
     524             :   /// a vector of all relevant species
     525             :   std::vector<GeochemistryEquilibriumSpecies> _secondary_info;
     526             : 
     527             :   /**
     528             :    * The name of the oxygen in all disequilibrium-redox equations, eg O2(aq), which must be a basis
     529             :    * species if disequilibrium redox reactions are to be recorded
     530             :    */
     531             :   const std::string _redox_ox;
     532             : 
     533             :   /// The name of the free electron involved in redox reactions
     534             :   const std::string _redox_e;
     535             : 
     536             :   /// The important datastructure built by this class
     537             :   ModelGeochemicalDatabase _model;
     538             : 
     539             :   /**
     540             :    * using the basis_species list, this method builds _basis_index and _basis_info
     541             :    */
     542             :   void buildBasis(const std::vector<std::string> & basis_species);
     543             : 
     544             :   /**
     545             :    * using the minerals list, this method builds _mineral_index and _mineral_info, unless minerals =
     546             :    * {"*"}, in which case buildAllMinerals is used instead
     547             :    */
     548             :   void buildMinerals(const std::vector<std::string> & minerals);
     549             : 
     550             :   /**
     551             :    * If minerals = {"*"} then populate _mineral_index and _mineral_info with all relevant minerals
     552             :    * This is called in the constructor after buildSecondarySpecies and buildKineticMinerals because
     553             :    * it adds to _mineral_index and _mineral_info all minerals that:
     554             :    * - are not kinetic minerals (these have been identified by buildKineticMinerals) and
     555             :    * - whose stoichiometry depends on the basis species specified in the constructor or on secondary
     556             :    * species (which are redox couples, secondary species and surface species) that depend on these
     557             :    * basis species.  These secondary species have already been identified by buildSecondarySpecies.
     558             :    */
     559             :   void buildAllMinerals(const std::vector<std::string> & minerals);
     560             : 
     561             :   /**
     562             :    * using the gas list, this method builds _gas_index and _gas_info
     563             :    */
     564             :   void buildGases(const std::vector<std::string> & gases);
     565             : 
     566             :   /**
     567             :    * using the kinetic_minerals list, this method builds _kinetic_mineral_index and
     568             :    * _kinetic_mineral_info
     569             :    */
     570             :   void buildKineticMinerals(const std::vector<std::string> & kinetic_minerals);
     571             : 
     572             :   /**
     573             :    * using the kinetic_redox list, this method builds _kinetic_redox_index and
     574             :    * _kinetic_redox_info
     575             :    */
     576             :   void buildKineticRedox(const std::vector<std::string> & kinetic_redox);
     577             : 
     578             :   /**
     579             :    * using the kinetic_surface list, this method builds _kinetic_surface_index and
     580             :    * _kinetic_surface_info
     581             :    */
     582             :   void buildKineticSurface(const std::vector<std::string> & kinetic_surface);
     583             : 
     584             :   /**
     585             :    * Extract all relevant "redox couples" and "secondary species" and "surface species" from the
     586             :    * database. These are all species whose reaction involves only the basis_species and are not
     587             :    * kinetically controlled or already in the basis_species list.
     588             :    */
     589             :   void buildSecondarySpecies();
     590             : 
     591             :   /**
     592             :    * @return true if _redox_e appears as a secondary species in the database and that its
     593             :    * stoichiometry can be expressed in terms of basis species
     594             :    */
     595             :   bool checkRedoxe();
     596             : 
     597             :   /**
     598             :    * Check that all minerals in mineral_info have reactions that involve only the
     599             :    * basis_species or secondary_species.   Check that if a mineral in this list is also a
     600             :    * "sorbing mineral", its sorbing sites are present in the basis_species list
     601             :    */
     602             :   void checkMinerals(const std::vector<GeochemistryMineralSpecies> & mineral_info) const;
     603             : 
     604             :   /**
     605             :    * Check that all gases in the "gases" list have reactions that involve only the
     606             :    * basis_species or secondary_species.
     607             :    */
     608             :   void checkGases() const;
     609             : 
     610             :   /**
     611             :    * Check that all kinetic redox species in the _kinetic_redox list have reactions that involve
     612             :    * only the basis_species or secondary_species.
     613             :    */
     614             :   void checkKineticRedox() const;
     615             : 
     616             :   /**
     617             :    * Check that all kinetic surface species in the _kinetic_surface_species list have reactions that
     618             :    * involve only the basis_species or secondary_species.
     619             :    */
     620             :   void checkKineticSurfaceSpecies() const;
     621             : 
     622             :   /**
     623             :    * Fully populate the ModelGeochemicalDatabase
     624             :    */
     625             :   void createModel();
     626             : 
     627             :   /**
     628             :    * Extract the stoichiometry and log10K for the _redox_e species.  This is called during
     629             :    * createModel()
     630             :    * @param redox_e_stoichiometry upon exit will contain the stoichiometry for the _redox_e species
     631             :    * @param redox_e_log10K upon exit will contain the log10K info for the _redox_e species
     632             :    */
     633             :   void buildRedoxeInfo(std::vector<Real> & redox_e_stoichiometry,
     634             :                        std::vector<Real> & redox_e_log10K);
     635             : };

Generated by: LCOV version 1.14