LCOV - code coverage report
Current view: top level - include/utils - GeochemistryKineticRateCalculator.h (source / functions) Hit Total Coverage
Test: idaholab/moose geochemistry: 602416 Lines: 31 47 66.0 %
Date: 2025-07-18 11:37:48 Functions: 1 2 50.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 "MooseTypes.h"
      13             : #include "DenseMatrix.h"
      14             : #include "GeochemistryConstants.h"
      15             : 
      16             : /**
      17             :  * This controls the direction of a kinetic rate
      18             :  * BOTH: both dissolution and precipitation are allowed
      19             :  * PRECIPITATION: if log10(activity_product) < log10(equilibrium_constant) so that dissolution
      20             :  * should occur, then the rate is set to zero
      21             :  * DISSOLUTION: if log10(activity_product) > log10(equilibrium_constant) so that precipitation
      22             :  * should occur, then the rate is set to zero
      23             :  * RAW: rate is unimpacted by sign of log10(activity_product) / log10(equilibrium_constant)
      24             :  * DEATH: rate is unimpacted by sign of log10(activity_product) / log10(equilibrium_constant).  This
      25             :  * is different from RAW because no reaction products are produced: the kinetic rate is *only* used
      26             :  * to modify the kinetic species' mass.  This is useful to model biological mortality.
      27             :  */
      28             : enum DirectionChoiceEnum
      29             : {
      30             :   BOTH,
      31             :   DISSOLUTION,
      32             :   PRECIPITATION,
      33             :   RAW,
      34             :   DEATH
      35             : };
      36             : 
      37             : /**
      38             :  * Holds a user-specified description of a kinetic rate
      39             :  *
      40             :  * @param kinetic_species name of the kinetic species
      41             :  * @param intrinsic_rate_constant Note that intrinsic_rate_constant * area_quantity *
      42             :  * [kinetic_species mass] must have dimensions mol.s^-1
      43             :  * @param area_quantity Either 1, or the fixed surface area of the kinetic species, or a specific
      44             :  * surface area (m^2/g)
      45             :  * @param multiply_by_mass whether the rate should be multiplied by the kinetic_species mass
      46             :  * @param kinetic_molal_index, rate is multiplied by kinetic_species_molality^kinetic_molal_index
      47             :  * @param kinetic_monod_index, rate is multiplied by 1.0 /
      48             :  * (kinetic_species_molality^kinetic_molal_index +
      49             :  * kinetic_half_saturation^kinetic_molal_index)^kinetic_monod_index
      50             :  * @param kinetic_half_saturation, rate is multiplied by 1.0 /
      51             :  * (kinetic_species_molality^kinetic_molal_index +
      52             :  * kinetic_half_saturation^kinetic_molal_index)^kinetic_monod_index
      53             :  * @param promoting_species names of species (which must be primary or secondary species in the
      54             :  * system)
      55             :  * @param promoting_indices indices of mass, fugacity, activity or mobility (as appropriate)
      56             :  * @param promoting_monod_indices monod indices of mass, fugacity, activity or mobility (as
      57             :  * appropriate)
      58             :  * @param promoting_half_saturation half saturation values of all promoting species
      59             :  * @param theta exponent of (Q/K)
      60             :  * @param eta exponent of |1-(Q/K)^theta|
      61             :  * @param activation_energy in J.mol^-1
      62             :  * @param one_over_T0 measured in 1/Kelvin
      63             :  * @param direction: whether this kinetic rate is designed for: "both" precipitation and
      64             :  * dissolution; "precipitation" only; "dissolution" only; and "raw" or "death" mean the rate does
      65             :  * not depend on the sign of 1-(Q/K)
      66             :  * @param progeny: A non-kinetic species that catalyses the reaction, and potentially gets produced
      67             :  * or consumed by it
      68             :  * @param progeny_efficiency: When one mole of reaction is catalysed, progeny_efficiency moles of
      69             :  * the progeny is created
      70             :  * @param kinetic_bio_efficiency: the efficiency of a biologically-catalysed reaction, that is, when
      71             :  * one mole of reaction is catalysed, the biomass increases by kinetic_bio_efficiency moles
      72             :  * @param energy captured: energy captured by a biologically-catalysed reaction, essentially this
      73             :  * reduces the equilibrium constant of the reaction by exp(-energy_capture / R / Tk)
      74             :  */
      75             : struct KineticRateUserDescription
      76             : {
      77         108 :   KineticRateUserDescription(const std::string & kinetic_species_name,
      78             :                              Real intrinsic_rate_constant,
      79             :                              Real area_quantity,
      80             :                              bool multiply_by_mass,
      81             :                              Real kinetic_molal_index,
      82             :                              Real kinetic_monod_index,
      83             :                              Real kinetic_half_saturation,
      84             :                              const std::vector<std::string> & promoting_species,
      85             :                              const std::vector<Real> & promoting_indices,
      86             :                              const std::vector<Real> & promoting_monod_indices,
      87             :                              const std::vector<Real> & promoting_half_saturation,
      88             :                              Real theta,
      89             :                              Real eta,
      90             :                              Real activation_energy,
      91             :                              Real one_over_T0,
      92             :                              DirectionChoiceEnum direction,
      93             :                              std::string progeny,
      94             :                              Real progeny_efficiency,
      95             :                              Real kinetic_bio_efficiency,
      96             :                              Real energy_captured)
      97         108 :     : kinetic_species_name(kinetic_species_name),
      98         108 :       intrinsic_rate_constant(intrinsic_rate_constant),
      99         108 :       area_quantity(area_quantity),
     100         108 :       multiply_by_mass(multiply_by_mass),
     101         108 :       kinetic_molal_index(kinetic_molal_index),
     102         108 :       kinetic_monod_index(kinetic_monod_index),
     103         108 :       kinetic_half_saturation(kinetic_half_saturation),
     104         108 :       promoting_species(promoting_species),
     105         108 :       promoting_indices(promoting_indices),
     106         108 :       promoting_monod_indices(promoting_monod_indices),
     107         108 :       promoting_half_saturation(promoting_half_saturation),
     108         108 :       theta(theta),
     109         108 :       eta(eta),
     110         108 :       activation_energy(activation_energy),
     111         108 :       one_over_T0(one_over_T0),
     112         108 :       direction(direction),
     113         108 :       progeny(progeny),
     114         108 :       progeny_efficiency(progeny_efficiency),
     115         108 :       kinetic_bio_efficiency(kinetic_bio_efficiency),
     116         108 :       energy_captured(energy_captured)
     117             :   {
     118         108 :     if (promoting_species.size() != promoting_indices.size())
     119           1 :       mooseError("The promoting_species and promoting_indices vectors must be the same size");
     120         107 :     if (promoting_species.size() != promoting_monod_indices.size())
     121           1 :       mooseError("The promoting_species and promoting_monod_indices vectors must be the same size");
     122         106 :     if (promoting_species.size() != promoting_half_saturation.size())
     123           1 :       mooseError(
     124             :           "The promoting_species and promoting_half_saturation vectors must be the same size");
     125             :     std::unordered_map<std::string, int> check_for_repeats;
     126         230 :     for (const std::string & name : promoting_species)
     127             :       if (check_for_repeats.count(name) == 1)
     128           1 :         mooseError("Promoting species ", name, " has already been provided with an exponent");
     129             :       else
     130         125 :         check_for_repeats[name] = 1;
     131         108 :   };
     132             : 
     133           0 :   bool operator==(const KineticRateUserDescription & rhs) const
     134             :   {
     135           0 :     return (kinetic_species_name == rhs.kinetic_species_name) &&
     136           0 :            (intrinsic_rate_constant == rhs.intrinsic_rate_constant) &&
     137           0 :            (area_quantity == rhs.area_quantity) && (multiply_by_mass == rhs.multiply_by_mass) &&
     138           0 :            (kinetic_molal_index == rhs.kinetic_molal_index) &&
     139           0 :            (kinetic_monod_index == rhs.kinetic_monod_index) &&
     140           0 :            (kinetic_half_saturation == rhs.kinetic_half_saturation) &&
     141           0 :            (promoting_species == rhs.promoting_species) &&
     142           0 :            (promoting_indices == rhs.promoting_indices) &&
     143           0 :            (promoting_monod_indices == rhs.promoting_monod_indices) &&
     144           0 :            (promoting_half_saturation == rhs.promoting_half_saturation) && (theta == rhs.theta) &&
     145           0 :            (eta == rhs.eta) && (activation_energy == rhs.activation_energy) &&
     146           0 :            (one_over_T0 == rhs.one_over_T0) && (direction == rhs.direction) &&
     147           0 :            (progeny == rhs.progeny) && (progeny_efficiency == rhs.progeny_efficiency) &&
     148           0 :            (kinetic_bio_efficiency == rhs.kinetic_bio_efficiency) &&
     149           0 :            (energy_captured == rhs.energy_captured);
     150             :   };
     151             : 
     152             :   std::string kinetic_species_name;
     153             :   Real intrinsic_rate_constant;
     154             :   Real area_quantity;
     155             :   bool multiply_by_mass;
     156             :   Real kinetic_molal_index;
     157             :   Real kinetic_monod_index;
     158             :   Real kinetic_half_saturation;
     159             :   std::vector<std::string> promoting_species;
     160             :   std::vector<Real> promoting_indices;
     161             :   std::vector<Real> promoting_monod_indices;
     162             :   std::vector<Real> promoting_half_saturation;
     163             :   Real theta;
     164             :   Real eta;
     165             :   Real activation_energy;
     166             :   Real one_over_T0;
     167             :   DirectionChoiceEnum direction;
     168             :   std::string progeny;
     169             :   Real progeny_efficiency;
     170             :   Real kinetic_bio_efficiency;
     171             :   Real energy_captured;
     172             : };
     173             : 
     174             : /**
     175             :  * Provides a parametric description of a general kinetic rate.  This is a separate class with very
     176             :  * little functionality partly so that it can be used by multiple other classes
     177             :  * (PertinentGeochemicalSystem, GeochemistryKineticRate) but also so that it can be easily added to
     178             :  * if more general kinetic rates are ever required.
     179             :  *
     180             :  * The rate is a product of the following terms:
     181             :  *
     182             :  * intrinsic_rate_constant
     183             :  * area_quantity
     184             :  * mass of the kinetic_species, measured in grams, if multiply_by_mass is true
     185             :  * (molality of kinetic_species)^kinetic_molal_index
     186             :  * 1 / ((molality of kinetic_species)^kinetic_molal_index +
     187             :  * kinetic_half_saturation^kinetic_molal_index)^kinetic_monod_index
     188             :  * product over the promoting_species of m^(promoting_index) / (m^(promoting_index) +
     189             :  * half_saturation^(promoting_index))^(promoting_monod_index)
     190             :  * |1 - (Q/K)^theta|^eta, where K = eqm_constant_in_database * exp(- energy_captured / R / TK)
     191             :  * exp(activation_energy / R * (1/T0 - 1/T)) D(1 - (Q/K))
     192             :  *
     193             :  * Some explanation may be useful:
     194             :  *
     195             :  * intrinsic_rate_constant * area_quantity * [mass of kinetic_species] has units mol.s^-1.  This
     196             :  * allows for the following common possibilities:
     197             :  * - intrinsic_rate_constant is measured in mol.s^-1.  In this case, the user should set
     198             :  * area_quantity=1 and multiply_by_mass=false
     199             :  * - intrinsic_rate_constant is measured in mol.s^-1/kg(solvent_water).  In this case the user
     200             :  * should set area_quantity=1 and multipliy_by_mass=false, but ensure that
     201             :  * promoting_species={"H2O",...} and promoting_index={1,...}.
     202             :  * - intrinsic_rate_constant is measured in mol.s^-1/area_of_kinetic_mineral, and the area of the
     203             :  * kinetic mineral is fixed.  In this case the user should set
     204             :  * area_quantity=area_of_kinetic_mineral and multiply_by_mass=false.
     205             :  * - intrinsic_rate_constant is measured in mol.s^-1/area_of_kinetic_mineral, and the area of the
     206             :  * kinetic mineral depends on its mass.  In this case, the user should set
     207             :  * area_quantity=specific_area_of_mineral (in m^2/g) and multiply_by_mass=true
     208             :  *
     209             :  * The "m" in the promoting species product is:
     210             :  * - mass of solvent water (in kg) if promoting_species="H2O"
     211             :  * - fugacity of a gas if promoting_species is a gas
     212             :  * - activity if promoting_species is either "H+" or "OH-"
     213             :  * - mobility, otherwise
     214             :  *
     215             :  * Q is the activity product, defined by the kinetic_species reaction (defined in the database
     216             :  * file).
     217             :  * K is the reaction's equilibrium constant (defined in the database file) multiplied by
     218             :  * exp(-energy_captured / (RT)).
     219             :  * R = 8.314472 m^2.kg.s^-2.K^-1.mol^-1 = 8.314472 J.K^-1.mol^-1 is
     220             :  * the gas constant. T is the temperature in Kelvin. T0 is a reference temperature, in Kelvin.  It
     221             :  * is inputted as 1/T0 so that 1/T0 = 0 is possible.
     222             :  *
     223             :  * D(x) depends on direction.  If direction == BOTH then D(x) = sgn(x).  If direction == DISSOLUTION
     224             :  * then D(x) = (x>0)?1:0.  If direction == PRECIPITATION then D(x) = (x<0)?-1:0.  If direction ==
     225             :  * RAW then D=1.  If direction == DEATH then D=1.
     226             :  *
     227             :  * The amount of kinetic species that is generated is kinetic_bio_efficiency * rate.  Note that rate
     228             :  * > 0 for dissolution of the kinetic species, so kinetic_bio_efficiency defaults to -1.  However,
     229             :  * for biogeochemistry, it is appropriate to set kinetic_bio_efficiency > 0, so that "dissolution"
     230             :  * of the biomass (with rate > 0) generates further biomass
     231             :  */
     232             : namespace GeochemistryKineticRateCalculator
     233             : {
     234             : /**
     235             :  * Calclates a kinetic rate and its derivative. The rate is a product of the following terms:
     236             :  *
     237             :  * intrinsic_rate_constant
     238             :  * area_quantity
     239             :  * mass of the kinetic_species, measured in grams, if multiply_by_mass is true
     240             :  * product over the promoting_species of m^(promoting_index)
     241             :  * |1 - (Q/K)^theta|^eta
     242             :  * exp(activation_energy / R * (1/T0 - 1/T))
     243             :  * D(1 - (Q/K))
     244             :  *
     245             :  * @param promoting_indices of the basis species and equilibrium species.  Note that this is
     246             :  * different from description.promoting_indices (which is paired with description.promoting_species)
     247             :  * because it is the promoting indices for the current basis and equilibrium.  For computational
     248             :  * efficiency promoting_indices[0:num_basis-1] are the promoting indices for the current basis
     249             :  * species while promoting_indices[num_basis:] are the promoting indices for the current eqm species
     250             :  * @param description contains definition of intrinsic_rate_constant, area_quantity, etc
     251             :  * @param basis_species_name vector of basis species names
     252             :  * @param basis_species_gas i^th element is true if the i^th basis species is a gas
     253             :  * @param basis_molality vector of the basis molalities (zeroth element is kg of solvent water, and
     254             :  * this is mole number for mineral species)
     255             :  * @param basis_activity vector of basis activities
     256             :  * @param basis_activity_known i^th element is true if the activity for the i^th basis species has
     257             :  * been constrained by the user
     258             :  * @param eqm_species_name vector of eqm species names
     259             :  * @param eqm_species_gas i^th element is true if the i^th eqm species is a gas
     260             :  * @param eqm_molality vector of the eqm molalities (zeroth element is kg of solvent water, and this
     261             :  * is mole number for mineral species)
     262             :  * @param eqm_activity vector of eqm activities
     263             :  * @param eqm_stoichiometry matrix of stoichiometric coefficient
     264             :  * @param kin_moles moles of the kinetic species
     265             :  * @param kin_species_molecular_weight molecular weight (g/mol) of the kinetic species
     266             :  * @param kin_stoichiometry kinetic stoichiometry matrix (only row=kin is used)
     267             :  * @param kin the row of kin_stoichiometry that corresponds to the kinetic species
     268             :  * @param log10K log10(equilibrium constant) of the kinetic species
     269             :  * @param log10_activity_product log10(activity product) of the kinetic species
     270             :  * @param temp_deg temperature in degC
     271             :  * @param[out] rate the rate computed by this method
     272             :  * @param[out] drate_dkin d(rate)/d(mole number of the kinetic species)
     273             :  * @param[out] drate_dmol d(rate)/d(basis molality[i])
     274             :  */
     275             : void calculateRate(const std::vector<Real> & promoting_indices,
     276             :                    const std::vector<Real> & promoting_monod_indices,
     277             :                    const std::vector<Real> & promoting_half_saturation,
     278             :                    const KineticRateUserDescription & description,
     279             :                    const std::vector<std::string> & basis_species_name,
     280             :                    const std::vector<bool> & basis_species_gas,
     281             :                    const std::vector<Real> & basis_molality,
     282             :                    const std::vector<Real> & basis_activity,
     283             :                    const std::vector<bool> & basis_activity_known,
     284             :                    const std::vector<std::string> & eqm_species_name,
     285             :                    const std::vector<bool> & eqm_species_gas,
     286             :                    const std::vector<Real> & eqm_molality,
     287             :                    const std::vector<Real> & eqm_activity,
     288             :                    const DenseMatrix<Real> & eqm_stoichiometry,
     289             :                    Real kin_moles,
     290             :                    Real kin_species_molecular_weight,
     291             :                    Real log10K,
     292             :                    Real log10_activity_product,
     293             :                    const DenseMatrix<Real> & kin_stoichiometry,
     294             :                    unsigned kin,
     295             :                    Real temp_degC,
     296             :                    Real & rate,
     297             :                    Real & drate_dkin,
     298             :                    std::vector<Real> & drate_dmol);
     299             : }

Generated by: LCOV version 1.14