From b40abd4330487b226490c61afbbcd0ac85289734 Mon Sep 17 00:00:00 2001
From: podlesny <podlesny@mi.fu-berlin.de>
Date: Thu, 4 Jul 2019 18:53:42 +0200
Subject: [PATCH] .

---
 src/CMakeLists.txt                            |   2 +-
 src/data-structures/contactnetwork.cc         |   2 +-
 src/data-structures/program_state.hh          |  10 +-
 src/factories/stackedblocksfactory.cc         | 208 +++++++-----
 src/factories/stackedblocksfactory.hh         |  49 +--
 src/factories/stackedblocksfactory_tmpl.cc    |   3 +-
 src/multi-body-problem-2D.cfg                 |   3 +
 src/multi-body-problem.cc                     |  51 ++-
 src/multi-body-problem.cfg                    |  10 +-
 src/spatial-solving/fixedpointiterator.cc     |   6 +-
 src/spatial-solving/fixedpointiterator.hh     |   2 +
 .../preconditioners/CMakeLists.txt            |   1 +
 .../levelglobalpreconditioner.hh              | 132 ++------
 .../levelpatchpreconditioner.hh               |  78 ++---
 .../multilevelpatchpreconditioner.hh          | 209 ++++++------
 .../preconditioners/nbodycontacttransfer.cc   | 297 ++++++++++++++++++
 .../preconditioners/nbodycontacttransfer.hh   |  88 ++++++
 .../preconditioners/supportpatchfactory.hh    |  10 +-
 src/spatial-solving/solverfactory.cc          |  16 +-
 src/spatial-solving/solverfactory.hh          |  22 +-
 src/time-stepping/adaptivetimestepper.cc      |  18 +-
 src/time-stepping/adaptivetimestepper.hh      |   7 +-
 src/time-stepping/coupledtimestepper.cc       |   7 +-
 src/time-stepping/coupledtimestepper.hh       |   3 +-
 24 files changed, 788 insertions(+), 446 deletions(-)
 create mode 100644 src/spatial-solving/preconditioners/nbodycontacttransfer.cc
 create mode 100644 src/spatial-solving/preconditioners/nbodycontacttransfer.hh

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6bf43fe7..26276d41 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -33,7 +33,7 @@ set(MSW_SOURCE_FILES
   data-structures/enumparser.cc
   #factories/cantorfactory.cc
   factories/threeblocksfactory.cc
-  #factories/stackedblocksfactory.cc
+  factories/stackedblocksfactory.cc
   io/vtk.cc
   io/hdf5/frictionalboundary-writer.cc
   io/hdf5/iteration-writer.cc
diff --git a/src/data-structures/contactnetwork.cc b/src/data-structures/contactnetwork.cc
index 81d9f8a9..4e66cf76 100644
--- a/src/data-structures/contactnetwork.cc
+++ b/src/data-structures/contactnetwork.cc
@@ -24,7 +24,7 @@ ContactNetwork<HostGridType, VectorType>::ContactNetwork(
     levelContactNetworks_(nLevels),
     bodies_(nBodies),
     couplings_(nCouplings),
-    frictionBoundaries_(nCouplings),
+    frictionBoundaries_(nBodies),
     stateEnergyNorms_(nBodies),
     nBodyAssembler_(nBodies, nCouplings)
 {}
diff --git a/src/data-structures/program_state.hh b/src/data-structures/program_state.hh
index 9c5dd4af..1e8f679d 100644
--- a/src/data-structures/program_state.hh
+++ b/src/data-structures/program_state.hh
@@ -151,10 +151,10 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
 
       // set up functional and TNMMG solver
       using Functional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, typename Matrix::field_type>;
-      Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), lower, upper);
+      Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), lower, upper); //TODO
 
-      using Factory = SolverFactory<Functional, Dune::BitSetVector<dims>>;
-      Factory factory(parset.sub("solver.tnnmg"), J, _dirichletNodes);
+    //  using Factory = SolverFactory<Functional, Dune::BitSetVector<dims>>;
+    //  Factory factory(parset.sub("solver.tnnmg"), J, _dirichletNodes);
 
    /*   std::vector<Dune::BitSetVector<dims>> bodyDirichletNodes;
       nBodyAssembler.postprocess(_dirichletNodes, bodyDirichletNodes);
@@ -166,7 +166,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
       print(totalX, "totalX: ");
       print(totalRhs, "totalRhs: ");*/
 
