https://mooseframework.inl.gov
PorousFlowMassTimeDerivative.C
Go to the documentation of this file.
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 
11 
12 #include "MooseVariable.h"
13 
14 #include "libmesh/quadrature.h"
15 
16 #include <limits>
17 
20 
21 template <bool is_ad>
24 {
26  params.set<MultiMooseEnum>("vector_tags") = "time";
27  params.set<MultiMooseEnum>("matrix_tags") = "system time";
28  params.addParam<bool>("strain_at_nearest_qp",
29  false,
30  "When calculating nodal porosity that depends on strain, use the strain at "
31  "the nearest quadpoint. This adds a small extra computational burden, and "
32  "is not necessary for simulations involving only linear lagrange elements. "
33  " If you set this to true, you will also want to set the same parameter to "
34  "true for related Kernels and Materials");
35  params.addParam<std::string>(
36  "base_name",
37  "For mechanically-coupled systems, this Kernel will depend on the volumetric strain. "
38  "base_name should almost always be the same base_name as given to the TensorMechanics object "
39  "that computes strain. Supplying a base_name to this Kernel but not defining an associated "
40  "TensorMechanics strain calculator means that this Kernel will not depend on volumetric "
41  "strain. That could be useful when models contain solid mechanics that is not coupled to "
42  "porous flow, for example");
43  params.addParam<bool>(
44  "multiply_by_density",
45  true,
46  "If true, then this Kernel represents the time derivative of the fluid mass. If false, then "
47  "this Kernel represents the time derivative of the fluid volume (care must then be taken "
48  "when using other PorousFlow objects, such as the PorousFlowFluidMass postprocessor).");
49  params.addParam<unsigned int>(
50  "fluid_component", 0, "The index corresponding to the component for this kernel");
51  params.addRequiredParam<UserObjectName>(
52  "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names.");
53  params.set<bool>("use_displaced_mesh") = false;
54  params.suppressParameter<bool>("use_displaced_mesh");
55  params.addClassDescription("Derivative of fluid-component mass with respect to time. Mass "
56  "lumping to the nodes is used.");
57  return params;
58 }
59 
60 template <bool is_ad>
62  const InputParameters & parameters)
63  : PorousFlowLumpedKernelBaseTempl<is_ad>(parameters),
64  _fluid_component(this->template getParam<unsigned int>("fluid_component")),
65  _dictator(this->template getUserObject<PorousFlowDictator>("PorousFlowDictator")),
66  _var_is_porflow_var(_dictator.isPorousFlowVariable(_var.number())),
67  _num_phases(_dictator.numPhases()),
68  _strain_at_nearest_qp(this->template getParam<bool>("strain_at_nearest_qp")),
69  _multiply_by_density(this->template getParam<bool>("multiply_by_density")),
70  _base_name(this->isParamValid("base_name")
71  ? this->template getParam<std::string>("base_name") + "_"
72  : ""),
73  _has_total_strain(
74  this->template hasMaterialProperty<RankTwoTensor>(_base_name + "total_strain")),
75  _total_strain_old(_has_total_strain ? &this->template getMaterialPropertyOld<RankTwoTensor>(
76  _base_name + "total_strain")
77  : nullptr),
78  _porosity(this->template getGenericMaterialProperty<Real, is_ad>("PorousFlow_porosity_nodal")),
79  _porosity_old(this->template getMaterialPropertyOld<Real>("PorousFlow_porosity_nodal")),
80  _dporosity_dvar(is_ad ? nullptr
81  : &this->template getMaterialProperty<std::vector<Real>>(
82  "dPorousFlow_porosity_nodal_dvar")),
83  _dporosity_dgradvar(is_ad ? nullptr
84  : &this->template getMaterialProperty<std::vector<RealGradient>>(
85  "dPorousFlow_porosity_nodal_dgradvar")),
86  _nearest_qp(_strain_at_nearest_qp ? &this->template getMaterialProperty<unsigned int>(
87  "PorousFlow_nearestqp_nodal")
88  : nullptr),
89  _fluid_density(_multiply_by_density
90  ? &this->template getGenericMaterialProperty<std::vector<Real>, is_ad>(
91  "PorousFlow_fluid_phase_density_nodal")
92  : nullptr),
93  _fluid_density_old(_multiply_by_density
94  ? &this->template getMaterialPropertyOld<std::vector<Real>>(
95  "PorousFlow_fluid_phase_density_nodal")
96  : nullptr),
97  _dfluid_density_dvar(_multiply_by_density && !is_ad
98  ? &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
99  "dPorousFlow_fluid_phase_density_nodal_dvar")
100  : nullptr),
101  _fluid_saturation_nodal(this->template getGenericMaterialProperty<std::vector<Real>, is_ad>(
102  "PorousFlow_saturation_nodal")),
103  _fluid_saturation_nodal_old(
104  this->template getMaterialPropertyOld<std::vector<Real>>("PorousFlow_saturation_nodal")),
105  _dfluid_saturation_nodal_dvar(
106  is_ad ? nullptr
107  : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
108  "dPorousFlow_saturation_nodal_dvar")),
109  _mass_frac(this->template getGenericMaterialProperty<std::vector<std::vector<Real>>, is_ad>(
110  "PorousFlow_mass_frac_nodal")),
111  _mass_frac_old(this->template getMaterialPropertyOld<std::vector<std::vector<Real>>>(
112  "PorousFlow_mass_frac_nodal")),
113  _dmass_frac_dvar(
114  is_ad ? nullptr
115  : &this->template getMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
116  "dPorousFlow_mass_frac_nodal_dvar"))
117 {
119  this->paramError(
120  "fluid_component",
121  "The Dictator proclaims that the maximum fluid component index in this simulation is ",
122  _dictator.numComponents() - 1,
123  " whereas you have used ",
125  ". Remember that indexing starts at 0. The Dictator does not take such mistakes lightly.");
126 }
127 
128 template <bool is_ad>
131 {
132  GenericReal<is_ad> mass = 0.0;
133  Real mass_old = 0.0;
134  for (unsigned ph = 0; ph < _num_phases; ++ph)
135  {
136  const GenericReal<is_ad> dens =
137  (_multiply_by_density ? (*_fluid_density)[_i][ph] : GenericReal<is_ad>(1.0));
138  mass += dens * _fluid_saturation_nodal[_i][ph] * _mass_frac[_i][ph][_fluid_component];
139  const Real dens_old = (_multiply_by_density ? (*_fluid_density_old)[_i][ph] : 1.0);
140  mass_old +=
141  dens_old * _fluid_saturation_nodal_old[_i][ph] * _mass_frac_old[_i][ph][_fluid_component];
142  }
143  const Real strain = (_has_total_strain ? (*_total_strain_old)[_qp].trace() : 0.0);
144 
145  return _test[_i][_qp] * (1.0 + strain) * (_porosity[_i] * mass - _porosity_old[_i] * mass_old) /
146  _dt;
147 }
148 
149 template <bool is_ad>
150 Real
152 {
153  if constexpr (!is_ad)
154  {
155  if (!_var_is_porflow_var)
156  return 0.0;
157  return computeQpJac(_dictator.porousFlowVariableNum(_var.number()));
158  }
159  return 0.0;
160 }
161 
162 template <bool is_ad>
163 Real
165 {
166  if constexpr (!is_ad)
167  {
168  if (_dictator.notPorousFlowVariable(jvar))
169  return 0.0;
170  return computeQpJac(_dictator.porousFlowVariableNum(jvar));
171  }
172  else
173  libmesh_ignore(jvar);
174  return 0.0;
175 }
176 
177 template <bool is_ad>
178 Real
180 {
181  if constexpr (!is_ad)
182  {
183  const unsigned nearest_qp = (_strain_at_nearest_qp ? (*_nearest_qp)[_i] : _i);
184 
185  const Real strain = (_has_total_strain ? (*_total_strain_old)[_qp].trace() : 0.0);
186 
187  Real dmass = 0.0;
188  for (unsigned ph = 0; ph < _num_phases; ++ph)
189  {
190  const Real dens = (_multiply_by_density ? (*_fluid_density)[_i][ph] : 1.0);
191  dmass += dens * _fluid_saturation_nodal[_i][ph] * _mass_frac[_i][ph][_fluid_component] *
192  (*_dporosity_dgradvar)[_i][pvar] * _grad_phi[_j][nearest_qp];
193  }
194 
195  if (_i != _j)
196  return _test[_i][_qp] * (1.0 + strain) * dmass / _dt;
197 
198  for (unsigned ph = 0; ph < _num_phases; ++ph)
199  {
200  if (_multiply_by_density)
201  dmass += (*_dfluid_density_dvar)[_i][ph][pvar] * _fluid_saturation_nodal[_i][ph] *
202  _mass_frac[_i][ph][_fluid_component] * _porosity[_i];
203  const Real dens = (_multiply_by_density ? (*_fluid_density)[_i][ph] : 1.0);
204  dmass += dens * (*_dfluid_saturation_nodal_dvar)[_i][ph][pvar] *
205  _mass_frac[_i][ph][_fluid_component] * _porosity[_i];
206  dmass += dens * _fluid_saturation_nodal[_i][ph] *
207  (*_dmass_frac_dvar)[_i][ph][_fluid_component][pvar] * _porosity[_i];
208  dmass += dens * _fluid_saturation_nodal[_i][ph] * _mass_frac[_i][ph][_fluid_component] *
209  (*_dporosity_dvar)[_i][pvar];
210  }
211  return _test[_i][_qp] * (1.0 + strain) * dmass / _dt;
212  }
213  else
214  libmesh_ignore(pvar);
215  return 0.0;
216 }
217 
Kernel = (mass_component - mass_component_old)/dt where mass_component = porosity*sum_phases(density_...
Moose::GenericType< Real, is_ad > GenericReal
registerMooseObject("PorousFlowApp", PorousFlowMassTimeDerivative)
void paramError(const std::string &param, Args... args) const
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
static InputParameters validParams()
PorousFlowMassTimeDerivativeTempl(const InputParameters &parameters)
T & set(const std::string &name, bool quiet_mode=false)
unsigned int numComponents() const
The number of fluid components.
Real computeQpJac(unsigned int pvar)
Derivative of residual wrt PorousFlow variable pvar (non-AD path only)
const PorousFlowDictator & _dictator
PorousFlowDictator UserObject.
virtual GenericReal< is_ad > computeQpResidual() override
void addRequiredParam(const std::string &name, const std::string &doc_string)
void suppressParameter(const std::string &name)
void libmesh_ignore(const Args &...)
virtual Real computeQpOffDiagJacobian(unsigned int jvar) override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This holds maps between the nonlinear variables used in a PorousFlow simulation and the variable numb...
void addClassDescription(const std::string &doc_string)
Base class for PorousFlow kernels that use mass-lumped (nodal) material properties.
const unsigned int _fluid_component
The fluid component index.
void ErrorVector unsigned int