diff --git a/dumux/multidomain/boundary/freeflowporousmedium/couplingmanager.hh b/dumux/multidomain/boundary/freeflowporousmedium/couplingmanager.hh index 938ae4915987f8fc2b1da60d67b9466c2125c6ae..cb3b2b57ade83aa1c4952885cf3f9b9d1ad79bec 100644 --- a/dumux/multidomain/boundary/freeflowporousmedium/couplingmanager.hh +++ b/dumux/multidomain/boundary/freeflowporousmedium/couplingmanager.hh @@ -82,13 +82,6 @@ constexpr auto coupledDomains(Dune::index_constant<i> domainI) return std::make_tuple(freeFlowMomentumIndex, freeFlowMassIndex); } -template<std::size_t i, std::size_t j> -struct LocalIndices -{ - static constexpr auto domainI = Dune::index_constant<i>(); - static constexpr auto domainJ = Dune::index_constant<j>(); -}; - template<std::size_t i, std::size_t j> constexpr auto globalToLocalDomainIndices(Dune::index_constant<i>, Dune::index_constant<j>) { @@ -96,20 +89,20 @@ constexpr auto globalToLocalDomainIndices(Dune::index_constant<i>, Dune::index_c static_assert(i != j); if constexpr (i < j) - return LocalIndices<0, 1>(); + return std::pair<Dune::index_constant<0>, Dune::index_constant<1>>{}; else - return LocalIndices<1, 0>(); + return std::pair<Dune::index_constant<1>, Dune::index_constant<0>>{}; } -struct CouplingManagerMaps +struct CouplingMaps { - static constexpr auto makeCouplingManagerMap() + static constexpr auto managerMap() { return FreeFlowPorousMediumDetail::makeCouplingManagerMap(); } template<std::size_t i, std::size_t j> - static constexpr auto globalToLocalDomainIndices(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) + static constexpr auto globalToLocal(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) { return FreeFlowPorousMediumDetail::globalToLocalDomainIndices(domainI, domainJ); } @@ -158,7 +151,7 @@ template<class MDTraits> class FreeFlowPorousMediumCouplingManager : public MultiBinaryCouplingManager< MDTraits, - FreeFlowPorousMediumDetail::CouplingManagerMaps, + FreeFlowPorousMediumDetail::CouplingMaps, typename FreeFlowPorousMediumDetail::CouplingManagers<MDTraits>::FreeFlowCouplingManager, typename FreeFlowPorousMediumDetail::CouplingManagers<MDTraits>::FreeFlowMomentumPorousMediumCouplingManager, typename FreeFlowPorousMediumDetail::CouplingManagers<MDTraits>::FreeFlowMassPorousMediumCouplingManager @@ -166,7 +159,7 @@ class FreeFlowPorousMediumCouplingManager { using ParentType = MultiBinaryCouplingManager< MDTraits, - FreeFlowPorousMediumDetail::CouplingManagerMaps, + FreeFlowPorousMediumDetail::CouplingMaps, typename FreeFlowPorousMediumDetail::CouplingManagers<MDTraits>::FreeFlowCouplingManager, typename FreeFlowPorousMediumDetail::CouplingManagers<MDTraits>::FreeFlowMomentumPorousMediumCouplingManager, typename FreeFlowPorousMediumDetail::CouplingManagers<MDTraits>::FreeFlowMassPorousMediumCouplingManager @@ -202,6 +195,8 @@ public: static constexpr auto porousMediumIndex = FreeFlowPorousMediumDetail::porousMediumIndex; public: + using ParentType::ParentType; + template<class GridVarsTuple> void init(std::shared_ptr<Problem<freeFlowMomentumIndex>> freeFlowMomentumProblem, std::shared_ptr<Problem<freeFlowMassIndex>> freeFlowMassProblem, @@ -247,9 +242,9 @@ public: { static_assert(domainI != freeFlowMomentumIndex && domainJ != freeFlowMomentumIndex); - auto& couplingContext = this->subCouplingManager(domainI, domainJ).couplingContext( - ParentType::globalToLocalDomainIndices(domainI, domainJ).domainI, fvGeometry, scvf - ); + const auto& couplingContext = this->subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj) -> const auto& { + return cm.couplingContext(ii, fvGeometry, scvf); + }); const auto& freeFlowElement = [&] { @@ -358,8 +353,9 @@ public: const SubControlVolumeFace<freeFlowMomentumIndex>& scvf, const bool considerPreviousTimeStep = false) const { - return this->subCouplingManager(freeFlowMomentumIndex, freeFlowMassIndex) - .density(element, fvGeometry, scvf, considerPreviousTimeStep); + return this->subCouplingManager(freeFlowMomentumIndex, freeFlowMassIndex).density( + element, fvGeometry, scvf, considerPreviousTimeStep + ); } auto insideAndOutsideDensity(const Element<freeFlowMomentumIndex>& element, @@ -407,43 +403,12 @@ public: ); } - - template<std::size_t i> - const auto& problem(Dune::index_constant<i> domainI) const - { - if constexpr (domainI == freeFlowMomentumIndex) - return this->subCouplingManager(freeFlowMomentumIndex, freeFlowMassIndex).problem( - ParentType::globalToLocalDomainIndices(freeFlowMomentumIndex, freeFlowMassIndex).domainI - ); - else if constexpr (domainI == freeFlowMassIndex) - return this->subCouplingManager(freeFlowMomentumIndex, freeFlowMassIndex).problem( - ParentType::globalToLocalDomainIndices(freeFlowMomentumIndex, freeFlowMassIndex).domainJ - ); - else if constexpr (domainI == porousMediumIndex) - return this->subCouplingManager(porousMediumIndex, freeFlowMassIndex).problem( - ParentType::globalToLocalDomainIndices(porousMediumIndex, freeFlowMassIndex).domainI - ); - else - DUNE_THROW(Dune::InvalidStateException, "Wrong index"); - } - template<std::size_t i> - auto& problem(Dune::index_constant<i> domainI) + const Problem<i>& problem(Dune::index_constant<i> domainI) const { - if constexpr (domainI == freeFlowMomentumIndex) - return this->subCouplingManager(freeFlowMomentumIndex, freeFlowMassIndex).problem( - ParentType::globalToLocalDomainIndices(freeFlowMomentumIndex, freeFlowMassIndex).domainI - ); - else if constexpr (domainI == freeFlowMassIndex) - return this->subCouplingManager(freeFlowMomentumIndex, freeFlowMassIndex).problem( - ParentType::globalToLocalDomainIndices(freeFlowMomentumIndex, freeFlowMassIndex).domainJ - ); - else if constexpr (domainI == porousMediumIndex) - return this->subCouplingManager(porousMediumIndex, freeFlowMassIndex).problem( - ParentType::globalToLocalDomainIndices(porousMediumIndex, freeFlowMassIndex).domainI - ); - else - DUNE_THROW(Dune::InvalidStateException, "Wrong index"); + return this->subApply(domainI, [&](const auto& cm, auto&& ii) -> const auto& { + return cm.problem(ii); + }); } template<std::size_t i, std::size_t j> @@ -451,9 +416,9 @@ public: Dune::index_constant<j> domainJ, const SubControlVolumeFace<i>& scvf) const { - return this->subCouplingManager(domainI, domainJ).isCoupled( - ParentType::globalToLocalDomainIndices(domainI, domainJ).domainI, scvf - ); + return this->subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj){ + return cm.isCoupled(ii, scvf); + }); } /*! @@ -466,9 +431,9 @@ public: Dune::index_constant<j> domainJ, const SubControlVolume<i>& scv) const { - return this->subCouplingManager(domainI, domainJ).isCoupled( - ParentType::globalToLocalDomainIndices(domainI, domainJ).domainI, scv - ); + return this->subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj){ + return cm.isCoupled(ii, scv); + }); } /*! @@ -478,9 +443,9 @@ public: Dune::index_constant<porousMediumIndex> domainJ, const SubControlVolumeFace<freeFlowMomentumIndex>& scvf) const { - return this->subCouplingManager(domainI, domainJ).isCoupledLateralScvf( - ParentType::globalToLocalDomainIndices(domainI, domainJ).domainI, scvf - ); + return this->subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj){ + return cm.isCoupledLateralScvf(ii, scvf); + }); } @@ -501,11 +466,9 @@ public: Dune::index_constant<j> domainJ) const { static_assert(freeFlowMomentumIndex != j); - return this->subCouplingManager(domainI, domainJ).couplingStencil( - ParentType::globalToLocalDomainIndices(domainI, domainJ).domainI, - elementI, scvI, - ParentType::globalToLocalDomainIndices(domainI, domainJ).domainJ - ); + return this->subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj) -> const auto& { + return cm.couplingStencil(ii, elementI, scvI, jj); + }); } }; diff --git a/dumux/multidomain/boundary/freeflowporousmedium/ffmasspm/couplingmanager.hh b/dumux/multidomain/boundary/freeflowporousmedium/ffmasspm/couplingmanager.hh index 09b317561d8e958c01e1701f4bd0aa0a5db2bb01..e8156b97747aff358f6f33891fcb029db0f2380d 100644 --- a/dumux/multidomain/boundary/freeflowporousmedium/ffmasspm/couplingmanager.hh +++ b/dumux/multidomain/boundary/freeflowporousmedium/ffmasspm/couplingmanager.hh @@ -117,11 +117,9 @@ public: std::shared_ptr<Problem<porousMediumIndex>> darcyProblem, SolutionVectorStorage& curSol) { + this->setSubProblems(std::make_tuple(freeFlowMassProblem, darcyProblem)); this->attachSolution(curSol); - freeFlowMassProblemPtr_ = &(*freeFlowMassProblem); - porousMediumProblemPtr_ = &(*darcyProblem); - couplingMapper_.update(*this); } @@ -164,9 +162,9 @@ public: { if (c.dofIdx == dofIdxGlobalJ) { - const auto elemSol = elementSolution(c.element, this->curSol(domainJ), problem(domainJ).gridGeometry()); + const auto elemSol = elementSolution(c.element, this->curSol(domainJ), this->problem(domainJ).gridGeometry()); const auto& scv = *scvs(c.fvGeometry).begin(); - c.volVars.update(elemSol, problem(domainJ), c.element, scv); + c.volVars.update(elemSol, this->problem(domainJ), c.element, scv); } } } @@ -209,7 +207,7 @@ public: const Element<i>& element, Dune::index_constant<j> domainJ) const { - const auto eIdx = problem(domainI).gridGeometry().elementMapper().index(element); + const auto eIdx = this->problem(domainI).gridGeometry().elementMapper().index(element); return couplingMapper_.couplingStencil(domainI, eIdx, domainJ); } @@ -222,24 +220,6 @@ public: bool isCoupled(Dune::index_constant<i> domainI, const SubControlVolumeFace<i>& scvf) const { return couplingMapper_.isCoupled(domainI, scvf); } - template<std::size_t i> - Problem<i>& problem(Dune::index_constant<i> domainI) - { - if constexpr (i == freeFlowMassIndex) - return *freeFlowMassProblemPtr_; - else - return *porousMediumProblemPtr_; - } - - template<std::size_t i> - const Problem<i>& problem(Dune::index_constant<i> domainI) const - { - if constexpr (i == freeFlowMassIndex) - return *freeFlowMassProblemPtr_; - else - return *porousMediumProblemPtr_; - } - private: /*! * \brief Returns whether a given scvf is coupled to the other domain @@ -268,7 +248,7 @@ private: template<std::size_t i> void bindCouplingContext_(Dune::index_constant<i> domainI, const Element<i>& element) const { - const auto fvGeometry = localView(problem(domainI).gridGeometry()).bindElement(element); + const auto fvGeometry = localView(this->problem(domainI).gridGeometry()).bindElement(element); bindCouplingContext_(domainI, fvGeometry); } @@ -281,7 +261,7 @@ private: auto& context = std::get<domainI>(couplingContext_); context.clear(); - const auto eIdx = problem(domainI).gridGeometry().elementMapper().index(fvGeometry.element()); + const auto eIdx = this->problem(domainI).gridGeometry().elementMapper().index(fvGeometry.element()); // do nothing if the element is not coupled to the other domain if (!isCoupledElement_(domainI, eIdx)) @@ -295,7 +275,7 @@ private: { const auto otherElementIdx = couplingMapper_.outsideElementIndex(domainI, scvf); constexpr auto domainJ = Dune::index_constant<1-domainI>(); - const auto& otherGridGeometry = problem(domainJ).gridGeometry(); + const auto& otherGridGeometry = this->problem(domainJ).gridGeometry(); const auto& otherElement = otherGridGeometry.element(otherElementIdx); auto otherFvGeometry = localView(otherGridGeometry).bindElement(otherElement); @@ -316,9 +296,6 @@ private: mutable std::tuple<std::vector<FreeFlowMassCouplingContext>, std::vector<PorousMediumCouplingContext>> couplingContext_; mutable std::array<std::size_t, 2> couplingContextBoundForElement_; - Problem<freeFlowMassIndex>* freeFlowMassProblemPtr_ = nullptr; - Problem<porousMediumIndex>* porousMediumProblemPtr_ = nullptr; - CouplingMapper couplingMapper_; }; diff --git a/dumux/multidomain/boundary/freeflowporousmedium/ffmomentumpm/couplingmanager.hh b/dumux/multidomain/boundary/freeflowporousmedium/ffmomentumpm/couplingmanager.hh index c8193ac26430470d82c1e7ff294bb1575290b0c2..f957e9f65f15d9c92dac5e867681b8f63f7d14f3 100644 --- a/dumux/multidomain/boundary/freeflowporousmedium/ffmomentumpm/couplingmanager.hh +++ b/dumux/multidomain/boundary/freeflowporousmedium/ffmomentumpm/couplingmanager.hh @@ -116,11 +116,9 @@ public: std::shared_ptr<Problem<porousMediumIndex>> porousMediumProblem, SolutionVectorStorage& curSol) { + this->setSubProblems(std::make_tuple(freeFlowMomentumProblem, porousMediumProblem)); this->attachSolution(curSol); - freeFlowMomentumProblemPtr_ = &(*freeFlowMomentumProblem); - porousMediumProblemPtr_ = &(*porousMediumProblem); - couplingMapper_.update(*this); } @@ -187,7 +185,7 @@ public: const auto& ggJ = c.fvGeometry.gridGeometry(); const auto& scv = *scvs(c.fvGeometry).begin(); const auto elemSol = elementSolution(c.element, this->curSol(domainJ), ggJ); - c.volVars.update(elemSol, problem(domainJ), c.element, scv); + c.volVars.update(elemSol, this->problem(domainJ), c.element, scv); } } } @@ -230,7 +228,7 @@ public: const Element<porousMediumIndex>& element, Dune::index_constant<freeFlowMomentumIndex> domainJ) const { - const auto eIdx = problem(domainI).gridGeometry().elementMapper().index(element); + const auto eIdx = this->problem(domainI).gridGeometry().elementMapper().index(element); return couplingMapper_.couplingStencil(domainI, eIdx, domainJ); } @@ -315,24 +313,6 @@ public: return velocity; } - template<std::size_t i> - Problem<i>& problem(Dune::index_constant<i> domainI) - { - if constexpr (i == freeFlowMomentumIndex) - return *freeFlowMomentumProblemPtr_; - else - return *porousMediumProblemPtr_; - } - - template<std::size_t i> - const Problem<i>& problem(Dune::index_constant<i> domainI) const - { - if constexpr (i == freeFlowMomentumIndex) - return *freeFlowMomentumProblemPtr_; - else - return *porousMediumProblemPtr_; - } - private: //! Return the volume variables of domain i for a given element and scv template<std::size_t i> @@ -342,9 +322,9 @@ private: { VolumeVariables<i> volVars; const auto elemSol = elementSolution( - element, this->curSol(domainI), problem(domainI).gridGeometry() + element, this->curSol(domainI), this->problem(domainI).gridGeometry() ); - volVars.update(elemSol, problem(domainI), element, scv); + volVars.update(elemSol, this->problem(domainI), element, scv); return volVars; } @@ -361,7 +341,7 @@ private: template<std::size_t i> void bindCouplingContext_(Dune::index_constant<i> domainI, const Element<i>& element) const { - const auto fvGeometry = localView(problem(domainI).gridGeometry()).bindElement(element); + const auto fvGeometry = localView(this->problem(domainI).gridGeometry()).bindElement(element); bindCouplingContext_(domainI, fvGeometry); } @@ -374,7 +354,7 @@ private: auto& context = std::get<domainI>(couplingContext_); context.clear(); - const auto eIdx = problem(domainI).gridGeometry().elementMapper().index(fvGeometry.element()); + const auto eIdx = this->problem(domainI).gridGeometry().elementMapper().index(fvGeometry.element()); // do nothing if the element is not coupled to the other domain if (!isCoupledElement_(domainI, eIdx)) @@ -390,7 +370,7 @@ private: { const auto otherElementIdx = couplingMapper_.outsideElementIndex(domainI, scvf); constexpr auto domainJ = Dune::index_constant<1-i>(); - const auto& otherGridGeometry = problem(domainJ).gridGeometry(); + const auto& otherGridGeometry = this->problem(domainJ).gridGeometry(); const auto& otherElement = otherGridGeometry.element(otherElementIdx); auto otherFvGeometry = localView(otherGridGeometry).bindElement(otherElement); @@ -402,7 +382,7 @@ private: scvf.index(), couplingMapper_.flipScvfIndex(domainI, scvf), otherElementIdx, - problem(domainJ).spatialParams().gravity(scvf.center()) + this->problem(domainJ).spatialParams().gravity(scvf.center()) }); } @@ -410,7 +390,7 @@ private: { const auto otherElementIdx = couplingMapper_.outsideElementIndex(domainI, scvf); constexpr auto domainJ = Dune::index_constant<1-i>(); - const auto& otherGridGeometry = problem(domainJ).gridGeometry(); + const auto& otherGridGeometry = this->problem(domainJ).gridGeometry(); const auto& otherElement = otherGridGeometry.element(otherElementIdx); auto otherFvGeometry = localView(otherGridGeometry).bindElement(otherElement); @@ -434,9 +414,6 @@ private: mutable std::tuple<std::vector<FreeFlowMomentumCouplingContext>, std::vector<PorousMediumCouplingContext>> couplingContext_; mutable std::array<std::size_t, 2> couplingContextBoundForElement_; - Problem<freeFlowMomentumIndex>* freeFlowMomentumProblemPtr_ = nullptr; - Problem<porousMediumIndex>* porousMediumProblemPtr_ = nullptr; - CouplingMapper couplingMapper_; }; diff --git a/dumux/multidomain/multibinarycouplingmanager.hh b/dumux/multidomain/multibinarycouplingmanager.hh index 082c69018766909e815e2e7204b8880fe28bf655..cd335ffb5bc48361b169ae87d43f27e9512f2df7 100644 --- a/dumux/multidomain/multibinarycouplingmanager.hh +++ b/dumux/multidomain/multibinarycouplingmanager.hh @@ -43,17 +43,21 @@ struct HasIndex<i, std::tuple<Indices...>> : std::disjunction<std::is_same<Dune::index_constant<i>, Indices>...> {}; -template<class Map, std::size_t i, std::size_t j> -constexpr bool isCoupled(Dune::index_constant<i> I, Dune::index_constant<j>) -{ return HasIndex<j, std::decay_t<decltype(Map::coupledDomains(I))>>::value; } - } // end namespace Detail /*! * \ingroup MultiDomain * \brief Coupling manager that combines an arbitrary number of binary coupling manager (coupling two domains each) + * \tparam MDTraits the multidomain traits + * \tparam CouplingMap a coupling policy class + * \tparam CouplingMgrs the binary sub-coupling manager types + * + * The coupling policy has to provide the interfaces + * - CouplingMap::coupledDomains(i): returns a tuple of Dune::index_constants with the coupled domains + * - CouplingMap::globalToLocal(i, j): maps the indices i, j to the local index pair of the responsible sub coupling manager + * - CouplingMap::managerMap(): returns a two-dimensional array mapping two indices to the coupling manager index */ -template<class MDTraits, class CouplingManagerMaps, class ...CouplingMgrs> +template<class MDTraits, class CouplingMap, class ...CouplingMgrs> class MultiBinaryCouplingManager { // the sub domain type tags @@ -78,12 +82,35 @@ class MultiBinaryCouplingManager using SubSolutionVector = std::decay_t<decltype(std::declval<typename MDTraits::SolutionVector>()[Dune::index_constant<id>()])>; using SolutionVectors = typename MDTraits::template TupleOfSharedPtr<SubSolutionVector>; -public: + static constexpr auto couplingManagerMap_ = CouplingMap::managerMap(); + + //! Returns the local domain indices used within the binary sub coupling managers. + template<std::size_t i, std::size_t j> + static constexpr auto globalToLocal_(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) + { + static_assert(i <= MDTraits::numSubDomains && j <= MDTraits::numSubDomains); + return CouplingMap::globalToLocal(domainI, domainJ); + } - static constexpr auto couplingManagerMap = CouplingManagerMaps::makeCouplingManagerMap(); + //! If two domain are coupled + template<class Map, std::size_t i, std::size_t j> + static constexpr bool isCoupled_(Dune::index_constant<i> domainI, Dune::index_constant<j>) + { return Detail::HasIndex<j, std::decay_t<decltype(Map::coupledDomains(domainI))>>::value; } + //! Returns the coupling manager index for a given domain combination template<std::size_t i, std::size_t j> - using SubCouplingManager = SubCouplingManagerT<couplingManagerMap[i][j]>; + static constexpr auto subCouplingManagerIndex_(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) + { + static_assert( + isCoupled_<CouplingMap>(domainI, domainJ), + "Sub-coupling manager only exists for coupled domains." + ); + return couplingManagerMap_[i][j]; + } + +public: + template<std::size_t i, std::size_t j> + using SubCouplingManager = SubCouplingManagerT<couplingManagerMap_[i][j]>; MultiBinaryCouplingManager() { @@ -99,31 +126,12 @@ public: }); } - //! Returns the local domain indices used within the binary sub coupling managers. - template<std::size_t i, std::size_t j> - static constexpr auto globalToLocalDomainIndices(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) - { - static_assert(i <= MDTraits::numSubDomains && j <= MDTraits::numSubDomains); - return CouplingManagerMaps::globalToLocalDomainIndices(domainI, domainJ); - } - - //! Returns the coupling manager index for a given domain combination - template<std::size_t i, std::size_t j> - static constexpr auto getCouplingManagerIndex(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) - { - static_assert( - Detail::template isCoupled<CouplingManagerMaps>(domainI, domainJ), - "Sub-coupling manager only exists for coupled domains." - ); - return couplingManagerMap[i][j]; - } - //! return the binary sub-coupling manager template<std::size_t i, std::size_t j> auto& subCouplingManager(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) { - constexpr auto idx = getCouplingManagerIndex(domainI, domainJ); + constexpr auto idx = subCouplingManagerIndex_(domainI, domainJ); return *std::get<idx>(couplingManagers_); } @@ -132,10 +140,52 @@ public: const auto& subCouplingManager(Dune::index_constant<i> domainI, Dune::index_constant<j> domainJ) const { - constexpr auto idx = getCouplingManagerIndex(domainI, domainJ); + constexpr auto idx = subCouplingManagerIndex_(domainI, domainJ); return *std::get<idx>(couplingManagers_); } + //! apply a function to the domainI-domainJ sub coupling manager using its local indices + template<std::size_t i, std::size_t j, class Apply> + decltype(auto) subApply(Dune::index_constant<i> domainI, + Dune::index_constant<j> domainJ, + Apply&& apply) + { + constexpr auto localIndices = globalToLocal_(domainI, domainJ); + return apply(subCouplingManager(domainI, domainJ), localIndices.first, localIndices.second); + } + + //! apply a function to the domainI-domainJ sub coupling manager using its local indices + template<std::size_t i, std::size_t j, class Apply> + decltype(auto) subApply(Dune::index_constant<i> domainI, + Dune::index_constant<j> domainJ, + const Apply& apply) const + { + constexpr auto localIndices = globalToLocal_(domainI, domainJ); + return apply(subCouplingManager(domainI, domainJ), localIndices.first, localIndices.second); + } + + //! apply a function to a sub coupling manager containing this domain + template<std::size_t i, class Apply> + decltype(auto) subApply(Dune::index_constant<i> domainI, Apply&& apply) + { + constexpr auto dm = CouplingMap::coupledDomains(domainI); + static_assert(std::tuple_size_v<std::decay_t<decltype(dm)>> != 0, "subApply on uncoupled domain!"); + constexpr auto domainJ = std::get<0>(dm); + constexpr auto localIndices = globalToLocal_(domainI, domainJ); + return apply(subCouplingManager(domainI, domainJ), localIndices.first); + } + + //! apply a function to a sub coupling manager containing this domain + template<std::size_t i, class Apply> + decltype(auto) subApply(Dune::index_constant<i> domainI, const Apply& apply) const + { + constexpr auto dm = CouplingMap::coupledDomains(domainI); + static_assert(std::tuple_size_v<std::decay_t<decltype(dm)>> != 0, "subApply on uncoupled domain!"); + constexpr auto domainJ = std::get<0>(dm); + constexpr auto localIndices = globalToLocal_(domainI, domainJ); + return apply(subCouplingManager(domainI, domainJ), localIndices.first); + } + //! Update the solution vector before assembly void updateSolution(const typename MDTraits::SolutionVector& curSol) { @@ -167,11 +217,10 @@ public: Dune::index_constant<j> domainJ) const { // if the domains are coupled according to the map, forward to sub-coupling manager - if constexpr (Detail::template isCoupled<CouplingManagerMaps>(domainI, domainJ)) - return subCouplingManager(domainI, domainJ).couplingStencil( - globalToLocalDomainIndices(domainI, domainJ).domainI, entity, - globalToLocalDomainIndices(domainI, domainJ).domainJ - ); + if constexpr (isCoupled_<CouplingMap>(domainI, domainJ)) + return subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj) -> const auto& { + return cm.couplingStencil(ii, entity, jj); + }); else return emptyStencil_; } @@ -185,13 +234,10 @@ public: Dune::index_constant<j> domainJ, std::size_t dofIdxGlobalJ) const { - if constexpr (i == j || Detail::template isCoupled<CouplingManagerMaps>(domainI, domainJ)) - return subCouplingManager(domainI, domainJ).evalCouplingResidual( - globalToLocalDomainIndices(domainI, domainJ).domainI, - scvfI, localAssemblerI, - globalToLocalDomainIndices(domainI, domainJ).domainJ, - dofIdxGlobalJ - ); + if constexpr (i == j || isCoupled_<CouplingMap>(domainI, domainJ)) + return subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj) -> decltype(auto) { + return cm.evalCouplingResidual(ii, scvfI, localAssemblerI, jj, dofIdxGlobalJ); + }); else { DUNE_THROW(Dune::InvalidStateException, @@ -209,13 +255,10 @@ public: Dune::index_constant<j> domainJ, std::size_t dofIdxGlobalJ) const { - if constexpr (i == j || Detail::template isCoupled<CouplingManagerMaps>(domainI, domainJ)) - return subCouplingManager(domainI, domainJ).evalCouplingResidual( - globalToLocalDomainIndices(domainI, domainJ).domainI, - localAssemblerI, - globalToLocalDomainIndices(domainI, domainJ).domainJ, - dofIdxGlobalJ - ); + if constexpr (i == j || isCoupled_<CouplingMap>(domainI, domainJ)) + return subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj) -> decltype(auto) { + return cm.evalCouplingResidual(ii, localAssemblerI, jj, dofIdxGlobalJ); + }); else { DUNE_THROW(Dune::InvalidStateException, @@ -234,14 +277,10 @@ public: Dune::index_constant<j> domainJ, std::size_t dofIdxGlobalJ) const { - if constexpr (i == j || Detail::template isCoupled<CouplingManagerMaps>(domainI, domainJ)) - return subCouplingManager(domainI, domainJ).evalCouplingResidual( - globalToLocalDomainIndices(domainI, domainJ).domainI, - localAssemblerI, - scvI, - globalToLocalDomainIndices(domainI, domainJ).domainJ, - dofIdxGlobalJ - ); + if constexpr (i == j || isCoupled_<CouplingMap>(domainI, domainJ)) + return subApply(domainI, domainJ, [&](const auto& cm, auto&& ii, auto&& jj) -> decltype(auto) { + return cm.evalCouplingResidual(ii, localAssemblerI, scvI, jj, dofIdxGlobalJ); + }); else { DUNE_THROW(Dune::InvalidStateException, @@ -265,32 +304,21 @@ public: // only one other manager needs to take action if i != j if constexpr (i != j) { - if constexpr (Detail::template isCoupled<CouplingManagerMaps>(domainI, domainJ)) - subCouplingManager(domainI, domainJ).updateCouplingContext( - globalToLocalDomainIndices(domainI, domainJ).domainI, - localAssemblerI, - globalToLocalDomainIndices(domainI, domainJ).domainJ, - dofIdxGlobalJ, - priVars, - pvIdxJ - ); + if constexpr (isCoupled_<CouplingMap>(domainI, domainJ)) + subApply(domainI, domainJ, [&](auto& cm, auto&& ii, auto&& jj){ + cm.updateCouplingContext(ii, localAssemblerI, jj, dofIdxGlobalJ, priVars, pvIdxJ); + }); } else { // for i == j, we need to call all relevant managers where domainI is involved and make sure that the - // context is updated with respect to its own domain + // context is updated with respect to its own domain (I-I coupling context) using namespace Dune::Hybrid; - forEach(CouplingManagerMaps::coupledDomains(domainI), [&](const auto domainJ) - { + forEach(CouplingMap::coupledDomains(domainI), [&](const auto domainJ){ static_assert(domainI != domainJ); - subCouplingManager(domainI, domainJ).updateCouplingContext( - globalToLocalDomainIndices(domainI, domainJ).domainI, - localAssemblerI, - globalToLocalDomainIndices(domainI, domainJ).domainI, - dofIdxGlobalJ, - priVars, - pvIdxJ - ); + subApply(domainI, domainJ, [&](auto& cm, auto&& ii, auto&& jj){ + cm.updateCouplingContext(ii, localAssemblerI, ii, dofIdxGlobalJ, priVars, pvIdxJ); + }); }); } } @@ -301,11 +329,10 @@ public: { // for the coupling blocks using namespace Dune::Hybrid; - forEach(CouplingManagerMaps::coupledDomains(domainI), [&](const auto domainJ) - { - this->subCouplingManager(domainI, domainJ).bindCouplingContext( - globalToLocalDomainIndices(domainI, domainJ).domainI, element, assembler - ); + forEach(CouplingMap::coupledDomains(domainI), [&](const auto domainJ){ + subApply(domainI, domainJ, [&](auto& cm, auto&& ii, auto&& jj) -> void { + cm.bindCouplingContext(ii, element, assembler); + }); }); } @@ -317,8 +344,9 @@ public: decltype(auto) numericEpsilon(Dune::index_constant<i> domainI, const std::string& paramGroup) const { - static constexpr auto someOtherDomain = std::get<0>(CouplingManagerMaps::coupledDomains(domainI)); - return subCouplingManager(domainI, someOtherDomain).numericEpsilon(globalToLocalDomainIndices(domainI, someOtherDomain).domainI, paramGroup); + return subApply(domainI, [&](const auto& cm, auto&& ii) -> decltype(auto) { + return cm.numericEpsilon(ii, paramGroup); + }); } /*! @@ -343,14 +371,10 @@ public: { // for the coupling blocks using namespace Dune::Hybrid; - forEach(CouplingManagerMaps::coupledDomains(domainI), [&](const auto domainJ) - { - subCouplingManager(domainI, domainJ).updateCoupledVariables( - globalToLocalDomainIndices(domainI, domainJ).domainI, - localAssemblerI, - elemVolVars, - elemFluxVarsCache - ); + forEach(CouplingMap::coupledDomains(domainI), [&](const auto domainJ){ + subApply(domainI, domainJ, [&](auto& cm, auto&& ii, auto&& jj){ + cm.updateCoupledVariables(ii, localAssemblerI, elemVolVars, elemFluxVarsCache); + }); }); }