36    using Scalar = 
typename MDTraits::Scalar;
 
   41    static constexpr auto poreNetworkIndex = 
typename MDTraits::template SubDomain<1>::Index();
 
   46    using FreeFlowMomentumTypeTag = 
typename MDTraits::template SubDomain<freeFlowMomentumIndex>::TypeTag;
 
   47    using PoreNetworkTypeTag = 
typename MDTraits::template SubDomain<poreNetworkIndex>::TypeTag;
 
   49    using CouplingStencils = std::unordered_map<std::size_t, std::vector<std::size_t> >;
 
   50    using CouplingStencil = CouplingStencils::mapped_type;
 
   53    template<std::
size_t id>
 
   54    using SubDomainTypeTag = 
typename MDTraits::template SubDomain<id>::TypeTag;
 
   62    template<std::
size_t id> 
using FVElementGeometry = 
typename GridGeometry<id>::LocalView;
 
   65    template<std::
size_t id> 
using ElementFluxVariablesCache = 
typename GridFluxVariablesCache<id>::LocalView;
 
   66    template<std::
size_t id> 
using Element = 
typename GridView<id>::template Codim<0>::Entity;
 
   68    template<std::
size_t id> 
using SubControlVolumeFace = 
typename FVElementGeometry<id>::SubControlVolumeFace;
 
   69    template<std::
size_t id> 
using SubControlVolume = 
typename FVElementGeometry<id>::SubControlVolume;
 
   71    using VelocityVector = 
typename Element<freeFlowMomentumIndex>::Geometry::GlobalCoordinate;
 
   73    struct FreeFlowMomentumCouplingContext
 
   75        FVElementGeometry<poreNetworkIndex> fvGeometry;
 
   76        ElementVolumeVariables<poreNetworkIndex> elemVolVars;
 
   77        ElementFluxVariablesCache<poreNetworkIndex> elemFluxVarsCache;
 
   78        std::size_t poreNetworkDofIdx;
 
   81    struct PoreNetworkCouplingContext
 
   83        SubControlVolumeFace<freeFlowMomentumIndex> freeFlowMomentumScvf;
 
   84        VelocityVector faceVelocity;
 
   85        std::size_t freeFlowMomentumDofIdx;
 
   88    using CouplingMapper = StaggeredFreeFlowPoreNetworkCouplingMapper;
 
   89    using GridVariablesTuple = 
typename MDTraits::template TupleOfSharedPtr<GridVariables>;
 
   99    void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> freeFlowMomentumProblem,
 
  100              std::shared_ptr<Problem<poreNetworkIndex>> porousMediumProblem,
 
  101              GridVariablesTuple&& gridVariables,
 
  102              std::shared_ptr<CouplingMapper> couplingMapper,
 
  105        couplingMapper_ = couplingMapper;
 
  106        gridVariables_ = gridVariables;
 
  107        this->
setSubProblems(std::make_tuple(freeFlowMomentumProblem, porousMediumProblem));
 
 
  122    template<std::
size_t i, 
class Assembler>
 
  123    void bindCouplingContext(Dune::index_constant<i> domainI, 
const Element<i>& element, 
const Assembler& assembler)
 const 
  125        bindCouplingContext_(domainI, element);
 
 
  131    template<std::
size_t i>
 
  134        bindCouplingContext_(domainI, element);
 
 
  140    template<std::
size_t i, std::
size_t j, 
class LocalAssemblerI>
 
  142                               const LocalAssemblerI& localAssemblerI,
 
  143                               Dune::index_constant<j> domainJ,
 
  144                               std::size_t dofIdxGlobalJ,
 
  145                               const PrimaryVariables<j>& priVarsJ,
 
  148        this->
curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
 
  150        const auto eIdx = localAssemblerI.fvGeometry().gridGeometry().elementMapper().index(localAssemblerI.fvGeometry().element());
 
  151        if (!isCoupledElement_(domainI, eIdx))
 
  164                auto& context = std::get<poreNetworkIndex>(couplingContext_);
 
  165                for (
auto& c : context)
 
  167                    if (c.freeFlowMomentumDofIdx == dofIdxGlobalJ)
 
  169                        assert(c.freeFlowMomentumScvf.isFrontal() && c.freeFlowMomentumScvf.boundary());
 
  170                        c.faceVelocity = 
