42    struct HostGridConnectionInfo
 
   44        std::size_t hostGridElementIndex;
 
   45        std::size_t voidVertexHostIdx;
 
   46        std::size_t solidVertexHostIdx;
 
   47        Scalar connectionArea;
 
   48        Scalar connectionLength;
 
   49        std::vector<std::size_t> voidElementHostIdx;
 
   50        std::vector<std::size_t> solidElementHostIdx;
 
   51        std::vector<std::size_t> coupledVoidVertexHostIdx;
 
   52        std::vector<std::size_t> coupledSolidVertexHostIdx;
 
   53        std::size_t connectionGlobalId;
 
   56    struct SubGridConnectionInfo
 
   59        std::size_t solidVertexIdx; 
 
   60        std::size_t voidVertexIdx; 
 
   61        std::size_t someSolidElementIdx; 
 
   62        std::size_t someVoidElementIdx; 
 
   63        std::vector<std::size_t> convectionVoidElementIdx; 
 
   64        Scalar connectionArea;
 
   65        Scalar connectionLength;
 
   68    template<
class Vector>
 
   69    class ConnectionIterator : 
public Dune::ForwardIteratorFacade<ConnectionIterator<Vector>, const SubGridConnectionInfo>
 
   71        using ThisType = ConnectionIterator<Vector>;
 
   72        using Iterator = 
typename Vector::const_iterator;
 
   74        ConnectionIterator(
const Iterator& it, 
const std::vector<SubGridConnectionInfo>& info)
 
   75        : it_(it), InfoPtr_(&info) {}
 
   77        ConnectionIterator() : it_(Iterator()), InfoPtr_(
nullptr) {}
 
   80        const SubGridConnectionInfo& dereference()
 const 
   81        { 
return InfoPtr_->at(*it_); }
 
   84        bool equals(
const ThisType& other)
 const 
   85        { 
return it_ == other.it_; }
 
   92        const std::vector<SubGridConnectionInfo>* InfoPtr_;
 
   98    template<
class HostGr
idView, 
class HostGr
idData, 
class Vo
idGr
idGeometry, 
class Sol
idGr
idGeometry>
 
  100                              const HostGridData& hostGridData,
 
  101                              const VoidGridGeometry& voidGridGeometry,
 
  102                              const SolidGridGeometry& solidGridGeometry)
 
  104        fillVertexMap_(hostGridView, voidGridGeometry, voidHostToSubVertexIdxMap_);
 
  105        fillVertexMap_(hostGridView, solidGridGeometry, solidHostToSubVertexIdxMap_);
 
  106        fillElementMap_(hostGridView, voidGridGeometry, voidHostToSubElementIdxMap_);
 
  107        fillElementMap_(hostGridView, solidGridGeometry, solidHostToSubElementIdxMap_);
 
  109        isCoupledVoidDof_.resize(voidGridGeometry.gridView().size(1), 
false);
 
  110        isCoupledSolidDof_.resize(solidGridGeometry.gridView().size(1), 
false);
 
  112        const auto connectionInfo = getConnectionInfo_(hostGridView, hostGridData);
 
  116            auto voidHostToSubVertexIdx = [&](
const auto hostIdx)
 
  117            { 
return voidHostToSubVertexIdxMap_.at(hostIdx); };
 
  119            auto solidHostToSubVertexIdx = [&](
const auto hostIdx)
 
  120            { 
return solidHostToSubVertexIdxMap_.at(hostIdx); };
 
  122            const auto directlyCoupledVoidDofIdx = voidHostToSubVertexIdx(info.voidVertexHostIdx);
 
  123            const auto directlyCoupledSolidDofIdx = solidHostToSubVertexIdx(info.solidVertexHostIdx);
 
  125            auto coupledVoidElementIdxSub = info.voidElementHostIdx;
 
  126            auto coupledSolidElementIdxSub = info.solidElementHostIdx;
 
  129            std::transform(coupledVoidElementIdxSub.begin(), coupledVoidElementIdxSub.end(),
 
  130                           coupledVoidElementIdxSub.begin(), [&](
const auto eIdx){ return voidHostToSubElementIdxMap_.at(eIdx); });
 
  131            std::transform(coupledSolidElementIdxSub.begin(), coupledSolidElementIdxSub.end(),
 
  132                           coupledSolidElementIdxSub.begin(), [&](
const auto eIdx){ return solidHostToSubElementIdxMap_.at(eIdx); });
 
  135            auto convectionVoidElementIdx = std::vector<std::size_t>();
 
  137            voidToSolidConnectionIds_[directlyCoupledVoidDofIdx].emplace_back(info.connectionGlobalId);
 
  138            solidToVoidConnectionIds_[directlyCoupledSolidDofIdx].emplace_back(info.connectionGlobalId);
 
  140            connectionInfo_[info.connectionGlobalId] = SubGridConnectionInfo{info.connectionGlobalId,
 
  141                                                                             directlyCoupledSolidDofIdx,
 
  142                                                                             directlyCoupledVoidDofIdx,
 
  143                                                                             coupledSolidElementIdxSub[0],
 
  144                                                                             coupledVoidElementIdxSub[0],
 
  145                                                                             convectionVoidElementIdx,
 
  147                                                                             info.connectionLength};
 
  149            hostGridElementIndexToGlobalId_[info.hostGridElementIndex] = info.connectionGlobalId;
 
  151            isCoupledVoidDof_[directlyCoupledVoidDofIdx] = 
