58    template<std::
size_t id> 
using SubDomainTypeTag = 
typename Traits::template SubDomain<id>::TypeTag;
 
   61    template<std::
size_t id> 
using GridView = 
typename GridGeometry<id>::GridView;
 
   62    template<std::
size_t id> 
using Element = 
typename GridView<id>::template Codim<0>::Entity;
 
   63    template<std::
size_t id> 
using ElementSeed = 
typename GridView<id>::Grid::template Codim<0>::EntitySeed;
 
   64    template<std::
size_t id> 
using FVElementGeometry = 
typename GridGeometry<id>::LocalView;
 
   65    template<std::
size_t id> 
using SubControlVolume = 
typename FVElementGeometry<id>::SubControlVolume;
 
   66    template<std::
size_t id> 
using SubControlVolumeFace = 
typename FVElementGeometry<id>::SubControlVolumeFace;
 
   67    template<std::
size_t id> 
using GridVariables = 
typename Traits::template SubDomain<id>::GridVariables;
 
   68    template<std::
size_t id> 
using ElementVolumeVariables = 
typename GridVariables<id>::GridVolumeVariables::LocalView;
 
   69    template<std::
size_t id> 
using GridFluxVariablesCache = 
typename GridVariables<id>::GridFluxVariablesCache;
 
   73    using Scalar = 
typename Traits::Scalar;
 
   74    using SolutionVector = 
typename Traits::SolutionVector;
 
   76    template<std::
size_t id>
 
   77    using SubSolutionVector
 
   78        = std::decay_t<decltype(std::declval<SolutionVector>()[Dune::index_constant<id>()])>;
 
   80    template<std::
size_t id>
 
   81    using ConstSubSolutionVectorPtr = 
const SubSolutionVector<id>*;
 
   83    using PrevSolutionVectorStorage = 
typename Traits::template Tuple<ConstSubSolutionVectorPtr>;
 
   85    using CouplingStencilType = std::vector<std::size_t>;
 
   87    using GridVariablesTuple = 
typename Traits::template TupleOfSharedPtr<GridVariables>;
 
   89    using FluidSystem = 
typename VolumeVariables<freeFlowMassIndex>::FluidSystem;
 
   91    using VelocityVector = 
typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition;
 
   92    static_assert(std::is_same_v<VelocityVector, typename SubControlVolumeFace<freeFlowMomentumIndex>::GlobalPosition>);
 
   94    struct MomentumCouplingContext
 
   96        FVElementGeometry<freeFlowMassIndex> fvGeometry;
 
   97        ElementVolumeVariables<freeFlowMassIndex> curElemVolVars;
 
   98        ElementVolumeVariables<freeFlowMassIndex> prevElemVolVars;
 
  102    struct MassAndEnergyCouplingContext
 
  104        MassAndEnergyCouplingContext(FVElementGeometry<freeFlowMomentumIndex>&& f, 
const std::size_t i)
 
  105        : fvGeometry(std::move(f))
 
  109        FVElementGeometry<freeFlowMomentumIndex> fvGeometry;
 
  115    static constexpr auto pressureIdx = VolumeVariables<freeFlowMassIndex>::Indices::pressureIdx;
 
  123    void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
 
  124              std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
 
  125              GridVariablesTuple&& gridVariables,
 
  126              const SolutionVector& 
curSol)
 
  128        this->momentumCouplingContext_().clear();
 
  129        this->massAndEnergyCouplingContext_().clear();
 
  131        this->
setSubProblems(std::make_tuple(momentumProblem, massProblem));
 
  132        gridVariables_ = gridVariables;
 
  135        computeCouplingStencils_();
 
 
  139    void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
 
  140              std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
 
  141              GridVariablesTuple&& gridVariables,
 
  142              const SolutionVector& 
curSol,
 
  143              const SolutionVector& prevSol)
 
  145        init(momentumProblem, massProblem, std::forward<GridVariablesTuple>(gridVariables), 
curSol);
 
  147        Dune::Hybrid::forEach(std::make_index_sequence<Traits::numSubDomains>{}, [&](
auto i)
 
  148        { std::get<i>(prevSolutions_) = &prevSol[i]; });
 
 
  152    void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
 
  153              std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
 
  154              GridVariablesTuple&& gridVariables,
 
  157        this->momentumCouplingContext_().clear();
 
  158        this->massAndEnergyCouplingContext_().clear();
 
  160        this->
