https://mooseframework.inl.gov
NavierStokesMethods.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 "NavierStokesMethods.h"
11 #include "MooseError.h"
12 #include "libmesh/vector_value.h"
13 #include "NS.h"
14 
15 namespace NS
16 {
17 int
18 delta(unsigned int i, unsigned int j)
19 {
20  if (i == j)
21  return 1;
22  else
23  return 0;
24 }
25 
26 int
27 computeSign(const Real & a)
28 {
29  return a > 0 ? 1 : (a < 0 ? -1 : 0);
30 }
31 
32 unsigned int
33 getIndex(const Real & p, const std::vector<Real> & bounds)
34 {
35  if (p < bounds.front() || p > bounds.back())
36  mooseError("Point exceeds bounds of domain!");
37 
38  for (unsigned int i = 1; i < bounds.size(); ++i)
39  if (p <= bounds[i])
40  return i - 1;
41 
42  return bounds.size() - 2;
43 }
44 
45 Real
47  const Real & Re, const Real & rho, const Real & mu, const Real & drho, const Real & dmu)
48 {
49  return Re * (drho / std::max(rho, 1e-6) - dmu / std::max(mu, 1e-8));
50 }
51 
52 Real
54  const Real & cp,
55  const Real & k,
56  const Real & dmu,
57  const Real & dcp,
58  const Real & dk)
59 {
60  return (k * (mu * dcp + cp * dmu) - mu * cp * dk) / std::max(k * k, 1e-8);
61 }
62 
63 template <typename T>
64 T
65 findUStar(const T & mu, const T & rho, const T & u, const Real dist)
66 {
67  // usually takes about 3-4 iterations
68  constexpr int MAX_ITERS{50};
69  constexpr Real REL_TOLERANCE{1e-6};
70 
71  // Check inputs
72  mooseAssert(mu > 0, "Need a strictly positive viscosity");
73  mooseAssert(rho > 0, "Need a strictly positive density");
74  mooseAssert(u > 0, "Need a strictly positive velocity");
75  mooseAssert(dist > 0, "Need a strictly positive wall distance");
76 
77  const T nu = mu / rho;
78 
79  // Wall-function linearized guess
80  const Real a_c = 1 / NS::von_karman_constant;
81  const T b_c = 1.0 / NS::von_karman_constant * (std::log(NS::E_turb_constant * dist / mu) + 1.0);
82  const T & c_c = u;
83 
85  T u_star = std::max(1e-20, (-b_c + std::sqrt(std::pow(b_c, 2) + 4.0 * a_c * c_c)) / (2.0 * a_c));
86 
87  // Newton-Raphson method to solve for u_star (friction velocity).
88  for (int i = 0; i < MAX_ITERS; ++i)
89  {
90  T residual =
91  u_star / NS::von_karman_constant * std::log(NS::E_turb_constant * u_star * dist / nu) - u;
92  T deriv = (1.0 + std::log(NS::E_turb_constant * u_star * dist / nu)) / NS::von_karman_constant;
93  T new_u_star = std::max(1e-20, u_star - residual / deriv);
94 
95  Real rel_err =
96  std::abs(MetaPhysicL::raw_value(new_u_star - u_star) / MetaPhysicL::raw_value(new_u_star));
97 
98  u_star = new_u_star;
99  if (rel_err < REL_TOLERANCE)
100  return u_star;
101  }
102 
103  mooseException("Could not find the wall friction velocity (mu: ",
104  mu,
105  " rho: ",
106  rho,
107  " velocity: ",
108  u,
109  " wall distance: ",
110  dist,
111  ")");
112 }
113 template Real findUStar<Real>(const Real & mu, const Real & rho, const Real & u, const Real dist);
114 template ADReal
115 findUStar<ADReal>(const ADReal & mu, const ADReal & rho, const ADReal & u, const Real dist);
116 
117 template <typename T>
118 T
119 findyPlus(const T & mu, const T & rho, const T & u, const Real dist)
120 {
121  // Fixed point iteration method to find y_plus
122  // It should take 3 or 4 iterations
123  constexpr int MAX_ITERS{10};
124  constexpr Real REL_TOLERANCE{1e-2};
125 
126  // Check inputs
127  mooseAssert(mu > 0, "Need a strictly positive viscosity");
128  mooseAssert(u > 0, "Need a strictly positive velocity");
129  mooseAssert(rho > 0, "Need a strictly positive density");
130  mooseAssert(dist > 0, "Need a strictly positive wall distance");
131 
132  Real yPlusLast = 0.0;
133  T yPlus = dist * u * rho / mu; // Assign initial value to laminar
134  const Real rev_yPlusLam = 1.0 / MetaPhysicL::raw_value(yPlus);
135  const T kappa_time_Re = NS::von_karman_constant * u * dist / (mu / rho);
136  unsigned int iters = 0;
137 
138  do
139  {
140  yPlusLast = MetaPhysicL::raw_value(yPlus);
141  // Negative y plus does not make sense
142  yPlus = std::max(NS::min_y_plus, yPlus);
143  yPlus = (kappa_time_Re + yPlus) / (1.0 + std::log(NS::E_turb_constant * yPlus));
144  } while (std::abs(rev_yPlusLam * (MetaPhysicL::raw_value(yPlus) - yPlusLast)) > REL_TOLERANCE &&
145  ++iters < MAX_ITERS);
146 
147  return std::max(NS::min_y_plus, yPlus);
148 }
149 template Real findyPlus<Real>(const Real & mu, const Real & rho, const Real & u, Real dist);
150 template ADReal
151 findyPlus<ADReal>(const ADReal & mu, const ADReal & rho, const ADReal & u, Real dist);
152 
153 template <typename T>
154 T
156 {
157  // if the velocity is zero, then the norm function call fails because AD tries to calculate the
158  // derivatives which causes a divide by zero - because d/dx(sqrt(f(x))) = 1/2/sqrt(f(x))*df/dx.
159  // So add a bit of noise (based on hitchhiker's guide to the galaxy's meaning of life number) to
160  // avoid this failure mode.
161  return isZero(velocity) ? 1e-42 : velocity.norm();
162 }
165 
166 template <typename T>
167 T
169  const Moose::Functor<T> * v,
170  const Moose::Functor<T> * w,
171  const Moose::ElemArg & elem_arg,
172  const Moose::StateArg & state)
173 {
174  const auto & grad_u = u.gradient(elem_arg, state);
175  const T Sij_xx = 2.0 * grad_u(0);
176  T Sij_xy = 0.0;
177  T Sij_xz = 0.0;
178  T Sij_yy = 0.0;
179  T Sij_yz = 0.0;
180  T Sij_zz = 0.0;
181 
182  const T grad_xx = grad_u(0);
183  T grad_xy = 0.0;
184  T grad_xz = 0.0;
185  T grad_yx = 0.0;
186  T grad_yy = 0.0;
187  T grad_yz = 0.0;
188  T grad_zx = 0.0;
189  T grad_zy = 0.0;
190  T grad_zz = 0.0;
191 
192  T trace = Sij_xx / 3.0;
193 
194  if (v) // dim >= 2
195  {
196  const auto & grad_v = (*v).gradient(elem_arg, state);
197  Sij_xy = grad_u(1) + grad_v(0);
198  Sij_yy = 2.0 * grad_v(1);
199 
200  grad_xy = grad_u(1);
201  grad_yx = grad_v(0);
202  grad_yy = grad_v(1);
203 
204  trace += Sij_yy / 3.0;
205 
206  if (w) // dim >= 3
207  {
208  const auto & grad_w = (*w).gradient(elem_arg, state);
209 
210  Sij_xz = grad_u(2) + grad_w(0);
211  Sij_yz = grad_v(2) + grad_w(1);
212  Sij_zz = 2.0 * grad_w(2);
213 
214  grad_xz = grad_u(2);
215  grad_yz = grad_v(2);
216  grad_zx = grad_w(0);
217  grad_zy = grad_w(1);
218  grad_zz = grad_w(2);
219 
220  trace += Sij_zz / 3.0;
221  }
222  }
223 
224  return (Sij_xx - trace) * grad_xx + Sij_xy * grad_xy + Sij_xz * grad_xz + Sij_xy * grad_yx +
225  (Sij_yy - trace) * grad_yy + Sij_yz * grad_yz + Sij_xz * grad_zx + Sij_yz * grad_zy +
226  (Sij_zz - trace) * grad_zz;
227 }
229  const Moose::Functor<Real> * v,
230  const Moose::Functor<Real> * w,
231  const Moose::ElemArg & elem_arg,
232  const Moose::StateArg & state);
234  const Moose::Functor<ADReal> * v,
235  const Moose::Functor<ADReal> * w,
236  const Moose::ElemArg & elem_arg,
237  const Moose::StateArg & state);
238 
240 void
241 getWallBoundedElements(const std::vector<BoundaryName> & wall_boundary_names,
242  const FEProblemBase & fe_problem,
243  const SubProblem & subproblem,
244  const std::set<SubdomainID> & block_ids,
245  std::unordered_set<const Elem *> & wall_bounded)
246 {
247 
248  wall_bounded.clear();
249  const auto wall_boundary_ids = subproblem.mesh().getBoundaryIDs(wall_boundary_names);
250 
251  for (const auto & elem : fe_problem.mesh().getMesh().active_element_ptr_range())
252  {
253  if (block_ids.find(elem->subdomain_id()) != block_ids.end())
254  for (const auto i_side : elem->side_index_range())
255  {
256  const auto & side_bnds = subproblem.mesh().getBoundaryIDs(elem, i_side);
257  for (const auto & wall_id : wall_boundary_ids)
258  {
259  for (const auto side_id : side_bnds)
260  if (side_id == wall_id)
261  wall_bounded.insert(elem);
262  }
263  }
264  }
265 }
266 
268 void
269 getWallDistance(const std::vector<BoundaryName> & wall_boundary_name,
270  const FEProblemBase & fe_problem,
271  const SubProblem & subproblem,
272  const std::set<SubdomainID> & block_ids,
273  std::map<const Elem *, std::vector<Real>> & dist_map)
274 {
275  dist_map.clear();
276 
277  for (const auto & elem : fe_problem.mesh().getMesh().active_element_ptr_range())
278  if (block_ids.find(elem->subdomain_id()) != block_ids.end())
279  for (const auto i_side : elem->side_index_range())
280  {
281  const auto & side_bnds = subproblem.mesh().getBoundaryIDs(elem, i_side);
282  for (const auto & name : wall_boundary_name)
283  {
284  const auto wall_id = subproblem.mesh().getBoundaryID(name);
285  for (const auto side_id : side_bnds)
286  if (side_id == wall_id)
287  {
288  // The list below stores the face infos with respect to their owning elements,
289  // depending on the block restriction we might encounter situations where the
290  // element outside of the block owns the face info.
291  const auto & neighbor = elem->neighbor_ptr(i_side);
292  const auto elem_has_fi = Moose::FV::elemHasFaceInfo(*elem, neighbor);
293  const auto & elem_for_fi = elem_has_fi ? elem : neighbor;
294  const auto side = elem_has_fi ? i_side : neighbor->which_neighbor_am_i(elem);
295 
296  const FaceInfo * const fi = subproblem.mesh().faceInfo(elem_for_fi, side);
297  const auto & elem_centroid =
298  elem_has_fi ? fi->elemCentroid() : fi->neighborCentroid();
299  const Real dist = std::abs((elem_centroid - fi->faceCentroid()) * fi->normal());
300  dist_map[elem].push_back(dist);
301  }
302  }
303  }
304 }
305 
307 void
308 getElementFaceArgs(const std::vector<BoundaryName> & wall_boundary_name,
309  const FEProblemBase & fe_problem,
310  const SubProblem & subproblem,
311  const std::set<SubdomainID> & block_ids,
312  std::map<const Elem *, std::vector<const FaceInfo *>> & face_info_map)
313 {
314  face_info_map.clear();
315 
316  for (const auto & elem : fe_problem.mesh().getMesh().active_element_ptr_range())
317  if (block_ids.find(elem->subdomain_id()) != block_ids.end())
318  for (const auto i_side : elem->side_index_range())
319  {
320  const auto & side_bnds = subproblem.mesh().getBoundaryIDs(elem, i_side);
321  for (const auto & name : wall_boundary_name)
322  {
323  const auto wall_id = subproblem.mesh().getBoundaryID(name);
324  for (const auto side_id : side_bnds)
325  if (side_id == wall_id)
326  {
327  // The list below stores the face infos with respect to their owning elements,
328  // depending on the block restriction we might encounter situations where the
329  // element outside of the block owns the face info.
330  const auto & neighbor = elem->neighbor_ptr(i_side);
331  const auto elem_has_fi = Moose::FV::elemHasFaceInfo(*elem, neighbor);
332  const auto & elem_for_fi = elem_has_fi ? elem : neighbor;
333  const auto side = elem_has_fi ? i_side : neighbor->which_neighbor_am_i(elem);
334 
335  const FaceInfo * const fi = subproblem.mesh().faceInfo(elem_for_fi, side);
336  face_info_map[elem].push_back(fi);
337  }
338  }
339  }
340 }
341 }
virtual MooseMesh & mesh()=0
int computeSign(const Real &a)
Sign function, returns $+1$ if $a$ is positive and $-1$ if $a$ is negative.
T computeShearStrainRateNormSquared(const Moose::Functor< T > &u, const Moose::Functor< T > *v, const Moose::Functor< T > *w, const Moose::ElemArg &elem_arg, const Moose::StateArg &state)
Utility function to compute the shear strain rate.
static constexpr Real von_karman_constant
Definition: NS.h:191
bool elemHasFaceInfo(const Elem &elem, const Elem *const neighbor)
static constexpr Real min_y_plus
Definition: NS.h:198
void mooseError(Args &&... args)
T computeSpeed(const libMesh::VectorValue< T > &velocity)
Compute the speed (velocity norm) given the supplied velocity.
Real prandtlPropertyDerivative(const Real &mu, const Real &cp, const Real &k, const Real &dmu, const Real &dcp, const Real &dk)
Computes the derivative of the Prandtl number, $Pr{ C_p}{k}$, with respect to an arbitrary variale $$...
bool isZero(const T &value, const Real tolerance=TOLERANCE *TOLERANCE *TOLERANCE)
template ADReal computeShearStrainRateNormSquared< ADReal >(const Moose::Functor< ADReal > &u, const Moose::Functor< ADReal > *v, const Moose::Functor< ADReal > *w, const Moose::ElemArg &elem_arg, const Moose::StateArg &state)
const boundary_id_type side_id
const Point & faceCentroid() const
auto raw_value(const Eigen::Map< T > &in)
int delta(unsigned int i, unsigned int j)
Delta function, which returns zero if $i j$ and unity if $i=j$.
template Real findUStar< Real >(const Real &mu, const Real &rho, const Real &u, const Real dist)
void getWallBoundedElements(const std::vector< BoundaryName > &wall_boundary_name, const FEProblemBase &fe_problem, const SubProblem &subproblem, const std::set< SubdomainID > &block_ids, std::unordered_set< const Elem *> &wall_bounded)
Map marking wall bounded elements The map passed in wall_bounded_map gets cleared and re-populated...
const Point & neighborCentroid() const
DualNumber< Real, DNDerivativeType, true > ADReal
template Real findyPlus< Real >(const Real &mu, const Real &rho, const Real &u, Real dist)
static const std::string cp
Definition: NS.h:121
const std::vector< const FaceInfo *> & faceInfo() const
const Point & elemCentroid() const
MeshBase & getMesh()
Real deriv(unsigned n, unsigned alpha, unsigned beta, Real x)
static const std::string mu
Definition: NS.h:123
const std::string name
Definition: Setup.h:20
template ADReal findUStar< ADReal >(const ADReal &mu, const ADReal &rho, const ADReal &u, const Real dist)
Real reynoldsPropertyDerivative(const Real &Re, const Real &rho, const Real &mu, const Real &drho, const Real &dmu)
Computes the derivative of the Reynolds number, $Re { Vd}{}$, with respect to an arbitrary variable $...
const Point & normal() const
unsigned int getIndex(const Real &p, const std::vector< Real > &bounds)
Determines the index $i$ in a sorted array such that the input point is within the $i$-th and $i+1$-t...
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...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string v
Definition: NS.h:84
template ADReal computeSpeed< ADReal >(const libMesh::VectorValue< ADReal > &velocity)
static constexpr Real E_turb_constant
Definition: NS.h:192
GradientType gradient(const ElemArg &elem, const StateArg &state) const
template ADReal findyPlus< ADReal >(const ADReal &mu, const ADReal &rho, const ADReal &u, Real dist)
virtual MooseMesh & mesh() override
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
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
T findyPlus(const T &mu, const T &rho, const T &u, Real dist)
Finds the non-dimensional wall distance normalized with the friction velocity Implements a fixed-poin...
template Real computeSpeed< Real >(const libMesh::VectorValue< Real > &velocity)
std::vector< BoundaryID > getBoundaryIDs(const Elem *const elem, const unsigned short int side) const
T findUStar(const T &mu, const T &rho, const T &u, Real dist)
Finds the friction velocity using standard velocity wall functions formulation.
MooseUnits pow(const MooseUnits &, int)
static const std::string k
Definition: NS.h:130
template Real computeShearStrainRateNormSquared< Real >(const Moose::Functor< Real > &u, const Moose::Functor< Real > *v, const Moose::Functor< Real > *w, const Moose::ElemArg &elem_arg, const Moose::StateArg &state)
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const