true;
 
  152            isCoupledSolidDof_[directlyCoupledSolidDofIdx] = 
true;
 
  154            for (
const auto eIdxVoidHost : info.voidElementHostIdx)
 
  156                const auto eIdxSubVoid = voidHostToSubElementIdxMap_.at(eIdxVoidHost);
 
  157                voidToSolidStencils_[eIdxSubVoid].push_back(directlyCoupledSolidDofIdx);
 
  160            for (
const auto eIdxSolidHost : info.solidElementHostIdx)
 
  162                const auto eIdxSubSolid = solidHostToSubElementIdxMap_.at(eIdxSolidHost);
 
  163                solidToVoidStencils_[eIdxSubSolid].push_back(directlyCoupledVoidDofIdx);
 
  167        for (
auto& stencil : voidToSolidStencils_)
 
  168            removeDuplicates_(stencil.second);
 
  169        for (
auto& stencil : solidToVoidStencils_)
 
  170            removeDuplicates_(stencil.second);
 
  173        auto voidFVGeometry = 
localView(voidGridGeometry);
 
  174        for (
const auto& voidElement : elements(voidGridGeometry.gridView()))
 
  176            voidFVGeometry.bindElement(voidElement);
 
  177            std::array<std::size_t, 2> dofIndex;
 
  178            std::array<std::vector<std::size_t>, 2> coupledSolidVertexIdx;
 
  179            for (
const auto& scv : scvs(voidFVGeometry))
 
  180                dofIndex[scv.indexInElement()] = scv.dofIndex();
 
  183            if (isCoupledVoidDof_[dofIndex[0]] && isCoupledVoidDof_[dofIndex[1]])
 
  185                for (
auto& conn0 : voidToSolidConnectionIds_[dofIndex[0]])
 
  187                    for (
auto& conn1 : voidToSolidConnectionIds_[dofIndex[1]])
 
  189                        const auto globalId0 = conn0;
 
  190                        const auto globalId1 = conn1;
 
  191                        assert(globalId0 != globalId1);
 
  193                        if (connectionInfo_[globalId0].solidVertexIdx == connectionInfo_[globalId1].solidVertexIdx)
 
  195                            const auto voidElemIdx = voidGridGeometry.elementMapper().index(voidElement);
 
  196                            connectionInfo_[globalId0].convectionVoidElementIdx.push_back(voidElemIdx);
 
  197                            connectionInfo_[globalId1].convectionVoidElementIdx.push_back(voidElemIdx);
 
  204        for (
auto& entry : voidToSolidConnectionIds_)
 
  206            removeDuplicates_(entry.second);
 
  208            std::cout << 
"void dof " << entry.first << 
" couples to " << entry.second.size() << 
" solid dofs: " << std::endl;
 
  209            for (
auto& conn : entry.second)
 
  211                const auto& info = connectionInfo_[conn];
 
  212                assert(entry.first == info.voidVertexIdx);
 
  213                std::cout << 
