version 3.10-dev
freeflow/rans/zeroeq/problem.hh
Go to the documentation of this file.
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//
12#ifndef DUMUX_ZEROEQ_PROBLEM_HH
13#define DUMUX_ZEROEQ_PROBLEM_HH
14
15#include <string>
16
17#include <dune/common/math.hh>
18#include <dune/common/stdstreams.hh>
19
27
28#include "model.hh"
29
30namespace Dumux {
31
39template<class TypeTag>
40class RANSProblemImpl<TypeTag, TurbulenceModel::zeroeq> : public RANSProblemBase<TypeTag>
41{
43 using Implementation = GetPropType<TypeTag, Properties::Problem>;
45 using Grid = typename GridView::Grid;
47
49 using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
50 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
53 using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>;
55
56 enum {
57 dim = Grid::dimension,
58 };
59 using DimVector = Dune::FieldVector<Scalar, dim>;
60 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
61
62public:
68 RANSProblemImpl(std::shared_ptr<const GridGeometry> gridGeometry, const std::string& paramGroup = "")
69 : ParentType(gridGeometry, paramGroup)
70 {}
71
76 {
77 if (!ParentType::isFlatWallBounded())
78 {
79 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, zero-eq models should only be used for flat channel geometries. "
80 << "\n If your geometry is a flat channel, please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
81 }
82
83 ParentType::updateStaticWallProperties();
84
85 // update size and initial values of the global vectors
86 kinematicEddyViscosity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
87 additionalRoughnessLength_.resize(this->gridGeometry().elementMapper().size(), 0.0);
88 }
89
97 template<class SolutionVector>
98 void updateDynamicWallProperties(const SolutionVector& curSol)
99 {
100 ParentType::updateDynamicWallProperties(curSol);
101
102 // correct roughness lengths if a sand grain roughness is specified
103 if (hasParam("RANS.SandGrainRoughness"))
104 calculateRoughnessLength_(curSol);
105
106 // update routine for specific models
107 if (eddyViscosityModel().compare("baldwinLomax") == 0)
108 updateBaldwinLomaxProperties();
109 }
110
115 {
116 std::vector<Scalar> kinematicEddyViscosityInner(this->gridGeometry().elementMapper().size(), 0.0);
117 std::vector<Scalar> kinematicEddyViscosityOuter(this->gridGeometry().elementMapper().size(), 0.0);
118 std::vector<Scalar> kinematicEddyViscosityDifference(this->gridGeometry().elementMapper().size(), 0.0);
119 std::vector<Scalar> switchingPosition(this->gridGeometry().elementMapper().size(), std::numeric_limits<Scalar>::max());
120
121 using std::abs;
122 using std::exp;
123 using std::min;
124 using std::sqrt;
125 using Dune::power;
126 const Scalar aPlus = 26.0;
127 const Scalar k = 0.0168;
128 const Scalar cCP = 1.6;
129 const Scalar cWake = 0.25;
130 const Scalar cKleb = 0.3;
131
132 std::vector<Scalar> storedFMax;
133 std::vector<Scalar> storedYFMax;
134 storedFMax.resize(this->gridGeometry().elementMapper().size(), 0.0);
135 storedYFMax.resize(this->gridGeometry().elementMapper().size(), 0.0);
136
137 // (1) calculate inner viscosity and Klebanoff function
138 for (const auto& element : elements(this->gridGeometry().gridView()))
139 {
140 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
141 Scalar effectiveWallDistance = asImp_().wallDistance(elementIdx) + additionalRoughnessLength(elementIdx);
142 unsigned int flowDirectionAxis = this->flowDirectionAxis(elementIdx);
143 unsigned int wallNormalAxis = this->wallNormalAxis(elementIdx);
144
145 Scalar omegaAbs = abs(this->velocityGradient(elementIdx, flowDirectionAxis, wallNormalAxis)
146 - this->velocityGradient(elementIdx, wallNormalAxis, flowDirectionAxis));
147 Scalar uStar = sqrt(this->kinematicViscosity(asImp_().wallElementIndex(elementIdx))
148 * abs(this->velocityGradient(asImp_().wallElementIndex(elementIdx), flowDirectionAxis, wallNormalAxis)));
149 Scalar yPlus = effectiveWallDistance * uStar / this->kinematicViscosity(elementIdx);
150 Scalar mixingLength = this->karmanConstant() * effectiveWallDistance * (1.0 - exp(-yPlus / aPlus));
151 kinematicEddyViscosityInner[elementIdx] = mixingLength * mixingLength * omegaAbs;
152
153 Scalar f = effectiveWallDistance * omegaAbs * (1.0 - exp(-yPlus / aPlus));
154 if (f > storedFMax[asImp_().wallElementIndex(elementIdx)])
155 {
156 storedFMax[asImp_().wallElementIndex(elementIdx)] = f;
157 storedYFMax[asImp_().wallElementIndex(elementIdx)] = effectiveWallDistance;
158 }
159 }
160
161 // (2) calculate outer viscosity
162 for (const auto& element : elements(this->gridGeometry().gridView()))
163 {
164 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
165 Scalar effectiveWallDistance = asImp_().wallDistance(elementIdx) + additionalRoughnessLength(elementIdx);
166
167 Scalar maxVelocityNorm = 0.0;
168 Scalar minVelocityNorm = 0.0;
169 for (unsigned axisIdx = 0; axisIdx < dim; ++axisIdx)
170 {
171 maxVelocityNorm += asImp_().velocityMaximum(asImp_().wallElementIndex(elementIdx))[axisIdx]
172 * asImp_().velocityMaximum(asImp_().wallElementIndex(elementIdx))[axisIdx];
173 minVelocityNorm += asImp_().velocityMinimum(asImp_().wallElementIndex(elementIdx))[axisIdx]
174 * asImp_().velocityMinimum(asImp_().wallElementIndex(elementIdx))[axisIdx];
175 }
176
177 Scalar deltaU = sqrt(maxVelocityNorm) - sqrt(minVelocityNorm);
178 Scalar yFMax = storedYFMax[asImp_().wallElementIndex(elementIdx)];
179 Scalar fMax = storedFMax[asImp_().wallElementIndex(elementIdx)];
180 Scalar fWake = min(yFMax * fMax, cWake * yFMax * deltaU * deltaU / fMax);
181 Scalar fKleb = 1.0 / (1.0 + 5.5 * power(cKleb * effectiveWallDistance / yFMax, 6));
182 kinematicEddyViscosityOuter[elementIdx] = k * cCP * fWake * fKleb;
183
184 kinematicEddyViscosityDifference[elementIdx]
185 = kinematicEddyViscosityInner[elementIdx] - kinematicEddyViscosityOuter[elementIdx];
186 }
187
188 // (3) switching point
189 for (const auto& element : elements(this->gridGeometry().gridView()))
190 {
191 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
192 Scalar effectiveWallDistance = asImp_().wallDistance(elementIdx) + additionalRoughnessLength(elementIdx);
193
194 // checks if sign switches, by multiplication
195 Scalar check = kinematicEddyViscosityDifference[asImp_().wallElementIndex(elementIdx)] * kinematicEddyViscosityDifference[elementIdx];
196 if (check < 0 // means sign has switched
197 && switchingPosition[asImp_().wallElementIndex(elementIdx)] > effectiveWallDistance)
198 {
199 switchingPosition[asImp_().wallElementIndex(elementIdx)] = effectiveWallDistance;
200 }
201 }
202
203 // (4) finally determine eddy viscosity
204 for (const auto& element : elements(this->gridGeometry().gridView()))
205 {
206 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
207 Scalar effectiveWallDistance = asImp_().wallDistance(elementIdx) + additionalRoughnessLength(elementIdx);
208
209 kinematicEddyViscosity_[elementIdx] = kinematicEddyViscosityInner[elementIdx];
210 if (effectiveWallDistance >= switchingPosition[asImp_().wallElementIndex(elementIdx)])
211 {
212 kinematicEddyViscosity_[elementIdx] = kinematicEddyViscosityOuter[elementIdx];
213 }
214 }
215 }
216
217 std::string eddyViscosityModel() const
218 {
219 static const std::string eddyViscosityModel = getParamFromGroup<std::string>(this->paramGroup(), "RANS.EddyViscosityModel", "vanDriest");
220 return eddyViscosityModel;
221 }
222
223 int additionalRoughnessLength(const int elementIdx) const
224 { return additionalRoughnessLength_[elementIdx]; }
225
226 Scalar kinematicEddyViscosity(const int elementIdx) const
227 { return kinematicEddyViscosity_[elementIdx]; }
228
229private:
230
231 template<class SolutionVector>
232 void calculateRoughnessLength_(const SolutionVector& curSol)
233 {
234 bool printedRangeWarning = false;
235 auto fvGeometry = localView(this->gridGeometry());
236 for (const auto& element : elements(this->gridGeometry().gridView()))
237 {
238 static const Scalar sandGrainRoughness = getParamFromGroup<Scalar>(this->paramGroup(), "RANS.SandGrainRoughness");
239 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
240 fvGeometry.bindElement(element);
241
242 for (auto&& scv : scvs(fvGeometry))
243 {
244 using std::sqrt;
245 using std::exp;
246
247 const int dofIdx = scv.dofIndex();
248
249 // construct a privars object from the cell center solution vector
250 const auto& cellCenterPriVars = curSol[GridGeometry::cellCenterIdx()][dofIdx];
251 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(cellCenterPriVars);
252 auto elemSol = elementSolution<typename GridGeometry::LocalView>(std::move(priVars));
253
254 VolumeVariables volVars;
255 volVars.update(elemSol, asImp_(), element, scv);
256
257 Scalar ksPlus = sandGrainRoughness * volVars.uStar() / volVars.kinematicViscosity();
258 if (ksPlus > 0 && eddyViscosityModel().compare("baldwinLomax") == 0)
259 {
260 DUNE_THROW(Dune::NotImplemented, "Roughness is not implemented for the Baldwin-Lomax model.");
261 }
262 if (ksPlus > 2000.)
263 {
264 std::cout << "info: equivalent sand grain roughness ks+=" << ksPlus << " at " << asImp_().cellCenter(asImp_().wallElementIndex(elementIdx))
265 << " is not in the valid range (ksPlus < 2000),"
266 << " for high ksPlus values the roughness function reaches a turning point."<< std::endl;
267 DUNE_THROW(Dune::InvalidStateException, "Unphysical roughness behavior.");
268 }
269 else if (ksPlus > 0.0 && ksPlus < 4.535 && !printedRangeWarning)
270 {
271 Dune::dinfo << "info: equivalent sand grain roughness ks+=" << ksPlus << " at " << asImp_().cellCenter(asImp_().wallElementIndex(elementIdx))
272 << " is not in the valid range (ksPlus > 4.535) and now set to 0.0"<< std::endl;
273 ksPlus = 0.0;
274 printedRangeWarning = true;
275 }
276 additionalRoughnessLength_[elementIdx] = 0.9 / (volVars.uStar() / volVars.kinematicViscosity())
277 * (sqrt(ksPlus) - ksPlus * exp(-ksPlus / 6.0));
278 }
279 }
280 }
281
282 std::vector<Scalar> additionalRoughnessLength_;
283 std::vector<Scalar> kinematicEddyViscosity_;
284
286 Implementation &asImp_()
287 { return *static_cast<Implementation *>(this); }
288
290 const Implementation &asImp_() const
291 { return *static_cast<const Implementation *>(this); }
292};
293
294} // end namespace Dumux
295
296#endif
Base class for all finite-volume problems.
Definition: common/fvproblem.hh:43
Reynolds-Averaged Navier-Stokes problem base class.
Definition: freeflow/rans/problem.hh:47
void updateDynamicWallProperties(const SolutionVector &curSol)
Update the dynamic (solution dependent) relations to the walls.
Definition: freeflow/rans/zeroeq/problem.hh:98
RANSProblemImpl(std::shared_ptr< const GridGeometry > gridGeometry, const std::string &paramGroup="")
The constructor.
Definition: freeflow/rans/zeroeq/problem.hh:68
void updateStaticWallProperties()
Correct size of the static (solution independent) wall variables.
Definition: freeflow/rans/zeroeq/problem.hh:75
int additionalRoughnessLength(const int elementIdx) const
Definition: freeflow/rans/zeroeq/problem.hh:223
Scalar kinematicEddyViscosity(const int elementIdx) const
Definition: freeflow/rans/zeroeq/problem.hh:226
std::string eddyViscosityModel() const
Definition: freeflow/rans/zeroeq/problem.hh:217
void updateBaldwinLomaxProperties()
Update the relations and coefficients for the Baldwin-Lomax turbulence model.
Definition: freeflow/rans/zeroeq/problem.hh:114
forward declare
Definition: freeflow/rans/problem.hh:31
Defines all properties used in Dumux.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
TurbulenceModel
The available free flow turbulence models in Dumux.
Definition: turbulencemodel.hh:26
bool hasParam(const std::string &param)
Check whether a key exists in the parameter tree.
Definition: parameters.hh:157
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296
Free function to get the local view of a grid cache object.
The available discretization methods in Dumux.
Definition: adapt.hh:17
Adaption of the fully implicit scheme to the tracer transport model.
The local element solution class for staggered methods.
Base class for all staggered fv problems.
The available free flow turbulence models in Dumux.