https://mooseframework.inl.gov
INSFVMomentumDiffusion.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 
10 #include "INSFVMomentumDiffusion.h"
12 #include "NS.h"
13 #include "NavierStokesMethods.h"
14 #include "SystemBase.h"
15 #include "NonlinearSystemBase.h"
16 #include "RelationshipManager.h"
17 #include "Factory.h"
18 #include "libmesh/nonlinear_solver.h"
19 
21 
24 {
25  auto params = INSFVFluxKernel::validParams();
27  params.addRequiredParam<MooseFunctorName>(NS::mu, "The viscosity");
28  params.addClassDescription(
29  "Implements the Laplace form of the viscous stress in the Navier-Stokes equation.");
30 
31  MooseEnum coeff_interp_method("average harmonic", "harmonic");
32  params.addParam<MooseEnum>("mu_interp_method",
33  coeff_interp_method,
34  "Switch that can select face interpolation method for the viscosity.");
35  params.set<unsigned short>("ghost_layers") = 2;
36 
37  // We add the relationship manager here, this will select the right number of
38  // ghosting layers depending on the chosen interpolation method
39  params.addRelationshipManager(
40  "ElementSideNeighborLayers",
43  [](const InputParameters & obj_params, InputParameters & rm_params)
44  { FVRelationshipManagerInterface::setRMParamsDiffusion(obj_params, rm_params, 3); });
45 
46  params.addParam<bool>(
47  "complete_expansion",
48  false,
49  "Boolean parameter to use complete momentum expansion is the diffusion term.");
50  params.addParam<bool>("include_isotropic_viscous_stress",
51  false,
52  "Add the -(2/3) mu div(u) I term (requires specifying the velocity "
53  "components via 'u', 'v', 'w'). Only meaningful for "
54  "weakly-compressible formulations.");
55  params.addParam<MooseFunctorName>("u", "The velocity in the x direction.");
56  params.addParam<MooseFunctorName>("v", "The velocity in the y direction.");
57  params.addParam<MooseFunctorName>("w", "The velocity in the z direction.");
58  params.addParam<bool>(
59  "limit_interpolation", false, "Flag to limit interpolation to positive values.");
60  params.addParam<bool>("newton_solve", false, "Whether a Newton nonlinear solve is being used");
61  params.addParamNamesToGroup("newton_solve", "Advanced");
62  return params;
63 }
64 
66  : INSFVFluxKernel(params),
68  _mu(getFunctor<ADReal>(NS::mu)),
69  _mu_interp_method(
70  Moose::FV::selectInterpolationMethod(getParam<MooseEnum>("mu_interp_method"))),
71  _u_var(params.isParamValid("u") ? &getFunctor<ADReal>("u") : nullptr),
72  _v_var(params.isParamValid("v") ? &getFunctor<ADReal>("v") : nullptr),
73  _w_var(params.isParamValid("w") ? &getFunctor<ADReal>("w") : nullptr),
74  _complete_expansion(getParam<bool>("complete_expansion")),
75  _include_isotropic_viscous_stress(getParam<bool>("include_isotropic_viscous_stress")),
76  _limit_interpolation(getParam<bool>("limit_interpolation")),
77  _dim(_subproblem.mesh().dimension()),
78  _newton_solve(getParam<bool>("newton_solve"))
79 {
81  paramError("u", "The u velocity must be defined when 'complete_expansion=true'.");
82 
83  if (_complete_expansion && _dim >= 2 && !_v_var)
84  paramError("v",
85  "The v velocity must be defined when 'complete_expansion=true'"
86  "and problem dimension is larger or equal to 2.");
87 
88  if (_complete_expansion && _dim >= 3 && !_w_var)
89  paramError("w",
90  "The w velocity must be defined when 'complete_expansion=true'"
91  "and problem dimension is larger or equal to three.");
92 
94  {
96  paramError("include_isotropic_viscous_stress",
97  "Complete expansion needs to be enabled to use the isotropic viscous stress!");
98 
99  if (!_u_var)
100  paramError("include_isotropic_viscous_stress",
101  "Velocity components must be provided to use the "
102  "'include_isotropic_viscous_stress' option.");
103  if (_dim >= 2 && !_v_var)
104  paramError("include_isotropic_viscous_stress",
105  "Velocity components must be provided to use the "
106  "'include_isotropic_viscous_stress' option in dimensions >= 2.");
107  if (_dim >= 3 && !_w_var)
108  paramError("include_isotropic_viscous_stress",
109  "Velocity components must be provided to use the "
110  "'include_isotropic_viscous_stress' option in 3D.");
111  }
112 }
113 
114 ADReal
116 {
117  const Moose::StateArg state = determineState();
118  const auto dudn = gradUDotNormal(state, _correct_skewness);
119  ADReal face_mu;
120 
121  if (onBoundary(*_face_info))
122  face_mu = _mu(makeCDFace(*_face_info), state);
123  else
125  face_mu,
126  _mu(elemArg(), state),
127  _mu(neighborArg(), state),
128  *_face_info,
129  true);
130 
131  // Protecting from negative viscosity at interpolation
132  // to preserve convergence
133  if (face_mu < 0.0)
134  {
135  if (!(_limit_interpolation))
136  {
137  mooseDoOnce(mooseWarning(
138  "Negative face viscosity has been encountered. Value ",
139  raw_value(face_mu),
140  " at ",
142  " limiting it to 0!\nFurther warnings for this issue will be silenced, but the "
143  "occurrences will be recorded through the solution invalidity interface."));
144  flagInvalidSolution("Negative face dynamic viscosity has been encountered.");
145  }
146  // Keep face_mu here for sparsity pattern detection
147  face_mu = 0 * face_mu;
148  }
149 
150  if (populate_a_coeffs)
151  {
154  {
155  const auto dof_number = _face_info->elem().dof_number(_sys.number(), _var.number(), 0);
156  // A gradient is a linear combination of degrees of freedom so it's safe to straight-up index
157  // into the derivatives vector at the dof we care about
158  _ae = dudn.derivatives()[dof_number];
159  _ae *= -face_mu;
160  }
163  {
164  const auto dof_number = _face_info->neighbor().dof_number(_sys.number(), _var.number(), 0);
165  _an = dudn.derivatives()[dof_number];
166  _an *= face_mu;
167  }
168  }
169 
170  ADReal dudn_transpose = 0.0;
171  ADReal divergence_term = 0.0;
173  {
174  // Computing the gradient from coupled variables
175  // Normally, we can do this with `_var.gradient(face, state)` but we will need the transpose
176  // gradient. So, we compute all at once
177  Moose::FaceArg face;
178  if (onBoundary(*_face_info))
179  face = singleSidedFaceArg();
180  else
182 
184  if (_dim == 1)
185  {
186  const auto & grad_u = _u_var->gradient(face, state);
187  gradient = ADRealTensorValue(grad_u, ADRealVectorValue(0, 0, 0), ADRealVectorValue(0, 0, 0));
188  }
189  else if (_dim == 2)
190  {
191  const auto & grad_u = _u_var->gradient(face, state);
192  const auto & grad_v = _v_var->gradient(face, state);
193  gradient = ADRealTensorValue(grad_u, grad_v, ADRealVectorValue(0, 0, 0));
194  }
195  else // if (_dim == 3)
196  {
197  const auto & grad_u = _u_var->gradient(face, state);
198  const auto & grad_v = _v_var->gradient(face, state);
199  const auto & grad_w = _w_var->gradient(face, state);
200  gradient = ADRealTensorValue(grad_u, grad_v, grad_w);
201  }
202 
203  // Getting transpose of the gradient matrix
204  const auto gradient_transpose = gradient.transpose();
205 
206  dudn_transpose += gradient_transpose.row(_index) * _face_info->normal();
207 
209  {
211  velocity(0) = _u_var ? (*_u_var)(face, state) : ADReal(0);
212  velocity(1) = _v_var ? (*_v_var)(face, state) : ADReal(0);
213  velocity(2) = _w_var ? (*_w_var)(face, state) : ADReal(0);
214 
215  const auto coord_sys = _subproblem.getCoordSystem(_face_info->elem().subdomain_id());
216  unsigned int rz_radial_coord =
218  divergence_term =
219  NS::divergence(gradient, velocity, face.getPoint(), coord_sys, rz_radial_coord);
220  }
221  }
222 
223  ADReal residual = -face_mu * (dudn + dudn_transpose);
225  residual += (2.0 / 3.0) * face_mu * divergence_term * _face_info->normal()(_index);
226 
227  return residual;
228 }
229 
230 void
232 {
233  if (skipForBoundary(fi))
234  return;
235 
236  _face_info = &fi;
237  _normal = fi.normal();
238  _face_type = fi.faceType(std::make_pair(_var.number(), _var.sys().number()));
239 
241 
244  _rc_uo.addToA(&fi.elem(), _index, _ae * (fi.faceArea() * fi.faceCoord()));
247  _rc_uo.addToA(fi.neighborPtr(), _index, _an * (fi.faceArea() * fi.faceCoord()));
248 }
249 
250 ADReal
252 {
253  return computeStrongResidual(false);
254 }
unsigned int getAxisymmetricRadialCoord() const
ADReal _ae
The a coefficient for the element.
virtual ADReal gradUDotNormal(const Moose::StateArg &time, const bool correct_skewness) const
ADReal _an
The a coefficient for the neighbor.
const unsigned int _dim
dimension
void paramError(const std::string &param, Args... args) const
A flux kernel that momentum residual objects that add non-advection flux terms, or more specifically ...
const bool _limit_interpolation
Boolean parameter to limit interpolation.
T divergence(const TensorValue< T > &gradient, const VectorType &value, const PointType &point, const Moose::CoordinateSystemType &coord_sys, const unsigned int rz_radial_coord)
Compute the divergence of a vector given its matrix of derivatives.
Moose::ElemArg elemArg(bool correct_skewness=false) const
unsigned int number() const
const Elem & elem() const
const Moose::Functor< ADReal > *const _v_var
y-velocity
const FaceInfo * _face_info
Moose::StateArg determineState() const
const Point & faceCentroid() const
virtual ADReal computeStrongResidual(const bool populate_a_coeffs)
Routine to compute this object&#39;s strong residual (e.g.
virtual ADReal computeSegregatedContribution() override
Compute the contribution which goes into the residual of the segregated system.
const unsigned int _index
index x|y|z
MeshBase & mesh
auto raw_value(const Eigen::Map< T > &in)
Real & faceCoord()
RealVectorValue _normal
const Moose::FV::InterpMethod _mu_interp_method
The face interpolation method for the viscosity.
Real faceArea() const
DualNumber< Real, DNDerivativeType, false > ADReal
registerMooseObject("NavierStokesApp", INSFVMomentumDiffusion)
RhieChowInterpolatorBase & _rc_uo
The Rhie Chow user object that is responsible for generating face velocities for advection terms...
SystemBase & _sys
virtual bool skipForBoundary(const FaceInfo &fi) const
bool onBoundary(const FaceInfo &fi) const
const Elem * neighborPtr() const
static const std::string mu
Definition: NS.h:127
SubProblem & _subproblem
static InputParameters validParams()
const Moose::Functor< ADReal > & _mu
The dynamic viscosity.
const Elem & neighbor() const
const Point & normal() const
unsigned int number() const
const Moose::Functor< ADReal > *const _u_var
x-velocity
FaceInfo::VarFaceNeighbors _face_type
void addResidualAndJacobian(const ADReal &residual)
Process into either the system residual or Jacobian.
virtual void addToA(const libMesh::Elem *elem, unsigned int component, const ADReal &value)=0
API for momentum residual objects that have on-diagonals for velocity call.
Moose::ElemArg neighborArg(bool correct_skewness=false) const
static InputParameters validParams()
virtual const OutputTools< Real >::VariableGradient & gradient()
static InputParameters validParams()
void gatherRCData(const FaceInfo &fi) override final
Should be a non-empty implementation if the residual object is a FVFluxKernel and introduces residual...
void mooseWarning(Args &&... args) const
Moose::FaceArg singleSidedFaceArg(const FaceInfo *fi=nullptr, Moose::FV::LimiterType limiter_type=Moose::FV::LimiterType::CentralDifference, bool correct_skewness=false, const Moose::StateArg *state_limiter=nullptr) const
InterpMethod selectInterpolationMethod(const std::string &interp_method)
Moose::CoordinateSystemType getCoordSystem(SubdomainID sid) const
static const std::string velocity
Definition: NS.h:46
MooseVariableFV< Real > & _var
const Moose::Functor< ADReal > *const _w_var
z-velocity
static void setRMParamsDiffusion(const InputParameters &obj_params, InputParameters &rm_params, const unsigned short conditional_extended_layers)
Moose::FaceArg makeCDFace(const FaceInfo &fi, const bool correct_skewness=false) const
void interpolate(InterpMethod m, T &result, const T2 &value1, const T3 &value2, const FaceInfo &fi, const bool one_is_elem)
const double mu
INSFVMomentumDiffusion(const InputParameters &params)
const bool _complete_expansion
Boolean parameter to include the complete momentum expansion.
VarFaceNeighbors faceType(const std::pair< unsigned int, unsigned int > &var_sys) const
const bool _include_isotropic_viscous_stress
Whether to add the -(2/3) mu div(u) I contribution.