faceVelocity(c.freeFlowMomentumScvf, c.freeFlowMomentumDofIdx);
 
  179            assert(couplingContextBoundForElement_[domainI] == localAssemblerI.fvGeometry().gridGeometry().elementMapper().index(localAssemblerI.fvGeometry().element()));
 
  181            auto& context = std::get<freeFlowMomentumIndex>(couplingContext_)[0];
 
  182            const auto& ggJ = context.fvGeometry.gridGeometry();
 
  183            const auto& element = context.fvGeometry.element();
 
  186            for (
const auto& scv : scvs(context.fvGeometry))
 
  188                if (scv.dofIndex() == dofIdxGlobalJ)
 
  190                    if constexpr (ElementVolumeVariables<poreNetworkIndex>::GridVolumeVariables::cachingEnabled)
 
  191                        gridVars_(
poreNetworkIndex).curGridVolVars().volVars(scv).update(std::move(elemSol), this->
problem(domainJ), element, scv);
 
  193                        context.elemVolVars[scv].update(std::move(elemSol), this->
problem(domainJ), element, scv);
 
  197            const auto& scvf = context.fvGeometry.scvf(0);
 
  198            if constexpr (ElementFluxVariablesCache<poreNetworkIndex>::GridFluxVariablesCache::cachingEnabled)
 
  200                const auto eIdx = ggJ.elementMapper().index(element);
 
  201                gridVars_(
poreNetworkIndex).gridFluxVarsCache().cache(eIdx, scvf.index()).update(this->
problem(domainJ), element, context.fvGeometry, context.elemVolVars, scvf);
 
  204                context.elemFluxVarsCache[scvf].update(this->
problem(domainJ), element, context.fvGeometry, context.elemVolVars, scvf);
 
 
  213    const auto& 
couplingContext(
const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry,
 
  214                                const SubControlVolumeFace<freeFlowMomentumIndex> scvf)
 const 
  216        auto& contexts = std::get<freeFlowMomentumIndex>(couplingContext_);
 
  218        if (contexts.empty() || couplingContextBoundForElement_[
freeFlowMomentumIndex] != fvGeometry.elementIndex())
 
 
  229                                const SubControlVolume<poreNetworkIndex> scv)
 const 
  231        auto& contexts = std::get<poreNetworkIndex>(couplingContext_);
 
  233        const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
 
  234        if (contexts.empty() || couplingContextBoundForElement_[
poreNetworkIndex] != eIdx)
 
 
  248    const CouplingStencil& 
couplingStencil(Dune::index_constant<poreNetworkIndex> domainI,
 
  249                                           const Element<poreNetworkIndex>& element,
 
  250                                           Dune::index_constant<freeFlowMomentumIndex> domainJ)
 const 
  252        const auto eIdx = this->
problem(domainI).gridGeometry().elementMapper().index(element);
 
  253        return couplingMapper_->poreNetworkToFreeFlowMomentumCouplingStencil(eIdx);
 
 
  265    const CouplingStencil& 
couplingStencil(Dune::index_constant<freeFlowMomentumIndex> domainI,
 
  266                                           const Element<freeFlowMomentumIndex>& elementI,
 
  267                                           const SubControlVolume<freeFlowMomentumIndex>& scvI,
 
  268                                           Dune::index_constant<poreNetworkIndex> domainJ)
 const 
  270        return couplingMapper_->freeFlowMomentumToPoreNetworkCouplingStencil(scvI.dofIndex());
 
 
  279    template<
class LocalAssemblerI, std::
size_t j>
 
  281                                        const LocalAssemblerI& localAssemblerI,
 
  282                                        const SubControlVolume<freeFlowMomentumIndex>& scvI,
 
  283                                        Dune::index_constant<j> domainJ,
 
  284                                        std::size_t dofIdxGlobalJ) 
const 
  286        return localAssemblerI.evalLocalResidual();
 
 
  294    bool isCoupledLateralScvf(Dune::index_constant<freeFlowMomentumIndex> domainI, 
const SubControlVolumeFace<freeFlowMomentumIndex>& scvf)
 const 
  295    { 
return  couplingMapper_->isCoupledFreeFlowMomentumLateralScvf(scvf.index()); }
 
 
  300    bool isCoupled(Dune::index_constant<freeFlowMomentumIndex> domainI, 
const SubControlVolumeFace<freeFlowMomentumIndex>& scvf)
 const 
  302        return couplingMapper_->isCoupledFreeFlowMomentumScvf(scvf.index()) || couplingMapper_->isCoupledFreeFlowMomentumLateralScvf(scvf.index());
 
 
  310    bool isCoupled(Dune::index_constant<poreNetworkIndex> domainI,
 
  311                   const SubControlVolume<poreNetworkIndex>& scv)
 const 
  312    { 
return couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()); }
 
 
  317    auto faceVelocity(
const SubControlVolumeFace<freeFlowMomentumIndex>& scvf,
 
  318                      std::size_t freeFlowMomentumDofIdx)
 const 
  321        auto velocity = scvf.unitOuterNormal();
 
  323        std::for_each(velocity.begin(), velocity.end(), [](
auto& v){ v = abs(v); });
 
 
  336    template<std::
size_t i>
 
  337    bool isCoupledElement_(Dune::index_constant<i> domainI, std::size_t eIdx)
 const 
  348    template<std::
size_t i>
 
  349    void bindCouplingContext_(Dune::index_constant<i> domainI, 
const Element<i>& element)
 const 
  351        const auto fvGeometry = 
