https://mooseframework.inl.gov
INSADTauMaterial.h
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 
10 #pragma once
11 
12 #include "InputParameters.h"
13 #include "NonlinearSystemBase.h"
14 #include "FEProblemBase.h"
15 #include "MaterialProperty.h"
16 #include "MooseArray.h"
17 #include "INSADMaterial.h"
18 #include "NavierStokesMethods.h"
19 #include "Assembly.h"
20 #include "MooseVariableFE.h"
21 #include "MooseMesh.h"
22 
23 #include "libmesh/elem.h"
24 #include "libmesh/node.h"
25 #include "libmesh/fe_type.h"
26 
27 #include <vector>
28 
29 class INSADMaterial;
30 
31 template <typename T>
32 class INSADTauMaterialTempl : public T
33 {
34 public:
36 
37  INSADTauMaterialTempl(const InputParameters & parameters);
38 
39 protected:
40  virtual void computeProperties() override;
41  virtual void computeQpProperties() override;
42 
46  void computeHMax();
47 
52 
56  void viscousTermRZ();
57 
61  bool doVelocityDerivatives() const;
62 
63  const Real _alpha;
65 
69 
72 
74 
77 
80  const FEBase * const & _scalar_lagrange_fe;
81 
83  std::vector<ADRealTensorValue> _d2u;
84  std::vector<ADRealTensorValue> _d2v;
85  std::vector<ADRealTensorValue> _d2w;
86 
88  const unsigned int _vel_number;
89 
91  const unsigned int _vel_sys_number;
92 
96 
97  using T::_ad_q_point;
98  using T::_advected_mesh_strong_residual;
99  using T::_advective_strong_residual;
100  using T::_assembly;
101  using T::_boussinesq_strong_residual;
102  using T::_coord_sys;
103  using T::_coupled_force_strong_residual;
104  using T::_current_elem;
105  using T::_disp_x_num;
106  using T::_disp_x_sys_num;
107  using T::_disp_y_num;
108  using T::_disp_y_sys_num;
109  using T::_disp_z_num;
110  using T::_disp_z_sys_num;
111  using T::_dt;
112  using T::_fe_problem;
113  using T::_grad_p;
114  using T::_grad_velocity;
115  using T::_gravity_strong_residual;
116  using T::_has_advected_mesh;
117  using T::_has_boussinesq;
118  using T::_has_coupled_force;
119  using T::_has_gravity;
120  using T::_has_transient;
121  using T::_mesh;
122  using T::_mu;
123  using T::_object_tracker;
124  using T::_q_point;
125  using T::_qp;
126  using T::_qrule;
127  using T::_relative_velocity;
128  using T::_rho;
129  using T::_rz_axial_coord;
130  using T::_rz_radial_coord;
131  using T::_td_strong_residual;
132  using T::_use_displaced_mesh;
133  using T::_velocity;
134  using T::_viscous_form;
135  using T::getVectorVar;
136 };
137 
139 
140 template <typename T>
143 {
144  InputParameters params = T::validParams();
145  params.addClassDescription(
146  "This is the material class used to compute the stabilization parameter tau.");
147  params.addParam<Real>("alpha", 1., "Multiplicative factor on the stabilization parameter tau.");
148  return params;
149 }
150 
151 template <typename T>
153  : T(parameters),
154  _alpha(this->template getParam<Real>("alpha")),
155  _tau(this->template declareADProperty<Real>("tau")),
156  _viscous_strong_residual(
157  this->template declareADProperty<RealVectorValue>("viscous_strong_residual")),
158  _momentum_strong_residual(
159  this->template declareADProperty<RealVectorValue>("momentum_strong_residual")),
160  _velocity_var(getVectorVar("velocity", 0)),
161  _scalar_lagrange_fe(
162  _assembly.getFE(FEType(_velocity_var->feType().order, LAGRANGE), _mesh.dimension())),
163  _vel_number(_velocity_var->number()),
164  _vel_sys_number(_velocity_var->sys().number())
165 {
167 }
168 
169 template <typename T>
170 bool
172 {
173  return ADReal::do_derivatives &&
174  (_vel_sys_number == _fe_problem.currentNonlinearSystem().number());
175 }
176 
177 template <typename T>
178 void
180 {
181  if (_disp_x_num == libMesh::invalid_uint || !ADReal::do_derivatives)
182  {
183  _hmax = _current_elem->hmax();
184  return;
185  }
186 
187  _hmax = 0;
188  std::array<unsigned int, 3> disps = {_disp_x_num, _disp_y_num, _disp_z_num};
189  std::array<unsigned int, 3> disp_sys_nums = {_disp_x_sys_num, _disp_y_sys_num, _disp_z_sys_num};
190 
191  for (unsigned int n_outer = 0; n_outer < _current_elem->n_vertices(); n_outer++)
192  for (unsigned int n_inner = n_outer + 1; n_inner < _current_elem->n_vertices(); n_inner++)
193  {
194  VectorValue<ADReal> diff = (_current_elem->point(n_outer) - _current_elem->point(n_inner));
195  for (const auto i : index_range(disps))
196  {
197  const auto disp_num = disps[i];
198  if (disp_num == libMesh::invalid_uint)
199  continue;
200  const auto sys_num = disp_sys_nums[i];
201 
202  // Here we insert derivatives of the difference in nodal positions with respect to the
203  // displacement degrees of freedom. From above, diff = outer_node_position -
204  // inner_node_position
205  diff(i).derivatives().insert(
206  _current_elem->node_ref(n_outer).dof_number(sys_num, disp_num, 0)) = 1.;
207  diff(i).derivatives().insert(
208  _current_elem->node_ref(n_inner).dof_number(sys_num, disp_num, 0)) = -1.;
209  }
210 
211  _hmax = std::max(_hmax, diff.norm_sq());
212  }
213 
214  _hmax = std::sqrt(_hmax);
215 }
216 
217 template <typename T>
218 void
220 {
221  computeHMax();
222  computeViscousStrongResidual();
223 
224  T::computeProperties();
225 }
226 
227 template <typename T>
228 void
230 {
231  auto resize_and_zero = [this](auto & d2vel)
232  {
233  d2vel.resize(_qrule->n_points());
234  for (auto & d2qp : d2vel)
235  d2qp = 0;
236  };
237  resize_and_zero(_d2u);
238  resize_and_zero(_d2v);
239  resize_and_zero(_d2w);
240 
241  auto get_d2 = [this](const auto i) -> std::vector<ADRealTensorValue> &
242  {
243  switch (i)
244  {
245  case 0:
246  return _d2u;
247  case 1:
248  return _d2v;
249  case 2:
250  return _d2w;
251  default:
252  mooseError("invalid value of 'i'");
253  }
254  };
255 
256  // libMesh does not yet have the capability for computing second order spatial derivatives of
257  // vector bases. Lacking that capability, we can compute the second order spatial derivatives "by
258  // hand" using the scalar field version of the vector basis, e.g. LAGRANGE instead of
259  // LAGRANGE_VEC. Adding this implementation allows us to be fully consistent with results from a
260  // scalar velocity field component implementation of Navier-Stokes
261  const auto & vel_dof_indices = _velocity_var->dofIndices();
262  for (const auto i : index_range(vel_dof_indices))
263  {
264  // This may not work if the element and spatial dimensions are different
265  mooseAssert(_current_elem->dim() == _mesh.dimension(),
266  "Below logic only applicable if element and mesh dimension are the same");
267  const auto dimensional_component = i % _mesh.dimension();
268  auto & d2vel = get_d2(dimensional_component);
269  const auto dof_index = vel_dof_indices[i];
270  ADReal dof_value = (*_velocity_var->sys().currentSolution())(dof_index);
271  if (doVelocityDerivatives())
272  dof_value.derivatives().insert(dof_index) = 1;
273  const auto scalar_i_component = i / _mesh.dimension();
274  for (const auto qp : make_range(_qrule->n_points()))
275  d2vel[qp] += dof_value * _scalar_lagrange_fe->get_d2phi()[scalar_i_component][qp];
276  }
277 
278  // Now that we have the second order spatial derivatives of velocity, we can compute the strong
279  // form of the viscous residual for use in our stabilization calculations
280  for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
281  {
282  _viscous_strong_residual[_qp](0) = -_mu[_qp] * _d2u[_qp].tr();
283  _viscous_strong_residual[_qp](1) =
284  _mesh.dimension() >= 2 ? -_mu[_qp] * _d2v[_qp].tr() : ADReal(0);
285  _viscous_strong_residual[_qp](2) =
286  _mesh.dimension() == 3 ? -_mu[_qp] * _d2w[_qp].tr() : ADReal(0);
287  if (_viscous_form == NS::ViscousForm::Traction)
288  {
289  _viscous_strong_residual[_qp] -= _mu[_qp] * _d2u[_qp].row(0);
290  if (_mesh.dimension() >= 2)
291  _viscous_strong_residual[_qp] -= _mu[_qp] * _d2v[_qp].row(1);
292  if (_mesh.dimension() == 3)
293  _viscous_strong_residual[_qp] -= _mu[_qp] * _d2w[_qp].row(2);
294  }
295  if (_coord_sys == Moose::COORD_RZ)
296  viscousTermRZ();
297  }
298 }
299 
300 template <typename T>
301 void
303 {
304  // To understand the code immediately below, visit
305  // https://en.wikipedia.org/wiki/Del_in_cylindrical_and_spherical_coordinates.
306  // The u_r / r^2 term comes from the vector Laplacian. The -du_i/dr * 1/r term comes from
307  // the scalar Laplacian. The scalar Laplacian in axisymmetric cylindrical coordinates is
308  // equivalent to the Cartesian Laplacian plus a 1/r * du_i/dr term. And of course we are
309  // applying a minus sign here because the strong form is -\nabala^2 * \vec{u}
310  //
311  // Another note: libMesh implements grad(v) as dvi/dxj or more obviously:
312  //
313  // grad(v) = (vx_x vx_y)
314  // (vy_x vy_y)
315  //
316  // so, the gradient of the velocity with respect to the radial coordinate will correspond to a
317  // *column* slice
318 
319  const auto & r = _ad_q_point[_qp](_rz_radial_coord);
320 
321  {
322  // Do the "Laplace" form. This will be present in *both* Laplace and Traction forms
323  ADRealVectorValue rz_term;
324  for (const auto i : make_range((unsigned int)2))
325  rz_term(i) = -_mu[_qp] * _grad_velocity[_qp](i, _rz_radial_coord) / r;
326  rz_term(_rz_radial_coord) += _mu[_qp] * _velocity[_qp](_rz_radial_coord) / (r * r);
327  _viscous_strong_residual[_qp] += rz_term;
328  }
329  if (_viscous_form == NS::ViscousForm::Traction)
330  {
331  ADRealVectorValue rz_term;
332  for (const auto i : make_range((unsigned int)2))
333  // This is the transpose of the above
334  rz_term(i) = -_mu[_qp] * _grad_velocity[_qp](_rz_radial_coord, i) / r;
335  // This is the same as above (since the transpose of the diagonal is the diagonal)
336  rz_term(_rz_radial_coord) += _mu[_qp] * _velocity[_qp](_rz_radial_coord) / (r * r);
337  _viscous_strong_residual[_qp] += rz_term;
338  }
339 }
340 
341 template <typename T>
342 void
344 {
345  T::computeQpProperties();
346 
347  const auto nu = _mu[_qp] / _rho[_qp];
348  const auto transient_part = _has_transient ? 4. / (_dt * _dt) : 0.;
349  _speed = NS::computeSpeed(_relative_velocity[_qp]);
350  _tau[_qp] = _alpha / std::sqrt(transient_part + (2. * _speed / _hmax) * (2. * _speed / _hmax) +
351  9. * (4. * nu / (_hmax * _hmax)) * (4. * nu / (_hmax * _hmax)));
352 
353  _momentum_strong_residual[_qp] =
354  _advective_strong_residual[_qp] + _viscous_strong_residual[_qp] + _grad_p[_qp];
355 
356  if (_has_transient)
357  _momentum_strong_residual[_qp] += _td_strong_residual[_qp];
358 
359  if (_has_gravity)
360  _momentum_strong_residual[_qp] += _gravity_strong_residual[_qp];
361 
362  if (_has_boussinesq)
363  _momentum_strong_residual[_qp] += _boussinesq_strong_residual[_qp];
364 
365  if (_has_advected_mesh)
366  _momentum_strong_residual[_qp] += _advected_mesh_strong_residual[_qp];
367 
368  if (_has_coupled_force)
369  _momentum_strong_residual[_qp] += _coupled_force_strong_residual[_qp];
370 
371  // // Future addition
372  // if (_object_tracker->hasMMS())
373  // _momentum_strong_residual[_qp] += _mms_function_strong_residual[_qp];
374 }
std::vector< ADRealTensorValue > _d2u
Containers to hold the matrix of second spatial derivatives of velocity.
LAGRANGE
void computeHMax()
Compute the maximum dimension of the current element.
const unsigned int invalid_uint
const FEBase *const & _scalar_lagrange_fe
A scalar Lagrange FE data member to compute the velocity second derivatives since they&#39;re currently n...
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
virtual void computeProperties() override
void mooseError(Args &&... args)
INSADTauMaterialTempl< INSADMaterial > INSADTauMaterial
bool doVelocityDerivatives() const
Whether to seed with respect to velocity derivatives.
static InputParameters validParams()
INSADTauMaterialTempl(const InputParameters &parameters)
DualNumber< Real, DNDerivativeType, true > ADReal
virtual void computeQpProperties() override
ADMaterialProperty< RealVectorValue > & _momentum_strong_residual
The strong residual of the momentum equation.
InputParameters validParams()
ADReal _speed
The speed of the medium.
const unsigned int _vel_number
The velocity variable number.
ADMaterialProperty< RealVectorValue > & _viscous_strong_residual
Strong residual corresponding to the momentum viscous term.
const std::vector< std::vector< OutputTensor > > & get_d2phi() const
void computeViscousStrongResidual()
Compute the viscous strong residual.
const VectorMooseVariable *const _velocity_var
The velocity variable.
ADMaterialProperty< Real > & _tau
const unsigned int _vel_sys_number
The velocity system number.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
void addClassDescription(const std::string &doc_string)
ADReal computeSpeed(const ADRealVectorValue &velocity)
Compute the speed (velocity norm) given the supplied velocity.
std::vector< ADRealTensorValue > _d2w
std::vector< ADRealTensorValue > _d2v
auto index_range(const T &sizable)
void viscousTermRZ()
Compute the strong form corresponding to RZ pieces of the viscous term.