-      auto tnnmgStep = factory.step();
+     /* auto tnnmgStep = factory.step();
       factory.setProblem(totalX);
 
       const EnergyNorm<Matrix, Vector> norm(bilinearForm);
@@ -184,7 +184,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
 
       Vector res = totalRhs;
       bilinearForm.mmv(tnnmgStep->getSol(), res);
-      std::cout << "TNNMG Res - energy norm: " << norm.operator ()(res) << std::endl;
+      std::cout << "TNNMG Res - energy norm: " << norm.operator ()(res) << std::endl; */
 
       // TODO: remove after debugging
   /*    using DeformedGridType = typename LevelContactNetwork<GridType, dims>::DeformedGridType;
diff --git a/src/factories/stackedblocksfactory.cc b/src/factories/stackedblocksfactory.cc
index 5a2aaaff..9f7fc32a 100644
--- a/src/factories/stackedblocksfactory.cc
+++ b/src/factories/stackedblocksfactory.cc
@@ -14,75 +14,97 @@
 
 #include "stackedblocksfactory.hh"
 
-template <class GridType, int dims>
-void StackedBlocksFactory<GridType, dims>::setBodies() {
-    // set up cuboid geometries
 
+template <class HostGridType, class VectorType>
+void StackedBlocksFactory<HostGridType, VectorType>::setBodies() {
+
+    // set up cuboid geometries
     double const length = 1.00;
-    double const width = 0.27;
-    double const weakLength = 0.20;
+    double const height = 0.27;
+    double const weakLength = 0.60;
 
-    std::vector<LocalVector> origins(this->bodyCount_);
-    std::vector<LocalVector> lowerWeakOrigins(this->bodyCount_);
-    std::vector<LocalVector> upperWeakOrigins(this->bodyCount_);
+    std::vector<GlobalCoords> origins(this->bodyCount_);
+
+    const auto& subParset = this->parset_.sub("boundary.friction.weakening");
 
 #if MY_DIM == 3
         double const depth = 0.60;
 
+        auto weakBound = [&] (const GlobalCoords& origin) {
+            GlobalCoords h = {origin[0] + weakLength, origin[1], origin[2]};
+            return h;
+        };
+
         origins[0] = {0,0,0};
-        lowerWeakOrigins[0] = {0.2,0,0};
-        upperWeakOrigins[0] = {0.2,width,0};
+        GlobalCoords lowerWeakOrigin = {0.2, 0, 0};
+        GlobalCoords upperWeakOrigin = {0.2, height, 0};
+
+        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], length, height, depth);
+        cuboidGeometries_[0]->addWeakeningPatch(subParset, upperWeakOrigin, weakBound(upperWeakOrigin));
 
-        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lowerWeakOrigins[0], upperWeakOrigins[0], 0.0, weakLength, length, width, depth);
         for (size_t i=1; i<this->bodyCount_-1; i++) {
-            origins[i] = cuboidGeometries_[i-1]->D;
-            lowerWeakOrigins[i] = {0.6,i*width,0};
-            upperWeakOrigins[i] = {0.6,(i+1)*width,0};
+            origins[i] = cuboidGeometries_[i-1]->upperLeft();
+            GlobalCoords lowerWeakOrigin_i = lowerWeakOrigin + origins[i];
+            GlobalCoords upperWeakOrigin_i = upperWeakOrigin + origins[i];
 
-            cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], lowerWeakOrigins[i], upperWeakOrigins[i], weakLength, weakLength, length, width, depth);
+            cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], length, height, depth);
+            cuboidGeometries_[i]->addWeakeningPatch(subParset, upperWeakOrigin_i, weakBound(upperWeakOrigin_i));
+            cuboidGeometries_[i]->addWeakeningPatch(subParset, lowerWeakOrigin_i, weakBound(lowerWeakOrigin_i));
         }
+
         const size_t idx = this->bodyCount_-1;
-        origins[idx] = cuboidGeometries_[idx-1]->D;
-        lowerWeakOrigins[idx] = {0.6,idx*width,0};
-        upperWeakOrigins[idx] = {0.6,(idx+1)*width,0};
+        origins[idx] = cuboidGeometries_[idx-1]->upperLeft();
+        lowerWeakOrigin += origins[idx];
 
-        cuboidGeometries_[idx] = std::make_shared<CuboidGeometry>(origins[idx], lowerWeakOrigins[idx], upperWeakOrigins[idx], weakLength, 0.0, length, width, depth);
+        cuboidGeometries_[idx] = std::make_shared<CuboidGeometry>(origins[idx], length, height, depth);
+        cuboidGeometries_[idx]->addWeakeningPatch(subParset, lowerWeakOrigin, weakBound(lowerWeakOrigin));
 #elif MY_DIM == 2
+        auto weakBound = [&] (const GlobalCoords& origin) {
+            GlobalCoords h = {origin[0] + weakLength, origin[1]};
+            return h;
+        };
+
         origins[0] = {0,0};
-        lowerWeakOrigins[0] = {0.2,0};
-        upperWeakOrigins[0] = {0.6,width};
+        GlobalCoords lowerWeakOrigin = {0.2, 0};
+        GlobalCoords upperWeakOrigin = {0.2, height};
+
+        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], length, height);
+        cuboidGeometries_[0]->addWeakeningPatch(subParset, upperWeakOrigin, weakBound(upperWeakOrigin));
 
-        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lowerWeakOrigins[0], upperWeakOrigins[0], 0.0, weakLength, length, width);
         for (size_t i=1; i<this->bodyCount_-1; i++) {
-            origins[i] = cuboidGeometries_[i-1]->D;
-            lowerWeakOrigins[i] = {0.6,i*width};
-            upperWeakOrigins[i] = {0.6,(i+1)*width};
+            origins[i] = cuboidGeometries_[i-1]->upperLeft();
+            GlobalCoords lowerWeakOrigin_i = lowerWeakOrigin + origins[i];
+            GlobalCoords upperWeakOrigin_i = upperWeakOrigin + origins[i];
 
-            cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], lowerWeakOrigins[i], upperWeakOrigins[i], weakLength, weakLength, length, width);
+            cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], length, height);
+
+
+            cuboidGeometries_[i]->addWeakeningPatch(subParset, upperWeakOrigin_i, weakBound(upperWeakOrigin_i));
+            cuboidGeometries_[i]->addWeakeningPatch(subParset, lowerWeakOrigin_i, weakBound(lowerWeakOrigin_i));
         }
+
         const size_t idx = this->bodyCount_-1;
-        origins[idx] = cuboidGeometries_[idx-1]->D + LocalVector({0.25,0});
-        lowerWeakOrigins[idx] = {0.6,idx*width};
-        upperWeakOrigins[idx] = {0.6,(idx+1)*width};
+        origins[idx] = cuboidGeometries_[idx-1]->upperLeft();
+        lowerWeakOrigin += origins[idx];
 
-        cuboidGeometries_[idx] = std::make_shared<CuboidGeometry>(origins[idx], lowerWeakOrigins[idx], upperWeakOrigins[idx], weakLength, 0.0, 5.0/8*length, width);
+        cuboidGeometries_[idx] = std::make_shared<CuboidGeometry>(origins[idx], length, height);
+        cuboidGeometries_[idx]->addWeakeningPatch(subParset, lowerWeakOrigin, weakBound(lowerWeakOrigin));
 #else
 #error CuboidGeometry only supports 2D and 3D!"
 #endif
 
     // set up reference grids
-    gridConstructor_ = new GridsConstructor<GridType>(cuboidGeometries_);
+    gridConstructor_ = std::make_unique<GridsConstructor<HostGridType>>(cuboidGeometries_);
     auto& grids = gridConstructor_->getGrids();
 
     for (size_t i=0; i<this->bodyCount_; i++) {
         const auto& cuboidGeometry = *cuboidGeometries_[i];
 
         // define weak patch and refine grid
-        auto lowerWeakPatch = lowerWeakPatches_[i] = std::make_shared<ConvexPolyhedron<LocalVector>>();
-        auto upperWeakPatch = upperWeakPatches_[i] = std::make_shared<ConvexPolyhedron<LocalVector>>();
-        getWeakPatch<LocalVector>(this->parset_.sub("boundary.friction.weakening"), cuboidGeometry, *lowerWeakPatch, *upperWeakPatch);
-        refine(*grids[i], *lowerWeakPatch, this->parset_.template get<double>("boundary.friction.smallestDiameter"), cuboidGeometry.lengthScale);
-        refine(*grids[i], *upperWeakPatch, this->parset_.template get<double>("boundary.friction.smallestDiameter"), cuboidGeometry.lengthScale);
+        const auto& weakeningRegions = cuboidGeometry.weakeningRegions();
+        for (size_t j=0; j<weakeningRegions.size(); j++) {
+            refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale);
+        }
 
         // determine minDiameter and maxDiameter
         double minDiameter = std::numeric_limits<double>::infinity();
@@ -98,96 +120,116 @@ void StackedBlocksFactory<GridType, dims>::setBodies() {
     }
 
     for (size_t i=0; i<this->bodyCount_; i++) {
-        this->bodies_[i] = std::make_shared<typename Base::Body>(bodyData_, grids[i]);
+        this->bodies_[i] = std::make_shared<typename Base::LeafBody>(bodyData_, grids[i]);
     }
 }
 
-template <class GridType, int dims>
-void StackedBlocksFactory<GridType, dims>::setCouplings() {
-    const auto deformedGrids = this->levelContactNetwork_.deformedGrids();
 
+template <class HostGridType, class VectorType>
+void StackedBlocksFactory<HostGridType, VectorType>::setCouplings() {
     for (size_t i=0; i<this->bodyCount_; i++) {
         const auto& cuboidGeometry = *cuboidGeometries_[i];
-        leafFaces_[i] = std::make_shared<LeafFaces>(this->levelContactNetwork_.leafView(i), cuboidGeometry);
-        levelFaces_[i] = std::make_shared<LevelFaces>(this->levelContactNetwork_.levelView(i), cuboidGeometry);
+
+        leafFaces_[i] = std::make_shared<LeafFaces>(this->bodies_[i]->gridView(), cuboidGeometry);
+        levelFaces_[i] = std::make_shared<LevelFaces>(this->bodies_[i]->grid()->levelGridView(0), cuboidGeometry);
     }
 
     auto contactProjection = std::make_shared<Dune::Contact::NormalProjection<LeafBoundaryPatch>>();
     std::shared_ptr<typename Base::FrictionCouplingPair::BackEndType> backend = nullptr;
+
+
     for (size_t i=0; i<this->couplings_.size(); i++) {
       auto& coupling = this->couplings_[i];
       coupling = std::make_shared<typename Base::FrictionCouplingPair>();
 
       nonmortarPatch_[i] = std::make_shared<LevelBoundaryPatch>(levelFaces_[i]->upper);
       mortarPatch_[i] = std::make_shared<LevelBoundaryPatch>(levelFaces_[i+1]->lower);
+      weakPatches_[i] = std::make_shared<WeakeningRegion>(cuboidGeometries_[i]->weakeningRegions()[0]);
 
       coupling->set(i, i+1, nonmortarPatch_[i], mortarPatch_[i], 0.1, Base::FrictionCouplingPair::CouplingType::STICK_SLIP, contactProjection, backend);
-      coupling->setWeakeningPatch(upperWeakPatches_[i]);
-      coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<LocalVector>>(this->parset_.sub("boundary.friction"), *upperWeakPatches_[i], CuboidGeometry::lengthScale));
+      coupling->setWeakeningPatch(weakPatches_[i]);
+      coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale));
     }
 }
 
-template <class GridType, int dims>
-void StackedBlocksFactory<GridType, dims>::setBoundaryConditions() {
-    using LeafBoundaryCondition = BoundaryCondition<DeformedLeafGridView, dims>;
+template <class HostGridType, class VectorType>
+void StackedBlocksFactory<HostGridType, VectorType>::setLevelBodies() {
+    const size_t nBodies = this->bodyCount_;
 
-    using Function = Dune::VirtualFunction<double, double>;
-    std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>();
-    std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>();
-
-    const double lengthScale = CuboidGeometry::lengthScale;
+    size_t maxLevel = 0;
+    std::vector<size_t> maxLevels(nBodies);
+    for (size_t i=0; i<nBodies; i++) {
+        const size_t bodyMaxLevel = this->bodies_[i]->grid()->maxLevel();
+        maxLevels[i] = bodyMaxLevel;
+        maxLevel = std::max(maxLevel, bodyMaxLevel);
+    }
 
-    for (size_t i=0; i<this->bodyCount_; i++) {
-      const auto& body = this->levelContactNetwork_.body(i);
-      const auto& leafVertexCount = body->leafVertexCount();
+    for (int l=maxLevel; l>=0; l--) {
+        this->contactNetwork_.addLevel(maxLevels, l);
 
-      std::cout << "Grid" << i << " Number of DOFs: " << leafVertexCount << std::endl;
+        for (size_t i=0; i<nBodies; i++) {
+            maxLevels[i]--;
+        }
+    }
+}
 
-      // Neumann boundary
-      std::shared_ptr<LeafBoundaryCondition> neumannBoundary = std::make_shared<LeafBoundaryCondition>(std::make_shared<LeafBoundaryPatch>(body->leafView()), neumannFunction, "neumann");
-      body->addBoundaryCondition(neumannBoundary);
 
-      // right Dirichlet Boundary
-      // identify Dirichlet nodes on leaf level
-      std::shared_ptr<Dune::BitSetVector<dims>> velocityDirichletNodes = std::make_shared<Dune::BitSetVector<dims>>(leafVertexCount);
-      for (int j=0; j<leafVertexCount; j++) {
-          if (leafFaces_[i]->upper.containsVertex(j))
-              (*velocityDirichletNodes)[j][0] = true;
+template <class HostGridType, class VectorType>
+void StackedBlocksFactory<HostGridType, VectorType>::setBoundaryConditions() {
+    using LeafBoundaryCondition = BoundaryCondition<LeafGridView, dim>;
 
-          #if MY_DIM == 3 //TODO: wrong, needs revision
-          if (leafFaces_[i]->front.containsVertex(j) || leafFaces_[i]->back.containsVertex(j))
-              zeroDirichletNodes->at(j)[2] = true;
-          #endif
-      }
+    using Function = Dune::VirtualFunction<double, double>;
+    std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>();
+    std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>();
 
-                  if (i>0) {
-      std::shared_ptr<LeafBoundaryCondition> velocityDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet");
+    const double lengthScale = CuboidGeometry::lengthScale;
 
-      velocityDirichletBoundary->setBoundaryPatch(body->leafView(), velocityDirichletNodes);
+    for (size_t i=0; i<this->bodyCount_; i++) {
+        const auto& body = this->contactNetwork_.body(i);
+        const auto& leafVertexCount = body->nVertices();
+
+        // Neumann boundary
+        std::shared_ptr<LeafBoundaryCondition> neumannBoundary = std::make_shared<LeafBoundaryCondition>(std::make_shared<LeafBoundaryPatch>(body->gridView()), neumannFunction, "neumann");
+        body->addBoundaryCondition(neumannBoundary);
+
+        // upper Dirichlet Boundary
+        // identify Dirichlet nodes on leaf level
+        if (i==this->bodyCount_-1) {
+            std::shared_ptr<Dune::BitSetVector<dim>> velocityDirichletNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount);
+            for (int j=0; j<leafVertexCount; j++) {
+                if (leafFaces_[i]->upper.containsVertex(j))
+                    (*velocityDirichletNodes)[j][0] = true;
+
+                #if MY_DIM == 3 //TODO: wrong, needs revision
+                if (leafFaces_[i]->front.containsVertex(j) || leafFaces_[i]->back.containsVertex(j))
+                    zeroDirichletNodes->at(j)[2] = true;
+                #endif
+            }
 
-        velocityDirichletBoundary->setBoundaryFunction(velocityDirichletFunction);
-              body->addBoundaryCondition(velocityDirichletBoundary);
-      } else {
-        //velocityDirichletBoundary->setBoundaryFunction(neumannFunction);
-      }
+            std::shared_ptr<LeafBoundaryCondition> velocityDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet");
 
+            velocityDirichletBoundary->setBoundaryPatch(body->gridView(), velocityDirichletNodes);
+            velocityDirichletBoundary->setBoundaryFunction(velocityDirichletFunction);
+            body->addBoundaryCondition(velocityDirichletBoundary);
+        } else {
 
+        }
     }
 
     // lower Dirichlet Boundary
-    const auto& firstBody = this->levelContactNetwork_.body(0);
-    const auto& firstLeafVertexCount = firstBody->leafVertexCount();
-    std::shared_ptr<Dune::BitSetVector<dims>> zeroDirichletNodes = std::make_shared<Dune::BitSetVector<dims>>(firstLeafVertexCount);
+    const auto& firstBody = this->contactNetwork_.body(0);
+    const auto& firstLeafVertexCount = firstBody->nVertices();
+    std::shared_ptr<Dune::BitSetVector<dim>> zeroDirichletNodes = std::make_shared<Dune::BitSetVector<dim>>(firstLeafVertexCount);
     for (int j=0; j<firstLeafVertexCount; j++) {
         if (leafFaces_[0]->lower.containsVertex(j)) {
-            for (size_t d=0; d<dims; d++) {
+            for (size_t d=0; d<dim; d++) {
               (*zeroDirichletNodes)[j][d] = true;
             }
         }
     }
 
     std::shared_ptr<LeafBoundaryCondition> zeroDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet");
-    zeroDirichletBoundary->setBoundaryPatch(firstBody->leafView(), zeroDirichletNodes);
+    zeroDirichletBoundary->setBoundaryPatch(firstBody->gridView(), zeroDirichletNodes);
 
     std::shared_ptr<Function> zeroFunction = std::make_shared<NeumannCondition>();
     zeroDirichletBoundary->setBoundaryFunction(zeroFunction);
diff --git a/src/factories/stackedblocksfactory.hh b/src/factories/stackedblocksfactory.hh
index ed38c0ff..b9471853 100644
--- a/src/factories/stackedblocksfactory.hh
+++ b/src/factories/stackedblocksfactory.hh
@@ -7,38 +7,46 @@
 
 #include <dune/fufem/boundarypatch.hh>
 
-#include "levelcontactnetworkfactory.hh"
+#include "contactnetworkfactory.hh"
 
 #include "../multi-body-problem-data/mybody.hh"
 #include "../multi-body-problem-data/grid/mygrids.hh"
+#include "../multi-body-problem-data/grid/cuboidgeometry.hh"
 
-template <class GridType, int dims> class StackedBlocksFactory : public LevelContactNetworkFactory<GridType, dims>{
+template <class HostGridType, class VectorType> class StackedBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType>{
 private:
-    using Base = LevelContactNetworkFactory<GridType, dims>;
+    using Base = ContactNetworkFactory<HostGridType, VectorType>;
 
-    using LocalVector = typename Base::LevelContactNetwork::LocalVector;
+public:
+    using ContactNetwork = typename Base::ContactNetwork;
+
+private:
+    using GlobalCoords = typename ContactNetwork::LocalVector;
 
-    using DeformedLeafGridView = typename Base::LevelContactNetwork::DeformedLeafGridView;
-    using DeformedLevelGridView = typename Base::LevelContactNetwork::DeformedLevelGridView;
+    using LeafGridView = typename ContactNetwork::GridView;
+    using LevelGridView = typename ContactNetwork::GridType::LevelGridView;
 
-    using LevelBoundaryPatch = BoundaryPatch<DeformedLevelGridView>;
-    using LeafBoundaryPatch = BoundaryPatch<DeformedLeafGridView>;
+    using LevelBoundaryPatch = BoundaryPatch<LevelGridView>;
+    using LeafBoundaryPatch = BoundaryPatch<LeafGridView>;
 
-    using LeafFaces = MyFaces<DeformedLeafGridView>;
-    using LevelFaces = MyFaces<DeformedLevelGridView>;
+    using LeafFaces = MyFaces<LeafGridView>;
+    using LevelFaces = MyFaces<LevelGridView>;
 
-private:
-    const std::shared_ptr<MyBodyData<dims>> bodyData_;     // material properties of bodies
+    using CuboidGeometry= CuboidGeometry<typename GlobalCoords::field_type>;
+    using WeakeningRegion = typename CuboidGeometry::WeakeningRegion;
 
-    GridsConstructor<GridType>* gridConstructor_;
+    static const int dim = ContactNetwork::dim;
+
+    const std::shared_ptr<MyBodyData<dim>> bodyData_;     // material properties of bodies
+
+    std::unique_ptr<GridsConstructor<HostGridType>> gridConstructor_;
 
     std::vector<std::shared_ptr<CuboidGeometry>> cuboidGeometries_;
 
     std::vector<std::shared_ptr<LeafFaces>> leafFaces_;
     std::vector<std::shared_ptr<LevelFaces>> levelFaces_;
 
-    std::vector<std::shared_ptr<ConvexPolyhedron<LocalVector>>> lowerWeakPatches_;
-    std::vector<std::shared_ptr<ConvexPolyhedron<LocalVector>>> upperWeakPatches_;
+    std::vector<std::shared_ptr<WeakeningRegion>> weakPatches_;
 
     std::vector<std::shared_ptr<LevelBoundaryPatch>> nonmortarPatch_;
     std::vector<std::shared_ptr<LevelBoundaryPatch>> mortarPatch_;
@@ -46,22 +54,19 @@ template <class GridType, int dims> class StackedBlocksFactory : public LevelCon
 public:
     StackedBlocksFactory(const Dune::ParameterTree& parset) :
         Base(parset, parset.get<size_t>("problem.bodyCount"), parset.get<size_t>("problem.bodyCount")-1),
-        bodyData_(std::make_shared<MyBodyData<dims>>(this->parset_, zenith_())),
+        bodyData_(std::make_shared<MyBodyData<dim>>(this->parset_, zenith_())),
         cuboidGeometries_(this->bodyCount_),
         leafFaces_(this->bodyCount_),
         levelFaces_(this->bodyCount_),
-        lowerWeakPatches_(this->bodyCount_),
-        upperWeakPatches_(this->bodyCount_),
+        weakPatches_(this->bodyCount_),
         nonmortarPatch_(this->couplingCount_),
         mortarPatch_(this->couplingCount_)
     {}
 
-    ~StackedBlocksFactory() {
-        delete gridConstructor_;
-    }
-
     void setBodies();
+    void setLevelBodies();
     void setCouplings();
+    void setLevelCouplings() {}
     void setBoundaryConditions();
 
 private:
diff --git a/src/factories/stackedblocksfactory_tmpl.cc b/src/factories/stackedblocksfactory_tmpl.cc
index c72f5199..ea0c3039 100644
--- a/src/factories/stackedblocksfactory_tmpl.cc
+++ b/src/factories/stackedblocksfactory_tmpl.cc
@@ -3,5 +3,6 @@
 #endif
 
 #include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
 
-template class StackedBlocksFactory<Grid, MY_DIM>;
+template class StackedBlocksFactory<Grid, Vector>;
diff --git a/src/multi-body-problem-2D.cfg b/src/multi-body-problem-2D.cfg
index a308c80b..c0b758a8 100644
--- a/src/multi-body-problem-2D.cfg
+++ b/src/multi-body-problem-2D.cfg
@@ -19,3 +19,6 @@ tolerance         = 1e-5
 
 [solver.tnnmg.linear]
 tolerance          = 1e-10
+
+[solver.tnnmg.linear.preconditioner]
+tolerance          = 1e-10
diff --git a/src/multi-body-problem.cc b/src/multi-body-problem.cc
index 51f691ad..6682374d 100644
--- a/src/multi-body-problem.cc
+++ b/src/multi-body-problem.cc
@@ -33,12 +33,8 @@
 #include <dune/fufem/hdf5/file.hh>
 
 #include <dune/solvers/norms/energynorm.hh>
-
-
-/*
 #include <dune/solvers/solvers/loopsolver.hh>
-#include <dune/solvers/solvers/solver.hh>*/
-#include <dune/tnnmg/problem-classes/convexproblem.hh>
+#include <dune/solvers/iterationsteps/blockgssteps.hh>
 
 #include <dune/contact/common/deformedcontinuacomplex.hh>
 #include <dune/contact/common/couplingpair.hh>