localView(this->
problem(domainI).gridGeometry()).bindElement(element);
 
  352        bindCouplingContext_(domainI, fvGeometry);
 
  358    void bindCouplingContext_(Dune::index_constant<freeFlowMomentumIndex> domainI, 
const FVElementGeometry<freeFlowMomentumIndex>& fvGeometry)
 const 
  360        auto& context = std::get<domainI>(couplingContext_);
 
  361        const auto eIdx = fvGeometry.elementIndex();
 
  364        if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx))
 
  367        bool bindElement = 
false;
 
  368        std::size_t actuallyCoupledFreeFlowElementIndex;
 
  372        if (couplingMapper_->isCoupledFreeFlowElement(eIdx))
 
  375            actuallyCoupledFreeFlowElementIndex = eIdx;
 
  381            for (
const auto& intersection : intersections(fvGeometry.gridGeometry().gridView(), fvGeometry.element()))
 
  383                const auto dofIdx = fvGeometry.gridGeometry().intersectionMapper().globalIntersectionIndex(fvGeometry.element(), intersection.indexInInside());
 
  384                if (couplingMapper_->isCoupledFreeFlowMomentumDof(dofIdx))
 
  387                    actuallyCoupledFreeFlowElementIndex = fvGeometry.gridGeometry().elementMapper().index(intersection.outside());
 
  397        couplingContextBoundForElement_[domainI] = eIdx;
 
  403        const auto poreNetworkElemIdx = couplingMapper_->freeFlowElementToPNMElementMap().at(actuallyCoupledFreeFlowElementIndex);
 
  406        poreNetworkFVGeometry.bindElement(poreNetworkElement);
 
  408        poreNetworkElemFluxVarsCache.bind(poreNetworkElement, poreNetworkFVGeometry, poreNetworkElemVolVars);
 
  410        const std::size_t poreNetworkDofIdx = [&]
 
  413            std::size_t counter = 0;
 
  414            for (
const auto& scv : scvs(poreNetworkFVGeometry))
 
  416                if (couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()))
 
  418                    idx = scv.dofIndex();
 
  424                DUNE_THROW(Dune::InvalidStateException, 
"Exactly one pore per throat needs to be coupled with the FF domain");
 
  429        context.push_back({std::move(poreNetworkFVGeometry),
 
  430                           std::move(poreNetworkElemVolVars),
 
  431                           std::move(poreNetworkElemFluxVarsCache),
 
  439    void bindCouplingContext_(Dune::index_constant<poreNetworkIndex> domainI, 
const FVElementGeometry<poreNetworkIndex>& fvGeometry)
 const 
  441        auto& context = std::get<domainI>(couplingContext_);
 
  442        const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
 
  445        if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx))
 
  449        couplingContextBoundForElement_[domainI] = eIdx;
 
  452        const auto& freeFlowElements = couplingMapper_->pnmElementToFreeFlowElementsMap().at(eIdx);
 
  455        for (
const auto ffElementIdx : freeFlowElements)
 
  458            ffFVGeometry.bindElement(ffElement);
 
  459            for (
const auto& scv : scvs(ffFVGeometry))
 
  461                if (couplingMapper_->isCoupledFreeFlowMomentumDof(scv.dofIndex()))
 
  463                    if (std::any_of(stencil.begin(), stencil.end(), [&](
const auto x){ return scv.dofIndex() == x; } ))
 
  465                        const auto& coupledScvf = ffFVGeometry.frontalScvfOnBoundary(scv);
 
  466                        context.push_back({coupledScvf,
 
  480    template<std::
size_t i>
 
  481    const GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
 const 
  483        if (std::get<i>(gridVariables_))
 
  484            return *std::get<i>(gridVariables_);
 
  486            DUNE_THROW(Dune::InvalidStateException, 
"The gridVariables pointer was not set. Use setGridVariables() before calling this function");
 
  493    template<std::
size_t i>
 
  494    GridVariables<i>& gridVars_(Dune::index_constant<i> domainIdx)
 
  496        if (std::get<i>(gridVariables_))
 
  497            return *std::get<i>(gridVariables_);
 
  499            DUNE_THROW(Dune::InvalidStateException, 
"The gridVariables pointer was not set. Use setGridVariables() before calling this function");
 
  503    GridVariablesTuple gridVariables_;
 
  505    mutable std::tuple<std::vector<FreeFlowMomentumCouplingContext>, std::vector<PoreNetworkCouplingContext>> couplingContext_;
 
  506    mutable std::array<std::size_t, 2> couplingContextBoundForElement_;
 
  508    std::shared_ptr<CouplingMapper> couplingMapper_;
 
 
decltype(auto) evalCouplingResidual(Dune::index_constant< i > domainI, const LocalAssemblerI &localAssemblerI, Dune::index_constant< j > domainJ, std::size_t dofIdxGlobalJ) const
Definition multidomain/couplingmanager.hh:237
The interface of the coupling manager for multi domain problems.