setSubProblems(std::make_tuple(momentumProblem, massProblem));
 
  161        gridVariables_ = gridVariables;
 
  164        computeCouplingStencils_();
 
 
  168    void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> momentumProblem,
 
  169              std::shared_ptr<Problem<freeFlowMassIndex>> massProblem,
 
  170              GridVariablesTuple&& gridVariables,
 
  172              const PrevSolutionVectorStorage& prevSol)
 
  174        init(momentumProblem, massProblem, std::forward<GridVariablesTuple>(gridVariables), 
curSol);
 
  175        prevSolutions_ = prevSol;
 
 
  199    template<std::
size_t j, 
class LocalAssemblerI>
 
  201                                        const LocalAssemblerI& localAssemblerI,
 
  202                                        const SubControlVolume<freeFlowMomentumIndex>& scvI,
 
  203                                        Dune::index_constant<j> domainJ,
 
  204                                        std::size_t dofIdxGlobalJ)
 const 
  206        const auto& 
problem = localAssemblerI.problem();
 
  207        const auto& element = localAssemblerI.element();
 
  208        const auto& fvGeometry = localAssemblerI.fvGeometry();
 
  209        const auto& curElemVolVars = localAssemblerI.curElemVolVars();
 
  210        const auto& prevElemVolVars = localAssemblerI.prevElemVolVars();
 
  211        typename LocalAssemblerI::ElementResidualVector residual(localAssemblerI.element().subEntities(1));
 
  212        const auto& localResidual = localAssemblerI.localResidual();
 
  214        localResidual.evalSource(residual, 
problem, element, fvGeometry, curElemVolVars, scvI);
 
  216        for (
const auto& scvf : scvfs(fvGeometry, scvI))
 
  217            localResidual.evalFlux(residual, 
problem, element, fvGeometry, curElemVolVars, localAssemblerI.elemBcTypes(), localAssemblerI.elemFluxVarsCache(), scvf);
 
  219        if (!localAssemblerI.assembler().isStationaryProblem())
 
  221            assert(isTransient_());
 
  222            localResidual.evalStorage(residual, 
problem, element, fvGeometry, prevElemVolVars, curElemVolVars, scvI);
 
 
  236    Scalar 
pressure(
const Element<freeFlowMomentumIndex>& element,
 
  237                    const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
 
  238                    const SubControlVolumeFace<freeFlowMomentumIndex>& scvf)
 const 
  240        assert(scvf.isFrontal() && !scvf.isLateral() && !scvf.boundary());
 
 
  250    Scalar 
cellPressure(
const Element<freeFlowMassIndex>& element,
 
  251                        const SubControlVolumeFace<freeFlowMassIndex>& scvf)
 const 
 
  259    Scalar 
density(
const Element<freeFlowMomentumIndex>& element,
 
  260                   const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
 
  261                   const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
 
  262                   const bool considerPreviousTimeStep = 
false)
 const 
  264        assert(!(considerPreviousTimeStep && !isTransient_()));
 
  265        bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
 
  266        const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
 
  267        const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
 
  269        const auto rho = [&](
const auto& elemVolVars)
 
  272                return elemVolVars[insideMassScv].density();
 
  275                const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
 
  276                const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
 
  278                return 0.5*(elemVolVars[insideMassScv].density() + elemVolVars[outsideMassScv].
density());
 
  282        return considerPreviousTimeStep ? rho(momentumCouplingContext_()[0].prevElemVolVars)
 
  283                                        : rho(momentumCouplingContext_()[0].curElemVolVars);
 
 
  287                                 const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
 
  288                                 const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
 
  289                                 const bool considerPreviousTimeStep = 
false)
 const 
  291        assert(!(considerPreviousTimeStep && !isTransient_()));
 
  292        bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
 
  293        const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
 
  294        const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
 
  296        const auto result = [&](
const auto& elemVolVars)
 
  299                return std::make_pair(elemVolVars[insideMassScv].
density(), elemVolVars[insideMassScv].
density());
 
  302                const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
 
  303                const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
 
  304                return std::make_pair(elemVolVars[insideMassScv].
density(), elemVolVars[outsideMassScv].
density());
 
  308        return considerPreviousTimeStep ? result(momentumCouplingContext_()[0].prevElemVolVars)
 
  309                                        : result(momentumCouplingContext_()[0].curElemVolVars);
 
 
  315    Scalar 