"solid vertex " << info.solidVertexIdx << 
" with elems ";
 
  214                for (
const auto e : info.convectionVoidElementIdx)
 
  215                    std::cout << e << 
" ";
 
  216                std:: cout << 
"||" << std::endl;
 
  219            std::cout << std::endl;
 
  222        for (
auto& entry : solidToVoidConnectionIds_)
 
  224            removeDuplicates_(entry.second);
 
  226            std::cout << 
"solid dof " << entry.first << 
" couples to " << entry.second.size() << 
" void dofs: " << std::endl;
 
  227            for (
auto& conn : entry.second)
 
  229                const auto& info = connectionInfo_[conn];
 
  230                assert(entry.first == info.solidVertexIdx);
 
  231                std::cout << 
"void vertex " << info.voidVertexIdx << 
" with elems ";
 
  232                for (
const auto e : info.convectionVoidElementIdx)
 
  233                    std::cout << e << 
" ";
 
  234                std:: cout << 
"||" << std::endl;
 
  237            std::cout << std::endl;
 
 
  244    { 
return voidToSolidStencils_; }
 
 
  247    { 
return solidToVoidStencils_; }
 
 
  250    { 
return isCoupledVoidDof_; }
 
 
  253    { 
return isCoupledSolidDof_; }
 
 
  259        using Iterator = ConnectionIterator<std::vector<std::size_t>>;
 
  260        return Dune::IteratorRange<Iterator>(Iterator(ids.cbegin(), 
connectionInfo()),
 
 
  267        using Iterator = ConnectionIterator<std::vector<std::size_t>>;
 
  268        return Dune::IteratorRange<Iterator>(Iterator(ids.cbegin(), 
connectionInfo()),
 
 
  273    { 
return voidToSolidConnectionIds_; }
 
 
  276    { 
return solidToVoidConnectionIds_; }
 
 
  279    { 
return connectionInfo_; }
 
 
  282    { 
return voidHostToSubVertexIdxMap_; }
 
 
  285    { 
return solidHostToSubVertexIdxMap_; }
 
 
  288    { 
return voidHostToSubElementIdxMap_; }
 
 
  291    { 
return solidHostToSubElementIdxMap_; }
 
 
  294    { 
return hostGridElementIndexToGlobalId_; }
 
 
  298    template<
class HostGr
idView, 
class HostGr
idData>
 
  299    std::vector<HostGridConnectionInfo> getConnectionInfo_(
const HostGridView& hostGridView,
 
  300                                                           const HostGridData& hostGridData)
 
  303        std::size_t connectionGlobalId = 0;
 
  305        for (
const auto& element : elements(hostGridView))
 
  307            if (hostGridData.getParameter(element, 
"ThroatDomainType") == 2) 
 
  309                const auto& vertex0 = element.template subEntity<1>(0);
 
  310                const auto& vertex1 = element.template subEntity<1>(1);
 
  312                HostGridConnectionInfo info;
 
  313                info.hostGridElementIndex = hostGridView.indexSet().index(element);
 
  314                info.connectionGlobalId = connectionGlobalId++;
 
  315                info.voidVertexHostIdx = hostGridView.indexSet().index(vertex0);
 
  316                info.solidVertexHostIdx = hostGridView.indexSet().index(vertex1);
 
  318                if (hostGridData.getParameter(vertex0, 
"PoreDomainType") == 1)
 
  320                    assert(hostGridData.getParameter(vertex1, 
"PoreDomainType") == 0);
 
  322                    swap(info.voidVertexHostIdx, info.solidVertexHostIdx);
 
  325                info.connectionArea = hostGridData.getParameter(element, 
"ThroatCrossSectionalArea");
 
  326                info.connectionLength = element.geometry().volume();
 
  328                for (
const auto& intersection : intersections(hostGridView, element))
 
  330                    if (!intersection.neighbor())
 
  333                    const auto& outsideElement = intersection.outside();
 
  336                    if (hostGridData.getParameter(outsideElement, 
"ThroatDomainType") == 2)
 
  339                    const auto outsideElementIdx = hostGridView.indexSet().index(outsideElement);
 
  341                    if (hostGridData.getParameter(outsideElement, 
"ThroatDomainType") == 0)
 
  342                        info.voidElementHostIdx.push_back(outsideElementIdx);
 
  344                        info.solidElementHostIdx.push_back(outsideElementIdx);
 
  346                    std::array outsideDomainType = {-1, -1};
 
  347                    for (
int localVIdx = 0; localVIdx < 2; ++localVIdx)
 
  349                        const auto& outsideVertex = outsideElement.template subEntity<1>(localVIdx);
 
  350                        const auto outsideVertexIdx = hostGridView.indexSet().index(outsideVertex);
 
  351                        outsideDomainType[localVIdx] = hostGridData.getParameter(outsideVertex, 
"PoreDomainType");
 
  353                        if (localVIdx == 1 && (outsideDomainType[1] != outsideDomainType[0]))
 
  354                            DUNE_THROW(Dune::IOError, 
"Pore with hostIdx " << hostGridView.indexSet().index(outsideElement.template subEntity<1>(0))
 
  355                                                       << 
" has domain type " << outsideDomainType[0]
 
  356                                                       << 
", but pore with hostIdx " << outsideVertexIdx
 
  357                                                       << 
" has domain type " << outsideDomainType[1] << 
". Check your grid file");
 
  359                        if (outsideDomainType[localVIdx] == 0)
 
  360                            info.coupledVoidVertexHostIdx.push_back(outsideVertexIdx);
 
  362                            info.coupledSolidVertexHostIdx.push_back(outsideVertexIdx);
 
  373    template<
class HostGr
idView, 
class SubGr
idGeometry, 
class Map>
 
  374    void fillVertexMap_(
const HostGridView& hostGridView, 
const SubGridGeometry& subGridGeometry, Map& map)
 
  376        for (
const auto& vertex : vertices(subGridGeometry.gridView()))
 
  378            const auto vIdxSub = subGridGeometry.vertexMapper().index(vertex);
 
  379            const auto vIdxHost = hostGridView.indexSet().index(
vertex.impl().hostEntity());
 
  380            map[vIdxHost] = vIdxSub;
 
  384    template<
class HostGr
idView, 
class SubGr
idGeometry, 
class Map>
 
  385    void fillElementMap_(
const HostGridView& hostGridView, 
const SubGridGeometry& subGridGeometry, Map& map)
 
  387        for (
const auto& element : elements(subGridGeometry.gridView()))
 
  389            const auto eIdxSub = subGridGeometry.elementMapper().index(element);
 
  390            const auto eIdxHost = hostGridView.indexSet().index(
element.impl().hostEntity());
 
  391            map[eIdxHost] = eIdxSub;
 
  396    void removeDuplicates_(std::vector<std::size_t>& stencil)
 
  398        std::sort(stencil.begin(), stencil.end());
 
  399        stencil.erase(std::unique(stencil.begin(), stencil.end()), stencil.end());
 
  402    std::unordered_map<std::size_t, std::size_t> voidHostToSubVertexIdxMap_;
 
  403    std::unordered_map<std::size_t, std::size_t> solidHostToSubVertexIdxMap_;
 
  404    std::unordered_map<std::size_t, std::size_t> voidHostToSubElementIdxMap_;
 
  405    std::unordered_map<std::size_t, std::size_t> solidHostToSubElementIdxMap_;
 
  407    std::vector<bool> isCoupledVoidDof_;
 
  408    std::vector<bool> isCoupledSolidDof_;
 
  410    std::unordered_map<std::size_t, Stencil> voidToSolidStencils_;
 
  411    std::unordered_map<std::size_t, Stencil> solidToVoidStencils_;
 
  413    std::unordered_map<std::size_t, std::vector<std::size_t>> voidToSolidConnectionIds_;
 
  414    std::unordered_map<std::size_t, std::vector<std::size_t>> solidToVoidConnectionIds_;
 
  416    std::vector<SubGridConnectionInfo> connectionInfo_;
 
  417    std::unordered_map<std::size_t, std::size_t> hostGridElementIndexToGlobalId_;