diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7c012be4a60057d74a9d619b34f13b8f3be5ce80..0cfcc7081672871f755ca84b6d7f8d0e39f2e082 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_subdirectory("tests")
+add_subdirectory("spatial-solving")
 
 set(SW_SOURCE_FILES
   assemblers.cc
diff --git a/src/data-structures/levelcontactnetwork.hh b/src/data-structures/levelcontactnetwork.hh
index 97792f2ee6dcd3ff2483e81e1eba0d053a1b3322..68bb716aaac8391fdb2c17798a512c66c91549d7 100644
--- a/src/data-structures/levelcontactnetwork.hh
+++ b/src/data-structures/levelcontactnetwork.hh
@@ -25,6 +25,7 @@
 
 template <class GridType, int dimension> class LevelContactNetwork {
     private:
+        //static const int dimension = typename GridType::dimension;
         using Vector = Dune::BlockVector<Dune::FieldVector<double, dimension>>;
 
     public:
diff --git a/src/data-structures/program_state.hh b/src/data-structures/program_state.hh
index 1eceb99a8ebdbbd5424d25146e24ce8935dd882d..bab650b970bdd1dffb466e5d648fe0cd3081a4f7 100644
--- a/src/data-structures/program_state.hh
+++ b/src/data-structures/program_state.hh
@@ -16,7 +16,6 @@
 #include "levelcontactnetwork.hh"
 #include "matrices.hh"
 #include "../spatial-solving/solverfactory.hh"
-#include "../spatial-solving/solverfactory_old.hh"
 #include "../spatial-solving/tnnmg/functional.hh"
 #include "../spatial-solving/tnnmg/zerononlinearity.hh"
 #include "../utils/debugutils.hh"
diff --git a/src/multi-body-problem.cc b/src/multi-body-problem.cc
index 5790cc65dfe920c95bda26ee52a3b91ce06d7ebb..e20cc637dd7c631136ba0712c78c3fb8ddc58ead 100644
--- a/src/multi-body-problem.cc
+++ b/src/multi-body-problem.cc
@@ -42,8 +42,6 @@
 
 #include <dune/contact/common/deformedcontinuacomplex.hh>
 #include <dune/contact/common/couplingpair.hh>
-#include <dune/contact/assemblers/nbodyassembler.hh>
-//#include <dune/contact/assemblers/dualmortarcoupling.hh>
 #include <dune/contact/projections/normalprojection.hh>
 
 #include <dune/tectonic/geocoordinate.hh>
@@ -73,6 +71,7 @@
 
 #include "spatial-solving/tnnmg/functional.hh"
 #include "spatial-solving/tnnmg/localbisectionsolver.hh"
+#include "spatial-solving/contact/nbodyassembler.hh"
 #include "spatial-solving/solverfactory.hh"
 
 #include "time-stepping/adaptivetimestepper.hh"
diff --git a/src/spatial-solving/CMakeLists.txt b/src/spatial-solving/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1970afe64c1da2c2152ba9de21234515d17472fc
--- /dev/null
+++ b/src/spatial-solving/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory("tnnmg")
+add_subdirectory("contact")
+add_subdirectory("preconditioners")
diff --git a/src/spatial-solving/contact/CMakeLists.txt b/src/spatial-solving/contact/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..05ec76c58ad389b8aac6c0368f6f551825f2ccb3
--- /dev/null
+++ b/src/spatial-solving/contact/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_custom_target(dune-tectonic_spatial-solving_contact_src SOURCES
+  dualmortarcoupling.cc
+  dualmortarcoupling.hh
+  nbodyassembler.cc
+  nbodyassembler.hh
+)
diff --git a/src/spatial-solving/contact/dualmortarcoupling.cc b/src/spatial-solving/contact/dualmortarcoupling.cc
new file mode 100644
index 0000000000000000000000000000000000000000..96ca666c521a49612d334915f26adf359af422fa
--- /dev/null
+++ b/src/spatial-solving/contact/dualmortarcoupling.cc
@@ -0,0 +1,333 @@
+// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set ts=8 sw=4 et sts=4:
+#include <dune/common/exceptions.hh>
+
+#include <dune/istl/matrixindexset.hh>
+#include <dune/istl/io.hh>
+
+#include <dune/geometry/quadraturerules.hh>
+#include <dune/geometry/type.hh>
+#include <dune/geometry/referenceelements.hh>
+
+#include <dune/localfunctions/lagrange/pqkfactory.hh>
+
+
+#include <dune/grid-glue/merging/contactmerge.hh>
+//#include <dune/grid-glue/adapter/gridgluevtkwriter.hh>
+//#include <dune/grid-glue/adapter/gridglueamirawriter.hh>
+
+#include <dune/contact/common/dualbasisadapter.hh>
+#include <dune/matrix-vector/addtodiagonal.hh>
+
+
+template <class field_type, class GridView0, class GridView1>
+void DualMortarCoupling<field_type, GridView0, GridView1>::assembleNonmortarLagrangeMatrix()
+{
+    // Create mapping from the global set of block dofs to the ones on the contact boundary
+    std::vector<int> globalToLocal;
+    nonmortarBoundary_.makeGlobalToLocal(globalToLocal);
+
+    // clear matrix
+    nonmortarLagrangeMatrix_ = Dune::BDMatrix<MatrixBlock>(nonmortarBoundary_.numVertices());
+    nonmortarLagrangeMatrix_ = 0;
+
+    const auto& indexSet = gridView0_.indexSet();
+
+    // loop over all faces of the boundary patch
+    for (const auto& nIt : nonmortarBoundary_) {
+
+        const auto& geometry = nIt.geometry();
+        const field_type numCorners = geometry.corners();
+
+        ctype intElem = geometry.integrationElement(Dune::FieldVector<ctype,dim-1>(0));
+
+        field_type sfI = (numCorners==3) ? intElem/6.0 : intElem/numCorners;
+
+        // turn scalar element mass matrix into vector-valued one
+        // and add element mass matrix to the global matrix
+
+        // Get global node ids
+        const auto& inside = nIt.inside();
+        const auto& refElement = Dune::ReferenceElements<ctype, dim>::general(inside.type());
+
+        // Add localMatrix to nonmortarLagrangeMat
+        for (int i=0; i<refElement.size(nIt.indexInInside(),1,dim); i++) {
+            // we can use subEntity here because we add all indices anyway
+            int v = globalToLocal[indexSet.subIndex(inside,refElement.subEntity(nIt.indexInInside(),1,
+                                                                          i,dim),dim)];
+                Dune::MatrixVector::addToDiagonal(nonmortarLagrangeMatrix_[v][v],sfI);
+        }
+
+    }
+
+}
+
+template <class field_type, class GridView0, class GridView1>
+void DualMortarCoupling<field_type, GridView0, GridView1>::setup()
+{
+    typedef Dune::PQkLocalFiniteElementCache<typename GridType1::ctype, field_type, GridType1::dimension,1> FiniteElementCache1;
+
+    // cache for the dual functions on the boundary
+    using DualCache = Dune::Contact::DualBasisAdapter<GridView0, field_type>;
+
+    using Element0 = typename GridView0::template Codim<0>::Entity;
+    using Element1 = typename GridView1::template Codim<0>::Entity;
+
+    auto desc0 = [&] (const Element0& e, unsigned int face) {
+        return nonmortarBoundary_.contains(e,face);
+    };
+
+    auto desc1 = [&] (const Element1& e, unsigned int face) {
+        return mortarBoundary_.contains(e,face);
+    };
+
+    auto extract0 = std::make_shared<Extractor0>(gridView0_,desc0);
+    auto extract1 = std::make_shared<Extractor1>(gridView1_,desc1);
+
+    if (!gridGlueBackend_)
+        gridGlueBackend_ = std::make_shared< Dune::GridGlue::ContactMerge<dimworld, ctype> >(overlap_);
+    glue_ = std::make_shared<Glue>(extract0, extract1, gridGlueBackend_);
+    auto& glue = *glue_;
+    glue.build();
+
+    std::cout << glue.size() << " remote intersections found." << std::endl;
+    //GridGlueAmiraWriter::write<GlueType>(glue,debugPath_);
+
+    // Restrict the hasObstacle fields to the part of the nonmortar boundary
+    // where we could actually create a contact mapping
+    BoundaryPatch0 boundaryWithMapping(gridView0);
+
+    const auto& indexSet0 = gridView0_.indexSet();
+    const auto& indexSet1 = gridView1_.indexSet();
+
+    ///////////////////////////////////
+    //  reducing nonmortar boundary
+    /////////////////////////////////
+
+    // Get all fine grid boundary segments that are totally covered by the grid-glue segments
+    typedef std::pair<int,int> Pair;
+    std::map<Pair,ctype> coveredArea, fullArea;
+
+    // initialize with area of boundary faces
+    for (const auto& bIt : nonmortarBoundary_) {
+        const Pair p(indexSet0.index(bIt.inside()),bIt.indexInInside());
+        fullArea[p] = bIt.geometry().volume();
+        coveredArea[p] = 0;
+    }
+
+    // sum up the remote intersection areas to find out which are totally covered
+    for (const auto& rIs : intersections(glue))
+        coveredArea[Pair(indexSet0.index(rIs.inside()),rIs.indexInInside())] += rIs.geometry().volume();
+
+    // add all fine grid faces that are totally covered by the contact mapping
+    for (const auto& bIt : nonmortarBoundary_) {
+        const auto& inside = bIt.inside();
+        if(coveredArea[Pair(indexSet0.index(inside),bIt.indexInInside())]/
+            fullArea[Pair(indexSet0.index(inside),bIt.indexInInside())] >= coveredArea_)
+            boundaryWithMapping.addFace(inside, bIt.indexInInside());
+    }
+
+    //writeBoundary(boundaryWithMapping,debugPath_ + "relevantNonmortar");
+
+
+    /** \todo replace by all fine grid segments which are totally covered by the RemoteIntersections. */
+    //for (const auto& rIs : intersections(glue))
+    //    boundaryWithMapping.addFace(rIs.inside(),rIs.indexInInside());
+
+    printf("contact mapping could be built for %d of %d boundary segments.\n",
+           boundaryWithMapping.numFaces(), nonmortarBoundary_.numFaces());
+
+    nonmortarBoundary_ = boundaryWithMapping;
+    mortarBoundary_.setup(gridView1_);
+    for (const auto& rIs : intersections(glue))
+        if (nonmortarBoundary_.contains(rIs.inside(),rIs.indexInInside()))
+            mortarBoundary_.addFace(rIs.outside(),rIs.indexInOutside());
+
+
+    // Assemble the diagonal matrix coupling the nonmortar side with the lagrange multiplyers there
+    assembleNonmortarLagrangeMatrix();
+
+    // The weak obstacle vector
+    weakObstacle_.resize(nonmortarBoundary_.numVertices());
+    weakObstacle_ = 0;
+
+    // ///////////////////////////////////////////////////////////
+    //   Get the occupation structure for the mortar matrix
+    // ///////////////////////////////////////////////////////////
+
+    /** \todo Also restrict mortar indices and don't use the whole grid level. */
+    Dune::MatrixIndexSet mortarIndices(nonmortarBoundary_.numVertices(), grid1_->size(dim));
+
+    // Create mapping from the global set of block dofs to the ones on the contact boundary
+    std::vector<int> globalToLocal;
+    nonmortarBoundary_.makeGlobalToLocal(globalToLocal);
+
+    // loop over all intersections
+    for (const auto& rIs : intersections(glue)) {
+
+        if (!nonmortarBoundary_.contains(rIs.inside(),rIs.indexInInside()))
+            continue;
+
+        const auto& inside = rIs.inside();
+        const auto& outside = rIs.outside();
+
+        const auto& domainRefElement = Dune::ReferenceElements<ctype, dim>::general(inside.type());
+        const auto& targetRefElement = Dune::ReferenceElements<ctype, dim>::general(outside.type());
+
+        int nDomainVertices = domainRefElement.size(dim);
+        int nTargetVertices = targetRefElement.size(dim);
+
+        for (int j=0; j<nDomainVertices; j++) {
+
+            int localDomainIdx = globalToLocal[indexSet0.subIndex(inside,j,dim)];
+
+            // if the vertex is not contained in the restricted contact boundary then dismiss it
+            if (localDomainIdx == -1)
+                continue;
+
+            for (int k=0; k<nTargetVertices; k++) {
+                int globalTargetIdx = indexSet1.subIndex(outside,k,dim);
+                if (!mortarBoundary_.containsVertex(globalTargetIdx))
+                    continue;
+
+                mortarIndices.add(localDomainIdx, globalTargetIdx);
+            }
+        }
+    }
+
+    mortarIndices.exportIdx(mortarLagrangeMatrix_);
+
+    // Clear it
+    mortarLagrangeMatrix_ = 0;
+
+
+    //cache of local bases
+    FiniteElementCache1 cache1;
+
+    std::unique_ptr<DualCache> dualCache;
+    dualCache = std::make_unique< Dune::Contact::DualBasisAdapterGlobal<GridView0, field_type> >();
+
+    std::vector<Dune::FieldVector<ctype,dim> > avNormals;
+    avNormals = nonmortarBoundary_.getNormals();
+
+    // loop over all intersections and compute the matrix entries
+    for (const auto& rIs : intersections(glue)) {
+
+
+        const auto& inside = rIs.inside();
+
+        if (!nonmortarBoundary_.contains(rIs.inside(),rIs.indexInInside()))
+            continue;
+
+        const auto& outside = rIs.outside();
+
+        // types of the elements supporting the boundary segments in question
+        Dune::GeometryType nonmortarEType = inside.type();
+        Dune::GeometryType mortarEType    = outside.type();
+
+        const auto& domainRefElement = Dune::ReferenceElements<ctype, dim>::general(nonmortarEType);
+
+        const auto& targetRefElement = Dune::ReferenceElements<ctype, dim>::general(mortarEType);
+
+        int noOfMortarVec = targetRefElement.size(dim);
+
+        Dune::GeometryType nmFaceType = domainRefElement.type(rIs.indexInInside(),1);
+        Dune::GeometryType mFaceType  = targetRefElement.type(rIs.indexInOutside(),1);
+
+        // Select a quadrature rule
+        // 2 in 2d and for integration over triangles in 3d.  If one (or both) of the two faces involved
+        // are quadrilaterals, then the quad order has to be risen to 3 (4).
+        int quadOrder = 2 + (!nmFaceType.isSimplex()) + (!mFaceType.isSimplex());
+        const auto& quadRule = Dune::QuadratureRules<ctype, dim-1>::rule(rIs.type(), quadOrder);
+
+        //const typename FiniteElementCache0::FiniteElementType& nonmortarFiniteElement = cache0.get(nonmortarEType);
+        const auto& mortarFiniteElement = cache1.get(mortarEType);
+        dualCache->bind(inside, rIs.indexInInside());
+
+        std::vector<Dune::FieldVector<field_type,1> > mortarQuadValues, dualQuadValues;
+
+        const auto& rGeom = rIs.geometry();
+        const auto& rGeomOutside = rIs.geometryOutside();
+        const auto& rGeomInInside = rIs.geometryInInside();
+        const auto& rGeomInOutside = rIs.geometryInOutside();
+
+        int nNonmortarFaceNodes = domainRefElement.size(rIs.indexInInside(),1,dim);
+        std::vector<int> nonmortarFaceNodes;
+        for (int i=0; i<nNonmortarFaceNodes; i++) {
+          int faceIdxi = domainRefElement.subEntity(rIs.indexInInside(), 1, i, dim);
+          nonmortarFaceNodes.push_back(faceIdxi);
+        }
+
+        for (const auto& quadPt : quadRule) {
+
+            // compute integration element of overlap
+            ctype integrationElement = rGeom.integrationElement(quadPt.position());
+
+            // quadrature point positions on the reference element
+            Dune::FieldVector<ctype,dim> nonmortarQuadPos = rGeomInInside.global(quadPt.position());
+            Dune::FieldVector<ctype,dim> mortarQuadPos    = rGeomInOutside.global(quadPt.position());
+
+            // The current quadrature point in world coordinates
+            Dune::FieldVector<field_type,dim> nonmortarQpWorld = rGeom.global(quadPt.position());
+            Dune::FieldVector<field_type,dim> mortarQpWorld    = rGeomOutside.global(quadPt.position());;
+
+            // the gap direction (normal * gapValue)
+            Dune::FieldVector<field_type,dim> gapVector = mortarQpWorld  - nonmortarQpWorld;
+
+            //evaluate all shapefunctions at the quadrature point
+            //nonmortarFiniteElement.localBasis().evaluateFunction(nonmortarQuadPos,nonmortarQuadValues);
+            mortarFiniteElement.localBasis().evaluateFunction(mortarQuadPos,mortarQuadValues);
+            dualCache->evaluateFunction(nonmortarQuadPos,dualQuadValues);
+
+            // loop over all Lagrange multiplier shape functions
+            for (int j=0; j<nNonmortarFaceNodes; j++) {
+
+                int globalDomainIdx = indexSet0.subIndex(inside,nonmortarFaceNodes[j],dim);
+                int rowIdx = globalToLocal[globalDomainIdx];
+
+                weakObstacle_[rowIdx][0] += integrationElement * quadPt.weight()
+                    * dualQuadValues[nonmortarFaceNodes[j]] * (gapVector*avNormals[globalDomainIdx]);
+
+                // loop over all mortar shape functions
+                for (int k=0; k<noOfMortarVec; k++) {
+
+                    int colIdx  = indexSet1.subIndex(outside, k, dim);
+                    if (!mortarBoundary_.containsVertex(colIdx))
+                        continue;
+
+                    // Integrate over the product of two shape functions
+                    field_type mortarEntry =  integrationElement* quadPt.weight()* dualQuadValues[nonmortarFaceNodes[j]]* mortarQuadValues[k];
+
+                    Dune::MatrixVector::addToDiagonal(mortarLagrangeMatrix_[rowIdx][colIdx], mortarEntry);
+
+                }
+
+            }
+
+        }
+
+    }
+
+    // ///////////////////////////////////////
+    //    Compute M = D^{-1} \hat{M}
+    // ///////////////////////////////////////
+
+    Dune::BCRSMatrix<MatrixBlock>& M  = mortarLagrangeMatrix_;
+    Dune::BDMatrix<MatrixBlock>& D    = nonmortarLagrangeMatrix_;
+
+    // First compute D^{-1}
+    D.invert();
+
+    // Then the matrix product D^{-1} \hat{M}
+    for (auto rowIt = M.begin(); rowIt != M.end(); ++rowIt) {
+        const auto rowIndex = rowIt.index();
+        for (auto& entry : *rowIt)
+            entry.leftmultiply(D[rowIndex][rowIndex]);
+    }
+
+    // weakObstacles in transformed basis = D^{-1}*weakObstacle_
+    for(size_t rowIdx=0; rowIdx<weakObstacle_.size(); rowIdx++)
+        weakObstacle_[rowIdx] *= D[rowIdx][rowIdx][0][0];
+
+    gridGlueBackend_->clear();
+}
diff --git a/src/spatial-solving/contact/dualmortarcoupling.hh b/src/spatial-solving/contact/dualmortarcoupling.hh
new file mode 100644
index 0000000000000000000000000000000000000000..90bc49dc759418d2f596a17ec75bc05a8df6b7cf
--- /dev/null
+++ b/src/spatial-solving/contact/dualmortarcoupling.hh
@@ -0,0 +1,199 @@
+// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set ts=8 sw=4 et sts=4:
+#ifndef DUNE_CONTACT_ASSEMBLERS_DUAL_MORTAR_COUPLING_HH
+#define DUNE_CONTACT_ASSEMBLERS_DUAL_MORTAR_COUPLING_HH
+
+#include <memory>
+
+#include <dune/istl/bcrsmatrix.hh>
+#include <dune/istl/bdmatrix.hh>
+#include <dune/istl/bvector.hh>
+
+#include <dune/fufem/boundarypatch.hh>
+#include <dune/fufem/boundarypatchprolongator.hh>
+
+#include <dune/grid-glue/gridglue.hh>
+#include <dune/grid-glue/extractors/codim1extractor.hh>
+#include <dune/grid-glue/merging/merger.hh>
+
+
+/** \brief Extension of Dune::Contact::DualMortarCoupling that works on
+ *         any GridView (not just LeafGridView) and allows crosspoints.
+ *
+ *         Assembles the transfer operator for two-body contact
+ */
+template<class field_type, class GridView0, class GridView1=GridView0>
+class DualMortarCoupling {
+
+    // /////////////////////
+    // private types
+    // /////////////////////
+
+    enum {dim = GridView0::dimension};
+
+    enum {dimworld = GridView0::dimensionworld};
+
+  protected:
+    using MatrixBlock = Dune::FieldMatrix<field_type, dim, dim>;
+    using MatrixType = Dune::BCRSMatrix<MatrixBlock>;
+    using ObstacleVector = Dune::BlockVector<Dune::FieldVector<field_type, 1> >;
+
+    using ctype = typename GridView0::ctype;
+
+    using GridType0 = typename GridView0::Grid;
+    using GridType1 = typename GridView1::Grid;
+
+    using BoundaryPatch0 = BoundaryPatch<GridView0>;
+    using BoundaryPatch1 = BoundaryPatch<GridView1>;
+
+    using LevelBoundaryPatch0 = BoundaryPatch<typename GridType0::LevelGridView>;
+    using LevelBoundaryPatch1 = BoundaryPatch<typename GridType1::LevelGridView>;
+
+    using Extractor0 = Dune::GridGlue::Codim1Extractor<GridView0>;
+    using Extractor1 = Dune::GridGlue::Codim1Extractor<GridView1>;
+
+public:
+
+    using Glue = Dune::GridGlue::GridGlue<Extractor0, Extractor1>;
+
+    DualMortarCoupling(field_type overlap = 1e-2, field_type coveredArea = 1.0 - 1e-2)
+        : overlap_(overlap), gridGlueBackend_(nullptr), coveredArea_(coveredArea)
+    {}
+
+    DualMortarCoupling(GridView0&& gridView0, GridView0&& gridView1,
+                       field_type overlap = 1e-2, field_type coveredArea = 1.0 - 1e-2)
+        : overlap_(overlap), gridGlueBackend_(nullptr), coveredArea_(coveredArea)
+    {
+        setGrids(gridView0, gridView1);
+    }
+
+    virtual ~DualMortarCoupling() {
+        /* Nothing. */
+    }
+
+    /** \brief Sets up the contact coupling operator on the grid leaf level */
+    virtual void setup();
+
+    /** \brief Assemble nonmortar matrix on the leaf level. */
+    void assembleNonmortarLagrangeMatrix();
+
+    /** \brief Get the dual mortar coupling matrix of the leaf level. */
+    virtual const MatrixType& mortarLagrangeMatrix() const {
+        return mortarLagrangeMatrix_;
+    }
+
+    /** \brief Get the dual mortar coupling matrix of the leaf level. */
+    virtual MatrixType& mortarLagrangeMatrix() {
+        return mortarLagrangeMatrix_;
+    }
+
+    /** \brief Get the non-mortar matrix. */
+    const BDMatrix<MatrixBlock>& nonmortarLagrangeMatrix() const {
+        return nonmortarLagrangeMatrix_;
+    }
+
+    /** \brief Setup leaf nonmortar and mortar patches. */
+    /*virtual void setupContactPatch(const LevelBoundaryPatch0& coarseNonmortar,
+                           const LevelBoundaryPatch1& coarseMortar) {
+
+        BoundaryPatchProlongator<GridType0>::prolong(coarseNonmortar,nonmortarBoundary_);
+        BoundaryPatchProlongator<GridType1>::prolong(coarseMortar,mortarBoundary_);
+    }*/
+
+    /** \brief Return the nonmortar boundary. */
+    const BoundaryPatch0& nonmortarBoundary() const {
+        return nonmortarBoundary_;
+    }
+
+    /** \brief Return the mortar boundary. */
+    const BoundaryPatch1& mortarBoundary() const {
+        return mortarBoundary_;
+    }
+
+    /** \brief Set the non-mortar and mortar grid. */
+    void setGrids(GridView0&& gridView0, GridView1&& gridView1) {
+        gridView0_ = std::forward<GridView0>(gridView0);
+        gridView1_ = std::forward<GridView1>(gridView1);
+
+        grid0_ = &gridView0_.grid();
+        grid1_ = &gridView1_.grid();
+    }
+
+    /** \brief Get non-mortar grid. */
+    const GridType0* getGrid0() const {
+        return grid0_;
+    }
+
+    /** \brief Get mortar grid. */
+    const GridType1* getGrid1() const {
+        return grid1_;
+    }
+
+    /** \brief Set the percentage of covered area each face must at least have
+     *         by the grid-glue projection.
+     */
+    void setCoveredArea(field_type coveredArea) {
+        coveredArea_ = coveredArea;
+    }
+
+    void setOverlap(field_type overlap) {
+        overlap_ = overlap;
+    }
+
+    /** \brief Get the GridGlue. */
+    std::shared_ptr<Glue> getGlue() {
+        return glue_;
+    }
+
+    const ObstacleVector& getWeakObstacle() const {
+        return weakObstacle_;
+    }
+
+
+    // /////////////////////////////////////////////
+    //   Data members
+    // /////////////////////////////////////////////
+private:
+    /** \brief The two grids involved in the two-body contact problem. */
+    const GridView0& gridView0_;
+    const GridView1& gridView1_;
+
+    const GridType0* grid0_;
+    const GridType1* grid1_;
+
+    /** \brief For each dof a bit specifying whether the dof carries an obstacle or not. */
+    BoundaryPatch0 nonmortarBoundary_;
+
+    /** \brief The mortar boundary. */
+    BoundaryPatch1 mortarBoundary_;
+
+    /** \brief The matrix coupling mortar side and Lagrange multipliers. */
+    MatrixType mortarLagrangeMatrix_;
+
+    /** \brief The diagonal matrix coupling nonmortar side and Lagrange multipliers */
+    Dune::BDMatrix<MatrixBlock> nonmortarLagrangeMatrix_;
+
+    /** \brief The weak obstacles. */
+    ObstacleVector weakObstacle_;
+
+    /** \brief Allow some small penetration of the bodies. */
+    field_type overlap_;
+
+    /** \brief A grid-glue merger. If this is not set ContactMerge is used. */
+    std::shared_ptr< Dune::GridGlue::Merger<field_type,dim-1,dim-1,dim> > gridGlueBackend_;
+
+    // Path where to write the merged grids and the reduced contact boundaries
+    //std::string debugPath_;
+
+    std::shared_ptr<Glue> glue_;
+
+    /** \brief Dismiss all faces that are not at least covered by the grid-glue projection for this
+     *         much percentage ranging between one - for total coverage and zero for taking all faces.
+     */
+    field_type coveredArea_;
+};
+
+
+#include "dualmortarcoupling.cc"
+
+#endif
diff --git a/src/spatial-solving/contact/nbodyassembler.cc b/src/spatial-solving/contact/nbodyassembler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d8ee25a45d13da8fdaa6f5810937c09631388b64
--- /dev/null
+++ b/src/spatial-solving/contact/nbodyassembler.cc
@@ -0,0 +1,519 @@
+// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set ts=8 sw=4 et sts=4:
+#include <memory>
+
+#include <dune/istl/preconditioners.hh>
+#include <dune/istl/solvers.hh>
+#include <dune/matrix-vector/transpose.hh>
+#include <dune/matrix-vector/blockmatrixview.hh>
+
+#include <dune/fufem/boundarypatchprolongator.hh>
+#include <dune/contact/projections/normalprojection.hh>
+
+namespace Dune {
+namespace Contact {
+
+template <class GridType, class VectorType>
+void NBodyAssembler<GridType, VectorType>::assembleTransferOperator()
+{
+
+    // /////////////////////////////////////////////////////////////////
+    //   Check if contact data is present
+    // /////////////////////////////////////////////////////////////////
+
+    for (int i=0; i<nCouplings(); i++) {
+
+
+         if (!coupling_[i].obsPatch_)
+             DUNE_THROW(Dune::Exception, "You have to supply a nonmortar patch for the " << i << "-th coupling!");
+
+         if (!coupling_[i].mortarPatch_)
+             DUNE_THROW(Dune::Exception, "You have to supply a mortar patch for the " << i << "-th coupling!");
+    }
+
+    // ////////////////////////////////////////////////////
+    //   Set up Mortar element transfer operators
+    // ///////////////////////////////////////////////////
+
+    std::cout<<"Setup mortar transfer operators\n";
+
+    for (size_t i=0; i<contactCoupling_.size(); i++) {
+        contactCoupling_[i]->setGrids(*grids_[coupling_[i].gridIdx_[0]],*grids_[coupling_[i].gridIdx_[1]]);
+        contactCoupling_[i]->setupContactPatch(*coupling_[i].patch0(),*coupling_[i].patch1());
+        contactCoupling_[i]->gridGlueBackend_ = coupling_[i].backend();
+        contactCoupling_[i]->setCoveredArea(coveredArea_);
+        contactCoupling_[i]->setup();
+    }
+
+    // setup Householder reflections
+    assembleHouseholderReflections();
+
+    // compute the mortar transformation matrix
+    computeTransformationMatrix();
+}
+
+template <class GridType, class VectorType>
+void NBodyAssembler<GridType, VectorType>::assembleHouseholderReflections()
+{
+    // //////////////////////////////////////////////////////////////////
+    //   Compute local coordinate systems for the dofs with obstacles
+    // //////////////////////////////////////////////////////////////////
+
+    std::vector<std::vector<MatrixBlock> > coordinateSystems(nCouplings());
+
+    for (int i=0; i<nCouplings(); i++) {
+
+        double dist = coupling_[i].obsDistance_;
+        auto projection = coupling_[i].projection();
+
+        if (!projection)
+            DUNE_THROW(Dune::Exception, "You have to supply a contact projection for the " << i << "-th coupling!");
+
+        std::vector<Dune::FieldVector<field_type,dim> > directions;
+
+        const auto& nonmortarBoundary = contactCoupling_[i]->nonmortarBoundary();
+        const auto& mortarBoundary    = contactCoupling_[i]->mortarBoundary();
+
+        projection->project(nonmortarBoundary, mortarBoundary,dist);
+        projection->getObstacleDirections(directions);
+
+        this->computeLocalCoordinateSystems(nonmortarBoundary,coordinateSystems[i], directions);
+    }
+
+    // ///////////////////////////////////////////////////////////////
+    // Combine the coordinate systems for each grid to one long array
+    // ///////////////////////////////////////////////////////////////
+    this->localCoordSystems_.resize(numDofs());
+
+    // initialise with identity
+    Dune::ScaledIdentityMatrix<field_type,dim> id(1);
+    for (size_t i=0; i<this->localCoordSystems_.size(); i++)
+        this->localCoordSystems_[i] = id;
+
+    for (int j=0; j<nCouplings(); j++) {
+
+        int grid0Idx = coupling_[j].gridIdx_[0];
+
+        // compute offset
+        int idx = 0;
+        for (int k=0;k<grid0Idx;k++)
+            idx += grids_[k]->size(dim);
+
+        const auto& nonmortarBoundary = contactCoupling_[j]->nonmortarBoundary();
+
+        // if a body is non-mortar more then once, one has to be careful with not overwriting entries
+        for (std::size_t k=0; k<coordinateSystems[j].size(); k++)
+          if(nonmortarBoundary.containsVertex(k))
+            this->localCoordSystems_[idx+k] = coordinateSystems[j][k];
+    }
+}
+
+template <class GridType, class VectorType>
+void NBodyAssembler<GridType, VectorType>::assembleObstacle()
+{
+
+    std::vector<std::vector<int> > globalToLocals(nCouplings());
+    for (std::size_t i = 0; i < globalToLocals.size(); ++i)
+        contactCoupling_[i]->nonmortarBoundary().makeGlobalToLocal(globalToLocals[i]);
+
+    ///////////////////////////////////////
+    //  Set the obstacle values
+    ///////////////////////////////////////
+
+    totalHasObstacle_.resize(numDofs(),false);
+
+    for (int j=0; j<nCouplings(); j++) {
+
+        int grid0Idx = coupling_[j].gridIdx_[0];
+        const auto& nonmortarBoundary = contactCoupling_[j]->nonmortarBoundary();
+
+        // compute offset
+        int idx = 0;
+        for (int k=0;k<grid0Idx;k++)
+            idx += grids_[k]->size(dim);
+
+        for (int k=0; k<grids_[grid0Idx]->size(dim); k++)
+            if (nonmortarBoundary.containsVertex(k))
+                totalHasObstacle_[idx+k] = true;
+    }
+
+    // //////////////////////////////////////////////////////////////////
+    //   Set the obstacle distances
+    // //////////////////////////////////////////////////////////////////
+
+    // Combine the obstacle values for each grid to one long array
+    totalObstacles_.resize(numDofs());
+
+    for (size_t j=0; j<totalObstacles_.size(); j++)
+        totalObstacles_[j].clear();
+
+    // Init the obstacle values
+    for (int i=0; i<nCouplings(); i++) {
+
+        int grid0Idx = coupling_[i].gridIdx_[0];
+
+        // compute offset
+        int idx = 0;
+        for (int k=0;k<grid0Idx;k++)
+            idx += grids_[k]->size(dim);
+
+        // The grids involved in this coupling
+        const auto& indexSet = grids_[grid0Idx]->leafIndexSet();
+
+        // the obstacles are stored using local indices
+        const std::vector<int>& globalToLocal = globalToLocals[i];
+
+        // the weak obstacles
+        const auto& obs = contactCoupling_[i]->weakObstacle_;
+
+        // get strong obstacles, the projection method of the correct level has already been called
+        //std::vector<field_type> obs;
+        //coupling_[i].projection()->getObstacles(obs);
+
+        const auto& leafView = grids_[grid0Idx]->leafGridView();
+
+        for (const auto& v : vertices(leafView)) {
+
+            int vIdx = indexSet.index(v);
+            if (globalToLocal[vIdx]<0)
+                continue;
+
+            // Set the obstacle
+            switch (coupling_[i].type_) {
+
+            case CouplingPairBase::CONTACT:
+                totalObstacles_[idx+vIdx].upper(0) = obs[globalToLocal[vIdx]];
+                break;
+
+            case CouplingPairBase::STICK_SLIP:
+                totalObstacles_[idx+vIdx].lower(0) = 0;
+                totalObstacles_[idx+vIdx].upper(0) = 0;
+                break;
+
+            case CouplingPairBase::GLUE:
+                for (int j=0; j<dim; j++) {
+                    totalObstacles_[idx+vIdx].lower(j) = 0;
+                    totalObstacles_[idx+vIdx].upper(j) = 0;
+                }
+                break;
+
+            case CouplingPairBase::NONE:
+                break;
+            default:
+                DUNE_THROW(Dune::NotImplemented, "Coupling type not handled yet!");
+            }
+        }
+    }
+
+}
+
+template <class GridType, class VectorType>
+void NBodyAssembler<GridType, VectorType>::
+assembleJacobian(const std::vector<const MatrixType*>& submat,
+                 MatrixType& totalMatrix) const
+{
+    // Create a block view of the grand matrix
+    Dune::MatrixVector::BlockMatrixView<MatrixType> blockView(submat);
+
+    int nRows = blockView.nRows();
+    int nCols = blockView.nCols();
+
+    // Create the index set of B \hat{A} B^T
+    Dune::MatrixIndexSet indicesBABT(nRows, nCols);
+
+    for (int i=0; i<nGrids(); i++) {
+
+        for (size_t iRow = 0; iRow<submat[i]->N(); iRow++) {
+
+            const RowType& row = (*submat[i])[iRow];
+
+            // Loop over all columns of the stiffness matrix
+            ConstColumnIterator j    = row.begin();
+            ConstColumnIterator jEnd = row.end();
+
+            for (; j!=jEnd; ++j) {
+
+                ConstColumnIterator k    = BT_[blockView.row(i,iRow)].begin();
+                ConstColumnIterator kEnd = BT_[blockView.row(i,iRow)].end();
+                for (; k!=kEnd; ++k) {
+
+                    ConstColumnIterator l    = BT_[blockView.col(i,j.index())].begin();
+                    ConstColumnIterator lEnd = BT_[blockView.col(i,j.index())].end();
+
+                    for (; l!=lEnd; ++l)
+                        indicesBABT.add(k.index(), l.index());
+
+                }
+
+            }
+
+        }
+
+    }
+
+    // ////////////////////////////////////////////////////////////////////
+    //   Multiply transformation matrix to the global stiffness matrix
+    // ////////////////////////////////////////////////////////////////////
+
+    indicesBABT.exportIdx(totalMatrix);
+    totalMatrix = 0;
+
+    for (int i=0; i<nGrids(); i++) {
+
+        for (size_t iRow = 0; iRow<submat[i]->N(); iRow++) {
+
+            const RowType& row = (*submat[i])[iRow];
+
+            // Loop over all columns of the stiffness matrix
+            ConstColumnIterator j    = row.begin();
+            ConstColumnIterator jEnd = row.end();
+
+            for (; j!=jEnd; ++j) {
+
+                ConstColumnIterator k    = BT_[blockView.row(i,iRow)].begin();
+                ConstColumnIterator kEnd = BT_[blockView.row(i,iRow)].end();
+
+                for (; k!=kEnd; ++k) {
+
+                    ConstColumnIterator l    = BT_[blockView.col(i,j.index())].begin();
+                    ConstColumnIterator lEnd = BT_[blockView.col(i,j.index())].end();
+
+                    for (; l!=lEnd; ++l) {
+
+                        //BABT[k][l] += BT[i][k] * mat_[i][j] * BT[j][l];
+                        MatrixBlock m_ij = *j;
+
+                        MatrixBlock BT_ik_trans;
+                        Dune::MatrixVector::transpose(*k, BT_ik_trans);
+
+                        m_ij.leftmultiply(BT_ik_trans);
+                        m_ij.rightmultiply(*l);
+
+                        totalMatrix[k.index()][l.index()] += m_ij;
+
+                    }
+
+                }
+
+            }
+
+        }
+
+    }
+}
+
+template <class GridType, class VectorType>
+template <class VectorTypeContainer>
+void NBodyAssembler<GridType, VectorType>::
+assembleRightHandSide(const VectorTypeContainer& rhs,
+               VectorType& totalRhs) const
+{
+    // Concatenate the two rhs vectors to a large one
+    VectorType untransformedTotalRhs(BT_.M());
+
+    int idx = 0;
+
+    for (size_t i=0; i<rhs.size(); i++) {
+
+        for (size_t j=0; j<rhs[i].size(); j++)
+            untransformedTotalRhs[idx++] = rhs[i][j];
+
+    }
+
+    if ((int) BT_.M() != idx)
+        DUNE_THROW(Dune::Exception, "assembleRightHandSide: vector size and matrix size don't match!");
+
+    // Transform the basis of the ansatz space
+    totalRhs.resize(untransformedTotalRhs.size());
+    totalRhs = 0;
+    BT_.umtv(untransformedTotalRhs, totalRhs);
+}
+
+
+template <class GridType, class VectorType>
+template <class VectorTypeContainer>
+void NBodyAssembler<GridType, VectorType>::
+postprocess(const VectorType& totalX, VectorTypeContainer& x) const
+{
+    // ///////////////////////////////////////////////////////
+    //   Transform the solution vector to the nodal basis
+    // ///////////////////////////////////////////////////////
+
+    VectorType nodalBasisTotalX(totalX.size());
+    BT_.mv(totalX, nodalBasisTotalX);
+
+
+    // ///////////////////////////////////////////////////////
+    //   Split the total solution vector into the parts
+    //   corresponding to the grids.
+    // ///////////////////////////////////////////////////////
+
+    int idx = 0;
+    for (int i=0; i<nGrids(); i++) {
+
+        x[i].resize(grids_[i]->size(dim));
+
+        for (size_t j=0; j<x[i].size(); j++, idx++)
+            x[i][j] = nodalBasisTotalX[idx];
+    }
+}
+
+template <class GridType, class VectorType>
+template <class VectorTypeContainer>
+void NBodyAssembler<GridType, VectorType>::
+concatenateVectors(const VectorTypeContainer& parts, VectorType& whole)
+{
+    int totalSize = 0;
+    for (size_t i=0; i<parts.size(); i++)
+        totalSize += parts[i].size();
+
+    whole.resize(totalSize);
+
+    int idx = 0;
+    for (size_t i=0; i<parts.size(); i++)
+        for (size_t j=0; j<parts[i].size(); j++)
+            whole[idx++] = parts[i][j];
+
+}
+
+// ////////////////////////////////////////////////////////////////////////////
+//   Turn the initial solutions from the nodal basis to the transformed basis
+// ////////////////////////////////////////////////////////////////////////////
+template <class GridType, class VectorType>
+template <class VectorTypeContainer>
+void NBodyAssembler<GridType, VectorType>::
+nodalToTransformed(const VectorTypeContainer& x,
+                   VectorType& transformedX) const
+{
+    VectorType canonicalTotalX;
+
+    concatenateVectors(x, canonicalTotalX);
+
+    // Make small cg solver
+    Dune::MatrixAdapter<MatrixType,VectorType,VectorType> op(getTransformationMatrix());
+
+    // A preconditioner
+    Dune::SeqILU<MatrixType,VectorType,VectorType> ilu0(getTransformationMatrix(),1.0);
+
+    // A cg solver for nonsymmetric matrices
+    Dune::BiCGSTABSolver<VectorType> bicgstab(op,ilu0,1E-4,100,0);
+
+    // Object storing some statistics about the solving process
+    Dune::InverseOperatorResult statistics;
+
+    // Solve!
+    transformedX = canonicalTotalX;  // seems to be a good initial value
+    bicgstab.apply(transformedX, canonicalTotalX, statistics);
+}
+
+template <class GridType, class VectorType>
+void NBodyAssembler<GridType, VectorType>::
+computeTransformationMatrix()
+{
+    std::cout<<"Setup transformation matrix...";
+    // compute offsets for the different grids
+    std::vector<int> offsets(grids_.size());
+    offsets[0] = 0;
+
+    // P1 elements are hard-wired here
+    size_t k;
+    for (k=0; k<grids_.size()-1; k++)
+        offsets[k+1] = offsets[k] + grids_[k]->size(dim);
+
+    int nRows = offsets[k] + grids_[k]->size(dim);
+    int nCols = nRows;
+
+    // /////////////////////////////////////////////////////////////////
+    //   First create the index structure
+    // /////////////////////////////////////////////////////////////////
+
+    Dune::MatrixIndexSet indicesBT(nRows, nCols);
+
+    // BT_ is the identity plus some off-diagonal elements
+    for (size_t i=0; i<indicesBT.rows(); i++)
+        indicesBT.add(i,i);
+
+    std::vector<std::vector<int> > nonmortarToGlobal(nCouplings());
+    // Enter all the off-diagonal entries
+    for (int i=0; i<nCouplings(); i++) {
+
+        const auto& nonmortarBoundary = contactCoupling_[i]->nonmortarBoundary();
+        // If the contact mapping could not be built at all then skip this coupling
+        if (nonmortarBoundary.numVertices() == 0)
+            continue;
+
+        // The grids involved in this coupling
+        int grid0Idx = coupling_[i].gridIdx_[0];
+        int grid1Idx = coupling_[i].gridIdx_[1];
+
+        // The mapping from nonmortar vertex indices to grid indices
+        nonmortarToGlobal[i].resize(nonmortarBoundary.numVertices());
+        int idx = 0;
+        for (int j=0; j<grids_[grid0Idx]->size(dim); j++)
+            if (nonmortarBoundary.containsVertex(j))
+                nonmortarToGlobal[i][idx++] = j;
+
+        // the off-diagonal part
+        const MatrixType& M = contactCoupling_[i]->mortarLagrangeMatrix();
+        for (size_t j=0; j<M.N(); j++) {
+
+            const RowType& row = M[j];
+
+            ConstColumnIterator cIt    = row.begin();
+            ConstColumnIterator cEndIt = row.end();
+
+            for (; cIt!=cEndIt; ++cIt)
+                indicesBT.add(offsets[grid0Idx] + nonmortarToGlobal[i][j],
+                              offsets[grid1Idx] + cIt.index());
+
+        }
+
+    }
+
+    // ////////////////////////////////////////////////////////////
+    //   Enter the values of the different couplings
+    // ////////////////////////////////////////////////////////////
+
+    indicesBT.exportIdx(BT_);
+    BT_ = 0;
+
+    // Enter identity part
+    for (int i=0; i<nRows; i++)
+        for (int j=0; j<dim; j++)
+            BT_[i][i][j][j] = 1;
+
+    for (int i=0; i<nCouplings(); i++) {
+
+        const auto& nonmortarBoundary = contactCoupling_[i]->nonmortarBoundary();
+        if (nonmortarBoundary.numVertices() == 0)
+            continue;
+
+        // The grids involved in this coupling
+        int grid0Idx = coupling_[i].gridIdx_[0];
+        int grid1Idx = coupling_[i].gridIdx_[1];
+
+        // the off-diagonal part
+        const MatrixType& M = contactCoupling_[i]->mortarLagrangeMatrix();
+        for (size_t j=0; j<M.N(); j++) {
+
+            const RowType& row = M[j];
+
+            ConstColumnIterator cIt    = row.begin();
+            ConstColumnIterator cEndIt = row.end();
+
+            for (; cIt!=cEndIt; ++cIt)
+                BT_[offsets[grid0Idx] + nonmortarToGlobal[i][j]][offsets[grid1Idx] +cIt.index()] = *cIt;
+
+        }
+
+        int offset = offsets[grid0Idx];
+
+        // modify non-mortar dofs and rotate them in normal and tangential coordinates
+        for (int k=0; k<grids_[grid0Idx]->size(dim); k++)
+            if(nonmortarBoundary.containsVertex(k))
+                BT_[offset + k][offset+k] =this->localCoordSystems_[offset + k];
+    }
+}
+
+} /* namespace Contact */
+} /* namespace Dune */
diff --git a/src/spatial-solving/contact/nbodyassembler.hh b/src/spatial-solving/contact/nbodyassembler.hh
new file mode 100644
index 0000000000000000000000000000000000000000..ae1db365287d1355a56753b509f3d6bc4e717395
--- /dev/null
+++ b/src/spatial-solving/contact/nbodyassembler.hh
@@ -0,0 +1,200 @@
+// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set ts=8 sw=4 et sts=4:
+#ifndef DUNE_CONTACT_ASSEMBLERS_N_BODY_MORTAR_ASSEMBLER_HH
+#define DUNE_CONTACT_ASSEMBLERS_N_BODY_MORTAR_ASSEMBLER_HH
+
+#include <dune/common/bitsetvector.hh>
+#include <dune/common/promotiontraits.hh>
+#include <dune/common/fmatrix.hh>
+#include <dune/istl/bcrsmatrix.hh>
+#include <dune/solvers/common/boxconstraint.hh>
+#include <dune/fufem/boundarypatch.hh>
+#include <dune/contact/assemblers/contactassembler.hh>
+#include <dune/contact/common/couplingpair.hh>
+#include <dune/contact/projections/contactprojection.hh>
+#include <dune/contact/assemblers/dualmortarcoupling.hh>
+
+#include "dualmortarcoupling.hh"
+
+#ifdef HAVE_DUNE_GRID_GLUE
+#include <dune/grid-glue/merging/merger.hh>
+#endif
+
+/**  \brief Assembler for mortar discretized contact problems with arbitrary number of bodies.
+ *
+ *  \tparam GridType Type of the corresponding grids.
+ *  \tparam VectorType The vector type for the displacements.
+ */
+template <class GridType, class VectorType>
+class NBodyAssembler : public Dune::Contact::ContactAssembler<GridType::dimension, typename VectorType::field_type>
+{
+protected:
+    enum {dim = GridType::dimension};
+
+    using field_type = typename Dune::PromotionTraits<typename VectorType::field_type,
+                                                typename GridType::ctype>::PromotedType;
+
+    using CouplingType = DualMortarCoupling<field_type, GridType>;
+
+    using MatrixBlock = Dune::FieldMatrix<field_type, dim, dim>;
+    using MatrixType = Dune::BCRSMatrix<MatrixBlock>;
+
+    using RowType =  typename MatrixType::row_type;
+    using ConstColumnIterator = typename RowType::ConstIterator;
+
+    using LeafBoundaryPatch = BoundaryPatch<typename GridType::LeafGridView>;
+
+public:
+    /** \brief Construct assembler from number of couplings and grids.
+     *
+     *  \param nGrids The number of involved bodies.
+     *  \param nCouplings The number of couplings.
+     *   \param hierarchyCoupling This boolean determines if the whole hierarchy of mortar matrices should be setup
+     */
+    NBodyAssembler(int nGrids, int nCouplings, bool hierarchyCoupling=false, field_type coveredArea = 0.99) :
+      coveredArea_(coveredArea)
+    {
+        grids_.resize(nGrids);
+
+        coupling_.resize(nCouplings);
+        contactCoupling_.resize(nCouplings);
+        // initialise the couplings with DualMortarCoupling
+        for (int i=0; i<nCouplings; i++)
+            if (hierarchyCoupling)
+                contactCoupling_[i] = std::make_shared<HierarchyCouplingType>();
+            else
+                contactCoupling_[i] = std::make_shared<CouplingType>();
+    }
+
+    /** \brief Get the number of couplings.*/
+    int nCouplings() const {return coupling_.size();}
+
+    /** \brief Get the number of involved bodies.*/
+    int nGrids() const {return grids_.size();}
+
+    /** \brief Get the total number of degrees of freedom of the leaf grids. */
+    int numDofs() const {
+        int n=0;
+        for (int i=0; i<nGrids(); i++)
+            n += grids_[i]->size(dim);
+        return n;
+    }
+
+    /** \brief Setup the patches for the contact boundary and compute the obstacles. */
+    void assembleObstacle();
+
+    /** \brief Assemble the mortar matrices and compute the basis transformation.*/
+    void assembleTransferOperator();
+
+    /** \brief Turn initial solutions from nodal basis to the transformed basis.
+     *         i.e. transformedX = O*B^{-T}nodalX
+     *  \param x Initial solution vector containing nodal coefficients.
+     *  \param transformedX Coefficient vector for all bodies in mortar transformed coordinates.
+     */
+    template <class VectorTypeContainer>
+    void nodalToTransformed(const VectorTypeContainer& x,
+                            VectorType& transformedX) const;
+
+    /** \brief Compute stiffness matrices in mortar transformed coordinates.
+     *         i.e. transformedA = O*B*nodalA*B^T*O^T
+     *  \param submat Stiffness matrices w.r.t the nodal finite element basis.
+     *  \param totalMatrix Reference to mortar transformed stiffness matrix for all bodies.
+     */
+    void assembleJacobian(const std::vector<const MatrixType*>& submat,
+                          MatrixType& totalMatrix) const;
+
+    /** \brief Compute the right hand side in mortar transformed coordinates.
+     *         i.e. totalRhs = O*B*nodalRhs
+     *  \param  rhs Right hand side coefficients w.r.t. the nodal finite element basis.
+     *  \param  totalRhs Reference to coefficient vector w.r.t. the transformed basis.
+     */
+    template <class VectorTypeContainer>
+    void assembleRightHandSide(const VectorTypeContainer& rhs,
+                               VectorType& totalRhs) const;
+
+    /** \brief Transform a vector from local coordinates to canonical coordinates.
+     *
+     *  \param totalX Coefficient vector of the mortar transformed basis.
+     *  \param x    Reference to target vector for the standard nodal coefficients of each body.
+     */
+    template <class VectorTypeContainer>
+    void postprocess(const VectorType& totalX, VectorTypeContainer& x) const;
+
+    /** \brief Concatenate a family of vectors .
+     *
+     * \param parts A vector of vectors.
+     * \param whole The vector to contain the concatenated family
+     */
+    template <class VectorTypeContainer>
+    static void concatenateVectors(const VectorTypeContainer& parts, VectorType& whole);
+
+    /** \brief Get the contact couplings. */
+    const auto& getContactCouplings() const {
+        return contactCoupling_;
+    }
+
+    /** \brief Get the contact couplings. */
+    auto& getContactCouplings() {
+        return contactCoupling_;
+    }
+
+    /** \brief Set the contact couplings. */
+    void setContactCouplings(std::vector<std::shared_ptr<CouplingType> >& contactCouplings) {
+
+        contactCoupling_.resize(contactCouplings.size());
+        for (size_t i=0; i<contactCouplings.size(); i++)
+            contactCoupling_[i] = contactCouplings[i];
+    }
+
+    /** \brief Get the transposed of the mortar transformation matrix B^T.*/
+    const MatrixType& getTransformationMatrix() const {return BT_;}
+
+    /** \brief Get the grids. */
+    const std::vector<const GridType*> getGrids() const { return grids_; }
+
+    /** \brief Set the grids. */
+    void setGrids(const std::vector<const GridType*>& grids) {grids_ = grids;}
+
+    /** \brief Set grids. */
+    void setCoupling(const CouplingPair<GridType, GridType, field_type>& coupling, size_t i) {
+        coupling_[i] = coupling;
+    }
+
+    /** \brief Get reference to i'th coupling. */
+    const auto& getCoupling(size_t i) const {return coupling_[i];}
+
+protected:
+    /** \brief Compute the transposed mortar transformation matrix. */
+    void computeTransformationMatrix();
+
+    /** \brief Setup the Householder reflections. */
+    void assembleHouseholderReflections();
+
+public:
+    /** \brief Bitvector for all bodies whose flags are set if a dof has an obstacle.*/
+    Dune::BitSetVector<dim> totalHasObstacle_;
+
+    /** \brief Obstacles for all bodies on the leafview.*/
+    std::vector<BoxConstraint<field_type,dim> > totalObstacles_;
+
+    /** \brief The mortar couplings between grid pairs */
+    std::vector<std::shared_ptr<CouplingType> > contactCoupling_;
+
+    /** \brief The coupling pairs. */
+    std::vector<CouplingPair<GridType,GridType,field_type> > coupling_;
+
+    /** \brief Vector containing the involved grids. */
+    std::vector<const GridType*> grids_;
+
+    /** \brief The transposed of the mortar transformation matrix. */
+    MatrixType BT_;
+
+    /** \brief Dismiss all faces that are not at least covered by the grid-glue projection for this
+     *         much percentage ranging between one - for total coverage and zero for taking all faces.
+     */
+    field_type coveredArea_;
+};
+
+#include "nbodyassembler.cc"
+
+#endif
diff --git a/src/spatial-solving/preconditioners/CMakeLists.txt b/src/spatial-solving/preconditioners/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..abb4ff76bea86b3ff68d31eb1b25e92947d747e7
--- /dev/null
+++ b/src/spatial-solving/preconditioners/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_custom_target(dune-tectonic_spatial-solving_preconditioners_src SOURCES
+  hierarchicleveliterator.hh
+  levelglobalpreconditioner.hh
+  levelpatchpreconditioner.hh
+  multilevelpatchpreconditioner.hh
+  supportpatchfactory.hh
+)
diff --git a/src/spatial-solving/preconditioners/hierarchicleveliterator.hh b/src/spatial-solving/preconditioners/hierarchicleveliterator.hh
new file mode 100644
index 0000000000000000000000000000000000000000..c8c7cf4cefecc371f30252c2c12c7c22b42159e7
--- /dev/null
+++ b/src/spatial-solving/preconditioners/hierarchicleveliterator.hh
@@ -0,0 +1,155 @@
+// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set ts=8 sw=4 et sts=4:
+#ifndef HIERARCHIC_LEVEL_ITERATOR_HH
+#define HIERARCHIC_LEVEL_ITERATOR_HH
+
+#include <dune/common/fvector.hh>
+#include <dune/common/iteratorfacades.hh>
+
+#include <dune/geometry/multilineargeometry.hh>
+#include <dune/geometry/referenceelements.hh>
+
+/** \brief Hierarchic leaf iterator.
+ *
+ *  This iterator loops over all children of a given coarse element and only returns the ones that are leaf.
+ *  If the starting element is leaf itself, then the returned iterator returns the element itself.
+ *  This class also provides a geometry, mapping local coordinates of the children to local coordinates
+ *  in the coarse element. 
+*/
+template <class GridImp>
+class HierarchicLevelIterator :
+    public Dune::ForwardIteratorFacade<HierarchicLevelIterator<GridImp>, const typename GridImp::template Codim<0>::Entity>
+{
+    typedef typename GridImp::template Codim<0>::Entity Element;
+    typedef typename GridImp::HierarchicIterator HierarchicIterator;
+    enum {dim = GridImp::dimension};
+    enum {dimworld = GridImp::dimensionworld};
+public:
+    typedef Dune::CachedMultiLinearGeometry<typename GridImp::ctype, dim, dimworld> LocalGeometry;
+
+    enum PositionFlag {begin, end};
+
+    HierarchicLevelIterator(const GridImp& grid, const Element& element, 
+                            PositionFlag flag, int maxlevel, bool nested = true)
+        : element_(element), maxlevel_(maxlevel), hIt_(element.hend(maxlevel_)),
+            flag_(flag), nested_(nested)
+    {
+
+        // if the element itself is leaf, then we don't have to iterate over the children
+        if (flag==begin && !(element_.level()==maxlevel_)) {
+            hIt_ = element_.hbegin(maxlevel_);
+
+            //NOTE This class by now assumes that possible non-nestedness of the grid levels only arises
+            // due to boundary parametrisation
+            if (!nested_)  {
+                // Check if the element is a boundary element, and set the nested flag correspondingly
+                // If the element is not at the boundary, then we can neglect the nested flag
+                typename GridImp::LevelIntersectionIterator lIt = grid.levelGridView(element.level()).ibegin(element);
+                typename GridImp::LevelIntersectionIterator lEndIt = grid.levelGridView(element.level()).ibegin(element);
+                nested_ = true;
+                for (; lIt != lEndIt; ++lIt)
+                    if (lIt->boundary()) {
+                        nested_ = false;
+                        break;
+                    }
+            }
+
+            if (!(hIt_->level()==maxlevel_))
+                increment();
+        }
+    }
+
+    //! Copy constructor
+    HierarchicLevelIterator(const HierarchicLevelIterator<GridImp>& other) :
+        element_(other.element_),maxlevel_(other.maxlevel_), hIt_(other.hIt_),
+        flag_(other.flag_), nested_(other.nested_)
+    {}
+
+    //! Equality
+    bool equals(const HierarchicLevelIterator<GridImp>& other) const {
+        return  (element_ == other.element_)  && 
+                ((flag_==other.flag_ && flag_==end) || (hIt_ == other.hIt_ && flag_==begin && other.flag_==flag_));
+    }
+
+    //! Prefix increment
+    void increment() {
+
+        HierarchicIterator hEndIt = element_.hend(maxlevel_);
+
+        if (hIt_ == hEndIt) {
+            flag_ = end;
+            return;
+        }
+
+        // Increment until we hit a leaf child element
+        do {
+            ++hIt_;
+        } while(hIt_ != hEndIt && (!(hIt_->level()==maxlevel_)));
+    
+        if (hIt_ == hEndIt)
+            flag_ = end;
+    }
+
+    //! Dereferencing
+    const Element& dereference() const {
+        if (flag_ == end)
+            DUNE_THROW(Dune::Exception,"HierarchicLevelIterator: Cannot dereference end iterator!");
+        return (element_.level()==maxlevel_) ? element_ : *hIt_;
+    }
+
+    //! Compute the local geometry mapping from the leaf child to the starting element
+    LocalGeometry geometryInAncestor() {
+
+        //NOTE: We assume here that the type of the child and the ancestors are the same!
+        const Dune::ReferenceElement<typename GridImp::ctype, dim>& ref = Dune::ReferenceElements<typename GridImp::ctype,dim>::general(element_.type());
+
+        // store local coordinates of the leaf child element within the coarse starting element
+        std::vector<Dune::FieldVector<typename GridImp::ctype,dim> > corners(ref.size(dim));
+        for (int i=0; i<corners.size(); i++)
+            corners[i] = ref.position(i,dim);
+
+        // If the element is leaf, then return an Identity mapping
+        if (element_.level()==maxlevel_)
+            return LocalGeometry(ref,corners);
+
+        if (nested_) {
+            const typename Element::Geometry leafGeom = hIt_->geometry();
+            const typename Element::Geometry coarseGeom = element_.geometry();
+
+            for (int i=0; i<corners.size();i++) 
+                corners[i] = coarseGeom.local(leafGeom.corner(i));
+            return LocalGeometry(ref,corners);
+        }
+ 
+        Element father(*hIt_);
+        while (father != element_) {
+
+            const typename Element::LocalGeometry fatherGeom = hIt_->geometryInFather();
+            father = father->father();
+
+            for (int i=0; i<corners.size(); i++)
+                corners[i] = fatherGeom.global(corners[i]);
+        }
+
+        return LocalGeometry(ref,corners);
+    }
+
+private:
+
+    //! The starting element
+    const Element element_;
+
+    //! The grids maxlevel
+    int maxlevel_;
+
+    //! The actual hierarchic iterator
+    HierarchicIterator hIt_;
+
+    //! Position flag
+    PositionFlag flag_;
+
+    //! Flag that is set true if the grid levels are conforming (i.e. no parametrised boundaries)
+    bool nested_;
+
+};
+#endif
diff --git a/src/spatial-solving/tnnmg/levelglobalpreconditioner.hh b/src/spatial-solving/preconditioners/levelglobalpreconditioner.hh
similarity index 98%
rename from src/spatial-solving/tnnmg/levelglobalpreconditioner.hh
rename to src/spatial-solving/preconditioners/levelglobalpreconditioner.hh
index 2b7b4e2bb80f6ad5ec302097654dbb5bc320deb4..ac9fd3fce63579595d9e64d29c2e9e69c1d6b63d 100644
--- a/src/spatial-solving/tnnmg/levelglobalpreconditioner.hh
+++ b/src/spatial-solving/preconditioners/levelglobalpreconditioner.hh
@@ -7,6 +7,7 @@
 
 #include <dune/solvers/iterationsteps/lineariterationstep.hh>
 
+//#include <dune/istl/superlu.hh>
 #include <dune/istl/umfpack.hh>
 
 #include <dune/fufem/boundarypatch.hh>
@@ -115,7 +116,7 @@ class LevelGlobalPreconditioner : public LinearIterationStep<MatrixType, VectorT
         this->x_->resize(matrix_.M());
         *(this->x_) = 0;
 
-        #if HAVE_UMFPACK
+        #if HAVE_SUPERLU
         Dune::InverseOperatorResult res;
         VectorType rhsCopy(rhs_);
 
@@ -123,7 +124,7 @@ class LevelGlobalPreconditioner : public LinearIterationStep<MatrixType, VectorT
         solver.apply(*(this->x_), rhsCopy, res);
 
         #else
-        #error No UMFPack!
+        #error No SuperLU!
         #endif
 
         //std::cout << "LevelGlobalPreconditioner::iterate() Solving global problem took: " << timer.elapsed() << " seconds" << std::endl;
diff --git a/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh b/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh
new file mode 100644
index 0000000000000000000000000000000000000000..d905e4a3b40f47cba638278ee36706ea88695ba5
--- /dev/null
+++ b/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh
@@ -0,0 +1,210 @@
+#ifndef LEVEL_PATCH_PRECONDITIONER_HH
+#define LEVEL_PATCH_PRECONDITIONER_HH
+
+#include <string>
+
+#include <dune/common/timer.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/bitsetvector.hh>
+
+#include <dune/solvers/iterationsteps/lineariterationstep.hh>
+
+#include "../../data-structures/levelcontactnetwork.hh"
+
+#include "supportpatchfactory.hh"
+
+#include <dune/localfunctions/lagrange/pqkfactory.hh>
+
+#include <dune/fufem/boundarypatch.hh>
+#include <dune/fufem/functiontools/boundarydofs.hh>
+
+
+template <class PatchSolver, class MatrixType, class VectorType>
+class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorType> {
+
+public:
+    enum Mode {additive, multiplicative};
+
+private:
+    using Base = LinearIterationStep<MatrixType, VectorType>;
+
+    using PatchFactory = SupportPatchFactory<GridView, GridView>;
+    using Patch = typename SupportPatchFactory::Patch;
+
+    typedef typename BasisType::GridView GridView;
+    typedef typename GridView::Grid GridType;
+
+    static const int dim = GridType::dimension;
+
+    const Mode mode_;
+
+    const LevelContactNetwork<GridView, dim>& levelContactNetwork_;
+
+    std::vector<Patch> patches_;
+    PatchSolver patchSolver_;
+
+    const GridType& grid_;
+    const int level_;
+    const BasisType basis_;
+
+    size_t patchDepth_;
+
+    MatrixType matrix_;
+    std::vector<std::shared_ptr<OscLocalProblem<MatrixType, VectorType>> > localProblems_;
+
+public:
+
+    // for each coarse patch given by patchLevelBasis: set up local problem, compute local correction
+    LevelPatchPreconditioner(const LevelContactNetwork<GridView, dim>& levelContactNetwork,
+                             const BasisType& patchLevelBasis,
+                             const LocalAssembler& localAssembler,
+                             const std::vector<std::shared_ptr<LocalInterfaceAssembler>>& localInterfaceAssemblers,
+                             const Mode mode = LevelPatchPreconditioner::Mode::additive) :
+          levelInterfaceNetwork_(levelInterfaceNetwork),
+          patchLevelBasis_(patchLevelBasis),
+          localAssembler_(localAssembler),
+          localInterfaceAssemblers_(localInterfaceAssemblers),
+          mode_(mode),
+          grid_(levelInterfaceNetwork_.grid()),
+          level_(levelInterfaceNetwork_.level()),
+          basis_(levelInterfaceNetwork_)
+    {
+        setPatchDepth();
+        this->verbosity_ = QUIET;
+    }
+
+    // build support patches
+    void build() {
+
+
+        localProblems_.resize(vertexInElements.size());
+
+        // init local fine level corrections
+        if (this->verbosity_ == FULL) {
+            std::cout << std::endl;
+            std::cout << "---------------------------------------------" << std::endl;
+            std::cout << "Initializing local fine grid corrections! Level: " << level_ << std::endl;
+
+            Dune::Timer timer;
+            timer.reset();
+            timer.start();
+        }
+
+        const int patchLevel = patchLevelBasis_.faultNetwork().level();
+        for (size_t i=0; i<vertexInElements.size(); i++) {
+            if (this->verbosity_ != QUIET) {
+                std::cout << i << std::endl;
+                std::cout << "---------------" << std::endl;
+            }
+
+            Patch patchDofs;
+            SupportPatchFactory<decltype(coarseGridView), decltype(fineGridView)> patchFactory(coarseGridView, fineGridView, vertexInElementsBody);
+            patchFactory.build(seedObject, patchDofs, patchDepth_);
+
+            if ((i+1) % 10 == 0 && this->verbosity_ == FULL) {
+                std::cout << '\r' << std::floor((i+1.0)/patchLevelBasis_.size()*100) << " % done. Elapsed time: " << timer.elapsed() << " seconds. Predicted total setup time: " << timer.elapsed()/(i+1.0)*patchLevelBasis_.size() << " seconds." << std::flush;
+            }
+        }
+
+        if (this->verbosity_ == FULL) {
+            std::cout << std::endl;
+            std::cout << "Total setup time: " << timer.elapsed() << " seconds." << std::endl;
+            std::cout << "---------------------------------------------" << std::endl;
+            timer.stop();
+        }
+
+        if (this->verbosity_ != REDUCED) {
+            std::cout << "Level: " << level_ << " LevelPatchPreconditioner::build() - SUCCESS" << std::endl;
+        }
+    }
+
+    void setPatchDepth(const size_t patchDepth = 0) {
+        patchDepth_ = patchDepth;
+    }
+
+    void setVerbosity(VerbosityMode verbosity) {
+        this->verbosity_ = verbosity;
+    }
+
+    virtual void setProblem(const MatrixType& mat, VectorType& x, const VectorType& rhs) {
+
+      /*  VectorType rhs;
+        rhs.resize(matrix_.N());
+        rhs = 0;
+
+        //print(localToGlobal, "localToGlobal: ");
+        //print(boundaryDofs, "boundaryDofs: ");
+
+        localProblems_[i] = std::make_shared<OscLocalProblem<MatrixType, VectorType>>(matrix_, rhs, localToGlobal, boundaryDofs);*/
+
+        this->x_ = &x;
+        this->rhs_ = &rhs;
+        this->mat_ = Dune::stackobject_to_shared_ptr(mat);
+
+        patchSolver_.setProblem(mat, x, rhs);
+    }
+
+    virtual void iterate() {
+        if (mode_ == additive)
+            iterateAdd();
+        else
+            iterateMult();
+    }
+
+    void iterateAdd() {
+        *(this->x_) = 0;	
+
+        VectorType x = *(this->x_);
+        for (size_t i=0; i<patches_.size(); i++) {
+            patchSolver_.setIgnore(patches_[i]);
+            patchSolver_.solve();
+
+            *(this->x_) += x;
+        }
+    }
+
+    void iterateMult() {
+        *(this->x_) = 0;
+
+        VectorType x = *(this->x_);
+        for (size_t i=0; i<patches_.size(); i++) {
+            VectorType updatedRhs(*(this->rhs_));
+            this->mat_->mmv(*(this->x_), updatedRhs);
+
+            //step(i);
+            //print(updatedRhs, "localRhs: ");
+            //writeToVTK(basis_, updatedRhs, "/storage/mi/podlesny/data/faultnetworks/rhs/local", "exactvertexdata_step_"+std::to_string(i));
+
+            patchSolver_.setProblem(*this->mat_, *(this->x_), updatedRhs);
+            patchSolver_.setIgnore(patches_[i]);
+            patchSolver_.solve();
+
+            //print(it, "it: ");
+            //print(x, "x: ");
+
+            //writeToVTK(basis_, x, "/storage/mi/podlesny/data/faultnetworks/sol/local", "exactvertexdata_step_"+std::to_string(i));
+
+            /*if (i==5) {
+                writeToVTK(basis_, x, "/storage/mi/podlesny/data/faultnetworks/iterates/", "exactvertexdata_patchDepth_"+std::to_string(patchDepth_));
+            }*/
+
+            *(this->x_) += x;
+        }
+    }
+
+    const GridView& gridView() const {
+        return basis_.getGridView();
+    }
+
+    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork() const {
+        return levelInterfaceNetwork_;
+    }
+
+    size_t size() const {
+        return localProblems_.size();
+    }
+
+};
+
+#endif
+
diff --git a/src/spatial-solving/tnnmg/multilevelpatchpreconditioner.hh b/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
similarity index 100%
rename from src/spatial-solving/tnnmg/multilevelpatchpreconditioner.hh
rename to src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
diff --git a/src/spatial-solving/preconditioners/supportpatchfactory.hh b/src/spatial-solving/preconditioners/supportpatchfactory.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f518ecc0de92b9fcdbaab92bdfca58b36f26072a
--- /dev/null
+++ b/src/spatial-solving/preconditioners/supportpatchfactory.hh
@@ -0,0 +1,514 @@
+#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& outside = neighbors[0];
+
+                    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/spatial-solving/preconditioners/supportpatchfactory.hh.autosave b/src/spatial-solving/preconditioners/supportpatchfactory.hh.autosave
new file mode 100644
index 0000000000000000000000000000000000000000..869cbd83d4f0cf01737f5d7d41f7cd53c392da96
--- /dev/null
+++ b/src/spatial-solving/preconditioners/supportpatchfactory.hh.autosave
@@ -0,0 +1,518 @@
+#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/spatial-solving/preconditioners/test/CMakeLists.txt b/src/spatial-solving/preconditioners/test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3a5964adeb30007351d7b9a5c14236191cbe0222
--- /dev/null
+++ b/src/spatial-solving/preconditioners/test/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Put your test in here if it needs access to external grids
+set(FAULTNETWORKS_PRECONDITIONERS_TESTS
+  levelfaultpreconditionertest
+  )
+
+set(TESTS ${FAULTNETWORKS_PRECONDITIONERS_TESTS})
+
+# Setup targets, register tests, and add dune flags
+foreach(_test ${TESTS})
+  #dune_add_test(SOURCES ${_test}.cc)
+endforeach()
+
diff --git a/src/spatial-solving/preconditioners/test/Makefile.am b/src/spatial-solving/preconditioners/test/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..a4c19c2c84cac95071500f9fa9c79aa2677057d1
--- /dev/null
+++ b/src/spatial-solving/preconditioners/test/Makefile.am
@@ -0,0 +1,42 @@
+# which tests where program to build and run are equal
+NORMALTESTS = levelfaultpreconditionertest
+
+# list of tests to run 
+TESTS = $(NORMALTESTS)
+
+# programs just to build when "make check" is used
+check_PROGRAMS = $(NORMALTESTS)
+
+# define the programs
+levelfaultpreconditionertest_SOURCES = levelfaultpreconditionertest.cc
+
+
+levelfaultpreconditionertest_CPPFLAGS = $(AM_CPPFLAGS) \
+	$(DUNEMPICPPFLAGS) \
+	$(UG_CPPFLAGS)
+	
+# The libraries have to be given in reverse order (most basic libraries
+# last).  Also, due to some misunderstanding, a lot of libraries include the
+# -L option in LDFLAGS instead of LIBS -- so we have to include the LDFLAGS
+# here as well.
+levelfaultpreconditionertest_LDADD = \
+	$(DUNE_LDFLAGS) $(DUNE_LIBS) \
+	$(UG_LDFLAGS) $(UG_LIBS) \
+	$(DUNEMPILIBS)	\
+	$(LDADD)
+levelfaultpreconditionertest_LDFLAGS = $(AM_LDFLAGS) \
+	$(DUNEMPILDFLAGS) \
+	$(UG_LDFLAGS) \
+	$(DUNE_LDFLAGS)
+
+# don't follow the full GNU-standard
+# we need automake 1.9
+AUTOMAKE_OPTIONS = foreign 1.9
+
+# pass most important options when "make distcheck" is used
+DISTCHECK_CONFIGURE_FLAGS = --with-dune-common=$(DUNE_COMMON_ROOT) --with-dune-geometry=$(DUNE_GEOMETRY_ROOT) --with-dune-grid=$(DUNE_GRID_ROOT) --with-dune-istl=$(DUNE_ISTL_ROOT) --with-dune-localfunctions=$(DUNE_LOCALFUNCTIONS_ROOT) --with-dune-solvers=$(DUNE_SOLVERS_ROOT) --with-dune-fufem=$(DUNE_FUFEM_ROOT)  CXX="$(CXX)" CC="$(CC)"
+
+EXTRA_DIST = CMakeLists.txt
+
+include $(top_srcdir)/am/global-rules
+
diff --git a/src/spatial-solving/preconditioners/test/levelfaultpreconditionertest.cc b/src/spatial-solving/preconditioners/test/levelfaultpreconditionertest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..69b2283a34652d187aa57bf7bb0623e0168cb519
--- /dev/null
+++ b/src/spatial-solving/preconditioners/test/levelfaultpreconditionertest.cc
@@ -0,0 +1,274 @@
+#include <config.h>
+
+#include <dune/common/parallel/mpihelper.hh>
+
+#include <dune/grid/uggrid.hh>
+#include <dune/grid/common/mcmgmapper.hh>
+
+#include <dune/fufem/assemblers/localassemblers/laplaceassembler.hh>
+
+#include <dune/faultnetworks/interfacenetwork.hh>
+#include <dune/faultnetworks/faultfactories/multileveluniformfaultfactory.hh>
+#include <dune/faultnetworks/preconditioners/levelfaultpreconditioner.hh>
+#include <dune/faultnetworks/preconditioners/multilevelfaultpreconditioner.hh>
+#include <dune/faultnetworks/assemblers/intersectionjumpmassassembler.hh>
+#include <dune/faultnetworks/faultp1nodalbasis.hh>
+#include <dune/faultnetworks/utils/debugutils.hh>
+
+const int dim = 2;
+
+const int coarseResolution = 2;
+const int fineResolution = 3;
+const int exactResolution = 4;
+
+const int faultCount = 3;
+
+
+typedef typename Dune::UGGrid<dim> GridType;
+typedef typename GridType::LevelGridView GridView;
+typedef typename GridType::LevelIntersection Intersection;
+typedef typename GridType::template Codim<0>::Entity Element;
+
+static const int dimElement = Element::dimension;
+
+void gridLevelOutput(const GridType& grid, const int level) {
+    std::cout << "Grid elements on lvl " << level << std::endl << std::endl;
+
+    typedef typename GridView::template Codim<0>::Iterator ElementLevelIterator;
+    GridView gridView(grid.levelGridView(level));
+
+    //Dune::LevelMultipleCodimMultipleGeomTypeMapper <GridType,  Dune::MCMGElementLayout > mapper(grid, level);
+    Dune::LevelMultipleCodimMultipleGeomTypeMapper <GridType, Dune::MCMGVertexLayout > vMapper(grid, level);
+
+    Dune::BitSetVector<1> vertexPrinted(vMapper.size(), false);
+
+    ElementLevelIterator elemIt = gridView.template begin<0>();
+    ElementLevelIterator elemEndIt = gridView.template end<0>();
+    for (; elemIt!=elemEndIt; ++elemIt) {
+        const Element& elem = *elemIt;
+        const auto& geometry = elem.geometry();
+
+        for(int i=0; i<geometry.corners(); ++i) {
+            size_t globalIdx = gridView.indexSet().subIndex(elem, i, Element::dimension);
+            if (!vertexPrinted[globalIdx][0]) {
+                const auto& vertex = geometry.corner(i);
+                print(vertex, "elem corner:" + std::to_string(globalIdx));
+                vertexPrinted[globalIdx][0] = true;
+            }
+        }
+    }
+    std::cout << "----------------" << std::endl << std::endl;
+	
+    /*
+    ElementLevelIterator elemIt = gridView.template begin<0>();
+    ElementLevelIterator elemEndIt = gridView.template end<0>();
+    for (; elemIt!=elemEndIt; ++elemIt) {
+        const Element& elem = *elemIt;
+        const auto& geometry = elem.geometry();
+
+        std::cout << "Element idx: " << mapper.index(elem) << std::endl;
+
+        for(int i=0; i<geometry.corners(); ++i) {
+            size_t globalIdx = gridView.indexSet().subIndex(elem, i, Element::dimension);
+            const auto& vertex = geometry.corner(i);
+            print(vertex, "elem corner:" + std::to_string(globalIdx));
+        }
+        std::cout << "----------------" << std::endl << std::endl;
+    }*/
+
+}
+
+
+void faultInterfaceOutput(const FaultInterface<GridView>& faultInterface) {
+    std::cout << "Level: " << faultInterface.level() << "  global faultID: " << faultInterface.id() << std::endl;
+
+    const std::set<size_t>& interfaceDofs = faultInterface.getInterfaceDofs();
+    print(interfaceDofs, "");
+}
+
+void interfaceNetworkLevelOutput(const InterfaceNetwork<GridType>& interfaceNetwork, const int level) {
+    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork = interfaceNetwork.levelInterfaceNetwork(level);
+
+    std::cout << "LevelInterfaceNetwork level: " << level << std::endl;
+    for (size_t i=0; i<levelInterfaceNetwork.size(); i++) {
+        std::cout << "local faultID : " << i << "  ";
+        faultInterfaceOutput(*(levelInterfaceNetwork.getInterface(i)));
+    }
+
+    std::cout << "------------------------------" << std::endl << std::endl;
+}
+
+void computeIntersectionDofs(const GridView& gridView, const Intersection& intersection, std::set<size_t>& intersectionDofs) {
+    intersectionDofs.clear();
+
+    // loop over all vertices of the intersection
+    const Element& insideElement = intersection.inside();
+			
+    const auto& refElement = Dune::ReferenceElements<double,dimElement>::general(insideElement.type());
+    for (int i=0; i<refElement.size(intersection.indexInInside(), 1, dimElement); i++) {
+        size_t idxInElement = refElement.subEntity(intersection.indexInInside(), 1, i, dimElement);
+        size_t globalIdx = gridView.indexSet().subIndex(insideElement, idxInElement, dimElement);
+        intersectionDofs.insert(globalIdx);
+     }
+}
+
+void prolongFaultDofs(const GridType& grid, const FaultInterface<GridView>& faultInterface, const int toLevel, std::set<size_t>& prolongedDofs) {
+    prolongedDofs.clear();
+
+    const std::vector<Intersection>& faces = faultInterface.faces();
+    const GridView gridView(grid.levelGridView(toLevel));
+
+    for (size_t i=0; i<faces.size(); i++) {
+        const Intersection& intersection = faces[i];
+        Face<GridType> face(grid, intersection.inside(), intersection.indexInInside());
+
+        typename Face<GridType>::HierarchicIterator exactIt = face.hbegin(toLevel);
+        typename Face<GridType>::HierarchicIterator exactEnd = face.hend(toLevel);
+        for(; exactIt!=exactEnd; ++exactIt) {
+            if (exactIt->level() == toLevel) {
+                std::set<size_t> faceDofs;
+                computeIntersectionDofs(gridView, *(exactIt->intersection()), faceDofs);
+
+                prolongedDofs.insert(faceDofs.begin(), faceDofs.end());
+            }
+        }
+    }
+}
+
+void prolongInterfaceNetworkLevelDofs(const GridType& grid, const InterfaceNetwork<GridType>& interfaceNetwork, const int level, const int toLevel, std::vector<std::set<size_t>>& prolongedFaultDofs) {
+    prolongedFaultDofs.resize(0);
+
+    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork = interfaceNetwork.levelInterfaceNetwork(level);
+
+    std::cout << "Correct prolonged LevelInterfaceNetwork level " << level << " to level " << toLevel << std::endl;
+    for (size_t i=0; i<levelInterfaceNetwork.size(); i++) {
+        std::set<size_t> prolongedDofs;
+        prolongFaultDofs(grid, *(levelInterfaceNetwork.getInterface(i)), toLevel, prolongedDofs);
+
+        print(prolongedDofs, "local faultID: " + std::to_string(i));
+        prolongedFaultDofs.push_back(prolongedDofs);
+    }
+
+    std::cout << "------------------------------" << std::endl << std::endl;
+}
+
+int main(int argc, char** argv) try
+{
+    typedef double ctype;
+
+    Dune::MPIHelper::instance(argc, argv);
+
+    std::ofstream out("/home/mi/podlesny/software/dune/faultnetworks/dune/faultnetworks/preconditioners/test/levelfaultpreconditionertest.log");
+    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
+    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!
+
+    const int fineLevelIdx = fineResolution - coarseResolution;
+    const int exactLevelIdx = exactResolution - coarseResolution;
+
+    std::vector<int> faultToLevel(faultCount);
+    for (size_t i=0; i<faultToLevel.size(); ) {
+        for (int j=fineLevelIdx; j>0 && i<faultToLevel.size(); j--) {
+            faultToLevel[i] = j;
+            i++;
+        }
+
+        for (int j=0; j<fineLevelIdx && i<faultToLevel.size(); j++) {
+            faultToLevel[i] = j;
+            i++;
+        }
+    }
+
+    print(faultToLevel, "faultToLevel: ");
+
+    MultilevelUniformFaultFactory<GridType> faultFactory(faultCount, faultToLevel, coarseResolution, exactLevelIdx);
+    const InterfaceNetwork<GridType>& interfaceNetwork = faultFactory.interfaceNetwork();
+
+    /*
+    const GridType& grid = faultFactory.grid();
+
+    gridLevelOutput(grid, 0);
+    gridLevelOutput(grid, fineLevelIdx);
+    gridLevelOutput(grid, exactLevelIdx);
+
+    interfaceNetworkLevelOutput(interfaceNetwork, 0);
+    interfaceNetworkLevelOutput(interfaceNetwork, fineLevelIdx);
+    interfaceNetworkLevelOutput(interfaceNetwork, exactLevelIdx); */
+
+    typedef typename Dune::BlockVector<Dune::FieldVector<ctype,1>> VectorType;
+    typedef typename Dune::BCRSMatrix<Dune::FieldMatrix<ctype, 1, 1>> MatrixType;
+
+    typedef FaultP1NodalBasis<GridView, ctype> DGBasis;
+    typedef typename DGBasis::LocalFiniteElement DGFE;
+
+    typedef IntersectionJumpMassAssembler<GridView, DGFE, DGFE> LocalInterfaceAssembler;
+    typedef Dune::Matrix<Dune::FieldMatrix<double,1,1>, std::allocator<Dune::FieldMatrix<double,1,1>>> OscMatrixType;
+    OscMatrixType B(2,2);
+    B[0][0] = 1;
+    B[1][1] = 1;
+    B[0][1] = -1;
+    B[1][0] = -1;
+
+    //--------------------------------------------------------------
+    // Multilevelfaultpreconditioner
+    //--------------------------------------------------------------
+
+    // setting local assemblers for laplace operator
+    LocalInterfaceAssembler localInterfaceAssembler(B);
+    typedef LaplaceAssembler<GridType, DGFE, DGFE> LocalLaplaceAssembler;
+    LocalLaplaceAssembler localAssembler;
+
+    Dune::BitSetVector<1> activeLevels(fineLevelIdx+1, true);
+    print(activeLevels, "activeLevels: ");
+
+    std::vector<std::shared_ptr<LocalLaplaceAssembler>> localAssemblers;
+    std::vector<std::shared_ptr<LocalInterfaceAssembler>> localIntersectionAssemblers;
+
+    localAssemblers.resize(activeLevels.size());
+    localIntersectionAssemblers.resize(activeLevels.size());
+
+    for (size_t i=0; i<activeLevels.size(); i++) {
+        localAssemblers[i] = std::make_shared<LocalLaplaceAssembler>(localAssembler);
+        localIntersectionAssemblers[i] = std::make_shared<LocalInterfaceAssembler>(localInterfaceAssembler);
+    }
+
+    MultilevelFaultPreconditioner<DGBasis, LocalLaplaceAssembler, LocalInterfaceAssembler, MatrixType, VectorType> preconditioner(interfaceNetwork, activeLevels, localAssemblers, localIntersectionAssemblers);
+
+    MatrixType matrix;
+    VectorType mgX(preconditioner.basis().size());
+    VectorType mgRhs(preconditioner.basis().size());
+    mgRhs = 0;
+
+    preconditioner.setProblem(matrix, mgX, mgRhs);
+    preconditioner.iterate();
+
+    const VectorType& mgSol = preconditioner.getSol();
+    print(mgSol, "mgSol: ");
+
+    step(0);
+
+    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork = interfaceNetwork.levelInterfaceNetwork(1);
+    LevelFaultPreconditioner<DGBasis, LocalLaplaceAssembler, LocalInterfaceAssembler, MatrixType, VectorType> levelFaultPreconditioner(levelInterfaceNetwork, localAssembler, localInterfaceAssembler);
+
+    step(1);
+
+    VectorType x(levelFaultPreconditioner.basis().size());
+    VectorType rhs(levelFaultPreconditioner.basis().size());
+    rhs = 0;
+
+    step(2);
+
+
+    levelFaultPreconditioner.setProblem(matrix, x, rhs);
+
+    step(3);
+
+    levelFaultPreconditioner.iterate();
+
+    const VectorType& sol = levelFaultPreconditioner.getSol();
+
+    print(sol, "sol: ");
+
+    std::cout.rdbuf(coutbuf);
+} catch (Dune::Exception e){
+  std::cout << e << std::endl;
+}
diff --git a/src/spatial-solving/preconditioners/test/levelfaultpreconditionertest.log b/src/spatial-solving/preconditioners/test/levelfaultpreconditionertest.log
new file mode 100644
index 0000000000000000000000000000000000000000..a66d14bfdf5e4aed77911c4071d9eda95e757075
--- /dev/null
+++ b/src/spatial-solving/preconditioners/test/levelfaultpreconditionertest.log
@@ -0,0 +1,26 @@
+faultToLevel: 
+1 0 1 
+
+Coarse and fine grid were generated!
+activeLevels: 
+1 1 
+
+Initializing local fine grid corrections! 
+
+Total setup time: 0.000599407 seconds.
+Initializing local fine grid corrections! 
+
+Total setup time: 0.00250133 seconds.
+mgSol: 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
+ Step 0!
+Initializing local fine grid corrections! 
+
+Total setup time: 0.00260553 seconds.
+ Step 1!
+ Step 2!
+ Step 3!
+sol: 
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
+
diff --git a/src/spatial-solving/solverfactory.hh b/src/spatial-solving/solverfactory.hh
index b4a5efd5ffe2b2aa9496da24892412329dea1e62..607ac3658ee0c185cd82f5a949a3dc5e97164af3 100644
--- a/src/spatial-solving/solverfactory.hh
+++ b/src/spatial-solving/solverfactory.hh
@@ -17,12 +17,13 @@
 #include <dune/tnnmg/projections/obstacledefectprojection.hh>
 #include <dune/tnnmg/linearsolvers/fastamgsolver.hh>
 
-//#include "tnnmg/functional.hh"
 #include "tnnmg/tnnmgstep.hh"
 #include "tnnmg/linearization.hh"
 #include "tnnmg/linesearchsolver.hh"
 #include "tnnmg/localbisectionsolver.hh"
 
+//#include "preconditioners/supportpatchfactory.hh"
+
 template <class FunctionalTEMPLATE, class BitVectorType>
 class SolverFactory {
 public:
diff --git a/src/spatial-solving/solverfactory_old.cc b/src/spatial-solving/solverfactory_old.cc
deleted file mode 100644
index cbbe5ef1d7cbabc1c2ecd56677dad245192ed600..0000000000000000000000000000000000000000
--- a/src/spatial-solving/solverfactory_old.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_IPOPT
-#undef HAVE_IPOPT
-#endif
-
-#include <dune/common/bitsetvector.hh>
-
-#include <dune/fufem/assemblers/transferoperatorassembler.hh>
-#include <dune/solvers/solvers/solver.hh>
-
-#include "solverfactory_old.hh"
-
-
-template <class DeformedGrid, class Nonlinearity, class MatrixType, class VectorType>
-SolverFactoryOld<DeformedGrid, Nonlinearity, MatrixType, VectorType>::SolverFactoryOld(
-    const Dune::ParameterTree& parset, const Dune::Contact::NBodyAssembler<DeformedGrid, VectorType>& nBodyAssembler,
-    const Dune::BitSetVector<DeformedGrid::dimension>& ignoreNodes)
-    : nBodyAssembler_(nBodyAssembler),
-      baseEnergyNorm_(baseSolverStep_),
-      baseSolver_(&baseSolverStep_,
-                       parset.get<size_t>("linear.maximumIterations"),
-                       parset.get<double>("linear.tolerance"), &baseEnergyNorm_,
-                       Solver::QUIET),
-      transferOperators_(nBodyAssembler.getGrids().at(0)->maxLevel()) {
-
- /* baseSolverStep_.obstacles_ = using HasObstacle = Dune::BitSetVector<BlockSize>;
-    using Obstacle = BoxConstraint<Field, BlockSize>;
-    const HasObstacle* hasObstacle_;
-    const std::vector<Obstacle>* obstacles_;*/
-
-  multigridStep_ = std::make_shared<Step>();
-  // tnnmg iteration step
-  multigridStep_->setMGType(parset.get<int>("main.multi"), parset.get<int>("main.pre"), parset.get<int>("main.post"));
-  multigridStep_->setIgnore(ignoreNodes);
-  multigridStep_->setBaseSolver(baseSolver_);
-  multigridStep_->setSmoother(&presmoother_, &postsmoother_);
-  multigridStep_->setHasObstacle(nBodyAssembler_.totalHasObstacle_);
-  multigridStep_->setObstacles(nBodyAssembler_.totalObstacles_);
-  multigridStep_->setVerbosity(NumProc::QUIET);
-
-  // create the transfer operators
-  const int nCouplings = nBodyAssembler_.nCouplings();
-  const auto grids = nBodyAssembler_.getGrids();
-
-  for (size_t i=0; i<transferOperators_.size(); i++) {
-    transferOperators_[i] = std::make_shared<TransferOperator>();
-  }
-
-  std::vector<const Dune::BitSetVector<1>*> fineHasObstacle(nCouplings);
-  std::vector<const MatrixType*> mortarTransfer(nCouplings);
-  std::vector<std::array<int,2> > gridIdx(nCouplings);
-
-  for (int j=0; j<nCouplings; j++) {
-    fineHasObstacle[j]    = nBodyAssembler_.contactCoupling_[j]->nonmortarBoundary().getVertices();
-    mortarTransfer[j] = &nBodyAssembler_.contactCoupling_[j]->mortarLagrangeMatrix();
-    gridIdx[j]        = nBodyAssembler_.coupling_[j].gridIdx_;
-  }
-
-  TransferOperator::setupHierarchy(transferOperators_,
-                                   grids,
-                                   mortarTransfer,
-                                   nBodyAssembler_.localCoordSystems_,
-                                   fineHasObstacle,
-                                   gridIdx);
-
-  multigridStep_->setTransferOperators(transferOperators_);
-}
-
-template <class DeformedGrid, class Nonlinearity, class MatrixType, class VectorType>
-auto SolverFactoryOld<DeformedGrid, Nonlinearity, MatrixType, VectorType>::getStep()
-    -> std::shared_ptr<Step> {
-  return multigridStep_;
-}
-
-#include "solverfactory_tmpl_old.cc"
diff --git a/src/spatial-solving/solverfactory_old.hh b/src/spatial-solving/solverfactory_old.hh
deleted file mode 100644
index 1c383419e1ac32eced29512d04260881f7157a82..0000000000000000000000000000000000000000
--- a/src/spatial-solving/solverfactory_old.hh
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef SRC_SPATIAL_SOLVING_SOLVERFACTORYOLD_HH
-#define SRC_SPATIAL_SOLVING_SOLVERFACTORYOLD_HH
-
-#include <dune/common/bitsetvector.hh>
-#include <dune/common/parametertree.hh>
-
-#include <dune/solvers/iterationsteps/multigridstep.hh>
-#include <dune/solvers/iterationsteps/projectedblockgsstep.hh>
-#include <dune/solvers/iterationsteps/blockgsstep.hh>
-#include <dune/solvers/norms/energynorm.hh>
-#include <dune/solvers/solvers/loopsolver.hh>
-
-//#include <dune/solvers/transferoperators/compressedmultigridtransfer.hh>
-//#include <dune/tnnmg/iterationsteps/genericnonlineargs.hh>
-//#include <dune/tnnmg/iterationsteps/tnnmgstep.hh>
-
-#include <dune/contact/assemblers/nbodyassembler.hh>
-
-//#include <dune/contact/estimators/hierarchiccontactestimator.hh>
-#include <dune/contact/solvers/nsnewtonmgstep.hh>
-#include <dune/contact/solvers/nsnewtoncontacttransfer.hh>
-#include <dune/contact/solvers/contactobsrestrict.hh>
-#include <dune/contact/solvers/contacttransferoperatorassembler.hh>
-#include <dune/contact/solvers/nsnewtoncontacttransfer.hh>
-
-#define USE_OLD_TNNMG //needed for old bisection.hh in tnnmg
-
-template <class DeformedGridTEMPLATE, class NonlinearityTEMPLATE, class MatrixType, class VectorType>
-class SolverFactoryOld {
-//protected:
-//  const size_t dim = DeformedGrid::dimension;
-
-public:
-  using Matrix = MatrixType;
-  using Vector = VectorType;
-  using DeformedGrid = DeformedGridTEMPLATE;
-  using Nonlinearity = NonlinearityTEMPLATE;
-
-public:
-  using Step = Dune::Contact::NonSmoothNewtonMGStep<MatrixType, VectorType>;
-  using TransferOperator = Dune::Contact::NonSmoothNewtonContactTransfer<VectorType>;
-
-  SolverFactoryOld(Dune::ParameterTree const &parset, const Dune::Contact::NBodyAssembler<DeformedGrid, VectorType>& nBodyAssembler,
-                const Dune::BitSetVector<DeformedGrid::dimension>& ignoreNodes);
-
-  std::shared_ptr<Step> getStep();
-
-  const Dune::Contact::NBodyAssembler<DeformedGrid, VectorType>& getNBodyAssembler() const {
-    return nBodyAssembler_;
-  }
-
-private:
-  const Dune::Contact::NBodyAssembler<DeformedGrid, VectorType>& nBodyAssembler_;
-
-  //ProjectedBlockGSStep<MatrixType, VectorType> baseSolverStep_;
-  BlockGSStep<MatrixType, VectorType> baseSolverStep_;
-  EnergyNorm<MatrixType, VectorType> baseEnergyNorm_;
-  LoopSolver<VectorType> baseSolver_;
-
-  ProjectedBlockGSStep<MatrixType, VectorType> presmoother_;
-  ProjectedBlockGSStep<MatrixType, VectorType> postsmoother_;
-  std::shared_ptr<Step> multigridStep_;
-
-  std::vector<std::shared_ptr<TransferOperator>> transferOperators_;
-};
-#endif
diff --git a/src/spatial-solving/solverfactory_tmpl_old.cc b/src/spatial-solving/solverfactory_tmpl_old.cc
deleted file mode 100644
index 600132d31b71a6fda13c7d955374bf98d01f9412..0000000000000000000000000000000000000000
--- a/src/spatial-solving/solverfactory_tmpl_old.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef MY_DIM
-#error MY_DIM unset
-#endif
-
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
-
-
-#include <dune/tectonic/globalfriction.hh>
-
-template class SolverFactoryOld<DeformedGrid, GlobalFriction<Matrix, Vector>, Matrix, Vector>;
-
-/*template class SolverFactory<
-    MY_DIM, BlockNonlinearTNNMGProblem<ConvexProblem<
-                ZeroNonlinearity<LocalVector, LocalMatrix>, Matrix>>,
-    Grid>;*/
diff --git a/src/spatial-solving/tnnmg/CMakeLists.txt b/src/spatial-solving/tnnmg/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..25682fc9e6c4962dd1d531ad1e5917944aca91d3
--- /dev/null
+++ b/src/spatial-solving/tnnmg/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_custom_target(dune-tectonic_spatial-solving_tnnmg_src SOURCES
+  functional.hh
+  linearization.hh
+  linesearchsolver.hh
+  localbisectionsolver.hh
+  localproblem.hh
+  tnnmgstep.hh
+  zerononlinearity.hh
+)
diff --git a/src/spatial-solving/tnnmg/levelpatchpreconditioner.hh b/src/spatial-solving/tnnmg/levelpatchpreconditioner.hh
deleted file mode 100644
index bbe464fdec9c3d9db5c218cecdbe4c448cd06fad..0000000000000000000000000000000000000000
--- a/src/spatial-solving/tnnmg/levelpatchpreconditioner.hh
+++ /dev/null
@@ -1,261 +0,0 @@
-#ifndef LEVEL_PATCH_PRECONDITIONER_HH
-#define LEVEL_PATCH_PRECONDITIONER_HH
-
-#include <string>
-
-#include <dune/common/timer.hh>
-#include <dune/common/fvector.hh>
-#include <dune/common/bitsetvector.hh>
-
-#include <dune/solvers/iterationsteps/lineariterationstep.hh>
-
-#include <dune/faultnetworks/assemblers/globalfaultassembler.hh>
-#include <dune/faultnetworks/patchfactories/supportpatchfactory.hh>
-#include <dune/faultnetworks/localproblem.hh>
-#include <dune/faultnetworks/levelinterfacenetwork.hh>
-#include <dune/faultnetworks/utils/debugutils.hh>
-
-#include <dune/fufem/boundarypatch.hh>
-#include <dune/fufem/functiontools/boundarydofs.hh>
-
-
-template <class BasisType, class LocalAssembler, class LocalInterfaceAssembler, class MatrixType, class VectorType>
-class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorType> {
-
-public:
-    enum Mode {additive, multiplicative};
-    enum BoundaryMode {homogeneous, fromIterate};
-
-private:
-    typedef typename BasisType::GridView GridView;
-    typedef typename GridView::Grid GridType;
-
-    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork_;
-    const BasisType& patchLevelBasis_;
-    const LocalAssembler& localAssembler_;
-    const std::vector<std::shared_ptr<LocalInterfaceAssembler>>& localInterfaceAssemblers_;
-    const Mode mode_;
-
-    const GridType& grid_;
-    const int level_;
-    const BasisType basis_;
-
-    size_t patchDepth_;
-    BoundaryMode boundaryMode_;
-
-    MatrixType matrix_;
-    std::vector<std::shared_ptr<OscLocalProblem<MatrixType, VectorType>> > localProblems_;
-
-public:
-
-    // for each coarse patch given by patchLevelBasis: set up local problem, compute local correction
-    LevelPatchPreconditioner(const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork,
-                             const BasisType& patchLevelBasis,
-                             const LocalAssembler& localAssembler,
-                             const std::vector<std::shared_ptr<LocalInterfaceAssembler>>& localInterfaceAssemblers,
-                             const Mode mode = LevelPatchPreconditioner::Mode::additive) :
-          levelInterfaceNetwork_(levelInterfaceNetwork),
-          patchLevelBasis_(patchLevelBasis),
-          localAssembler_(localAssembler),
-          localInterfaceAssemblers_(localInterfaceAssemblers),
-          mode_(mode),
-          grid_(levelInterfaceNetwork_.grid()),
-          level_(levelInterfaceNetwork_.level()),
-          basis_(levelInterfaceNetwork_)
-    {
-        setPatchDepth();
-        setBoundaryMode();
-
-        assert(localInterfaceAssemblers_.size() == levelInterfaceNetwork_.size());
-    }
-
-    void build() {
-        // assemble stiffness matrix for entire level including all faults
-        GlobalFaultAssembler<BasisType, BasisType> globalFaultAssembler(basis_, basis_, levelInterfaceNetwork_);
-        globalFaultAssembler.assembleOperator(localAssembler_, localInterfaceAssemblers_, matrix_);
-
-        // set boundary conditions
-        Dune::BitSetVector<1> globalBoundaryDofs;
-        BoundaryPatch<GridView> boundaryPatch(levelInterfaceNetwork_.levelGridView(), true);
-        constructBoundaryDofs(boundaryPatch, basis_, globalBoundaryDofs);
-
-        typedef typename MatrixType::row_type RowType;
-        typedef typename RowType::ConstIterator ColumnIterator;
-
-        for(size_t i=0; i<globalBoundaryDofs.size(); i++) {
-            if(!globalBoundaryDofs[i][0])
-                continue;
-
-            RowType& row = matrix_[i];
-
-            ColumnIterator cIt    = row.begin();
-            ColumnIterator cEndIt = row.end();
-
-            for(; cIt!=cEndIt; ++cIt) {
-                row[cIt.index()] = 0;
-            }
-            row[i] = 1;
-        }
-
-        // init vertexInElements
-        const int dim = GridType::dimension;
-        typedef typename GridType::template Codim<0>::Entity EntityType;
-        std::vector<std::vector<EntityType>> vertexInElements;
-
-        const GridView& patchLevelGridView = patchLevelBasis_.getGridView();
-        vertexInElements.resize(patchLevelGridView.size(dim));
-        for (size_t i=0; i<vertexInElements.size(); i++) {
-            vertexInElements[i].resize(0);
-        }
-
-        typedef typename BasisType::LocalFiniteElement FE;
-        typedef  typename GridView::template Codim <0>::Iterator  ElementLevelIterator;
-        ElementLevelIterator endElemIt = patchLevelGridView.template end <0>();
-        for (ElementLevelIterator  it = patchLevelGridView. template begin <0>(); it!=endElemIt; ++it) {
-
-            // compute coarseGrid vertexInElements
-            const FE& coarseFE = patchLevelBasis_.getLocalFiniteElement(*it);
-
-            for (size_t i=0; i<coarseFE.localBasis().size(); ++i) {
-                int dofIndex = patchLevelBasis_.indexInGridView(*it, i);
-                vertexInElements[dofIndex].push_back(*it);
-            }
-        }
-
-        localProblems_.resize(vertexInElements.size());
-
-        std::cout << std::endl;
-        std::cout << "---------------------------------------------" << std::endl;
-        std::cout << "Initializing local fine grid corrections! Level: " << level_ << std::endl;
-
-        // init local fine level corrections
-        Dune::Timer timer;
-        timer.reset();
-        timer.start();
-
-        const int patchLevel = patchLevelBasis_.faultNetwork().level();
-        for (size_t i=0; i<vertexInElements.size(); i++) {
-            //std::cout << i << std::endl;
-            //std::cout << "---------------" << std::endl;
-
-            SupportPatchFactory<BasisType> patchFactory(patchLevelBasis_, basis_, patchLevel, level_, vertexInElements, i, patchDepth_);
-            std::vector<int>& localToGlobal = patchFactory.getLocalToGlobal();
-            Dune::BitSetVector<1>& boundaryDofs = patchFactory.getBoundaryDofs();
-            VectorType rhs;
-            rhs.resize(matrix_.N());
-            rhs = 0;
-
-            //print(localToGlobal, "localToGlobal: ");
-            //print(boundaryDofs, "boundaryDofs: ");
-
-            localProblems_[i] = std::make_shared<OscLocalProblem<MatrixType, VectorType>>(matrix_, rhs, localToGlobal, boundaryDofs);
-
-            /*
-            if ((i+1) % 10 == 0) {
-                std::cout << '\r' << std::floor((i+1.0)/patchLevelBasis_.size()*100) << " % done. Elapsed time: " << timer.elapsed() << " seconds. Predicted total setup time: " << timer.elapsed()/(i+1.0)*patchLevelBasis_.size() << " seconds." << std::flush;
-            }*/
-        }
-
-        std::cout << std::endl;
-        std::cout << "Total setup time: " << timer.elapsed() << " seconds." << std::endl;
-        std::cout << "---------------------------------------------" << std::endl;
-        timer.stop();
-    }
-
-    void setPatchDepth(const size_t patchDepth = 0) {
-        patchDepth_ = patchDepth;
-    }
-
-    void setBoundaryMode(const BoundaryMode boundaryMode = LevelPatchPreconditioner::BoundaryMode::homogeneous) {
-        boundaryMode_ = boundaryMode;
-    }
-
-    virtual void setProblem(const MatrixType& mat, VectorType& x, const VectorType& rhs) {
-        this->x_ = &x;
-        this->rhs_ = &rhs;
-        this->mat_ = Dune::stackobject_to_shared_ptr(mat);
-
-        for (size_t i=0; i<localProblems_.size(); i++) {
-            if (boundaryMode_ == BoundaryMode::homogeneous)
-                localProblems_[i]->updateRhs(rhs);
-            else
-                localProblems_[i]->updateRhsAndBoundary(rhs, x);
-        }
-    }
-
-    virtual void iterate() {
-        if (mode_ == additive)
-            iterateAdd();
-        else
-            iterateMult();
-    }
-
-    void iterateAdd() {
-        *(this->x_) = 0;	
-
-        VectorType it, x;
-        for (size_t i=0; i<localProblems_.size(); i++) {
-            localProblems_[i]->solve(it);
-            localProblems_[i]->prolong(it, x);
-
-            /*if (i==5) {
-                writeToVTK(basis_, x, "/storage/mi/podlesny/data/faultnetworks/iterates/", "exactvertexdata_patchDepth_"+std::to_string(patchDepth_));
-            }*/
-
-            *(this->x_) += x;
-        }
-    }
-
-    void iterateMult() {
-        *(this->x_) = 0;
-
-        VectorType it, x;
-        for (size_t i=0; i<localProblems_.size(); i++) {
-            VectorType updatedRhs(*(this->rhs_));
-            matrix_.mmv(*(this->x_), updatedRhs);
-
-            //step(i);
-            //print(updatedRhs, "localRhs: ");
-            //writeToVTK(basis_, updatedRhs, "/storage/mi/podlesny/data/faultnetworks/rhs/local", "exactvertexdata_step_"+std::to_string(i));
-
-            if (boundaryMode_ == BoundaryMode::homogeneous)
-                localProblems_[i]->updateRhs(updatedRhs);
-            else
-                localProblems_[i]->updateRhsAndBoundary(updatedRhs, *(this->x_));
-
-            localProblems_[i]->solve(it);
-            localProblems_[i]->prolong(it, x);
-
-
-            //print(it, "it: ");
-            //print(x, "x: ");
-
-            //writeToVTK(basis_, x, "/storage/mi/podlesny/data/faultnetworks/sol/local", "exactvertexdata_step_"+std::to_string(i));
-
-            /*if (i==5) {
-                writeToVTK(basis_, x, "/storage/mi/podlesny/data/faultnetworks/iterates/", "exactvertexdata_patchDepth_"+std::to_string(patchDepth_));
-            }*/
-
-            *(this->x_) += x;
-        }
-    }
-
-    const BasisType& basis() const {
-        return basis_;
-    }
-
-    const GridView& gridView() const {
-        return basis_.getGridView();
-    }
-
-    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork() const {
-        return levelInterfaceNetwork_;
-    }
-
-    size_t size() const {
-        return localProblems_.size();
-    }
-};
-
-#endif
-
diff --git a/src/spatial-solving/tnnmg/supportpatchfactory.hh b/src/spatial-solving/tnnmg/supportpatchfactory.hh
deleted file mode 100644
index 20754c0d5c371b5d9a715778a2b9d7e87cace00d..0000000000000000000000000000000000000000
--- a/src/spatial-solving/tnnmg/supportpatchfactory.hh
+++ /dev/null
@@ -1,253 +0,0 @@
-#ifndef SUPPORT_PATCH_FACTORY_HH
-#define SUPPORT_PATCH_FACTORY_HH
-
-#include<queue>
-
-#include <dune/common/bitsetvector.hh>
-#include <dune/common/fvector.hh>
-
-#include <dune/fufem/referenceelementhelper.hh>
-#include <dune/grid/common/mcmgmapper.hh>
-
-#include <dune/faultnetworks/hierarchicleveliterator.hh>
-
-template <class BasisType>
-class SupportPatchFactory
-{
-    protected:
-        typedef typename BasisType::GridView GV;
-        typedef typename BasisType::LocalFiniteElement LFE;
-	
-	typedef typename GV::Grid GridType;
-	typedef typename GridType::ctype ctype;
-	static const int dim = GridType::dimension;
-	typedef typename GridType::template Codim<0>::Entity Element;
-	typedef typename GridType::template Codim<dim>::Entity Vertex;
-
-	typedef HierarchicLevelIterator<GridType> HierarchicLevelIteratorType;
-	typedef typename Dune::LevelMultipleCodimMultipleGeomTypeMapper<GridType,  Dune::MCMGElementLayout > ElementMapper;
-	
-    private:
-	const BasisType& coarseBasis_;
-	const BasisType& fineBasis_;
-	
-	const int coarseLevel_;
-	const int fineLevel_;
-	
- 	const std::vector< std::vector <Element>>& vertexInElements_;
-	const int centerVertexIdx_;
-	const int patchDepth_;
-
-  
-	const GridType& grid;
-	const GV& coarseGridView;
-	const GV& fineGridView;
-	
-	std::vector<int> localToGlobal;
-	Dune::BitSetVector<1> boundaryDofs;
-	std::vector<Element> fineRegionElements;
-	
-	ElementMapper coarseMapper;
-
-    public:
-        //setup 
-    SupportPatchFactory(const BasisType& coarseBasis, const BasisType& fineBasis, const int coarseLevel, const int fineLevel, const std::vector< std::vector <Element>>& vertexInElements, const int centerVertexIdx, const int patchDepth) :
-            coarseBasis_(coarseBasis),
-            fineBasis_(fineBasis),
-            coarseLevel_(coarseLevel),
-            fineLevel_(fineLevel),
-            vertexInElements_(vertexInElements),
-            centerVertexIdx_(centerVertexIdx),
-            patchDepth_(patchDepth),
-            grid(coarseBasis_.getGridView().grid()),
-	    coarseGridView(coarseBasis_.getGridView()),
-	    fineGridView(fineBasis_.getGridView()),
-	    coarseMapper(grid, coarseLevel_)
-        {   
-	    fineRegionElements.resize(0);
-	  
-            std::vector<Element> coarseElements;
-	    Dune::BitSetVector<1> visited(coarseMapper.size());
-	    Dune::BitSetVector<1> vertexVisited(vertexInElements_.size());
-            visited.unsetAll();
-	    vertexVisited.unsetAll();
-	    
-	    std::set<int> localDofs;
-	    std::set<int> localBoundaryDofs;
-
-	    addVertexSupport(centerVertexIdx_, coarseElements, visited, vertexVisited);
-	    
-	    // construct coarse patch
-	    for (int depth=1; depth<patchDepth_; depth++) {
-		std::vector<Element> coarseElementNeighbors;
-		
-		for (size_t i=0; i<coarseElements.size(); ++i) {
-		    const Element& elem = coarseElements[i];     
-		    const LFE& coarseLFE = coarseBasis_.getLocalFiniteElement(elem);
-	      
-		    for (size_t j=0; j<coarseLFE.localBasis().size(); ++j) {
-            int dofIndex = coarseBasis_.indexInGridView(elem, j);
-			
-			if (!vertexVisited[dofIndex][0]) {
-			    addVertexSupport(dofIndex, coarseElementNeighbors, visited, vertexVisited);
-			}
-		    }
-		}	        
-		    
-		coarseElements.insert(coarseElements.begin(), coarseElementNeighbors.begin(), coarseElementNeighbors.end());
-	    }
-	    
-
-	    // construct fine patch
-	    for (size_t i=0; i<coarseElements.size(); ++i) {
-		const Element& elem = coarseElements[i];
-		addFinePatchElements(elem, visited, localDofs, localBoundaryDofs);
-	    }
-
-	 
-	 
-        localToGlobal.resize(localDofs.size());
-	    boundaryDofs.resize(localDofs.size());
-	    boundaryDofs.unsetAll();
-	    
-	    std::set<int>::iterator dofIt = localDofs.begin();
-	    std::set<int>::iterator dofEndIt = localDofs.end();
-	    size_t i=0;
-	    for (; dofIt != dofEndIt; ++dofIt) {
-		int localDof = *dofIt;
-		localToGlobal[i] = localDof;
-		
-		if (localBoundaryDofs.count(localDof)) {
-		    boundaryDofs[i][0] = true;
-		}
-		i++;
-	    }
-	}
-
-	std::vector<int>& getLocalToGlobal() {
-	    return localToGlobal;
-	}
-	
-	std::vector<Element>& getRegionElements() {
-	    return fineRegionElements;
-	}
-	
-	Dune::BitSetVector<1>& getBoundaryDofs() {
-	    return boundaryDofs;
-	}
-	
-	
-private:
-
-
-    void print(const Dune::BitSetVector<1>& x, std::string message){
-       std::cout << message << std::endl;
-       for (size_t i=0; i<x.size(); i++) {
-           std::cout << x[i][0] << " ";
-       }
-       std::cout << std::endl << std::endl;
-   }
-
-	void addVertexSupport(const int vertexIdx, std::vector<Element>& coarseElements, Dune::BitSetVector<1>& visited, Dune::BitSetVector<1>& vertexVisited) {
-	    const std::vector<Element>& vertexInElement = vertexInElements_[vertexIdx];
-	    
-	    for (size_t i=0; i<vertexInElement.size(); i++) {
-		const Element& elem = vertexInElement[i];
-		const int elemIdx = coarseMapper.index(elem);
-		
-		if (!visited[elemIdx][0]) {
-		    coarseElements.push_back(elem);
-		    visited[elemIdx][0] = true;
-		}
-	    }
-	    vertexVisited[vertexIdx][0] = true;
-	}
-      
-	bool containsInsideSubentity(const Element& elem, const typename GridType::LevelIntersection& intersection, int subEntity, int codim) {
-	    return ReferenceElementHelper<double, dim>::subEntityContainsSubEntity(elem.type(), intersection.indexInInside(), 1, subEntity, codim);
-	}
-      
-      
-	void addFinePatchElements(const Element& coarseElem, const Dune::BitSetVector<1>& inCoarsePatch, std::set<int>& localDofs, std::set<int>& localBoundaryDofs) {
-	    HierarchicLevelIteratorType endHierIt(grid, coarseElem, HierarchicLevelIteratorType::PositionFlag::end, fineLevel_);
-	    for (HierarchicLevelIteratorType hierIt(grid, coarseElem, HierarchicLevelIteratorType::PositionFlag::begin, fineLevel_); hierIt!=endHierIt; ++hierIt) {
-
-		const Element& fineElem = *hierIt;
-		fineRegionElements.push_back(fineElem);
-
-		addLocalDofs(coarseElem, fineElem, inCoarsePatch, localDofs, localBoundaryDofs);
-	    }
-	}	  
-	
-	void addLocalDofs(const Element& coarseElem, const Element& fineElem, const Dune::BitSetVector<1>& inCoarsePatch, std::set<int>& localDofs, std::set<int>& localBoundaryDofs) {
-	    const LFE& fineLFE = fineBasis_.getLocalFiniteElement(fineElem);
-	    
-        /*
-	    const auto& fineGeometry = fineElem.geometry();
-	    const auto& coarseGeometry = coarseElem.geometry();
-		
-        const auto& ref = Dune::ReferenceElements<ctype, dim>::general(fineElem.type()); */
-	    
-	    // insert local dofs
-	    for (size_t i=0; i<fineLFE.localBasis().size(); ++i) {
-		int dofIndex = fineBasis_.index(fineElem, i);
-		localDofs.insert(dofIndex);
-	    }
-
-	    
-	    // search for parts of the global and inner boundary 
-	    typename GridType::LevelIntersectionIterator neighborIt = fineGridView.ibegin(fineElem);
-	    typename GridType::LevelIntersectionIterator neighborItEnd = fineGridView.iend(fineElem);
-	    for (; neighborIt!=neighborItEnd; ++neighborIt) {
-		const typename GridType::LevelIntersection& intersection = *neighborIt;
-
-		bool isInnerBoundary = false;
-		if (intersection.neighbor()) {
-		    Element outsideFather = intersection.outside();
-		    
-		    while (outsideFather.level()>coarseLevel_) {
-			outsideFather = outsideFather.father();
-		    }
-		    
-		    if (!inCoarsePatch[coarseMapper.index(outsideFather)][0]) {
-			isInnerBoundary = true;
-		    }
-		}
-		
-		if (intersection.boundary() or isInnerBoundary) {
-		    typedef typename LFE::Traits::LocalCoefficientsType LocalCoefficients;
-		    const LocalCoefficients* localCoefficients = &fineBasis_.getLocalFiniteElement(intersection.inside()).localCoefficients();
-
-		    for (size_t i=0; i<localCoefficients->size(); i++) {
-			unsigned int entity = localCoefficients->localKey(i).subEntity();
-			unsigned int codim  = localCoefficients->localKey(i).codim();
-
-			if (containsInsideSubentity(fineElem, intersection, entity, codim))
-			    localBoundaryDofs.insert(fineBasis_.index(intersection.inside(), i));
-		    } 
-		}
-	    }	
-	    
-        /* add interior coarse level vertices to boundary dofs
-	    for(int i=0; i<coarseGeometry.corners(); ++i) {
-		const auto& local = fineGeometry.local(coarseGeometry.corner(i));
-		    
-		if (!ref.checkInside(local))
-		    continue;
-		
-		const int localBasisSize = fineLFE.localBasis().size(); 
-		std::vector<Dune::FieldVector<double, 1>, std::allocator<Dune::FieldVector<double, 1> > > localBasisRep(localBasisSize);
-		fineLFE.localBasis().evaluateFunction(local, localBasisRep);
-		
-		for(int k=0; k<localBasisSize; ++k) {
-		    if (localBasisRep[k]==1) {
-			int dofIndex = fineBasis_.index(fineElem, k);
-			localBoundaryDofs.insert(dofIndex);
-			break;
-		    }	
-		}
-        }   */
-
-	}
-};
-#endif
diff --git a/src/tests/gridgluefrictiontest.cc b/src/tests/gridgluefrictiontest.cc
index c33a84937204f1649228608d9fb08f640e034fc9..d31f58d3490ba44c1012a520af030400f1787ef3 100644
--- a/src/tests/gridgluefrictiontest.cc
+++ b/src/tests/gridgluefrictiontest.cc
@@ -399,6 +399,43 @@ int main(int argc, char *argv[]) { try {
         std::cout << "---------"<< std::endl;
     }*/
 
+    for (const auto& elem : elements(gridView0)) {
+        std::cout << "seed element corners:" << std::endl;
+
+        const auto& eRefElement = Dune::ReferenceElements<double, dim>::general(elem.type());
+        size_t vertices = eRefElement.size(dim);
+
+        for (size_t j=0; j<vertices; j++) {
+            print(elem.geometry().corner(j), "corner: ");
+        }
+
+
+        for (auto&& is : intersections(gridView0, elem)) {
+            const auto& isGeo = is.geometry();
+
+            if (!is.neighbor())
+                continue;
+
+            std::cout << "neighbor corners:" << std::endl;
+
+            const auto& outside = is.outside();
+
+            const auto& refElement = Dune::ReferenceElements<double, dim>::general(outside.type());
+            size_t nVertices = refElement.size(dim);
+
+            const auto& isRefElement = Dune::ReferenceElements<double, dim-1>::general(isGeo.type());
+
+            for (size_t j=0; j<nVertices; j++) {
+                print(outside.geometry().corner(j), "corner: ");
+                const auto& local = elem.geometry().local(outside.geometry().corner(j));
+
+                print(local, "local:");
+            }
+
+        }
+
+        break;
+    }
 
 
     bool passed = true;