LCOV - code coverage report
Current view: top level - src/kernels - PorousFlowMassTimeDerivative.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #31405 (292dce) with base fef103 Lines: 85 89 95.5 %
Date: 2025-09-04 07:55:56 Functions: 6 6 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 "PorousFlowMassTimeDerivative.h"
      11             : 
      12             : #include "MooseVariable.h"
      13             : 
      14             : #include "libmesh/quadrature.h"
      15             : 
      16             : #include <limits>
      17             : 
      18             : registerMooseObject("PorousFlowApp", PorousFlowMassTimeDerivative);
      19             : 
      20             : InputParameters
      21       13736 : PorousFlowMassTimeDerivative::validParams()
      22             : {
      23       13736 :   InputParameters params = TimeKernel::validParams();
      24       27472 :   params.addParam<bool>("strain_at_nearest_qp",
      25       27472 :                         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       27472 :   params.addParam<std::string>(
      32             :       "base_name",
      33             :       "For mechanically-coupled systems, this Kernel will depend on the volumetric strain.  "
      34             :       "base_name should almost always be the same base_name as given to the TensorMechanics object "
      35             :       "that computes strain.  Supplying a base_name to this Kernel but not defining an associated "
      36             :       "TensorMechanics strain calculator means that this Kernel will not depend on volumetric "
      37             :       "strain.  That could be useful when models contain solid mechanics that is not coupled to "
      38             :       "porous flow, for example");
      39       27472 :   params.addParam<bool>(
      40             :       "multiply_by_density",
      41       27472 :       true,
      42             :       "If true, then this Kernel represents the time derivative of the fluid mass.  If false, then "
      43             :       "this Kernel represents the time derivative of the fluid volume (care must then be taken "
      44             :       "when using other PorousFlow objects, such as the PorousFlowFluidMass postprocessor).");
      45       27472 :   params.addParam<unsigned int>(
      46       27472 :       "fluid_component", 0, "The index corresponding to the component for this kernel");
      47       27472 :   params.addRequiredParam<UserObjectName>(
      48             :       "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names.");
      49       13736 :   params.set<bool>("use_displaced_mesh") = false;
      50       13736 :   params.suppressParameter<bool>("use_displaced_mesh");
      51       13736 :   params.addClassDescription("Derivative of fluid-component mass with respect to time.  Mass "
      52             :                              "lumping to the nodes is used.");
      53       13736 :   return params;
      54           0 : }
      55             : 
      56        7586 : PorousFlowMassTimeDerivative::PorousFlowMassTimeDerivative(const InputParameters & parameters)
      57             :   : TimeKernel(parameters),
      58        7586 :     _fluid_component(getParam<unsigned int>("fluid_component")),
      59        7586 :     _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
      60       15172 :     _var_is_porflow_var(_dictator.isPorousFlowVariable(_var.number())),
      61        7586 :     _num_phases(_dictator.numPhases()),
      62       15172 :     _strain_at_nearest_qp(getParam<bool>("strain_at_nearest_qp")),
      63       15172 :     _multiply_by_density(getParam<bool>("multiply_by_density")),
      64       15172 :     _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
      65        7586 :     _has_total_strain(hasMaterialProperty<RankTwoTensor>(_base_name + "total_strain")),
      66       15172 :     _total_strain_old(_has_total_strain
      67        8259 :                           ? &getMaterialPropertyOld<RankTwoTensor>(_base_name + "total_strain")
      68             :                           : nullptr),
      69       15172 :     _porosity(getMaterialProperty<Real>("PorousFlow_porosity_nodal")),
      70       15172 :     _porosity_old(getMaterialPropertyOld<Real>("PorousFlow_porosity_nodal")),
      71       15172 :     _dporosity_dvar(getMaterialProperty<std::vector<Real>>("dPorousFlow_porosity_nodal_dvar")),
      72        7586 :     _dporosity_dgradvar(
      73        7586 :         getMaterialProperty<std::vector<RealGradient>>("dPorousFlow_porosity_nodal_dgradvar")),
      74       15172 :     _nearest_qp(_strain_at_nearest_qp
      75        7641 :                     ? &getMaterialProperty<unsigned int>("PorousFlow_nearestqp_nodal")
      76             :                     : nullptr),
      77       14985 :     _fluid_density(_multiply_by_density ? &getMaterialProperty<std::vector<Real>>(
      78             :                                               "PorousFlow_fluid_phase_density_nodal")
      79             :                                         : nullptr),
      80       14985 :     _fluid_density_old(_multiply_by_density ? &getMaterialPropertyOld<std::vector<Real>>(
      81             :                                                   "PorousFlow_fluid_phase_density_nodal")
      82             :                                             : nullptr),
      83       15172 :     _dfluid_density_dvar(_multiply_by_density
      84       14985 :                              ? &getMaterialProperty<std::vector<std::vector<Real>>>(
      85             :                                    "dPorousFlow_fluid_phase_density_nodal_dvar")
      86             :                              : nullptr),
      87       15172 :     _fluid_saturation_nodal(getMaterialProperty<std::vector<Real>>("PorousFlow_saturation_nodal")),
      88        7586 :     _fluid_saturation_nodal_old(
      89        7586 :         getMaterialPropertyOld<std::vector<Real>>("PorousFlow_saturation_nodal")),
      90        7586 :     _dfluid_saturation_nodal_dvar(
      91        7586 :         getMaterialProperty<std::vector<std::vector<Real>>>("dPorousFlow_saturation_nodal_dvar")),
      92       15172 :     _mass_frac(getMaterialProperty<std::vector<std::vector<Real>>>("PorousFlow_mass_frac_nodal")),
      93        7586 :     _mass_frac_old(
      94        7586 :         getMaterialPropertyOld<std::vector<std::vector<Real>>>("PorousFlow_mass_frac_nodal")),
      95       15172 :     _dmass_frac_dvar(getMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
      96        7586 :         "dPorousFlow_mass_frac_nodal_dvar"))
      97             : {
      98        7586 :   if (_fluid_component >= _dictator.numComponents())
      99           0 :     paramError(
     100             :         "fluid_component",
     101             :         "The Dictator proclaims that the maximum fluid component index in this simulation is ",
     102           0 :         _dictator.numComponents() - 1,
     103             :         " whereas you have used ",
     104           0 :         _fluid_component,
     105             :         ". Remember that indexing starts at 0. The Dictator does not take such mistakes lightly.");
     106        7586 : }
     107             : 
     108             : Real
     109   133015892 : PorousFlowMassTimeDerivative::computeQpResidual()
     110             : {
     111             :   Real mass = 0.0;
     112             :   Real mass_old = 0.0;
     113   274723224 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
     114             :   {
     115   141707332 :     const Real dens = (_multiply_by_density ? (*_fluid_density)[_i][ph] : 1.0);
     116   141707332 :     mass += dens * _fluid_saturation_nodal[_i][ph] * _mass_frac[_i][ph][_fluid_component];
     117   141707332 :     const Real dens_old = (_multiply_by_density ? (*_fluid_density_old)[_i][ph] : 1.0);
     118   141707332 :     mass_old +=
     119   141707332 :         dens_old * _fluid_saturation_nodal_old[_i][ph] * _mass_frac_old[_i][ph][_fluid_component];
     120             :   }
     121   133015892 :   const Real strain = (_has_total_strain ? (*_total_strain_old)[_qp].trace() : 0.0);
     122             : 
     123   133015892 :   return _test[_i][_qp] * (1.0 + strain) * (_porosity[_i] * mass - _porosity_old[_i] * mass_old) /
     124   133015892 :          _dt;
     125             : }
     126             : 
     127             : Real
     128   600316880 : PorousFlowMassTimeDerivative::computeQpJacobian()
     129             : {
     130             :   // If the variable is not a PorousFlow variable (very unusual), the diag Jacobian terms are 0
     131   600316880 :   if (!_var_is_porflow_var)
     132             :     return 0.0;
     133   600316272 :   return computeQpJac(_dictator.porousFlowVariableNum(_var.number()));
     134             : }
     135             : 
     136             : Real
     137   417909560 : PorousFlowMassTimeDerivative::computeQpOffDiagJacobian(unsigned int jvar)
     138             : {
     139             :   // If the variable is not a PorousFlow variable, the OffDiag Jacobian terms are 0
     140   417909560 :   if (_dictator.notPorousFlowVariable(jvar))
     141             :     return 0.0;
     142   417908344 :   return computeQpJac(_dictator.porousFlowVariableNum(jvar));
     143             : }
     144             : 
     145             : Real
     146  1018224616 : PorousFlowMassTimeDerivative::computeQpJac(unsigned int pvar)
     147             : {
     148  1018224616 :   const unsigned nearest_qp = (_strain_at_nearest_qp ? (*_nearest_qp)[_i] : _i);
     149             : 
     150  1018224616 :   const Real strain = (_has_total_strain ? (*_total_strain_old)[_qp].trace() : 0.0);
     151             : 
     152             :   // porosity is dependent on variables that are lumped to the nodes,
     153             :   // but it can depend on the gradient
     154             :   // of variables, which are NOT lumped to the nodes, hence:
     155             :   Real dmass = 0.0;
     156  2080545720 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
     157             :   {
     158  1062321104 :     const Real dens = (_multiply_by_density ? (*_fluid_density)[_i][ph] : 1.0);
     159  1062321104 :     dmass += dens * _fluid_saturation_nodal[_i][ph] * _mass_frac[_i][ph][_fluid_component] *
     160  1062321104 :              _dporosity_dgradvar[_i][pvar] * _grad_phi[_j][nearest_qp];
     161             :   }
     162             : 
     163  1018224616 :   if (_i != _j)
     164   876945332 :     return _test[_i][_qp] * (1.0 + strain) * dmass / _dt;
     165             : 
     166             :   // As the fluid mass is lumped to the nodes, only non-zero terms are for _i==_j
     167   295187436 :   for (unsigned ph = 0; ph < _num_phases; ++ph)
     168             :   {
     169   153908152 :     if (_multiply_by_density)
     170   153859112 :       dmass += (*_dfluid_density_dvar)[_i][ph][pvar] * _fluid_saturation_nodal[_i][ph] *
     171   153859112 :                _mass_frac[_i][ph][_fluid_component] * _porosity[_i];
     172   153908152 :     const Real dens = (_multiply_by_density ? (*_fluid_density)[_i][ph] : 1.0);
     173   153908152 :     dmass += dens * _dfluid_saturation_nodal_dvar[_i][ph][pvar] *
     174   153908152 :              _mass_frac[_i][ph][_fluid_component] * _porosity[_i];
     175   153908152 :     dmass += dens * _fluid_saturation_nodal[_i][ph] *
     176   153908152 :              _dmass_frac_dvar[_i][ph][_fluid_component][pvar] * _porosity[_i];
     177   153908152 :     dmass += dens * _fluid_saturation_nodal[_i][ph] * _mass_frac[_i][ph][_fluid_component] *
     178   153908152 :              _dporosity_dvar[_i][pvar];
     179             :   }
     180   141279284 :   return _test[_i][_qp] * (1.0 + strain) * dmass / _dt;
     181             : }

Generated by: LCOV version 1.14