LCOV - code coverage report
Current view: top level - src/actions - AddCoupledEqSpeciesAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose chemical_reactions: #32971 (54bef8) with base c6cf66 Lines: 120 123 97.6 %
Date: 2026-05-29 20:35:47 Functions: 3 3 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 "AddCoupledEqSpeciesAction.h"
      11             : #include "Parser.h"
      12             : #include "FEProblem.h"
      13             : #include "Factory.h"
      14             : #include "MooseError.h"
      15             : 
      16             : #include "libmesh/string_to_enum.h"
      17             : 
      18             : // Regular expression includes
      19             : #include "pcrecpp.h"
      20             : 
      21             : registerMooseAction("ChemicalReactionsApp", AddCoupledEqSpeciesAction, "add_kernel");
      22             : 
      23             : registerMooseAction("ChemicalReactionsApp", AddCoupledEqSpeciesAction, "add_aux_kernel");
      24             : 
      25             : InputParameters
      26         101 : AddCoupledEqSpeciesAction::validParams()
      27             : {
      28         101 :   InputParameters params = Action::validParams();
      29         202 :   params.addRequiredParam<std::vector<NonlinearVariableName>>(
      30             :       "primary_species", "The list of primary variables to add");
      31         202 :   params.addParam<std::vector<AuxVariableName>>(
      32             :       "secondary_species", "The list of aqueous equilibrium species to be output as aux variables");
      33         202 :   params.addParam<std::string>("reactions", "The list of aqueous equilibrium reactions");
      34         202 :   params.addParam<std::vector<VariableName>>("pressure", {}, "Pressure variable");
      35             :   RealVectorValue g(0, 0, 0);
      36         202 :   params.addParam<RealVectorValue>("gravity", g, "Gravity vector (default is (0, 0, 0))");
      37         101 :   params.addClassDescription("Adds coupled equilibrium Kernels and AuxKernels for primary species");
      38         101 :   return params;
      39           0 : }
      40             : 
      41         101 : AddCoupledEqSpeciesAction::AddCoupledEqSpeciesAction(const InputParameters & params)
      42             :   : Action(params),
      43         101 :     _primary_species(getParam<std::vector<NonlinearVariableName>>("primary_species")),
      44         303 :     _secondary_species(getParam<std::vector<AuxVariableName>>("secondary_species")),
      45         101 :     _weights(_primary_species.size()),
      46         101 :     _primary_participation(_primary_species.size()),
      47         101 :     _sto_u(_primary_species.size()),
      48         101 :     _sto_v(_primary_species.size()),
      49         101 :     _coupled_v(_primary_species.size()),
      50         303 :     _input_reactions(getParam<std::string>("reactions")),
      51         202 :     _pressure_var(getParam<std::vector<VariableName>>("pressure")),
      52         303 :     _gravity(getParam<RealVectorValue>("gravity"))
      53             : {
      54             :   // Parse the aqueous equilibrium reactions
      55             :   pcrecpp::RE re_reaction(
      56             :       "(.+?)" // single reaction (any character until the equilibrium coefficient appears)
      57             :       "\\s"   // word boundary
      58             :       "("     // start capture
      59             :       "-?"    // optional minus sign
      60             :       "\\d+(?:\\.\\d*)?" // digits followed by optional decimal and more digits
      61             :       ")"                // end capture
      62             :       "\\b"              // word boundary
      63             :       "(?:,?\\s*|$)"     // optional comma or end of string
      64             :       ,
      65         101 :       pcrecpp::RE_Options().set_extended(true));
      66             : 
      67         101 :   pcrecpp::RE re_terms("(\\S+)");
      68             :   pcrecpp::RE re_coeff_and_species("(?: \\(? (.*?) \\)? )" // match the leading coefficent
      69             :                                    "([A-Za-z].*)"          // match the species
      70             :                                    ,
      71         101 :                                    pcrecpp::RE_Options().set_extended(true));
      72             : 
      73             :   pcrecpp::StringPiece input(_input_reactions);
      74             : 
      75             :   pcrecpp::StringPiece single_reaction, term;
      76             :   std::string single_reaction_str;
      77             :   Real eq_coeff;
      78             : 
      79             :   // Parse reaction network to extract each individual reaction
      80         434 :   while (re_reaction.FindAndConsume(&input, &single_reaction_str, &eq_coeff))
      81             :   {
      82         333 :     _reactions.push_back(single_reaction_str);
      83         333 :     _eq_const.push_back(eq_coeff);
      84             :   }
      85             : 
      86         101 :   _num_reactions = _reactions.size();
      87             : 
      88         101 :   if (_num_reactions == 0)
      89           0 :     mooseError("No equilibrium reaction provided!");
      90             : 
      91         202 :   if (_pars.isParamValid("secondary_species"))
      92         434 :     for (unsigned int k = 0; k < _secondary_species.size(); ++k)
      93         333 :       _aux_species.insert(_secondary_species[k]);
      94             : 
      95             :   // Start parsing each reaction
      96         434 :   for (unsigned int i = 0; i < _num_reactions; ++i)
      97             :   {
      98         333 :     single_reaction = _reactions[i];
      99             : 
     100             :     // Capture all of the terms
     101             :     std::string species, coeff_str;
     102             :     Real coeff;
     103             :     int sign = 1;
     104             :     bool secondary = false;
     105             : 
     106             :     std::vector<Real> local_stos;
     107             :     std::vector<VariableName> local_species_list;
     108             : 
     109             :     // Find every single term in this reaction (species and operators)
     110        1919 :     while (re_terms.FindAndConsume(&single_reaction, &term))
     111             :     {
     112             :       // Separating the stoichiometric coefficients from species
     113        1586 :       if (re_coeff_and_species.PartialMatch(term, &coeff_str, &species))
     114             :       {
     115         933 :         if (coeff_str.length())
     116          66 :           coeff = std::stod(coeff_str);
     117             :         else
     118         867 :           coeff = 1.0;
     119             : 
     120         933 :         coeff *= sign;
     121             : 
     122         933 :         if (secondary)
     123         666 :           _eq_species.push_back(species);
     124             :         else
     125             :         {
     126         600 :           local_stos.push_back(coeff);
     127         600 :           local_species_list.push_back(species);
     128             :         }
     129             :       }
     130             :       // Finding the operators and assign value of -1.0 to "-" sign
     131         653 :       else if (term == "+" || term == "=" || term == "-")
     132             :       {
     133         653 :         if (term == "-")
     134             :         {
     135             :           sign = -1;
     136         167 :           term = "+";
     137             :         }
     138             :         else
     139             :           sign = 1;
     140             : 
     141         653 :         if (term == "=")
     142             :           secondary = true;
     143             :       }
     144             :       else
     145           0 :         mooseError("Error parsing term: ", term.as_string());
     146             :     }
     147             : 
     148         333 :     _stos.push_back(local_stos);
     149         333 :     _primary_species_involved.push_back(local_species_list);
     150         333 :   }
     151             : 
     152             :   // Start picking out primary species and coupled primary species and assigning
     153             :   // corresponding stoichiomentric coefficients
     154         320 :   for (unsigned int i = 0; i < _primary_species.size(); ++i)
     155             :   {
     156         219 :     _sto_u[i].resize(_num_reactions, 0.0);
     157         219 :     _sto_v[i].resize(_num_reactions);
     158         219 :     _coupled_v[i].resize(_num_reactions);
     159         219 :     _weights[i].resize(_num_reactions, 0.0);
     160             : 
     161         219 :     _primary_participation[i].resize(_num_reactions, false);
     162        1077 :     for (unsigned int j = 0; j < _num_reactions; ++j)
     163             :     {
     164        2460 :       for (unsigned int k = 0; k < _primary_species_involved[j].size(); ++k)
     165        1602 :         if (_primary_species_involved[j][k] == _primary_species[i])
     166             :           _primary_participation[i][j] = true;
     167             : 
     168         858 :       if (_primary_participation[i][j])
     169             :       {
     170        1804 :         for (unsigned int k = 0; k < _primary_species_involved[j].size(); ++k)
     171             :         {
     172        1204 :           if (_primary_species_involved[j][k] == _primary_species[i])
     173             :           {
     174         600 :             _sto_u[i][j] = _stos[j][k];
     175         600 :             _weights[i][j] = _stos[j][k];
     176             :           }
     177             :           else
     178             :           {
     179         604 :             _sto_v[i][j].push_back(_stos[j][k]);
     180         604 :             _coupled_v[i][j].push_back(_primary_species_involved[j][k]);
     181             :           }
     182             :         }
     183             :       }
     184             :     }
     185             :   }
     186             : 
     187             :   // Print out details of the equilibrium reactions to the console
     188         101 :   _console << "Aqueous equilibrium reactions:\n";
     189         434 :   for (unsigned int i = 0; i < _num_reactions; ++i)
     190         666 :     _console << "  Reaction " << i + 1 << ": " << _reactions[i] << ", log10(Keq) = " << _eq_const[i]
     191         333 :              << "\n";
     192         101 :   _console << std::endl;
     193         101 : }
     194             : 
     195             : void
     196         202 : AddCoupledEqSpeciesAction::act()
     197             : {
     198         202 :   if (_current_task == "add_kernel")
     199             :   {
     200             :     // Add Kernels for each primary species
     201         320 :     for (unsigned int i = 0; i < _primary_species.size(); ++i)
     202             :     {
     203        1077 :       for (unsigned int j = 0; j < _num_reactions; ++j)
     204             :       {
     205         858 :         if (_primary_participation[i][j])
     206             :         {
     207        1200 :           InputParameters params_sub = _factory.getValidParams("CoupledBEEquilibriumSub");
     208        1200 :           params_sub.set<NonlinearVariableName>("variable") = _primary_species[i];
     209         600 :           params_sub.set<Real>("weight") = _weights[i][j];
     210        1200 :           params_sub.defaultCoupledValue("log_k", _eq_const[j]);
     211         600 :           params_sub.set<Real>("sto_u") = _sto_u[i][j];
     212        1200 :           params_sub.set<std::vector<Real>>("sto_v") = _sto_v[i][j];
     213         600 :           params_sub.set<std::vector<VariableName>>("v") = _coupled_v[i][j];
     214        1800 :           _problem->addKernel("CoupledBEEquilibriumSub",
     215         600 :                               _primary_species[i] + "_" + _eq_species[j] + "_sub",
     216             :                               params_sub);
     217             : 
     218        1200 :           InputParameters params_cd = _factory.getValidParams("CoupledDiffusionReactionSub");
     219        1200 :           params_cd.set<NonlinearVariableName>("variable") = _primary_species[i];
     220         600 :           params_cd.set<Real>("weight") = _weights[i][j];
     221        1200 :           params_cd.defaultCoupledValue("log_k", _eq_const[j]);
     222         600 :           params_cd.set<Real>("sto_u") = _sto_u[i][j];
     223        1200 :           params_cd.set<std::vector<Real>>("sto_v") = _sto_v[i][j];
     224         600 :           params_cd.set<std::vector<VariableName>>("v") = _coupled_v[i][j];
     225        1800 :           _problem->addKernel("CoupledDiffusionReactionSub",
     226         600 :                               _primary_species[i] + "_" + _eq_species[j] + "_cd",
     227             :                               params_cd);
     228             : 
     229             :           // If pressure is coupled, add a CoupledConvectionReactionSub Kernel as well
     230        1200 :           if (_pars.isParamValid("pressure"))
     231             :           {
     232        1200 :             InputParameters params_conv = _factory.getValidParams("CoupledConvectionReactionSub");
     233        1200 :             params_conv.set<NonlinearVariableName>("variable") = _primary_species[i];
     234         600 :             params_conv.set<Real>("weight") = _weights[i][j];
     235        1200 :             params_conv.defaultCoupledValue("log_k", _eq_const[j]);
     236         600 :             params_conv.set<Real>("sto_u") = _sto_u[i][j];
     237        1200 :             params_conv.set<std::vector<Real>>("sto_v") = _sto_v[i][j];
     238         600 :             params_conv.set<std::vector<VariableName>>("v") = _coupled_v[i][j];
     239         600 :             params_conv.set<std::vector<VariableName>>("p") = _pressure_var;
     240         600 :             params_conv.set<RealVectorValue>("gravity") = _gravity;
     241        1800 :             _problem->addKernel("CoupledConvectionReactionSub",
     242         600 :                                 _primary_species[i] + "_" + _eq_species[j] + "_conv",
     243             :                                 params_conv);
     244         600 :           }
     245         600 :         }
     246             :       }
     247             :     }
     248             :   }
     249             : 
     250         202 :   if (_current_task == "add_aux_kernel")
     251             :   {
     252             :     // Add AqueousEquilibriumRxnAux AuxKernels for equilibrium species
     253         434 :     for (unsigned int j = 0; j < _num_reactions; ++j)
     254             :     {
     255         333 :       if (_aux_species.find(_eq_species[j]) != _aux_species.end())
     256             :       {
     257         666 :         InputParameters params_eq = _factory.getValidParams("AqueousEquilibriumRxnAux");
     258         666 :         params_eq.set<AuxVariableName>("variable") = _eq_species[j];
     259         666 :         params_eq.defaultCoupledValue("log_k", _eq_const[j]);
     260         666 :         params_eq.set<std::vector<Real>>("sto_v") = _stos[j];
     261         333 :         params_eq.set<std::vector<VariableName>>("v") = _primary_species_involved[j];
     262         666 :         _problem->addAuxKernel("AqueousEquilibriumRxnAux", "aux_" + _eq_species[j], params_eq);
     263         333 :       }
     264             :     }
     265             :   }
     266         202 : }

Generated by: LCOV version 1.14