version 3.8
freeflow/navierstokes/staggered/fluxvariables.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_NAVIERSTOKES_STAGGERED_FLUXVARIABLES_HH
13#define DUMUX_NAVIERSTOKES_STAGGERED_FLUXVARIABLES_HH
14
15#include <array>
16#include <optional>
17#include <type_traits>
18
19#include <dumux/common/math.hh>
24
28
30#include "velocitygradients.hh"
31
32namespace Dumux {
33
39// forward declaration
40template<class TypeTag, class DiscretizationMethod>
41class NavierStokesFluxVariablesImpl;
42
43template<class TypeTag>
44class NavierStokesFluxVariablesImpl<TypeTag, DiscretizationMethods::Staggered>
45: public FluxVariablesBase<GetPropType<TypeTag, Properties::Problem>,
46 typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView,
47 typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView,
48 typename GetPropType<TypeTag, Properties::GridFluxVariablesCache>::LocalView>
49{
51
52 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
53 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
54 using VolumeVariables = typename GridVolumeVariables::VolumeVariables;
55
56 using GridFluxVariablesCache = typename GridVariables::GridFluxVariablesCache;
57 using FluxVariablesCache = typename GridFluxVariablesCache::FluxVariablesCache;
58
59 using GridFaceVariables = typename GridVariables::GridFaceVariables;
60 using ElementFaceVariables = typename GridFaceVariables::LocalView;
61 using FaceVariables = typename GridFaceVariables::FaceVariables;
62
65 using FVElementGeometry = typename GridGeometry::LocalView;
66 using GridView = typename GridGeometry::GridView;
67 using Element = typename GridView::template Codim<0>::Entity;
70 using Indices = typename ModelTraits::Indices;
71 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
72 using FaceFrontalSubControlVolumeFace = typename GridGeometry::Traits::FaceFrontalSubControlVolumeFace;
73 using FaceLateralSubControlVolumeFace = typename GridGeometry::Traits::FaceLateralSubControlVolumeFace;
74 using Extrusion = Extrusion_t<GridGeometry>;
75 using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>;
77 using BoundaryTypes = typename ProblemTraits<Problem>::BoundaryTypes;
79
80 static constexpr bool normalizePressure = getPropValue<TypeTag, Properties::NormalizePressure>();
81
82 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
83
84 static constexpr auto cellCenterIdx = GridGeometry::cellCenterIdx();
85 static constexpr auto faceIdx = GridGeometry::faceIdx();
86
87 static constexpr int upwindSchemeOrder = getPropValue<TypeTag, Properties::UpwindSchemeOrder>();
88 static constexpr bool useHigherOrder = upwindSchemeOrder > 1;
89
90public:
91
93
94
104 template<class UpwindTerm>
105 static Scalar advectiveFluxForCellCenter(const Problem& problem,
106 const FVElementGeometry& fvGeometry,
107 const ElementVolumeVariables& elemVolVars,
108 const ElementFaceVariables& elemFaceVars,
109 const SubControlVolumeFace &scvf,
110 UpwindTerm upwindTerm)
111 {
112 const Scalar velocity = elemFaceVars[scvf].velocitySelf();
113 const bool insideIsUpstream = scvf.directionSign() == sign(velocity);
114 static const Scalar upwindWeight = getParamFromGroup<Scalar>(problem.paramGroup(), "Flux.UpwindWeight");
115
116 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
117 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
118
119 const auto& upstreamVolVars = insideIsUpstream ? insideVolVars : outsideVolVars;
120 const auto& downstreamVolVars = insideIsUpstream ? outsideVolVars : insideVolVars;
121
122 const Scalar flux = (upwindWeight * upwindTerm(upstreamVolVars) +
123 (1.0 - upwindWeight) * upwindTerm(downstreamVolVars))
124 * velocity * Extrusion::area(fvGeometry, scvf) * scvf.directionSign();
125
126 return flux * extrusionFactor_(elemVolVars, scvf);
127 }
128
144 CellCenterPrimaryVariables computeMassFlux(const Problem& problem,
145 const Element& element,
146 const FVElementGeometry& fvGeometry,
147 const ElementVolumeVariables& elemVolVars,
148 const ElementFaceVariables& elemFaceVars,
149 const SubControlVolumeFace& scvf,
150 const FluxVariablesCache& fluxVarsCache)
151 {
152 // The advectively transported quantity (i.e density for a single-phase system).
153 auto upwindTerm = [](const auto& volVars) { return volVars.density(); };
154
155 // Call the generic flux function.
156 CellCenterPrimaryVariables result(0.0);
157 result[Indices::conti0EqIdx - ModelTraits::dim()] = advectiveFluxForCellCenter(problem, fvGeometry, elemVolVars, elemFaceVars, scvf, upwindTerm);
158
159 return result;
160 }
161
165 FacePrimaryVariables computeMomentumFlux(const Problem& problem,
166 const Element& element,
167 const SubControlVolumeFace& scvf,
168 const FVElementGeometry& fvGeometry,
169 const ElementVolumeVariables& elemVolVars,
170 const ElementFaceVariables& elemFaceVars,
171 const GridFluxVariablesCache& gridFluxVarsCache)
172 {
173 return computeFrontalMomentumFlux(problem, element, scvf, fvGeometry, elemVolVars, elemFaceVars, gridFluxVarsCache) +
174 computeLateralMomentumFlux(problem, element, scvf, fvGeometry, elemVolVars, elemFaceVars, gridFluxVarsCache);
175 }
176
194 FacePrimaryVariables computeFrontalMomentumFlux(const Problem& problem,
195 const Element& element,
196 const SubControlVolumeFace& scvf,
197 const FVElementGeometry& fvGeometry,
198 const ElementVolumeVariables& elemVolVars,
199 const ElementFaceVariables& elemFaceVars,
200 const GridFluxVariablesCache& gridFluxVarsCache)
201 {
202 FacePrimaryVariables frontalFlux(0.0);
203
204 // The velocities of the dof at interest and the one of the opposite scvf.
205 const Scalar velocitySelf = elemFaceVars[scvf].velocitySelf();
206 const Scalar velocityOpposite = elemFaceVars[scvf].velocityOpposite();
207 const auto& faceVars = elemFaceVars[scvf];
208
209 // Advective flux.
210 if (problem.enableInertiaTerms())
211 {
212 // Get the average velocity at the center of the element (i.e. the location of the staggered face).
213 const Scalar transportingVelocity = (velocitySelf + velocityOpposite) * 0.5;
214 const bool selfIsUpstream = scvf.directionSign() != sign(transportingVelocity);
215
216 StaggeredUpwindHelper<TypeTag, upwindSchemeOrder> upwindHelper(element, fvGeometry, scvf, elemFaceVars, elemVolVars, gridFluxVarsCache.staggeredUpwindMethods());
217 frontalFlux += upwindHelper.computeUpwindFrontalMomentum(selfIsUpstream)
218 * transportingVelocity * -1.0 * scvf.directionSign();
219 }
220
221 // The volume variables within the current element. We only require those (and none of neighboring elements)
222 // because the fluxes are calculated over the staggered face at the center of the element.
223 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
224
225 // Diffusive flux.
226 const Scalar velocityGrad_ii = VelocityGradients::velocityGradII(scvf, faceVars) * scvf.directionSign();
227
228 static const bool enableUnsymmetrizedVelocityGradient
229 = getParamFromGroup<bool>(problem.paramGroup(), "FreeFlow.EnableUnsymmetrizedVelocityGradient", false);
230 const Scalar factor = enableUnsymmetrizedVelocityGradient ? 1.0 : 2.0;
231 frontalFlux -= factor * insideVolVars.effectiveViscosity() * velocityGrad_ii;
232
233 // The pressure term.
234 // If specified, the pressure can be normalized using the initial value on the scfv of interest.
235 // The scvf is used to normalize by the same value from the left and right side.
236 // Can potentially help to improve the condition number of the system matrix.
237 const Scalar pressure = normalizePressure ?
238 insideVolVars.pressure() - problem.initial(scvf)[Indices::pressureIdx]
239 : insideVolVars.pressure();
240
241 // Account for the orientation of the staggered face's normal outer normal vector
242 // (pointing in opposite direction of the scvf's one).
243 frontalFlux += pressure * -1.0 * scvf.directionSign();
244
245 // Account for the staggered face's area. For rectangular elements, this equals the area of the scvf
246 // our velocity dof of interest lives on but with adjusted centroid
247 const auto& scv = fvGeometry.scv(scvf.insideScvIdx());
248 FaceFrontalSubControlVolumeFace frontalFace(scv.center(), scvf.area());
249 return frontalFlux * Extrusion::area(fvGeometry, frontalFace) * insideVolVars.extrusionFactor();
250 }
251
269 FacePrimaryVariables computeLateralMomentumFlux(const Problem& problem,
270 const Element& element,
271 const SubControlVolumeFace& scvf,
272 const FVElementGeometry& fvGeometry,
273 const ElementVolumeVariables& elemVolVars,
274 const ElementFaceVariables& elemFaceVars,
275 const GridFluxVariablesCache& gridFluxVarsCache)
276 {
277 FacePrimaryVariables lateralFlux(0.0);
278 const auto& faceVars = elemFaceVars[scvf];
279 const std::size_t numSubFaces = scvf.pairData().size();
280
281 // If the current scvf is on a boundary, check if there is a Neumann BC for the stress in tangential direction.
282 // Create a boundaryTypes object (will be empty if not at a boundary).
283 std::optional<BoundaryTypes> currentScvfBoundaryTypes;
284 if (scvf.boundary())
285 currentScvfBoundaryTypes.emplace(problem.boundaryTypes(element, scvf));
286
287 // Account for all sub faces.
288 for (int localSubFaceIdx = 0; localSubFaceIdx < numSubFaces; ++localSubFaceIdx)
289 {
290 const auto eIdx = scvf.insideScvIdx();
291 // Get the face normal to the face the dof lives on. The staggered sub face coincides with half of this lateral face.
292 const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
293
294 // Create a boundaryTypes object (will be empty if not at a boundary).
295 std::optional<BoundaryTypes> lateralFaceBoundaryTypes;
296
297 // Check if there is face/element parallel to our face of interest where the dof lives on. If there is no parallel neighbor,
298 // we are on a boundary where we have to check for boundary conditions.
299 if (lateralFace.boundary())
300 {
301 // Retrieve the boundary types that correspond to the center of the lateral scvf. As a convention, we always query
302 // the type of BCs at the center of the element's "actual" lateral scvf (not the face of the staggered control volume).
303 // The value of the BC will be evaluated at the center of the staggered face.
304 // --------T######V || frontal face of staggered half-control-volume
305 // | || | current scvf # lateral staggered face of interest (may lie on a boundary)
306 // | || | x dof position
307 // | || x~~~~> vel.Self -- element boundaries
308 // | || | T position at which the type of boundary conditions will be evaluated
309 // | || | (center of lateral scvf)
310 // ---------------- V position at which the value of the boundary conditions will be evaluated
311 // (center of the staggered lateral face)
312 lateralFaceBoundaryTypes.emplace(problem.boundaryTypes(element, lateralFace));
313 }
314
315 // If the current scvf is on a boundary and if there is a Neumann or Beavers-Joseph-(Saffmann) BC for the stress in tangential direction,
316 // assign this value for the lateral momentum flux. No further calculations are required. We assume that all lateral faces
317 // have the same type of BC (Neumann or Beavers-Joseph-(Saffmann)), but we sample the value at their actual positions.
318 if (currentScvfBoundaryTypes)
319 {
320 // Handle Neumann BCs.
321 if (currentScvfBoundaryTypes->isNeumann(Indices::velocity(lateralFace.directionIndex())))
322 {
323 // Get the location of the lateral staggered face's center.
324 FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
325 const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
326 const auto lateralBoundaryFace = makeStaggeredBoundaryFace(scvf, lateralStaggeredFaceCenter);
327 lateralFlux += problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, lateralBoundaryFace)[Indices::velocity(lateralFace.directionIndex())]
328 * extrusionFactor_(elemVolVars, lateralFace) * Extrusion::area(fvGeometry, lateralScvf) * lateralFace.directionSign();
329
330 continue;
331 }
332
333 // Treat the edge case when our current scvf has a BJ condition while the lateral face has a Neumann BC.
334 // It is not clear how to evaluate the BJ condition here.
335 // For symmetry reasons, our own scvf should then have the same Neumann flux as the lateral face.
336 // TODO: We should clarify if this is the correct approach.
337 if (currentScvfBoundaryTypes->isBeaversJoseph(Indices::velocity(lateralFace.directionIndex())) && lateralFaceBoundaryTypes &&
338 lateralFaceBoundaryTypes->isNeumann(Indices::velocity(scvf.directionIndex())))
339 {
340 FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
341 const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
342 const auto lateralBoundaryFace = makeStaggeredBoundaryFace(lateralFace, lateralStaggeredFaceCenter);
343 lateralFlux += problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, lateralBoundaryFace)[Indices::velocity(scvf.directionIndex())]
344 * extrusionFactor_(elemVolVars, lateralFace) * Extrusion::area(fvGeometry, lateralScvf) * lateralFace.directionSign();
345
346 continue;
347 }
348 }
349
350 // Check if the lateral face (perpendicular to our current scvf) lies on a boundary. If yes, boundary conditions might need to be treated
351 // and further calculations can be skipped.
352 if (lateralFace.boundary())
353 {
354 // Check if we have a symmetry boundary condition. If yes, the tangential part of the momentum flux can be neglected
355 // and we may skip any further calculations for the given sub face.
356 if (lateralFaceBoundaryTypes->isSymmetry())
357 continue;
358
359 // Handle Neumann boundary conditions. No further calculations are then required for the given sub face.
360 if (lateralFaceBoundaryTypes->isNeumann(Indices::velocity(scvf.directionIndex())))
361 {
362 // Construct a temporary scvf which corresponds to the staggered sub face, featuring the location
363 // the staggered faces's center.
364 FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
365 const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
366 const auto lateralBoundaryFace = makeStaggeredBoundaryFace(lateralFace, lateralStaggeredFaceCenter);
367 lateralFlux += problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, lateralBoundaryFace)[Indices::velocity(scvf.directionIndex())]
368 * elemVolVars[lateralFace.insideScvIdx()].extrusionFactor() * Extrusion::area(fvGeometry, lateralScvf);
369
370 continue;
371 }
372
373 // Handle wall-function fluxes (only required for RANS models)
374 if (incorporateWallFunction_(lateralFlux, problem, element, fvGeometry, scvf, elemVolVars, elemFaceVars, localSubFaceIdx))
375 continue;
376 }
377
378 // Check the consistency of the boundary conditions, exactly one of the following must be set
379 if (lateralFaceBoundaryTypes)
380 {
381 std::bitset<3> admittableBcTypes;
382 admittableBcTypes.set(0, lateralFaceBoundaryTypes->isDirichlet(Indices::pressureIdx));
383 admittableBcTypes.set(1, lateralFaceBoundaryTypes->isDirichlet(Indices::velocity(scvf.directionIndex())));
384 admittableBcTypes.set(2, lateralFaceBoundaryTypes->isBeaversJoseph(Indices::velocity(scvf.directionIndex())));
385 if (admittableBcTypes.count() != 1)
386 {
387 DUNE_THROW(Dune::InvalidStateException, "Invalid boundary conditions for lateral scvf "
388 "for the momentum equations at global position " << lateralStaggeredFaceCenter_(scvf, localSubFaceIdx)
389 << ", current scvf global position " << scvf.center());
390 }
391 }
392
393 // If none of the above boundary conditions apply for the given sub face, proceed to calculate the tangential momentum flux.
394 if (problem.enableInertiaTerms())
395 lateralFlux += computeAdvectivePartOfLateralMomentumFlux_(problem, fvGeometry, element,
396 scvf, elemVolVars, elemFaceVars,
397 gridFluxVarsCache,
398 currentScvfBoundaryTypes, lateralFaceBoundaryTypes,
399 localSubFaceIdx);
400
401 lateralFlux += computeDiffusivePartOfLateralMomentumFlux_(problem, fvGeometry, element,
402 scvf, elemVolVars, faceVars,
403 currentScvfBoundaryTypes, lateralFaceBoundaryTypes,
404 localSubFaceIdx);
405 }
406 return lateralFlux;
407 }
408
409
426 FacePrimaryVariables inflowOutflowBoundaryFlux(const Problem& problem,
427 const SubControlVolumeFace& scvf,
428 const FVElementGeometry& fvGeometry,
429 const ElementVolumeVariables& elemVolVars,
430 const ElementFaceVariables& elemFaceVars) const
431 {
432 FacePrimaryVariables inOrOutflow(0.0);
433 const auto& element = fvGeometry.element();
434 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
435
436 // Advective momentum flux.
437 if (problem.enableInertiaTerms())
438 {
439 const Scalar velocitySelf = elemFaceVars[scvf].velocitySelf();
440 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
441 const auto& upVolVars = (scvf.directionSign() == sign(velocitySelf)) ?
442 insideVolVars : outsideVolVars;
443
444 inOrOutflow += velocitySelf * velocitySelf * upVolVars.density();
445 }
446
447 // Apply a pressure at the boundary.
448 const Scalar boundaryPressure = normalizePressure
449 ? (problem.dirichlet(element, scvf)[Indices::pressureIdx] -
450 problem.initial(scvf)[Indices::pressureIdx])
451 : problem.dirichlet(element, scvf)[Indices::pressureIdx];
452 inOrOutflow += boundaryPressure;
453
454 // Account for the orientation of the face at the boundary,
455 return inOrOutflow * scvf.directionSign() * Extrusion::area(fvGeometry, scvf) * insideVolVars.extrusionFactor();
456 }
457
458private:
459
481 FacePrimaryVariables computeAdvectivePartOfLateralMomentumFlux_(const Problem& problem,
482 const FVElementGeometry& fvGeometry,
483 const Element& element,
484 const SubControlVolumeFace& scvf,
485 const ElementVolumeVariables& elemVolVars,
486 const ElementFaceVariables& elemFaceVars,
487 const GridFluxVariablesCache& gridFluxVarsCache,
488 const std::optional<BoundaryTypes>& currentScvfBoundaryTypes,
489 const std::optional<BoundaryTypes>& lateralFaceBoundaryTypes,
490 const int localSubFaceIdx)
491 {
492 const auto eIdx = scvf.insideScvIdx();
493 const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
494
495 // Get the transporting velocity, located at the scvf perpendicular to the current scvf where the dof
496 // of interest is located.
497 const Scalar transportingVelocity = [&]()
498 {
499 const auto& faceVars = elemFaceVars[scvf];
500 if (!scvf.boundary())
501 return faceVars.velocityLateralInside(localSubFaceIdx);
502 else
503 {
504 // Create a boundaryTypes object. Get the boundary conditions. We sample the type of BC at the center of the current scvf.
505 const auto bcTypes = problem.boundaryTypes(element, scvf);
506
507 if (bcTypes.isDirichlet(Indices::velocity(lateralFace.directionIndex())))
508 {
509 // Construct a temporary scvf which corresponds to the staggered sub face, featuring the location
510 // the staggered faces's center.
511 const auto& lateralBoundaryFacePos = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
512 const auto lateralBoundaryFace = makeStaggeredBoundaryFace(scvf, lateralBoundaryFacePos);
513 return problem.dirichlet(element, lateralBoundaryFace)[Indices::velocity(lateralFace.directionIndex())];
514 }
515 else if (bcTypes.isBeaversJoseph(Indices::velocity(lateralFace.directionIndex())))
516 {
517 return VelocityGradients::beaversJosephVelocityAtCurrentScvf(problem, element, fvGeometry, scvf, faceVars,
518 currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx);
519 }
520 else
521 return faceVars.velocityLateralInside(localSubFaceIdx);
522 }
523 }();
524
525 const bool selfIsUpstream = lateralFace.directionSign() == sign(transportingVelocity);
526 StaggeredUpwindHelper<TypeTag, upwindSchemeOrder> upwindHelper(element, fvGeometry, scvf, elemFaceVars, elemVolVars, gridFluxVarsCache.staggeredUpwindMethods());
527 FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
528 return upwindHelper.computeUpwindLateralMomentum(selfIsUpstream, lateralFace, localSubFaceIdx, currentScvfBoundaryTypes, lateralFaceBoundaryTypes)
529 * transportingVelocity * lateralFace.directionSign() * Extrusion::area(fvGeometry, lateralScvf) * extrusionFactor_(elemVolVars, lateralFace);
530 }
531
554 FacePrimaryVariables computeDiffusivePartOfLateralMomentumFlux_(const Problem& problem,
555 const FVElementGeometry& fvGeometry,
556 const Element& element,
557 const SubControlVolumeFace& scvf,
558 const ElementVolumeVariables& elemVolVars,
559 const FaceVariables& faceVars,
560 const std::optional<BoundaryTypes>& currentScvfBoundaryTypes,
561 const std::optional<BoundaryTypes>& lateralFaceBoundaryTypes,
562 const int localSubFaceIdx)
563 {
564 const auto eIdx = scvf.insideScvIdx();
565 const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
566
567 FacePrimaryVariables lateralDiffusiveFlux(0.0);
568
569 static const bool enableUnsymmetrizedVelocityGradient
570 = getParamFromGroup<bool>(problem.paramGroup(), "FreeFlow.EnableUnsymmetrizedVelocityGradient", false);
571
572 // Get the volume variables of the own and the neighboring element. The neighboring
573 // element is adjacent to the staggered face normal to the current scvf
574 // where the dof of interest is located.
575 const auto& insideVolVars = elemVolVars[lateralFace.insideScvIdx()];
576 const auto& outsideVolVars = elemVolVars[lateralFace.outsideScvIdx()];
577
578 // Get the averaged viscosity at the staggered face normal to the current scvf.
579 const Scalar muAvg = lateralFace.boundary()
580 ? insideVolVars.effectiveViscosity()
581 : (insideVolVars.effectiveViscosity() + outsideVolVars.effectiveViscosity()) * 0.5;
582
583 // Consider the shear stress caused by the gradient of the velocities normal to our face of interest.
584 if (!enableUnsymmetrizedVelocityGradient)
585 {
586 if (!scvf.boundary() ||
587 currentScvfBoundaryTypes->isDirichlet(Indices::velocity(lateralFace.directionIndex())) ||
588 currentScvfBoundaryTypes->isBeaversJoseph(Indices::velocity(lateralFace.directionIndex())))
589 {
590 const Scalar velocityGrad_ji = VelocityGradients::velocityGradJI(problem, element, fvGeometry, scvf, faceVars, currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx);
591 // Account for the orientation of the staggered normal face's outer normal vector.
592 lateralDiffusiveFlux -= muAvg * velocityGrad_ji * lateralFace.directionSign();
593 }
594 }
595
596 // Consider the shear stress caused by the gradient of the velocities parallel to our face of interest.
597 // If we have a Dirichlet condition for the pressure at the lateral face we assume to have a zero velocityGrad_ij velocity gradient
598 // so we can skip the computation.
599 if (!lateralFace.boundary() || !lateralFaceBoundaryTypes->isDirichlet(Indices::pressureIdx))
600 {
601 const Scalar velocityGrad_ij = VelocityGradients::velocityGradIJ(problem, element, fvGeometry, scvf, faceVars, currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx);
602 lateralDiffusiveFlux -= muAvg * velocityGrad_ij * lateralFace.directionSign();
603 }
604
605 // Account for the area of the staggered lateral face (0.5 of the coinciding scfv).
606 FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
607 return lateralDiffusiveFlux * Extrusion::area(fvGeometry, lateralScvf) * extrusionFactor_(elemVolVars, lateralFace);
608 }
609
624 const GlobalPosition& lateralStaggeredFaceCenter_(const SubControlVolumeFace& scvf, const int localSubFaceIdx) const
625 {
626 return scvf.pairData(localSubFaceIdx).lateralStaggeredFaceCenter;
627 };
628
643 GlobalPosition lateralStaggeredSCVFCenter_(const SubControlVolumeFace& lateralFace,
644 const SubControlVolumeFace& currentFace,
645 const int localSubFaceIdx) const
646 {
647 auto pos = lateralStaggeredFaceCenter_(currentFace, localSubFaceIdx) + lateralFace.center();
648 pos *= 0.5;
649 return pos;
650 }
651
653 static Scalar extrusionFactor_(const ElementVolumeVariables& elemVolVars, const SubControlVolumeFace& scvf)
654 {
655 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
656 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
657 return harmonicMean(insideVolVars.extrusionFactor(), outsideVolVars.extrusionFactor());
658 }
659
661 template<class ...Args, bool turbulenceModel = ModelTraits::usesTurbulenceModel(), std::enable_if_t<!turbulenceModel, int> = 0>
662 bool incorporateWallFunction_(Args&&... args) const
663 { return false; }
664
666 template<bool turbulenceModel = ModelTraits::usesTurbulenceModel(), std::enable_if_t<turbulenceModel, int> = 0>
667 bool incorporateWallFunction_(FacePrimaryVariables& lateralFlux,
668 const Problem& problem,
669 const Element& element,
670 const FVElementGeometry& fvGeometry,
671 const SubControlVolumeFace& scvf,
672 const ElementVolumeVariables& elemVolVars,
673 const ElementFaceVariables& elemFaceVars,
674 const std::size_t localSubFaceIdx) const
675 {
676 const auto eIdx = scvf.insideScvIdx();
677 const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
678
679 if (problem.useWallFunction(element, lateralFace, Indices::velocity(scvf.directionIndex())))
680 {
681 FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
682 const auto lateralBoundaryFace = makeStaggeredBoundaryFace(lateralFace, lateralStaggeredFaceCenter_(scvf, localSubFaceIdx));
683 lateralFlux += problem.wallFunction(element, fvGeometry, elemVolVars, elemFaceVars, scvf, lateralBoundaryFace)[Indices::velocity(scvf.directionIndex())]
684 * extrusionFactor_(elemVolVars, lateralFace) * Extrusion::area(fvGeometry, lateralScvf);
685 return true;
686 }
687 else
688 return false;
689 }
690};
691
692} // end namespace Dumux
693
694#endif
Base class for the flux variables living on a sub control volume face.
Definition: fluxvariablesbase.hh:33
static Scalar advectiveFluxForCellCenter(const Problem &problem, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars, const SubControlVolumeFace &scvf, UpwindTerm upwindTerm)
Returns the advective flux over a sub control volume face.
Definition: freeflow/navierstokes/staggered/fluxvariables.hh:105
FacePrimaryVariables computeLateralMomentumFlux(const Problem &problem, const Element &element, const SubControlVolumeFace &scvf, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars, const GridFluxVariablesCache &gridFluxVarsCache)
Returns the momentum flux over the staggered faces perpendicular to the scvf where the velocity dof o...
Definition: freeflow/navierstokes/staggered/fluxvariables.hh:269
FacePrimaryVariables inflowOutflowBoundaryFlux(const Problem &problem, const SubControlVolumeFace &scvf, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars) const
Returns the momentum flux over an inflow or outflow boundary face.
Definition: freeflow/navierstokes/staggered/fluxvariables.hh:426
FacePrimaryVariables computeFrontalMomentumFlux(const Problem &problem, const Element &element, const SubControlVolumeFace &scvf, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars, const GridFluxVariablesCache &gridFluxVarsCache)
Returns the frontal part of the momentum flux. This treats the flux over the staggered face at the ce...
Definition: freeflow/navierstokes/staggered/fluxvariables.hh:194
FacePrimaryVariables computeMomentumFlux(const Problem &problem, const Element &element, const SubControlVolumeFace &scvf, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars, const GridFluxVariablesCache &gridFluxVarsCache)
Returns the momentum flux over all staggered faces.
Definition: freeflow/navierstokes/staggered/fluxvariables.hh:165
GetPropType< TypeTag, Properties::HeatConductionType > HeatConductionType
Definition: freeflow/navierstokes/staggered/fluxvariables.hh:92
CellCenterPrimaryVariables computeMassFlux(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const ElementVolumeVariables &elemVolVars, const ElementFaceVariables &elemFaceVars, const SubControlVolumeFace &scvf, const FluxVariablesCache &fluxVarsCache)
Computes the flux for the cell center residual (mass balance).
Definition: freeflow/navierstokes/staggered/fluxvariables.hh:144
The flux variables class for the Navier-Stokes model using the staggered grid discretization.
Definition: freeflow/navierstokes/fluxvariables.hh:23
The upwinding variables class for the Navier-Stokes model using the staggered grid discretization.
Definition: staggeredupwindhelper.hh:36
FacePrimaryVariables computeUpwindFrontalMomentum(const bool selfIsUpstream) const
Returns the momentum in the frontal direction.
Definition: staggeredupwindhelper.hh:103
Helper class for calculating the velocity gradients for the Navier-Stokes model using the staggered g...
Definition: momentum/velocitygradients.hh:46
Defines all properties used in Dumux.
Type traits for problem classes.
Some exceptions thrown in DuMux
Helper classes to compute the integration elements.
Base class for the flux variables living on a sub control volume face.
constexpr Scalar harmonicMean(Scalar x, Scalar y, Scalar wx=1.0, Scalar wy=1.0) noexcept
Calculate the (weighted) harmonic mean of two scalar values.
Definition: math.hh:57
constexpr int sign(const ValueType &value) noexcept
Sign or signum function.
Definition: math.hh:629
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296
SubControlVolumeFace makeStaggeredBoundaryFace(const SubControlVolumeFace &scvf, const typename SubControlVolumeFace::GlobalPosition &newCenter)
Helper function to turn a given cell scvface into a fake boundary face.
Definition: discretization/staggered/freeflow/subcontrolvolumeface.hh:62
Define some often used mathematical functions.
The available discretization methods in Dumux.
std::string pressure(int phaseIdx) noexcept
I/O name of pressure for multiphase systems.
Definition: name.hh:22
Definition: adapt.hh:17
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition: extrusion.hh:166
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
typename Detail::template ProblemTraits< Problem, typename GridGeometry::DiscretizationMethod >::BoundaryTypes BoundaryTypes
Definition: common/typetraits/problem.hh:34