density(
const Element<freeFlowMomentumIndex>& element,
 
  316                   const SubControlVolume<freeFlowMomentumIndex>& scv,
 
  317                   const bool considerPreviousTimeStep = 
false)
 const 
  319        assert(!(considerPreviousTimeStep && !isTransient_()));
 
  320        bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, scv.elementIndex());
 
  321        const auto& massScv = (*scvs(momentumCouplingContext_()[0].fvGeometry).begin());
 
  323        return considerPreviousTimeStep ? momentumCouplingContext_()[0].prevElemVolVars[massScv].density()
 
  324                                        : momentumCouplingContext_()[0].curElemVolVars[massScv].density();
 
 
  331                              const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
 
  332                              const SubControlVolumeFace<freeFlowMomentumIndex>& scvf)
 const 
  334        bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
 
  336        const auto& insideMomentumScv = fvGeometry.scv(scvf.insideScvIdx());
 
  337        const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(insideMomentumScv.elementIndex());
 
  340            return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
 
  342        const auto& outsideMomentumScv = fvGeometry.scv(scvf.outsideScvIdx());
 
  343        const auto& outsideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(outsideMomentumScv.elementIndex());
 
  345        const auto mu = [&](
const auto& elemVolVars)
 
  348            return 0.5*(elemVolVars[insideMassScv].viscosity() + elemVolVars[outsideMassScv].viscosity());
 
  351        return mu(momentumCouplingContext_()[0].curElemVolVars);
 
 
  358                              const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
 
  359                              const SubControlVolume<freeFlowMomentumIndex>& scv)
 const 
  361        bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex>(), element, fvGeometry.elementIndex());
 
  362        const auto& insideMassScv = momentumCouplingContext_()[0].fvGeometry.scv(scv.elementIndex());
 
  363        return momentumCouplingContext_()[0].curElemVolVars[insideMassScv].viscosity();
 
 
  369    VelocityVector 
faceVelocity(
const Element<freeFlowMassIndex>& element,
 
  370                                const SubControlVolumeFace<freeFlowMassIndex>& scvf)
 const 
  373        bindCouplingContext_(Dune::index_constant<freeFlowMassIndex>(), element, scvf.insideScvIdx());
 
  376        const auto localMomentumScvIdx = massScvfToMomentumScvIdx_(scvf, massAndEnergyCouplingContext_()[0].fvGeometry);
 
  377        const auto& scvJ = massAndEnergyCouplingContext_()[0].fvGeometry.scv(localMomentumScvIdx);
 
  380        typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition velocity;
 
  381        velocity[scvJ.dofAxis()] = 1.0;
 
 
  398    template<std::
size_t j>
 
  399    const CouplingStencilType& 
couplingStencil(Dune::index_constant<freeFlowMomentumIndex> domainI,
 
  400                                               const Element<freeFlowMomentumIndex>& elementI,
 
  401                                               const SubControlVolume<freeFlowMomentumIndex>& scvI,
 
  402                                               Dune::index_constant<j> domainJ)
 const 
 
  403    { 
return emptyStencil_; }
 
  419    const CouplingStencilType& 
couplingStencil(Dune::index_constant<freeFlowMassIndex> domainI,
 
  420                                              const Element<freeFlowMassIndex>& elementI,
 
  421                                              Dune::index_constant<freeFlowMomentumIndex> domainJ)
 const 
  424        return massAndEnergyToMomentumStencils_[eIdx];
 
 
  436    const CouplingStencilType& 
couplingStencil(Dune::index_constant<freeFlowMomentumIndex> domainI,
 
  437                                               const Element<freeFlowMomentumIndex>& elementI,
 
  438                                               const SubControlVolume<freeFlowMomentumIndex>& scvI,
 
  439                                               Dune::index_constant<freeFlowMassIndex> domainJ)
 const 
  441        return momentumToMassAndEnergyStencils_[scvI.index()];
 
 
  452    template<std::
