3.5-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
freeflow/rans/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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
24#ifndef DUMUX_RANS_PROBLEM_HH
25#define DUMUX_RANS_PROBLEM_HH
26
27#include <algorithm>
28
29#include <dune/common/fmatrix.hh>
38#include "model.hh"
39
40namespace Dumux {
41
43template<class TypeTag, TurbulenceModel turbulenceModel>
45
47template<class TypeTag>
49
58template<class TypeTag>
59class RANSProblemBase : public NavierStokesProblem<TypeTag>
60{
62 using Implementation = GetPropType<TypeTag, Properties::Problem>;
63
65
67 using FVElementGeometry = typename GridGeometry::LocalView;
68 using GridView = typename GridGeometry::GridView;
69 using Element = typename GridView::template Codim<0>::Entity;
70 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
71 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
74 using PrimaryVariables = typename VolumeVariables::PrimaryVariables;
75 using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>;
78
79 using GlobalPosition = typename SubControlVolumeFace::GlobalPosition;
80
81 static constexpr auto dim = GridView::dimension;
82 static constexpr int numCorners = SubControlVolumeFace::numCornersPerFace;
83 using DimVector = GlobalPosition;
84 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
85
86 struct WallElementInformation
87 {
88 // store the element indicies for all elements with an intersection on the wall
89 unsigned int wallElementIdx;
90 // for each wall element, store the faces normal axis
91 unsigned int wallFaceNormalAxis;
92 // for each wall element, store the location of the face center and each corner.
93 GlobalPosition wallFaceCenter;
94 std::array<GlobalPosition, numCorners> wallFaceCorners;
95 };
96
97public:
98
104 RANSProblemBase(std::shared_ptr<const GridGeometry> gridGeometry, const std::string& paramGroup = "")
105 : ParentType(gridGeometry, paramGroup)
106 {
107 if ( !(hasParamInGroup(this->paramGroup(), "RANS.IsFlatWallBounded")))
108 {
109 std::cout << "The parameter \"Rans.IsFlatWallBounded\" is not specified. \n"
110 << " -- Based on the grid and the boundary conditions specified by the user,"
111 << " this parameter is set to be "<< std::boolalpha << isFlatWallBounded() << "\n";
112 }
113
114 // update size and initial values of the global vectors
115 wallDistance_.resize(this->gridGeometry().elementMapper().size(), std::numeric_limits<Scalar>::max());
116 neighborIdx_.resize(this->gridGeometry().elementMapper().size());
117 velocity_.resize(this->gridGeometry().elementMapper().size(), DimVector(0.0));
118 velocityGradients_.resize(this->gridGeometry().elementMapper().size(), DimMatrix(0.0));
119 stressTensorScalarProduct_.resize(this->gridGeometry().elementMapper().size(), 0.0);
120 vorticityTensorScalarProduct_.resize(this->gridGeometry().elementMapper().size(), 0.0);
121 flowDirectionAxis_.resize(this->gridGeometry().elementMapper().size(), fixedFlowDirectionAxis_);
122 storedViscosity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
123 storedDensity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
124 }
125
130 {
131 std::cout << "Update static wall properties. ";
133
134 checkForWalls_();
135 findWallDistances_();
136 findNeighborIndices_();
137 }
138
144 void updateDynamicWallProperties(const SolutionVector& curSol)
145 {
146 std::cout << "Update dynamic wall properties." << std::endl;
148 DUNE_THROW(Dune::InvalidStateException,
149 "You have to call updateStaticWallProperties() once before you call updateDynamicWallProperties().");
150
151 calculateCCVelocities_(curSol);
152 calculateCCVelocityGradients_();
153 calculateMaxMinVelocities_();
154 calculateStressTensor_();
155 calculateVorticityTensor_();
156 storeViscosities_(curSol);
157 }
158
166 bool useWallFunction(const Element& element,
167 const SubControlVolumeFace& scvf,
168 const int& eqIdx) const
169 { return false; }
170
174 template<class ElementVolumeVariables, class ElementFaceVariables>
175 FacePrimaryVariables wallFunction(const Element& element,
176 const FVElementGeometry& fvGeometry,
177 const ElementVolumeVariables& elemVolVars,
178 const ElementFaceVariables& elemFaceVars,
179 const SubControlVolumeFace& scvf,
180 const SubControlVolumeFace& lateralBoundaryFace) const
181 { return FacePrimaryVariables(0.0); }
182
186 template<class ElementVolumeVariables, class ElementFaceVariables>
187 CellCenterPrimaryVariables wallFunction(const Element& element,
188 const FVElementGeometry& fvGeometry,
189 const ElementVolumeVariables& elemVolVars,
190 const ElementFaceVariables& elemFaceVars,
191 const SubControlVolumeFace& scvf) const
192 { return CellCenterPrimaryVariables(0.0); }
193
199 [[deprecated("The isOnWall and IsOnWallAtPos functions will be removed after release 3.5. "
200 "Please use the Rans specific boundarytypes, and mark wall boundaries with the setWall() function.")]]
201 bool isOnWall(const SubControlVolumeFace& scvf) const
202 {
203 return asImp_().isOnWallAtPos(scvf.center());
204 }
205
206 bool isFlatWallBounded() const
207 {
208 static const bool hasAlignedWalls = hasAlignedWalls_();
209 return hasAlignedWalls;
210 }
211
215 const Scalar karmanConstant() const
216 { return 0.41; }
217
219 const Scalar betaOmega() const
220 {
221 return 0.0708;
222 }
223
229 {
230 static const Scalar turbulentPrandtlNumber
231 = getParamFromGroup<Scalar>(this->paramGroup(), "RANS.TurbulentPrandtlNumber", 1.0);
233 }
234
240 {
241 static const Scalar turbulentSchmidtNumber
242 = getParamFromGroup<Scalar>(this->paramGroup(), "RANS.TurbulentSchmidtNumber", 1.0);
244 }
245
246 int wallNormalAxis(const int elementIdx) const
247 {
248 if (!isFlatWallBounded())
249 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, models requiring a wallNormalAxis "
250 << "can only be used for flat wall bounded flows. "
251 << "\n If your geometry is a flat channel, "
252 << "please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
253 return wallNormalAxis_[elementIdx];
254 }
255
256 int flowDirectionAxis(const int elementIdx) const
257 {
258 if (!isFlatWallBounded())
259 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, models requiring a flowDirectionAxis "
260 << "can only be used for flat wall bounded flows. "
261 << "\n If your geometry is a flat channel, "
262 << "please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
263 return flowDirectionAxis_[elementIdx];
264 }
265
266 unsigned int wallElementIndex(const int elementIdx) const
267 {
268 if (!isFlatWallBounded())
269 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, models requiring a wallElementIndex "
270 << "can only be used for flat wall bounded flows. "
271 << "\n If your geometry is a flat channel, "
272 << "please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
273 return wallElementIdx_[elementIdx];
274
275 }
276
277 Scalar wallDistance(const int elementIdx) const
278 { return wallDistance_[elementIdx]; }
279
280 GlobalPosition cellCenter(const int elementIdx) const
281 {
282 const auto& element = this->gridGeometry().element(elementIdx);
283 return element.geometry().center();
284 }
285
286 unsigned int neighborIndex(const int elementIdx, const int axisIdx, const int sideIdx) const
287 { return neighborIdx_[elementIdx][axisIdx][sideIdx];}
288
289 DimVector ccVelocityVector(const int elementIdx) const
290 { return velocity_[elementIdx]; }
291
292 Scalar ccVelocity(const int elementIdx, const int axisIdx) const
293 { return velocity_[elementIdx][axisIdx]; }
294
295 DimVector velocityMaximum(const int elementIdx) const
296 { return velocityMaximum_[elementIdx]; }
297
298 DimVector velocityMinimum(const int elementIdx) const
299 { return velocityMinimum_[elementIdx]; }
300
301 DimMatrix velocityGradientTensor(const int elementIdx) const
302 { return velocityGradients_[elementIdx]; }
303
304 Scalar velocityGradient(const int elementIdx, const int i, const int j) const
305 { return velocityGradients_[elementIdx][i][j]; }
306
307 Scalar stressTensorScalarProduct(const int elementIdx) const
308 { return stressTensorScalarProduct_[elementIdx]; }
309
310 Scalar vorticityTensorScalarProduct(const int elementIdx) const
311 { return vorticityTensorScalarProduct_[elementIdx]; }
312
313 Scalar storedViscosity(const int elementIdx) const
314 { return storedViscosity_[elementIdx]; }
315
316 Scalar storedDensity(const int elementIdx) const
317 { return storedDensity_[elementIdx]; }
318
319 Scalar kinematicViscosity(const int elementIdx) const
320 { return storedViscosity(elementIdx) / storedDensity(elementIdx); }
321
323
324private:
325
326 bool hasAlignedWalls_() const
327 {
328 if ( hasParamInGroup(this->paramGroup(), "RANS.IsFlatWallBounded"))
329 {
330 static const bool isFlatWallBounded = getParamFromGroup<bool>(this->paramGroup(), "RANS.IsFlatWallBounded");
331 return isFlatWallBounded;
332 }
333
334 std::vector<int> wallFaceAxis;
335 wallFaceAxis.reserve(this->gridGeometry().numBoundaryScvf());
336
337 const auto gridView = this->gridGeometry().gridView();
338 auto fvGeometry = localView(this->gridGeometry());
339 for (const auto& element : elements(gridView))
340 {
341 fvGeometry.bindElement(element);
342 for (const auto& scvf : scvfs(fvGeometry))
343 {
344 // Remove this check after release 3.5. IsOnWall Interface is deprecated
345 if constexpr (Deprecated::hasIsOnWall<Implementation, GlobalPosition>())
346 {
347 // Remove this part
348 if (!scvf.boundary() && asImp_().isOnWall(scvf)) // only search for walls at a global boundary
349 wallFaceAxis.push_back(scvf.directionIndex());
350 }
351 else
352 {
353 // Keep this part
354 if (!scvf.boundary() && asImp_().boundaryTypes(element, scvf).hasWall()) // only search for walls at a global boundary
355 wallFaceAxis.push_back(scvf.directionIndex());
356 }
357 }
358 }
359
360 // Returns if all wall directions are the same
361 return std::all_of(wallFaceAxis.begin(), wallFaceAxis.end(), [firstDir=wallFaceAxis[0]](auto dir){ return (dir == firstDir);} ) ;
362 }
363
364 void checkForWalls_()
365 {
366 for (const auto& element : elements(this->gridGeometry().gridView()))
367 {
368 auto fvGeometry = localView(this->gridGeometry());
369 fvGeometry.bindElement(element);
370 for (auto&& scvf : scvfs(fvGeometry))
371 if constexpr (!Deprecated::hasIsOnWall<Implementation, GlobalPosition>())
372 if (asImp_().boundaryTypes(element, scvf).hasWall())
373 return;
374 }
375
376 // If reached, no walls were found, throw exception. Remove check after 3.5
377 if constexpr (!Deprecated::hasIsOnWall<Implementation, GlobalPosition>())
378 DUNE_THROW(Dune::InvalidStateException, "No walls are are specified with the setWall() function");
379 }
380
386 void findWallDistances_()
387 {
388 // Remove this check after release 3.5. IsOnWall Interface is deprecated
389 if constexpr (Deprecated::hasIsOnWall<Implementation, GlobalPosition>())
390 {
391 WallDistance wallInformation(this->gridGeometry(), WallDistance<GridGeometry>::atElementCenters,
392 [this] (const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf)
393 { return asImp_().isOnWall(scvf); });
394 wallDistance_ = wallInformation.wallDistance();
395 storeWallElementAndDirectionIndex_(wallInformation.wallData());
396 }
397 else
398 {
399 WallDistance wallInformation(this->gridGeometry(), WallDistance<GridGeometry>::atElementCenters,
400 [this] (const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvf)
401 { return asImp_().boundaryTypes(fvGeometry.element(), scvf).hasWall(); });
402 wallDistance_ = wallInformation.wallDistance();
403 storeWallElementAndDirectionIndex_(wallInformation.wallData());
404 }
405 }
406
407 template <class WallData>
408 void storeWallElementAndDirectionIndex_(const WallData& wallData)
409 {
410 // The wall Direction Index is used for flat quadrilateral channel problems only
411 if (!(GridGeometry::discMethod == DiscretizationMethods::staggered))
412 DUNE_THROW(Dune::NotImplemented, "The wall direction Index can only be calculated for quadrilateral structured grids");
413
414 // If isFlatWallBounded, the corresonding wall element is stored for each element
415 if (isFlatWallBounded())
416 {
417 wallNormalAxis_.resize(wallData.size());
418 wallElementIdx_.resize(wallData.size());
419
420 for (const auto& element : elements(this->gridGeometry().gridView()))
421 {
422 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
423 wallElementIdx_[elementIdx] = wallData[elementIdx].eIdx;
424 if ( ! (hasParam("RANS.WallNormalAxis")) )
425 {
426 GlobalPosition wallOuterNormal = wallData[elementIdx].scvfOuterNormal;
427 if constexpr (dim == 2) // 2D
428 wallNormalAxis_[elementIdx] = (wallOuterNormal[0] == 1) ? 0 : 1;
429 else // 3D
430 wallNormalAxis_[elementIdx] = (wallOuterNormal[0] == 1) ? 0 : ((wallOuterNormal[1] == 1) ? 1 : 2);
431 }
432 else
433 wallNormalAxis_[elementIdx] = fixedWallNormalAxis_;
434 }
435 }
436 }
437
441 void findNeighborIndices_()
442 {
443 // search for neighbor Idxs
444 for (const auto& element : elements(this->gridGeometry().gridView()))
445 {
446 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
447 for (unsigned int axisIdx = 0; axisIdx < dim; ++axisIdx)
448 {
449 neighborIdx_[elementIdx][axisIdx][0] = elementIdx;
450 neighborIdx_[elementIdx][axisIdx][1] = elementIdx;
451 }
452
453 for (const auto& intersection : intersections(this->gridGeometry().gridView(), element))
454 {
455 if (intersection.boundary())
456 continue;
457
458 unsigned int neighborIdx = this->gridGeometry().elementMapper().index(intersection.outside());
459 for (unsigned int axisIdx = 0; axisIdx < dim; ++axisIdx)
460 {
461 if (abs(cellCenter(elementIdx)[axisIdx] - cellCenter(neighborIdx)[axisIdx]) > 1e-8)
462 {
463 if (cellCenter(elementIdx)[axisIdx] > cellCenter(neighborIdx)[axisIdx])
464 neighborIdx_[elementIdx][axisIdx][0] = neighborIdx;
465
466 if (cellCenter(elementIdx)[axisIdx] < cellCenter(neighborIdx)[axisIdx])
467 neighborIdx_[elementIdx][axisIdx][1] = neighborIdx;
468 }
469 }
470 }
471 }
472 }
473
474 void calculateCCVelocities_(const SolutionVector& curSol)
475 {
476 auto fvGeometry = localView(this->gridGeometry());
477 // calculate cell-center-averaged velocities
478 for (const auto& element : elements(this->gridGeometry().gridView()))
479 {
480 fvGeometry.bindElement(element);
481 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
482
483 // calculate velocities
484 DimVector velocityTemp(0.0);
485 for (auto&& scvf : scvfs(fvGeometry))
486 {
487 const int dofIdxFace = scvf.dofIndex();
488 const auto numericalSolutionFace = curSol[GridGeometry::faceIdx()][dofIdxFace][Indices::velocity(scvf.directionIndex())];
489 velocityTemp[scvf.directionIndex()] += numericalSolutionFace;
490 }
491 for (unsigned int axisIdx = 0; axisIdx < dim; ++axisIdx)
492 velocity_[elementIdx][axisIdx] = velocityTemp[axisIdx] * 0.5; // faces are equidistant to cell center
493 }
494 }
495
496
497 void calculateCCVelocityGradients_()
498 {
499 using std::abs;
500
501 // calculate cell-center-averaged velocity gradients, maximum, and minimum values
502 auto fvGeometry = localView(this->gridGeometry());
503 for (const auto& element : elements(this->gridGeometry().gridView()))
504 {
505 const unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
506
507 for (unsigned int j = 0; j < dim; ++j)
508 {
509 for (unsigned int i = 0; i < dim; ++i)
510 {
511 const unsigned int neighborIndex0 = neighborIndex(elementIdx, j, 0);
512 const unsigned int neighborIndex1 = neighborIndex(elementIdx, j, 1);
513
514 velocityGradients_[elementIdx][i][j]
515 = (ccVelocity(neighborIndex1, i) - ccVelocity(neighborIndex0, i))
516 / (cellCenter(neighborIndex1)[j] - cellCenter(neighborIndex0)[j]);
517
518 if (abs(cellCenter(neighborIndex1)[j] - cellCenter(neighborIndex0)[j]) < 1e-8)
519 velocityGradients_[elementIdx][i][j] = 0.0;
520 }
521 }
522
523 fvGeometry.bindElement(element);
524 for (auto&& scvf : scvfs(fvGeometry))
525 {
526 // adapt calculations for Dirichlet condition
527 unsigned int axisIdx = scvf.directionIndex();
528 if (scvf.boundary())
529 {
530 for (unsigned int velIdx = 0; velIdx < dim; ++velIdx)
531 {
532 if (!asImp_().boundaryTypes(element, scvf).isDirichlet(Indices::velocity(velIdx)))
533 continue;
534
535 Scalar dirichletVelocity = asImp_().dirichlet(element, scvf)[Indices::velocity(velIdx)];
536
537 unsigned int neighborIdx = neighborIndex(elementIdx, axisIdx, 0);
538 if (scvf.center()[axisIdx] < cellCenter(elementIdx)[axisIdx])
539 neighborIdx = neighborIndex(elementIdx, axisIdx, 1);
540
541 velocityGradients_[elementIdx][velIdx][axisIdx]
542 = (ccVelocity(neighborIdx, velIdx) - dirichletVelocity)
543 / (cellCenter(neighborIdx)[axisIdx] - scvf.center()[axisIdx]);
544 }
545 }
546
547 // Calculate the BJS-velocity by accounting for all sub faces.
548 std::vector<int> bjsNumFaces(dim, 0);
549 std::vector<unsigned int> bjsNeighbor(dim, 0);
550 DimVector bjsVelocityAverage(0.0);
551 DimVector normalNormCoordinate(0.0);
552 unsigned int velCompIdx = Indices::velocity(scvf.directionIndex());
553 const int numSubFaces = scvf.pairData().size();
554 for(int localSubFaceIdx = 0; localSubFaceIdx < numSubFaces; ++localSubFaceIdx)
555 {
556 const auto& lateralFace = fvGeometry.scvf(scvf.insideScvIdx(), scvf.pairData()[localSubFaceIdx].localLateralFaceIdx);
557
558 // adapt calculations for Beavers-Joseph-Saffman condition
559 unsigned int lateralAxisIdx = lateralFace.directionIndex();
560 if (lateralFace.boundary() && (asImp_().boundaryTypes(element, lateralFace).isBeaversJoseph(Indices::velocity(velCompIdx))))
561 {
562 unsigned int neighborIdx = neighborIndex(elementIdx, lateralAxisIdx, 0);
563 if (lateralFace.center()[lateralAxisIdx] < cellCenter(elementIdx)[lateralAxisIdx])
564 neighborIdx = neighborIndex(elementIdx, lateralAxisIdx, 1);
565
566 const SubControlVolume& scv = fvGeometry.scv(scvf.insideScvIdx());
567 bjsVelocityAverage[lateralAxisIdx] += ParentType::beaversJosephVelocity(element, scv, scvf, lateralFace, ccVelocity(elementIdx, velCompIdx), 0.0);
568 if (bjsNumFaces[lateralAxisIdx] > 0 && neighborIdx != bjsNeighbor[lateralAxisIdx])
569 DUNE_THROW(Dune::InvalidStateException, "Two different neighborIdx should not occur");
570 bjsNeighbor[lateralAxisIdx] = neighborIdx;
571 normalNormCoordinate[lateralAxisIdx] = lateralFace.center()[lateralAxisIdx];
572 bjsNumFaces[lateralAxisIdx]++;
573 }
574 }
575 for (unsigned axisIdx = 0; axisIdx < dim; ++axisIdx)
576 {
577 if (bjsNumFaces[axisIdx] == 0)
578 continue;
579
580 unsigned int neighborIdx = bjsNeighbor[axisIdx];
581 bjsVelocityAverage[axisIdx] /= bjsNumFaces[axisIdx];
582
583 velocityGradients_[elementIdx][velCompIdx][axisIdx]
584 = (ccVelocity(neighborIdx, velCompIdx) - bjsVelocityAverage[axisIdx])
585 / (cellCenter(neighborIdx)[axisIdx] - normalNormCoordinate[axisIdx]);
586
587 }
588 }
589 }
590 }
591
592 void calculateMaxMinVelocities_()
593 {
594 using std::abs;
595 if (isFlatWallBounded())
596 {
597 // If the parameter isFlatWallBounded is set to true,
598 // the maximum/minimum velocities are calculated along a profile perpendicular to the corresponding wall face.
599
600 // re-initialize min and max values
601 velocityMaximum_.assign(this->gridGeometry().elementMapper().size(), DimVector(1e-16));
602 velocityMinimum_.assign(this->gridGeometry().elementMapper().size(), DimVector(std::numeric_limits<Scalar>::max()));
603
604 // For each profile perpendicular to the channel wall, find the max and minimum velocities
605 for (const auto& element : elements(this->gridGeometry().gridView()))
606 {
607 const unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
608 Scalar maxVelocity = 0.0;
609 const unsigned int wallElementIdx = wallElementIndex(elementIdx);
610
611 for (unsigned int axisIdx = 0; axisIdx < dim; ++axisIdx)
612 {
613 if (abs(ccVelocity(elementIdx, axisIdx)) > abs(velocityMaximum_[wallElementIdx][axisIdx]))
614 velocityMaximum_[wallElementIdx][axisIdx] = ccVelocity(elementIdx, axisIdx);
615
616 if (abs(ccVelocity(elementIdx, axisIdx)) < abs(velocityMinimum_[wallElementIdx][axisIdx]))
617 velocityMinimum_[wallElementIdx][axisIdx] = ccVelocity(elementIdx, axisIdx);
618
619 // Set the flow direction axis as the direction of the max velocity
620 if ((hasParam("RANS.FlowDirectionAxis") != 1) && (maxVelocity) < abs(ccVelocity(elementIdx, axisIdx)))
621 {
622 maxVelocity = abs(ccVelocity(elementIdx, axisIdx));
623 flowDirectionAxis_[elementIdx] = axisIdx;
624 }
625 }
626 }
627 }
628 else
629 {
630 // If the parameter isFlatWallBounded is set to false, or not set,
631 // the maximum/minimum velocities are calculated as a global max/min throughout the domain.
632
633 DimVector maxVelocity(0.0);
634 DimVector minVelocity(std::numeric_limits<Scalar>::max());
635 // Find the max and minimum velocities in the full domain
636 for (const auto& element : elements(this->gridGeometry().gridView()))
637 {
638 const unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
639
640 for (unsigned int axisIdx = 0; axisIdx < dim; ++axisIdx)
641 {
642 if (abs(ccVelocity(elementIdx, axisIdx)) > abs(maxVelocity[axisIdx]))
643 maxVelocity[axisIdx] = ccVelocity(elementIdx, axisIdx);
644
645 if (abs(ccVelocity(elementIdx, axisIdx)) < abs(minVelocity[axisIdx]))
646 minVelocity[axisIdx] = ccVelocity(elementIdx, axisIdx);
647 }
648 }
649 velocityMaximum_.assign(this->gridGeometry().elementMapper().size(), maxVelocity);
650 velocityMinimum_.assign(this->gridGeometry().elementMapper().size(), minVelocity);
651 }
652 }
653
654 void calculateStressTensor_()
655 {
656 for (const auto& element : elements(this->gridGeometry().gridView()))
657 {
658 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
659 Dune::FieldMatrix<Scalar, GridView::dimension, GridView::dimension> stressTensor(0.0);
660 for (unsigned int j = 0; j < dim; ++j)
661 {
662 for (unsigned int i = 0; i < dim; ++i)
663 {
664 stressTensor[j][i] = 0.5 * velocityGradient(elementIdx, j, i)
665 + 0.5 * velocityGradient(elementIdx, i, j);
666 }
667 }
668 stressTensorScalarProduct_[elementIdx] = 0.0;
669 for (unsigned int j = 0; j < dim; ++j)
670 {
671 for (unsigned int i = 0; i < dim; ++i)
672 {
673 stressTensorScalarProduct_[elementIdx] += stressTensor[j][i] * stressTensor[j][i];
674 }
675 }
676 }
677 }
678
679 void calculateVorticityTensor_()
680 {
681 for (const auto& element : elements(this->gridGeometry().gridView()))
682 {
683 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
684 Dune::FieldMatrix<Scalar, GridView::dimension, GridView::dimension> vorticityTensor(0.0);
685 for (unsigned int j = 0; j < dim; ++j)
686 {
687 for (unsigned int i = 0; i < dim; ++i)
688 {
689 vorticityTensor[j][i] = 0.5 * velocityGradient(elementIdx, j, i)
690 - 0.5 * velocityGradient(elementIdx, i, j);
691 }
692 }
693 vorticityTensorScalarProduct_[elementIdx] = 0.0;
694 for (unsigned int j = 0; j < dim; ++j)
695 {
696 for (unsigned int i = 0; i < dim; ++i)
697 {
698 vorticityTensorScalarProduct_[elementIdx] += vorticityTensor[j][i] * vorticityTensor[j][i];
699 }
700 }
701 }
702 }
703
704 void storeViscosities_(const SolutionVector& curSol)
705 {
706 // calculate or call all secondary variables
707 auto fvGeometry = localView(this->gridGeometry());
708 for (const auto& element : elements(this->gridGeometry().gridView()))
709 {
710 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
711 fvGeometry.bindElement(element);
712 for (auto&& scv : scvs(fvGeometry))
713 {
714 const int dofIdx = scv.dofIndex();
715 // construct a privars object from the cell center solution vector
716 const auto& cellCenterPriVars = curSol[GridGeometry::cellCenterIdx()][dofIdx];
717 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(cellCenterPriVars);
718 auto elemSol = elementSolution<typename GridGeometry::LocalView>(std::move(priVars));
719
720 VolumeVariables volVars;
721 volVars.update(elemSol, asImp_(), element, scv);
722 storedDensity_[elementIdx] = volVars.density();
723 storedViscosity_[elementIdx] = volVars.viscosity();
724 }
725 }
726 }
727
728 const int fixedFlowDirectionAxis_ = getParam<int>("RANS.FlowDirectionAxis", 0);
729 const int fixedWallNormalAxis_ = getParam<int>("RANS.WallNormalAxis", 1);
730
731 std::vector<unsigned int> wallNormalAxis_;
732 std::vector<unsigned int> flowDirectionAxis_;
733 std::vector<Scalar> wallDistance_;
734 std::vector<unsigned int> wallElementIdx_;
735 std::vector<std::array<std::array<unsigned int, 2>, dim>> neighborIdx_;
736
737 std::vector<DimVector> velocity_;
738 std::vector<DimVector> velocityMaximum_;
739 std::vector<DimVector> velocityMinimum_;
740 std::vector<DimMatrix> velocityGradients_;
741
742 std::vector<Scalar> stressTensorScalarProduct_;
743 std::vector<Scalar> vorticityTensorScalarProduct_;
744
745 std::vector<Scalar> storedDensity_;
746 std::vector<Scalar> storedViscosity_;
747
749 Implementation &asImp_()
750 { return *static_cast<Implementation *>(this); }
751
753 const Implementation &asImp_() const
754 { return *static_cast<const Implementation *>(this); }
755};
756
757} // end namespace Dumux
758
759#endif
Helpers for deprecation.
Base class for all staggered fv problems.
Free function to get the local view of a grid cache object.
The available discretization methods in Dumux.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:38
bool hasParamInGroup(const std::string &paramGroup, const std::string &param)
Check whether a key exists in the parameter tree with a model group prefix.
Definition: parameters.hh:177
bool hasParam(const std::string &param)
Check whether a key exists in the parameter tree.
Definition: parameters.hh:169
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
constexpr Staggered staggered
Definition: method.hh:140
static constexpr auto atElementCenters
Definition: walldistance.hh:113
Definition: freeflow/navierstokes/problem.hh:55
forward declare
Definition: freeflow/rans/problem.hh:44
Reynolds-Averaged Navier-Stokes problem base class.
Definition: freeflow/rans/problem.hh:60
unsigned int wallElementIndex(const int elementIdx) const
Definition: freeflow/rans/problem.hh:266
int flowDirectionAxis(const int elementIdx) const
Definition: freeflow/rans/problem.hh:256
void updateDynamicWallProperties(const SolutionVector &curSol)
Update the dynamic (solution dependent) turbulence parameters.
Definition: freeflow/rans/problem.hh:144
DimMatrix velocityGradientTensor(const int elementIdx) const
Definition: freeflow/rans/problem.hh:301
Scalar vorticityTensorScalarProduct(const int elementIdx) const
Definition: freeflow/rans/problem.hh:310
Scalar ccVelocity(const int elementIdx, const int axisIdx) const
Definition: freeflow/rans/problem.hh:292
void updateStaticWallProperties()
Update the static (solution independent) relations to the walls and neighbors.
Definition: freeflow/rans/problem.hh:129
GlobalPosition cellCenter(const int elementIdx) const
Definition: freeflow/rans/problem.hh:280
FacePrimaryVariables wallFunction(const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars, const SubControlVolumeFace &scvf, const SubControlVolumeFace &lateralBoundaryFace) const
Returns an additional wall function momentum flux.
Definition: freeflow/rans/problem.hh:175
Scalar velocityGradient(const int elementIdx, const int i, const int j) const
Definition: freeflow/rans/problem.hh:304
DimVector velocityMaximum(const int elementIdx) const
Definition: freeflow/rans/problem.hh:295
const Scalar betaOmega() const
Returns the constant.
Definition: freeflow/rans/problem.hh:219
DimVector ccVelocityVector(const int elementIdx) const
Definition: freeflow/rans/problem.hh:289
Scalar kinematicViscosity(const int elementIdx) const
Definition: freeflow/rans/problem.hh:319
Scalar turbulentSchmidtNumber() const
Return the turbulent Schmidt number which is used to convert the eddy viscosity to an eddy diffusivi...
Definition: freeflow/rans/problem.hh:239
CellCenterPrimaryVariables wallFunction(const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars, const SubControlVolumeFace &scvf) const
Returns an additional wall function flux for cell-centered quantities.
Definition: freeflow/rans/problem.hh:187
DimVector velocityMinimum(const int elementIdx) const
Definition: freeflow/rans/problem.hh:298
Scalar wallDistance(const int elementIdx) const
Definition: freeflow/rans/problem.hh:277
Scalar storedDensity(const int elementIdx) const
Definition: freeflow/rans/problem.hh:316
Scalar turbulentPrandtlNumber() const
Return the turbulent Prandtl number which is used to convert the eddy viscosity to an eddy thermal c...
Definition: freeflow/rans/problem.hh:228
int wallNormalAxis(const int elementIdx) const
Definition: freeflow/rans/problem.hh:246
unsigned int neighborIndex(const int elementIdx, const int axisIdx, const int sideIdx) const
Definition: freeflow/rans/problem.hh:286
RANSProblemBase(std::shared_ptr< const GridGeometry > gridGeometry, const std::string &paramGroup="")
The constructor.
Definition: freeflow/rans/problem.hh:104
bool isFlatWallBounded() const
Definition: freeflow/rans/problem.hh:206
Scalar stressTensorScalarProduct(const int elementIdx) const
Definition: freeflow/rans/problem.hh:307
bool calledUpdateStaticWallProperties
Definition: freeflow/rans/problem.hh:322
bool useWallFunction(const Element &element, const SubControlVolumeFace &scvf, const int &eqIdx) const
Returns whether a wall function should be used at a given face.
Definition: freeflow/rans/problem.hh:166
const Scalar karmanConstant() const
Returns the Karman constant.
Definition: freeflow/rans/problem.hh:215
Scalar storedViscosity(const int elementIdx) const
Definition: freeflow/rans/problem.hh:313
bool isOnWall(const SubControlVolumeFace &scvf) const
Returns whether a given sub control volume face is on a wall.
Definition: freeflow/rans/problem.hh:201
Declares all properties used in Dumux.
Adaption of the fully implicit scheme to the tracer transport model.
The local element solution class for staggered methods.