https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
29class INSADMaterial;
30
31template <typename T>
33{
34public:
36
38
39protected:
40 virtual void computeProperties() override;
41 virtual void computeQpProperties() override;
42
47
52
57
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
140template <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
151template <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{
166 _scalar_lagrange_fe->get_d2phi();
167}
168
169template <typename T>
170bool
172{
173 return ADReal::do_derivatives &&
174 (_vel_sys_number == _fe_problem.currentNonlinearSystem().number());
175}
176
177template <typename T>
178void
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 using std::sqrt;
215 _hmax = sqrt(_hmax);
216}
217
218template <typename T>
219void
221{
222 computeHMax();
223 computeViscousStrongResidual();
224
225 T::computeProperties();
226}
227
228template <typename T>
229void
231{
232 auto resize_and_zero = [this](auto & d2vel)
233 {
234 d2vel.resize(_qrule->n_points());
235 for (auto & d2qp : d2vel)
236 d2qp = 0;
237 };
238 resize_and_zero(_d2u);
239 resize_and_zero(_d2v);
240 resize_and_zero(_d2w);
241
242 auto get_d2 = [this](const auto i) -> std::vector<ADRealTensorValue> &
243 {
244 switch (i)
245 {
246 case 0:
247 return _d2u;
248 case 1:
249 return _d2v;
250 case 2:
251 return _d2w;
252 default:
253 mooseError("invalid value of 'i'");
254 }
255 };
256
257 // libMesh does not yet have the capability for computing second order spatial derivatives of
258 // vector bases. Lacking that capability, we can compute the second order spatial derivatives "by
259 // hand" using the scalar field version of the vector basis, e.g. LAGRANGE instead of
260 // LAGRANGE_VEC. Adding this implementation allows us to be fully consistent with results from a
261 // scalar velocity field component implementation of Navier-Stokes
262 const auto & vel_dof_indices = _velocity_var->dofIndices();
263 for (const auto i : index_range(vel_dof_indices))
264 {
265 // This may not work if the element and spatial dimensions are different
266 mooseAssert(_current_elem->dim() == _mesh.dimension(),
267 "Below logic only applicable if element and mesh dimension are the same");
268 const auto dimensional_component = i % _mesh.dimension();
269 auto & d2vel = get_d2(dimensional_component);
270 const auto dof_index = vel_dof_indices[i];
271 ADReal dof_value = (*_velocity_var->sys().currentSolution())(dof_index);
272 if (doVelocityDerivatives())
273 dof_value.derivatives().insert(dof_index) = 1;
274 const auto scalar_i_component = i / _mesh.dimension();
275 for (const auto qp : make_range(_qrule->n_points()))
276 d2vel[qp] += dof_value * _scalar_lagrange_fe->get_d2phi()[scalar_i_component][qp];
277 }
278
279 // Now that we have the second order spatial derivatives of velocity, we can compute the strong
280 // form of the viscous residual for use in our stabilization calculations
281 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
282 {
283 _viscous_strong_residual[_qp](0) = -_mu[_qp] * _d2u[_qp].tr();
284 _viscous_strong_residual[_qp](1) =
285 _mesh.dimension() >= 2 ? -_mu[_qp] * _d2v[_qp].tr() : ADReal(0);
286 _viscous_strong_residual[_qp](2) =
287 _mesh.dimension() == 3 ? -_mu[_qp] * _d2w[_qp].tr() : ADReal(0);
288 if (_viscous_form == NS::ViscousForm::Traction)
289 {
290 _viscous_strong_residual[_qp] -= _mu[_qp] * _d2u[_qp].row(0);
291 if (_mesh.dimension() >= 2)
292 _viscous_strong_residual[_qp] -= _mu[_qp] * _d2v[_qp].row(1);
293 if (_mesh.dimension() == 3)
294 _viscous_strong_residual[_qp] -= _mu[_qp] * _d2w[_qp].row(2);
295 }
296 if (_coord_sys == Moose::COORD_RZ)
297 viscousTermRZ();
298 }
299}
300
301template <typename T>
302void
304{
305 // To understand the code immediately below, visit
306 // https://en.wikipedia.org/wiki/Del_in_cylindrical_and_spherical_coordinates.
307 // The u_r / r^2 term comes from the vector Laplacian. The -du_i/dr * 1/r term comes from
308 // the scalar Laplacian. The scalar Laplacian in axisymmetric cylindrical coordinates is
309 // equivalent to the Cartesian Laplacian plus a 1/r * du_i/dr term. And of course we are
310 // applying a minus sign here because the strong form is -\nabala^2 * \vec{u}
311 //
312 // Another note: libMesh implements grad(v) as dvi/dxj or more obviously:
313 //
314 // grad(v) = (vx_x vx_y)
315 // (vy_x vy_y)
316 //
317 // so, the gradient of the velocity with respect to the radial coordinate will correspond to a
318 // *column* slice
319
320 const auto & r = _ad_q_point[_qp](_rz_radial_coord);
321
322 {
323 // Do the "Laplace" form. This will be present in *both* Laplace and Traction forms
324 ADRealVectorValue rz_term;
325 for (const auto i : make_range((unsigned int)2))
326 rz_term(i) = -_mu[_qp] * _grad_velocity[_qp](i, _rz_radial_coord) / r;
327 rz_term(_rz_radial_coord) += _mu[_qp] * _velocity[_qp](_rz_radial_coord) / (r * r);
328 _viscous_strong_residual[_qp] += rz_term;
329 }
330 if (_viscous_form == NS::ViscousForm::Traction)
331 {
332 ADRealVectorValue rz_term;
333 for (const auto i : make_range((unsigned int)2))
334 // This is the transpose of the above
335 rz_term(i) = -_mu[_qp] * _grad_velocity[_qp](_rz_radial_coord, i) / r;
336 // This is the same as above (since the transpose of the diagonal is the diagonal)
337 rz_term(_rz_radial_coord) += _mu[_qp] * _velocity[_qp](_rz_radial_coord) / (r * r);
338 _viscous_strong_residual[_qp] += rz_term;
339 }
340}
341
342template <typename T>
343void
345{
346 T::computeQpProperties();
347
348 using std::sqrt;
349
350 const auto nu = _mu[_qp] / _rho[_qp];
351 const auto transient_part = _has_transient ? 4. / (_dt * _dt) : 0.;
352 _speed = NS::computeSpeed<ADReal>(_relative_velocity[_qp]);
353 _tau[_qp] = _alpha / sqrt(transient_part + (2. * _speed / _hmax) * (2. * _speed / _hmax) +
354 9. * (4. * nu / (_hmax * _hmax)) * (4. * nu / (_hmax * _hmax)));
355
356 _momentum_strong_residual[_qp] =
357 _advective_strong_residual[_qp] + _viscous_strong_residual[_qp] + _grad_p[_qp];
358
359 if (_has_transient)
360 _momentum_strong_residual[_qp] += _td_strong_residual[_qp];
361
362 if (_has_gravity)
363 _momentum_strong_residual[_qp] += _gravity_strong_residual[_qp];
364
365 if (_has_boussinesq)
366 _momentum_strong_residual[_qp] += _boussinesq_strong_residual[_qp];
367
368 if (_has_advected_mesh)
369 _momentum_strong_residual[_qp] += _advected_mesh_strong_residual[_qp];
370
371 if (_has_coupled_force)
372 _momentum_strong_residual[_qp] += _coupled_force_strong_residual[_qp];
373
374 // // Future addition
375 // if (_object_tracker->hasMMS())
376 // _momentum_strong_residual[_qp] += _mms_function_strong_residual[_qp];
377}
DualNumber< Real, DNDerivativeType, true > ADReal
const double T
INSADTauMaterialTempl< INSADMaterial > INSADTauMaterial
void mooseError(Args &&... args)
ADMaterialProperty< RealVectorValue > & _viscous_strong_residual
Strong residual corresponding to the momentum viscous term.
const FEBase *const & _scalar_lagrange_fe
A scalar Lagrange FE data member to compute the velocity second derivatives since they're currently n...
void computeViscousStrongResidual()
Compute the viscous strong residual.
virtual void computeQpProperties() override
std::vector< ADRealTensorValue > _d2u
Containers to hold the matrix of second spatial derivatives of velocity.
void viscousTermRZ()
Compute the strong form corresponding to RZ pieces of the viscous term.
const VectorMooseVariable *const _velocity_var
The velocity variable.
ADReal _speed
The speed of the medium.
static InputParameters validParams()
const unsigned int _vel_sys_number
The velocity system number.
std::vector< ADRealTensorValue > _d2v
INSADTauMaterialTempl(const InputParameters &parameters)
ADMaterialProperty< Real > & _tau
void computeHMax()
Compute the maximum dimension of the current element.
virtual void computeProperties() override
ADMaterialProperty< RealVectorValue > & _momentum_strong_residual
The strong residual of the momentum equation.
bool doVelocityDerivatives() const
Whether to seed with respect to velocity derivatives.
const unsigned int _vel_number
The velocity variable number.
std::vector< ADRealTensorValue > _d2w
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
template ADReal computeSpeed< ADReal >(const libMesh::VectorValue< ADReal > &velocity)
const unsigned int invalid_uint