Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://www.mooseframework.org
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 "LinearFVTKESourceSink.h"
11 : #include "Assembly.h"
12 : #include "SubProblem.h"
13 : #include "NavierStokesMethods.h"
14 :
15 : registerMooseObject("NavierStokesApp", LinearFVTKESourceSink);
16 :
17 : InputParameters
18 88 : LinearFVTKESourceSink::validParams()
19 : {
20 88 : InputParameters params = LinearFVElementalKernel::validParams();
21 88 : params.addClassDescription("Elemental kernel to compute the production and destruction "
22 : " terms of turbulent kinetic energy (TKE).");
23 176 : params.addRequiredParam<MooseFunctorName>("u", "The velocity in the x direction.");
24 176 : params.addParam<MooseFunctorName>("v", "The velocity in the y direction.");
25 176 : params.addParam<MooseFunctorName>("w", "The velocity in the z direction.");
26 88 : params.addRequiredParam<MooseFunctorName>(NS::TKED,
27 : "Coupled turbulent kinetic energy dissipation rate.");
28 88 : params.addRequiredParam<MooseFunctorName>(NS::density, "Fluid density");
29 88 : params.addRequiredParam<MooseFunctorName>(NS::mu, "Dynamic viscosity.");
30 88 : params.addRequiredParam<MooseFunctorName>(NS::mu_t, "Turbulent viscosity.");
31 :
32 176 : params.addParam<std::vector<BoundaryName>>(
33 : "walls", {}, "Boundaries that correspond to solid walls.");
34 176 : params.addParam<bool>(
35 : "linearized_model",
36 176 : true,
37 : "Boolean to determine if the problem should be use in a linear or nonlinear solve.");
38 176 : MooseEnum wall_treatment("eq_newton eq_incremental eq_linearized neq", "neq");
39 :
40 176 : params.addParam<MooseEnum>("wall_treatment",
41 : wall_treatment,
42 : "The method used for computing the wall functions "
43 : "'eq_newton', 'eq_incremental', 'eq_linearized', 'neq'");
44 176 : params.addParam<Real>("C_mu", 0.09, "Coupled turbulent kinetic energy closure.");
45 176 : params.addParam<Real>("C_pl", 10.0, "Production Limiter Constant Multiplier.");
46 :
47 88 : return params;
48 88 : }
49 :
50 44 : LinearFVTKESourceSink::LinearFVTKESourceSink(const InputParameters & params)
51 : : LinearFVElementalKernel(params),
52 44 : _dim(_subproblem.mesh().dimension()),
53 88 : _u_var(getFunctor<Real>("u")),
54 132 : _v_var(params.isParamValid("v") ? &(getFunctor<Real>("v")) : nullptr),
55 44 : _w_var(params.isParamValid("w") ? &(getFunctor<Real>("w")) : nullptr),
56 44 : _epsilon(getFunctor<Real>(NS::TKED)),
57 44 : _rho(getFunctor<Real>(NS::density)),
58 44 : _mu(getFunctor<Real>(NS::mu)),
59 44 : _mu_t(getFunctor<Real>(NS::mu_t)),
60 88 : _wall_boundary_names(getParam<std::vector<BoundaryName>>("walls")),
61 88 : _linearized_model(getParam<bool>("linearized_model")),
62 88 : _wall_treatment(getParam<MooseEnum>("wall_treatment").getEnum<NS::WallTreatmentEnum>()),
63 88 : _C_mu(getParam<Real>("C_mu")),
64 132 : _C_pl(getParam<Real>("C_pl"))
65 : {
66 44 : if (_dim >= 2 && !_v_var)
67 0 : paramError("v", "In two or more dimensions, the v velocity must be supplied!");
68 :
69 44 : if (_dim >= 3 && !_w_var)
70 0 : paramError("w", "In three or more dimensions, the w velocity must be supplied!");
71 :
72 : // // Strain tensor term requires velocity gradients;
73 44 : if (dynamic_cast<const MooseLinearVariableFV<Real> *>(&_u_var))
74 0 : requestVariableCellGradient(getParam<MooseFunctorName>("u"));
75 44 : if (dynamic_cast<const MooseLinearVariableFV<Real> *>(_v_var))
76 0 : requestVariableCellGradient(getParam<MooseFunctorName>("v"));
77 44 : if (dynamic_cast<const MooseLinearVariableFV<Real> *>(_w_var))
78 0 : requestVariableCellGradient(getParam<MooseFunctorName>("w"));
79 44 : }
80 :
81 : void
82 220 : LinearFVTKESourceSink::initialSetup()
83 : {
84 220 : LinearFVElementalKernel::initialSetup();
85 440 : NS::getWallBoundedElements(
86 220 : _wall_boundary_names, _fe_problem, _subproblem, blockIDs(), _wall_bounded);
87 220 : NS::getWallDistance(_wall_boundary_names, _fe_problem, _subproblem, blockIDs(), _dist);
88 220 : NS::getElementFaceArgs(_wall_boundary_names, _fe_problem, _subproblem, blockIDs(), _face_infos);
89 220 : }
90 :
91 : Real
92 548992 : LinearFVTKESourceSink::computeMatrixContribution()
93 : {
94 : /*
95 : Matrix contribution:
96 : - Computes near-wall TKE destruction
97 : - Computes bulk TKE destruction
98 : */
99 :
100 : // Useful variables
101 548992 : const auto state = determineState();
102 548992 : const auto elem_arg = makeElemArg(_current_elem_info->elem());
103 548992 : const Real rho = _rho(elem_arg, state);
104 :
105 548992 : if (_wall_bounded.find(_current_elem_info->elem()) != _wall_bounded.end())
106 : {
107 :
108 : // Useful variables
109 145052 : const Real mu = _mu(elem_arg, state);
110 145052 : const Real TKE = _var.getElemValue(*_current_elem_info, state);
111 :
112 : // Assembly variables
113 : Real production = 0.0;
114 : Real destruction = 0.0;
115 : Real tot_weight = 0.0;
116 : std::vector<Real> y_plus_vec, velocity_grad_norm_vec;
117 :
118 : // Get near-wall element velocity vector
119 145052 : RealVectorValue velocity(_u_var(elem_arg, state));
120 145052 : if (_v_var)
121 145052 : velocity(1) = (*_v_var)(elem_arg, state);
122 145052 : if (_w_var)
123 0 : velocity(2) = (*_w_var)(elem_arg, state);
124 :
125 : // Get faceInfo and distance vector for between all walls and elements
126 145052 : const auto & face_info_vec = libmesh_map_find(_face_infos, _current_elem_info->elem());
127 145052 : const auto & distance_vec = libmesh_map_find(_dist, _current_elem_info->elem());
128 : mooseAssert(distance_vec.size(), "Should have found a distance vector");
129 : mooseAssert(distance_vec.size() == face_info_vec.size(),
130 : "Should be as many distance vectors as face info vectors");
131 :
132 : // Populate y+, near wall velocity gradient, and update weights
133 291164 : for (unsigned int i = 0; i < distance_vec.size(); i++)
134 : {
135 146112 : const auto parallel_speed = NS::computeSpeed<Real>(
136 146112 : velocity - velocity * face_info_vec[i]->normal() * face_info_vec[i]->normal());
137 146112 : const auto distance = distance_vec[i];
138 :
139 : Real y_plus;
140 146112 : if (_wall_treatment == NS::WallTreatmentEnum::NEQ) // Non-equilibrium --> Non-iterative
141 50000 : y_plus = distance * std::sqrt(std::sqrt(_C_mu) * TKE) * rho / mu;
142 : else // Equilibrium --> Iterative
143 96112 : y_plus = NS::findyPlus<Real>(mu, rho, std::max(parallel_speed, 1e-10), distance);
144 :
145 146112 : y_plus_vec.push_back(y_plus);
146 146112 : const Real velocity_grad_norm = parallel_speed / distance;
147 146112 : velocity_grad_norm_vec.push_back(velocity_grad_norm);
148 146112 : tot_weight += 1.0;
149 : }
150 :
151 : // Compute near-wall production and destruction
152 291164 : for (unsigned int i = 0; i < y_plus_vec.size(); i++)
153 : {
154 146112 : const auto y_plus = y_plus_vec[i];
155 :
156 146112 : const auto fi = face_info_vec[i];
157 146112 : const bool defined_on_elem_side = _var.hasFaceSide(*fi, true);
158 146112 : const Elem * const loc_elem = defined_on_elem_side ? &fi->elem() : fi->neighborPtr();
159 146112 : const Moose::FaceArg facearg = {
160 146112 : fi, Moose::FV::LimiterType::CentralDifference, false, false, loc_elem, nullptr};
161 :
162 146112 : const Real wall_mut = _mu_t(facearg, state);
163 146112 : const Real wall_mu = _mu(facearg, state);
164 146112 : const auto tau_w = (wall_mut + wall_mu) * velocity_grad_norm_vec[i];
165 146112 : const auto destruction_visc = 2.0 * wall_mu / Utility::pow<2>(distance_vec[i]) / tot_weight;
166 146112 : const auto destruction_log = std::pow(_C_mu, 0.75) * rho * std::pow(TKE, 0.5) /
167 146112 : (NS::von_karman_constant * distance_vec[i]) / tot_weight;
168 :
169 146112 : if (y_plus < 11.25)
170 32459 : destruction += destruction_visc;
171 : else
172 : {
173 113653 : destruction += destruction_log;
174 113653 : production += tau_w * std::pow(_C_mu, 0.25) / std::sqrt(TKE) /
175 113653 : (NS::von_karman_constant * distance_vec[i]) / tot_weight;
176 : }
177 : }
178 :
179 : // Assign terms to matrix to solve implicitly (they get multiplied by TKE)
180 145052 : return (destruction - production) * _current_elem_volume;
181 145052 : }
182 : else
183 : {
184 : // Compute destruction
185 : const auto destruction =
186 403940 : rho * _epsilon(elem_arg, state) / _var.getElemValue(*_current_elem_info, state);
187 :
188 : // Assign to matrix to solve implicitly
189 403940 : return destruction * _current_elem_volume;
190 : }
191 : }
192 :
193 : Real
194 548992 : LinearFVTKESourceSink::computeRightHandSideContribution()
195 : {
196 :
197 : // Useful variables
198 548992 : const auto state = determineState();
199 548992 : const auto elem_arg = makeElemArg(_current_elem_info->elem());
200 :
201 548992 : if (_wall_bounded.find(_current_elem_info->elem()) != _wall_bounded.end()) // Wall bounded
202 : return 0.0; // Do nothing
203 : else // Not wall bounded
204 : {
205 : // Compute TKE production
206 : const auto symmetric_strain_tensor_sq_norm =
207 403940 : NS::computeShearStrainRateNormSquared<Real>(_u_var, _v_var, _w_var, elem_arg, state);
208 :
209 403940 : auto production = _mu_t(elem_arg, state) * symmetric_strain_tensor_sq_norm;
210 :
211 : // k-Production limiter (needed for flows with stagnation zones)
212 403940 : const Real production_limit = _C_pl * _rho(elem_arg, state) * _epsilon(elem_arg, state);
213 :
214 : // Apply production limiter
215 403940 : production = std::min(production, production_limit);
216 :
217 : // Assign production to RHS
218 403940 : return production * _current_elem_volume;
219 : }
220 : }
|