50    void update(
const FreeFlowMomentumGridGeometry& ffMomentumGridGeometry,
 
   51                const FreeFlowMassGridGeometry& ffMassGridGeometry,
 
   52                const PoreNetworkGridGeometry& pnmGridGeometry)
 
   55        resize_(ffMomentumGridGeometry, pnmGridGeometry);
 
   57        std::cout << 
"Initializing the coupling map..." << std::endl;
 
   59        auto ffFvGeometry = 
localView(ffMomentumGridGeometry);
 
   60        auto pnmFvGeometry = 
localView(pnmGridGeometry);
 
   62        using GlobalPosition = 
typename FreeFlowMomentumGridGeometry::GridView::template Codim<0>::Entity::Geometry::GlobalCoordinate;
 
   64        for (
const auto& pnmElement : elements(pnmGridGeometry.gridView()))
 
   66            const auto pnmElementIdx = pnmGridGeometry.elementMapper().index(pnmElement);
 
   67            pnmFvGeometry.bindElement(pnmElement);
 
   68            for (
const auto& pnmScv : scvs(pnmFvGeometry))
 
   71                if (!pnmGridGeometry.dofOnBoundary(pnmScv.dofIndex()))
 
   75                const auto pnmPos = pnmScv.dofPosition();
 
   76                const auto pnmDofIdx = pnmScv.dofIndex();
 
   77                const auto& otherPNMScv = pnmFvGeometry.scv(1 - pnmScv.indexInElement());
 
   78                const auto otherPNMScvDofIdx = otherPNMScv.dofIndex();
 
   81                const auto directlyCoupledFreeFlowElements = 
intersectingEntities(pnmPos, ffMomentumGridGeometry.boundingBoxTree());
 
   82                if (directlyCoupledFreeFlowElements.empty())
 
   85                    isCoupledPNMDof_[pnmDofIdx] = 
true;
 
   90                const std::size_t couplingNormalDirectionIndex = [&]
 
   92                    using Key = std::pair<std::size_t, bool>;
 
   93                    std::map<Key, std::size_t> result;
 
   94                    for (
const auto eIdx : directlyCoupledFreeFlowElements)
 
   96                        for (
const auto& intersection : intersections(ffMomentumGridGeometry.gridView(), ffMomentumGridGeometry.element(eIdx)))
 
  100                                const auto& 
normal = intersection.centerUnitOuterNormal();
 
  109                    if (directlyCoupledFreeFlowElements.size() == 1 && result.size() > 1)
 
  110                        DUNE_THROW(Dune::InvalidStateException, 
"Pore may not intersect with faces of different orientation when coupled to only one element");
 
  112                    return std::max_element(result.begin(), result.end(), [](
const auto& x, 
const auto& y) { return x.second < y.second;})->first.first;
 
  115                using Scalar = 
typename FreeFlowMomentumGridGeometry::GridView::ctype;
 
  116                const Scalar couplingPoreRadius = pnmGridGeometry.poreInscribedRadius(pnmDofIdx);
 
  117                GlobalPosition lowerLeft = pnmPos - GlobalPosition(couplingPoreRadius);
 
  118                lowerLeft[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
 
  119                GlobalPosition upperRight = pnmPos + GlobalPosition(couplingPoreRadius);
 
  120                upperRight[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
 
  122                auto axes = std::move(std::bitset<FreeFlowMomentumGridGeometry::Grid::dimensionworld>{}.set());
 
  123                axes.set(couplingNormalDirectionIndex, 
false);
 
  125                using PoreIntersectionGeometryType = Dune::AxisAlignedCubeGeometry<Scalar,
 
  126                                                                                   FreeFlowMomentumGridGeometry::GridView::dimension-1,
 
  127                                                                                   FreeFlowMomentumGridGeometry::GridView::dimensionworld>;
 
  129                PoreIntersectionGeometryType poreIntersectionGeometry(lowerLeft, upperRight, axes);
 
  130                const auto allCoupledFreeFlowElements = 
intersectingEntities(std::move(poreIntersectionGeometry), ffMomentumGridGeometry.boundingBoxTree());
 
  133                for (
const auto& ffElementInfo : allCoupledFreeFlowElements)
 
  135                    const auto freeFlowElementIndex = ffElementInfo.second();
 
  136                    pnmElementToFreeFlowElementsMap_[pnmElementIdx].push_back(freeFlowElementIndex);
 
  137                    freeFlowElementToPNMElementMap_[freeFlowElementIndex] = pnmElementIdx;
 
  139                    pnmToFreeFlowMassStencils_[pnmElementIdx].push_back(freeFlowElementIndex);
 
  140                    freeFlowMassToPNMStencils_[freeFlowElementIndex].push_back(pnmDofIdx);
 
  142                    ffFvGeometry.bindElement(ffMomentumGridGeometry.element(freeFlowElementIndex));
 
  143                    const auto coupledFreeFlowMomentumDofIndices = coupledFFMomentumDofs_(ffFvGeometry, ffMassGridGeometry, pnmPos, couplingPoreRadius, couplingNormalDirectionIndex);
 
  145                    pnmToFreeFlowMomentumStencils_[pnmElementIdx].push_back(coupledFreeFlowMomentumDofIndices.coupledFrontalDof);
 
  146                    freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(pnmDofIdx);
 
  147                    freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(otherPNMScvDofIdx);
 
  149                    isCoupledFreeFlowMomentumDof_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] = 
true;
 
  150                    isCoupledFreeFlowMomentumDofOnInterface_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] = 
true;
 
  153                    for (
const auto ffDofIdx : coupledFreeFlowMomentumDofIndices.coupledLateralDofs)
 
  155                        freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(pnmDofIdx);
 
  156                        freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(otherPNMScvDofIdx);
 
  157                        isCoupledFreeFlowMomentumDof_[ffDofIdx] = 
true;
 
  163        std::cout << 
"took " << watch.elapsed() << 
" seconds." << std::endl;