LCOV - code coverage report
Current view: top level - src/materials - PorousFlowAqueousPreDisChemistry.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #31405 (292dce) with base fef103 Lines: 219 234 93.6 %
Date: 2025-09-04 07:55:56 Functions: 10 10 100.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             : #include "PorousFlowAqueousPreDisChemistry.h"
      11             : 
      12             : registerMooseObject("PorousFlowApp", PorousFlowAqueousPreDisChemistry);
      13             : 
      14             : InputParameters
      15        2260 : PorousFlowAqueousPreDisChemistry::validParams()
      16             : {
      17        2260 :   InputParameters params = PorousFlowMaterialVectorBase::validParams();
      18        4520 :   params.addRequiredCoupledVar(
      19             :       "primary_concentrations",
      20             :       "List of MOOSE Variables that represent the concentrations of the primary species");
      21        4520 :   params.addRequiredParam<unsigned>("num_reactions",
      22             :                                     "Number of equations in the system of chemical reactions");
      23        4520 :   params.addParam<bool>("equilibrium_constants_as_log10",
      24        4520 :                         false,
      25             :                         "If true, the equilibrium constants are written in their log10 form, eg, "
      26             :                         "-2.  If false, the equilibrium constants are written in absolute terms, "
      27             :                         "eg, 0.01");
      28        4520 :   params.addRequiredCoupledVar("equilibrium_constants",
      29             :                                "Equilibrium constant for each equation (dimensionless).  If these "
      30             :                                "are temperature dependent AuxVariables, the Jacobian will not be "
      31             :                                "exact");
      32        4520 :   params.addRequiredParam<std::vector<Real>>(
      33             :       "primary_activity_coefficients",
      34             :       "Activity coefficients for the primary species (dimensionless) (one for each)");
      35        4520 :   params.addRequiredParam<std::vector<Real>>(
      36             :       "reactions",
      37             :       "A matrix defining the aqueous reactions.  The matrix is entered as a long vector: the first "
      38             :       "row is "
      39             :       "entered first, followed by the second row, etc.  There should be num_reactions rows.  All "
      40             :       "primary species should appear only on the LHS of each reaction (and there should be just "
      41             :       "one secondary species on the RHS, by definition) so they may have negative coefficients.  "
      42             :       "Each row should have number of primary_concentrations entries, which are the stoichiometric "
      43             :       "coefficients.  The first coefficient must always correspond to the first primary species, "
      44             :       "etc");
      45        4520 :   params.addRequiredParam<std::vector<Real>>("specific_reactive_surface_area",
      46             :                                              "Specific reactive surface area in m^2/(L solution).");
      47        4520 :   params.addRequiredParam<std::vector<Real>>(
      48             :       "kinetic_rate_constant",
      49             :       "Kinetic rate constant in mol/(m^2 s), at the reference temperature (one for each reaction)");
      50        4520 :   params.addRequiredParam<std::vector<Real>>("molar_volume",
      51             :                                              "Volume occupied by one mole of the secondary species "
      52             :                                              "(L(solution)/mol) (one for each reaction)");
      53        4520 :   params.addRequiredParam<std::vector<Real>>("activation_energy",
      54             :                                              "Activation energy, J/mol (one for each reaction)");
      55        4520 :   params.addParam<Real>("gas_constant", 8.31434, "Gas constant, in J/(mol K)");
      56        4520 :   params.addParam<Real>("reference_temperature", 298.15, "Reference temperature, K");
      57        4520 :   params.addParam<std::vector<Real>>("theta_exponent",
      58             :                                      "Theta exponent.  Defaults to 1.  (one for each reaction)");
      59        4520 :   params.addParam<std::vector<Real>>("eta_exponent",
      60             :                                      "Eta exponent.  Defaults to 1.  (one for each reaction)");
      61        4520 :   params.addPrivateParam<std::string>("pf_material_type", "chemistry");
      62        2260 :   params.addClassDescription("This Material forms a std::vector of mineralisation reaction rates "
      63             :                              "(L(precipitate)/L(solution)/s) appropriate to the aqueous "
      64             :                              "precipitation-dissolution system provided.  Note: the "
      65             :                              "PorousFlowTemperature must be measured in Kelvin.");
      66        2260 :   return params;
      67           0 : }
      68             : 
      69        1777 : PorousFlowAqueousPreDisChemistry::PorousFlowAqueousPreDisChemistry(
      70        1777 :     const InputParameters & parameters)
      71             :   : PorousFlowMaterialVectorBase(parameters),
      72        1074 :     _porosity_old(_nodal_material ? getMaterialPropertyOld<Real>("PorousFlow_porosity_nodal")
      73        3183 :                                   : getMaterialPropertyOld<Real>("PorousFlow_porosity_qp")),
      74        1777 :     _aq_ph(_dictator.aqueousPhaseNumber()),
      75        3554 :     _saturation(_nodal_material
      76        1777 :                     ? getMaterialProperty<std::vector<Real>>("PorousFlow_saturation_nodal")
      77        3183 :                     : getMaterialProperty<std::vector<Real>>("PorousFlow_saturation_qp")),
      78             : 
      79        1777 :     _temperature(_nodal_material ? getMaterialProperty<Real>("PorousFlow_temperature_nodal")
      80        3183 :                                  : getMaterialProperty<Real>("PorousFlow_temperature_qp")),
      81        1777 :     _dtemperature_dvar(
      82        1777 :         _nodal_material
      83        1777 :             ? getMaterialProperty<std::vector<Real>>("dPorousFlow_temperature_nodal_dvar")
      84        3183 :             : getMaterialProperty<std::vector<Real>>("dPorousFlow_temperature_qp_dvar")),
      85             : 
      86        1777 :     _num_primary(coupledComponents("primary_concentrations")),
      87        3554 :     _num_reactions(getParam<unsigned>("num_reactions")),
      88        3554 :     _equilibrium_constants_as_log10(getParam<bool>("equilibrium_constants_as_log10")),
      89        1777 :     _num_equilibrium_constants(coupledComponents("equilibrium_constants")),
      90        1777 :     _equilibrium_constants(_num_equilibrium_constants),
      91        3554 :     _primary_activity_coefficients(getParam<std::vector<Real>>("primary_activity_coefficients")),
      92        5331 :     _reactions(getParam<std::vector<Real>>("reactions")),
      93             : 
      94        1777 :     _sec_conc_old(
      95        1777 :         _nodal_material
      96        1777 :             ? getMaterialPropertyOld<std::vector<Real>>("PorousFlow_mineral_concentration_nodal")
      97        3183 :             : getMaterialPropertyOld<std::vector<Real>>("PorousFlow_mineral_concentration_qp")),
      98             : 
      99        1777 :     _mineral_sat(_num_reactions),
     100        1777 :     _bounded_rate(_num_reactions),
     101        1777 :     _reaction_rate(
     102        1777 :         _nodal_material
     103        1777 :             ? declareProperty<std::vector<Real>>("PorousFlow_mineral_reaction_rate_nodal")
     104        2480 :             : declareProperty<std::vector<Real>>("PorousFlow_mineral_reaction_rate_qp")),
     105        1777 :     _dreaction_rate_dvar(_nodal_material ? declareProperty<std::vector<std::vector<Real>>>(
     106             :                                                "dPorousFlow_mineral_reaction_rate_nodal_dvar")
     107        2480 :                                          : declareProperty<std::vector<std::vector<Real>>>(
     108             :                                                "dPorousFlow_mineral_reaction_rate_qp_dvar")),
     109             : 
     110        3554 :     _r_area(getParam<std::vector<Real>>("specific_reactive_surface_area")),
     111        3554 :     _molar_volume(getParam<std::vector<Real>>("molar_volume")),
     112        3554 :     _ref_kconst(getParam<std::vector<Real>>("kinetic_rate_constant")),
     113        3554 :     _e_act(getParam<std::vector<Real>>("activation_energy")),
     114        3554 :     _gas_const(getParam<Real>("gas_constant")),
     115        3554 :     _one_over_ref_temp(1.0 / getParam<Real>("reference_temperature")),
     116        5762 :     _theta_exponent(isParamValid("theta_exponent") ? getParam<std::vector<Real>>("theta_exponent")
     117        1777 :                                                    : std::vector<Real>(_num_reactions, 1.0)),
     118        5762 :     _eta_exponent(isParamValid("eta_exponent") ? getParam<std::vector<Real>>("eta_exponent")
     119        3554 :                                                : std::vector<Real>(_num_reactions, 1.0))
     120             : {
     121        1777 :   if (_dictator.numPhases() < 1)
     122           2 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of fluid phases must not be zero");
     123             : 
     124        1775 :   if (_num_primary != _num_components - 1)
     125           0 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of mass_fraction_vars is ",
     126           0 :                _num_components,
     127             :                " which must be one greater than the number of primary concentrations (which is ",
     128           0 :                _num_primary,
     129             :                ")");
     130             : 
     131             :   // correct number of equilibrium constants
     132        1775 :   if (_num_equilibrium_constants != _num_reactions)
     133           0 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of equilibrium constants is ",
     134           0 :                _num_equilibrium_constants,
     135             :                " which must be equal to the number of reactions (",
     136           0 :                _num_reactions,
     137             :                ")");
     138             : 
     139             :   // correct number of activity coefficients
     140        1775 :   if (_primary_activity_coefficients.size() != _num_primary)
     141           0 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of primary activity "
     142             :                "coefficients is ",
     143           0 :                _primary_activity_coefficients.size(),
     144             :                " which must be equal to the number of primary species (",
     145           0 :                _num_primary,
     146             :                ")");
     147             : 
     148             :   // correct number of stoichiometry coefficients
     149        1775 :   if (_reactions.size() != _num_reactions * _num_primary)
     150           0 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of stoichiometric "
     151             :                "coefficients specified in 'reactions' (",
     152           0 :                _reactions.size(),
     153             :                ") must be equal to the number of reactions (",
     154           0 :                _num_reactions,
     155             :                ") multiplied by the number of primary species (",
     156           0 :                _num_primary,
     157             :                ")");
     158             : 
     159        1775 :   if (_r_area.size() != _num_reactions)
     160           2 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of specific reactive "
     161             :                "surface areas provided is ",
     162           2 :                _r_area.size(),
     163             :                " which must be equal to the number of reactions (",
     164           2 :                _num_reactions,
     165             :                ")");
     166             : 
     167        1773 :   if (_ref_kconst.size() != _num_reactions)
     168           2 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of kinetic rate constants is ",
     169           2 :                _ref_kconst.size(),
     170             :                " which must be equal to the number of reactions (",
     171           2 :                _num_reactions,
     172             :                ")");
     173             : 
     174        1771 :   if (_e_act.size() != _num_reactions)
     175           2 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of activation energies is ",
     176           2 :                _e_act.size(),
     177             :                " which must be equal to the number of reactions (",
     178           2 :                _num_reactions,
     179             :                ")");
     180             : 
     181        1769 :   if (_molar_volume.size() != _num_reactions)
     182           2 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of molar volumes is ",
     183           2 :                _molar_volume.size(),
     184             :                " which must be equal to the number of reactions (",
     185           2 :                _num_reactions,
     186             :                ")");
     187             : 
     188        1767 :   if (_theta_exponent.size() != _num_reactions)
     189           2 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of theta exponents is ",
     190           2 :                _theta_exponent.size(),
     191             :                " which must be equal to the number of reactions (",
     192           2 :                _num_reactions,
     193             :                ")");
     194             : 
     195        1765 :   if (_eta_exponent.size() != _num_reactions)
     196           2 :     mooseError("PorousFlowAqueousPreDisChemistry: The number of eta exponents is ",
     197           2 :                _eta_exponent.size(),
     198             :                " which must be equal to the number of reactions (",
     199           2 :                _num_reactions,
     200             :                ")");
     201             : 
     202        1763 :   if (_num_reactions != _dictator.numAqueousKinetic())
     203           4 :     mooseError("PorousFlowAqueousPreDisChemistry: You have specified the number of "
     204             :                "reactions to be ",
     205           2 :                _num_reactions,
     206             :                " but the Dictator knows that the number of aqueous kinetic "
     207             :                "(precipitation-dissolution) reactions is ",
     208           2 :                _dictator.numAqueousKinetic());
     209             : 
     210        1761 :   _primary_var_num.resize(_num_primary);
     211        1761 :   _primary.resize(_num_primary);
     212        4869 :   for (unsigned i = 0; i < _num_primary; ++i)
     213             :   {
     214        3108 :     _primary_var_num[i] = coupled("primary_concentrations", i);
     215        6216 :     _primary[i] = (_nodal_material ? &coupledDofValues("primary_concentrations", i)
     216        4200 :                                    : &coupledValue("primary_concentrations", i));
     217             :   }
     218             : 
     219        3852 :   for (unsigned i = 0; i < _num_equilibrium_constants; ++i)
     220             :   {
     221             :     // If equilibrium_constants are elemental AuxVariables (or constants), we want to use
     222             :     // coupledGenericValue() rather than coupledGenericDofValue()
     223        2091 :     const bool is_nodal = isCoupled("equilibrium_constants")
     224        4182 :                               ? getFieldVar("equilibrium_constants", i)->isNodal()
     225             :                               : false;
     226             : 
     227        2091 :     _equilibrium_constants[i] =
     228        4182 :         (_nodal_material && is_nodal ? &coupledDofValues("equilibrium_constants", i)
     229        2844 :                                      : &coupledValue("equilibrium_constants", i));
     230             :   }
     231        1761 : }
     232             : 
     233             : void
     234       22666 : PorousFlowAqueousPreDisChemistry::initQpStatefulProperties()
     235             : {
     236       22666 :   _reaction_rate[_qp].resize(_num_reactions);
     237       22666 :   _dreaction_rate_dvar[_qp].resize(_num_reactions);
     238       45532 :   for (unsigned r = 0; r < _num_reactions; ++r)
     239       22866 :     _dreaction_rate_dvar[_qp][r].assign(_num_var, 0.0);
     240       22666 : }
     241             : 
     242             : void
     243      951658 : PorousFlowAqueousPreDisChemistry::computeQpProperties()
     244             : {
     245      951658 :   _reaction_rate[_qp].resize(_num_reactions);
     246      951658 :   _dreaction_rate_dvar[_qp].resize(_num_reactions);
     247     1904556 :   for (unsigned r = 0; r < _num_reactions; ++r)
     248      952898 :     _dreaction_rate_dvar[_qp][r].assign(_num_var, 0.0);
     249             : 
     250             :   // Compute the reaction rates
     251      951658 :   computeQpReactionRates();
     252             : 
     253             :   // Compute the derivatives of the reaction rates
     254      951658 :   std::vector<std::vector<Real>> drr(_num_reactions);
     255      951658 :   std::vector<Real> drr_dT(_num_reactions);
     256     1904556 :   for (unsigned r = 0; r < _num_reactions; ++r)
     257             :   {
     258      952898 :     dQpReactionRate_dprimary(r, drr[r]);
     259      952898 :     drr_dT[r] = dQpReactionRate_dT(r);
     260             :   }
     261             : 
     262             :   // compute _dreaction_rate_dvar[_qp]
     263     4037576 :   for (unsigned wrt = 0; wrt < _num_primary; ++wrt)
     264             :   {
     265             :     // derivative with respect to the "wrt"^th primary species concentration
     266     3085918 :     if (!_dictator.isPorousFlowVariable(_primary_var_num[wrt]))
     267         222 :       continue;
     268     3085696 :     const unsigned pf_wrt = _dictator.porousFlowVariableNum(_primary_var_num[wrt]);
     269             : 
     270             :     // run through the reactions, using drr in the appropriate places
     271     6174972 :     for (unsigned r = 0; r < _num_reactions; ++r)
     272     3089276 :       _dreaction_rate_dvar[_qp][r][pf_wrt] = drr[r][wrt];
     273             :   }
     274             : 
     275             :   // use the derivative wrt temperature
     276     1904556 :   for (unsigned r = 0; r < _num_reactions; ++r)
     277     4044506 :     for (unsigned v = 0; v < _num_var; ++v)
     278     3091608 :       _dreaction_rate_dvar[_qp][r][v] += drr_dT[r] * _dtemperature_dvar[_qp][v];
     279      951658 : }
     280             : 
     281             : Real
     282     5519564 : PorousFlowAqueousPreDisChemistry::stoichiometry(unsigned reaction_num, unsigned primary_num) const
     283             : {
     284     5519564 :   const unsigned index = reaction_num * _num_primary + primary_num;
     285     5519564 :   return _reactions[index];
     286             : }
     287             : 
     288             : void
     289      615810 : PorousFlowAqueousPreDisChemistry::findZeroConcentration(unsigned & zero_conc_index,
     290             :                                                         unsigned & zero_count) const
     291             : {
     292      615810 :   zero_count = 0;
     293     3043912 :   for (unsigned i = 0; i < _num_primary; ++i)
     294             :   {
     295     2428592 :     if (_primary_activity_coefficients[i] * (*_primary[i])[_qp] <= 0.0)
     296             :     {
     297        1350 :       zero_count += 1;
     298        1350 :       zero_conc_index = i;
     299        1350 :       if (zero_count > 1)
     300             :         return;
     301             :     }
     302             :   }
     303             :   return;
     304             : }
     305             : 
     306             : void
     307      951658 : PorousFlowAqueousPreDisChemistry::computeQpReactionRates()
     308             : {
     309     1904556 :   for (unsigned r = 0; r < _num_reactions; ++r)
     310             :   {
     311      952898 :     _mineral_sat[r] =
     312      952898 :         (_equilibrium_constants_as_log10 ? std::pow(10.0, -(*_equilibrium_constants[r])[_qp])
     313      952378 :                                          : 1.0 / (*_equilibrium_constants[r])[_qp]);
     314     3998490 :     for (unsigned j = 0; j < _num_primary; ++j)
     315             :     {
     316     3068812 :       const Real gamp = _primary_activity_coefficients[j] * (*_primary[j])[_qp];
     317     3068812 :       if (gamp <= 0.0)
     318             :       {
     319       23400 :         if (stoichiometry(r, j) < 0.0)
     320          20 :           _mineral_sat[r] = std::numeric_limits<Real>::max();
     321       23380 :         else if (stoichiometry(r, j) == 0.0)
     322             :           _mineral_sat[r] *= 1.0;
     323             :         else
     324             :         {
     325       23220 :           _mineral_sat[r] = 0.0;
     326       23220 :           break;
     327             :         }
     328             :       }
     329             :       else
     330     3045412 :         _mineral_sat[r] *= std::pow(gamp, stoichiometry(r, j));
     331             :     }
     332      952898 :     const Real fac = 1.0 - std::pow(_mineral_sat[r], _theta_exponent[r]);
     333             :     // if fac > 0 then dissolution occurs; if fac < 0 then precipitation occurs.
     334      952898 :     const Real sgn = (fac < 0 ? -1.0 : 1.0);
     335      952898 :     const Real unbounded_rr = -sgn * rateConstantQp(r) * _r_area[r] * _molar_volume[r] *
     336      952898 :                               std::pow(std::abs(fac), _eta_exponent[r]);
     337             : 
     338             :     /*
     339             :      *
     340             :      * Note the use of the OLD value of porosity here.
     341             :      * This strategy, which breaks the cyclic dependency between porosity
     342             :      * and mineral concentration, is used in
     343             :      * Kernel: PorousFlowPreDis
     344             :      * Material: PorousFlowPorosity
     345             :      * Material: PorousFlowAqueousPreDisChemistry
     346             :      * Material: PorousFlowAqueousPreDisMineral
     347             :      *
     348             :      */
     349             : 
     350             :     // bound the reaction so _sec_conc lies between zero and unity
     351      952898 :     const Real por_times_rr_dt = _porosity_old[_qp] * _saturation[_qp][_aq_ph] * unbounded_rr * _dt;
     352      952898 :     if (_sec_conc_old[_qp][r] + por_times_rr_dt > 1.0)
     353             :     {
     354             :       _bounded_rate[r] = true;
     355         250 :       _reaction_rate[_qp][r] =
     356         250 :           (1.0 - _sec_conc_old[_qp][r]) / _porosity_old[_qp] / _saturation[_qp][_aq_ph] / _dt;
     357             :     }
     358      952648 :     else if (_sec_conc_old[_qp][r] + por_times_rr_dt < 0.0)
     359             :     {
     360             :       _bounded_rate[r] = true;
     361      336838 :       _reaction_rate[_qp][r] =
     362      336838 :           -_sec_conc_old[_qp][r] / _porosity_old[_qp] / _saturation[_qp][_aq_ph] / _dt;
     363             :     }
     364             :     else
     365             :     {
     366             :       _bounded_rate[r] = false;
     367      615810 :       _reaction_rate[_qp][r] = unbounded_rr;
     368             :     }
     369             :   }
     370      951658 : }
     371             : 
     372             : void
     373      952898 : PorousFlowAqueousPreDisChemistry::dQpReactionRate_dprimary(unsigned reaction_num,
     374             :                                                            std::vector<Real> & drr) const
     375             : {
     376      952898 :   drr.assign(_num_primary, 0.0);
     377             : 
     378             :   // handle corner case
     379      952898 :   if (_bounded_rate[reaction_num])
     380      337758 :     return;
     381             : 
     382             :   /*
     383             :    * Form the derivative of _mineral_sat, and store it in drr for now.
     384             :    * The derivatives are straightforward if all primary > 0.
     385             :    *
     386             :    * If more than one primary = 0 then I set the derivatives to zero, even though it could be
     387             :    * argued that with certain stoichiometric coefficients you might have derivative = 0/0 and it
     388             :    * might be appropriate to set this to a non-zero finite value.
     389             :    *
     390             :    * If exactly one primary = 0 and its stoichiometry = 1 then the derivative wrt this one is
     391             :    * nonzero.
     392             :    * If exactly one primary = 0 and its stoichiometry > 1 then all derivatives are zero.
     393             :    * If exactly one primary = 0 and its stoichiometry < 1 then the derivative wrt this one is
     394             :    * infinity
     395             :    */
     396             : 
     397      615810 :   unsigned zero_count = 0;
     398      615810 :   unsigned zero_conc_index = 0;
     399      615810 :   findZeroConcentration(zero_conc_index, zero_count);
     400      615810 :   if (zero_count == 0)
     401             :   {
     402     3041752 :     for (unsigned i = 0; i < _num_primary; ++i)
     403     2426802 :       drr[i] = stoichiometry(reaction_num, i) * _mineral_sat[reaction_num] /
     404     2426802 :                std::max((*_primary[i])[_qp], 0.0);
     405             :   }
     406             :   else
     407             :   {
     408         860 :     if (_theta_exponent[reaction_num] < 1.0)
     409             :       // dfac = infinity (see below) so the derivative may be inf, inf * 0, or inf/inf.  I simply
     410             :       // return with drr = 0
     411             :       return;
     412             : 
     413             :     // count the number of primary <= 0, and record the one that's zero
     414         720 :     if (zero_count == 1 && stoichiometry(reaction_num, zero_conc_index) == 1.0)
     415             :     {
     416         190 :       Real conc_without_zero = (_equilibrium_constants_as_log10
     417         190 :                                     ? std::pow(10.0, -(*_equilibrium_constants[reaction_num])[_qp])
     418         190 :                                     : 1.0 / (*_equilibrium_constants[reaction_num])[_qp]);
     419         580 :       for (unsigned i = 0; i < _num_primary; ++i)
     420             :       {
     421         390 :         if (i == zero_conc_index)
     422         190 :           conc_without_zero *= _primary_activity_coefficients[i];
     423             :         else
     424         200 :           conc_without_zero *=
     425         200 :               std::pow(_primary_activity_coefficients[i] * std::max((*_primary[i])[_qp], 0.0),
     426             :                        stoichiometry(reaction_num, i));
     427             :       }
     428         190 :       drr[zero_conc_index] = conc_without_zero;
     429             :     }
     430         530 :     else if (zero_count == 0 and stoichiometry(reaction_num, zero_conc_index) < 1.0)
     431           0 :       drr[zero_conc_index] = std::numeric_limits<Real>::max();
     432             :     else
     433             :       // all other cases have drr = 0, so return without performing any other calculations
     434         530 :       return;
     435             :   }
     436             : 
     437             :   // At the moment _drr = d(mineral_sat)/d(primary)
     438             :   // Multiply by appropriate term to give _drr = d(reaction_rate)/d(primary)
     439      615140 :   const Real fac = 1.0 - std::pow(_mineral_sat[reaction_num], _theta_exponent[reaction_num]);
     440      615140 :   const Real dfac = -_theta_exponent[reaction_num] *
     441      615140 :                     std::pow(_mineral_sat[reaction_num], _theta_exponent[reaction_num] - 1.0);
     442      615140 :   const Real multiplier = -rateConstantQp(reaction_num) * _r_area[reaction_num] *
     443      615140 :                           _molar_volume[reaction_num] *
     444      615140 :                           std::pow(std::abs(fac), _eta_exponent[reaction_num] - 1.0) *
     445      615140 :                           _eta_exponent[reaction_num] * dfac;
     446     3042332 :   for (unsigned i = 0; i < _num_primary; ++i)
     447     2427192 :     drr[i] *= multiplier;
     448             : }
     449             : 
     450             : Real
     451     2183848 : PorousFlowAqueousPreDisChemistry::rateConstantQp(unsigned reaction_num) const
     452             : {
     453     2183848 :   return _ref_kconst[reaction_num] * std::exp(_e_act[reaction_num] / _gas_const *
     454     2183848 :                                               (_one_over_ref_temp - 1.0 / _temperature[_qp]));
     455             : }
     456             : 
     457             : Real
     458      952898 : PorousFlowAqueousPreDisChemistry::dQpReactionRate_dT(unsigned reaction_num) const
     459             : {
     460             :   // handle corner case
     461      952898 :   if (_bounded_rate[reaction_num])
     462             :     return 0.0;
     463             : 
     464      615810 :   const Real drate_const = rateConstantQp(reaction_num) * _e_act[reaction_num] / _gas_const *
     465      615810 :                            std::pow(_temperature[_qp], -2.0);
     466      615810 :   const Real fac = 1.0 - std::pow(_mineral_sat[reaction_num], _theta_exponent[reaction_num]);
     467      615810 :   const Real sgn = (fac < 0 ? -1.0 : 1.0);
     468      615810 :   const Real dkinetic_rate = -sgn * drate_const * _r_area[reaction_num] *
     469             :                              _molar_volume[reaction_num] *
     470      615810 :                              std::pow(std::abs(fac), _eta_exponent[reaction_num]);
     471             : 
     472      615810 :   return dkinetic_rate;
     473             : }

Generated by: LCOV version 1.14