36    using Scalar = 
typename MDTraits::Scalar;
 
   40    static constexpr auto freeFlowMassIndex = 
typename MDTraits::template SubDomain<0>::Index();
 
   41    static constexpr auto poreNetworkIndex = 
typename MDTraits::template SubDomain<1>::Index();
 
   47    using FreeFlowMassTypeTag = 
typename MDTraits::template SubDomain<freeFlowMassIndex>::TypeTag;
 
   48    using PoreNetworkTypeTag = 
typename MDTraits::template SubDomain<poreNetworkIndex>::TypeTag;
 
   50    using CouplingStencils = std::unordered_map<std::size_t, std::vector<std::size_t> >;
 
   51    using CouplingStencil = CouplingStencils::mapped_type;
 
   54    template<std::
size_t id>
 
   55    using SubDomainTypeTag = 
typename MDTraits::template SubDomain<id>::TypeTag;
 
   63    template<std::
size_t id> 
using FVElementGeometry = 
typename GridGeometry<id>::LocalView;
 
   65    template<std::
size_t id> 
using Element = 
typename GridView<id>::template Codim<0>::Entity;
 
   67    template<std::
size_t id> 
using SubControlVolumeFace = 
typename FVElementGeometry<id>::SubControlVolumeFace;
 
   68    template<std::
size_t id> 
using SubControlVolume = 
typename FVElementGeometry<id>::SubControlVolume;
 
   70    using VelocityVector = 
typename Element<freeFlowMassIndex>::Geometry::GlobalCoordinate;
 
   72    struct FreeFlowMassCouplingContext
 
   74        SubControlVolume<poreNetworkIndex> scv;
 
   75        VolumeVariables<poreNetworkIndex> volVars;
 
   76        mutable VelocityVector velocity; 
 
   79    struct PoreNetworkCouplingContext
 
   81        SubControlVolume<freeFlowMassIndex> scv;
 
   82        SubControlVolumeFace<freeFlowMassIndex> scvf;
 
   83        VolumeVariables<freeFlowMassIndex> volVars;
 
   84        mutable VelocityVector velocity; 
 
   87    using CouplingMapper = StaggeredFreeFlowPoreNetworkCouplingMapper;
 
   97    void init(std::shared_ptr<Problem<freeFlowMassIndex>> freeFlowMassProblem,
 
   98              std::shared_ptr<Problem<poreNetworkIndex>> pnmProblem,
 
   99              std::shared_ptr<CouplingMapper> couplingMapper,
 
  102        couplingMapper_ = couplingMapper;
 
  103        this->
setSubProblems(std::make_tuple(freeFlowMassProblem, pnmProblem));
 
 
  117    template<std::
size_t i, 
class Assembler>
 
  118    void bindCouplingContext(Dune::index_constant<i> domainI, 
const Element<i>& element, 
const Assembler& assembler)
 const 
  120        bindCouplingContext_(domainI, element);
 
 
  126    template<std::
size_t i, std::
size_t j, 
class LocalAssemblerI>
 
  128                               const LocalAssemblerI& localAssemblerI,
 
  129                               Dune::index_constant<j> domainJ,
 
  130                               std::size_t dofIdxGlobalJ,
 
  131                               const PrimaryVariables<j>& priVarsJ,
 
  134        this->
curSol(domainJ)[dofIdxGlobalJ][pvIdxJ] = priVarsJ[pvIdxJ];
 
  141        auto& context = std::get<1-j>(couplingContext_);
 
  142        for (
auto& c : context)
 
  144            if (c.scv.dofIndex() == dofIdxGlobalJ)
 
  147                const auto& element = 
problem.gridGeometry().element(c.scv.elementIndex());
 
  149                c.volVars.update(elemSol, 
problem, element, c.scv);
 
 
  160                                const FVElementGeometry<freeFlowMassIndex>& fvGeometry,
 
  161                                const SubControlVolumeFace<freeFlowMassIndex> scvf)
 const 
  163        auto& contexts = std::get<freeFlowMassIndex>(couplingContext_);
 
  164        const auto eIdx = scvf.insideScvIdx();
 
  166        if (contexts.empty() || couplingContextBoundForElement_[
freeFlowMassIndex] != eIdx)
 
 
  177                                const FVElementGeometry<poreNetworkIndex>& fvGeometry,
 
  178                                const SubControlVolume<poreNetworkIndex> scv)
 const 
  180        auto& contexts = std::get<poreNetworkIndex>(couplingContext_);
 
  181        const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
 
  183        if (contexts.empty() || couplingContextBoundForElement_[
poreNetworkIndex] != eIdx)
 
 
  197    template<std::
size_t i, std::
size_t j>
 
  199                                           const Element<i>& element,
 
  200                                           Dune::index_constant<j> domainJ)
 const 
  202        const auto eIdx = this->
