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