14 #include "libmesh/quadrature.h" 28 params.
addParam<
bool>(
"strain_at_nearest_qp",
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");
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");
44 "multiply_by_density",
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).");
50 "fluid_component", 0,
"The index corresponding to the component for this kernel");
52 "PorousFlowDictator",
"The UserObject that holds the list of PorousFlow variable names.");
53 params.
set<
bool>(
"use_displaced_mesh") =
false;
56 "lumping to the nodes is used.");
64 _fluid_component(this->template getParam<unsigned
int>(
"fluid_component")),
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") +
"_" 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")
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
85 "dPorousFlow_porosity_nodal_dgradvar")),
86 _nearest_qp(_strain_at_nearest_qp ? &this->template getMaterialProperty<unsigned
int>(
87 "PorousFlow_nearestqp_nodal")
89 _fluid_density(_multiply_by_density
90 ? &this->template getGenericMaterialProperty<
std::vector<
Real>, is_ad>(
91 "PorousFlow_fluid_phase_density_nodal")
93 _fluid_density_old(_multiply_by_density
94 ? &this->template getMaterialPropertyOld<
std::vector<
Real>>(
95 "PorousFlow_fluid_phase_density_nodal")
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")
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(
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")),
115 : &this->template getMaterialProperty<
std::vector<
std::vector<
std::vector<
Real>>>>(
116 "dPorousFlow_mass_frac_nodal_dvar"))
121 "The Dictator proclaims that the maximum fluid component index in this simulation is ",
123 " whereas you have used ",
125 ". Remember that indexing starts at 0. The Dictator does not take such mistakes lightly.");
128 template <
bool is_ad>
134 for (
unsigned ph = 0; ph < _num_phases; ++ph)
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);
141 dens_old * _fluid_saturation_nodal_old[_i][ph] * _mass_frac_old[_i][ph][_fluid_component];
143 const Real strain = (_has_total_strain ? (*_total_strain_old)[_qp].trace() : 0.0);
145 return _test[_i][_qp] * (1.0 + strain) * (_porosity[_i] * mass - _porosity_old[_i] * mass_old) /
149 template <
bool is_ad>
153 if constexpr (!is_ad)
155 if (!_var_is_porflow_var)
157 return computeQpJac(_dictator.porousFlowVariableNum(_var.number()));
162 template <
bool is_ad>
166 if constexpr (!is_ad)
168 if (_dictator.notPorousFlowVariable(jvar))
170 return computeQpJac(_dictator.porousFlowVariableNum(jvar));
177 template <
bool is_ad>
181 if constexpr (!is_ad)
183 const unsigned nearest_qp = (_strain_at_nearest_qp ? (*_nearest_qp)[_i] : _i);
185 const Real strain = (_has_total_strain ? (*_total_strain_old)[_qp].trace() : 0.0);
188 for (
unsigned ph = 0; ph < _num_phases; ++ph)
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];
196 return _test[_i][_qp] * (1.0 + strain) * dmass / _dt;
198 for (
unsigned ph = 0; ph < _num_phases; ++ph)
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];
211 return _test[_i][_qp] * (1.0 + strain) * dmass / _dt;
Kernel = (mass_component - mass_component_old)/dt where mass_component = porosity*sum_phases(density_...
Moose::GenericType< Real, is_ad > GenericReal
registerMooseObject("PorousFlowApp", PorousFlowMassTimeDerivative)
virtual Real computeQpJacobian() override
void paramError(const std::string ¶m, Args... args) const
static InputParameters validParams()
PorousFlowMassTimeDerivativeTempl(const InputParameters ¶meters)
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 libmesh_ignore(const Args &...)
virtual Real computeQpOffDiagJacobian(unsigned int jvar) override
static InputParameters validParams()
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...
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