46                           typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView,
 
   47                           typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView,
 
   48                           typename GetPropType<TypeTag, Properties::GridFluxVariablesCache>::LocalView>
 
   52    using GridVolumeVariables = 
typename GridVariables::GridVolumeVariables;
 
   53    using ElementVolumeVariables = 
typename GridVolumeVariables::LocalView;
 
   54    using VolumeVariables = 
typename GridVolumeVariables::VolumeVariables;
 
   56    using GridFluxVariablesCache = 
typename GridVariables::GridFluxVariablesCache;
 
   57    using FluxVariablesCache = 
typename GridFluxVariablesCache::FluxVariablesCache;
 
   59    using GridFaceVariables = 
typename GridVariables::GridFaceVariables;
 
   60    using ElementFaceVariables = 
typename GridFaceVariables::LocalView;
 
   61    using FaceVariables = 
typename GridFaceVariables::FaceVariables;
 
   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;
 
   82    using GlobalPosition = 
typename Element::Geometry::GlobalCoordinate;
 
   84    static constexpr auto cellCenterIdx = GridGeometry::cellCenterIdx();
 
   85    static constexpr auto faceIdx = GridGeometry::faceIdx();
 
   88    static constexpr bool useHigherOrder = upwindSchemeOrder > 1;
 
  104    template<
class UpwindTerm>
 
  108                                             const ElementFaceVariables& elemFaceVars,
 
  109                                             const SubControlVolumeFace &scvf,
 
  110                                             UpwindTerm upwindTerm)
 
  112        const Scalar velocity = elemFaceVars[scvf].velocitySelf();
 
  113        const bool insideIsUpstream = scvf.directionSign() == 
sign(velocity);
 
  116        const auto& insideVolVars = 
elemVolVars[scvf.insideScvIdx()];
 
  117        const auto& outsideVolVars = 
elemVolVars[scvf.outsideScvIdx()];
 
  119        const auto& upstreamVolVars = insideIsUpstream ? insideVolVars : outsideVolVars;
 
  120        const auto& downstreamVolVars = insideIsUpstream ? outsideVolVars : insideVolVars;
 
  122        const Scalar flux = (upwindWeight * upwindTerm(upstreamVolVars) +
 
  123                            (1.0 - upwindWeight) * upwindTerm(downstreamVolVars))
 
  124                            * velocity * Extrusion::area(
fvGeometry, scvf) * scvf.directionSign();
 
 
  148                                               const ElementFaceVariables& elemFaceVars,
 
  149                                               const SubControlVolumeFace& scvf,
 
  150                                               const FluxVariablesCache& fluxVarsCache)
 
  153        auto upwindTerm = [](
const auto& volVars) { 
return volVars.density(); };
 
  156        CellCenterPrimaryVariables result(0.0);
 
 
  167                                             const SubControlVolumeFace& scvf,
 
  170                                             const ElementFaceVariables& elemFaceVars,
 
  171                                             const GridFluxVariablesCache& gridFluxVarsCache)
 
 
  196                                                    const SubControlVolumeFace& scvf,
 
  199                                                    const ElementFaceVariables& elemFaceVars,
 
  200                                                    const GridFluxVariablesCache& gridFluxVarsCache)
 
  202        FacePrimaryVariables frontalFlux(0.0);
 
  205        const Scalar velocitySelf = elemFaceVars[scvf].velocitySelf();
 
  206        const Scalar velocityOpposite = elemFaceVars[scvf].velocityOpposite();
 
  207        const auto& faceVars =  elemFaceVars[scvf];
 
  210        if (
problem.enableInertiaTerms())
 
  213            const Scalar transportingVelocity = (velocitySelf + velocityOpposite) * 0.5;
 
  214            const bool selfIsUpstream = scvf.directionSign() != 
sign(transportingVelocity);
 
  218                           * transportingVelocity * -1.0 * scvf.directionSign();
 
  223        const auto& insideVolVars = 
elemVolVars[scvf.insideScvIdx()];
 
  228        static const bool enableUnsymmetrizedVelocityGradient
 
  230        const Scalar factor = enableUnsymmetrizedVelocityGradient ? 1.0 : 2.0;
 
  231        frontalFlux -= factor * insideVolVars.effectiveViscosity() * velocityGrad_ii;
 
  237        const Scalar pressure = normalizePressure ?
 
  238                                insideVolVars.pressure() - 
