GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/freeflow/rans/twoeq/kepsilon/problem.hh
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 157 169 92.9%
Functions: 103 121 85.1%
Branches: 191 294 65.0%

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 16 RANSProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry, const std::string& paramGroup = "")
75
2/6
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
96 : ParentType(gridGeometry, paramGroup)
76 16 { }
77
78 /*!
79 * \brief Correct size of the static (solution independent) wall variables
80 */
81 16 void updateStaticWallProperties()
82 {
83
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
16 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 16 ParentType::updateStaticWallProperties();
91 // update size and initial values of the global vectors
92 64 matchingPointIdx_.resize(this->gridGeometry().elementMapper().size(), 0);
93 64 storedDissipation_.resize(this->gridGeometry().elementMapper().size(), 0.0);
94 64 storedTurbulentKineticEnergy_.resize(this->gridGeometry().elementMapper().size(), 0.0);
95 64 storedDynamicEddyViscosity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
96 64 zeroEqDynamicEddyViscosity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
97 16 }
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 295 void updateDynamicWallProperties(const SolutionVector& curSol)
106 {
107 295 ParentType::updateDynamicWallProperties(curSol);
108
109 // update the stored eddy viscosities
110
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
598 auto fvGeometry = localView(this->gridGeometry());
111
5/9
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 104 times.
✗ Branch 10 not taken.
130517 for (const auto& element : elements(this->gridGeometry().gridView()))
112 {
113 194448 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
114
1/2
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
64816 fvGeometry.bindElement(element);
115
6/6
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 64616 times.
✓ Branch 3 taken 64616 times.
✓ Branch 4 taken 64616 times.
✓ Branch 5 taken 64616 times.
258864 for (auto&& scv : scvs(fvGeometry))
116 {
117 64816 const int dofIdx = scv.dofIndex();
118 129632 const auto& cellCenterPriVars = curSol[GridGeometry::cellCenterIdx()][dofIdx];
119 64816 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(cellCenterPriVars);
120
1/4
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
129632 auto elemSol = elementSolution<typename GridGeometry::LocalView>(std::move(priVars));
121 // NOTE: first update the turbulence quantities
122 129632 storedDissipation_[elementIdx] = elemSol[0][Indices::dissipationEqIdx];
123 129632 storedTurbulentKineticEnergy_[elementIdx] = elemSol[0][Indices::turbulentKineticEnergyEqIdx];
124 // NOTE: then update the volVars
125 64816 VolumeVariables volVars;
126
1/2
✓ Branch 1 taken 64716 times.
✗ Branch 2 not taken.
64816 volVars.update(elemSol, asImp_(), element, scv);
127
3/6
✓ Branch 0 taken 64716 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64716 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 64716 times.
✗ Branch 5 not taken.
194448 storedDynamicEddyViscosity_[elementIdx] = volVars.calculateEddyViscosity();
128 }
129 }
130
131 // get matching point for k-epsilon wall function
132 295 unsigned int numElementsInNearWallRegion = 0;
133
5/9
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 104 times.
✗ Branch 10 not taken.
130517 for (const auto& element : elements(this->gridGeometry().gridView()))
134 {
135 194448 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
136
1/2
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
64816 unsigned int wallNormalAxis = asImp_().wallNormalAxis(elementIdx);
137
1/2
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
64816 unsigned int neighborIndex0 = asImp_().neighborIndex(elementIdx, wallNormalAxis, 0);
138
1/2
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
64816 unsigned int neighborIndex1 = asImp_().neighborIndex(elementIdx, wallNormalAxis, 1);
139 64816 numElementsInNearWallRegion = inNearWallRegion(elementIdx)
140
4/4
✓ Branch 1 taken 14919 times.
✓ Branch 2 taken 49797 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 80 times.
64816 ? numElementsInNearWallRegion + 1
141 : numElementsInNearWallRegion + 0;
142
8/11
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 47479 times.
✓ Branch 3 taken 2318 times.
✓ Branch 4 taken 80 times.
✓ Branch 5 taken 45786 times.
✓ Branch 6 taken 1773 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 80 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 80 times.
✗ Branch 12 not taken.
114773 if ((!inNearWallRegion(elementIdx) && (inNearWallRegion(neighborIndex0) || inNearWallRegion(neighborIndex1)))
143
7/9
✓ Branch 1 taken 45886 times.
✓ Branch 2 taken 14819 times.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 43516 times.
✓ Branch 5 taken 2290 times.
✓ Branch 6 taken 80 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 80 times.
✗ Branch 9 not taken.
60805 || (!inNearWallRegion(elementIdx) && elementIdx == asImp_().wallElementIndex(elementIdx))
144
10/13
✓ Branch 0 taken 49877 times.
✓ Branch 1 taken 14839 times.
✓ Branch 3 taken 14919 times.
✓ Branch 4 taken 43496 times.
✓ Branch 5 taken 20 times.
✓ Branch 6 taken 80 times.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 14829 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 20 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 20 times.
123331 || (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
2/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
590 std::cout << "numElementsInNearWallRegion: " << numElementsInNearWallRegion << std::endl;
150
151 // calculate the potential zeroeq eddy viscosities for two-layer model
152
5/9
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 104 times.
✗ Branch 10 not taken.
130517 for (const auto& element : elements(this->gridGeometry().gridView()))
153 {
154 194448 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
155
1/2
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
64816 zeroEqDynamicEddyViscosity_[elementIdx] = zeroEqEddyViscosityModel(elementIdx);
156 }
157
158 // then make them match at the matching point
159
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 279 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
311 static const auto enableZeroEqScaling
160
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
48 = getParamFromGroup<bool>(this->paramGroup(), "KEpsilon.EnableZeroEqScaling", true);
161
1/2
✓ Branch 0 taken 291 times.
✗ Branch 1 not taken.
295 if (enableZeroEqScaling)
162 {
163
5/9
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 104 times.
✗ Branch 10 not taken.
130517 for (const auto& element : elements(this->gridGeometry().gridView()))
164 {
165 194448 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
166
1/2
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
64816 unsigned int matchingPointIndex = matchingPointIdx(asImp_().wallElementIndex(elementIdx));
167
168 64816 Scalar scalingFactor = storedDynamicEddyViscosity(matchingPointIndex)
169 194448 / zeroEqDynamicEddyViscosity_[matchingPointIndex];
170 129632 if (!isMatchingPoint(elementIdx)
171
5/6
✓ Branch 0 taken 58390 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57302 times.
✓ Branch 3 taken 1088 times.
✓ Branch 4 taken 57302 times.
✓ Branch 5 taken 1088 times.
58486 && !std::isnan(scalingFactor) && !std::isinf(scalingFactor))
172 {
173 114604 zeroEqDynamicEddyViscosity_[elementIdx] *= scalingFactor;
174 }
175 }
176
5/9
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64903 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 104 times.
✗ Branch 10 not taken.
130812 for (const auto& element : elements(this->gridGeometry().gridView()))
177 {
178 194448 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
179
1/2
✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
64816 unsigned int matchingPointIndex = matchingPointIdx(asImp_().wallElementIndex(elementIdx));
180 129632 if (isMatchingPoint(elementIdx))
181 {
182 6330 zeroEqDynamicEddyViscosity_[matchingPointIndex] = storedDynamicEddyViscosity(matchingPointIndex);
183 }
184 }
185 }
186 295 }
187
188 /*!
189 * \brief Returns if an element is located in the near-wall region
190 */
191 69245292 bool inNearWallRegion(unsigned int elementIdx) const
192 {
193 69245292 unsigned int wallElementIdx = asImp_().wallElementIndex(elementIdx);
194 138490584 unsigned int matchingPointIndex = matchingPointIdx(wallElementIdx);
195 69245292 return (wallElementIdx == matchingPointIndex) ? yPlusNominal(elementIdx) < yPlusThreshold()
196 48966772 : 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
4/8
✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 25 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 25 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 25 times.
✗ Branch 15 not taken.
59300264 { return matchingPointIdx(asImp_().wallElementIndex(elementIdx)) == elementIdx; }
204
205 /*!
206 * \brief Returns the \f$ y^+ \f$ value at an element center
207 */
208 49031588 const Scalar yPlus(unsigned int elementIdx) const
209 {
210 98063176 return asImp_().wallDistance(elementIdx) * uStar(elementIdx)
211 98063176 / asImp_().kinematicViscosity(elementIdx);
212 }
213 /*!
214 * \brief Returns the nominal \f$ y^+ \f$ value at an element center
215 */
216 20979712 const Scalar yPlusNominal(unsigned int elementIdx) const
217 {
218 41959424 return asImp_().wallDistance(elementIdx) * uStarNominal(elementIdx)
219 41959424 / asImp_().kinematicViscosity(elementIdx);
220 }
221
222 /*!
223 * \brief Returns the kinematic eddy viscosity of a 0-Eq. model
224 */
225 64816 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 64816 Scalar yPlusValue = yPlus(elementIdx);
233 64816 Scalar mixingLength = 0.0;
234
2/2
✓ Branch 0 taken 64696 times.
✓ Branch 1 taken 20 times.
64816 if (yPlusValue > 0.0)
235 {
236 64776 mixingLength = asImp_().karmanConstant() * asImp_().wallDistance(elementIdx)
237 64776 * (1.0 - exp(-yPlusValue / 26.0 ))
238 64776 / sqrt(1.0 - exp(-0.26 * yPlusValue));
239 }
240
241 64816 unsigned int wallNormalAxis = asImp_().wallNormalAxis(elementIdx);
242 64816 unsigned int flowDirectionAxis = asImp_().flowDirectionAxis(elementIdx);
243 129632 Scalar velocityGradient = asImp_().velocityGradient(elementIdx, flowDirectionAxis, wallNormalAxis);
244 194448 return mixingLength * mixingLength * abs(velocityGradient) * asImp_().storedDensity(elementIdx);
245 }
246
247 //! \brief Returns the wall shear stress velocity
248 49031588 const Scalar uStar(unsigned int elementIdx) const
249 {
250 using std::abs;
251 using std::sqrt;
252 49031588 unsigned int wallElementIdx = asImp_().wallElementIndex(elementIdx);
253 49031588 unsigned int wallNormalAxis = asImp_().wallNormalAxis(elementIdx);
254 49031588 unsigned int flowDirectionAxis = asImp_().flowDirectionAxis(elementIdx);
255 98063176 return sqrt(asImp_().kinematicViscosity(wallElementIdx)
256 245157940 * 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 69354228 const Scalar uStarNominal(unsigned int elementIdx) const
261 {
262 using std::pow;
263 using std::sqrt;
264 69354228 unsigned int matchingPointIndex = matchingPointIdx(asImp_().wallElementIndex(elementIdx));
265 138708456 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 69245292 Scalar yPlusThreshold() const
447 {
448
5/8
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 69244020 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
69245292 static const Scalar yPlusThreshold = getParamFromGroup<Scalar>(this->paramGroup(), "KEpsilon.YPlusThreshold", 30.0);
449 69245292 return yPlusThreshold;
450 }
451
452 29758404 bool useStoredEddyViscosity() const
453 {
454
5/8
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 29757692 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
29758404 static const bool useStoredEddyViscosity = getParamFromGroup<bool>(this->paramGroup(), "RANS.UseStoredEddyViscosity", false);
455 29758404 return useStoredEddyViscosity;
456 }
457
458 Scalar storedDissipation(const int elementIdx) const
459 59515408 { return storedDissipation_[elementIdx]; }
460
461 Scalar storedTurbulentKineticEnergy(const int elementIdx) const
462 65147816 { return storedTurbulentKineticEnergy_[elementIdx]; }
463
464 Scalar storedDynamicEddyViscosity(const int elementIdx) const
465
4/8
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 25 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 25 times.
✗ Branch 11 not taken.
77368 { return storedDynamicEddyViscosity_[elementIdx]; }
466
467 Scalar zeroEqDynamicEddyViscosity(const int elementIdx) const
468 13032650 { return zeroEqDynamicEddyViscosity_[elementIdx]; }
469
470 unsigned int matchingPointIdx(const int elementIdx) const
471
73/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 3543525 times.
✓ Branch 9 taken 25934634 times.
✓ Branch 10 taken 107 times.
✓ Branch 11 taken 208 times.
✓ Branch 12 taken 20277771 times.
✓ Branch 13 taken 48965316 times.
✓ Branch 14 taken 20277771 times.
✓ Branch 15 taken 48965316 times.
✓ Branch 16 taken 107 times.
✓ Branch 17 taken 208 times.
✓ Branch 18 taken 58401 times.
✓ Branch 19 taken 6530 times.
✓ Branch 20 taken 58401 times.
✓ Branch 21 taken 6530 times.
✓ Branch 22 taken 107 times.
✓ Branch 23 taken 208 times.
✓ Branch 24 taken 6322 times.
✓ Branch 25 taken 58319 times.
✓ Branch 26 taken 6322 times.
✓ Branch 27 taken 58294 times.
✓ Branch 28 taken 25 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 24 times.
✓ Branch 31 taken 1 times.
✓ Branch 32 taken 24 times.
✓ Branch 33 taken 1 times.
✓ Branch 35 taken 25 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 25 times.
✗ Branch 39 not taken.
✓ Branch 40 taken 1 times.
✓ Branch 41 taken 24 times.
✓ Branch 42 taken 1 times.
✓ Branch 43 taken 24 times.
✓ Branch 45 taken 25 times.
✗ Branch 46 not taken.
✓ Branch 48 taken 25 times.
✗ Branch 49 not taken.
✓ Branch 50 taken 24 times.
✓ Branch 51 taken 1 times.
✓ Branch 52 taken 24 times.
✓ Branch 53 taken 1 times.
✓ Branch 55 taken 25 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 25 times.
✗ Branch 59 not taken.
✓ Branch 60 taken 1 times.
✓ Branch 61 taken 24 times.
✓ Branch 62 taken 1 times.
✓ Branch 63 taken 24 times.
✓ Branch 65 taken 25 times.
✗ Branch 66 not taken.
✓ Branch 68 taken 25 times.
✗ Branch 69 not taken.
✓ Branch 70 taken 24 times.
✓ Branch 71 taken 1 times.
✓ Branch 72 taken 24 times.
✓ Branch 73 taken 1 times.
✓ Branch 75 taken 25 times.
✗ Branch 76 not taken.
✓ Branch 78 taken 25 times.
✗ Branch 79 not taken.
✓ Branch 80 taken 1 times.
✓ Branch 81 taken 24 times.
✓ Branch 82 taken 1 times.
✓ Branch 83 taken 24 times.
✓ Branch 85 taken 25 times.
✗ Branch 86 not taken.
✓ Branch 88 taken 25 times.
✗ Branch 89 not taken.
✓ Branch 90 taken 24 times.
✓ Branch 91 taken 1 times.
✓ Branch 92 taken 24 times.
✓ Branch 93 taken 1 times.
✓ Branch 95 taken 25 times.
✗ Branch 96 not taken.
✓ Branch 98 taken 25 times.
✗ Branch 99 not taken.
✓ Branch 100 taken 1 times.
✓ Branch 101 taken 24 times.
✓ Branch 102 taken 1 times.
✓ Branch 103 taken 24 times.
275398894 { 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