size_t i, std::
size_t j, 
class LocalAssemblerI>
 
  454                               const LocalAssemblerI& localAssemblerI,
 
  455                               Dune::index_constant<j> domainJ,
 
  456                               std::size_t dofIdxGlobalJ,
 
  457                               const PrimaryVariables<j>& priVarsJ,
 
  460        this->
curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
 
  464            bindCouplingContext_(domainI, localAssemblerI.element());
 
  467            const auto& deflectedElement = 
problem.gridGeometry().element(dofIdxGlobalJ);
 
  469            const auto& fvGeometry = momentumCouplingContext_()[0].fvGeometry;
 
  470            const auto scvIdxJ = dofIdxGlobalJ;
 
  471            const auto& scv = fvGeometry.scv(scvIdxJ);
 
  473            if constexpr (ElementVolumeVariables<freeFlowMassIndex>::GridVolumeVariables::cachingEnabled)
 
  474                gridVars_(
freeFlowMassIndex).curGridVolVars().volVars(scv).update(std::move(elemSol), 
problem, deflectedElement, scv);
 
  476                momentumCouplingContext_()[0].curElemVolVars[scv].update(std::move(elemSol), 
problem, deflectedElement, scv);
 
 
  497    template<std::
size_t i, 
class AssembleElementFunc>
 
  498    void assembleMultithreaded(Dune::index_constant<i> domainI, AssembleElementFunc&& assembleElement)
 const 
  500        if (elementSets_.empty())
 
  501            DUNE_THROW(Dune::InvalidStateException, 
"Call computeColorsForAssembly before assembling in parallel!");
 
  508        for (
const auto& elements : elementSets_)
 
  512                const auto element = grid.entity(elements[eIdx]);
 
  513                assembleElement(element);
 
 
  519    void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
 
  520                              const Element<freeFlowMomentumIndex>& elementI)
 const 
  523        bindCouplingContext_(domainI, elementI, eIdx);
 
  526    void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI,
 
  527                              const Element<freeFlowMomentumIndex>& elementI,
 
  528                              const std::size_t eIdx)
 const 
  530        if (momentumCouplingContext_().empty())
 
  533            fvGeometry.bind(elementI);
 
  544            momentumCouplingContext_().emplace_back(MomentumCouplingContext{std::move(fvGeometry), std::move(curElemVolVars), std::move(prevElemVolVars), eIdx});
 
  546        else if (eIdx != momentumCouplingContext_()[0].eIdx)
 
  548            momentumCouplingContext_()[0].eIdx = eIdx;
 
  549            momentumCouplingContext_()[0].fvGeometry.bind(elementI);
 
  550            momentumCouplingContext_()[0].curElemVolVars.bind(elementI, momentumCouplingContext_()[0].fvGeometry, this->
curSol(
freeFlowMassIndex));
 
  553                momentumCouplingContext_()[0].prevElemVolVars.bindElement(elementI, momentumCouplingContext_()[0].fvGeometry, prevSol_(
freeFlowMassIndex));
 
  557    void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
 
  558                              const Element<freeFlowMassIndex>& elementI)
 const 
  561        bindCouplingContext_(domainI, elementI, eIdx);
 
  564    void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI,
 
  565                              const Element<freeFlowMassIndex>& elementI,
 
  566                              const std::size_t eIdx)
 const 
  568        if (massAndEnergyCouplingContext_().empty())
 
  571            auto fvGeometry = 
localView(gridGeometry);
 
  572            fvGeometry.bindElement(elementI);
 
  573            massAndEnergyCouplingContext_().emplace_back(std::move(fvGeometry), eIdx);
 
  575        else if (eIdx != massAndEnergyCouplingContext_()[0].eIdx)
 
  577            massAndEnergyCouplingContext_()[0].eIdx = eIdx;
 
  578            massAndEnergyCouplingContext_()[0].fvGeometry.bindElement(elementI);
 
  586    template<std::
size_t i>
 
  587    const GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
 const 
  589        if (std::get<i>(gridVariables_))
 
  590            return *std::get<i>(gridVariables_);
 
  592            DUNE_THROW(Dune::InvalidStateException, 
"The gridVariables pointer was not set. Use setGridVariables() before calling this function");
 
  599    template<std::
