3.3.0
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>
36
37#include "model.hh"
38
39namespace Dumux {
40
42template<class TypeTag, TurbulenceModel turbulenceModel>
44
46template<class TypeTag>
48
57template<class TypeTag>
58class RANSProblemBase : public NavierStokesProblem<TypeTag>
59{
60 using ParentType = NavierStokesProblem<TypeTag>;
61 using Implementation = GetPropType<TypeTag, Properties::Problem>;
62
64
66 using FVElementGeometry = typename GridGeometry::LocalView;
67 using GridView = typename GridGeometry::GridView;
68 using Element = typename GridView::template Codim<0>::Entity;
69 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
70 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
73 using PrimaryVariables = typename VolumeVariables::PrimaryVariables;
74 using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>;
77
78 using GlobalPosition = typename SubControlVolumeFace::GlobalPosition;
79
80 static constexpr auto dim = GridView::dimension;
81 static constexpr int numCorners = SubControlVolumeFace::numCornersPerFace;
82 using DimVector = GlobalPosition;
83 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
84
85 struct WallElementInformation
86 {
87 // store the element indicies for all elements with an intersection on the wall
88 unsigned int wallElementIdx;
89 // for each wall element, store the faces normal axis
90 unsigned int wallFaceNormalAxis;
91 // for each wall element, store the location of the face center and each corner.
92 GlobalPosition wallFaceCenter;
93 std::array<GlobalPosition, numCorners> wallFaceCorners;
94 };
95
96public:
102 RANSProblemBase(std::shared_ptr<const GridGeometry> gridGeometry, const std::string& paramGroup = "")
103 : ParentType(gridGeometry, paramGroup)
104 { }
105
113 {
114 using std::abs;
115 std::cout << "Update static wall properties. ";
117
118 // update size and initial values of the global vectors
119 wallElementIdx_.resize(this->gridGeometry().elementMapper().size());
120 wallDistance_.resize(this->gridGeometry().elementMapper().size(), std::numeric_limits<Scalar>::max());
121 neighborIdx_.resize(this->gridGeometry().elementMapper().size());
122 cellCenter_.resize(this->gridGeometry().elementMapper().size(), GlobalPosition(0.0));
123 velocity_.resize(this->gridGeometry().elementMapper().size(), DimVector(0.0));
124 velocityGradients_.resize(this->gridGeometry().elementMapper().size(), DimMatrix(0.0));
125 stressTensorScalarProduct_.resize(this->gridGeometry().elementMapper().size(), 0.0);
126 vorticityTensorScalarProduct_.resize(this->gridGeometry().elementMapper().size(), 0.0);
127 flowDirectionAxis_.resize(this->gridGeometry().elementMapper().size(), fixedFlowDirectionAxis_);
128 wallNormalAxis_.resize(this->gridGeometry().elementMapper().size(), fixedWallNormalAxis_);
129 storedViscosity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
130 storedDensity_.resize(this->gridGeometry().elementMapper().size(), 0.0);
131
132 if ( !(hasParamInGroup(this->paramGroup(), "RANS.IsFlatWallBounded")))
133 {
134 std::cout << "The parameter \"Rans.IsFlatWallBounded\" is not specified. \n"
135 << " -- Based on the grid and the isOnWallAtPos function specified by the user,"
136 << " this parameter is set to be "<< std::boolalpha << isFlatWallBounded() << "\n";
137 }
138
139 std::vector<WallElementInformation> wallElements;
140
141 const auto gridView = this->gridGeometry().gridView();
142 auto fvGeometry = localView(this->gridGeometry());
143
144 for (const auto& element : elements(gridView))
145 {
146 fvGeometry.bindElement(element);
147 for (const auto& scvf : scvfs(fvGeometry))
148 {
149 // only search for walls at a global boundary
150 if (!scvf.boundary())
151 continue;
152
153 if (asImp_().isOnWall(scvf))
154 {
155 WallElementInformation wallElementInformation;
156
157 // store the location of the wall adjacent face's center and all corners
158 wallElementInformation.wallFaceCenter = scvf.center();
159 for (int i = 0; i < numCorners; i++)
160 wallElementInformation.wallFaceCorners[i] = scvf.corner(i);
161
162 // Store the wall element index and face's normal direction (used only with isFlatWallBounded on)
163 wallElementInformation.wallElementIdx = this->gridGeometry().elementMapper().index(element);
164 wallElementInformation.wallFaceNormalAxis = scvf.directionIndex();
165
166 wallElements.push_back(wallElementInformation);
167 }
168 }
169 }
170 // output the number of wall adjacent faces. Check that this is non-zero.
171 std::cout << "NumWallIntersections=" << wallElements.size() << std::endl;
172 if (wallElements.size() == 0)
173 DUNE_THROW(Dune::InvalidStateException,
174 "No wall intersections have been found. Make sure that the isOnWall(globalPos) is working properly.");
175
176 // search for shortest distance to the wall for each element
177 for (const auto& element : elements(gridView))
178 {
179 // Store the cell center position for each element
180 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
181 cellCenter_[elementIdx] = element.geometry().center();
182
183 for (unsigned int i = 0; i < wallElements.size(); ++i)
184 {
185 // Find the minimum distance from the cell center to the wall face (center and corners)
186 std::array<Scalar,numCorners+1> cellToWallDistances;
187 for (unsigned int j = 0; j < numCorners; j++)
188 cellToWallDistances[j] = (cellCenter(elementIdx) - wallElements[i].wallFaceCorners[j]).two_norm();
189 cellToWallDistances[numCorners] = (cellCenter(elementIdx) - wallElements[i].wallFaceCenter).two_norm();
190 Scalar distanceToWall = *std::min_element(cellToWallDistances.begin(), cellToWallDistances.end());
191
192 if (distanceToWall < wallDistance_[elementIdx])
193 {
194 wallDistance_[elementIdx] = distanceToWall;
195 // If isFlatWallBounded, the corresonding wall element is stored for each element
196 if (isFlatWallBounded())
197 {
198 wallElementIdx_[elementIdx] = wallElements[i].wallElementIdx;
199 if ( !(hasParam("RANS.WallNormalAxis")) )
200 wallNormalAxis_[elementIdx] = wallElements[i].wallFaceNormalAxis;
201 }
202 }
203 }
204 }
205
206 // search for neighbor Idxs
207 for (const auto& element : elements(gridView))
208 {
209 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
210 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
211 {
212 neighborIdx_[elementIdx][dimIdx][0] = elementIdx;
213 neighborIdx_[elementIdx][dimIdx][1] = elementIdx;
214 }
215
216 for (const auto& intersection : intersections(gridView, element))
217 {
218 if (intersection.boundary())
219 continue;
220
221 unsigned int neighborIdx = this->gridGeometry().elementMapper().index(intersection.outside());
222 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
223 {
224 if (abs(cellCenter(elementIdx)[dimIdx] - cellCenter(neighborIdx)[dimIdx]) > 1e-8)
225 {
226 if (cellCenter(elementIdx)[dimIdx] > cellCenter(neighborIdx)[dimIdx])
227 neighborIdx_[elementIdx][dimIdx][0] = neighborIdx;
228
229 if (cellCenter(elementIdx)[dimIdx] < cellCenter(neighborIdx)[dimIdx])
230 neighborIdx_[elementIdx][dimIdx][1] = neighborIdx;
231 }
232 }
233 }
234 }
235 }
236
246 void updateDynamicWallProperties(const SolutionVector& curSol)
247 {
248 std::cout << "Update dynamic wall properties." << std::endl;
250 DUNE_THROW(Dune::InvalidStateException,
251 "You have to call updateStaticWallProperties() once before you call updateDynamicWallProperties().");
252
253 calculateCCVelocities_(curSol);
254 calculateCCVelocityGradients_();
255 calculateMaxMinVelocities_();
256 calculateStressTensor_();
257 calculateVorticityTensor_();
258 storeViscosities_(curSol);
259 }
260
268 bool useWallFunction(const Element& element,
269 const SubControlVolumeFace& scvf,
270 const int& eqIdx) const
271 { return false; }
272
276 template<class ElementVolumeVariables, class ElementFaceVariables>
277 FacePrimaryVariables wallFunction(const Element& element,
278 const FVElementGeometry& fvGeometry,
279 const ElementVolumeVariables& elemVolVars,
280 const ElementFaceVariables& elemFaceVars,
281 const SubControlVolumeFace& scvf,
282 const SubControlVolumeFace& lateralBoundaryFace) const
283 { return FacePrimaryVariables(0.0); }
284
288 template<class ElementVolumeVariables, class ElementFaceVariables>
289 CellCenterPrimaryVariables wallFunction(const Element& element,
290 const FVElementGeometry& fvGeometry,
291 const ElementVolumeVariables& elemVolVars,
292 const ElementFaceVariables& elemFaceVars,
293 const SubControlVolumeFace& scvf) const
294 { return CellCenterPrimaryVariables(0.0); }
295
301 bool isOnWall(const SubControlVolumeFace& scvf) const
302 {
303 return asImp_().isOnWallAtPos(scvf.center());
304 }
305
311 bool isOnWallAtPos(const GlobalPosition &globalPos) const
312 {
313 // Throw an exception if no walls are implemented
314 DUNE_THROW(Dune::InvalidStateException,
315 "The problem does not provide an isOnWall() method.");
316 }
317
318 bool isFlatWallBounded() const
319 {
320 static const bool hasAlignedWalls = hasAlignedWalls_();
321 return hasAlignedWalls;
322 }
323
327 const Scalar karmanConstant() const
328 { return 0.41; }
329
331 const Scalar betaOmega() const
332 {
333 return 0.0708;
334 }
335
341 {
342 static const Scalar turbulentPrandtlNumber
343 = getParamFromGroup<Scalar>(this->paramGroup(), "RANS.TurbulentPrandtlNumber", 1.0);
345 }
346
352 {
353 static const Scalar turbulentSchmidtNumber
354 = getParamFromGroup<Scalar>(this->paramGroup(), "RANS.TurbulentSchmidtNumber", 1.0);
356 }
357
358 int wallNormalAxis(const int elementIdx) const
359 {
360 if (!isFlatWallBounded())
361 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, models requiring a wallNormalAxis can only be used for flat wall bounded flows. "
362 << "\n If your geometry is a flat channel, please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
363 return wallNormalAxis_[elementIdx];
364 }
365
366 int flowDirectionAxis(const int elementIdx) const
367 {
368 if (!isFlatWallBounded())
369 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, models requiring a flowDirectionAxis can only be used for flat wall bounded flows. "
370 << "\n If your geometry is a flat channel, please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
371 return flowDirectionAxis_[elementIdx];
372 }
373
374 unsigned int wallElementIndex(const int elementIdx) const
375 {
376 if (!isFlatWallBounded())
377 DUNE_THROW(Dune::NotImplemented, "\n Due to grid/geometric concerns, models requiring a wallElementIndex can only be used for flat wall bounded flows. "
378 << "\n If your geometry is a flat channel, please set the runtime parameter RANS.IsFlatWallBounded to true. \n");
379 return wallElementIdx_[elementIdx];
380
381 }
382
383 Scalar wallDistance(const int elementIdx) const
384 { return wallDistance_[elementIdx]; }
385
386 GlobalPosition cellCenter(const int elementIdx) const
387 { return cellCenter_[elementIdx]; }
388
389 unsigned int neighborIndex(const int elementIdx, const int dimIdx, const int sideIdx) const
390 { return neighborIdx_[elementIdx][dimIdx][sideIdx];}
391
392 DimVector ccVelocityVector(const int elementIdx) const
393 { return velocity_[elementIdx]; }
394
395 Scalar ccVelocity(const int elementIdx, const int dimIdx) const
396 { return velocity_[elementIdx][dimIdx]; }
397
398 DimVector velocityMaximum(const int elementIdx) const
399 { return velocityMaximum_[elementIdx]; }
400
401 DimVector velocityMinimum(const int elementIdx) const
402 { return velocityMinimum_[elementIdx]; }
403
404 DimMatrix velocityGradientTensor(const int elementIdx) const
405 { return velocityGradients_[elementIdx]; }
406
407 Scalar velocityGradient(const int elementIdx, const int dimIdx, const int velIdx) const
408 { return velocityGradients_[elementIdx][dimIdx][velIdx]; }
409
410 Scalar stressTensorScalarProduct(const int elementIdx) const
411 { return stressTensorScalarProduct_[elementIdx]; }
412
413 Scalar vorticityTensorScalarProduct(const int elementIdx) const
414 { return vorticityTensorScalarProduct_[elementIdx]; }
415
416 Scalar storedViscosity(const int elementIdx) const
417 { return storedViscosity_[elementIdx]; }
418
419 Scalar storedDensity(const int elementIdx) const
420 { return storedDensity_[elementIdx]; }
421
422 Scalar kinematicViscosity(const int elementIdx) const
423 { return storedViscosity(elementIdx) / storedDensity(elementIdx); }
424
426
427private:
428
429 bool hasAlignedWalls_() const
430 {
431 if ( hasParamInGroup(this->paramGroup(), "RANS.IsFlatWallBounded"))
432 {
433 static const bool isFlatWallBounded = getParamFromGroup<bool>(this->paramGroup(), "RANS.IsFlatWallBounded");
434 return isFlatWallBounded;
435 }
436
437 std::vector<int> wallFaceAxis;
438 wallFaceAxis.reserve(this->gridGeometry().numBoundaryScvf());
439
440 const auto gridView = this->gridGeometry().gridView();
441 auto fvGeometry = localView(this->gridGeometry());
442 for (const auto& element : elements(gridView))
443 {
444 fvGeometry.bindElement(element);
445 for (const auto& scvf : scvfs(fvGeometry))
446 {
447 // only search for walls at a global boundary
448 if (!scvf.boundary() && asImp_().isOnWall(scvf))
449 wallFaceAxis.push_back(scvf.directionIndex());
450 }
451 }
452
453 // Returns if all wall directions are the same
454 return std::all_of(wallFaceAxis.begin(), wallFaceAxis.end(), [firstDir=wallFaceAxis[0]](auto dir){ return (dir == firstDir);} ) ;
455 }
456
457 void calculateCCVelocities_(const SolutionVector& curSol)
458 {
459 // calculate cell-center-averaged velocities
460 for (const auto& element : elements(this->gridGeometry().gridView()))
461 {
462 auto fvGeometry = localView(this->gridGeometry());
463 fvGeometry.bindElement(element);
464 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
465
466 // calculate velocities
467 DimVector velocityTemp(0.0);
468 for (auto&& scvf : scvfs(fvGeometry))
469 {
470 const int dofIdxFace = scvf.dofIndex();
471 const auto numericalSolutionFace = curSol[GridGeometry::faceIdx()][dofIdxFace][Indices::velocity(scvf.directionIndex())];
472 velocityTemp[scvf.directionIndex()] += numericalSolutionFace;
473 }
474 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
475 velocity_[elementIdx][dimIdx] = velocityTemp[dimIdx] * 0.5; // faces are equidistant to cell center
476 }
477 }
478
479
480 void calculateCCVelocityGradients_()
481 {
482 using std::abs;
483 // calculate cell-center-averaged velocity gradients, maximum, and minimum values
484 for (const auto& element : elements(this->gridGeometry().gridView()))
485 {
486 const unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
487 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
488 {
489 for (unsigned int velIdx = 0; velIdx < dim; ++velIdx)
490 {
491 const unsigned int neighborIndex0 = neighborIndex(elementIdx, dimIdx, 0);
492 const unsigned int neighborIndex1 = neighborIndex(elementIdx, dimIdx, 1);
493
494 velocityGradients_[elementIdx][velIdx][dimIdx]
495 = (ccVelocity(neighborIndex1, velIdx) - ccVelocity(neighborIndex0, velIdx))
496 / (cellCenter(neighborIndex1)[dimIdx] - cellCenter(neighborIndex0)[dimIdx]);
497
498 if (abs(cellCenter(neighborIndex1)[dimIdx] - cellCenter(neighborIndex0)[dimIdx]) < 1e-8)
499 velocityGradients_[elementIdx][velIdx][dimIdx] = 0.0;
500 }
501 }
502
503 auto fvGeometry = localView(this->gridGeometry());
504 fvGeometry.bindElement(element);
505 for (auto&& scvf : scvfs(fvGeometry))
506 {
507 // adapt calculations for Dirichlet condition
508 unsigned int scvfNormDim = scvf.directionIndex();
509 if (scvf.boundary())
510 {
511 for (unsigned int velIdx = 0; velIdx < dim; ++velIdx)
512 {
513 if (!asImp_().boundaryTypes(element, scvf).isDirichlet(Indices::velocity(velIdx)))
514 continue;
515
516 Scalar dirichletVelocity = asImp_().dirichlet(element, scvf)[Indices::velocity(velIdx)];
517
518 unsigned int neighborIdx = neighborIndex(elementIdx, scvfNormDim, 0);
519 if (scvf.center()[scvfNormDim] < cellCenter(elementIdx)[scvfNormDim])
520 neighborIdx = neighborIndex(elementIdx, scvfNormDim, 1);
521
522 velocityGradients_[elementIdx][velIdx][scvfNormDim]
523 = (ccVelocity(neighborIdx, velIdx) - dirichletVelocity)
524 / (cellCenter(neighborIdx)[scvfNormDim] - scvf.center()[scvfNormDim]);
525 }
526 }
527
528 // Calculate the BJS-velocity by accounting for all sub faces.
529 std::vector<int> bjsNumFaces(dim, 0);
530 std::vector<unsigned int> bjsNeighbor(dim, 0);
531 DimVector bjsVelocityAverage(0.0);
532 DimVector normalNormCoordinate(0.0);
533 unsigned int velIdx = Indices::velocity(scvfNormDim);
534 const int numSubFaces = scvf.pairData().size();
535 for(int localSubFaceIdx = 0; localSubFaceIdx < numSubFaces; ++localSubFaceIdx)
536 {
537 const auto& lateralFace = fvGeometry.scvf(scvf.insideScvIdx(), scvf.pairData()[localSubFaceIdx].localLateralFaceIdx);
538
539 // adapt calculations for Beavers-Joseph-Saffman condition
540 unsigned int normalNormDim = lateralFace.directionIndex();
541 if (lateralFace.boundary() && (asImp_().boundaryTypes(element, lateralFace).isBeaversJoseph(Indices::velocity(velIdx))))
542 {
543 unsigned int neighborIdx = neighborIndex(elementIdx, normalNormDim, 0);
544 if (lateralFace.center()[normalNormDim] < cellCenter(elementIdx)[normalNormDim])
545 neighborIdx = neighborIndex(elementIdx, normalNormDim, 1);
546
547 const SubControlVolume& scv = fvGeometry.scv(scvf.insideScvIdx());
548 bjsVelocityAverage[normalNormDim] += ParentType::beaversJosephVelocity(element, scv, scvf, lateralFace, ccVelocity(elementIdx, velIdx), 0.0);
549 if (bjsNumFaces[normalNormDim] > 0 && neighborIdx != bjsNeighbor[normalNormDim])
550 DUNE_THROW(Dune::InvalidStateException, "Two different neighborIdx should not occur");
551 bjsNeighbor[normalNormDim] = neighborIdx;
552 normalNormCoordinate[normalNormDim] = lateralFace.center()[normalNormDim];
553 bjsNumFaces[normalNormDim]++;
554 }
555 }
556 for (unsigned dirIdx = 0; dirIdx < dim; ++dirIdx)
557 {
558 if (bjsNumFaces[dirIdx] == 0)
559 continue;
560
561 unsigned int neighborIdx = bjsNeighbor[dirIdx];
562 bjsVelocityAverage[dirIdx] /= bjsNumFaces[dirIdx];
563
564 velocityGradients_[elementIdx][velIdx][dirIdx]
565 = (ccVelocity(neighborIdx, velIdx) - bjsVelocityAverage[dirIdx])
566 / (cellCenter(neighborIdx)[dirIdx] - normalNormCoordinate[dirIdx]);
567
568 }
569 }
570 }
571 }
572
573 void calculateMaxMinVelocities_()
574 {
575 using std::abs;
576 if (isFlatWallBounded())
577 {
578 // If the parameter isFlatWallBounded is set to true,
579 // the maximum/minimum velocities are calculated along a profile perpendicular to the corresponding wall face.
580
581 // re-initialize min and max values
582 velocityMaximum_.assign(this->gridGeometry().elementMapper().size(), DimVector(1e-16));
583 velocityMinimum_.assign(this->gridGeometry().elementMapper().size(), DimVector(std::numeric_limits<Scalar>::max()));
584
585 // For each profile perpendicular to the channel wall, find the max and minimum velocities
586 for (const auto& element : elements(this->gridGeometry().gridView()))
587 {
588 const unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
589 Scalar maxVelocity = 0.0;
590 const unsigned int wallElementIdx = wallElementIndex(elementIdx);
591
592 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
593 {
594 if (abs(ccVelocity(elementIdx, dimIdx)) > abs(velocityMaximum_[wallElementIdx][dimIdx]))
595 velocityMaximum_[wallElementIdx][dimIdx] = ccVelocity(elementIdx, dimIdx);
596
597 if (abs(ccVelocity(elementIdx, dimIdx)) < abs(velocityMinimum_[wallElementIdx][dimIdx]))
598 velocityMinimum_[wallElementIdx][dimIdx] = ccVelocity(elementIdx, dimIdx);
599
600 // Set the flow direction axis as the direction of the max velocity
601 if ((hasParam("RANS.FlowDirectionAxis") != 1) && (maxVelocity) < abs(ccVelocity(elementIdx, dimIdx)))
602 {
603 maxVelocity = abs(ccVelocity(elementIdx, dimIdx));
604 flowDirectionAxis_[elementIdx] = dimIdx;
605 }
606 }
607 }
608 }
609 else
610 {
611 // If the parameter isFlatWallBounded is set to false, or not set,
612 // the maximum/minimum velocities are calculated as a global max/min throughout the domain.
613
614 DimVector maxVelocity(0.0);
615 DimVector minVelocity(std::numeric_limits<Scalar>::max());
616 // Find the max and minimum velocities in the full domain
617 for (const auto& element : elements(this->gridGeometry().gridView()))
618 {
619 const unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
620
621 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
622 {
623 if (abs(ccVelocity(elementIdx, dimIdx)) > abs(maxVelocity[dimIdx]))
624 maxVelocity[dimIdx] = ccVelocity(elementIdx, dimIdx);
625
626 if (abs(ccVelocity(elementIdx, dimIdx)) < abs(minVelocity[dimIdx]))
627 minVelocity[dimIdx] = ccVelocity(elementIdx, dimIdx);
628 }
629 }
630 velocityMaximum_.assign(this->gridGeometry().elementMapper().size(), maxVelocity);
631 velocityMinimum_.assign(this->gridGeometry().elementMapper().size(), minVelocity);
632 }
633 }
634
635 void calculateStressTensor_()
636 {
637 for (const auto& element : elements(this->gridGeometry().gridView()))
638 {
639 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
640 Dune::FieldMatrix<Scalar, GridView::dimension, GridView::dimension> stressTensor(0.0);
641 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
642 {
643 for (unsigned int velIdx = 0; velIdx < dim; ++velIdx)
644 {
645 stressTensor[dimIdx][velIdx] = 0.5 * velocityGradient(elementIdx, dimIdx, velIdx)
646 + 0.5 * velocityGradient(elementIdx, velIdx, dimIdx);
647 }
648 }
649 stressTensorScalarProduct_[elementIdx] = 0.0;
650 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
651 {
652 for (unsigned int velIdx = 0; velIdx < dim; ++velIdx)
653 {
654 stressTensorScalarProduct_[elementIdx] += stressTensor[dimIdx][velIdx] * stressTensor[dimIdx][velIdx];
655 }
656 }
657 }
658 }
659
660 void calculateVorticityTensor_()
661 {
662 for (const auto& element : elements(this->gridGeometry().gridView()))
663 {
664 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
665 Dune::FieldMatrix<Scalar, GridView::dimension, GridView::dimension> vorticityTensor(0.0);
666 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
667 {
668 for (unsigned int velIdx = 0; velIdx < dim; ++velIdx)
669 {
670 vorticityTensor[dimIdx][velIdx] = 0.5 * velocityGradient(elementIdx, dimIdx, velIdx)
671 - 0.5 * velocityGradient(elementIdx, velIdx, dimIdx);
672 }
673 }
674 vorticityTensorScalarProduct_[elementIdx] = 0.0;
675 for (unsigned int dimIdx = 0; dimIdx < dim; ++dimIdx)
676 {
677 for (unsigned int velIdx = 0; velIdx < dim; ++velIdx)
678 {
679 vorticityTensorScalarProduct_[elementIdx] += vorticityTensor[dimIdx][velIdx] * vorticityTensor[dimIdx][velIdx];
680 }
681 }
682 }
683 }
684
685 void storeViscosities_(const SolutionVector& curSol)
686 {
687 // calculate or call all secondary variables
688 for (const auto& element : elements(this->gridGeometry().gridView()))
689 {
690 unsigned int elementIdx = this->gridGeometry().elementMapper().index(element);
691 auto fvGeometry = localView(this->gridGeometry());
692 fvGeometry.bindElement(element);
693 for (auto&& scv : scvs(fvGeometry))
694 {
695 const int dofIdx = scv.dofIndex();
696 // construct a privars object from the cell center solution vector
697 const auto& cellCenterPriVars = curSol[GridGeometry::cellCenterIdx()][dofIdx];
698 PrimaryVariables priVars = makePriVarsFromCellCenterPriVars<PrimaryVariables>(cellCenterPriVars);
699 auto elemSol = elementSolution<typename GridGeometry::LocalView>(std::move(priVars));
700
701 VolumeVariables volVars;
702 volVars.update(elemSol, asImp_(), element, scv);
703 storedDensity_[elementIdx] = volVars.density();
704 storedViscosity_[elementIdx] = volVars.viscosity();
705 }
706 }
707 }
708
709 const int fixedFlowDirectionAxis_ = getParam<int>("RANS.FlowDirectionAxis", 0);
710 const int fixedWallNormalAxis_ = getParam<int>("RANS.WallNormalAxis", 1);
711
712 std::vector<unsigned int> wallNormalAxis_;
713 std::vector<unsigned int> flowDirectionAxis_;
714 std::vector<Scalar> wallDistance_;
715 std::vector<unsigned int> wallElementIdx_;
716 std::vector<GlobalPosition> cellCenter_;
717 std::vector<std::array<std::array<unsigned int, 2>, dim>> neighborIdx_;
718
719 std::vector<DimVector> velocity_;
720 std::vector<DimVector> velocityMaximum_;
721 std::vector<DimVector> velocityMinimum_;
722 std::vector<DimMatrix> velocityGradients_;
723
724 std::vector<Scalar> stressTensorScalarProduct_;
725 std::vector<Scalar> vorticityTensorScalarProduct_;
726
727 std::vector<Scalar> storedDensity_;
728 std::vector<Scalar> storedViscosity_;
729
731 Implementation &asImp_()
732 { return *static_cast<Implementation *>(this); }
733
735 const Implementation &asImp_() const
736 { return *static_cast<const Implementation *>(this); }
737};
738
739} // end namespace Dumux
740
741#endif
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:390
bool hasParam(const std::string &param)
Check whether a key exists in the parameter tree.
Definition: parameters.hh:382
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:149
Navier-Stokes problem base class.
Definition: freeflow/navierstokes/problem.hh:60
const Scalar beaversJosephVelocity(const Element &element, const SubControlVolume &scv, const SubControlVolumeFace &ownScvf, const SubControlVolumeFace &faceOnPorousBoundary, const Scalar velocitySelf, const Scalar tangentialVelocityGradient) const
Returns the slip velocity at a porous boundary based on the Beavers-Joseph(-Saffman) condition.
Definition: freeflow/navierstokes/problem.hh:239
forward declare
Definition: freeflow/rans/problem.hh:43
Reynolds-Averaged Navier-Stokes problem base class.
Definition: freeflow/rans/problem.hh:59
unsigned int wallElementIndex(const int elementIdx) const
Definition: freeflow/rans/problem.hh:374
int flowDirectionAxis(const int elementIdx) const
Definition: freeflow/rans/problem.hh:366
void updateDynamicWallProperties(const SolutionVector &curSol)
Update the dynamic (solution dependent) relations to the walls.
Definition: freeflow/rans/problem.hh:246
DimMatrix velocityGradientTensor(const int elementIdx) const
Definition: freeflow/rans/problem.hh:404
bool isOnWallAtPos(const GlobalPosition &globalPos) const
Returns whether a given point is on a wall.
Definition: freeflow/rans/problem.hh:311
Scalar vorticityTensorScalarProduct(const int elementIdx) const
Definition: freeflow/rans/problem.hh:413
void updateStaticWallProperties()
Update the static (solution independent) relations to the walls.
Definition: freeflow/rans/problem.hh:112
GlobalPosition cellCenter(const int elementIdx) const
Definition: freeflow/rans/problem.hh:386
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:277
DimVector velocityMaximum(const int elementIdx) const
Definition: freeflow/rans/problem.hh:398
const Scalar betaOmega() const
Returns the constant.
Definition: freeflow/rans/problem.hh:331
DimVector ccVelocityVector(const int elementIdx) const
Definition: freeflow/rans/problem.hh:392
Scalar kinematicViscosity(const int elementIdx) const
Definition: freeflow/rans/problem.hh:422
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:351
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:289
unsigned int neighborIndex(const int elementIdx, const int dimIdx, const int sideIdx) const
Definition: freeflow/rans/problem.hh:389
Scalar ccVelocity(const int elementIdx, const int dimIdx) const
Definition: freeflow/rans/problem.hh:395
DimVector velocityMinimum(const int elementIdx) const
Definition: freeflow/rans/problem.hh:401
Scalar wallDistance(const int elementIdx) const
Definition: freeflow/rans/problem.hh:383
Scalar storedDensity(const int elementIdx) const
Definition: freeflow/rans/problem.hh:419
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:340
Scalar velocityGradient(const int elementIdx, const int dimIdx, const int velIdx) const
Definition: freeflow/rans/problem.hh:407
int wallNormalAxis(const int elementIdx) const
Definition: freeflow/rans/problem.hh:358
RANSProblemBase(std::shared_ptr< const GridGeometry > gridGeometry, const std::string &paramGroup="")
The constructor.
Definition: freeflow/rans/problem.hh:102
bool isFlatWallBounded() const
Definition: freeflow/rans/problem.hh:318
Scalar stressTensorScalarProduct(const int elementIdx) const
Definition: freeflow/rans/problem.hh:410
bool calledUpdateStaticWallProperties
Definition: freeflow/rans/problem.hh:425
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:268
const Scalar karmanConstant() const
Returns the Karman constant.
Definition: freeflow/rans/problem.hh:327
Scalar storedViscosity(const int elementIdx) const
Definition: freeflow/rans/problem.hh:416
bool isOnWall(const SubControlVolumeFace &scvf) const
Returns whether a given sub control volume face is on a wall.
Definition: freeflow/rans/problem.hh:301
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.