LCOV - code coverage report
Current view: top level - src/kernels - PorousFlowMassRadioactiveDecay.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #31405 (292dce) with base fef103 Lines: 59 66 89.4 %
Date: 2025-09-04 07:55:56 Functions: 5 6 83.3 %
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 "PorousFlowMassRadioactiveDecay.h"
      11             : 
      12             : #include "MooseVariable.h"
      13             : 
      14             : #include "libmesh/quadrature.h"
      15             : 
      16             : #include <limits>
      17             : 
      18             : registerMooseObject("PorousFlowApp", PorousFlowMassRadioactiveDecay);
      19             : 
      20             : InputParameters
      21          41 : PorousFlowMassRadioactiveDecay::validParams()
      22             : {
      23          41 :   InputParameters params = TimeKernel::validParams();
      24          82 :   params.addParam<bool>("strain_at_nearest_qp",
      25          82 :                         false,
      26             :                         "When calculating nodal porosity that depends on strain, use the strain at "
      27             :                         "the nearest quadpoint.  This adds a small extra computational burden, and "
      28             :                         "is not necessary for simulations involving only linear lagrange elements. "
      29             :                         " If you set this to true, you will also want to set the same parameter to "
      30             :                         "true for related Kernels and Materials");
      31          82 :   params.addParam<unsigned int>(
      32          82 :       "fluid_component", 0, "The index corresponding to the fluid component for this kernel");
      33          82 :   params.addRequiredParam<Real>("decay_rate",
      34             :                                 "The decay rate (units 1/time) for the fluid component");
      35          82 :   params.addRequiredParam<UserObjectName>(
      36             :       "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names.");
      37          41 :   params.addClassDescription("Radioactive decay of a fluid component");
      38          41 :   return params;
      39           0 : }
      40             : 
      41          22 : PorousFlowMassRadioactiveDecay::PorousFlowMassRadioactiveDecay(const InputParameters & parameters)
      42             :   : TimeKernel(parameters),
      43          22 :     _decay_rate(getParam<Real>("decay_rate")),
      44          44 :     _fluid_component(getParam<unsigned int>("fluid_component")),
      45          22 :     _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
      46          22 :     _var_is_porflow_var(_dictator.isPorousFlowVariable(_var.number())),
      47          22 :     _num_phases(_dictator.numPhases()),
      48          44 :     _strain_at_nearest_qp(getParam<bool>("strain_at_nearest_qp")),
      49          44 :     _porosity(getMaterialProperty<Real>("PorousFlow_porosity_nodal")),
      50          44 :     _dporosity_dvar(getMaterialProperty<std::vector<Real>>("dPorousFlow_porosity_nodal_dvar")),
      51          22 :     _dporosity_dgradvar(
      52          22 :         getMaterialProperty<std::vector<RealGradient>>("dPorousFlow_porosity_nodal_dgradvar")),
      53          44 :     _nearest_qp(_strain_at_nearest_qp
      54          22 :                     ? &getMaterialProperty<unsigned int>("PorousFlow_nearestqp_nodal")
      55             :                     : nullptr),
      56          44 :     _fluid_density(getMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_nodal")),
      57          44 :     _dfluid_density_dvar(getMaterialProperty<std::vector<std::vector<Real>>>(
      58             :         "dPorousFlow_fluid_phase_density_nodal_dvar")),
      59          44 :     _fluid_saturation_nodal(getMaterialProperty<std::vector<Real>>("PorousFlow_saturation_nodal")),
      60          22 :     _dfluid_saturation_nodal_dvar(
      61          22 :         getMaterialProperty<std::vector<std::vector<Real>>>("dPorousFlow_saturation_nodal_dvar")),
      62          44 :     _mass_frac(getMaterialProperty<std::vector<std::vector<Real>>>("PorousFlow_mass_frac_nodal")),
      63          44 :     _dmass_frac_dvar(getMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
      64          22 :         "dPorousFlow_mass_frac_nodal_dvar"))
      65             : {
      66          22 :   if (_fluid_component >= _dictator.numComponents())
      67           0 :     paramError(
      68             :         "fluid_component",
      69             :         "The Dictator proclaims that the maximum fluid component index in this simulation is ",
      70           0 :         _dictator.numComponents() - 1,
      71             :         " whereas you have used ",
      72           0 :         _fluid_component,
      73             :         ". Remember that indexing starts at 0. The Dictator does not take such mistakes lightly.");
      74          22 : }
      75             : 
      76             : Real
      77         720 : PorousFlowMassRadioactiveDecay::computeQpResidual()
      78             : {
      79             :   Real mass = 0.0;
      80        1440 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
      81         720 :     mass += _fluid_density[_i][ph] * _fluid_saturation_nodal[_i][ph] *
      82         720 :             _mass_frac[_i][ph][_fluid_component];
      83             : 
      84         720 :   return _test[_i][_qp] * _decay_rate * _porosity[_i] * mass;
      85             : }
      86             : 
      87             : Real
      88        1200 : PorousFlowMassRadioactiveDecay::computeQpJacobian()
      89             : {
      90             :   // If the variable is not a PorousFlow variable (very unusual), the diag Jacobian terms are 0
      91        1200 :   if (!_var_is_porflow_var)
      92             :     return 0.0;
      93        1200 :   return computeQpJac(_dictator.porousFlowVariableNum(_var.number()));
      94             : }
      95             : 
      96             : Real
      97           0 : PorousFlowMassRadioactiveDecay::computeQpOffDiagJacobian(unsigned int jvar)
      98             : {
      99             :   // If the variable is not a PorousFlow variable, the OffDiag Jacobian terms are 0
     100           0 :   if (_dictator.notPorousFlowVariable(jvar))
     101             :     return 0.0;
     102           0 :   return computeQpJac(_dictator.porousFlowVariableNum(jvar));
     103             : }
     104             : 
     105             : Real
     106        1200 : PorousFlowMassRadioactiveDecay::computeQpJac(unsigned int pvar)
     107             : {
     108        1200 :   const unsigned nearest_qp = (_strain_at_nearest_qp ? (*_nearest_qp)[_i] : _i);
     109             : 
     110             :   // porosity is dependent on variables that are lumped to the nodes,
     111             :   // but it can depend on the gradient
     112             :   // of variables, which are NOT lumped to the nodes, hence:
     113             :   Real dmass = 0.0;
     114        2400 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
     115        1200 :     dmass += _fluid_density[_i][ph] * _fluid_saturation_nodal[_i][ph] *
     116        1200 :              _mass_frac[_i][ph][_fluid_component] * _dporosity_dgradvar[_i][pvar] *
     117        1200 :              _grad_phi[_j][nearest_qp];
     118             : 
     119        1200 :   if (_i != _j)
     120         600 :     return _test[_i][_qp] * _decay_rate * dmass;
     121             : 
     122             :   // As the fluid mass is lumped to the nodes, only non-zero terms are for _i==_j
     123        1200 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
     124             :   {
     125         600 :     dmass += _dfluid_density_dvar[_i][ph][pvar] * _fluid_saturation_nodal[_i][ph] *
     126         600 :              _mass_frac[_i][ph][_fluid_component] * _porosity[_i];
     127         600 :     dmass += _fluid_density[_i][ph] * _dfluid_saturation_nodal_dvar[_i][ph][pvar] *
     128         600 :              _mass_frac[_i][ph][_fluid_component] * _porosity[_i];
     129         600 :     dmass += _fluid_density[_i][ph] * _fluid_saturation_nodal[_i][ph] *
     130         600 :              _dmass_frac_dvar[_i][ph][_fluid_component][pvar] * _porosity[_i];
     131         600 :     dmass += _fluid_density[_i][ph] * _fluid_saturation_nodal[_i][ph] *
     132         600 :              _mass_frac[_i][ph][_fluid_component] * _dporosity_dvar[_i][pvar];
     133             :   }
     134         600 :   return _test[_i][_qp] * _decay_rate * dmass;
     135             : }

Generated by: LCOV version 1.14