VertexCFD  0.0-dev
VertexCFD_Closure_IncompressibleSSTEddyViscosity_impl.hpp
1 #ifndef VERTEXCFD_CLOSURE_INCOMPRESSIBLESSTEDDYVISCOSITY_IMPL_HPP
2 #define VERTEXCFD_CLOSURE_INCOMPRESSIBLESSTEDDYVISCOSITY_IMPL_HPP
3 
4 #include "utils/VertexCFD_Utils_SmoothMath.hpp"
5 #include "utils/VertexCFD_Utils_VectorField.hpp"
6 
7 #include <Panzer_HierarchicParallelism.hpp>
8 
9 namespace VertexCFD
10 {
11 namespace ClosureModel
12 {
13 //---------------------------------------------------------------------------//
14 template<class EvalType, class Traits, int NumSpaceDim>
15 IncompressibleSSTEddyViscosity<EvalType, Traits, NumSpaceDim>::
16  IncompressibleSSTEddyViscosity(const panzer::IntegrationRule& ir,
17  const Teuchos::ParameterList& user_params,
18  bool on_wall_boundary)
19  : _turb_kinetic_energy("turb_kinetic_energy", ir.dl_scalar)
20  , _turb_specific_dissipation_rate("turb_specific_dissipation_rate",
21  ir.dl_scalar)
22  , _grad_turb_kinetic_energy("GRAD_turb_kinetic_energy", ir.dl_vector)
23  , _grad_turb_specific_dissipation_rate(
24  "GRAD_turb_specific_dissipation_rate", ir.dl_vector)
25  , _distance("distance", ir.dl_scalar)
26  , _rho("density", ir.dl_scalar)
27  , _nu("kinematic_viscosity", ir.dl_scalar)
28  , _a_1(0.31)
29  , _beta_star(0.09)
30  , _sigma_w2(0.856)
31  , _on_wall_boundary(on_wall_boundary)
32  , _nu_t("turbulent_eddy_viscosity", ir.dl_scalar)
33  , _sst_blending_function("sst_blending_function", ir.dl_scalar)
34 {
35  // Check for user-defined coefficients or parameters
36  if (user_params.isSublist("Turbulence Parameters"))
37  {
38  const Teuchos::ParameterList turb_list
39  = user_params.sublist("Turbulence Parameters");
40 
41  if (turb_list.isSublist("SST K-Omega Parameters"))
42  {
43  const Teuchos::ParameterList sst_list
44  = turb_list.sublist("SST K-Omega Parameters");
45 
46  if (sst_list.isType<double>("beta_star"))
47  {
48  _beta_star = sst_list.get<double>("beta_star");
49  }
50 
51  if (sst_list.isType<double>("a_1"))
52  {
53  _a_1 = sst_list.get<double>("a_1");
54  }
55 
56  if (turb_list.isType<double>("sigma_w2"))
57  {
58  _sigma_w2 = turb_list.get<double>("sigma_w2");
59  }
60  }
61  }
62  // Add dependent fields
63  this->addDependentField(_turb_kinetic_energy);
64  this->addDependentField(_turb_specific_dissipation_rate);
65  this->addDependentField(_grad_turb_kinetic_energy);
66  this->addDependentField(_grad_turb_specific_dissipation_rate);
67  if (!_on_wall_boundary)
68  {
69  this->addDependentField(_distance);
70  }
71  this->addDependentField(_rho);
72  this->addDependentField(_nu);
73 
74  Utils::addDependentVectorField(
75  *this, ir.dl_vector, _grad_velocity, "GRAD_velocity_");
76 
77  // Add evaluated fields
78  this->addEvaluatedField(_sst_blending_function);
79  this->addEvaluatedField(_nu_t);
80 
81  // Closure model name
82  this->setName("Incompressible SST Turbulent Eddy Viscosity "
83  + std::to_string(num_space_dim) + "D");
84 }
85 
86 //---------------------------------------------------------------------------//
87 template<class EvalType, class Traits, int NumSpaceDim>
88 void IncompressibleSSTEddyViscosity<EvalType, Traits, NumSpaceDim>::evaluateFields(
89  typename Traits::EvalData workset)
90 {
91  // Allocate space for thread-local temporaries
92  size_t bytes;
93  if constexpr (Sacado::IsADType<scalar_type>::value)
94  {
95  const int fad_size = Kokkos::dimension_scalar(_nu_t.get_view());
96  bytes = scratch_view::shmem_size(_nu_t.extent(1), NUM_TMPS, fad_size);
97  }
98  else
99  {
100  bytes = scratch_view::shmem_size(_nu_t.extent(1), NUM_TMPS);
101  }
102  auto policy = panzer::HP::inst().teamPolicy<scalar_type, PHX::Device>(
103  workset.num_cells);
104  policy.set_scratch_size(0, Kokkos::PerTeam(bytes));
105  Kokkos::parallel_for(this->getName(), policy, *this);
106 }
107 
108 //---------------------------------------------------------------------------//
109 template<class EvalType, class Traits, int NumSpaceDim>
110 KOKKOS_INLINE_FUNCTION void
111 IncompressibleSSTEddyViscosity<EvalType, Traits, NumSpaceDim>::operator()(
112  const Kokkos::TeamPolicy<PHX::exec_space>::member_type& team) const
113 {
114  using Kokkos::pow;
115  using Kokkos::sqrt;
116  using Kokkos::tanh;
117 
118  const int cell = team.league_rank();
119  const int num_point = _nu_t.extent(1);
120  const double max_tol = 1.0e-10;
121 
122  scratch_view tmp_field;
123  if constexpr (Sacado::IsADType<scalar_type>::value)
124  {
125  const int fad_size = Kokkos::dimension_scalar(_nu_t.get_view());
126  tmp_field
127  = scratch_view(team.team_shmem(), num_point, NUM_TMPS, fad_size);
128  }
129  else
130  {
131  tmp_field = scratch_view(team.team_shmem(), num_point, NUM_TMPS);
132  }
133 
134  Kokkos::parallel_for(
135  Kokkos::TeamThreadRange(team, 0, num_point), [&](const int point) {
136  auto&& vort_mag_x_F2 = _nu_t(cell, point);
137  vort_mag_x_F2 = 0.0;
138  for (int i = 0; i < num_space_dim; ++i)
139  {
140  for (int j = i + 1; j < num_space_dim; ++j)
141  {
142  vort_mag_x_F2
143  += pow(_grad_velocity[i](cell, point, j)
144  - _grad_velocity[j](cell, point, i),
145  2.0);
146  }
147  }
148  // The SmoothMath::max on the vorticity magnitude was not needed
149  // with Trilinos 13, but with Trilinos 16 it will produce nans
150  // without the protection
151  vort_mag_x_F2 = sqrt(SmoothMath::max(vort_mag_x_F2, max_tol, 0.0));
152 
153  // This was also not needed with Trilinos 13, but is needed in
154  // Trilinos 16 to survive negative tke values that crop up early in
155  // the calculation for the 2d channel case
156  auto&& tke = tmp_field(point, TKE);
157  tke = SmoothMath::max(
158  _turb_kinetic_energy(cell, point), max_tol, 0.0);
159  auto&& omega = tmp_field(point, OMEGA);
160  omega = SmoothMath::max(
161  _turb_specific_dissipation_rate(cell, point), max_tol, 0.0);
162 
163  _sst_blending_function(cell, point) = 1.0;
164 
165  if (!_on_wall_boundary)
166  {
167  if (_distance(cell, point) > max_tol)
168  {
169  // Compute the positive part of the cross diffusion term
170  // (dkdxj_domegadxj)
171  auto&& C = _sst_blending_function(cell, point);
172  C = 0.0;
173  for (int j = 0; j < num_space_dim; ++j)
174  {
175  C += _grad_turb_kinetic_energy(cell, point, j)
176  * _grad_turb_specific_dissipation_rate(
177  cell, point, j);
178  }
179  // The 1.0e-20 limiter in the CD_kw calculation below is a
180  // model parameter that is modified in the 2003 revision of
181  // the model.
182  C = SmoothMath::max(
183  2.0 * _rho(cell, point) * _sigma_w2 * C / omega,
184  1.0e-20,
185  0.0);
186 
187  // The original reference and the NASA write-up don't use
188  // these temporaries, but it should help us avoid
189  // recalculation. The meanings/uses of the terms are given
190  // below (according to Menter (1994).
191 
192  // arg1 = min( max( A, B ), C )
193  // arg2 = max( 2A, B )
194 
195  // A is the turbulent length scale divided by the wall
196  // distance. It goes to zero at the wall, is constant in
197  // the boundary layer log region, and goes to zero at the
198  // edge of the boundary layer.
199  auto&& A = tmp_field(point, LOG_REGION);
200  A = sqrt(tke)
201  / (_beta_star * omega * _distance(cell, point));
202 
203  // B ensures that F_1 (the blending function) is equal to 1
204  // in the sublayer. omega goes like 1/d^2 near the wall and
205  // like 1/d in the log region so the B term is constant
206  // near the wall and goes to zero in the log region.
207  auto&& B = tmp_field(point, NEAR_WALL);
208  B = 500.0 * _nu(cell, point)
209  / (omega * pow(_distance(cell, point), 2));
210 
211  // C is an additional safeguard against a
212  // freestream-dependent solution. According to Menter
213  // (1994) it ensures that arg1 goes to zero near the
214  // boundary layer edge.
215  C = 4.0 * _rho(cell, point) * _sigma_w2 * tke
216  / (C * pow(_distance(cell, point), 2));
217 
218  // Compute F_1, arg1 is the min(max) expression in the pow
219  // call
220  _sst_blending_function(cell, point) = tanh(pow(
221  SmoothMath::min(SmoothMath::max(A, B, 0.0), C, 0.0), 4));
222 
223  // Compute F_2 and multiply it with the vorticity
224  // magnitude, arg2 is the max expression in the pow call
225  vort_mag_x_F2
226  *= tanh(pow(SmoothMath::max(2.0 * A, B, 0.0), 2));
227  }
228  }
229 
230  // All of the terms are now protected against negative and zero
231  // values, only one max needed
232  _nu_t(cell, point)
233  = _a_1 * tke
234  / SmoothMath::max(_a_1 * omega, vort_mag_x_F2, max_tol);
235  });
236 }
237 
238 //---------------------------------------------------------------------------//
239 
240 } // end namespace ClosureModel
241 } // end namespace VertexCFD
242 
243 #endif // end
244  // VERTEXCFD_CLOSURE_INCOMPRESSIBLESSTEDDYVISCOSITY_IMPL_HPP
VertexCFD
Definition: tstMethodManufacturedSolutionBC.cpp:23