problem.initial(scvf)[Indices::pressureIdx]
 
  239                              : insideVolVars.pressure();
 
  243        frontalFlux += pressure * -1.0 * scvf.directionSign();
 
  247        const auto& scv = 
fvGeometry.scv(scvf.insideScvIdx());
 
  248        FaceFrontalSubControlVolumeFace frontalFace(scv.center(), scvf.area());
 
  249        return frontalFlux * Extrusion::area(
fvGeometry, frontalFace) * insideVolVars.extrusionFactor();
 
 
  271                                                    const SubControlVolumeFace& scvf,
 
  274                                                    const ElementFaceVariables& elemFaceVars,
 
  275                                                    const GridFluxVariablesCache& gridFluxVarsCache)
 
  277        FacePrimaryVariables lateralFlux(0.0);
 
  278        const auto& faceVars = elemFaceVars[scvf];
 
  279        const std::size_t numSubFaces = scvf.pairData().size();
 
  283        std::optional<BoundaryTypes> currentScvfBoundaryTypes;
 
  285            currentScvfBoundaryTypes.emplace(
problem.boundaryTypes(
element, scvf));
 
  288        for (
int localSubFaceIdx = 0; localSubFaceIdx < numSubFaces; ++localSubFaceIdx)
 
  290            const auto eIdx = scvf.insideScvIdx();
 
  292            const auto& lateralFace = 
fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
 
  295            std::optional<BoundaryTypes> lateralFaceBoundaryTypes;
 
  299            if (lateralFace.boundary())
 
  312                lateralFaceBoundaryTypes.emplace(
problem.boundaryTypes(
element, lateralFace));
 
  318            if (currentScvfBoundaryTypes)
 
  321                if (currentScvfBoundaryTypes->isNeumann(Indices::velocity(lateralFace.directionIndex())))
 
  324                    FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
 
  325                    const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
 
  328                        * extrusionFactor_(
elemVolVars, lateralFace) * Extrusion::area(
fvGeometry, lateralScvf) * lateralFace.directionSign();
 
  337                if (currentScvfBoundaryTypes->isBeaversJoseph(Indices::velocity(lateralFace.directionIndex())) && lateralFaceBoundaryTypes &&
 
  338                    lateralFaceBoundaryTypes->isNeumann(Indices::velocity(scvf.directionIndex())))
 
  340                    FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
 
  341                    const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
 
  344                        * extrusionFactor_(
elemVolVars, lateralFace) * Extrusion::area(
fvGeometry, lateralScvf) * lateralFace.directionSign();
 
  352            if (lateralFace.boundary())
 
  356                if (lateralFaceBoundaryTypes->isSymmetry())
 
  360                if (lateralFaceBoundaryTypes->isNeumann(Indices::velocity(scvf.directionIndex())))
 
  364                    FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
 
  365                    const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
 
  368                                                  * 
elemVolVars[lateralFace.insideScvIdx()].extrusionFactor() * Extrusion::area(
fvGeometry, lateralScvf);
 
  379            if (lateralFaceBoundaryTypes)
 
  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)
 
  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());
 
  394            if (
problem.enableInertiaTerms())
 
  398                                                                          currentScvfBoundaryTypes, lateralFaceBoundaryTypes,
 
  403                                                                      currentScvfBoundaryTypes, lateralFaceBoundaryTypes,
 
 
  427                                                   const SubControlVolumeFace& scvf,
 
  430                                                   const ElementFaceVariables& elemFaceVars)
 const 
  432        FacePrimaryVariables inOrOutflow(0.0);
 
  434        const auto& insideVolVars = 