problem(domainI).gridGeometry().elementMapper().index(element);
 
  204            return couplingMapper_->freeFlowMassToPoreNetworkCouplingStencil(eIdx);
 
  206            return couplingMapper_->poreNetworkToFreeFlowMassCouplingStencil(eIdx);
 
 
  214    bool isCoupled(Dune::index_constant<freeFlowMassIndex> domainI,
 
  215                   const SubControlVolumeFace<freeFlowMassIndex>& scvf)
 const 
  216    { 
return couplingMapper_->isCoupledFreeFlowMassScvf(scvf.index()); }
 
 
  223    bool isCoupled(Dune::index_constant<poreNetworkIndex> domainI,
 
  224                   const SubControlVolume<poreNetworkIndex>& scv)
 const 
  225    { 
return couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()); }
 
 
  231    template<std::
size_t i>
 
  232    bool isCoupledElement_(Dune::index_constant<i> domainI, std::size_t eIdx)
 const 
  241    template<std::
size_t i>
 
  242    VolumeVariables<i> volVars_(Dune::index_constant<i> domainI,
 
  243                                const Element<i>& element,
 
  244                                const SubControlVolume<i>& scv)
 const 
  246        VolumeVariables<i> volVars;
 
  248            element, this->
curSol(domainI), this->
problem(domainI).gridGeometry()
 
  250        volVars.update(elemSol, this->
problem(domainI), element, scv);
 
  257    template<std::
size_t i>
 
  258    void bindCouplingContext_(Dune::index_constant<i> domainI, 
const Element<i>& element)
 const 
  260        const auto fvGeometry = 
localView(this->
problem(domainI).gridGeometry()).bindElement(element);
 
  261        bindCouplingContext_(domainI, fvGeometry);
 
  267    void bindCouplingContext_(Dune::index_constant<poreNetworkIndex> domainI, 
const FVElementGeometry<poreNetworkIndex>& fvGeometry)
 const 
  269        auto& context = std::get<domainI>(couplingContext_);
 
  270        const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
 
  273        if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx))
 
  277        couplingContextBoundForElement_[domainI] = eIdx;
 
  280        const auto& freeFlowElements = couplingMapper_->pnmElementToFreeFlowElementsMap().at(eIdx);
 
  283        for (
const auto ffElementIdx : freeFlowElements)
 
  286            ffFVGeometry.bindElement(ffElement);
 
  288            for (
const auto& scvf : scvfs(ffFVGeometry))
 
  290                if (couplingMapper_->isCoupledFreeFlowMassScvf(scvf.index()))
 
  292                    const auto& scv = ffFVGeometry.scv(scvf.insideScvIdx());
 
  293                    const auto dofIdx = scv.dofIndex();
 
  294                    if (std::any_of(stencil.begin(), stencil.end(), [&](
const auto x){ return dofIdx == x; } ))
 
  296                        context.push_back({scv,
 
  310    void bindCouplingContext_(Dune::index_constant<freeFlowMassIndex> domainI, 
const FVElementGeometry<freeFlowMassIndex>& fvGeometry)
 const 
  312        auto& context = std::get<domainI>(couplingContext_);
 
  313        const auto eIdx = fvGeometry.gridGeometry().elementMapper().index(fvGeometry.element());
 
  316        if ((!context.empty() && couplingContextBoundForElement_[domainI] == eIdx) || !isCoupledElement_(domainI, eIdx))
 
  320        couplingContextBoundForElement_[domainI] = eIdx;
 
  324        const auto poreNetworkElemIdx = couplingMapper_->freeFlowElementToPNMElementMap().at(eIdx);
 
  326        poreNetworkFVGeometry.bindElement(poreNetworkElement);
 
  328        auto poreNetworkScv = [&]
 
  330            SubControlVolume<poreNetworkIndex> result;
 
  331            std::size_t counter = 0;
 
  332            for (
auto&& scv : scvs(poreNetworkFVGeometry))
 
  334                if (couplingMapper_->isCoupledPoreNetworkDof(scv.dofIndex()))
 
  342                DUNE_THROW(Dune::InvalidStateException, 
"Only one pore per throat may be coupled");
 
  347        auto volVars = volVars_(
poreNetworkIndex, poreNetworkElement, poreNetworkScv);
 
  349        context.push_back({std::move(poreNetworkScv),
 
  355    mutable std::tuple<std::vector<FreeFlowMassCouplingContext>, std::vector<PoreNetworkCouplingContext>> couplingContext_;
 
  356    mutable std::array<std::size_t, 2> couplingContextBoundForElement_;
 
  358    std::shared_ptr<CouplingMapper> couplingMapper_;
 
 
The interface of the coupling manager for multi domain problems.