diff --git a/src/spatial-solving/preconditioners/supportpatchfactory.hh b/src/spatial-solving/preconditioners/supportpatchfactory.hh
index f518ecc0de92b9fcdbaab92bdfca58b36f26072a..76d64e3761a95ae0196c94e0a11e46bedb856b0f 100644
--- a/src/spatial-solving/preconditioners/supportpatchfactory.hh
+++ b/src/spatial-solving/preconditioners/supportpatchfactory.hh
@@ -16,128 +16,77 @@
 //#include "../../data-structures/levelcontactnetwork.hh"
 #include "hierarchicleveliterator.hh"
 
-template <class Element>
-class BodyElement {
-private:
-    size_t bodyID_;
-    Element element_;
-
-public:
-    BodyElement() {}
-    BodyElement(size_t bodyID, const Element& element) {
-        set(bodyID, element);
-    }
-
-    void set(size_t bodyID, const Element& element) {
-        bodyID_ = bodyID;
-        element_ = element;
-    }
-
-    const auto& bodyID() const {
-        return bodyID_;
-    }
-    const auto& element() const {
-        return element_;
-    }
-};
-
-
 template <class LevelContactNetwork>
-class BodyHelper {
+class NetworkIndexMapper {
 private:
+    using FiniteElementCache = Dune::PQkLocalFiniteElementCache<ctype, ctype, dim, 1>; // P1 finite element cache
     using GridType = typename LevelContactNetwork::DeformedGridType;
-    static const int dim = GridType::dimension;
-
     using Element = typename GridType::template Codim<0>::Entity;
-    //using Vertex = typename GridType::template Codim<dim>::Entity;
-
-    using LevelGridView = typename LevelContactNetwork::DeformedLevelGridView;
-    using LeafGridView = typename LevelContactNetwork::DeformedLeafGridView;
-
-    using HierarchicLevelIteratorType = HierarchicLevelIterator<GridType>;
-    using LevelElementMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LevelGridView,  Dune::MCMGElementLayout >;
-    using LevelFaceMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LevelGridView,  mcmgLayout(Codim<1>()) >;
 
-    using LeafElementMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LeafGridView,  Dune::MCMGElementLayout >;
-    using LeafFaceMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LeafGridView, mcmgLayout(Codim<1>()) >;
-
-    bool levelMode_;
-
-    std::unique_ptr<LevelGridView> levelGridView_;
-    LevelElementMapper levelElementMapper_;
-    LevelFaceMapper levelFaceMapper_;
+    static const int dim = LevelContactNetwork::dimension; //TODO
+    static const FiniteElementCache cache_;
 
-    std::unique_ptr<LeafGridView> leafGridView_;
-    LeafElementMapper leafElementMapper_;
-    LeafFaceMapper leafFaceMapper_;
+    const LevelContactNetwork& levelContactNetwork_;
+    const size_t nBodies_;
 
-    std::vector<std::vector<Element>>& vertexInElements_;
+    std::vector<size_t> vertexOffSet_;
+    std::vector<size_t> faceOffSet_;
+    std::vector<size_t> elementOffSet_;
 
-    //std::vector<size_t> globalToLocal_;
+public:
+    NetworkIndexMapper(const LevelContactNetwork& levelContactNetwork) :
+        levelContactNetwork_(levelContactNetwork),
+        nBodies_(levelContactNetwork_.nBodies()),
+        vertexOffSet_(nBodies_),
+        faceOffSet_(nBodies_),
+        elementOffSet_(nBodies_) {
 
-    template <class GV>
-    void init(const GV& gv) {
-        // init vertexInElements
-        vertexInElements_.resize(gv.size(dim));
-        for (size_t i=0; i<vertexInElements_.size(); i++) {
-                vertexInElements_[i].resize(0);
-        }
+        size_t vertexOffSet = 0;
+        size_t faceOffSet = 0;
+        size_t elementOffSet = 0;
 
-        const auto& indexSet = gv.indexSet();
+        for (size_t i=0; i<nBodies_; i++) {
+            const auto& gridView = levelContactNetwork_.body(i)->gridView();
 
-        for (const auto& elem : elements(gv)) {
-            const auto& lfe = cache_.get(elem.type());
+            vertexOffSet_[i] = vertexOffSet + gridView.size(dim);
+            vertexOffSet = vertexOffSet_[i];
 
-            for (size_t j=0; j<lfe.localBasis().size(); ++j) {
-                auto localIdx = lfe.localCoefficients().localKey(j).subEntity();
-                int dofIndex = indexSet.subIndex(elem, localIdx, dim);
+            faceOffSet_[i] = faceOffSet + gridView.size(1);
+            faceOffSet = faceOffSet_[i];
 
-                vertexInElements_[dofIndex].push_back(elem);
-            }
+            elementOffSet_[i] = elementOffSet + gridView.size(0);
+            elementOffSet = elementOffSet_[i];
         }
     }
-public:
-
-    BodyHelper(const LevelGridView& gridView) :
-        levelMode_(true),
-        levelGridView_(std::make_unique<LevelGridView>(gridView)),
-        levelElementMapper_(gridView),
-        leafFaceMapper_(gridView) {
-
-        init(gridView);
-    }
 
-    BodyHelper(const LeafGridView& gridView) :
-        levelMode_(false),
-        leafGridView_(std::make_unique<LeafGridView>(gridView)),
-        leafElementMapper_(gridView),
-        leafFaceMapper_(gridView) {
-
-        init(gridView);
-    }
+    size_t vertexIndex(const size_t bodyID, const Element& elem, const size_t localVertex) const {
+        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
 
-    const auto& gridView() const {
-        return (levelMode_ ? levelGridView_ : leafGridView_);
+        auto localIdx = cache_.get(elem.type()).localCoefficients().localKey(localVertex).subEntity();
+        return vertexOffSet_[bodyID] + gridView.indexSet().subIndex(elem, localIdx, dim);
     }
 
-    const auto& elementMapper() const {
-        return (levelMode_ ? levelElementMapper_ : leafElementMapper_);
+    template <class Intersection>
+    size_t faceIndex(const size_t bodyID, const Intersection& is) const {
+        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
+        return faceOffSet_[bodyID] + gridView.indexSet().subIndex(is.inside(), is.indexInInside(), 1);
     }
 
-    const auto& faceMapper() const {
-        return (levelMode_ ? levelFaceMapper_ : leafFaceMapper_);
+    size_t faceIndex(const size_t bodyID, const Element& elem, const size_t indexInInside) const {
+        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
+        return faceOffSet_[bodyID] + gridView.indexSet().subIndex(elem, indexInInside, 1);
     }
 
-    const auto& vertexInElements() const {
-        return vertexInElements_;
+    size_t elementIndex(const size_t bodyID, const Element& elem) const {
+        const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
+        return elementOffSet_[bodyID] + gridView.indexSet().index(elem);
     }
 
-    const auto& cache() const {
+    static const auto& cache() const {
         return cache_;
     }
 };
 
-
 /**
  *  constructs BitSetVector whose entries are
  *      true,   if vertex is outside of patch or part of patch boundary
@@ -150,130 +99,139 @@ class SupportPatchFactory
     using Patch = Dune::BitSetVector<1>;
 
 private:
+    struct BodyElement {
+        size_t bodyID;
+        Element element;
+
+        void set(const size_t _bodyID, const Element& _elem) {
+            bodyID = _bodyID;
+            element = _elem;
+        }
+    };
+
+    struct RemoteIntersection {
+        size_t bodyID; // used to store bodyID of outside elem
+        GridGlue& glue;
+        size_t intersectionID;
+
+        bool flip = false;
+
+        void set(const size_t _bodyID, const GridGlue& _glue, const size_t _intersectionID, bool _flip = false) {
+            bodyID = _bodyID;
+            glue = _glue;
+            intersectionID = _intersectionID;
+            flip = _flip;
+        }
+
+        auto& get() {
+            return (flip) ? glue.getIntersection(intersectionID).flip() : glue.getIntersection(intersectionID);
+        }
+    };
+
     static const int dim = LevelContactNetwork::dimension; //TODO
     using ctype = typename LevelContactNetwork::ctype;
 
-    using BodyHelper = BodyHelper<LevelContactNetwork>;
     //using Vertex = typename GridType::template Codim<dim>::Entity;
 
     using Element = typename LevelContactNetwork::DeformedGridType::template Codim<0>::Entity;
     using BodyElement = BodyElement<Element>;
-    using FiniteElementCache = Dune::PQkLocalFiniteElementCache<ctype, ctype, dim, 1>; // P1 finite element cache
+
+    using NetworkIndexMapper = NetworkIndexMapper<LevelContactNetwork>;
+
+    using GridGlue = ;
 
     const size_t nBodies_;
 
     const LevelContactNetwork& coarseContactNetwork_;
     const LevelContactNetwork& fineContactNetwork_;
 
-    std::vector<std::unique_ptr<BodyHelper>> bodyHelper_;
+    std::map<size_t, std::vector<RemoteIntersection>> coarseIntersectionMapper_; // map faceID to neighbor elements
+    std::map<size_t, std::vector<RemoteIntersection>> fineIntersectionMapper_; // map faceID to neighbor elements
+    std::map<size_t, std::vector<size_t>> neighborFaceDofs_; // map faceID to neighbor element dofs
 
-    std::map<size_t, std::vector<BodyElement>> neighborElements_; // map faceID to neighbor elements
-    std::map<size_t, std::vector<size_t>> neighborElementDofs_; // map faceID to neighbor element dofs
+    std::set<size_t> interiorContactDofs_;
 
-    std::vector<size_t> vertexOffSet_;
-    std::vector<size_t> faceOffSet_;
-    std::vector<size_t> elementOffSet_;
-
-    FiniteElementCache cache_;
+    const NetworkIndexMapper coarseIndices_;
+    const NetworkIndexMapper fineIndices_;
 
 public:
     SupportPatchFactory(const LevelContactNetwork& coarseContactNetwork, const LevelContactNetwork& fineContactNetwork) :
         nBodies_(coarseContactNetwork_.nBodies()),
         coarseContactNetwork_(coarseContactNetwork),
         fineContactNetwork_(fineContactNetwork),
-        bodyHelper_(nBodies_),
-        vertexOffSet_(nBodies_),
-        faceOffSet_(nBodies_),
-        elementOffSet_(nBodies_){
+        coarseIndices_(coarseContactNetwork_),
+        fineIndices_(fineContactNetwork_) {
 
         assert(nBodies_ == fineContactNetwork_.nBodies());
 
-        size_t vertexOffSet = 0;
-        size_t faceOffSet = 0;
-        size_t elementOffSet = 0;
-
-        for (size_t i=0; i<nBodies_; i++) {
-            const auto& gridView = coarseContactNetwork_.body(i)->gridView();
-            bodyHelper_[i] = std::make_unique<BodyHelper>(gridView);
-
-            vertexOffSet_[i] = vertexOffSet + gridView.size(dim);
-            vertexOffSet = vertexOffSet_[i];
-
-            faceOffSet_[i] = faceOffSet + gridView.size(1);
-            faceOffSet = faceOffSet_[i];
-
-            elementOffSet_[i] = elementOffSet + gridView.size(0);
-            elementOffSet = elementOffSet_[i];
-        }
-
-        // init boundary mapping/transfer
-        const auto& nBodyAssembler = coarseContactNetwork_.nBodyAssembler();
-        const auto& contactCouplings = nBodyAssembler.getContactCouplings();
+        setup(coarseContactNetwork_, coarseIndices_, coarseIntersectionMapper_);
+        setup(fineContactNetwork_, fineIndices_, fineIntersectionMapper_);
 
+        // setup neighborFaceDofs_
+        const auto& contactCouplings = coarseContactNetwork_.nBodyAssembler().getContactCouplings();
         for (size_t i=0; i<contactCouplings.size(); i++) {
-            const auto& coupling = nBodyAssembler.getCoupling(i);
-            const auto& contactCoupling = contactCouplings[i];
-
-            const size_t nmBody = coupling.gridIdx_[0];
-            const size_t mBody = coupling.gridIdx_[1];
-
-            const auto& nmBoundary = contactCoupling.nonmortarBoundary();
-            const auto& mBoundary = contactCoupling.mortarBoundary();
-
-            const auto& nmIndexSet = nonmortarBoundary.gridView().indexSet();
-            const auto& mIndexSet = mortarBoundary.gridView().indexSet();
-
-            for (const auto& rIs : intersections(*contactCoupling.getGlue())) {
-                const auto& inside = rIs.inside();
-                const auto& outside = rIs.outside();
-
-                int nmFaceIdx = nmIndexSet.subIndex(inside, rIs.indexInInside(), 1);
-                int mFaceIdx = mIndexSet.subIndex(outside, rIs.indexInOutside(), 1);
-
-                BodyElement nmBodyElement(nmBody, inside);
-                BodyElement mBodyElement(mBody, outside);
+                const auto& coupling = nBodyAssembler.getCoupling(i);
+                const auto& glue = *contactCouplings[i].getGlue();
 
-                neighborElements_[nmFaceIdx].emplace_back(mBodyElement);
-                neighborElements_[mFaceIdx].emplace_back(nmBodyElement);
+                const size_t nmBody = coupling.gridIdx_[0];
+                const size_t mBody = coupling.gridIdx_[1];
 
-                std::set<size_t> dofs;
-                computeIntersectionDofs(nmIndexSet, rIs, dofs);
-                neighborElementDofs_[nmFaceIdx].insert(neighborElementDofs_[nmFaceIdx].end(), dofs.begin(), dofs.end());
+                for (const auto& rIs : intersections(glue)) {
+                    size_t nmFaceIdx = coarseIndices_.faceIndex(nmBody, rIs.inside(), rIs.indexInInside());
+                    size_t mFaceIdx = coarseIndices_.faceIndex(mBody, rIs.outside(), rIs.indexInOutside());
 
-                computeIntersectionDofs(mIndexSet, rIs, dofs, false);
-                neighborElementDofs_[mFaceIdx].insert(neighborElementDofs_[mFaceIdx].end(), dofs.begin(), dofs.end());
+                    std::array<std::set<size_t>, 2> dofs;
+                    remoteIntersectionDofs(coarseIndices_, rIs, nmBody, mBody, dofs);
+                    neighborFaceDofs_[nmFaceIdx].insert(neighborFaceDofs_[nmFaceIdx].end(), dofs[1].begin(), dofs[1].end());
+                    neighborFaceDofs_[mFaceIdx].insert(neighborFaceDofs_[mFaceIdx].end(), dofs[0].begin(), dofs[0].end());
+                }
             }
-        }
 
-        // neighborElementDofs_ contains dofs of connected intersections that are neighbors to a face given by faceID,
-        // boundary dofs are contained once, interior dofs multiple times
-        // task: remove boundary dofs and redundant multiples of interior dofs
-        for (auto& it : neighborElementDofs_) {
-            auto& dofs = it.second;
-
-            std::sort(dofs.begin(), dofs.end());
-            auto& dof = dofs.begin();
-            while (dof != dofs.end()) {
-                auto next = dof;
-                if (*dof != *(++next))
-                    dof = dofs.erase(dof);
+        /*
+            // neighborElementDofs_ contains dofs of connected intersections that are neighbors to a face given by faceID,
+            // boundary dofs are contained once, interior dofs multiple times
+            // task: remove boundary dofs and redundant multiples of interior dofs
+            // TODO: only works in 2D
+            for (auto& it : neighborElementDofs) {
+                auto& dofs = it.second;
+
+                std::sort(dofs.begin(), dofs.end());
+                auto& dof = dofs.begin();
+                while (dof != dofs.end()) {
+                    auto next = dof;
+                    if (*dof != *(++next))
+                        dof = dofs.erase(dof);
+                }
+                dofs.erase(std::unique(dofs.begin(), dofs.end()), dofs.end());
             }
-            dofs.erase(std::unique(dofs.begin(), dofs.end()), dofs.end());
-        }
+        */
     }
 
     void build(const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const int patchDepth = 0) {
         BodyElement seedElement(bodyID, coarseElement);
 
+        auto isPatchIntersection = [](auto& is, const size_t bodyID, const std::set<size_t>& patchVertices, std::set<size_t>& newPatchVertices) {
+            std::set<size_t> dofs;
+            intersectionDofs(coarseIndices_, is, bodyID, dofs);
+
+            for (auto& dof : dofs) {
+                if (patchVertices.count(dof)) {
+                    newPatchVertices.insert(dofs.begin(), dofs.end());
+                    return true;
+                }
+            }
+            return false;
+        };
+
         // construct coarse patch
         std::vector<BodyElement> patchElements;
         patchElements.emplace_back(seedElement);
 
         std::set<size_t> visitedElements;
-        visitedElements.insert(elementIndex(seedElement));
+        visitedElements.insert(coarseIndices_.elementIndex(seedElement.bodyID, seedElement.element));
 
         std::set<size_t> patchVertices;
-        patchVertices.insert(vertexIndex(bodyID, coarseElement, localVertex));
+        patchVertices.insert(coarseIndices_.vertexIndex(bodyID, coarseElement, localVertex));
 
         std::queue<BodyElement> patchSeeds;
         patchSeeds.push(seedElement);
@@ -286,36 +244,37 @@ class SupportPatchFactory
                 const auto& patchSeed = patchSeeds.front();
                 patchSeeds.pop();
 
-                size_t elemIdx = elementIndex(patchSeed);
+                size_t elemIdx = coarseIndices_.elementIndex(patchSeed.bodyID, patchSeed.element);
 
                 if (visitedElements.count(elemIdx))
                     continue;
 
                 visitedElements.insert(elemIdx);
 
-                size_t bodyIdx = patchSeed.bodyID();
-                const auto& elem = patchSeed.element();
-                const auto& gridView = bodyHelper_[bodyIdx]->gridView();
+                size_t bodyIdx = patchSeed.bodyID;
+                const auto& elem = patchSeed.element;
+                const auto& gridView = coarseContactNetwork_.body(bodyIdx)->gridView();
 
                 for (auto& it : intersections(gridView, elem)) {
-                    if (isPatchIntersection(gridView.indexSet(), it, patchVertices, newPatchVertices)) {
+                    if (isPatchIntersection(it, bodyIdx, patchVertices, newPatchVertices)) {
                         if (it.neighbor()) {
                             BodyElement neighbor(bodyIdx, it.outside());
 
-                            if (visitedElements.count(elementIndex(neighbor)))
+                            if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                 continue;
 
                             patchElements.emplace_back(neighbor);
                             patchSeeds.push(neighbor);
                         } else {
-                            size_t faceIdx = faceIndex(bodyIdx, it);
+                            size_t faceIdx = coarseIndices_.faceIndex(bodyIdx, it);
 
-                            if (neighborElements_.count(faceIdx)) {
-                                const auto& neighbors = neighborElements_[faceIdx];
-                                for (size_t i=0; i<neighbors.size(); i++) {
-                                    const auto& neighbor = neighbors[i];
+                            if (coarseIntersectionMapper_.count(faceIdx)) {
+                                const auto& intersections = coarseIntersectionMapper_[faceIdx];
+                                for (size_t i=0; i<intersections.size(); i++) {
+                                    BodyElement neighbor;
+                                    neighbor.set(intersections[i].bodyID, intersections[i].get().outside());
 
-                                    if (visitedElements.count(elementIndex(neighbor)))
+                                    if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                         continue;
 
                                     patchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
@@ -328,19 +287,20 @@ class SupportPatchFactory
                         if (it.neighbor()) {
                             BodyElement neighbor(bodyIdx, it.outside());
 
-                            if (visitedElements.count(elementIndex(neighbor)))
+                            if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                 continue;
 
                             nextSeeds.emplace_back(neighbor);
                         } else {
-                            size_t faceIdx = faceIndex(bodyIdx, it);
+                            size_t faceIdx = coarseIndices_.faceIndex(bodyIdx, it);
 
-                            if (neighborElements_.count(faceIdx)) {
-                                const auto& neighbors = neighborElements_[faceIdx];
-                                for (size_t i=0; i<neighbors.size(); i++) {
-                                    const auto& neighbor = neighbors[i];
+                            if (coarseIntersectionMapper_.count(faceIdx)) {
+                                const auto& intersections = coarseIntersectionMapper_[faceIdx];
+                                for (size_t i=0; i<intersections.size(); i++) {
+                                    BodyElement neighbor;
+                                    neighbor.set(intersections[i].bodyID, intersections[i].get().outside());
 
-                                    if (visitedElements.count(elementIndex(neighbor)))
+                                    if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                         continue;
 
                                     newPatchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
@@ -359,42 +319,50 @@ class SupportPatchFactory
         }
 
         // construct fine patch
+        using HierarchicLevelIteratorType = HierarchicLevelIterator<typename LevelContactNetwork::DeformedGridType>;
+        std::set<size_t> patchBoundary;
         for (size_t i=0; i<patchElements.size(); ++i) {
-            addFinePatchElements(patchElements[i], visitedElements, patchDofs);
-        }
-    }
+            const auto& coarseElem = patchElements[i];
 
-private:
-    template <class IndexSet, class Intersection>
-    bool isPatchIntersection(const IndexSet& indexSet, const Intersection& is, const std::set<size_t>& patchVertices, std::set<size_t>& newPatchVertices) {
-        std::set<size_t> intersectionDofs;
-        computeIntersectionDofs(indexSet, is, intersectionDofs);
-
-        for (auto& dof : intersectionDofs) {
-            if (patchVertices.count(dof)) {
-                newPatchVertices.insert(intersectionDofs.begin(), intersectionDofs.end());
-                return true;
+            const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID)->gridView().grid();
+            const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID)->gridView().level();
+
+            // add fine patch elements
+            HierarchicLevelIteratorType endHierIt(grid, coarseElem.element, HierarchicLevelIteratorType::PositionFlag::end, fineLevel);
+            HierarchicLevelIteratorType hierIt(grid, coarseElem.element, HierarchicLevelIteratorType::PositionFlag::begin, fineLevel);
+            for (; hierIt!=endHierIt; ++hierIt) {
+                const Element& fineElem = *hierIt;
+                addLocalDofs(coarseElem, fineElem, visitedElements, patchBoundary, patchDofs);
             }
         }
-        return false;
     }
 
-    size_t vertexIndex(const size_t bodyID, const Element& elem, const size_t localVertex) const {
-        const auto& gridView = bodyHelper_[bodyID]->gridView();
+private:
+    void setup(const LevelContactNetwork& levelContactNetwork, const NetworkIndexMapper& indices, std::map<size_t, std::vector<RemoteIntersection>>& faceToRIntersections) {
+        const auto& nBodyAssembler = levelContactNetwork.nBodyAssembler();
+        const auto& contactCouplings = nBodyAssembler.getContactCouplings();
 
-        auto localIdx = cache_.get(elem.type()).localCoefficients().localKey(localVertex).subEntity();
-        return vertexOffSet_[bodyID] + gridView.indexSet().subIndex(elem, localIdx, dim);
-    }
+        for (size_t i=0; i<contactCouplings.size(); i++) {
+            const auto& coupling = nBodyAssembler.getCoupling(i);
+            const auto& glue = *contactCouplings[i].getGlue();
 
-    template <class Intersection>
-    size_t faceIndex(const size_t bodyID, const Intersection& is) const {
-        const auto& gridView = bodyHelper_[bodyID]->gridView();
-        return faceOffSet_[bodyID] + gridView.indexSet().subIndex(is.inside(), is.indexInInside(), 1);
-    }
+            const size_t nmBody = coupling.gridIdx_[0];
+            const size_t mBody = coupling.gridIdx_[1];
+
+            size_t rIsID = 0;
+            for (const auto& rIs : intersections(glue)) {
+                size_t nmFaceIdx = indices.faceIndex(nmBody, rIs.inside(), rIs.indexInInside());
+                size_t mFaceIdx = indices.faceIndex(mBody, rIs.outside(), rIs.indexInOutside());
+
+                RemoteIntersection nmIntersection(mBody, glue, rIsID, false);
+                faceToRIntersections[nmFaceIdx].emplace_back(nmIntersection);
 
-    size_t elementIndex(const BodyElement& bodyElem) const {
-        const auto& gridView = bodyHelper_[bodyElem.bodyID()]->gridView();
-        return elementOffSet_[bodyElem.bodyID()] + gridView.indexSet().index(bodyElem.element());
+                RemoteIntersection mIntersection(nmBody, glue, rIsID, true);
+                faceToRIntersections[mFaceIdx].emplace_back(mIntersection);
+
+                rIsID++;
+            }
+        }
     }
 
     template <class Intersection>
@@ -402,112 +370,133 @@ class SupportPatchFactory
 	    return ReferenceElementHelper<double, dim>::subEntityContainsSubEntity(elem.type(), intersection.indexInInside(), 1, subEntity, codim);
 	}
       
-    void addFinePatchElements(const BodyElement& coarseElem, const std::set<size_t>& coarsePatch, Patch& patchDofs) {
-        using HierarchicLevelIteratorType = HierarchicLevelIterator<typename LevelContactNetwork::DeformedGridType>;
-
-        const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID())->gridView().grid();
-        const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID())->gridView().level();
-
-        HierarchicLevelIteratorType endHierIt(grid, coarseElem.element(), HierarchicLevelIteratorType::PositionFlag::end, fineLevel);
-        HierarchicLevelIteratorType hierIt(grid, coarseElem.element(), HierarchicLevelIteratorType::PositionFlag::begin, fineLevel);
-        for (; hierIt!=endHierIt; ++hierIt) {
-            const Element& fineElem = *hierIt;
-            addLocalDofs(coarseElem, fineElem, coarsePatch, patchDofs);
-	    }
-	}	  
-	
-    void addLocalDofs(const BodyElement& coarseElem, const Element& fineElem, const std::set<size_t>& coarsePatch, Patch& patchDofs) {
+    void addLocalDofs(const BodyElement& coarseElem, const Element& fineElem, const std::set<size_t>& coarsePatch, std::set<size_t>& patchBoundary, Patch& patchDofs) {
 	    // insert local dofs
         const auto& lfe = cache_.get(fineElem.type());
-        const auto& gridView = fineContactNetwork_.body(coarseElem.bodyID())->gridView();
+        const auto& gridView = fineContactNetwork_.body(coarseElem.bodyID)->gridView();
         const auto& indexSet = gridView.indexSet();
-
-        for (size_t i=0; i<lfe.localBasis().size(); ++i) {
-            auto localIdx = lfe.localCoefficients().localKey(i).subEntity();
-            int dofIndex = indexSet.subIndex(fineElem, localIdx, dim);
-            patchDofs[dofIndex][0] = false;
-	    }
 	    
-        const auto coarseLevel = coarseElem.element().level();
+        const size_t bodyID = coarseElem.bodyID;
+
+        const auto coarseLevel = coarseElem.element.level();
 
 	    // search for parts of the global and inner boundary 
         for (const auto& is : intersections(gridView, fineElem)) {
-            bool isPatchBoundary = false;
-
             if (is.neighbor()) {
-                auto outsideFather = is.outside();
-		    
-                while (outsideFather.level()>coarseLevel) {
-                    outsideFather = outsideFather.father();
-                }
-		    
-                BodyElement outside(coarseElem.bodyID(), outsideFather);
+                std::set<size_t> isDofs;
+                intersectionDofs(fineIndices_, is, bodyID, isDofs);
 
-                if (!coarsePatch.count(elementIndex(outside))) {
-                    isPatchBoundary = true;
+                auto outsideFather = coarseFather(is.outside(), coarseLevel);
+		    
+                if (!coarsePatch.count(coarseIndices_.elementIndex(coarseElem.bodyID, outsideFather))) {
+                    addToPatchBoundary(isDofs, patchBoundary, patchDofs);
+                } else {
+                    addToPatch(isDofs, patchBoundary, patchDofs);
                 }
             } else {
-                isPatchBoundary = true;
+                size_t faceIdx = fineIndices_.faceIndex(bodyID, is);
+                if (fineIntersectionMapper_.count(faceIdx)) {
+                    const auto& intersections = coarseIntersectionMapper_[faceIdx];
 
-                auto outsideFather = is.outside();
+                    for (size_t i=0; i<intersections.size(); i++) {
+                        const auto& intersection = intersections[i];
+                        const auto& rIs = intersection.get();
+                        const size_t outsideID = intersection.bodyID;
 
-                while (outsideFather.level()>coarseLevel) {
-                    outsideFather = outsideFather.father();
-                }
+                        std::set<size_t> rIsDofs;
+                        remoteIntersectionDofs(fineIndices_, rIs, bodyID, outsideID, rIsDofs);
 
-                BodyElement outside(coarseElem.bodyID(), outsideFather);
+                        if (rIs.neighbor()) {
+                            auto outsideFather = coarseFather(rIs.outside(), fineContactNetwork_.body(outsideID)->gridView().level());
 
-                size_t faceIdx = faceIndex(coarseElem.bodyID(), is);
-
-                if (neighborElements_.count(faceIdx)) {
-                    const auto& outside = neighbors[0];
-
-                    if (coarsePatch.count(elementIndex(outside))) {
-                        isPatchBoundary = false;
+                            if (!coarsePatch.count(coarseIndices_.elementIndex(outsideID, outsideFather))) {
+                                addToPatchBoundary(rIsDofs, patchBoundary, patchDofs);
+                            } else {
+                                addToPatch(rIsDofs, patchBoundary, patchDofs);
+                            }
+                        } else {
+                            addToPatchBoundary(rIsDofs, patchBoundary, patchDofs);
+                        }
                     }
+                } else {
+                    std::set<size_t> isDofs;
+                    intersectionDofs(fineIndices_, is, bodyID, isDofs);
+
+                    addToPatchBoundary(isDofs, patchBoundary, patchDofs);
                 }
             }
-		
-            if (isPatchBoundary) {
-                const auto& localCoefficients = cache_.get(fineElem.type()).localCoefficients();
+        }
+	}
+
+    auto&& coarseFather(const Element& fineElem, const size_t coarseLevel) const {
+        Element coarseElem = fineElem;
+        while (coarseElem.level() > coarseLevel) {
+            coarseElem = coarseElem.father();
+        }
+        return coarseElem;
+    }
+
+    void addToPatchBoundary(const std::set<size_t>& dofs, std::set<size_t>& patchBoundary, Patch& patchDofs) {
+        for (auto& dof : dofs) {
+            patchBoundary.insert(dof);
+            patchDofs[dof][0] = true;
+        }
+    }
+
+    template <class Intersection>
+    void addToPatch(const std::set<size_t>& dofs, const std::set<size_t>& patchBoundary, Patch& patchDofs) {
+        for (auto& dof : dofs) {
+            if (!patchBoundary.count(dof)) {
+                patchDofs[dof][0] = false;
+            }
+        }
+    }
 
-                for (size_t i=0; i<localCoefficients.size(); i++) {
-                    auto entity = localCoefficients.localKey(i).subEntity();
-                    auto codim  = localCoefficients.localKey(i).codim();
+    template <class RIntersection>
+    void remoteIntersectionDofs(const NetworkIndexMapper& indices, const RIntersection& is, const size_t insideID, const size_t outsideID, std::array<std::set<size_t>, 2>& dofs) {
+        dofs.clear();
 
-                    if (containsInsideSubentity(fineElem, is, entity, codim)) {
-                        int dofIndex = indexSet.subIndex(fineElem, entity, dim);
-                        patchDofs[dofIndex][0] = true;
-                    }
-                }
+        const auto& inside = is.inside();
+        const auto& insideGeo = inside.geometry();
+        const auto& insideRefElement = Dune::ReferenceElements<ctype, dim>::general(inside.type());
+
+        for (int i=0; i<insideRefElement.size(dim); i++) {
+            const auto& localCorner = isGeo.local(insideGeo.corner(i));
+
+            if (isRefElement.checkInside(localCorner)) {
+                dofs[0].insert(indices.vertexIndex(insideID, inside, i));
             }
-	    }	
-	}
+        }
 
+        const auto& isGeo = is.geometry();
+        const auto& isRefElement = Dune::ReferenceElements<ctype, dim-1>::general(is.type());
 
-    template <class IndexSet, class Intersection>
-    void computeIntersectionDofs(const IndexSet& idxSet, const Intersection& intersection, std::set<size_t>& intersectionDofs, bool inside = true) {
-        intersectionDofs.clear();
+        const auto& outside = is.outside();
+        const auto& outsideGeo = outside.geometry();
+        const auto& outsideRefElement = Dune::ReferenceElements<ctype, dim>::general(outside.type());
 
-        Element* elem;
-        size_t intersectionIndex;
+        for (int i=0; i<outsideRefElement.size(dim); i++) {
+            const auto& localCorner = isGeo.local(outsideGeo.corner(i));
 
-        if (inside) {
-            elem = &intersection.inside();
-            intersectionIndex = intersection.indexInInside();
-        } else {
-            elem = &intersection.outside();
-            intersectionIndex = intersection.indexInOutside();
+            if (isRefElement.checkInside(localCorner)) {
+                dofs[1].insert(indices.vertexIndex(outsideID, outside, i));
+            }
         }
+    }
+
+    template <class Intersection>
+    void intersectionDofs(const NetworkIndexMapper& indices, const Intersection& is, const size_t bodyID, std::set<size_t>& dofs) {
+        dofs.clear();
+
+        const Element& elem = is.inside();
+        size_t intersectionIndex = is.indexInInside();
 
         const int dimElement = Element::dimension;
-        const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(elem->type());
+        const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(elem.type());
 
         for (int i=0; i<refElement.size(intersectionIndex, 1, dimElement); i++) {
             size_t idxInElement = refElement.subEntity(intersectionIndex, 1, i, dimElement);
-            size_t globalIdx = idxSet.subIndex(*elem, idxInElement, dimElement);
-
-            intersectionDofs.insert(globalIdx);
+            dofs.insert(indices.vertexIndex(bodyID, elem, idxInElement));
         }
     }
 };
diff --git a/src/spatial-solving/preconditioners/supportpatchfactory.hh.autosave b/src/spatial-solving/preconditioners/supportpatchfactory.hh.autosave
deleted file mode 100644
index 869cbd83d4f0cf01737f5d7d41f7cd53c392da96..0000000000000000000000000000000000000000
--- a/src/spatial-solving/preconditioners/supportpatchfactory.hh.autosave
+++ /dev/null
@@ -1,518 +0,0 @@
-#ifndef SUPPORT_PATCH_FACTORY_HH
-#define SUPPORT_PATCH_FACTORY_HH
-
-#include <set>
-#include <queue>
-#include <memory>
-
-#include <dune/common/bitsetvector.hh>
-#include <dune/common/fvector.hh>
-
-#include <dune/fufem/referenceelementhelper.hh>
-#include <dune/grid/common/mcmgmapper.hh>
-
-#include <dune/localfunctions/lagrange/pqkfactory.hh>
-
-//#include "../../data-structures/levelcontactnetwork.hh"
-#include "hierarchicleveliterator.hh"
-
-template <class Element>
-class BodyElement {
-private:
-    size_t bodyID_;
-    Element element_;
-
-public:
-    BodyElement() {}
-    BodyElement(size_t bodyID, const Element& element) {
-        set(bodyID, element);
-    }
-
-    void set(size_t bodyID, const Element& element) {
-        bodyID_ = bodyID;
-        element_ = element;
-    }
-
-    const auto& bodyID() const {
-        return bodyID_;
-    }
-    const auto& element() const {
-        return element_;
-    }
-};
-
-
-template <class LevelContactNetwork>
-class BodyHelper {
-private:
-    using GridType = typename LevelContactNetwork::DeformedGridType;
-    static const int dim = GridType::dimension;
-
-    using Element = typename GridType::template Codim<0>::Entity;
-    //using Vertex = typename GridType::template Codim<dim>::Entity;
-
-    using LevelGridView = typename LevelContactNetwork::DeformedLevelGridView;
-    using LeafGridView = typename LevelContactNetwork::DeformedLeafGridView;
-
-    using HierarchicLevelIteratorType = HierarchicLevelIterator<GridType>;
-    using LevelElementMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LevelGridView,  Dune::MCMGElementLayout >;
-    using LevelFaceMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LevelGridView,  mcmgLayout(Codim<1>()) >;
-
-    using LeafElementMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LeafGridView,  Dune::MCMGElementLayout >;
-    using LeafFaceMapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<LeafGridView, mcmgLayout(Codim<1>()) >;
-
-    bool levelMode_;
-
-    std::unique_ptr<LevelGridView> levelGridView_;
-    LevelElementMapper levelElementMapper_;
-    LevelFaceMapper levelFaceMapper_;
-
-    std::unique_ptr<LeafGridView> leafGridView_;
-    LeafElementMapper leafElementMapper_;
-    LeafFaceMapper leafFaceMapper_;
-
-    std::vector<std::vector<Element>>& vertexInElements_;
-
-    //std::vector<size_t> globalToLocal_;
-
-    template <class GV>
-    void init(const GV& gv) {
-        // init vertexInElements
-        vertexInElements_.resize(gv.size(dim));
-        for (size_t i=0; i<vertexInElements_.size(); i++) {
-                vertexInElements_[i].resize(0);
-        }
-
-        const auto& indexSet = gv.indexSet();
-
-        for (const auto& elem : elements(gv)) {
-            const auto& lfe = cache_.get(elem.type());
-
-            for (size_t j=0; j<lfe.localBasis().size(); ++j) {
-                auto localIdx = lfe.localCoefficients().localKey(j).subEntity();
-                int dofIndex = indexSet.subIndex(elem, localIdx, dim);
-
-                vertexInElements_[dofIndex].push_back(elem);
-            }
-        }
-    }
-public:
-
-    BodyHelper(const LevelGridView& gridView) :
-        levelMode_(true),
-        levelGridView_(std::make_unique<LevelGridView>(gridView)),
-        levelElementMapper_(gridView),
-        leafFaceMapper_(gridView) {
-
-        init(gridView);
-    }
-
-    BodyHelper(const LeafGridView& gridView) :
-        levelMode_(false),
-        leafGridView_(std::make_unique<LeafGridView>(gridView)),
-        leafElementMapper_(gridView),
-        leafFaceMapper_(gridView) {
-
-        init(gridView);
-    }
-
-    const auto& gridView() const {
-        return (levelMode_ ? levelGridView_ : leafGridView_);
-    }
-
-    const auto& elementMapper() const {
-        return (levelMode_ ? levelElementMapper_ : leafElementMapper_);
-    }
-
-    const auto& faceMapper() const {
-        return (levelMode_ ? levelFaceMapper_ : leafFaceMapper_);
-    }
-
-    const auto& vertexInElements() const {
-        return vertexInElements_;
-    }
-
-    const auto& cache() const {
-        return cache_;
-    }
-};
-
-
-/**
- *  constructs BitSetVector whose entries are
- *      true,   if vertex is outside of patch or part of patch boundary
- *      false,  if vertex is in interior of patch
- */
-template <class LevelContactNetwork>
-class SupportPatchFactory
-{
-public:
-    using Patch = Dune::BitSetVector<1>;
-
-private:
-    static const int dim = LevelContactNetwork::dimension; //TODO
-    using ctype = typename LevelContactNetwork::ctype;
-
-    using BodyHelper = BodyHelper<LevelContactNetwork>;
-    //using Vertex = typename GridType::template Codim<dim>::Entity;
-
-    using Element = typename LevelContactNetwork::DeformedGridType::template Codim<0>::Entity;
-    using BodyElement = BodyElement<Element>;
-    using FiniteElementCache = Dune::PQkLocalFiniteElementCache<ctype, ctype, dim, 1>; // P1 finite element cache
-
-    const size_t nBodies_;
-
-    const LevelContactNetwork& coarseContactNetwork_;
-    const LevelContactNetwork& fineContactNetwork_;
-
-    std::vector<std::unique_ptr<BodyHelper>> bodyHelper_;
-
-    std::map<size_t, std::vector<BodyElement>> neighborElements_; // map faceID to neighbor elements
-    std::map<size_t, std::vector<size_t>> neighborElementDofs_; // map faceID to neighbor element dofs
-
-    std::vector<size_t> vertexOffSet_;
-    std::vector<size_t> faceOffSet_;
-    std::vector<size_t> elementOffSet_;
-
-    FiniteElementCache cache_;
-
-public:
-    SupportPatchFactory(const LevelContactNetwork& coarseContactNetwork, const LevelContactNetwork& fineContactNetwork) :
-        nBodies_(coarseContactNetwork_.nBodies()),
-        coarseContactNetwork_(coarseContactNetwork),
-        fineContactNetwork_(fineContactNetwork),
-        bodyHelper_(nBodies_),
-        vertexOffSet_(nBodies_),
-        faceOffSet_(nBodies_),
-        elementOffSet_(nBodies_){
-
-        assert(nBodies_ == fineContactNetwork_.nBodies());
-
-        size_t vertexOffSet = 0;
-        size_t faceOffSet = 0;
-        size_t elementOffSet = 0;
-
-        for (size_t i=0; i<nBodies_; i++) {
-            const auto& gridView = coarseContactNetwork_.body(i)->gridView();
-            bodyHelper_[i] = std::make_unique<BodyHelper>(gridView);
-
-            vertexOffSet_[i] = vertexOffSet + gridView.size(dim);
-            vertexOffSet = vertexOffSet_[i];
-
-            faceOffSet_[i] = faceOffSet + gridView.size(1);
-            faceOffSet = faceOffSet_[i];
-
-            elementOffSet_[i] = elementOffSet + gridView.size(0);
-            elementOffSet = elementOffSet_[i];
-        }
-
-        // init boundary mapping/transfer
-        const auto& nBodyAssembler = coarseContactNetwork_.nBodyAssembler();
-        const auto& contactCouplings = nBodyAssembler.getContactCouplings();
-
-        for (size_t i=0; i<contactCouplings.size(); i++) {
-            const auto& coupling = nBodyAssembler.getCoupling(i);
-            const auto& contactCoupling = contactCouplings[i];
-
-            const size_t nmBody = coupling.gridIdx_[0];
-            const size_t mBody = coupling.gridIdx_[1];
-
-            const auto& nmBoundary = contactCoupling.nonmortarBoundary();
-            const auto& mBoundary = contactCoupling.mortarBoundary();
-
-            const auto& nmIndexSet = nonmortarBoundary.gridView().indexSet();
-            const auto& mIndexSet = mortarBoundary.gridView().indexSet();
-
-            for (const auto& rIs : intersections(*contactCoupling.getGlue())) {
-                const auto& inside = rIs.inside();
-                const auto& outside = rIs.outside();
-
-                int nmFaceIdx = nmIndexSet.subIndex(inside, rIs.indexInInside(), 1);
-                int mFaceIdx = mIndexSet.subIndex(outside, rIs.indexInOutside(), 1);
-
-                BodyElement nmBodyElement(nmBody, inside);
-                BodyElement mBodyElement(mBody, outside);
-
-                neighborElements_[nmFaceIdx].emplace_back(mBodyElement);
-                neighborElements_[mFaceIdx].emplace_back(nmBodyElement);
-
-                std::set<size_t> dofs;
-                computeIntersectionDofs(nmIndexSet, rIs, dofs);
-                neighborElementDofs_[nmFaceIdx].insert(neighborElementDofs_[nmFaceIdx].end(), dofs.begin(), dofs.end());
-
-                computeIntersectionDofs(mIndexSet, rIs, dofs, false);
-                neighborElementDofs_[mFaceIdx].insert(neighborElementDofs_[mFaceIdx].end(), dofs.begin(), dofs.end());
-            }
-        }
-
-        // neighborElementDofs_ contains dofs of connected intersections that are neighbors to a face given by faceID,
-        // boundary dofs are contained once, interior dofs multiple times
-        // task: remove boundary dofs and redundant multiples of interior dofs
-        for (auto& it : neighborElementDofs_) {
-            auto& dofs = it.second;
-
-            std::sort(dofs.begin(), dofs.end());
-            auto& dof = dofs.begin();
-            while (dof != dofs.end()) {
-                auto next = dof;
-                if (*dof != *(++next))
-                    dof = dofs.erase(dof);
-            }
-            dofs.erase(std::unique(dofs.begin(), dofs.end()), dofs.end());
-        }
-    }
-
-    void build(const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const int patchDepth = 0) {
-        BodyElement seedElement(bodyID, coarseElement);
-
-        // construct coarse patch
-        std::vector<BodyElement> patchElements;
-        patchElements.emplace_back(seedElement);
-
-        std::set<size_t> visitedElements;
-        visitedElements.insert(elementIndex(seedElement));
-
-        std::set<size_t> patchVertices;
-        patchVertices.insert(vertexIndex(bodyID, coarseElement, localVertex));
-
-        std::queue<BodyElement> patchSeeds;
-        patchSeeds.push(seedElement);
-
-        for (size_t depth=0; depth<=patchDepth; depth++) {
-            std::vector<BodyElement> nextSeeds;
-            std::set<size_t> newPatchVertices;
-
-            while (!patchSeeds.empty()) {
-                const auto& patchSeed = patchSeeds.front();
-                patchSeeds.pop();
-
-                size_t elemIdx = elementIndex(patchSeed);
-
-                if (visitedElements.count(elemIdx))
-                    continue;
-
-                visitedElements.insert(elemIdx);
-
-                size_t bodyIdx = patchSeed.bodyID();
-                const auto& elem = patchSeed.element();
-                const auto& gridView = bodyHelper_[bodyIdx]->gridView();
-
-                for (auto& it : intersections(gridView, elem)) {
-                    if (isPatchIntersection(gridView.indexSet(), it, patchVertices, newPatchVertices)) {
-                        if (it.neighbor()) {
-                            BodyElement neighbor(bodyIdx, it.outside());
-
-                            if (visitedElements.count(elementIndex(neighbor)))
-                                continue;
-
-                            patchElements.emplace_back(neighbor);
-                            patchSeeds.push(neighbor);
-                        } else {
-                            size_t faceIdx = faceIndex(bodyIdx, it);
-
-                            if (neighborElements_.count(faceIdx)) {
-                                const auto& neighbors = neighborElements_[faceIdx];
-                                for (size_t i=0; i<neighbors.size(); i++) {
-                                    const auto& neighbor = neighbors[i];
-
-                                    if (visitedElements.count(elementIndex(neighbor)))
-                                        continue;
-
-                                    patchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
-                                    patchElements.emplace_back(neighbor);
-                                    patchSeeds.push(neighbor);
-                                }
-                            }
-                        }
-                    } else {
-                        if (it.neighbor()) {
-                            BodyElement neighbor(bodyIdx, it.outside());
-
-                            if (visitedElements.count(elementIndex(neighbor)))
-                                continue;
-
-                            nextSeeds.emplace_back(neighbor);
-                        } else {
-                            size_t faceIdx = faceIndex(bodyIdx, it);
-
-                            if (neighborElements_.count(faceIdx)) {
-                                const auto& neighbors = neighborElements_[faceIdx];
-                                for (size_t i=0; i<neighbors.size(); i++) {
-                                    const auto& neighbor = neighbors[i];
-
-                                    if (visitedElements.count(elementIndex(neighbor)))
-                                        continue;
-
-                                    newPatchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
-                                    nextSeeds.emplace_back(neighbor);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            for (size_t i=0; i<nextSeeds.size(); i++) {
-                patchSeeds.push(nextSeeds[i]);
-            }
-            patchVertices.insert(newPatchVertices.begin(), newPatchVertices.end());
-        }
-
-        // construct fine patch
-        for (size_t i=0; i<patchElements.size(); ++i) {
-            addFinePatchElements(patchElements[i], visitedElements, patchDofs);
-        }
-    }
-
-private:
-    template <class IndexSet, class Intersection>
-    bool isPatchIntersection(const IndexSet& indexSet, const Intersection& is, const std::set<size_t>& patchVertices, std::set<size_t>& newPatchVertices) {
-        std::set<size_t> intersectionDofs;
-        computeIntersectionDofs(indexSet, is, intersectionDofs);
-
-        for (auto& dof : intersectionDofs) {
-            if (patchVertices.count(dof)) {
-                newPatchVertices.insert(intersectionDofs.begin(), intersectionDofs.end());
-                return true;
-            }
-        }
-        return false;
-    }
-
-    size_t vertexIndex(const size_t bodyID, const Element& elem, const size_t localVertex) const {
-        const auto& gridView = bodyHelper_[bodyID]->gridView();
-
-        auto localIdx = cache_.get(elem.type()).localCoefficients().localKey(localVertex).subEntity();
-        return vertexOffSet_[bodyID] + gridView.indexSet().subIndex(elem, localIdx, dim);
-    }
-
-    template <class Intersection>
-    size_t faceIndex(const size_t bodyID, const Intersection& is) const {
-        const auto& gridView = bodyHelper_[bodyID]->gridView();
-        return faceOffSet_[bodyID] + gridView.indexSet().subIndex(is.inside(), is.indexInInside(), 1);
-    }
-
-    size_t elementIndex(const BodyElement& bodyElem) const {
-        const auto& gridView = bodyHelper_[bodyElem.bodyID()]->gridView();
-        return elementOffSet_[bodyElem.bodyID()] + gridView.indexSet().index(bodyElem.element());
-    }
-
-    template <class Intersection>
-    bool containsInsideSubentity(const Element& elem, const Intersection& intersection, int subEntity, int codim) {
-	    return ReferenceElementHelper<double, dim>::subEntityContainsSubEntity(elem.type(), intersection.indexInInside(), 1, subEntity, codim);
-	}
-      
-    void addFinePatchElements(const BodyElement& coarseElem, const std::set<size_t>& coarsePatch, Patch& patchDofs) {
-        using HierarchicLevelIteratorType = HierarchicLevelIterator<typename LevelContactNetwork::DeformedGridType>;
-
-        const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID())->gridView().grid();
-        const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID())->gridView().level();
-
-        HierarchicLevelIteratorType endHierIt(grid, coarseElem.element(), HierarchicLevelIteratorType::PositionFlag::end, fineLevel);
-        HierarchicLevelIteratorType hierIt(grid, coarseElem.element(), HierarchicLevelIteratorType::PositionFlag::begin, fineLevel);
-        for (; hierIt!=endHierIt; ++hierIt) {
-            const Element& fineElem = *hierIt;
-            addLocalDofs(coarseElem, fineElem, coarsePatch, patchDofs);
-	    }
-	}	  
-	
-    void addLocalDofs(const BodyElement& coarseElem, const Element& fineElem, const std::set<size_t>& coarsePatch, Patch& patchDofs) {
-	    // insert local dofs
-        const auto& lfe = cache_.get(fineElem.type());
-        const auto& gridView = fineContactNetwork_.body(coarseElem.bodyID())->gridView();
-        const auto& indexSet = gridView.indexSet();
-
-        for (size_t i=0; i<lfe.localBasis().size(); ++i) {
-            auto localIdx = lfe.localCoefficients().localKey(i).subEntity();
-            int dofIndex = indexSet.subIndex(fineElem, localIdx, dim);
-            patchDofs[dofIndex][0] = false;
-	    }
-	    
-        const auto coarseLevel = coarseElem.element().level();
-
-	    // search for parts of the global and inner boundary 
-        for (const auto& is : intersections(gridView, fineElem)) {
-            bool isPatchBoundary = false;
-
-            if (is.neighbor()) {
-                auto outsideFather = is.outside();
-		    
-                while (outsideFather.level()>coarseLevel) {
-                    outsideFather = outsideFather.father();
-                }
-		    
-                BodyElement outside(coarseElem.bodyID(), outsideFather);
-
-                if (!coarsePatch.count(elementIndex(outside))) {
-                    isPatchBoundary = true;
-                }
-            } else {
-                isPatchBoundary = true;
-
-                auto outsideFather = is.outside();
-
-                while (outsideFather.level()>coarseLevel) {
-                    outsideFather = outsideFather.father();
-                }
-
-                BodyElement outside(coarseElem.bodyID(), outsideFather);
-
-                size_t faceIdx = faceIndex(coarseElem.bodyID(), is);
-
-                if (neighborElements_.count(faceIdx)) {
-                    const auto& neighbors = neighborElements_[faceIdx];
-                    for (size_t i=0; i<neighbors.size(); i++) {
-                        const auto& neighbor = neighbors[i];
-                        
-                        if (coarsePatch.count(elementIndex(outside))) {
-                            isPatchBoundary = false;
-                        }
-                    }
-
-                }
-            }
-		
-            if (isPatchBoundary) {
-                const auto& localCoefficients = cache_.get(fineElem.type()).localCoefficients();
-
-                for (size_t i=0; i<localCoefficients.size(); i++) {
-                    auto entity = localCoefficients.localKey(i).subEntity();
-                    auto codim  = localCoefficients.localKey(i).codim();
-
-                    if (containsInsideSubentity(fineElem, is, entity, codim)) {
-                        int dofIndex = indexSet.subIndex(fineElem, entity, dim);
-                        patchDofs[dofIndex][0] = true;
-                    }
-                }
-            }
-	    }	
-	}
-
-
-    template <class IndexSet, class Intersection>
-    void computeIntersectionDofs(const IndexSet& idxSet, const Intersection& intersection, std::set<size_t>& intersectionDofs, bool inside = true) {
-        intersectionDofs.clear();
-
-        Element* elem;
-        size_t intersectionIndex;
-
-        if (inside) {
-            elem = &intersection.inside();
-            intersectionIndex = intersection.indexInInside();
-        } else {
-            elem = &intersection.outside();
-            intersectionIndex = intersection.indexInOutside();
-        }
-
-        const int dimElement = Element::dimension;
-        const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(elem->type());
-
-        for (int i=0; i<refElement.size(intersectionIndex, 1, dimElement); i++) {
-            size_t idxInElement = refElement.subEntity(intersectionIndex, 1, i, dimElement);
-            size_t globalIdx = idxSet.subIndex(*elem, idxInElement, dimElement);
-
-            intersectionDofs.insert(globalIdx);
-        }
-    }
-};
-#endif
diff --git a/src/tests/gridgluefrictiontest.cc b/src/tests/gridgluefrictiontest.cc
index d31f58d3490ba44c1012a520af030400f1787ef3..6ac022ea9ed5a7867e7f219ac9e422c42facf5f5 100644
--- a/src/tests/gridgluefrictiontest.cc
+++ b/src/tests/gridgluefrictiontest.cc
@@ -334,6 +334,25 @@ int main(int argc, char *argv[]) { try {
 
     print(postprocessed, "postprocessed: ");
 
+    const auto& contactCouplings = nBodyAssembler.getContactCouplings();
+    const auto& contactCoupling = contactCouplings[0];
+    const auto& glue = *contactCoupling->getGlue();
+
+    size_t isCount = 0;
+    for (const auto& rIs : intersections(glue)) {
+        std::cout << "intersection id: " << isCount
+                  << " insideElement: " << gridView0.indexSet().index(rIs.inside())
+                  << " outsideElement: " << gridView1.indexSet().index(rIs.outside()) << std::endl;
+        isCount++;
+    }
+
+    for (size_t i=0; i<isCount; i++) {
+        const auto& is = glue.getIntersection(i);
+        std::cout << "intersection id: " << i
+                  << " insideElement: " << gridView0.indexSet().index(is.inside())
+                  << " outsideElement: " << gridView1.indexSet().index(is.outside()) << std::endl;
+    }
+
    /* using DualBasis = ;
     DualBasis dualBasis;
     BoundaryFunctionalAssembler<DualBasis> bAssembler(dualBasis, nonmortarBoundary);