https://mooseframework.inl.gov
PorousFlowDispersiveFlux.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 
16 
17 template <bool is_ad>
20 {
22  params.addParam<unsigned int>(
23  "fluid_component", 0, "The index corresponding to the fluid component for this kernel");
24  params.addRequiredParam<UserObjectName>(
25  "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names");
26  params.addRequiredParam<std::vector<Real>>(
27  "disp_long", "Vector of longitudinal dispersion coefficients for each phase");
28  params.addRequiredParam<std::vector<Real>>(
29  "disp_trans", "Vector of transverse dispersion coefficients for each phase");
30  params.addRequiredParam<RealVectorValue>("gravity",
31  "Gravitational acceleration vector downwards (m/s^2)");
32  params.addClassDescription(
33  "Dispersive and diffusive flux of the component given by fluid_component in all phases");
34  return params;
35 }
36 
37 template <bool is_ad>
39  const InputParameters & parameters)
40  : GenericKernel<is_ad>(parameters),
41  _fluid_density_qp(this->template getGenericMaterialProperty<std::vector<Real>, is_ad>(
42  "PorousFlow_fluid_phase_density_qp")),
43  _dfluid_density_qp_dvar(
44  is_ad ? nullptr
45  : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
46  "dPorousFlow_fluid_phase_density_qp_dvar")),
47  _grad_mass_frac(
48  this->template getGenericMaterialProperty<std::vector<std::vector<RealGradient>>, is_ad>(
49  "PorousFlow_grad_mass_frac_qp")),
50  _dmass_frac_dvar(
51  is_ad ? nullptr
52  : &this->template getMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
53  "dPorousFlow_mass_frac_qp_dvar")),
54  _porosity_qp(this->template getGenericMaterialProperty<Real, is_ad>("PorousFlow_porosity_qp")),
55  _dporosity_qp_dvar(is_ad ? nullptr
56  : &this->template getMaterialProperty<std::vector<Real>>(
57  "dPorousFlow_porosity_qp_dvar")),
58  _tortuosity(this->template getGenericMaterialProperty<std::vector<Real>, is_ad>(
59  "PorousFlow_tortuosity_qp")),
60  _dtortuosity_dvar(is_ad ? nullptr
61  : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
62  "dPorousFlow_tortuosity_qp_dvar")),
63  _diffusion_coeff(this->template getMaterialProperty<std::vector<std::vector<Real>>>(
64  "PorousFlow_diffusion_coeff_qp")),
65  _ddiffusion_coeff_dvar(
66  is_ad ? nullptr
67  : &this->template getMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
68  "dPorousFlow_diffusion_coeff_qp_dvar")),
69  _dictator(this->template getUserObject<PorousFlowDictator>("PorousFlowDictator")),
70  _fluid_component(this->template getParam<unsigned int>("fluid_component")),
71  _num_phases(_dictator.numPhases()),
72  _identity_tensor(GenericRankTwoTensor<is_ad>::initIdentity),
73  _relative_permeability(this->template getGenericMaterialProperty<std::vector<Real>, is_ad>(
74  "PorousFlow_relative_permeability_qp")),
75  _drelative_permeability_dvar(
76  is_ad ? nullptr
77  : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
78  "dPorousFlow_relative_permeability_qp_dvar")),
79  _fluid_viscosity(this->template getGenericMaterialProperty<std::vector<Real>, is_ad>(
80  "PorousFlow_viscosity_qp")),
81  _dfluid_viscosity_dvar(
82  is_ad ? nullptr
83  : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
84  "dPorousFlow_viscosity_qp_dvar")),
85  _permeability(this->template getGenericMaterialProperty<RealTensorValue, is_ad>(
86  "PorousFlow_permeability_qp")),
87  _dpermeability_dvar(is_ad ? nullptr
88  : &this->template getMaterialProperty<std::vector<RealTensorValue>>(
89  "dPorousFlow_permeability_qp_dvar")),
90  _dpermeability_dgradvar(
91  is_ad ? nullptr
92  : &this->template getMaterialProperty<std::vector<std::vector<RealTensorValue>>>(
93  "dPorousFlow_permeability_qp_dgradvar")),
94  _grad_p(this->template getGenericMaterialProperty<std::vector<RealGradient>, is_ad>(
95  "PorousFlow_grad_porepressure_qp")),
96  _dgrad_p_dgrad_var(is_ad ? nullptr
97  : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
98  "dPorousFlow_grad_porepressure_qp_dgradvar")),
99  _dgrad_p_dvar(is_ad
100  ? nullptr
101  : &this->template getMaterialProperty<std::vector<std::vector<RealGradient>>>(
102  "dPorousFlow_grad_porepressure_qp_dvar")),
103  _gravity(this->template getParam<RealVectorValue>("gravity")),
104  _disp_long(this->template getParam<std::vector<Real>>("disp_long")),
105  _disp_trans(this->template getParam<std::vector<Real>>("disp_trans")),
106  _perm_derivs(_dictator.usePermDerivs())
107 {
109  this->paramError(
110  "fluid_component",
111  "The Dictator proclaims that the maximum fluid component index in this simulation is ",
112  _dictator.numComponents() - 1,
113  " whereas you have used ",
115  ". Remember that indexing starts at 0. The Dictator does not take such mistakes lightly.");
116 
117  if (_disp_long.size() != _num_phases)
118  this->paramError(
119  "disp_long",
120  "The number of longitudinal dispersion coefficients is not equal to the number of phases");
121 
122  if (_disp_trans.size() != _num_phases)
123  this->paramError("disp_trans",
124  "The number of transverse dispersion coefficients disp_trans is not equal to "
125  "the number of phases");
126 }
127 
128 template <bool is_ad>
131 {
134  GenericReal<is_ad> velocity_abs;
136  GenericRankTwoTensor<is_ad> dispersion;
137  dispersion.zero();
138  GenericReal<is_ad> diffusion;
139 
140  for (unsigned int ph = 0; ph < _num_phases; ++ph)
141  {
142  diffusion =
143  _porosity_qp[_qp] * _tortuosity[_qp][ph] * _diffusion_coeff[_qp][ph][_fluid_component];
144 
145  velocity = _permeability[_qp] * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity) *
146  _relative_permeability[_qp][ph] / _fluid_viscosity[_qp][ph];
147  velocity_abs = velocity.norm();
148 
149  if (MetaPhysicL::raw_value(velocity_abs) > 0.0)
150  {
152  diffusion += GenericReal<is_ad>(_disp_trans[ph]) * velocity_abs;
153  dispersion = GenericReal<is_ad>(_disp_long[ph] - _disp_trans[ph]) * v2 / velocity_abs;
154  }
155 
156  flux += _fluid_density_qp[_qp][ph] * (diffusion * _identity_tensor + dispersion) *
157  _grad_mass_frac[_qp][ph][_fluid_component];
158  }
159  return _grad_test[_i][_qp] * flux;
160 }
161 
162 template <bool is_ad>
163 Real
165 {
166  return computeQpJac(_var.number());
167 }
168 
169 template <bool is_ad>
170 Real
172 {
173  return computeQpJac(jvar);
174 }
175 
176 template <bool is_ad>
177 Real
179 {
180  if constexpr (!is_ad)
181  {
182  if (_dictator.notPorousFlowVariable(jvar))
183  return 0.0;
184 
185  const unsigned int pvar = _dictator.porousFlowVariableNum(jvar);
186 
188  Real velocity_abs;
189  RankTwoTensor v2;
190  RankTwoTensor dispersion;
191  dispersion.zero();
192  Real diffusion;
193  RealVectorValue dflux = 0.0;
194 
195  for (unsigned int ph = 0; ph < _num_phases; ++ph)
196  {
197  diffusion =
198  _porosity_qp[_qp] * _tortuosity[_qp][ph] * _diffusion_coeff[_qp][ph][_fluid_component];
199 
200  velocity = _permeability[_qp] * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity) *
201  _relative_permeability[_qp][ph] / _fluid_viscosity[_qp][ph];
202  velocity_abs = MetaPhysicL::raw_value(velocity).norm();
203 
204  if (velocity_abs > 0.0)
205  {
207  diffusion += _disp_trans[ph] * velocity_abs;
208  dispersion = (_disp_long[ph] - _disp_trans[ph]) * v2 / velocity_abs;
209  }
210 
211  RealVectorValue dvelocity =
212  _permeability[_qp] *
213  (_grad_phi[_j][_qp] * (*_dgrad_p_dgrad_var)[_qp][ph][pvar] -
214  _phi[_j][_qp] * (*_dfluid_density_qp_dvar)[_qp][ph][pvar] * _gravity);
215  dvelocity += _permeability[_qp] * ((*_dgrad_p_dvar)[_qp][ph][pvar] * _phi[_j][_qp]);
216 
217  if (_perm_derivs)
218  {
219  dvelocity += (*_dpermeability_dvar)[_qp][pvar] * _phi[_j][_qp] *
220  (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity);
221 
222  for (const auto i : make_range(Moose::dim))
223  dvelocity += (*_dpermeability_dgradvar)[_qp][i][pvar] * _grad_phi[_j][_qp](i) *
224  (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity);
225  }
226 
227  dvelocity =
228  dvelocity * _relative_permeability[_qp][ph] / _fluid_viscosity[_qp][ph] +
229  (_permeability[_qp] * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity)) *
230  ((*_drelative_permeability_dvar)[_qp][ph][pvar] / _fluid_viscosity[_qp][ph] -
231  _relative_permeability[_qp][ph] * (*_dfluid_viscosity_dvar)[_qp][ph][pvar] /
232  std::pow(_fluid_viscosity[_qp][ph], 2)) *
233  _phi[_j][_qp];
234 
235  Real dvelocity_abs = 0.0;
236  if (velocity_abs > 0.0)
237  dvelocity_abs = velocity * dvelocity / velocity_abs;
238 
239  Real ddiffusion = _phi[_j][_qp] * (*_dporosity_qp_dvar)[_qp][pvar] * _tortuosity[_qp][ph] *
240  _diffusion_coeff[_qp][ph][_fluid_component];
241  ddiffusion += _phi[_j][_qp] * _porosity_qp[_qp] * (*_dtortuosity_dvar)[_qp][ph][pvar] *
242  _diffusion_coeff[_qp][ph][_fluid_component];
243  ddiffusion += _phi[_j][_qp] * _porosity_qp[_qp] * _tortuosity[_qp][ph] *
244  (*_ddiffusion_coeff_dvar)[_qp][ph][_fluid_component][pvar];
245  ddiffusion += _disp_trans[ph] * dvelocity_abs;
246 
247  RankTwoTensor ddispersion;
248  ddispersion.zero();
249  if (velocity_abs > 0.0)
250  {
251  RankTwoTensor dv2a, dv2b;
252  dv2a = RankTwoTensor::outerProduct(velocity, dvelocity);
253  dv2b = RankTwoTensor::outerProduct(dvelocity, velocity);
254  ddispersion = (_disp_long[ph] - _disp_trans[ph]) * (dv2a + dv2b) / velocity_abs;
255  ddispersion -=
256  (_disp_long[ph] - _disp_trans[ph]) * v2 * dvelocity_abs / velocity_abs / velocity_abs;
257  }
258 
259  dflux += _phi[_j][_qp] * (*_dfluid_density_qp_dvar)[_qp][ph][pvar] *
260  (diffusion * _identity_tensor + dispersion) *
261  _grad_mass_frac[_qp][ph][_fluid_component];
262  dflux += _fluid_density_qp[_qp][ph] * (ddiffusion * _identity_tensor + ddispersion) *
263  _grad_mass_frac[_qp][ph][_fluid_component];
264 
265  // NOTE: Here we assume that d(grad_mass_frac)/d(var) = d(mass_frac)/d(var) * grad_phi
266  // This is true for most PorousFlow scenarios, but not for chemical reactions
267  // where mass_frac is a nonlinear function of the primary MOOSE Variables
268  dflux += _fluid_density_qp[_qp][ph] * (diffusion * _identity_tensor + dispersion) *
269  (*_dmass_frac_dvar)[_qp][ph][_fluid_component][pvar] * _grad_phi[_j][_qp];
270  }
271 
272  return _grad_test[_i][_qp] * dflux;
273  }
274  else
275  libmesh_ignore(jvar);
276  return 0.0;
277 }
278 
RankFourTensorTempl< Real > outerProduct(const RankTwoTensorTempl< Real > &b) const
Moose::GenericType< Real, is_ad > GenericReal
registerMooseObject("PorousFlowApp", PorousFlowDispersiveFlux)
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)
const std::vector< Real > _disp_long
Longitudinal dispersivity for each phase.
static InputParameters validParams()
PorousFlowDispersiveFluxTempl(const InputParameters &parameters)
unsigned int numComponents() const
The number of fluid components.
auto raw_value(const Eigen::Map< T > &in)
static InputParameters validParams()
static constexpr std::size_t dim
virtual GenericReal< is_ad > computeQpResidual() override
Real computeQpJac(unsigned int jvar) const
Derivative of the residual with respect to the PorousFlow variable with variable number jvar...
const PorousFlowDictator & _dictator
PorousFlowDictator UserObject.
void addRequiredParam(const std::string &name, const std::string &doc_string)
static RankTwoTensorTempl< Real > selfOuterProduct(const libMesh::TypeVector< Real > &)
TensorValue< Real > RealTensorValue
void libmesh_ignore(const Args &...)
Moose::GenericType< RealVectorValue, is_ad > GenericRealVectorValue
virtual Real computeQpOffDiagJacobian(unsigned int jvar) override
const unsigned int _num_phases
The number of fluid phases.
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...
virtual Real computeQpJacobian() override
IntRange< T > make_range(T beg, T end)
void addClassDescription(const std::string &doc_string)
static const std::string velocity
Definition: NS.h:46
const std::vector< Real > _disp_trans
Transverse dispersivity for each phase.
Dispersive flux of component k in fluid phase alpha.
MooseUnits pow(const MooseUnits &, int)
const unsigned int _fluid_component
Index of the fluid component that this kernel acts on.
void ErrorVector unsigned int
Moose::GenericType< RankTwoTensor, is_ad > GenericRankTwoTensor