GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/freeflow/rans/twoeq/kepsilon/problem.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 157 169 92.9%
Functions: 59 121 48.8%
Branches: 82 294 27.9%

Line Branch Exec Source
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 //
4 // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7 /*!
8 * \file
9 * \ingroup KEpsilonModel
10 * \brief K-epsilon turbulence problem base class.
11 */
12 #ifndef DUMUX_KEPSILON_PROBLEM_HH
13 #define DUMUX_KEPSILON_PROBLEM_HH
14
15 #include <numeric>
16
17 #include <dumux/common/properties.hh>
18 #include <dumux/common/staggeredfvproblem.hh>
19 #include <dumux/discretization/localview.hh>
20 #include <dumux/discretization/staggered/elementsolution.hh>
21 #include <dumux/discretization/method.hh>
22 #include <dumux/freeflow/rans/problem.hh>
23 #include <dumux/freeflow/turbulencemodel.hh>
24
25 #include "model.hh"
26
27 namespace Dumux {
28
29 /*!
30 * \ingroup KEpsilonModel
31 * \brief K-epsilon turbulence problem base class.
32 *
33 * This implements some base functionality for k-epsilon models.
34 */
35 template<class TypeTag>
36 class RANSProblemImpl<TypeTag, TurbulenceModel::kepsilon> : public RANSProblemBase<TypeTag>
37 {
38 using ParentType = RANSProblemBase<TypeTag>;
39 using Implementation = GetPropType<TypeTag, Properties::Problem>;
40 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
41
42 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
43 using GridView = typename GridGeometry::GridView;
44 using Element = typename GridView::template Codim<0>::Entity;
45
46 using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
47 using GridFaceVariables = typename GridVariables::GridFaceVariables;
48 using ElementFaceVariables = typename GridFaceVariables::LocalView;
49 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
50 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
51
52 using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
53 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
54 using GlobalPosition = typename SubControlVolumeFace::GlobalPosition;
55
56 using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>;
57 using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
58 using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>;
59 using FacePrimaryVariables = GetPropType<TypeTag, Properties::FacePrimaryVariables>;
60 using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
61 using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
62 using Indices = typename ModelTraits::Indices;
63
64 static constexpr bool enableEnergyBalance = ModelTraits::enableEnergyBalance();
65 static constexpr bool isCompositional = ModelTraits::numFluidComponents() > 1;
66
67 // account for the offset of the cell center privars within the PrimaryVariables container
68 static constexpr auto cellCenterOffset = ModelTraits::numEq() - CellCenterPrimaryVariables::dimension;
69 static_assert(cellCenterOffset == ModelTraits::dim(), "cellCenterOffset must equal dim for staggered NavierStokes");
70
71 public:
72
73 //! The constructor sets the gravity, if desired by the user.
74 8 RANSProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry, const std::string& paramGroup = "")
75
2/6
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
48 : ParentType(gridGeometry, paramGroup)
76 8 { }
77
78 /*!
79 * \brief Correct size of the static (solution independent) wall variables
80 */
81 8 void updateStaticWallProperties()
82 {
83
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (!ParentType::isFlatWallBounded())
84 {
85 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, k-epsilon models should only be used for "
86 << " wall bounded flows with flat channel geometries. "
87 << "\n If your geometry is a flat channel, please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
88 }
89
90 8 ParentType::updateStaticWallProperties();
91 // update size and initial values of the global vectors
92 32 matchingPointIdx_.resize(this->gridGeometry().elementMapper().size(), 0);
93 32 storedDissipation_.resize(this->gridGeometry().elementMapper().size(), 0.0);
94 32 storedTurbulentKineticEnergy_.resize(this->gridGeometry().elementMapper().size(), 0.0);
95 32 storedDynamicEddyViscosity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
96 32 zeroEqDynamicEddyViscosity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
97 8 }
98
99 /*!
100 * \brief Update the dynamic (solution dependent) relations to the walls
101 *
102 * \param curSol The solution vector.
103 */
104 template<class SolutionVector>
105 287 void updateDynamicWallProperties(const SolutionVector& curSol)
106 {
107 287 ParentType::updateDynamicWallProperties(curSol);
108
109 // update the stored eddy viscosities
110
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
574 auto fvGeometry = localView(this->gridGeometry());
111
1/9
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
130093 for (const auto& element : elements(this->gridGeometry().gridView()))
112 {
113 193848 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
114
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
64616 fvGeometry.bindElement(element);
115
4/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 64616 times.
✓ Branch 3 taken 64616 times.
✓ Branch 4 taken 64616 times.
✓ Branch 5 taken 64616 times.
258464 for (auto&& scv : scvs(fvGeometry))
116 {
117 64616 const int dofIdx = scv.dofIndex();
118 129232 const auto& cellCenterPriVars = curSol[GridGeometry::cellCenterIdx()][dofIdx];
119 64616 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(cellCenterPriVars);
120
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
129232 auto elemSol = elementSolution<typename GridGeometry::LocalView>(std::move(priVars));
121 // NOTE: first update the turbulence quantities
122 129232 storedDissipation_[elementIdx] = elemSol[0][Indices::dissipationEqIdx];
123 129232 storedTurbulentKineticEnergy_[elementIdx] = elemSol[0][Indices::turbulentKineticEnergyEqIdx];
124 // NOTE: then update the volVars
125 64616 VolumeVariables volVars;
126
1/2
✓ Branch 1 taken 64616 times.
✗ Branch 2 not taken.
64616 volVars.update(elemSol, asImp_(), element, scv);
127
3/6
✓ Branch 0 taken 64616 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64616 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 64616 times.
✗ Branch 5 not taken.
193848 storedDynamicEddyViscosity_[elementIdx] = volVars.calculateEddyViscosity();
128 }
129 }
130
131 // get matching point for k-epsilon wall function
132 287 unsigned int numElementsInNearWallRegion = 0;
133
1/9
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
130093 for (const auto& element : elements(this->gridGeometry().gridView()))
134 {
135 193848 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
136
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
64616 unsigned int wallNormalAxis = asImp_().wallNormalAxis(elementIdx);
137
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
64616 unsigned int neighborIndex0 = asImp_().neighborIndex(elementIdx, wallNormalAxis, 0);
138
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
64616 unsigned int neighborIndex1 = asImp_().neighborIndex(elementIdx, wallNormalAxis, 1);
139 64616 numElementsInNearWallRegion = inNearWallRegion(elementIdx)
140
2/4
✓ Branch 1 taken 14819 times.
✓ Branch 2 taken 49797 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
64616 ? numElementsInNearWallRegion + 1
141 : numElementsInNearWallRegion + 0;
142
4/11
✗ Branch 1 not taken.
✓ Branch 2 taken 47479 times.
✓ Branch 3 taken 2318 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 45786 times.
✓ Branch 6 taken 1693 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
114413 if ((!inNearWallRegion(elementIdx) && (inNearWallRegion(neighborIndex0) || inNearWallRegion(neighborIndex1)))
143
4/9
✓ Branch 1 taken 45786 times.
✓ Branch 2 taken 14819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43496 times.
✓ Branch 5 taken 2290 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
60605 || (!inNearWallRegion(elementIdx) && elementIdx == asImp_().wallElementIndex(elementIdx))
144
6/13
✓ Branch 0 taken 49797 times.
✓ Branch 1 taken 14819 times.
✓ Branch 3 taken 14819 times.
✓ Branch 4 taken 43496 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 14809 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
122931 || (inNearWallRegion(elementIdx) && (asImp_().wallElementIndex(neighborIndex0) != asImp_().wallElementIndex(neighborIndex1))))
145 {
146
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
6311 matchingPointIdx_[asImp_().wallElementIndex(elementIdx)] = elementIdx;
147 }
148 }
149
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
574 std::cout << "numElementsInNearWallRegion: " << numElementsInNearWallRegion << std::endl;
150
151 // calculate the potential zeroeq eddy viscosities for two-layer model
152
1/9
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
130093 for (const auto& element : elements(this->gridGeometry().gridView()))
153 {
154 193848 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
155
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
64616 zeroEqDynamicEddyViscosity_[elementIdx] = zeroEqEddyViscosityModel(elementIdx);
156 }
157
158 // then make them match at the matching point
159
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 279 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
295 static const auto enableZeroEqScaling
160
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
24 = getParamFromGroup<bool>(this->paramGroup(), "KEpsilon.EnableZeroEqScaling", true);
161
1/2
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
287 if (enableZeroEqScaling)
162 {
163
1/9
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
130093 for (const auto& element : elements(this->gridGeometry().gridView()))
164 {
165 193848 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
166
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
64616 unsigned int matchingPointIndex = matchingPointIdx(asImp_().wallElementIndex(elementIdx));
167
168 64616 Scalar scalingFactor = storedDynamicEddyViscosity(matchingPointIndex)
169 193848 / zeroEqDynamicEddyViscosity_[matchingPointIndex];
170 129232 if (!isMatchingPoint(elementIdx)
171
5/6
✓ Branch 0 taken 58294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57302 times.
✓ Branch 3 taken 992 times.
✓ Branch 4 taken 57302 times.
✓ Branch 5 taken 992 times.
58294 && !std::isnan(scalingFactor) && !std::isinf(scalingFactor))
172 {
173 114604 zeroEqDynamicEddyViscosity_[elementIdx] *= scalingFactor;
174 }
175 }
176
1/9
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
130380 for (const auto& element : elements(this->gridGeometry().gridView()))
177 {
178 193848 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
179
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
64616 unsigned int matchingPointIndex = matchingPointIdx(asImp_().wallElementIndex(elementIdx));
180 129232 if (isMatchingPoint(elementIdx))
181 {
182 6322 zeroEqDynamicEddyViscosity_[matchingPointIndex] = storedDynamicEddyViscosity(matchingPointIndex);
183 }
184 }
185 }
186 287 }
187
188 /*!
189 * \brief Returns if an element is located in the near-wall region
190 */
191 69242772 bool inNearWallRegion(unsigned int elementIdx) const
192 {
193 69242772 unsigned int wallElementIdx = asImp_().wallElementIndex(elementIdx);
194 138485544 unsigned int matchingPointIndex = matchingPointIdx(wallElementIdx);
195 69242772 return (wallElementIdx == matchingPointIndex) ? yPlusNominal(elementIdx) < yPlusThreshold()
196 48965108 : yPlus(elementIdx) < yPlusThreshold();
197 }
198
199 /*!
200 * \brief Returns if an element is the matching point
201 */
202 bool isMatchingPoint(unsigned int elementIdx) const
203
0/8
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
59299464 { return matchingPointIdx(asImp_().wallElementIndex(elementIdx)) == elementIdx; }
204
205 /*!
206 * \brief Returns the \f$ y^+ \f$ value at an element center
207 */
208 49029724 const Scalar yPlus(unsigned int elementIdx) const
209 {
210 98059448 return asImp_().wallDistance(elementIdx) * uStar(elementIdx)
211 98059448 / asImp_().kinematicViscosity(elementIdx);
212 }
213 /*!
214 * \brief Returns the nominal \f$ y^+ \f$ value at an element center
215 */
216 20978856 const Scalar yPlusNominal(unsigned int elementIdx) const
217 {
218 41957712 return asImp_().wallDistance(elementIdx) * uStarNominal(elementIdx)
219 41957712 / asImp_().kinematicViscosity(elementIdx);
220 }
221
222 /*!
223 * \brief Returns the kinematic eddy viscosity of a 0-Eq. model
224 */
225 64616 const Scalar zeroEqEddyViscosityModel(unsigned int elementIdx) const
226 {
227 using std::abs;
228 using std::exp;
229 using std::sqrt;
230
231 // use VanDriest's model
232 64616 Scalar yPlusValue = yPlus(elementIdx);
233 64616 Scalar mixingLength = 0.0;
234
1/2
✓ Branch 0 taken 64616 times.
✗ Branch 1 not taken.
64616 if (yPlusValue > 0.0)
235 {
236 64616 mixingLength = asImp_().karmanConstant() * asImp_().wallDistance(elementIdx)
237 64616 * (1.0 - exp(-yPlusValue / 26.0 ))
238 64616 / sqrt(1.0 - exp(-0.26 * yPlusValue));
239 }
240
241 64616 unsigned int wallNormalAxis = asImp_().wallNormalAxis(elementIdx);
242 64616 unsigned int flowDirectionAxis = asImp_().flowDirectionAxis(elementIdx);
243 129232 Scalar velocityGradient = asImp_().velocityGradient(elementIdx, flowDirectionAxis, wallNormalAxis);
244 193848 return mixingLength * mixingLength * abs(velocityGradient) * asImp_().storedDensity(elementIdx);
245 }
246
247 //! \brief Returns the wall shear stress velocity
248 49029724 const Scalar uStar(unsigned int elementIdx) const
249 {
250 using std::abs;
251 using std::sqrt;
252 49029724 unsigned int wallElementIdx = asImp_().wallElementIndex(elementIdx);
253 49029724 unsigned int wallNormalAxis = asImp_().wallNormalAxis(elementIdx);
254 49029724 unsigned int flowDirectionAxis = asImp_().flowDirectionAxis(elementIdx);
255 98059448 return sqrt(asImp_().kinematicViscosity(wallElementIdx)
256 245148620 * abs(asImp_().velocityGradient(wallElementIdx, flowDirectionAxis, wallNormalAxis)));
257 }
258
259 //! \brief Returns the nominal wall shear stress velocity (accounts for poor approximation of viscous sublayer)
260 69351972 const Scalar uStarNominal(unsigned int elementIdx) const
261 {
262 using std::pow;
263 using std::sqrt;
264 69351972 unsigned int matchingPointIndex = matchingPointIdx(asImp_().wallElementIndex(elementIdx));
265 138703944 return pow(cMu(), 0.25) * sqrt(storedTurbulentKineticEnergy(matchingPointIndex));
266 }
267
268 /*!
269 * \brief Returns the dissipation calculated from the wall function consideration
270 */
271 5632408 const Scalar dissipationWallFunction(unsigned int elementIdx) const
272 {
273 5632408 return uStarNominal(elementIdx) * uStarNominal(elementIdx) * uStarNominal(elementIdx)
274 11264816 / asImp_().karmanConstant() / asImp_().wallDistance(elementIdx);
275 }
276
277 /*!
278 * \brief Returns the turbulentKineticEnergy calculated from the wall function consideration
279 */
280 const Scalar turbulentKineticEnergyWallFunction(unsigned int elementIdx) const
281 {
282 5632408 unsigned int matchingPointIndex = matchingPointIdx(asImp_().wallElementIndex(elementIdx));
283 11264816 return storedTurbulentKineticEnergy(matchingPointIndex);
284 }
285
286 //! \brief Returns the nominal wall shear stress (accounts for poor approximation of viscous sublayer)
287 508848 const Scalar tangentialMomentumWallFunction(unsigned int elementIdx, Scalar velocity) const
288 {
289 using std::log;
290 508848 Scalar velocityNominal = uStarNominal(elementIdx) * (1.0 / asImp_().karmanConstant() * log(yPlusNominal(elementIdx)) + 5.0);
291 508848 return uStarNominal(elementIdx) * uStarNominal(elementIdx) * velocity / velocityNominal;
292 }
293
294 //! \brief Checks whether a wall function should be used
295 11821545 bool useWallFunction(const Element& element,
296 const SubControlVolumeFace& localSubFace,
297 const int& eqIdx) const
298 {
299 35464635 unsigned int elementIdx = asImp_().gridGeometry().elementMapper().index(element);
300 11821545 auto bcTypes = asImp_().boundaryTypes(element, localSubFace);
301
302 return bcTypes.hasWall()
303
2/2
✓ Branch 0 taken 1033654 times.
✓ Branch 1 taken 3458027 times.
4491681 && bcTypes.isDirichlet(eqIdx)
304
2/2
✓ Branch 0 taken 4491681 times.
✓ Branch 1 taken 7329864 times.
15279572 && isMatchingPoint(elementIdx);
305 }
306
307 //! \brief Returns an additional wall function momentum flux (only needed for RANS models)
308 FacePrimaryVariables wallFunction(const Element& element,
309 const FVElementGeometry& fvGeometry,
310 const ElementVolumeVariables& elemVolVars,
311 const ElementFaceVariables& elemFaceVars,
312 const SubControlVolumeFace& scvf,
313 const SubControlVolumeFace& localSubFace) const
314 {
315 unsigned int elementIdx = asImp_().gridGeometry().elementMapper().index(element);
316 return FacePrimaryVariables(asImp_().tangentialMomentumWallFunction(elementIdx, elemFaceVars[scvf].velocitySelf())
317 * asImp_().storedDensity(elementIdx) );
318 }
319
320 //! \brief Returns the flux for non-isothermal and compositional RANS models
321 template<bool eB = enableEnergyBalance, bool compositional = isCompositional,
322 typename std::enable_if_t<eB && compositional, int> = 0>
323 73320 CellCenterPrimaryVariables wallFunction(const Element& element,
324 const FVElementGeometry& fvGeometry,
325 const ElementVolumeVariables& elemVolVars,
326 const ElementFaceVariables& elemFaceVars,
327 const SubControlVolumeFace& scvf) const
328 {
329 return wallFunctionComponent(element, fvGeometry, elemVolVars, elemFaceVars, scvf)
330 73320 + wallFunctionEnergy(element, fvGeometry, elemVolVars, elemFaceVars, scvf);
331 }
332
333 //! \brief Returns the flux for isothermal and compositional RANS models
334 template<bool eB = enableEnergyBalance, bool compositional = isCompositional,
335 typename std::enable_if_t<!eB && compositional, int> = 0>
336 CellCenterPrimaryVariables wallFunction(const Element& element,
337 const FVElementGeometry& fvGeometry,
338 const ElementVolumeVariables& elemVolVars,
339 const ElementFaceVariables& elemFaceVars,
340 const SubControlVolumeFace& scvf) const
341 45704 { return wallFunctionComponent(element, fvGeometry, elemVolVars, elemFaceVars, scvf); }
342
343 //! \brief Returns the flux for non-isothermal RANS models
344 template<bool eB = enableEnergyBalance, bool compositional = isCompositional,
345 typename std::enable_if_t<eB && !compositional, int> = 0>
346 CellCenterPrimaryVariables wallFunction(const Element& element,
347 const FVElementGeometry& fvGeometry,
348 const ElementVolumeVariables& elemVolVars,
349 const ElementFaceVariables& elemFaceVars,
350 const SubControlVolumeFace& scvf) const
351 { return wallFunctionEnergy(element, fvGeometry, elemVolVars, elemFaceVars, scvf); }
352
353 //! \brief Returns the flux for isothermal RANS models
354 template<bool eB = enableEnergyBalance, bool compositional = isCompositional,
355 typename std::enable_if_t<!eB && !compositional, int> = 0>
356 CellCenterPrimaryVariables wallFunction(const Element& element,
357 const FVElementGeometry& fvGeometry,
358 const ElementVolumeVariables& elemVolVars,
359 const ElementFaceVariables& elemFaceVars,
360 const SubControlVolumeFace& scvf) const
361 1086168 { return CellCenterPrimaryVariables(0.0); }
362
363 //! \brief Returns the component wall-function flux
364 119024 CellCenterPrimaryVariables wallFunctionComponent(const Element& element,
365 const FVElementGeometry& fvGeometry,
366 const ElementVolumeVariables& elemVolVars,
367 const ElementFaceVariables& elemFaceVars,
368 const SubControlVolumeFace& scvf) const
369 {
370 using std::log;
371 119024 auto wallFunctionFlux = CellCenterPrimaryVariables(0.0);
372 238048 unsigned int elementIdx = asImp_().gridGeometry().elementMapper().index(element);
373
374 // component mass fluxes
375
2/2
✓ Branch 1 taken 238048 times.
✓ Branch 2 taken 119024 times.
357072 for (int compIdx = 0; compIdx < ModelTraits::numFluidComponents(); ++compIdx)
376 {
377
2/2
✓ Branch 0 taken 119024 times.
✓ Branch 1 taken 119024 times.
238048 if (ModelTraits::replaceCompEqIdx() == compIdx)
378 continue;
379
380 238048 Scalar schmidtNumber = elemVolVars[scvf.insideScvIdx()].kinematicViscosity()
381 357072 / elemVolVars[scvf.insideScvIdx()].diffusionCoefficient(0, 0, compIdx);
382 119024 Scalar moleToMassConversionFactor = ModelTraits::useMoles()
383 ? 1.0 : FluidSystem::molarMass(compIdx);
384 238048 wallFunctionFlux[compIdx] +=
385 238048 -1.0 * (asImp_().dirichlet(element, scvf)[Indices::conti0EqIdx + compIdx]
386 238048 - elemVolVars[scvf.insideScvIdx()].moleFraction(compIdx))
387 238048 * elemVolVars[scvf.insideScvIdx()].molarDensity()
388 * moleToMassConversionFactor
389 119024 * uStarNominal(elementIdx)
390 119024 / asImp_().turbulentSchmidtNumber()
391 119024 / (1. / asImp_().karmanConstant() * log(yPlusNominal(elementIdx) * 9.793)
392 119024 + pFunction(schmidtNumber, asImp_().turbulentSchmidtNumber()));
393 }
394
395 if (ModelTraits::replaceCompEqIdx() < ModelTraits::numFluidComponents())
396 {
397 238048 wallFunctionFlux[ModelTraits::replaceCompEqIdx()] =
398 119024 -std::accumulate(wallFunctionFlux.begin(), wallFunctionFlux.end(), 0.0);
399 }
400
401 119024 return wallFunctionFlux;
402 }
403
404 //! \brief Returns the energy wall-function flux
405 73320 CellCenterPrimaryVariables wallFunctionEnergy(const Element& element,
406 const FVElementGeometry& fvGeometry,
407 const ElementVolumeVariables& elemVolVars,
408 const ElementFaceVariables& elemFaceVars,
409 const SubControlVolumeFace& scvf) const
410 {
411 using std::log;
412 73320 auto wallFunctionFlux = CellCenterPrimaryVariables(0.0);
413 219960 unsigned int elementIdx = asImp_().gridGeometry().elementMapper().index(element);
414 // energy fluxes
415 146640 Scalar prandtlNumber = elemVolVars[scvf.insideScvIdx()].kinematicViscosity()
416 219960 * elemVolVars[scvf.insideScvIdx()].density()
417 146640 * elemVolVars[scvf.insideScvIdx()].heatCapacity()
418 146640 / elemVolVars[scvf.insideScvIdx()].thermalConductivity();
419 146640 wallFunctionFlux[Indices::energyEqIdx - cellCenterOffset] +=
420 73320 -1.0 * (asImp_().dirichlet(element, scvf)[Indices::temperatureIdx]
421 146640 - elemVolVars[scvf.insideScvIdx()].temperature())
422 146640 * elemVolVars[scvf.insideScvIdx()].density()
423 146640 * elemVolVars[scvf.insideScvIdx()].heatCapacity()
424 73320 * uStarNominal(elementIdx)
425 73320 / asImp_().turbulentPrandtlNumber()
426 73320 / (1. / asImp_().karmanConstant() * log(yPlusNominal(elementIdx) * 9.793)
427 73320 + pFunction(prandtlNumber, asImp_().turbulentPrandtlNumber()));
428
429 73320 return wallFunctionFlux;
430 }
431
432 //! \brief Returns the value of the P-function after Jayatilleke \cite Versteeg2009a
433 const Scalar pFunction(Scalar molecularNumber, Scalar turbulentNumber) const
434 {
435 using std::pow;
436 using std::exp;
437 return 9.24
438 * (pow(molecularNumber / turbulentNumber, 0.75) - 1.0)
439 * (1.0 + 0.28 * exp(-0.007 * molecularNumber / turbulentNumber));
440 }
441
442 //! \brief Returns the \f$ C_{\mu} \f$ constant
443 const Scalar cMu() const
444 { return 0.09; }
445
446 69242772 Scalar yPlusThreshold() const
447 {
448
5/8
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 69242764 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
69242772 static const Scalar yPlusThreshold = getParamFromGroup<Scalar>(this->paramGroup(), "KEpsilon.YPlusThreshold", 30.0);
449 69242772 return yPlusThreshold;
450 }
451
452 29757004 bool useStoredEddyViscosity() const
453 {
454
5/8
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 29756996 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
29757004 static const bool useStoredEddyViscosity = getParamFromGroup<bool>(this->paramGroup(), "RANS.UseStoredEddyViscosity", false);
455 29757004 return useStoredEddyViscosity;
456 }
457
458 Scalar storedDissipation(const int elementIdx) const
459 59514008 { return storedDissipation_[elementIdx]; }
460
461 Scalar storedTurbulentKineticEnergy(const int elementIdx) const
462 65146416 { return storedTurbulentKineticEnergy_[elementIdx]; }
463
464 Scalar storedDynamicEddyViscosity(const int elementIdx) const
465
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
77260 { return storedDynamicEddyViscosity_[elementIdx]; }
466
467 Scalar zeroEqDynamicEddyViscosity(const int elementIdx) const
468 13032410 { return zeroEqDynamicEddyViscosity_[elementIdx]; }
469
470 unsigned int matchingPointIdx(const int elementIdx) const
471
20/88
✓ Branch 0 taken 2287071 times.
✓ Branch 1 taken 1170956 times.
✓ Branch 2 taken 2287071 times.
✓ Branch 3 taken 1170956 times.
✓ Branch 6 taken 3543418 times.
✓ Branch 7 taken 25934426 times.
✓ Branch 8 taken 3543418 times.
✓ Branch 9 taken 25934426 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 20277664 times.
✓ Branch 13 taken 48965108 times.
✓ Branch 14 taken 20277664 times.
✓ Branch 15 taken 48965108 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 58294 times.
✓ Branch 19 taken 6322 times.
✓ Branch 20 taken 58294 times.
✓ Branch 21 taken 6322 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✓ Branch 24 taken 6322 times.
✓ Branch 25 taken 58294 times.
✓ Branch 26 taken 6322 times.
✓ Branch 27 taken 58294 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 98 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
275394574 { return matchingPointIdx_[elementIdx]; }
472
473 private:
474 std::vector<unsigned int> matchingPointIdx_;
475 std::vector<Scalar> storedDissipation_;
476 std::vector<Scalar> storedTurbulentKineticEnergy_;
477 std::vector<Scalar> storedDynamicEddyViscosity_;
478 std::vector<Scalar> zeroEqDynamicEddyViscosity_;
479
480 //! Returns the implementation of the problem (i.e. static polymorphism)
481 Implementation &asImp_()
482 { return *static_cast<Implementation *>(this); }
483
484 //! \copydoc asImp_()
485 const Implementation &asImp_() const
486 { return *static_cast<const Implementation *>(this); }
487 };
488
489 } // end namespace Dumux
490
491 #endif
492