size_t i>
 
  600    GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
 
  602        if (std::get<i>(gridVariables_))
 
  603            return *std::get<i>(gridVariables_);
 
  605            DUNE_THROW(Dune::InvalidStateException, 
"The gridVariables pointer was not set. Use setGridVariables() before calling this function");
 
  609    void computeCouplingStencils_()
 
  613        auto momentumFvGeometry = 
localView(momentumGridGeometry);
 
  614        massAndEnergyToMomentumStencils_.clear();
 
  615        massAndEnergyToMomentumStencils_.resize(momentumGridGeometry.gridView().size(0));
 
  617        momentumToMassAndEnergyStencils_.clear();
 
  618        momentumToMassAndEnergyStencils_.resize(momentumGridGeometry.numScv());
 
  620        for (
const auto& element : elements(momentumGridGeometry.gridView()))
 
  622            const auto eIdx = momentumGridGeometry.elementMapper().index(element);
 
  623            momentumFvGeometry.bind(element);
 
  624            for (
const auto& scv : scvs(momentumFvGeometry))
 
  626                massAndEnergyToMomentumStencils_[eIdx].push_back(scv.dofIndex());
 
  627                momentumToMassAndEnergyStencils_[scv.index()].push_back(eIdx);
 
  630                if constexpr (FluidSystem::isCompressible(0))
 
  633                    for (
const auto& scvf : scvfs(momentumFvGeometry, scv))
 
  635                        if (scvf.isLateral() && !scvf.boundary())
 
  637                            const auto& outsideScv = momentumFvGeometry.scv(scvf.outsideScvIdx());
 
  638                            momentumToMassAndEnergyStencils_[scv.index()].push_back(outsideScv.elementIndex());
 
  646    std::size_t massScvfToMomentumScvIdx_(
const SubControlVolumeFace<freeFlowMassIndex>& massScvf,
 
  647                                          [[maybe_unused]] 
const FVElementGeometry<freeFlowMomentumIndex>& momentumFVGeometry)
 const 
  649        if constexpr (ConsistentlyOrientedGrid<typename GridView<freeFlowMomentumIndex>::Grid>{})
 
  650            return massScvf.index();
 
  653            static const bool makeConsistentlyOriented = 
getParam<bool>(
"Grid.MakeConsistentlyOriented", 
true);
 
  654            if (!makeConsistentlyOriented)
 
  655                return massScvf.index();
 
  657            for (
const auto& momentumScv : scvs(momentumFVGeometry))
 
  659                typename SubControlVolumeFace<freeFlowMassIndex>::GlobalPosition momentumUnitOuterNormal(0.0);
 
  660                momentumUnitOuterNormal[momentumScv.dofAxis()] = momentumScv.directionSign();
 
  661                if (Dune::FloatCmp::eq<
typename GridView<freeFlowMomentumIndex>::ctype>(massScvf.unitOuterNormal()*momentumUnitOuterNormal, 1.0))
 
  662                    return momentumScv.index();
 
  664            DUNE_THROW(Dune::InvalidStateException, 
"No Momentum SCV found");
 
  668    CouplingStencilType emptyStencil_;
 
  669    std::vector<CouplingStencilType> momentumToMassAndEnergyStencils_;
 
  670    std::vector<CouplingStencilType> massAndEnergyToMomentumStencils_;
 
  672    std::vector<MomentumCouplingContext>& momentumCouplingContext_()
 const 
  673    { 
return momentumCouplingContextImpl_; }
 
  675    std::vector<MassAndEnergyCouplingContext>& massAndEnergyCouplingContext_()
 const 
  676    { 
return massAndEnergyCouplingContextImpl_; }
 
  678    mutable std::vector<MassAndEnergyCouplingContext> massAndEnergyCouplingContextImpl_;
 
  679    mutable std::vector<MomentumCouplingContext> momentumCouplingContextImpl_;
 
  682    GridVariablesTuple gridVariables_;
 
  684    bool isTransient_()
 const 
  685    { 
return std::get<0>(prevSolutions_) != 
nullptr; }
 
  687    template<std::
size_t i>
 
  688    const SubSolutionVector<i>& prevSol_(Dune::index_constant<i>)
 const 
  689    { 
return *std::get<i>(prevSolutions_); }
 
  691    PrevSolutionVectorStorage prevSolutions_;
 
  693    std::deque<std::vector<ElementSeed<freeFlowMomentumIndex>>> elementSets_;