https://mooseframework.inl.gov
INSFVTKESourceSink.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 "INSFVTKESourceSink.h"
11 #include "NonlinearSystemBase.h"
12 #include "NavierStokesMethods.h"
13 #include "libmesh/nonlinear_solver.h"
14 
15 registerMooseObject("NavierStokesApp", INSFVTKESourceSink);
16 
19 {
21  params.addClassDescription("Elemental kernel to compute the production and destruction "
22  " terms of turbulent kinetic energy (TKE).");
23  params.addRequiredParam<MooseFunctorName>("u", "The velocity in the x direction.");
24  params.addParam<MooseFunctorName>("v", "The velocity in the y direction.");
25  params.addParam<MooseFunctorName>("w", "The velocity in the z direction.");
26  params.addRequiredParam<MooseFunctorName>(NS::TKED,
27  "Coupled turbulent kinetic energy dissipation rate.");
28  params.addRequiredParam<MooseFunctorName>(NS::density, "fluid density");
29  params.addRequiredParam<MooseFunctorName>(NS::mu, "Dynamic viscosity.");
30  params.addRequiredParam<MooseFunctorName>(NS::mu_t, "Turbulent viscosity.");
31  params.addParam<std::vector<BoundaryName>>(
32  "walls", {}, "Boundaries that correspond to solid walls.");
33  params.addParam<bool>(
34  "linearized_model",
35  true,
36  "Boolean to determine if the problem should be use in a linear or nonlinear solve.");
37  MooseEnum wall_treatment("eq_newton eq_incremental eq_linearized neq", "neq");
38  params.addParam<MooseEnum>("wall_treatment",
39  wall_treatment,
40  "The method used for computing the wall functions "
41  "'eq_newton', 'eq_incremental', 'eq_linearized', 'neq'");
42  params.addParam<Real>("C_mu", 0.09, "Coupled turbulent kinetic energy closure.");
43  params.addParam<Real>("C_pl", 10.0, "Production Limiter Constant Multiplier.");
44  params.set<unsigned short>("ghost_layers") = 2;
45  params.addParam<bool>("newton_solve", false, "Whether a Newton nonlinear solve is being used");
46  params.addParamNamesToGroup("newton_solve", "Advanced");
47 
48  return params;
49 }
50 
52  : FVElementalKernel(params),
53  _dim(_subproblem.mesh().dimension()),
54  _u_var(getFunctor<ADReal>("u")),
55  _v_var(params.isParamValid("v") ? &(getFunctor<ADReal>("v")) : nullptr),
56  _w_var(params.isParamValid("w") ? &(getFunctor<ADReal>("w")) : nullptr),
57  _epsilon(getFunctor<ADReal>(NS::TKED)),
58  _rho(getFunctor<ADReal>(NS::density)),
59  _mu(getFunctor<ADReal>(NS::mu)),
60  _mu_t(getFunctor<ADReal>(NS::mu_t)),
61  _wall_boundary_names(getParam<std::vector<BoundaryName>>("walls")),
62  _linearized_model(getParam<bool>("linearized_model")),
63  _wall_treatment(getParam<MooseEnum>("wall_treatment").getEnum<NS::WallTreatmentEnum>()),
64  _C_mu(getParam<Real>("C_mu")),
65  _C_pl(getParam<Real>("C_pl")),
66  _newton_solve(getParam<bool>("newton_solve"))
67 {
68  if (_dim >= 2 && !_v_var)
69  paramError("v", "In two or more dimensions, the v velocity must be supplied!");
70 
71  if (_dim >= 3 && !_w_var)
72  paramError("w", "In three or more dimensions, the w velocity must be supplied!");
73 }
74 
75 void
77 {
82 }
83 
84 ADReal
86 {
87  ADReal residual = 0.0;
88  ADReal production = 0.0;
89  ADReal destruction = 0.0;
90 
91  const auto state = determineState();
92  const auto elem_arg = makeElemArg(_current_elem);
93  const auto old_state =
95  const auto rho = _rho(elem_arg, state);
96  const auto mu = _mu(elem_arg, state);
97  // To prevent negative values & preserve sparsity pattern
98  auto TKE = _newton_solve
99  ? std::max(_var(elem_arg, old_state), ADReal(0) * _var(elem_arg, old_state))
100  : _var(elem_arg, old_state);
101  // Prevent computation of sqrt(0) with undefined automatic derivatives
102  // This is not needed for segregated solves, as TKE has minimum bound in the solver
103  if (_newton_solve)
104  TKE = std::max(TKE, 1e-10);
105 
106  if (_wall_bounded.find(_current_elem) != _wall_bounded.end())
107  {
108  std::vector<ADReal> y_plus_vec, velocity_grad_norm_vec;
109 
110  Real tot_weight = 0.0;
111 
112  ADRealVectorValue velocity(_u_var(elem_arg, state));
113  if (_v_var)
114  velocity(1) = (*_v_var)(elem_arg, state);
115  if (_w_var)
116  velocity(2) = (*_w_var)(elem_arg, state);
117 
118  const auto & face_info_vec = libmesh_map_find(_face_infos, _current_elem);
119  const auto & distance_vec = libmesh_map_find(_dist, _current_elem);
120 
121  for (unsigned int i = 0; i < distance_vec.size(); i++)
122  {
123  const auto parallel_speed = NS::computeSpeed(
124  velocity - velocity * face_info_vec[i]->normal() * face_info_vec[i]->normal());
125  const auto distance = distance_vec[i];
126 
127  ADReal y_plus;
128  if (_wall_treatment == NS::WallTreatmentEnum::NEQ) // Non-equilibrium / Non-iterative
129  y_plus = distance * std::sqrt(std::sqrt(_C_mu) * TKE) * rho / mu;
130  else // Equilibrium / Iterative
131  y_plus = NS::findyPlus(mu, rho, std::max(parallel_speed, 1e-10), distance);
132 
133  y_plus_vec.push_back(y_plus);
134 
135  const ADReal velocity_grad_norm = parallel_speed / distance;
136 
138  // More complete expansion for velocity gradient. Leave commented for now.
139  // Will be useful later when doing two-phase or compressible flow
140  // ADReal velocity_grad_norm_sq =
141  // Utility::pow<2>(_u_var->gradient(elem_arg, state) *
142  // _normal[_current_elem][i]);
143  // if (_dim >= 2)
144  // velocity_grad_norm_sq +=
145  // Utility::pow<2>(_v_var->gradient(elem_arg, state) *
146  // _normal[_current_elem][i]);
147  // if (_dim >= 3)
148  // velocity_grad_norm_sq +=
149  // Utility::pow<2>(_w_var->gradient(elem_arg, state) *
150  // _normal[_current_elem][i]);
151  // ADReal velocity_grad_norm = std::sqrt(velocity_grad_norm_sq);
152 
153  velocity_grad_norm_vec.push_back(velocity_grad_norm);
154 
155  tot_weight += 1.0;
156  }
157 
158  for (unsigned int i = 0; i < y_plus_vec.size(); i++)
159  {
160  const auto y_plus = y_plus_vec[i];
161 
162  const auto fi = face_info_vec[i];
163  const bool defined_on_elem_side = _var.hasFaceSide(*fi, true);
164  const Elem * const loc_elem = defined_on_elem_side ? &fi->elem() : fi->neighborPtr();
165  const Moose::FaceArg facearg = {
166  fi, Moose::FV::LimiterType::CentralDifference, false, false, loc_elem, nullptr};
167  const ADReal wall_mut = _mu_t(facearg, state);
168  const ADReal wall_mu = _mu(facearg, state);
169 
170  const auto destruction_visc = 2.0 * wall_mu / Utility::pow<2>(distance_vec[i]) / tot_weight;
171  const auto destruction_log = std::pow(_C_mu, 0.75) * rho * std::pow(TKE, 0.5) /
172  (NS::von_karman_constant * distance_vec[i]) / tot_weight;
173  const auto tau_w = (wall_mut + wall_mu) * velocity_grad_norm_vec[i];
174 
175  // Additional 0-value terms to make sure new derivative entries are not added during the solve
176  if (y_plus < 11.25)
177  {
178  destruction += destruction_visc;
179  if (_newton_solve)
180  destruction += 0 * destruction_log + 0 * tau_w;
181  }
182  else
183  {
184  destruction += destruction_log;
185  if (_newton_solve)
186  destruction += 0 * destruction_visc;
187  production += tau_w * std::pow(_C_mu, 0.25) / std::sqrt(TKE) /
188  (NS::von_karman_constant * distance_vec[i]) / tot_weight;
189  }
190  }
191 
192  residual = (destruction - production) * _var(elem_arg, state);
193  // Additional 0-value term to make sure new derivative entries are not added during the solve
194  if (_newton_solve)
195  residual += 0 * _epsilon(elem_arg, old_state);
196  }
197  else
198  {
199  const auto & grad_u = _u_var.gradient(elem_arg, state);
200  const auto Sij_xx = 2.0 * grad_u(0);
201  ADReal Sij_xy = 0.0;
202  ADReal Sij_xz = 0.0;
203  ADReal Sij_yy = 0.0;
204  ADReal Sij_yz = 0.0;
205  ADReal Sij_zz = 0.0;
206 
207  const auto grad_xx = grad_u(0);
208  ADReal grad_xy = 0.0;
209  ADReal grad_xz = 0.0;
210  ADReal grad_yx = 0.0;
211  ADReal grad_yy = 0.0;
212  ADReal grad_yz = 0.0;
213  ADReal grad_zx = 0.0;
214  ADReal grad_zy = 0.0;
215  ADReal grad_zz = 0.0;
216 
217  auto trace = Sij_xx / 3.0;
218 
219  if (_dim >= 2)
220  {
221  const auto & grad_v = (*_v_var).gradient(elem_arg, state);
222  Sij_xy = grad_u(1) + grad_v(0);
223  Sij_yy = 2.0 * grad_v(1);
224 
225  grad_xy = grad_u(1);
226  grad_yx = grad_v(0);
227  grad_yy = grad_v(1);
228 
229  trace += Sij_yy / 3.0;
230 
231  if (_dim >= 3)
232  {
233  const auto & grad_w = (*_w_var).gradient(elem_arg, state);
234 
235  Sij_xz = grad_u(2) + grad_w(0);
236  Sij_yz = grad_v(2) + grad_w(1);
237  Sij_zz = 2.0 * grad_w(2);
238 
239  grad_xz = grad_u(2);
240  grad_yz = grad_v(2);
241  grad_zx = grad_w(0);
242  grad_zy = grad_w(1);
243  grad_zz = grad_w(2);
244 
245  trace += Sij_zz / 3.0;
246  }
247  }
248 
249  const auto symmetric_strain_tensor_sq_norm =
250  (Sij_xx - trace) * grad_xx + Sij_xy * grad_xy + Sij_xz * grad_xz + Sij_xy * grad_yx +
251  (Sij_yy - trace) * grad_yy + Sij_yz * grad_yz + Sij_xz * grad_zx + Sij_yz * grad_zy +
252  (Sij_zz - trace) * grad_zz;
253 
254  production = _mu_t(elem_arg, state) * symmetric_strain_tensor_sq_norm;
255 
256  const auto tke_old_raw = raw_value(TKE);
257  const auto epsilon_old = _epsilon(elem_arg, old_state);
258 
259  if (MooseUtils::absoluteFuzzyEqual(tke_old_raw, 0))
260  destruction = rho * epsilon_old;
261  else
262  destruction = rho * _var(elem_arg, state) / tke_old_raw * raw_value(epsilon_old);
263 
264  // k-Production limiter (needed for flows with stagnation zones)
265  const ADReal production_limit =
266  _C_pl * rho * (_newton_solve ? std::max(epsilon_old, ADReal(0)) : epsilon_old);
267 
268  // Apply production limiter
269  production = std::min(production, production_limit);
270 
271  residual = destruction - production;
272 
273  // Additional 0-value terms to make sure new derivative entries are not added during the solve
274  if (_newton_solve)
275  residual += 0 * _epsilon(elem_arg, state);
276  }
277 
278  return residual;
279 }
const bool _newton_solve
For Newton solves we want to add extra zero-valued terms regardless of y-plus to avoid sparsity patte...
static constexpr Real von_karman_constant
Definition: NS.h:191
const bool _linearized_model
Linearized model?
static const std::string mu_t
Definition: NS.h:125
const Moose::Functor< ADReal > & _mu_t
Turbulent dynamic viscosity.
const Moose::Functor< ADReal > * _w_var
z-velocity
const Real _C_mu
C_mu constant.
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const std::vector< BoundaryName > & _wall_boundary_names
Wall boundaries.
ADReal computeQpResidual() override
std::map< const Elem *, bool > _wall_bounded
void getWallBoundedElements(const std::vector< BoundaryName > &wall_boundary_name, const FEProblemBase &fe_problem, const SubProblem &subproblem, const std::set< SubdomainID > &block_ids, std::map< const Elem *, bool > &wall_bounded_map)
Map marking wall bounded elements The map passed in wall_bounded_map gets cleared and re-populated...
Moose::StateArg determineState() const
T & set(const std::string &name, bool quiet_mode=false)
MeshBase & mesh
static const std::string density
Definition: NS.h:33
auto raw_value(const Eigen::Map< T > &in)
static const std::string TKE
Definition: NS.h:176
WallTreatmentEnum
Wall treatment options.
Definition: NS.h:182
const Moose::Functor< ADReal > & _u_var
x-velocity
virtual const std::set< SubdomainID > & blockIDs() const
const Moose::Functor< ADReal > & _mu
Dynamic viscosity.
const Moose::Functor< ADReal > & _rho
Density.
DualNumber< Real, DNDerivativeType, true > ADReal
std::map< const Elem *, std::vector< Real > > _dist
Real distance(const Point &p)
void addRequiredParam(const std::string &name, const std::string &doc_string)
Moose::ElemArg makeElemArg(const Elem *elem, bool correct_skewnewss=false) const
const Elem *const & _current_elem
static const std::string mu
Definition: NS.h:123
SubProblem & _subproblem
NS::WallTreatmentEnum _wall_treatment
Method used for wall treatment.
static InputParameters validParams()
ADReal findyPlus(const ADReal &mu, const ADReal &rho, const ADReal &u, Real dist)
Finds the non-dimensional wall distance normalized with the friction velocity Implements a fixed-poin...
FEProblemBase & _fe_problem
const Moose::Functor< ADReal > * _v_var
y-velocity
static InputParameters validParams()
void paramError(const std::string &param, Args... args) const
void getWallDistance(const std::vector< BoundaryName > &wall_boundary_name, const FEProblemBase &fe_problem, const SubProblem &subproblem, const std::set< SubdomainID > &block_ids, std::map< const Elem *, std::vector< Real >> &dist_map)
Map storing wall ditance for near-wall marked elements The map passed in dist_map gets cleared and re...
const unsigned int _dim
The dimension of the domain.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string TKED
Definition: NS.h:177
registerMooseObject("NavierStokesApp", INSFVTKESourceSink)
void addClassDescription(const std::string &doc_string)
void getElementFaceArgs(const std::vector< BoundaryName > &wall_boundary_name, const FEProblemBase &fe_problem, const SubProblem &subproblem, const std::set< SubdomainID > &block_ids, std::map< const Elem *, std::vector< const FaceInfo *>> &face_info_map)
Map storing face arguments to wall bounded faces The map passed in face_info_map gets cleared and re-...
static const std::string velocity
Definition: NS.h:45
Computes source the sink terms for the turbulent kinetic energy.
virtual void initialSetup() override
ADReal computeSpeed(const ADRealVectorValue &velocity)
Compute the speed (velocity norm) given the supplied velocity.
const Moose::Functor< ADReal > & _epsilon
epsilon - dissipation rate of TKE
std::map< const Elem *, std::vector< const FaceInfo * > > _face_infos
MooseUnits pow(const MooseUnits &, int)
MooseVariableFV< Real > & _var
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
INSFVTKESourceSink(const InputParameters &parameters)
virtual bool hasFaceSide(const FaceInfo &fi, const bool fi_elem_side) const override