version 3.9.0
Loading...
Searching...
No Matches
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
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.
the turbulence-model-specfic RANS problem
A single-phase, isothermal Reynolds-Averaged Navier-Stokes 0-Eq. model.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition localview.hh:26
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::cctpfa||GridGeometry::discMethod==DiscretizationMethods::ccmpfa, CCElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for cell-centered schemes.
Definition cellcentered/elementsolution.hh:101
TurbulenceModel
The available free flow turbulence models in Dumux.
Definition turbulencemodel.hh:26
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:149
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
PrimaryVariables makePriVarsFromCellCenterPriVars(const CellCenterPrimaryVariables &cellCenterPriVars)
Helper function to create a PrimaryVariables object from CellCenterPrimaryVariables.
Definition staggered/elementsolution.hh:29
Free function to get the local view of a grid cache object.
The available discretization methods in Dumux.
Definition adapt.hh:17
The local element solution class for staggered methods.
Base class for all staggered fv problems.
The available free flow turbulence models in Dumux.