elemVolVars[scvf.insideScvIdx()];
 
  437        if (
problem.enableInertiaTerms())
 
  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;
 
  444            inOrOutflow += velocitySelf * velocitySelf * upVolVars.density();
 
  448        const Scalar boundaryPressure = normalizePressure
 
  450                                           problem.initial(scvf)[Indices::pressureIdx])
 
  452        inOrOutflow += boundaryPressure;
 
  455        return inOrOutflow * scvf.directionSign() * Extrusion::area(
fvGeometry, scvf) * insideVolVars.extrusionFactor();
 
 
  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)
 
  492        const auto eIdx = scvf.insideScvIdx();
 
  493        const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
 
  497        const Scalar transportingVelocity = [&]()
 
  499            const auto& faceVars = elemFaceVars[scvf];
 
  500            if (!scvf.boundary())
 
  501                return faceVars.velocityLateralInside(localSubFaceIdx);
 
  505                const auto bcTypes = problem.boundaryTypes(element, scvf);
 
  507                if (bcTypes.isDirichlet(Indices::velocity(lateralFace.directionIndex())))
 
  511                    const auto& lateralBoundaryFacePos = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx);
 
  513                    return problem.dirichlet(element, lateralBoundaryFace)[Indices::velocity(lateralFace.directionIndex())];
 
  515                else if (bcTypes.isBeaversJoseph(Indices::velocity(lateralFace.directionIndex())))
 
  517                    return VelocityGradients::beaversJosephVelocityAtCurrentScvf(problem, element, fvGeometry, scvf,  faceVars,
 
  518                                                                                 currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx);
 
  521                    return faceVars.velocityLateralInside(localSubFaceIdx);
 
  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);
 
  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)
 
  564        const auto eIdx = scvf.insideScvIdx();
 
  565        const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
 
  567        FacePrimaryVariables lateralDiffusiveFlux(0.0);
 
  569        static const bool enableUnsymmetrizedVelocityGradient
 
  575        const auto& insideVolVars = elemVolVars[lateralFace.insideScvIdx()];
 
  576        const auto& outsideVolVars = elemVolVars[lateralFace.outsideScvIdx()];
 
  579        const Scalar muAvg = lateralFace.boundary()
 
  580                             ? insideVolVars.effectiveViscosity()
 
  581                             : (insideVolVars.effectiveViscosity() + outsideVolVars.effectiveViscosity()) * 0.5;
 
  584        if (!enableUnsymmetrizedVelocityGradient)
 
  586            if (!scvf.boundary() ||
 
  587                currentScvfBoundaryTypes->isDirichlet(Indices::velocity(lateralFace.directionIndex())) ||
 
  588                currentScvfBoundaryTypes->isBeaversJoseph(Indices::velocity(lateralFace.directionIndex())))
 
  590                const Scalar velocityGrad_ji = VelocityGradients::velocityGradJI(problem, element, fvGeometry, scvf, faceVars, currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx);
 
  592                lateralDiffusiveFlux -= muAvg * velocityGrad_ji * lateralFace.directionSign();
 
  599        if (!lateralFace.boundary() || !lateralFaceBoundaryTypes->isDirichlet(Indices::pressureIdx))
 
  601            const Scalar velocityGrad_ij = VelocityGradients::velocityGradIJ(problem, element, fvGeometry, scvf, faceVars, currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx);
 
  602            lateralDiffusiveFlux -= muAvg * velocityGrad_ij * lateralFace.directionSign();
 
  606        FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area());
 
  607        return lateralDiffusiveFlux * Extrusion::area(fvGeometry, lateralScvf) * extrusionFactor_(elemVolVars, lateralFace);
 
  624    const GlobalPosition& lateralStaggeredFaceCenter_(
const SubControlVolumeFace& scvf, 
const int localSubFaceIdx)
 const 
  626        return scvf.pairData(localSubFaceIdx).lateralStaggeredFaceCenter;
 
  643    GlobalPosition lateralStaggeredSCVFCenter_(
const SubControlVolumeFace& lateralFace,
 
  644                                               const SubControlVolumeFace& currentFace,
 
  645                                               const int localSubFaceIdx)
 const 
  647        auto pos = lateralStaggeredFaceCenter_(currentFace, localSubFaceIdx) + lateralFace.center();
 
  653    static Scalar extrusionFactor_(
const ElementVolumeVariables& elemVolVars, 
const SubControlVolumeFace& scvf)
 
  655        const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
 
  656        const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
 
  657        return harmonicMean(insideVolVars.extrusionFactor(), outsideVolVars.extrusionFactor());
 
  661    template<
class ...Args, 
bool turbulenceModel = ModelTraits::usesTurbulenceModel(), std::enable_if_t<!turbulenceModel, int> = 0>
 
  662    bool incorporateWallFunction_(Args&&... args)
 const 
  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 
  676        const auto eIdx = scvf.insideScvIdx();
 
  677        const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx);
 
  679        if (problem.useWallFunction(element, lateralFace, Indices::velocity(scvf.directionIndex())))
 
  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);