@@ -47,7 +43,6 @@
 #include <dune/tectonic/geocoordinate.hh>
 #include <dune/tectonic/globalfriction.hh>
 
-
 #include "assemblers.hh"
 #include "gridselector.hh"
 #include "explicitgrid.hh"
@@ -59,6 +54,7 @@
 #include "data-structures/matrices.hh"
 #include "data-structures/program_state.hh"
 
+#include "factories/stackedblocksfactory.hh"
 #include "factories/threeblocksfactory.hh"
 
 //#include "io/hdf5-levelwriter.hh"
@@ -70,7 +66,7 @@
 #include "multi-body-problem-data/grid/mygrids.hh"
 
 #include "spatial-solving/tnnmg/functional.hh"
-#include "spatial-solving/preconditioners/supportpatchfactory.hh"
+//#include "spatial-solving/preconditioners/multilevelpatchpreconditioner.hh"
 #include "spatial-solving/tnnmg/localbisectionsolver.hh"
 #include "spatial-solving/contact/nbodyassembler.hh"
 #include "spatial-solving/solverfactory.hh"
@@ -151,15 +147,20 @@ int main(int argc, char *argv[]) {
     using Assembler = MyAssembler<DefLeafGridView, dims>;
     using field_type = Matrix::field_type;
 
-
     // ----------------------
     // set up contact network
     // ----------------------
-    ThreeBlocksFactory<Grid, Vector> threeBlocksFactory(parset);
+    StackedBlocksFactory<Grid, Vector> stackedBlocksFactory(parset);
+    using ContactNetwork = typename StackedBlocksFactory<Grid, Vector>::ContactNetwork;
+    stackedBlocksFactory.build();
+
+    ContactNetwork& contactNetwork = stackedBlocksFactory.contactNetwork();
+
+    /*ThreeBlocksFactory<Grid, Vector> threeBlocksFactory(parset);
     using ContactNetwork = typename ThreeBlocksFactory<Grid, Vector>::ContactNetwork;
     threeBlocksFactory.build();
 
-    ContactNetwork& contactNetwork = threeBlocksFactory.contactNetwork();
+    ContactNetwork& contactNetwork = threeBlocksFactory.contactNetwork(); */
     const size_t bodyCount = contactNetwork.nBodies();
 
     for (size_t i=0; i<bodyCount; i++) {
@@ -191,7 +192,7 @@ int main(int argc, char *argv[]) {
 
     const auto & coarseContactNetwork = *contactNetwork.level(3);
     const auto & fineContactNetwork = *contactNetwork.level(4);
-    SupportPatchFactory<typename ContactNetwork::LevelContactNetwork> supportPatchFactory(coarseContactNetwork, fineContactNetwork);
+   // SupportPatchFactory<typename ContactNetwork::LevelContactNetwork> supportPatchFactory(coarseContactNetwork, fineContactNetwork);
     size_t bodyID = 2;
     size_t patchDepth = 3;
 
@@ -223,6 +224,7 @@ int main(int argc, char *argv[]) {
         writeToVTK(gv, dofs, "", "body_" + std::to_string(i) + "_fine");
     }
 
+    /*
     using Patch = typename SupportPatchFactory<typename ContactNetwork::LevelContactNetwork>::Patch;
     Patch patch;
 
@@ -263,7 +265,7 @@ int main(int argc, char *argv[]) {
                 }
             }
         }
-    }
+    } */
 
     std::cout << "Done! :)" << std::endl;
     return 1;
@@ -506,6 +508,27 @@ int main(int argc, char *argv[]) {
     std::signal(SIGINT, handleSignal);
     std::signal(SIGTERM, handleSignal);
 
+    /*
+    // set patch preconditioner for linear correction in TNNMG method
+    using PatchSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
+    using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, PatchSolver, Matrix, Vector>;
+
+    const auto& preconditionerParset = parset.sub("solver.tnnmg.linear.preconditioner");
+
+    auto gsStep = Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::create(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0));
+    PatchSolver patchSolver(gsStep,
+                               preconditionerParset.get<size_t>("maximumIterations"),
+                               preconditionerParset.get<double>("tolerance"),
+                               nullptr,
+                               preconditionerParset.get<Solver::VerbosityMode>("verbosity"),
+                               false); // absolute error
+
+    Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), true);
+    Preconditioner preconditioner(contactNetwork, activeLevels, preconditionerParset.get<Preconditioner::Mode>("mode"));
+    preconditioner.setPatchSolver(patchSolver);
+    preconditioner.setPatchDepth(preconditionerParset.get<size_t>("patchDepth"));
+
+    // set adaptive time stepper
     typename ContactNetwork::ExternalForces externalForces;
     contactNetwork.externalForces(externalForces);
 
@@ -517,7 +540,8 @@ int main(int argc, char *argv[]) {
     while (!adaptiveTimeStepper.reachedEnd()) {
       programState.timeStep++;
 
-      iterationCount = adaptiveTimeStepper.advance();
+      preconditioner.build();
+      iterationCount = adaptiveTimeStepper.advance(preconditioner);
 
       programState.relativeTime = adaptiveTimeStepper.relativeTime_;
       programState.relativeTau = adaptiveTimeStepper.relativeTau_;
@@ -545,6 +569,7 @@ int main(int argc, char *argv[]) {
         break;
       }
     }
+    */
 
     std::cout.rdbuf(coutbuf); //reset to standard output again
 
diff --git a/src/multi-body-problem.cfg b/src/multi-body-problem.cfg
index 5fa9847b..8678a5dd 100644
--- a/src/multi-body-problem.cfg
+++ b/src/multi-body-problem.cfg
@@ -11,7 +11,7 @@ vtk.write       = true
 
 [problem]
 finalTime       = 100  # [s] #1000
-bodyCount       = 2
+bodyCount       = 4
 
 [body]
 bulkModulus     = 0.5e5 # [Pa]
@@ -69,8 +69,16 @@ maximumIterations = 100
 pre                = 3
 cycle              = 1  # 1 = V, 2 = W, etc.
 post               = 3
+[solver.tnnmg.linear.preconditioner]
+mode         = additive
+patchDepth   = 0
+maximumIterations = 10000
+verbosity         = quiet
 
 [solver.tnnmg.main]
 pre   = 1
 multi = 5 # number of multigrid steps
 post  = 0
+
+
+
diff --git a/src/spatial-solving/fixedpointiterator.cc b/src/spatial-solving/fixedpointiterator.cc
index 2c741b77..99456a3b 100644
--- a/src/spatial-solving/fixedpointiterator.cc
+++ b/src/spatial-solving/fixedpointiterator.cc
@@ -59,9 +59,11 @@ FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::FixedPointIte
       errorNorms_(errorNorms) {}
 
 template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+template <class Preconditioner>
 FixedPointIterationCounter
 FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run(
-    Updaters updaters, const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs,
+    Updaters updaters, Preconditioner&& preconditioner,
+    const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs,
     std::vector<Vector>& velocityIterates) {
 
   std::cout << "FixedPointIterator::run()" << std::endl;
@@ -124,7 +126,7 @@ FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run(
 
   // set up functional and TNMMG solver
   Functional J(bilinearForm, totalRhs, globalFriction_, vLower, vUpper);
-  Factory solverFactory(parset_.sub("solver.tnnmg"), J, ignoreNodes_);
+  Factory solverFactory(parset_.sub("solver.tnnmg"), J, std::forward<Preconditioner>(preconditioner), ignoreNodes_);
   auto step = solverFactory.step();
 
   std::cout << "- Functional and TNNMG step setup: success" << std::endl;
diff --git a/src/spatial-solving/fixedpointiterator.hh b/src/spatial-solving/fixedpointiterator.hh
index 867e8058..c7c74189 100644
--- a/src/spatial-solving/fixedpointiterator.hh
+++ b/src/spatial-solving/fixedpointiterator.hh
@@ -52,7 +52,9 @@ class FixedPointIterator {
                      const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
                      const ErrorNorms& errorNorms);
 
+  template <class Preconditioner>
   FixedPointIterationCounter run(Updaters updaters,
+                                 Preconditioner&& preconditioner,
                                  const std::vector<Matrix>& velocityMatrices,
                                  const std::vector<Vector>& velocityRHSs,
                                  std::vector<Vector>& velocityIterates);
diff --git a/src/spatial-solving/preconditioners/CMakeLists.txt b/src/spatial-solving/preconditioners/CMakeLists.txt
index abb4ff76..c5f8a1b5 100644
--- a/src/spatial-solving/preconditioners/CMakeLists.txt
+++ b/src/spatial-solving/preconditioners/CMakeLists.txt
@@ -3,5 +3,6 @@ add_custom_target(dune-tectonic_spatial-solving_preconditioners_src SOURCES
   levelglobalpreconditioner.hh
   levelpatchpreconditioner.hh
   multilevelpatchpreconditioner.hh
+  nbodycontacttransfer.hh
   supportpatchfactory.hh
 )
diff --git a/src/spatial-solving/preconditioners/levelglobalpreconditioner.hh b/src/spatial-solving/preconditioners/levelglobalpreconditioner.hh
index ac9fd3fc..e593c60d 100644
--- a/src/spatial-solving/preconditioners/levelglobalpreconditioner.hh
+++ b/src/spatial-solving/preconditioners/levelglobalpreconditioner.hh
@@ -3,6 +3,7 @@
 
 #include <string>
 
+#include <dune/common/timer.hh>
 #include <dune/common/fvector.hh>
 
 #include <dune/solvers/iterationsteps/lineariterationstep.hh>
@@ -10,105 +11,61 @@
 //#include <dune/istl/superlu.hh>
 #include <dune/istl/umfpack.hh>
 
-#include <dune/fufem/boundarypatch.hh>
-#include <dune/fufem/functiontools/boundarydofs.hh>
+#include "../../data-structures/levelcontactnetwork.hh"
 
-#include <dune/faultnetworks/assemblers/globalfaultassembler.hh>
-#include <dune/faultnetworks/levelinterfacenetwork.hh>
-#include <dune/faultnetworks/utils/debugutils.hh>
 
-
-template <class BasisType, class LocalAssembler, class LocalInterfaceAssembler, class MatrixType, class VectorType>
+template <class LevelContactNetwork, class Solver, class MatrixType, class VectorType>
 class LevelGlobalPreconditioner : public LinearIterationStep<MatrixType, VectorType> {
 
-public:
-    enum BoundaryMode {homogeneous, fromIterate};
-
 private:
-    typedef typename BasisType::GridView GridView;
-    typedef typename GridView::Grid GridType;
+    using Base = LinearIterationStep<MatrixType, VectorType>;
 
-    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork_;
-    const LocalAssembler& localAssembler_;
-    const std::vector<std::shared_ptr<LocalInterfaceAssembler>>& localInterfaceAssemblers_;
+    using ctype = typename LevelContactNetwork::ctype;
 
-    const GridType& grid_;
+    const LevelContactNetwork& levelContactNetwork_;
     const int level_;
-    const BasisType basis_;
-
-    Dune::BitSetVector<1> boundaryDofs_;
-    MatrixType matrix_;
-    VectorType rhs_;
 
-    bool requireBuild_;
+    std::shared_ptr<Solver> solver_;
 
 public:
 
-    // for each active fault in levelInterfaceNetwork: set up local problem, compute local correction
-    LevelGlobalPreconditioner(const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork,
-                             const LocalAssembler& localAssembler,
-                             const std::vector<std::shared_ptr<LocalInterfaceAssembler>>& localInterfaceAssemblers) :
-          levelInterfaceNetwork_(levelInterfaceNetwork),
-          localAssembler_(localAssembler),
-          localInterfaceAssemblers_(localInterfaceAssemblers),
-          grid_(levelInterfaceNetwork_.grid()),
-          level_(levelInterfaceNetwork_.level()),
-          basis_(levelInterfaceNetwork_)
-    {
-        assert(localInterfaceAssemblers_.size() == levelInterfaceNetwork_.size());
-    }
-
-    void build() {
-        //printBasisDofLocation(basis_);
+    LevelGlobalPreconditioner(const LevelContactNetwork& levelContactNetwork, const int level = 0) :
+          levelContactNetwork_(levelContactNetwork),
+          level_(level) {
 
-        GlobalFaultAssembler<BasisType, BasisType> globalFaultAssembler(basis_, basis_, levelInterfaceNetwork_);
-        globalFaultAssembler.assembleOperator(localAssembler_, localInterfaceAssemblers_, matrix_);
+        this->verbosity_ = QUIET;
+    }
 
-        typedef typename MatrixType::row_type RowType;
-        typedef typename RowType::ConstIterator ColumnIterator;
+    void setSolver(Solver&& patchSolver) {
+        solver_ = Dune::Solvers::wrap_own_share<PatchSolver>(std::forward<PatchSolver>(patchSolver));
+    }
 
-        const GridView& gridView = levelInterfaceNetwork_.levelGridView();
+    void iterate() override {
+        Dune::Timer timer;
 
-        // set boundary conditions
-        BoundaryPatch<GridView> boundaryPatch(gridView, true);
-        constructBoundaryDofs(boundaryPatch, basis_, boundaryDofs_);
+        if (this->verbosity_ == FULL) {
+            timer.reset();
+            timer.start();
+        }
 
-        for(size_t i=0; i<boundaryDofs_.size(); i++) {
-            if(!boundaryDofs_[i][0])
-                continue;
+        *(this->x_) = 0;
 
-            RowType& row = matrix_[i];
+        auto& step = solver_->getIterationStep();
+        step.setProblem(this->mat_, this->x_, this->rhs_);
+        step.setIgnore(this->ignoreNodes_);
 
-            ColumnIterator cIt    = row.begin();
-            ColumnIterator cEndIt = row.end();
+        solver_->check();
+        solver_->preprocess();
+        solver_->solve();
 
-            for(; cIt!=cEndIt; ++cIt) {
-                row[cIt.index()] = 0;
-            }
+        *(this->x_) = solver_->getSol();
 
-            row[i] = 1;
+        if (this->verbosity_ == FULL) {
+            std::cout << "LevelGlobalPreconditioner::iterate() Solving global problem took: " << timer.stop() << " seconds" << std::endl;
         }
-
-        requireBuild_ = false;
-    }
-
-
-
-    virtual void setProblem(const MatrixType& mat, VectorType& x, const VectorType& rhs) {
-        this->x_ = &x;
-        updateRhs(rhs);
-        this->mat_ = Dune::stackobject_to_shared_ptr(mat); // mat will be set but not used
     }
 
-    virtual void iterate() {      
-        //print(matrix_, "coarse matrix: ");
-        //print(rhs_, "coarse rhs: ");
-
-        // compute solution directly
-
-        if (requireBuild_)
-            DUNE_THROW(Dune::Exception, "LevelGlobalPreconditioner::iterate() Call build() before solving the global problem!");
-
+    /*void iterate() override {
         Dune::Timer timer;
         timer.reset();
         timer.start();
@@ -129,31 +86,8 @@ class LevelGlobalPreconditioner : public LinearIterationStep<MatrixType, VectorT
 
         //std::cout << "LevelGlobalPreconditioner::iterate() Solving global problem took: " << timer.elapsed() << " seconds" << std::endl;
 
-    }
-
-    const BasisType& basis() const {
-        return basis_;
-    }
-
-    const GridView& gridView() const {
-        return basis_.getGridView();
-    }
+    }*/
 
-    const LevelInterfaceNetwork<GridView>& levelInterfaceNetwork() const {
-        return levelInterfaceNetwork_;
-    }
-
-private:
-    void updateRhs(const VectorType& rhs){
-        rhs_.resize(matrix_.M());
-        rhs_ = 0;
-
-        for (size_t i=0; i<rhs.size(); i++) {
-            if (!boundaryDofs_[i][0])
-                rhs_[i] = rhs[i];
-        }
-    }
 };
-
 #endif
 
diff --git a/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh b/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh
index 1c8257c1..52d5f1d1 100644
--- a/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh
+++ b/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh
@@ -43,15 +43,10 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
 
     PatchFactory patchFactory_;
     std::vector<Patch> patches_;
-    PatchSolver patchSolver_;
-
-
 
+    std::shared_ptr<PatchSolver> patchSolver_;
     size_t patchDepth_;
 
-    MatrixType matrix_;
-    std::vector<std::shared_ptr<OscLocalProblem<MatrixType, VectorType>> > localProblems_;
-
 public:
 
     // for each coarse patch given by levelContactNetwork: set up local problem, compute local correction
@@ -78,12 +73,13 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
         patches_.resize(totalNVertices);
 
         // init local fine level corrections
+        Dune::Timer timer;
         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();
         }
@@ -91,6 +87,8 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
         Dune::BitSetVector<1> vertexVisited(totalNVertices);
         vertexVisited.unsetAll();
 
+        const auto& levelIndices = patchFactory_.coarseIndices();
+
         for (size_t bodyIdx=0; bodyIdx<levelContactNetwork_.nBodies(); bodyIdx++) {
             const auto& gridView = levelContactNetwork_.body(bodyIdx)->gridView();
 
@@ -98,16 +96,10 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
                 const auto& refElement = Dune::ReferenceElements<double, dim>::general(e.type());
 
                 for (size_t i=0; i<refElement.size(dim); i++) {
-                    auto globalIdx = patchFactory_.coarseIndices().vertexIndex(bodyIdx, e, i);
+                    auto globalIdx = levelIndices.vertexIndex(bodyIdx, e, i);
 
                     if (!vertexVisited[globalIdx][0]) {
                         vertexVisited[globalIdx][0] = true;
-
-                     /*   if (this->verbosity_ != QUIET) {
-                            std::cout << i << std::endl;
-                            std::cout << "---------------" << std::endl;
-                        }*/
-
                         patchFactory_.build(bodyIdx, e, i, patches_[globalIdx], patchDepth_);
                     }
                 }
@@ -121,11 +113,15 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
             timer.stop();
         }
 
-        if (this->verbosity_ != REDUCED) {
+        if (this->verbosity_ != QUIET) {
             std::cout << "Level: " << level_ << " LevelPatchPreconditioner::build() - SUCCESS" << std::endl;
         }
     }
 
+    void setPatchSolver(PatchSolver&& patchSolver) {
+        patchSolver_ = Dune::Solvers::wrap_own_share<PatchSolver>(std::forward<PatchSolver>(patchSolver));
+    }
+
     void setPatchDepth(const size_t patchDepth = 0) {
         patchDepth_ = patchDepth;
     }
@@ -134,24 +130,6 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
         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();
@@ -161,43 +139,37 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
 
     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;
+        for (const auto& p : patches_) {
+            x = 0;
+
+            auto& step = patchSolver_->getIterationStep();
+            step.setProblem(this->mat_, x, this->rhs_);
+            step.setIgnore(p);
+
+            patchSolver_->check();
+            patchSolver_->preprocess();
+            patchSolver_->solve();
+
+            *(this->x_) += patchSolver_->getSol();
         }
     }
 
     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;
-        }
+        } */
     }
 
     size_t size() const {
diff --git a/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh b/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
index 93529434..3d1f9afc 100644
--- a/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
+++ b/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
@@ -9,60 +9,50 @@
 
 #include <dune/solvers/iterationsteps/lineariterationstep.hh>
 
-#include <dune/faultnetworks/preconditioners/levelglobalpreconditioner.hh>
-#include <dune/faultnetworks/preconditioners/levelpatchpreconditioner.hh>
-#include <dune/faultnetworks/levelinterfacenetwork.hh>
-#include <dune/faultnetworks/interfacenetwork.hh>
+#include "nbodytransfer.hh"
+#include "levelpatchpreconditioner.hh"
 #include <dune/faultnetworks/dgmgtransfer.hh>
 
-#include <dune/faultnetworks/utils/debugutils.hh>
-
-template <class BasisType, class LocalOperatorAssembler, class LocalInterfaceAssembler, class MatrixType, class VectorType>
+template <class ContactNetwork, class PatchSolver, class MatrixType, class VectorType>
 class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorType> {
-
 public:
     enum Mode {additive, multiplicative};
-    typedef LevelPatchPreconditioner<BasisType, LocalOperatorAssembler, LocalInterfaceAssembler, MatrixType, VectorType> LevelPatchPreconditionerType;
-    typedef LevelGlobalPreconditioner<BasisType, LocalOperatorAssembler, LocalInterfaceAssembler, MatrixType, VectorType> LevelGlobalPreconditionerType;
 
 private:
-    typedef typename BasisType::GridView GridView;
-    typedef typename GridView::Grid GridType;
-
+    using LevelContactNetwork = typename ContactNetwork::LevelContactNetwork;
+    using LevelPatchPreconditioner = LevelPatchPreconditioner<LevelContactNetwork, PatchSolver, MatrixType, VectorType>;
+    using LevelGlobalPreconditioner = LevelPatchPreconditioner<LevelContactNetwork, PatchSolver, MatrixType, VectorType>;
+    using BitVector = typename LinearIterationStep<MatrixType, VectorType>::BitVector;
 
-    typedef typename Dune::BitSetVector<1> BitVector;
+    using MGTransfer = ;
 
-    const ContactNetwork<GridType>& interfaceNetwork_;
-    const BitVector& activeLevels_;
+    const ContactNetwork& contactNetwork_;
+    const Dune::BitSetVector<1>& activeLevels_;
 
     const Mode mode_;
 
-    int itCounter_;
+    std::vector<std::shared_ptr<LevelPatchPreconditioner>> levelPatchPreconditioners_;
 
-    std::shared_ptr<LevelGlobalPreconditionerType> coarseGlobalPreconditioner_;
-    std::vector<std::shared_ptr<LevelPatchPreconditionerType>> levelPatchPreconditioners_;
+    std::vector<MatrixType> levelMat_;
     std::vector<VectorType> levelX_;
     std::vector<VectorType> levelRhs_;
+    std::vector<BitVector> levelIgnore_;
 
-    std::vector<std::shared_ptr<DGMGTransfer<BasisType>>> mgTransfer_;
+    PatchSolver coarseSolver_;
+
+    std::vector<std::shared_ptr<MGTransfer>> mgTransfer_; //TODO
 
 public:
-    MultilevelPatchPreconditioner(const ContactNetwork<GridType>& interfaceNetwork,
-                                  const BitVector& activeLevels,
+    MultilevelPatchPreconditioner(const ContactNetwork& contactNetwork,
+                                  const Dune::BitSetVector<1>& activeLevels,
                                   const Mode mode = MultilevelPatchPreconditioner::Mode::additive) :
-          interfaceNetwork_(interfaceNetwork),
+          contactNetwork_(contactNetwork),
           activeLevels_(activeLevels),
-          localAssemblers_(localAssemblers),
-          localInterfaceAssemblers_(localInterfaceAssemblers),
-          mode_(mode)
-    {
-
-        if (activeLevels_.size() > (size_t) interfaceNetwork.maxLevel() +1)
-            DUNE_THROW(Dune::Exception, "MultilevelFaultPreconditioner: too many active levels; preconditioner supports at most (grid.maxLevel + 1) levels!");
+          mode_(mode) {
 
-        assert(activeLevels.size() == localAssemblers_.size() && activeLevels.size() == localInterfaceAssemblers_.size());
+        assert(activeLevels.size() == contactNetwork_.nLevels());
 
-        // init level fault preconditioners and multigrid transfer
+        // init level patch preconditioners and multigrid transfer
         levelPatchPreconditioners_.resize(0);
         mgTransfer_.resize(0);
 
@@ -70,74 +60,73 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
         for (size_t i=0; i<activeLevels_.size(); i++) {
             if (activeLevels_[i][0]) {
                 // init global problem on coarsest level
-                const LevelInterfaceNetwork<GridView>& levelNetwork = interfaceNetwork.levelInterfaceNetwork(i);
-                coarseGlobalPreconditioner_ = std::make_shared<LevelGlobalPreconditionerType>(levelNetwork, *localAssemblers_[i], localInterfaceAssemblers_[i]);
+                const auto& levelNetwork = *contactNetwork_.level(i);
+                coarseGlobalPreconditioner_ = std::make_shared<LevelGlobalPreconditioner>(levelNetwork);
 
                 maxLevel = i;
                 break;
             }
         }
 
-        typename LevelPatchPreconditionerType::Mode levelMode = LevelPatchPreconditionerType::Mode::additive;
+        const int coarsestLevel = maxLevel;
+
+        typename LevelPatchPreconditioner::Mode levelMode = LevelPatchPreconditioner::Mode::additive;
         if (mode_ != additive){
-            levelMode = LevelPatchPreconditionerType::Mode::multiplicative;
+            levelMode = LevelPatchPreconditioner::Mode::multiplicative;
         }
 
         for (size_t i=maxLevel+1; i<activeLevels_.size(); i++) {
             if (activeLevels_[i][0]) {
                 // init local patch preconditioners on each level
-                const LevelInterfaceNetwork<GridView>& levelNetwork = interfaceNetwork.levelInterfaceNetwork(i);
-
-                //levelPatchPreconditioners_.push_back(std::make_shared<LevelGlobalPreconditionerType>(levelNetwork, *localAssemblers_[i], localInterfaceAssemblers_[i]));
-
-                if (levelPatchPreconditioners_.size() == 0) {
-                    levelPatchPreconditioners_.push_back(std::make_shared<LevelPatchPreconditionerType>(levelNetwork, coarseGlobalPreconditioner_->basis(), *localAssemblers_[i], localInterfaceAssemblers_[i], levelMode));
-                } else {
-                    //levelPatchPreconditioners_.push_back(std::make_shared<LevelPatchPreconditionerType>(levelNetwork, coarseGlobalPreconditioner_->basis(), *localAssemblers_[i], localInterfaceAssemblers_[i], levelMode));
-
-                    levelPatchPreconditioners_.push_back(std::make_shared<LevelPatchPreconditionerType>(levelNetwork, levelPatchPreconditioners_.back()->basis(), *localAssemblers_[i], localInterfaceAssemblers_[i], levelMode));
-                }
+                const auto& fineNetwork = contactNetwork_.level(i);
+                levelPatchPreconditioners_.push_back(std::make_shared<LevelPatchPreconditioner(*contactNetwork_.level(maxLevel), fineNetwork, levelMode));
 
                 maxLevel = i;
             }
         }
 
-        levelX_.resize(levelPatchPreconditioners_.size()+1);
-        levelRhs_.resize(levelPatchPreconditioners_.size()+1);
-
-        allFaultBasis_ = std::make_shared<BasisType>(interfaceNetwork_.levelInterfaceNetwork(maxLevel));
+        levelX_.resize(size());
+        levelRhs_.resize(size());
 
         // init multigrid transfer
         for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
-            mgTransfer_.push_back(std::make_shared<DGMGTransfer<BasisType>>(levelPatchPreconditioners_[i]->basis(), *allFaultBasis_));
+            mgTransfer_.push_back(std::make_shared<MGTransfer>(...));
         }
-        mgTransfer_.push_back(std::make_shared<DGMGTransfer<BasisType>>(coarseGlobalPreconditioner_->basis(), *allFaultBasis_));
-
-        itCounter_ = 0;
+        mgTransfer_.push_back(std::make_shared<MGTransfer>(coarseGlobalPreconditioner_->basis(), *allFaultBasis_));
     }
 
 
-   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);
+   void setProblem(const MatrixType& mat, VectorType& x, const VectorType& rhs) override {
+        this->setProblem(mat, x, rhs);
 
         for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
-            mgTransfer_[i]->restrict(x, levelX_[i]);
-            mgTransfer_[i]->restrict(rhs, levelRhs_[i]);
+            const auto& transfer = *mgTransfer_[i];
+            auto& _x = levelX_[i];
+            auto& _rhs = levelRhs_[i];
+            auto& _mat = levelMat_[i];
+
+            transfer.restrict(x, _x);
+            transfer.restrict(rhs, _rhs);
+            transfer.galerkinRestrict(mat, _mat);
 
-            levelPatchPreconditioners_[i]->setProblem(mat, levelX_[i], levelRhs_[i]);
+            levelPatchPreconditioners_[i]->setProblem(_mat, _x, _rhs);
         }
 
-        size_t j = levelPatchPreconditioners_.size();
-        mgTransfer_[j]->restrict(x, levelX_[j]);
-        mgTransfer_[j]->restrict(rhs, levelRhs_[j]);
+        // set coarse global problem
+        const auto& coarseTransfer = *mgTransfer_.back();
+        auto& coarseX = levelX_.back();
+        auto& coarseRhs = levelRhs_.back();
+        auto& coarseMat = levelMat_.back();
+
+        coarseTransfer.restrict(x, coarseX);
+        coarseTransfer.restrict(rhs, coarseRhs);
+        coarseTransfer.galerkinRestrict(mat, coarseMat);
 
-        coarseGlobalPreconditioner_->setProblem(mat, levelX_[j], levelRhs_[j]);
+        coarseSolver_.getIterationStep().setProblem(coarseMat, coarseX, coarseRhs);
     }
 
 
-    virtual void iterate() {
+    void iterate() {
         if (mode_ == additive)
             iterateAdd();
         else
@@ -149,67 +138,52 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
 
         VectorType x;
 
-        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
-            levelPatchPreconditioners_[i]->iterate();
-            const VectorType& it = levelPatchPreconditioners_[i]->getSol();
+        // solve coarse global problem
+        auto& coarseIgnore = levelIgnore_.back();
+        mgTransfer_.back()->restrict(this->ignore(), coarseIgnore);
+        coarseSolver_.getIterationStep().setIgnore(coarseIgnore);
 
-            mgTransfer_[i]->prolong(it, x);
+        coarseSolver_.check();
+        coarseSolver_.preprocess();
+        coarseSolver_.solve();
 
-            //writeToVTK(*allFaultBasis_, x, "/home/mi/podlesny/data/faultnetworks/sol/", "preconditioner_step_"+std::to_string(i));
+        mgTransfer_.back()->prolong(coarseSolver_.getSol(), x);
 
-            *(this->x_) += x;
-        }
+        for (size_t i=levelPatchPreconditioners_.size()-2; i>=0; i--) {
+            const auto& transfer = *mgTransfer_[i];
+            auto& preconditioner = *levelPatchPreconditioners_[i];
 
-        coarseGlobalPreconditioner_->iterate();
-        const VectorType& it = coarseGlobalPreconditioner_->getSol();
+            auto& _ignore = levelIgnore_[i];
+            transfer.restrict(this->ignore(), _ignore);
+            preconditioner.setIgnore(_ignore);
 
-        mgTransfer_[levelPatchPreconditioners_.size()]->prolong(it, x);
-        *(this->x_) += x;
+            preconditioner.iterate();
 
+            x += preconditioner.getSol();
 
-        /*
-            levelPatchPreconditioners_[itCounter_]->iterate();
-            const VectorType& it = levelPatchPreconditioners_[itCounter_]->getSol();
+            VectorType newX;
+            transfer.prolong(x, newX);
 
-            mgTransfer_[itCounter_]->prolong(it, x);
-
-            //writeToVTK(*allFaultBasis_, x, "/home/mi/podlesny/data/faultnetworks/sol/", "preconditioner_step_"+std::to_string(i));
-
-            *(this->x_) += x;
-
-        coarseGlobalPreconditioner_->iterate();
-        const VectorType& it2 = coarseGlobalPreconditioner_->getSol();
-
-        mgTransfer_[levelPatchPreconditioners_.size()]->prolong(it2, x);
-        *(this->x_) += x;
-
-        itCounter_++;
-        itCounter_ = itCounter_ % (levelPatchPreconditioners_.size());
-
-        if (itCounter_==0)
-            std::cout << "Multilevel pass complete!" << std::endl;
+            x = newX;
+        }
 
-        */
+        *(this->x_) = x;
     }
 
 
     void iterateMult() {
         *(this->x_) = 0;
 
+        /*
         VectorType x;
 
         for (int i=(levelPatchPreconditioners_.size()-1); i>=0; i--) {
             VectorType updatedRhs(*(this->rhs_));
             this->mat_->mmv(*(this->x_), updatedRhs);
 
-            //print(updatedRhs, "globalRhs: ");
-
             mgTransfer_[i]->restrict(*(this->x_), levelX_[i]);
             mgTransfer_[i]->restrict(updatedRhs, levelRhs_[i]);
 
-            //print(levelRhs_[i], "levelLocalCoarseRhs: ");
-            //writeToVTK(levelPatchPreconditioners_[i]->basis(), levelRhs_[i], "/storage/mi/podlesny/data/faultnetworks/rhs/fine", "exactvertexdata_step_"+std::to_string(itCounter_));
-
             levelPatchPreconditioners_[i]->setProblem(*(this->mat_), levelX_[i], levelRhs_[i]);
 
             levelPatchPreconditioners_[i]->iterate();
@@ -217,9 +191,6 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
 
             mgTransfer_[i]->prolong(it, x);
 
-            //writeToVTK(*allFaultBasis_, x, "/storage/mi/podlesny/data/faultnetworks/fineIterates/multilevel", "exactvertexdata_step_"+std::to_string(itCounter_));
-
-
             *(this->x_) += x;
         }
 
@@ -230,20 +201,13 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
         mgTransfer_[j]->restrict(*(this->x_), levelX_[j]);
         mgTransfer_[j]->restrict(updatedCoarseRhs, levelRhs_[j]);
 
-        //print(levelRhs_[j], "localCoarseRhs: ");
-        //writeToVTK(coarseGlobalPreconditioner_->basis(), levelRhs_[j], "/storage/mi/podlesny/data/faultnetworks/rhs/coarse", "exactvertexdata_step_"+std::to_string(itCounter_));
-
         coarseGlobalPreconditioner_->setProblem(*(this->mat_), levelX_[j], levelRhs_[j]);
         coarseGlobalPreconditioner_->iterate();
         const VectorType& it = coarseGlobalPreconditioner_->getSol();
 
         mgTransfer_[j]->prolong(it, x);
 
-        //writeToVTK(*allFaultBasis_, x, "/storage/mi/podlesny/data/faultnetworks/coarseIterates/multilevel", "exactvertexdata_step_"+std::to_string(itCounter_));
-
-        *(this->x_) += x;
-
-        itCounter_++;
+        *(this->x_) += x; */
     }
 
     void build() {
@@ -254,12 +218,17 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
         }
     }
 
-    std::shared_ptr<LevelPatchPreconditionerType> levelPatchPreconditioner(const int level) {
-        return levelPatchPreconditioners_[level];
-    }
+    void setPatchSolver(PatchSolver&& patchSolver) {
+        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
+            levelPatchPreconditioners_[i]->setPatchSolver(std::forward<PatchSolver>(patchSolver));
+        }
+        coarseGlobalPreconditioner_->setPatchSolver(std::forward<PatchSolver>(patchSolver));
+    };
 
-    const BasisType& basis() const {
-        return *allFaultBasis_;
+    void setPatchDepth(const size_t patchDepth = 0) {
+        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
+            levelPatchPreconditioners_[i]->setPatchDepth(patchDepth);
+        }
     }
 
     size_t size() const {
diff --git a/src/spatial-solving/preconditioners/nbodycontacttransfer.cc b/src/spatial-solving/preconditioners/nbodycontacttransfer.cc
new file mode 100644
index 00000000..961ee3f5
--- /dev/null
+++ b/src/spatial-solving/preconditioners/nbodycontacttransfer.cc
@@ -0,0 +1,297 @@
+#include <dune/common/fvector.hh>
+#include <dune/common/exceptions.hh>
+#include <dune/istl/bdmatrix.hh>
+
+#include <dune/fufem/assemblers/transferoperatorassembler.hh>
+#include <dune/matrix-vector/blockmatrixview.hh>
+
+#include <dune/matrix-vector/addtodiagonal.hh>
+#include <dune/matrix-vector/axpy.hh>
+#include <dune/solvers/common/numproc.hh>
+#include <dune/solvers/transferoperators/densemultigridtransfer.hh>
+
+template<class ContactNetwork, class VectorType>
+void NBodyContactTransfer<ContactNetwork, VectorType>::setup(const ContactNetwork& contactNetwork, const int coarseLevel, const int fineLevel)
+
+        (const std::vector<const GridType*>& grids, int colevel,
+                                                         const std::vector<const MatrixType*>& mortarTransferOperator,
+                                                         const CoordSystemVector& fineLocalCoordSystems,
+                                                         const std::vector<const BitSetVector<1>*>& fineHasObstacle,
+                                                         const std::vector<std::array<int,2> >& gridIdx)
+
+transfer->setup(*grids[0], *grids[1], i,
+                        contactAssembler.contactCoupling_[0]->mortarLagrangeMatrix(),
+                        contactAssembler.localCoordSystems_,
+                        *contactAssembler.contactCoupling_[0]->nonmortarBoundary().getVertices());
+
+{
+    const size_t nBodies     = contactNetwork.nBodies();
+    const size_t nCouplings = contactNetwork.nCouplings();
+
+    const auto& coarseContactNetwork = contactNetwork.level(coarseLevel);
+    const auto& fineContactNetwork = contactNetwork.level(fineLevel);
+
+    std::vector<size_t> maxL(nBodies), cL(nBodies), fL(nBodies);
+
+    for (size_t i=0; i<nBodies; i++) {
+        maxL[i] = contactNetwork.body(i)->grid()->maxLevel();
+        cL[i] = coarseContactNetwork.body(i)->level();
+        fL[i] = fineContactNetwork.body(i)->level();
+    }
+
+    // ////////////////////////////////////////////////////////////
+    //   Create the standard prolongation matrices for each grid
+    // ////////////////////////////////////////////////////////////
+
+    std::vector<TruncatedDenseMGTransfer<VectorType>* > gridTransfer(nBodies);
+    std::vector<const MatrixType*> submat(nBodies);
+
+    for (size_t i=0; i<nBodies; i++) {
+        if (fL[i] > cL[i]) {
+            gridTransfer[i] = new TruncatedDenseMGTransfer<VectorType>;
+            gridTransfer[i]->setup(*contactNetwork.body(i)->grid(), cL[i], fL[i]);
+            submat[i] = &gridTransfer[i]->getMatrix();
+
+        } else {
+            // gridTransfer is identity if coarse and fine level coincide for body
+            BDMatrix<MatrixBlock>* newMatrix = new BDMatrix<MatrixBlock>(coarseContactNetwork.body(i)->nVertices());
+
+            for (size_t j=0; j<newMatrix->N(); j++)
+                for (int k=0; k<blocksize; k++)
+                    for (int l=0; l<blocksize; l++)
+                        (*newMatrix)[j][j][k][l] = (k==l);
+
+            submat[i] = newMatrix;
+        }
+    }
+
+    // ///////////////////////////////////
+    //   Combine the submatrices
+    // ///////////////////////////////////
+
+    if (fineLevel == contactNetwork.maxLevel())
+        combineSubMatrices(submat, mortarTransferOperator, fineLocalCoordSystems, fineHasObstacle, gridIdx);
+    else
+        Dune::MatrixVector::BlockMatrixView<MatrixType>::setupBlockMatrix(submat, this->matrix_);
+
+    for (size_t i=0; i<nBodies; i++) {
+        if (fL[i]==0) {
+            delete(submat[i]);
+        }
+    }
+
+    // Delete separate transfer objects
+    for (size_t i=0; i<nBodies; i++) {
+        delete(gridTransfer[i]);
+    }
+}
+
+template<class VectorType>
+template<class GridType>
+void NBodyContactTransfer<VectorType>::setupHierarchy(std::vector<std::shared_ptr<NonSmoothNewtonContactTransfer<VectorType> > >& mgTransfers,
+                                    const std::vector<const GridType*> grids,
+                                    const std::vector<const MatrixType*> mortarTransferOperator,
+                                    const CoordSystemVector& fineLocalCoordSystems,
+                                    const std::vector<const BitSetVector<1>*>& fineHasObstacle,
+                                    const std::vector<std::array<int,2> >& gridIdx)
+{
+    const size_t nGrids     = grids.size();
+
+    std::vector<std::vector<TruncatedDenseMGTransfer<VectorType>* > > gridTransfer(nGrids);
+    std::vector<const MatrixType*> submat(nGrids);
+
+    // ////////////////////////////////////////////////////////////
+    //   Create the standard prolongation matrices for each grid
+    // ////////////////////////////////////////////////////////////
+
+    for (size_t i=0; i<nGrids; i++) {
+
+        gridTransfer[i].resize(grids[i]->maxLevel());
+        for (size_t j=0; j<gridTransfer[i].size(); j++)
+            gridTransfer[i][j] = new TruncatedDenseMGTransfer<VectorType>;
+
+        // Assemble standard transfer operator
+        TransferOperatorAssembler<GridType> transferOperatorAssembler(*grids[i]);
+        transferOperatorAssembler.assembleOperatorPointerHierarchy(gridTransfer[i]);
+    }
+
+    // ////////////////////////////////////////////////////////////////////////////
+    //      Combine matrices in one matrix and add mortar entries on the fine level
+    // ///////////////////////////////////////////////////////////////////////////
+    int toplevel = mgTransfers.size();
+
+    for (size_t colevel=0; colevel<mgTransfers.size(); colevel++) {
+
+        std::vector<int> fL(nGrids);
+
+        for (size_t i=0; i<nGrids; i++) {
+            fL[i] = std::max(size_t(0), grids[i]->maxLevel() - colevel);
+
+            // If the prolongation matrix exists, take it
+            if (fL[i] > 0) {
+
+                submat[i] =&gridTransfer[i][fL[i]-1]->getMatrix();
+            } else {
+                // when the maxLevels of the grids differ then we add copys of the coarsest level to the "smaller" grid
+                BDMatrix<MatrixBlock>* newMatrix = new BDMatrix<MatrixBlock>(grids[i]->size(0,GridType::dimension));
+                *newMatrix = 0;
+
+                for (size_t j=0; j<newMatrix->N(); j++)
+                    for (int k=0; k<blocksize; k++)
+                            (*newMatrix)[j][j][k][k] = 1.0;
+
+                submat[i] = newMatrix;
+            }
+        }
+
+        if (colevel == 0)
+            mgTransfers[toplevel-colevel-1]->combineSubMatrices(submat, mortarTransferOperator, fineLocalCoordSystems, fineHasObstacle, gridIdx);
+        else
+          Dune::MatrixVector::BlockMatrixView<MatrixType>::setupBlockMatrix(submat, mgTransfers[toplevel-colevel-1]->matrix_);
+
+        for (size_t i=0; i<nGrids; i++)
+            if (fL[i]==0)
+                delete(submat[i]);
+    }
+
+    // Delete separate transfer objects
+    for (size_t i=0; i<nGrids; i++)
+        for (size_t j=0; j<gridTransfer[i].size(); j++)
+            delete(gridTransfer[i][j]);
+}
+
+
+template<class VectorType>
+void NBodyContactTransfer<VectorType>::combineSubMatrices(const std::vector<const MatrixType*>& submat,
+                                                                      const std::vector<const MatrixType*>& mortarTransferOperator,
+                                                                      const CoordSystemVector& fineLocalCoordSystems,
+                                                                      const std::vector<const BitSetVector<1>*>& fineHasObstacle,
+                                                                      const std::vector<std::array<int,2> >& gridIdx)
+{
+    // ///////////////////////////////////
+    //   Combine the submatrices
+    // ///////////////////////////////////
+
+    const size_t nGrids     = submat.size();
+    const size_t nCouplings = mortarTransferOperator.size();
+
+    Dune::MatrixVector::BlockMatrixView<MatrixType> view(submat);
+
+    MatrixIndexSet totalIndexSet(view.nRows(), view.nCols());
+
+    // import indices of canonical transfer operator
+    for (size_t i=0; i<nGrids; i++)
+        totalIndexSet.import(*submat[i], view.row(i, 0), view.col(i, 0));
+
+    // ///////////////////////////////////////////////////////////////
+    //   Add additional matrix entries  $ -D^{-1}M I_{mm} $
+    // ///////////////////////////////////////////////////////////////
+
+    typedef typename OperatorType::row_type RowType;
+    typedef typename RowType::ConstIterator ConstIterator;
+
+    std::vector<std::vector<int> > localToGlobal(nCouplings);
+
+    for (size_t i=0; i<nCouplings; i++) {
+
+      if (fineHasObstacle[i]->size() != submat[gridIdx[i][0]]->N())
+        DUNE_THROW(Dune::Exception,
+                   "fineHasObstacle[" << i << "] doesn't have the proper length!");
+
+      localToGlobal[i].resize(mortarTransferOperator[i]->N());
+      size_t idx = 0;
+      for (size_t j=0; j<fineHasObstacle[i]->size(); j++)
+        if ((*fineHasObstacle[i])[j][0])
+          localToGlobal[i][idx++] = j;
+
+      assert(idx==localToGlobal[i].size());
+
+      for (size_t j=0; j<mortarTransferOperator[i]->N(); j++) {
+
+        ConstIterator cTIt = (*mortarTransferOperator[i])[j].begin();
+        ConstIterator cEndIt = (*mortarTransferOperator[i])[j].end();
+        for (; cTIt != cEndIt; ++cTIt) {
+
+          int k = cTIt.index();
+
+          ConstIterator cMIt = (*submat[gridIdx[i][1]])[k].begin();
+          ConstIterator cMEndIt = (*submat[gridIdx[i][1]])[k].end();
+          for (; cMIt != cMEndIt; ++cMIt)
+            totalIndexSet.add(view.row(gridIdx[i][0], localToGlobal[i][j]),
+                view.col(gridIdx[i][1], cMIt.index()));
+
+        }
+
+      }
+
+    }
+
+    totalIndexSet.exportIdx(this->matrix_);
+    this->matrix_ = 0;
+
+    // Copy matrices
+    for (size_t i=0; i<nGrids; i++) {
+
+        for(size_t rowIdx=0; rowIdx<submat[i]->N(); rowIdx++) {
+
+            const RowType& row = (*submat[i])[rowIdx];
+
+            ConstIterator cIt    = row.begin();
+            ConstIterator cEndIt = row.end();
+
+            for(; cIt!=cEndIt; ++cIt)
+                this->matrix_[view.row(i, rowIdx)][view.col(i, cIt.index())] = *cIt;
+
+        }
+
+    }
+
+    // ///////////////////////////////////////////////////////////////
+    //   Add additional matrix entries  $ -D^{-1}M I_{mm} $
+    // ///////////////////////////////////////////////////////////////
+
+    for (size_t i=0; i<nCouplings; i++) {
+
+        for (size_t j=0; j<mortarTransferOperator[i]->N(); j++) {
+
+            ConstIterator cTIt = (*mortarTransferOperator[i])[j].begin();
+            ConstIterator cTEndIt = (*mortarTransferOperator[i])[j].end();
+
+            for (; cTIt != cTEndIt; ++cTIt) {
+
+                int k = cTIt.index();
+
+                ConstIterator cMIt = (*submat[gridIdx[i][1]])[k].begin();
+                ConstIterator cMEndIt = (*submat[gridIdx[i][1]])[k].end();
+
+                for (; cMIt != cMEndIt; ++cMIt) {
+
+                    auto& currentMatrixBlock = this->matrix_[view.row(gridIdx[i][0], localToGlobal[i][j])][view.col(gridIdx[i][1], cMIt.index())];
+
+                    // the entry in the prolongation matrix of the mortar grid
+                    const auto& subMatBlock = this->matrix_[view.row(gridIdx[i][1], k)][view.col(gridIdx[i][1], cMIt.index())];
+
+                    // the - is due to the negation formula for BT
+                    Dune::MatrixVector::subtractProduct(currentMatrixBlock,(*cTIt), subMatBlock);
+                }
+            }
+        }
+    }
+
+    // ///////////////////////////////////////////////////////////////
+    // Transform matrix to account for the local coordinate systems
+    // ///////////////////////////////////////////////////////////////
+
+    /** \todo Hack.  Those should really be equal */
+    assert(fineLocalCoordSystems.size() <= this->matrix_.N());
+
+    for(size_t rowIdx=0; rowIdx<fineLocalCoordSystems.size(); rowIdx++) {
+
+        auto& row = this->matrix_[rowIdx];
+
+        for(auto& col : row)
+            col.leftmultiply(fineLocalCoordSystems[rowIdx]);
+
+    }
+
+}
diff --git a/src/spatial-solving/preconditioners/nbodycontacttransfer.hh b/src/spatial-solving/preconditioners/nbodycontacttransfer.hh
new file mode 100644
index 00000000..7cc8ae01
--- /dev/null
+++ b/src/spatial-solving/preconditioners/nbodycontacttransfer.hh
@@ -0,0 +1,88 @@
+#ifndef N_BODY_CONTACT_TRANSFER_HH
+#define N_BODY_CONTACT_TRANSFER_HH
+
+#include <vector>
+#include <dune/common/bitsetvector.hh>
+#include <dune/solvers/transferoperators/truncateddensemgtransfer.hh>
+#include <dune/solvers/transferoperators/truncatedcompressedmgtransfer.hh>
+
+
+/** \brief Multigrid restriction and prolongation operator for contact problems using the TNNMG method.
+ *
+ * Currently only works for first-order Lagrangian elements!
+ *
+ *   This class sets up the multigrid transfer operator for n-body contact
+ *   problems.  It first constructs the standard prolongation matrices for the
+ *   grids and then combines them into a single matrix.  Then, this matrix
+ *   is modified using the mortar transformation basis of Wohlmuth, Krause: "Monotone
+ *   Methods on Nonmatching Grids for Nonlinear Contact Problems". In the TNNMG method
+ *   the nonlinear obstacle problem is only solved on the finest level using a smoother.
+ *   As coarse grid correction a linear multigrid step is applied which is later projected
+ *   back onto the admissible set. Consequently the mortar basis is only needed on the finest
+ *   level. This transfer operator thus additionally to the restriction and truncation,
+ *   transformes the mortar basis back to the nodal basis on the finest level and otherwise
+ *   just does standard restriction/prolongation. On the finest level the prolongation matrix
+ *   is of the form
+
+ *   \f[ \begin{pmatrix}
+ *        (I_l^{l+1})_{ii} & (I_l^{l+1})_{im}       & (I_l^{l+1})_{is} \\
+ *        0                & (I_l^{l+1})_{mm}       & 0 \\
+ *        0                & -M_{l+1}(I_l^{l+1})_{mm} & (I_l^{l+1})_{ss}
+ *       \end{pmatrix} \f].
+ *
+ *   where \f[ I_l^{l+1} \f] denote the standard transfer operators
+ *     and \f[ M_{l+1} \f] denotes the weighted mortar matrix
+ */
+template<class ContactNetwork, class VectorType>
+class NBodyContactTransfer : public TruncatedDenseMGTransfer<VectorType> {
+
+    enum {blocksize = VectorType::block_type::dimension};
+
+    using field_type = typename VectorType::field_type;
+
+    using MatrixBlock = Dune::FieldMatrix<field_type, blocksize, blocksize>;
+    using MatrixType = Dune::BCRSMatrix<MatrixBlock>;
+
+    using CoordSystemVector = std::vector<MatrixBlock>;
+
+public:
+
+    typedef typename MultigridTransfer<VectorType>::OperatorType OperatorType;
+
+    /** \brief Setup transfer operator for a N-body contact problem.
+     *
+     *  \param grids The involved grids
+     *  \param colevel The co-level of the fine grid level to which the transfer operator belongs
+     *  \param mortarTransferOperator The weighted mortar matrices of the couplings
+     *  \param fineLocalCoordSystems A vector containing the local coordinate systems (householder transformations) of all grids
+     *  \param fineHasObstacle  Bitfields determining for each coupling which fine grid nodes belong to the nonmortar boundary.
+     *  \param gridIdx  For each coupling store the indices of the nonmortar and mortar grid.
+    */
+    template <class GridType>
+    void setup(const std::vector<const GridType*>& grids, int colevel,
+               const std::vector<const MatrixType*>& mortarTransferOper,
+               const CoordSystemVector& fineLocalCoordSystems,
+               const std::vector<const BitSetVector<1>*>& fineHasObstacle,
+               const std::vector<std::array<int,2> >& gridIdx);
+
+protected:
+    /** \brief Combine all the standard prolongation and mortar operators to one big matrix.
+     *
+     *  \param submat The standard transfer operators
+     *  \param mortarTransferOperator The weighted mortar matrices of the couplings
+     *  \param fineLocalCoordSystems A vector containing the local coordinate systems (householder transformations) of all grids
+     *  \param fineHasObstacle  Bitfields determining for each coupling which fine grid nodes belong to the nonmortar boundary.
+     *  \param gridIdx  For each coupling store the indices of the nonmortar and mortar grid.
+
+    */
+    void combineSubMatrices(const std::vector<const MatrixType*>& submat,
+                            const std::vector<const MatrixType*>& mortarTransferOperator,
+                            const CoordSystemVector& fineLocalCoordSystems,
+                            const std::vector<const BitSetVector<1>*>& fineHasObstacle,
+                            const std::vector<std::array<int,2> >& gridIdx);
+
+};
+
+#include "nbodycontacttransfer.cc"
+
+#endif
diff --git a/src/spatial-solving/preconditioners/supportpatchfactory.hh b/src/spatial-solving/preconditioners/supportpatchfactory.hh
index 07091fee..15348097 100644
--- a/src/spatial-solving/preconditioners/supportpatchfactory.hh
+++ b/src/spatial-solving/preconditioners/supportpatchfactory.hh
@@ -102,12 +102,12 @@ template <class LevelContactNetwork>
 class SupportPatchFactory
 {
 public:
-    using Patch = Dune::BitSetVector<1>;
-
-private:
     static const int dim = LevelContactNetwork::dim; //TODO
     using ctype = typename LevelContactNetwork::ctype;
 
+    using Patch = Dune::BitSetVector<dim>;
+
+private:
     using Element = typename LevelContactNetwork::GridView::template Codim<0>::Entity;
 
     struct RemoteIntersection {
@@ -555,14 +555,14 @@ class SupportPatchFactory
     void addToPatchBoundary(const std::set<size_t>& dofs, std::set<size_t>& patchBoundary, Patch& patchDofs) {
         for (auto& dof : dofs) {
             patchBoundary.insert(dof);
-            patchDofs[dof][0] = true;
+            patchDofs[dof] = true;
         }
     }
 
     void addToPatch(const std::set<size_t>& dofs, const std::set<size_t>& patchBoundary, Patch& patchDofs) {
         for (auto& dof : dofs) {
             if (!patchBoundary.count(dof)) {
-                patchDofs[dof][0] = false;
+                patchDofs[dof] = false;
             }
         }
     }
diff --git a/src/spatial-solving/solverfactory.cc b/src/spatial-solving/solverfactory.cc
index b40d02d1..6196d3ea 100644
--- a/src/spatial-solving/solverfactory.cc
+++ b/src/spatial-solving/solverfactory.cc
@@ -11,22 +11,20 @@
 #include "../utils/debugutils.hh"
 
 template <class Functional, class BitVector>
+template <class Preconditioner>
 SolverFactory<Functional, BitVector>::SolverFactory(
     const Dune::ParameterTree& parset,
     Functional& J,
+    Preconditioner&& preconditioner,
     const BitVector& ignoreNodes) :
-      J_(Dune::Solvers::wrap_own_share<const Functional>(std::forward<Functional>(J)))
-      //linear solver
-      //preconditioner_(),
-      //linearSolverStep_(),
-    {
+        J_(Dune::Solvers::wrap_own_share<const Functional>(std::forward<Functional>(J))) {
+
     nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, LocalSolver());
 
-    // linearSolverStep_.setPreconditioner(preconditioner_);
-    linearSolverStep_ = Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::createPtr(Dune::Solvers::BlockGS::LocalSolvers::ldlt());
+    linearSolverStep_ = std::make_shared<LinearSolverStep>();
+    linearSolverStep_.setPreconditioner(std::forward<Preconditioner>(preconditioner));
     energyNorm_ = std::make_shared<EnergyNorm<Matrix, Vector>>(*linearSolverStep_);
-    //linearSolver_ = std::make_shared<LinearSolver>(*linearSolverStep_, parset.get<size_t>("linear.maximumIterations"), parset.get<double>("linear.tolerance"), *energyNorm_, Solver::QUIET);
-    linearSolver_ = std::make_shared<Dune::Solvers::UMFPackSolver<Matrix, Vector>>();
+    linearSolver_ = std::make_shared<LinearSolver>(*linearSolverStep_, parset.get<size_t>("linear.maximumIterations"), parset.get<double>("linear.tolerance"), *energyNorm_, Solver::QUIET);
 
     tnnmgStep_ = std::make_shared<Step>(*J_, dummyIterate_, nonlinearSmoother_, linearSolver_, DefectProjection(), LineSearchSolver());
     tnnmgStep_->setPreSmoothingSteps(parset.get<int>("main.pre"));
diff --git a/src/spatial-solving/solverfactory.hh b/src/spatial-solving/solverfactory.hh
index 607ac365..458b54d7 100644
--- a/src/spatial-solving/solverfactory.hh
+++ b/src/spatial-solving/solverfactory.hh
@@ -8,9 +8,7 @@
 
 #include <dune/solvers/norms/energynorm.hh>
 #include <dune/solvers/solvers/loopsolver.hh>
-#include <dune/solvers/iterationsteps/lineariterationstep.hh>
-//#include <dune/solvers/iterationsteps/cgstep.hh>
-//#include <dune/solvers/iterationsteps/amgstep.hh>
+#include <dune/solvers/iterationsteps/cgstep.hh>
 
 //#include <dune/tnnmg/iterationsteps/tnnmgstep.hh>
 #include <dune/tnnmg/iterationsteps/nonlineargsstep.hh>
@@ -22,8 +20,6 @@
 #include "tnnmg/linesearchsolver.hh"
 #include "tnnmg/localbisectionsolver.hh"
 
-//#include "preconditioners/supportpatchfactory.hh"
-
 template <class FunctionalTEMPLATE, class BitVectorType>
 class SolverFactory {
 public:
@@ -34,25 +30,18 @@ class SolverFactory {
 
     using LocalSolver = LocalBisectionSolver;
     using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, LocalSolver>;
-
     using Linearization = Linearization<Functional, BitVector>;
-    //using Preconditioner = Dune::Solvers::Preconditioner; //TODO Platzhalter für PatchPreconditioner
-    //using LinearSolverStep = typename Dune::Solvers::CGStep<Matrix, Vector, BitVector>;
-    //using LinearSolverStep = typename Dune::Solvers::AMGStep<Matrix, Vector>;
-    using LinearSolverStep = LinearIterationStep<Matrix, Vector>;
-    //using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
-    using LinearSolver = typename Dune::Solvers::LinearSolver<Matrix, Vector>;
-
-    //using LinearSolver = typename Dune::Solvers::UMFPackSolver<Matrix, Vector>;
-    //using LinearSolver = typename Dune::TNNMG::FastAMGSolver<Matrix, Vector>;
-
     using DefectProjection = typename Dune::TNNMG::ObstacleDefectProjection;
 
     using Step = typename Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver>;
 
+    using LinearSolverStep = typename Dune::Solvers::CGStep<Matrix, Vector, BitVector>;
+    using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
 
+  template <class Preconditioner>
   SolverFactory(Dune::ParameterTree const &,
                 Functional&,
+                Preconditioner&& preconditioner,
                 const BitVector&);
 
   void setProblem(Vector& x);
@@ -67,7 +56,6 @@ class SolverFactory {
   std::shared_ptr<NonlinearSmoother> nonlinearSmoother_;
 
   // linear solver
-  //Preconditioner preconditioner_;
   std::shared_ptr<LinearSolverStep> linearSolverStep_;
   std::shared_ptr<EnergyNorm<Matrix, Vector>> energyNorm_;
   std::shared_ptr<LinearSolver> linearSolver_;
diff --git a/src/time-stepping/adaptivetimestepper.cc b/src/time-stepping/adaptivetimestepper.cc
index e2608f9b..fae06ed6 100644
--- a/src/time-stepping/adaptivetimestepper.cc
+++ b/src/time-stepping/adaptivetimestepper.cc
@@ -50,7 +50,8 @@ bool AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::reached
 }
 
 template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
-IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::advance() {
+template <class Preconditioner>
+IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::advance(Preconditioner&& preconditioner) {
   /*
     |     C     | We check here if making the step R1 of size tau is a
     |  R1 | R2  | good idea. To check if we can coarsen, we compare
@@ -63,7 +64,7 @@ IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNo
   std::cout << "AdaptiveTimeStepper::advance()" << std::endl;
 
   if (R1_.updaters == Updaters())
-    R1_ = step(current_, relativeTime_, relativeTau_);
+    R1_ = step(current_, relativeTime_, relativeTau_, std::forward<Preconditioner>(preconditioner));
 
   std::cout << "AdaptiveTimeStepper Step 1" << std::endl;
 
@@ -73,9 +74,9 @@ IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNo
   UpdatersWithCount R2;
   UpdatersWithCount C;
   while (relativeTime_ + relativeTau_ <= 1.0) {
-    R2 = step(R1_.updaters, relativeTime_ + relativeTau_, relativeTau_);
+    R2 = step(R1_.updaters, relativeTime_ + relativeTau_, relativeTau_, std::forward<Preconditioner>(preconditioner));
     std::cout << "AdaptiveTimeStepper R2 computed!" << std::endl << std::endl;
-    C = step(current_, relativeTime_, 2 * relativeTau_);
+    C = step(current_, relativeTime_, 2 * relativeTau_, std::forward<Preconditioner>(preconditioner));
     std::cout << "AdaptiveTimeStepper C computed!" << std::endl << std::endl;
     if (mustRefine_(R2.updaters, C.updaters))
       break;
@@ -90,10 +91,10 @@ IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNo
   UpdatersWithCount F2;
   if (!didCoarsen) {
     while (true) {
-      F1 = step(current_, relativeTime_, relativeTau_ / 2.0);
+      F1 = step(current_, relativeTime_, relativeTau_ / 2.0, std::forward<Preconditioner>(preconditioner));
       std::cout << "AdaptiveTimeStepper F1 computed!" << std::endl << std::endl;
       F2 = step(F1.updaters, relativeTime_ + relativeTau_ / 2.0,
-                relativeTau_ / 2.0);
+                relativeTau_ / 2.0, std::forward<Preconditioner>(preconditioner));
       std::cout << "AdaptiveTimeStepper F2 computed!" << std::endl << std::endl;
       if (!mustRefine_(F2.updaters, R1_.updaters)) {
         std::cout << "Sufficiently refined!" << std::endl;
@@ -122,15 +123,16 @@ IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNo
 }
 
 template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+template <class Preconditioner>
 typename AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::UpdatersWithCount
 AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::step(
-    Updaters const &oldUpdaters, double rTime, double rTau) {
+    Updaters const &oldUpdaters, double rTime, double rTau, Preconditioner&& preconditioner) {
   UpdatersWithCount newUpdatersAndCount = {oldUpdaters.clone(), {}};
   newUpdatersAndCount.count =
       MyCoupledTimeStepper(finalTime_, parset_, nBodyAssembler_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_,
                            newUpdatersAndCount.updaters, errorNorms_,
                            externalForces_)
-          .step(rTime, rTau);
+          .step(rTime, rTau, std::forward<Preconditioner>(preconditioner));
   iterationRegister_.registerCount(newUpdatersAndCount.count);
   return newUpdatersAndCount;
 }
diff --git a/src/time-stepping/adaptivetimestepper.hh b/src/time-stepping/adaptivetimestepper.hh
index af9fb0b1..3e48b221 100644
--- a/src/time-stepping/adaptivetimestepper.hh
+++ b/src/time-stepping/adaptivetimestepper.hh
@@ -48,14 +48,17 @@ class AdaptiveTimeStepper {
                       std::function<bool(Updaters &, Updaters &)> mustRefine);
 
   bool reachedEnd();
-  IterationRegister advance();
+
+  template <class Preconditioner>
+  IterationRegister advance(Preconditioner&& preconditioner);
 
   double relativeTime_;
   double relativeTau_;
 
 private:
+  template <class Preconditioner>
   UpdatersWithCount step(Updaters const &oldUpdaters, double rTime,
-                         double rTau);
+                         double rTau, Preconditioner&& preconditioner);
 
   double finalTime_;
   Dune::ParameterTree const &parset_;
diff --git a/src/time-stepping/coupledtimestepper.cc b/src/time-stepping/coupledtimestepper.cc
index d3b9b1e2..6b9daac7 100644
--- a/src/time-stepping/coupledtimestepper.cc
+++ b/src/time-stepping/coupledtimestepper.cc
@@ -25,9 +25,10 @@ CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::CoupledTimeSt
       errorNorms_(errorNorms) {}
 
 template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+template <class Preconditioner>
 FixedPointIterationCounter
 CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::step(double relativeTime,
-                                                       double relativeTau) {
+                                                       double relativeTau, Preconditioner&& preconditioner) {
 
   std::cout << "CoupledTimeStepper::step()" << std::endl;
 
@@ -50,8 +51,8 @@ CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::step(double r
 
   FixedPointIterator fixedPointIterator(
       parset_, nBodyAssembler_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, errorNorms_);
-  auto const iterations = fixedPointIterator.run(updaters_, velocityMatrix,
-                                                 velocityRHS, velocityIterate);
+  auto const iterations = fixedPointIterator.run(updaters_, std::forward<Preconditioner>(preconditioner),
+                                                 velocityMatrix, velocityRHS, velocityIterate);
   return iterations;
 }
 
diff --git a/src/time-stepping/coupledtimestepper.hh b/src/time-stepping/coupledtimestepper.hh
index 8b017775..0b2ac468 100644
--- a/src/time-stepping/coupledtimestepper.hh
+++ b/src/time-stepping/coupledtimestepper.hh
@@ -31,7 +31,8 @@ class CoupledTimeStepper {
                      const ErrorNorms& errorNorms,
                      ExternalForces& externalForces);
 
-  FixedPointIterationCounter step(double relativeTime, double relativeTau);
+  template <class Preconditioner>
+  FixedPointIterationCounter step(double relativeTime, double relativeTau, Preconditioner&& preconditioner);
 
 private:
   double finalTime_;
-- 
GitLab