From 8e48508f58de63a8209ef4bc74585a247357d8a7 Mon Sep 17 00:00:00 2001
From: podlesny <podlesny@mi.fu-berlin.de>
Date: Fri, 21 Jun 2019 18:03:28 +0200
Subject: [PATCH] .

---
 src/CMakeLists.txt                            |   7 +-
 src/data-structures/body.cc                   | 300 ++++++++------
 src/data-structures/body.hh                   | 162 +++++---
 src/data-structures/body_tmpl.cc              |   5 +-
 src/data-structures/contactnetwork.cc         | 391 +++++++++++++++++-
 src/data-structures/contactnetwork.hh         | 153 ++++++-
 src/data-structures/contactnetwork_tmpl.cc    |   7 +-
 src/data-structures/levelcontactnetwork.cc    | 342 ++++-----------
 src/data-structures/levelcontactnetwork.hh    | 214 ++++------
 .../levelcontactnetwork_tmpl.cc               |   8 +-
 src/data-structures/program_state.hh          |  22 +-
 src/explicitvectors.hh                        |  10 +-
 src/factories/contactnetworkfactory.hh        |  36 +-
 src/factories/levelcontactnetworkfactory.hh   |   8 +-
 src/factories/stackedblocksfactory.cc         |   1 -
 src/factories/threeblocksfactory.cc           | 204 +++++++++
 src/factories/threeblocksfactory.hh           |  84 ++++
 src/factories/threeblocksfactory_tmpl.cc      |   8 +
 .../grid/cuboidgeometry.cc                    | 131 +++---
 .../grid/cuboidgeometry.hh                    |  80 ++--
 .../grid/cuboidgeometry_tmpl.cc               |   8 +
 src/multi-body-problem-data/grid/mygrids.cc   |  30 +-
 src/multi-body-problem-data/grid/mygrids.hh   |  10 +-
 .../grid/mygrids_tmpl.cc                      |   4 +-
 src/multi-body-problem-data/weakpatch.hh      |  67 ---
 src/multi-body-problem.cc                     | 177 +++++---
 .../contact/dualmortarcoupling.hh             |   4 +-
 src/spatial-solving/fixedpointiterator.cc     |  14 +-
 src/spatial-solving/fixedpointiterator.hh     |   8 +-
 .../fixedpointiterator_tmpl.cc                |  12 +-
 .../preconditioners/supportpatchfactory.hh    | 173 ++++----
 src/tests/CMakeLists.txt                      |   1 +
 src/tests/supportpatchfactorytest.cc          | 144 +++++++
 src/time-stepping/adaptivetimestepper.cc      |  20 +-
 src/time-stepping/adaptivetimestepper.hh      |   8 +-
 src/time-stepping/adaptivetimestepper_tmpl.cc |  14 +-
 src/time-stepping/coupledtimestepper.cc       |  12 +-
 src/time-stepping/coupledtimestepper.hh       |  16 +-
 src/time-stepping/coupledtimestepper_tmpl.cc  |  12 +-
 src/time-stepping/rate/rateupdater_tmpl.cc    |   6 +-
 src/time-stepping/rate_tmpl.cc                |   6 +-
 src/utils/debugutils.hh                       |  17 +-
 42 files changed, 1953 insertions(+), 983 deletions(-)
 create mode 100644 src/factories/threeblocksfactory.cc
 create mode 100644 src/factories/threeblocksfactory.hh
 create mode 100644 src/factories/threeblocksfactory_tmpl.cc
 create mode 100644 src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc
 delete mode 100644 src/multi-body-problem-data/weakpatch.hh
 create mode 100644 src/tests/supportpatchfactorytest.cc

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0cfcc708..6bf43fe7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -28,11 +28,12 @@ set(MSW_SOURCE_FILES
   assemblers.cc
   #nodalweights.cc
   data-structures/body.cc
-  #data-structures/contactnetwork.cc
-  data-structures/enumparser.cc
   data-structures/levelcontactnetwork.cc
+  data-structures/contactnetwork.cc
+  data-structures/enumparser.cc
   #factories/cantorfactory.cc
-  factories/stackedblocksfactory.cc
+  factories/threeblocksfactory.cc
+  #factories/stackedblocksfactory.cc
   io/vtk.cc
   io/hdf5/frictionalboundary-writer.cc
   io/hdf5/iteration-writer.cc
diff --git a/src/data-structures/body.cc b/src/data-structures/body.cc
index 39220bd5..75d92f7d 100644
--- a/src/data-structures/body.cc
+++ b/src/data-structures/body.cc
@@ -2,33 +2,31 @@
 #include "config.h"
 #endif
 
-
+#include <dune/common/hybridutilities.hh>
 #include "body.hh"
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-Body<GridTEMPLATE, VectorTEMPLATE, dims>::Body(
-        const std::shared_ptr<BodyData<dims>>& bodyData,
-        const std::shared_ptr<GridType>& grid) :
+// -------------------------------
+// --- LeafBody Implementation ---
+// -------------------------------
+template <class GridTEMPLATE, class VectorType>
+LeafBody<GridTEMPLATE, VectorType>::LeafBody(
+        const std::shared_ptr<BodyData<dim>>& bodyData,
+        const std::shared_ptr<GridTEMPLATE>& hostGrid) :
     bodyData_(bodyData),
-    grid_(grid),
-    deformation_(std::make_shared<DeformationFunction>(grid_->leafGridView())),
-    deformedGrid_(std::make_shared<DeformedGridType>(*grid_, *deformation_)),
-    leafView_(deformedGrid_->leafGridView()),
-    leafVertexCount_(leafView_.size(dims)),
-    assembler_(std::make_shared<Assembler>(leafView_)),
+    hostGrid_(hostGrid),
+    deformation_(std::make_shared<DeformationFunction>(hostGrid_->leafGridView())),
+    grid_(std::make_shared<GridType>(*hostGrid_, *deformation_)),
+    gridView_(grid_->leafGridView()),
+    assembler_(std::make_shared<Assembler>(gridView_)),
     matrices_()
 {
-    leafBoundaryConditions_.resize(0);
 
-    levelBoundaryConditions_.resize(grid_->maxLevel()+1);
-    for (size_t i=0; i<levelBoundaryConditions_.size(); i++) {
-        levelBoundaryConditions_[i].resize(0);
-    }
+    boundaryConditions_.resize(0);
 
     externalForce_ = [&](double relativeTime, VectorType &ell) {
         // Problem formulation: right-hand side
-        std::vector<std::shared_ptr<LeafBoundaryCondition>> leafNeumannConditions;
-        leafBoundaryConditions("neumann", leafNeumannConditions);
+        std::vector<std::shared_ptr<BoundaryCondition>> leafNeumannConditions;
+        boundaryConditions("neumann", leafNeumannConditions);
         ell.resize(gravityFunctional_.size());
         ell = gravityFunctional_;
 
@@ -44,8 +42,8 @@ Body<GridTEMPLATE, VectorTEMPLATE, dims>::Body(
 }
 
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::assemble() {
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::assemble() {
 
     // assemble matrices
     assembler_->assembleElasticity(bodyData_->getYoungModulus(), bodyData_->getPoissonRatio(), *matrices_.elasticity);
@@ -58,204 +56,274 @@ void Body<GridTEMPLATE, VectorTEMPLATE, dims>::assemble() {
 
 // setter and getter
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::data() const
--> const std::shared_ptr<BodyData<dims>>& {
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::data() const
+-> const std::shared_ptr<BodyData<dim>>& {
 
     return bodyData_;
 }
 
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::setDeformation(const VectorType& def) {
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::setDeformation(const VectorType& def) {
     deformation_->setDeformation(def);
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::deformation() const
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::deformation() const
 -> DeformationFunction& {
 
     return *deformation_;
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::deformedGrid() const
--> const DeformedGridType* {
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::grid() const
+-> std::shared_ptr<GridType> {
 
-    return deformedGrid_.get();
+    return grid_;
 }
 
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::leafView() const
--> const DeformedLeafGridView& {
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::gridView() const
+-> const GridView& {
 
-    return leafView_;
+    return gridView_;
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::leafVertexCount() const
--> int {
-
-    return leafVertexCount_;
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::nVertices() const
+-> size_t {
+    return gridView_.size(dim);
 }
 
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::assembler() const
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::assembler() const
 -> const std::shared_ptr<Assembler>& {
 
     return assembler_;
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::matrices() const
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::matrices() const
 -> const Matrices<Matrix,1>& {
 
     return matrices_;
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::externalForce() const
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::externalForce() const
 -> const ExternalForce& {
 
     return externalForce_;
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::addBoundaryCondition(std::shared_ptr<LeafBoundaryCondition> leafBoundaryCondition) {
-    leafBoundaryConditions_.emplace_back(leafBoundaryCondition);
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::addBoundaryCondition(std::shared_ptr<BoundaryCondition> boundaryCondition) {
+    boundaryConditions_.emplace_back(boundaryCondition);
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::leafBoundaryConditions(
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::boundaryConditions(
         const std::string& tag,
-        std::vector<std::shared_ptr<LeafBoundaryCondition>>& selectedConditions) const {
+        std::vector<std::shared_ptr<BoundaryCondition>>& selectedConditions) const {
 
     selectedConditions.resize(0);
-    for (size_t i=0; i<leafBoundaryConditions_.size(); i++) {
-        if (leafBoundaryConditions_[i]->tag() == tag)
-            selectedConditions.emplace_back(leafBoundaryConditions_[i]);
+    for (size_t i=0; i<boundaryConditions_.size(); i++) {
+        if (boundaryConditions_[i]->tag() == tag)
+            selectedConditions.emplace_back(boundaryConditions_[i]);
     }
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::leafBoundaryConditions() const
--> const std::vector<std::shared_ptr<LeafBoundaryCondition>>& {
+template <class GridTEMPLATE, class VectorType>
+auto LeafBody<GridTEMPLATE, VectorType>::boundaryConditions() const
+-> const std::vector<std::shared_ptr<BoundaryCondition>>& {
 
-    return leafBoundaryConditions_;
+    return boundaryConditions_;
 }
 
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::boundaryPatchNodes(
+        const std::string& tag,
+        BoundaryPatchNodes& nodes) const {
+
+    std::vector<std::shared_ptr<typename LeafBody::BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::addBoundaryCondition(
-        std::shared_ptr<LevelBoundaryCondition> levelBoundaryCondition,
-        int level) {
+    nodes.resize(_boundaryConditions.size());
 
-    levelBoundaryConditions_[level].push_back(levelBoundaryCondition);
+    for (size_t i=0; i<nodes.size(); i++) {
+        nodes[i] = _boundaryConditions[i]->boundaryPatch()->getVertices();
+    }
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::levelBoundaryConditions(
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::boundaryNodes(
         const std::string& tag,
-        std::vector<std::vector<std::shared_ptr<LevelBoundaryCondition>>>& selectedConditions) const {
-
-    selectedConditions.resize(levelBoundaryConditions_.size());
-    for (size_t level=0; level<levelBoundaryConditions_.size(); level++) {
-        const std::vector<std::shared_ptr<LevelBoundaryCondition>>& levelBoundaryConditions = levelBoundaryConditions_[level];
-        for (size_t i=0; i<levelBoundaryConditions.size(); i++) {
-            if (levelBoundaryConditions[i]->tag() == tag)
-                selectedConditions[level].push_back(levelBoundaryConditions[i]);
-        }
+        BoundaryNodes& nodes) const {
+
+    std::vector<std::shared_ptr<typename LeafBody::BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
+
+    nodes.resize(_boundaryConditions.size());
+
+    for (size_t i=0; i<nodes.size(); i++) {
+        nodes[i] = _boundaryConditions[i]->boundaryNodes().get();
     }
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::levelBoundaryConditions(
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::boundaryFunctions(
         const std::string& tag,
-        int level,
-        std::vector<std::shared_ptr<LevelBoundaryCondition>>& selectedConditions) const {
+        BoundaryFunctions& functions) const {
 
-    selectedConditions.resize(0);
-    const std::vector<std::shared_ptr<LevelBoundaryCondition>>& levelBoundaryConditions = levelBoundaryConditions_[level];
-    for (size_t i=0; i<levelBoundaryConditions.size(); i++) {
-        if (levelBoundaryConditions[i]->tag() == tag)
-            selectedConditions.push_back(levelBoundaryConditions[i]);
+    std::vector<std::shared_ptr<typename LeafBody::BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
+
+    functions.resize(_boundaryConditions.size());
+
+    for (size_t i=0; i<functions.size(); i++) {
+        functions[i] = _boundaryConditions[i]->boundaryFunction().get();
+    }
+}
+
+template <class GridTEMPLATE, class VectorType>
+void LeafBody<GridTEMPLATE, VectorType>::boundaryPatches(
+        const std::string& tag,
+        BoundaryPatches& patches) const {
+
+    std::vector<std::shared_ptr<typename LeafBody::BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
+
+    patches.resize(_boundaryConditions.size());
+
+    for (size_t i=0; i<patches.size(); i++) {
+        patches[i] = _boundaryConditions[i]->boundaryPatch().get();
     }
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::levelBoundaryConditions(int level) const
--> const std::vector<std::shared_ptr<LevelBoundaryCondition>>& {
 
-    return levelBoundaryConditions_[level];
+// ---------------------------
+// --- Body Implementation ---
+// ---------------------------
+
+// setter and getter
+
+template <class GridView>
+auto Body<GridView>::data() const
+-> const std::shared_ptr<BodyData<dim>>& {
+
+    return bodyData_;
+}
+
+
+template <class GridView>
+auto Body<GridView>::grid() const
+-> std::shared_ptr<GridType> {
+
+    return grid_;
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-auto Body<GridTEMPLATE, VectorTEMPLATE, dims>::levelBoundaryConditions() const
--> const std::vector<std::vector<std::shared_ptr<LevelBoundaryCondition>>>& {
+template <class GridView>
+auto Body<GridView>::gridView() const
+-> const GridView& {
+
+    return gridView_;
+}
+
+template <class GridView>
+auto Body<GridView>::nVertices() const
+-> size_t {
+    return gridView_.size(dim);
+}
+
+
+template <class GridView>
+void Body<GridView>::addBoundaryCondition(std::shared_ptr<BoundaryCondition> boundaryCondition) {
+
+    boundaryConditions_.push_back(boundaryCondition);
+}
+
+
+template <class GridView>
+void Body<GridView>::boundaryConditions(
+        const std::string& tag,
+        std::vector<std::shared_ptr<BoundaryCondition>>& selectedConditions) const {
+
+    selectedConditions.resize(0);
+    for (size_t i=0; i<boundaryConditions_.size(); i++) {
+        if (boundaryConditions_[i]->tag() == tag)
+            selectedConditions.push_back(boundaryConditions_[i]);
+    }
+}
+
+
+template <class GridView>
+auto Body<GridView>::boundaryConditions() const
+-> const std::vector<std::shared_ptr<BoundaryCondition>>& {
 
-    return levelBoundaryConditions_;
+    return boundaryConditions_;
 }
 
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::boundaryPatchNodes(
+template <class GridView>
+void Body<GridView>::boundaryPatchNodes(
         const std::string& tag,
         BoundaryPatchNodes& nodes) const {
 
-    std::vector<std::shared_ptr<typename Body::LeafBoundaryCondition>> boundaryConditions;
-    this->leafBoundaryConditions(tag, boundaryConditions);
+    std::vector<std::shared_ptr<BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
 
-    nodes.resize(boundaryConditions.size());
+    nodes.resize(_boundaryConditions.size());
 
     for (size_t i=0; i<nodes.size(); i++) {
-        nodes[i] = boundaryConditions[i]->boundaryPatch()->getVertices();
+        nodes[i] = _boundaryConditions[i]->boundaryPatch()->getVertices();
     }
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::boundaryNodes(
+template <class GridView>
+void Body<GridView>::boundaryNodes(
         const std::string& tag,
         BoundaryNodes& nodes) const {
 
-    std::vector<std::shared_ptr<typename Body::LeafBoundaryCondition>> boundaryConditions;
-    this->leafBoundaryConditions(tag, boundaryConditions);
+    std::vector<std::shared_ptr<BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
 
-    nodes.resize(boundaryConditions.size());
+    nodes.resize(_boundaryConditions.size());
 
     for (size_t i=0; i<nodes.size(); i++) {
-        nodes[i] = boundaryConditions[i]->boundaryNodes().get();
+        nodes[i] = _boundaryConditions[i]->boundaryNodes().get();
     }
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::boundaryFunctions(
+template <class GridView>
+void Body<GridView>::boundaryFunctions(
         const std::string& tag,
         BoundaryFunctions& functions) const {
 
-    std::vector<std::shared_ptr<typename Body::LeafBoundaryCondition>> boundaryConditions;
-    this->leafBoundaryConditions(tag, boundaryConditions);
+    std::vector<std::shared_ptr<BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
 
-    functions.resize(boundaryConditions.size());
+    functions.resize(_boundaryConditions.size());
 
     for (size_t i=0; i<functions.size(); i++) {
-        functions[i] = boundaryConditions[i]->boundaryFunction().get();
+        functions[i] = _boundaryConditions[i]->boundaryFunction().get();
     }
 }
 
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-void Body<GridTEMPLATE, VectorTEMPLATE, dims>::boundaryPatches(
+template <class GridView>
+void Body<GridView>::boundaryPatches(
         const std::string& tag,
         BoundaryPatches& patches) const {
 
-    std::vector<std::shared_ptr<typename Body::LeafBoundaryCondition>> boundaryConditions;
-    this->leafBoundaryConditions(tag, boundaryConditions);
+    std::vector<std::shared_ptr<BoundaryCondition>> _boundaryConditions;
+    this->boundaryConditions(tag, _boundaryConditions);
 
-    patches.resize(boundaryConditions.size());
+    patches.resize(_boundaryConditions.size());
 
     for (size_t i=0; i<patches.size(); i++) {
-        patches[i] = boundaryConditions[i]->boundaryPatch().get();
+        patches[i] = _boundaryConditions[i]->boundaryPatch().get();
     }
 }
 
diff --git a/src/data-structures/body.hh b/src/data-structures/body.hh
index ed71b586..6b5463cd 100644
--- a/src/data-structures/body.hh
+++ b/src/data-structures/body.hh
@@ -2,6 +2,7 @@
 #define SRC_DATA_STRUCTURES_BODY_HH
 
 #include <functional>
+#include <type_traits>
 
 #include <dune/common/bitsetvector.hh>
 #include <dune/common/function.hh>
@@ -30,51 +31,41 @@
 #include "enums.hh"
 #include "matrices.hh"
 
-
-
-template <class GridTEMPLATE, class VectorTEMPLATE, int dims>
-class Body {
+template <class HostGridType, class VectorType>
+class LeafBody {
 public:
-    using GridType = GridTEMPLATE;
-    using VectorType = VectorTEMPLATE;
+    static const int dim = HostGridType::dimensionworld;
 
-    using DeformationFunction = DeformationFunction<typename GridType::LeafGridView, VectorType>;
-    using DeformedGridType = Dune::GeometryGrid<GridType, DeformationFunction>;
-    using DeformedLeafGridView = typename DeformedGridType::LeafGridView;
-    using DeformedLevelGridView = typename DeformedGridType::LevelGridView;
+    using DeformationFunction = DeformationFunction<typename HostGridType::LeafGridView, VectorType>;
+    using GridType = Dune::GeometryGrid<HostGridType, DeformationFunction>;
+    using GridView = typename GridType::LeafGridView;
 
-    using Assembler = MyAssembler<DeformedLeafGridView, dims>;
+    using Function = Dune::VirtualFunction<double, double>;
+    using ExternalForce = std::function<void(double, VectorType &)>;
+
+    using Assembler = MyAssembler<GridView, dim>;
     using Matrix = typename Assembler::Matrix;
     using LocalVector = typename VectorType::block_type;
 
     using ScalarMatrix = Dune::BCRSMatrix<Dune::FieldMatrix<double, 1, 1>>;
     using ScalarVector = Dune::BlockVector<Dune::FieldVector<double, 1>>;
 
-    using Function = Dune::VirtualFunction<double, double>;
-    using ExternalForce = std::function<void(double, VectorType &)>;
-
-    using LeafBoundaryCondition = BoundaryCondition<DeformedLeafGridView, dims>;   
-    using LevelBoundaryCondition = BoundaryCondition<DeformedLevelGridView, dims>;
+    using BoundaryCondition = BoundaryCondition<GridView, dim>;
 
     using BoundaryFunctions = std::vector<const Function* >;
-    using BoundaryNodes = std::vector<const Dune::BitSetVector<dims>* >;
+    using BoundaryNodes = std::vector<const Dune::BitSetVector<dim>* >;
     using BoundaryPatchNodes = std::vector<const Dune::BitSetVector<1>* >;
-    using BoundaryPatches = std::vector<const typename LeafBoundaryCondition::BoundaryPatch* >;
+    using BoundaryPatches = std::vector<const typename BoundaryCondition::BoundaryPatch* >;
 
     using StateEnergyNorm = EnergyNorm<ScalarMatrix, ScalarVector>;
 
 private:
-    std::shared_ptr<Body<GridType, VectorType, dims>> parent_;
-    std::vector<std::shared_ptr<Body<GridType, VectorType, dims>>> children_;
+    std::shared_ptr<BodyData<dim>> bodyData_;
 
-    std::shared_ptr<BodyData<dims>> bodyData_;
-
-    std::shared_ptr<GridType> grid_;
+    std::shared_ptr<HostGridType> hostGrid_;
     std::shared_ptr<DeformationFunction> deformation_;
-    std::shared_ptr<DeformedGridType> deformedGrid_;
-
-    DeformedLeafGridView leafView_;
-    int leafVertexCount_;
+    std::shared_ptr<GridType> grid_;
+    GridView gridView_;
 
     std::shared_ptr<Assembler> assembler_;
     Matrices<Matrix,1> matrices_;
@@ -84,47 +75,122 @@ class Body {
     VectorType gravityFunctional_;
 
     // boundary conditions
-    std::vector<std::shared_ptr<LeafBoundaryCondition>> leafBoundaryConditions_;
-    std::vector<std::vector<std::shared_ptr<LevelBoundaryCondition>>> levelBoundaryConditions_; // first index: level, second index: bc on lvl
+    std::vector<std::shared_ptr<BoundaryCondition>> boundaryConditions_;
 
 public:
-    Body(
-            const std::shared_ptr<BodyData<dims>>& bodyData,
-            const std::shared_ptr<GridType>& grid);
+    LeafBody(
+            const std::shared_ptr<BodyData<dim>>& bodyData,
+            const std::shared_ptr<HostGridType>& hostGrid);
 
     void assemble();
 
     // setter and getter
-    auto data() const -> const std::shared_ptr<BodyData<dims>>&;
+    auto data() const -> const std::shared_ptr<BodyData<dim>>&;
 
     void setDeformation(const VectorType& def);
     auto deformation() const -> DeformationFunction&;
-    auto deformedGrid() const -> const DeformedGridType*;
+    auto grid() const -> std::shared_ptr<GridType>;
 
-    auto leafView() const -> const DeformedLeafGridView&;
-    auto leafVertexCount() const -> int;
+    auto gridView() const -> const GridView&;
+    auto nVertices() const -> size_t;
 
     auto assembler() const -> const std::shared_ptr<Assembler>&;
     auto matrices() const -> const Matrices<Matrix,1>&;
 
     auto externalForce() const -> const ExternalForce&;
 
-    void addBoundaryCondition(std::shared_ptr<LeafBoundaryCondition> leafBoundaryCondition);
-    void leafBoundaryConditions(
+    void addBoundaryCondition(std::shared_ptr<BoundaryCondition> boundaryCondition);
+    void boundaryConditions(
             const std::string& tag,
-            std::vector<std::shared_ptr<LeafBoundaryCondition>>& selectedConditions) const;
-    auto leafBoundaryConditions() const -> const std::vector<std::shared_ptr<LeafBoundaryCondition>>&;
+            std::vector<std::shared_ptr<BoundaryCondition>>& selectedConditions) const;
+    auto boundaryConditions() const -> const std::vector<std::shared_ptr<BoundaryCondition>>&;
 
-    void addBoundaryCondition(std::shared_ptr<LevelBoundaryCondition> levelBoundaryCondition, int level);
-    void levelBoundaryConditions(
+    void boundaryPatchNodes(
+            const std::string& tag,
+            BoundaryPatchNodes& nodes) const;
+    void boundaryNodes(
+            const std::string& tag,
+            BoundaryNodes& nodes) const;
+    void boundaryFunctions(
             const std::string& tag,
-            std::vector<std::vector<std::shared_ptr<LevelBoundaryCondition>>>& selectedConditions) const;
-    void levelBoundaryConditions(
+            BoundaryFunctions& functions) const;
+    void boundaryPatches(
+            const std::string& tag,
+            BoundaryPatches& patches) const;
+};
+
+template <class GridView>
+class Body {
+public:
+    enum {dim = GridView::dimensionworld};
+
+    using GridType = typename GridView::Grid;
+
+    using Function = Dune::VirtualFunction<double, double>;
+
+    using BoundaryCondition = BoundaryCondition<GridView, dim>;
+
+    using BoundaryFunctions = std::vector<const Function* >;
+    using BoundaryNodes = std::vector<const Dune::BitSetVector<dim>* >;
+    using BoundaryPatchNodes = std::vector<const Dune::BitSetVector<1>* >;
+    using BoundaryPatches = std::vector<const typename BoundaryCondition::BoundaryPatch* >;
+
+private:
+    std::shared_ptr<BodyData<dim>> bodyData_;
+
+    std::shared_ptr<GridType> grid_;
+    const size_t level_;
+    GridView gridView_;
+
+    // boundary conditions
+    std::vector<std::shared_ptr<BoundaryCondition>> boundaryConditions_;
+
+public:
+    template <class GridView_ = GridView, std::enable_if_t<std::is_same<GridView_, typename GridType::LeafGridView>::value, int> = 0>
+    Body(
+            const std::shared_ptr<BodyData<dim>>& bodyData,
+            const std::shared_ptr<GridType>& grid) :
+        bodyData_(bodyData),
+        grid_(grid),
+        level_(grid_->maxLevel()),
+        gridView_(grid_->leafGridView()) {
+
+        boundaryConditions_.resize(0);
+    }
+
+    template <class GridView_ = GridView, std::enable_if_t<std::is_same<GridView_, typename GridType::LevelGridView>::value, int> = 0>
+    Body(
+            const std::shared_ptr<BodyData<dim>>& bodyData,
+            const std::shared_ptr<GridType>& grid,
+            const size_t level) :
+        bodyData_(bodyData),
+        grid_(grid),
+        level_(level),
+        gridView_(grid_->levelGridView(level_)) {
+
+        boundaryConditions_.resize(0);
+    }
+
+
+    // setter and getter
+    auto data() const -> const std::shared_ptr<BodyData<dim>>&;
+    auto grid() const -> std::shared_ptr<GridType>;
+
+    //template <class GridView_ = GridView, std::enable_if_t<std::is_same<GridView_, typename GridType::LevelGridView>::value, int> = 0>
+    auto level() const
+    -> size_t {
+
+        return level_;
+    }
+
+    auto gridView() const -> const GridView&;
+    auto nVertices() const -> size_t;
+
+    void addBoundaryCondition(std::shared_ptr<BoundaryCondition> boundaryCondition);
+    void boundaryConditions(
             const std::string& tag,
-            int level,
-            std::vector<std::shared_ptr<LevelBoundaryCondition>>& selectedConditions) const;
-    auto levelBoundaryConditions(int level) const -> const std::vector<std::shared_ptr<LevelBoundaryCondition>>&;
-    auto levelBoundaryConditions() const -> const std::vector<std::vector<std::shared_ptr<LevelBoundaryCondition>>>&;
+            std::vector<std::shared_ptr<BoundaryCondition>>& selectedConditions) const;
+    auto boundaryConditions() const -> const std::vector<std::shared_ptr<BoundaryCondition>>&;
 
     void boundaryPatchNodes(
             const std::string& tag,
diff --git a/src/data-structures/body_tmpl.cc b/src/data-structures/body_tmpl.cc
index b35e1cfa..d2a5dab1 100644
--- a/src/data-structures/body_tmpl.cc
+++ b/src/data-structures/body_tmpl.cc
@@ -5,4 +5,7 @@
 #include "../explicitgrid.hh"
 #include "../explicitvectors.hh"
 
-template class Body<Grid, Vector, MY_DIM>;
+template class LeafBody<Grid, Vector>;
+
+template class Body<DefLeafGridView>;
+template class Body<DefLevelGridView>;
diff --git a/src/data-structures/contactnetwork.cc b/src/data-structures/contactnetwork.cc
index ac118a1e..81d9f8a9 100644
--- a/src/data-structures/contactnetwork.cc
+++ b/src/data-structures/contactnetwork.cc
@@ -2,30 +2,397 @@
 #include "config.h"
 #endif
 
+#include <dune/contact/projections/normalprojection.hh>
+
+#include <dune/fufem/assemblers/localassemblers/neumannboundaryassembler.hh>
+#include <dune/fufem/functions/constantfunction.hh>
+
+#include <dune/tectonic/globalratestatefriction.hh>
+#include <dune/tectonic/frictionpotential.hh>
 
 #include "contactnetwork.hh"
 
-template <class GridType, int dim>
-void ContactNetwork<GridType, dim>::assemble() {
+#include "../assemblers.hh"
+#include "../utils/tobool.hh"
+
+
+template <class HostGridType, class VectorType>
+ContactNetwork<HostGridType, VectorType>::ContactNetwork(
+        size_t nBodies,
+        size_t nCouplings,
+        size_t nLevels) :
+    levelContactNetworks_(nLevels),
+    bodies_(nBodies),
+    couplings_(nCouplings),
+    frictionBoundaries_(nCouplings),
+    stateEnergyNorms_(nBodies),
+    nBodyAssembler_(nBodies, nCouplings)
+{}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::addLevel(std::shared_ptr<LevelContactNetwork> levelContactNetwork) {
+    size_t level = levelContactNetwork->level();
+    if (level >= levelContactNetworks_.size()) {
+        levelContactNetworks_.resize(level);
+    }
+
+    levelContactNetworks_[level] = levelContactNetwork;
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::addLevel(const std::vector<size_t>& bodyLevels, const size_t level) {
+    assert(bodyLevels.size() == nBodies());
+
+    if (level >= levelContactNetworks_.size()) {
+        levelContactNetworks_.resize(level+1);
+    }
+
+    auto& levelContactNetwork = levelContactNetworks_[level];
+    levelContactNetwork = std::make_shared<LevelContactNetwork>(nBodies(), nCouplings(), level);
+
+    std::vector<std::shared_ptr<Body>> bodies(nBodies());
+
+    for (size_t id=0; id<nBodies(); id++) {
+        const auto& body = this->body(id);
+        bodies[id] = std::make_shared<Body>(body->data(), body->grid(), std::min((size_t) body->grid()->maxLevel(), bodyLevels[id]));
+    }
+    levelContactNetwork->setBodies(bodies);
+    levelContactNetwork->setCouplings(this->couplings_);
+    levelContactNetwork->build();
+}
+
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::assemble() {
+    std::vector<const GridType*> grids(nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        grids[i] = bodies_[i]->grid().get();
+        bodies_[i]->assemble();
+        frictionBoundaries_[i] = std::make_unique<BoundaryPatch>(bodies_[i]->gridView(), false);
+    }
+
+    // set up dune-contact nBodyAssembler
+    nBodyAssembler_.setGrids(grids);
+
+    for (size_t i=0; i<nCouplings(); i++) {
+      nBodyAssembler_.setCoupling(*couplings_[i], i);
+    }
+
+    nBodyAssembler_.assembleTransferOperator();
+    nBodyAssembler_.assembleObstacle();
+
+    for (size_t i=0; i<nCouplings(); i++) {
+      auto& coupling = couplings_[i];
+      const auto& contactCoupling = nBodyAssembler_.getContactCouplings()[i]; // dual mortar object holding boundary patches
+      const auto nonmortarIdx = coupling->gridIdx_[0];
+      //const auto mortarIdx = coupling->gridIdx_[1];
+
+      frictionBoundaries_[nonmortarIdx]->addPatch(contactCoupling->nonmortarBoundary());
+      //frictionBoundaries_[mortarIdx]->addPatch(contactCoupling->mortarBoundary());
+    }
+
+    // assemble state energy norm
+    frictionBoundaryMass_.resize(nBodies());
+    for (size_t i=0; i<nBodies(); i++) {
+        frictionBoundaryMass_[i] = std::make_unique<ScalarMatrix>();
+        bodies_[i]->assembler()->assembleFrictionalBoundaryMass(*frictionBoundaries_[i], *frictionBoundaryMass_[i]);
+        *frictionBoundaryMass_[i] /= frictionBoundaries_[i]->area(); // TODO: weight by individual friction patches?
+
+        stateEnergyNorms_[i] = std::make_unique<typename LeafBody::StateEnergyNorm>(*frictionBoundaryMass_[i]);
+    }
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::assembleFriction(
+        const Config::FrictionModel& frictionModel,
+        const std::vector<ScalarVector>& weightedNormalStress) {
+
+      assert(weightedNormalStress.size() == bodies_.size());
+
+      const size_t nBodies = bodies_.size();
+
+      // Lumping of the nonlinearity
+      std::vector<ScalarVector> weights(nBodies);
+      {
+        NeumannBoundaryAssembler<GridType, typename ScalarVector::block_type>
+            frictionalBoundaryAssembler(std::make_shared<
+                ConstantFunction<LocalVector, typename ScalarVector::block_type>>(
+                1));
+
+        for (size_t i=0; i<nBodies; i++) {
+            bodies_[i]->assembler()->assembleBoundaryFunctional(frictionalBoundaryAssembler, weights[i], *frictionBoundaries_[i]);
+        }
+      }
+
+    /*  globalFriction_ = std::make_shared<GlobalRateStateFriction<
+          Matrix, Vector, ZeroFunction, DeformedGridType>>(
+          nBodyAssembler_.getContactCouplings(), couplings_, weights, weightedNormalStress); */
+
+      switch (frictionModel) {
+        case Config::Truncated:
+          globalFriction_ = std::make_shared<GlobalRateStateFriction<
+              Matrix, VectorType, TruncatedRateState, GridType>>(
+              nBodyAssembler_.getContactCouplings(), couplings_, weights, weightedNormalStress);
+          break;
+        case Config::Regularised:
+          globalFriction_ = std::make_shared<GlobalRateStateFriction<
+              Matrix, VectorType, RegularisedRateState, GridType>>(
+              nBodyAssembler_.getContactCouplings(), couplings_, weights, weightedNormalStress);
+          break;
+        default:
+          assert(false);
+          break;
+      }
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::setBodies(const std::vector<std::shared_ptr<LeafBody>> bodies) {
+    assert(nBodies()==bodies.size());
+    bodies_ = bodies;
+
+    matrices_.elasticity.resize(nBodies());
+    matrices_.damping.resize(nBodies());
+    matrices_.mass.resize(nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        matrices_.elasticity[i] = bodies_[i]->matrices().elasticity;
+        matrices_.damping[i] = bodies_[i]->matrices().damping;
+        matrices_.mass[i] = bodies_[i]->matrices().mass;
+    }
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::setCouplings(const std::vector<std::shared_ptr<FrictionCouplingPair>> couplings) {
+    assert(this->nCouplings()==couplings.size());
+    couplings_ = couplings;
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::constructBody(
+        const std::shared_ptr<BodyData<dim>>& bodyData,
+        const std::shared_ptr<HostGridType>& grid,
+        std::shared_ptr<LeafBody>& body) const {
+
+    body = std::make_shared<LeafBody>(bodyData, grid);
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::setDeformation(const std::vector<VectorType>& totalDeformation) {
+    assert(totalDeformation.size() == nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        body(i)->setDeformation(totalDeformation[i]);
+    }
+
+    nBodyAssembler_.assembleTransferOperator();
+    nBodyAssembler_.assembleObstacle();
+
     for (size_t i=0; i<levelContactNetworks_.size(); i++) {
-        levelContactNetworks_[i]->assemble();
+        levelContactNetworks_[i]->build();
     }
 }
 
-template <class GridType, int dim>
-void ContactNetwork<GridType, dim>::addLevelContactNetwork(std::shared_ptr<LevelContactNetwork> levelContactNetwork) {
-    size_t level = levelContactNetwork->level();
-    assert(level < this->size());
+template <class HostGridType, class VectorType>
+template <class LevelBoundaryPatch>
+void ContactNetwork<HostGridType, VectorType>::constructCoupling(
+        int nonMortarBodyIdx, int mortarBodyIdx,
+        const std::shared_ptr<LevelBoundaryPatch>& nonmortarPatch,
+        const std::shared_ptr<LevelBoundaryPatch>& mortarPatch,
+        const std::shared_ptr<ConvexPolyhedron<LocalVector>>& weakeningPatch,
+        const std::shared_ptr<GlobalFrictionData<dim>>& frictionData,
+        std::shared_ptr<FrictionCouplingPair>& coupling) const {
 
-    levelContactNetworks_[level] = levelContactNetwork;
+    coupling = std::make_shared<FrictionCouplingPair>();
+
+    auto contactProjection = std::make_shared<Dune::Contact::NormalProjection<BoundaryPatch>>();
+    std::shared_ptr<typename FrictionCouplingPair::BackEndType> backend = nullptr;
+    coupling->set(nonMortarBodyIdx, mortarBodyIdx, nonmortarPatch, mortarPatch, 0.1, Dune::Contact::CouplingPairBase::STICK_SLIP, contactProjection, backend);
+    coupling->setWeakeningPatch(weakeningPatch);
+    coupling->setFrictionData(frictionData);
 }
 
-template <class GridType, int dim>
-const std::shared_ptr<typename ContactNetwork<GridType, dim>::LevelContactNetwork>& ContactNetwork<GridType, dim>::addLevelContactNetwork(int nBodies, int nCouplings, int level) {
-    assert(level < this->size());
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::level(size_t level) const
+-> const std::shared_ptr<LevelContactNetwork>& {
 
-    levelContactNetworks_[level] = std::make_shared<LevelContactNetwork>(nBodies, nCouplings, level);
     return levelContactNetworks_[level];
 }
 
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::nLevels() const
+-> size_t {
+
+    return levelContactNetworks_.size();
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::nBodies() const
+-> size_t {
+
+    return bodies_.size();
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::nCouplings() const
+-> size_t {
+
+    return couplings_.size();
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::body(int i) const
+-> const std::shared_ptr<LeafBody>& {
+
+    return bodies_[i];
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::coupling(int i) const
+-> const std::shared_ptr<FrictionCouplingPair>& {
+
+    return couplings_[i];
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::couplings() const
+-> const std::vector<std::shared_ptr<FrictionCouplingPair>>& {
+
+    return couplings_;
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::nBodyAssembler()
+-> Dune::Contact::NBodyAssembler<GridType, VectorType>& {
+
+    return nBodyAssembler_;
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::nBodyAssembler() const
+-> const Dune::Contact::NBodyAssembler<GridType, VectorType>& {
+
+    return nBodyAssembler_;
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::matrices() const
+-> const Matrices<Matrix,2>& {
+
+    return matrices_;
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::stateEnergyNorms() const
+-> const StateEnergyNorms& {
+
+    return stateEnergyNorms_;
+}
+
+template <class HostGridType, class VectorType>
+auto ContactNetwork<HostGridType, VectorType>::globalFriction() const
+-> GlobalFriction& {
+
+    return *globalFriction_;
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::externalForces(ExternalForces& externalForces) const {
+    externalForces.resize(nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        externalForces[i] = std::make_unique<typename LeafBody::ExternalForce>(bodies_[i]->externalForce());
+    }
+}
+
+// collects all leaf boundary nodes from the different bodies identified by "tag" in a single BitSetVector
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::totalNodes(
+        const std::string& tag,
+        Dune::BitSetVector<dim>& totalNodes) const {
+
+    int totalSize = 0;
+    for (size_t i=0; i<nBodies(); i++) {
+        totalSize += this->body(i)->nVertices();
+    }
+
+    totalNodes.resize(totalSize);
+
+    int idx=0;
+    for (size_t i=0; i<nBodies(); i++) {
+        const auto& body = this->body(i);
+        std::vector<std::shared_ptr<typename LeafBody::BoundaryCondition>> boundaryConditions;
+        body->boundaryConditions(tag, boundaryConditions);
+
+        const int idxBackup = idx;
+        for (size_t bc = 0; bc<boundaryConditions.size(); bc++) {
+            const auto& nodes = boundaryConditions[bc]->boundaryNodes();
+            for (size_t j=0; j<nodes->size(); j++, idx++)
+                for (int k=0; k<dim; k++)
+                    totalNodes[idx][k] = (*nodes)[j][k];
+            idx = (bc==boundaryConditions.size()-1 ? idx : idxBackup);
+        }
+    }
+}
+
+// collects all leaf boundary nodes from the different bodies identified by "tag" in a vector of BitSetVector
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::boundaryPatchNodes(
+        const std::string& tag,
+        BoundaryPatchNodes& nodes) const {
+
+    nodes.resize(nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        this->body(i)->boundaryPatchNodes(tag, nodes[i]);
+    }
+}
+
+// collects all leaf boundary nodes from the different bodies identified by "tag" in a vector of BitSetVector
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::boundaryNodes(
+        const std::string& tag,
+        BoundaryNodes& nodes) const {
+
+    nodes.resize(nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        this->body(i)->boundaryNodes(tag, nodes[i]);
+    }
+}
+
+// collects all leaf boundary functions from the different bodies identified by "tag"
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::boundaryFunctions(
+        const std::string& tag,
+        BoundaryFunctions& functions) const {
+
+    functions.resize(nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        this->body(i)->boundaryFunctions(tag, functions[i]);
+    }
+}
+
+// collects all leaf boundary patches from the different bodies identified by "tag"
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::boundaryPatches(
+        const std::string& tag,
+        BoundaryPatches& patches) const {
+
+    patches.resize(nBodies());
+
+    for (size_t i=0; i<nBodies(); i++) {
+        this->body(i)->boundaryPatches(tag, patches[i]);
+    }
+}
+
+template <class HostGridType, class VectorType>
+void ContactNetwork<HostGridType, VectorType>::frictionNodes(std::vector<const Dune::BitSetVector<1>*>& nodes) const {
+    nodes.resize(nBodies());
+    for (size_t i=0; i<nBodies(); i++) {
+        nodes[i] = frictionBoundaries_[i]->getVertices();
+    }
+}
+
 #include "contactnetwork_tmpl.cc"
diff --git a/src/data-structures/contactnetwork.hh b/src/data-structures/contactnetwork.hh
index 25baf45b..6fb2e48b 100644
--- a/src/data-structures/contactnetwork.hh
+++ b/src/data-structures/contactnetwork.hh
@@ -1,37 +1,146 @@
 #ifndef SRC_CONTACTNETWORK_HH
 #define SRC_CONTACTNETWORK_HH
 
+#include <memory>
+
+#include <dune/common/promotiontraits.hh>
+
+#include <dune/contact/assemblers/nbodyassembler.hh>
+
+#include <dune/tectonic/bodydata.hh>
+#include <dune/tectonic/globalfriction.hh>
+#include <dune/tectonic/globalfrictiondata.hh>
+
+#include "../assemblers.hh"
+#include "../frictioncouplingpair.hh"
+#include "body.hh"
+#include "enums.hh"
+#include "matrices.hh"
 #include "levelcontactnetwork.hh"
 
-template <class GridType, int dim> class ContactNetwork {
-  public:
-    using LevelContactNetwork = LevelContactNetwork<GridType, dim>;
+template <class HostGridType, class VectorType>
+class ContactNetwork {
+    //using Vector = Dune::BlockVector<Dune::FieldVector<double, dim>>;
+public:
+    enum {dim = HostGridType::dimensionworld};
+
+    using field_type = typename Dune::PromotionTraits<typename VectorType::field_type,
+                                                typename HostGridType::ctype>::PromotedType;
+
+    using LeafBody = LeafBody<HostGridType, VectorType>;
+    using GridType = typename LeafBody::GridType;
+    using GridView = typename LeafBody::GridView;
+    using BoundaryPatch = BoundaryPatch<GridView>;
+
+    using Assembler = typename LeafBody::Assembler;
+    using Matrix = typename Assembler::Matrix;
+
+    using ScalarMatrix = typename Assembler::ScalarMatrix;
+    using ScalarVector = typename Assembler::ScalarVector;
+
+    using LocalVector = typename VectorType::block_type;
+    using FrictionCouplingPair = FrictionCouplingPair<GridType, LocalVector, field_type>;
+
+    using Function = Dune::VirtualFunction<double, double>;
+
+    using BoundaryFunctions = std::vector<typename LeafBody::BoundaryFunctions>;
+    using BoundaryNodes = std::vector<typename LeafBody::BoundaryNodes>;
+    using BoundaryPatchNodes = std::vector<typename LeafBody::BoundaryPatchNodes>;
+    using BoundaryPatches = std::vector<typename LeafBody::BoundaryPatches>;
+
+    using GlobalFriction = GlobalFriction<Matrix, VectorType>;
+
+    using StateEnergyNorms = std::vector<std::unique_ptr<typename LeafBody::StateEnergyNorm> >;
+    using ExternalForces = std::vector<std::unique_ptr<const typename LeafBody::ExternalForce> >;
+
+    using NBodyAssembler = Dune::Contact::NBodyAssembler<GridType, VectorType>;
+
+    using LevelContactNetwork = LevelContactNetwork<GridType, FrictionCouplingPair, field_type>;
+    using Body = typename LevelContactNetwork::Body;
+
+private:
+    std::vector<std::shared_ptr<LevelContactNetwork>> levelContactNetworks_;
+
+    std::vector<std::shared_ptr<LeafBody>> bodies_;
+    std::vector<std::shared_ptr<FrictionCouplingPair>> couplings_;
+
+    std::vector<std::unique_ptr<BoundaryPatch>> frictionBoundaries_; // union of all boundary patches per body
+    std::vector<std::unique_ptr<ScalarMatrix>> frictionBoundaryMass_;
+    StateEnergyNorms stateEnergyNorms_;
+
+    NBodyAssembler nBodyAssembler_;
+
+    Matrices<Matrix,2> matrices_;
+
+    std::shared_ptr<GlobalFriction> globalFriction_;
+
+public:
+    ContactNetwork(size_t nBodies, size_t nCouplings, size_t nLevels = 0);
+
+    void addLevel(std::shared_ptr<LevelContactNetwork> levelContactNetwork);
+    void addLevel(const std::vector<size_t>& bodyLevels, const size_t level);
+
+    void assemble();
+    void assembleFriction(
+            const Config::FrictionModel& frictionModel,
+            const std::vector<ScalarVector>& weightedNormalStress);
+
+    void setBodies(const std::vector<std::shared_ptr<LeafBody>> bodies);
+    void setCouplings(const std::vector<std::shared_ptr<FrictionCouplingPair>> couplings);
+
+    void setDeformation(const std::vector<VectorType>& totalDeformation);
+
+    void constructBody(
+            const std::shared_ptr<BodyData<dim>>& bodyData,
+            const std::shared_ptr<HostGridType>& grid,
+            std::shared_ptr<LeafBody>& body) const;
+
+    template <class LevelBoundaryPatch>
+    void constructCoupling(
+            int nonMortarBodyIdx,
+            int mortarBodyIdx,
+            const std::shared_ptr<LevelBoundaryPatch>& nonmortarPatch,
+            const std::shared_ptr<LevelBoundaryPatch>& mortarPatch,
+            const std::shared_ptr<ConvexPolyhedron<LocalVector>>& weakeningPatch,
+            const std::shared_ptr<GlobalFrictionData<dim>>& frictionData,
+            std::shared_ptr<FrictionCouplingPair>& coupling) const;
 
-  private:
-   std::vector<std::shared_ptr<LevelContactNetwork>> levelContactNetworks_;
+    // getter
+    auto level(size_t level) const -> const std::shared_ptr<LevelContactNetwork>&;
 
-  public:
-        ContactNetwork() {}
+    auto nLevels() const -> size_t;
+    auto nBodies() const -> size_t;
+    auto nCouplings() const -> size_t;
 
-        void addLevelContactNetwork(std::shared_ptr<LevelContactNetwork> levelContactNetwork);
-        const std::shared_ptr<LevelContactNetwork>& addLevelContactNetwork(int nBodies, int nCouplings, int level);
+    auto body(int i) const -> const std::shared_ptr<LeafBody>&;
 
-        void assemble();
+    auto coupling(int i) const -> const std::shared_ptr<FrictionCouplingPair>&;
+    auto couplings() const -> const std::vector<std::shared_ptr<FrictionCouplingPair>>&;
 
-        const std::shared_ptr<LevelContactNetwork>& levelContactNetwork(size_t level) const {
-            return levelContactNetworks_[level];
-        }
+    auto nBodyAssembler() -> NBodyAssembler&;
+    auto nBodyAssembler() const -> const NBodyAssembler&;
 
-        void resize(size_t size) {
-            levelContactNetworks_.resize(size);
-        }
+    auto matrices() const -> const Matrices<Matrix,2>&;
 
-        size_t size() const {
-            return levelContactNetworks_.size();
-        }
+    auto stateEnergyNorms() const -> const StateEnergyNorms&;
+    auto globalFriction() const -> GlobalFriction&;
+    void externalForces(ExternalForces& externalForces) const;
 
-        size_t maxLevel() const {
-            return size()-1;
-		} 
+    void totalNodes(
+            const std::string& tag,
+            Dune::BitSetVector<dim>& totalNodes) const;
+    void boundaryPatches(
+            const std::string& tag,
+            BoundaryPatches& patches) const;
+    void boundaryPatchNodes(
+            const std::string& tag,
+            BoundaryPatchNodes& nodes) const;
+    void boundaryNodes(
+            const std::string& tag,
+            BoundaryNodes& nodes) const;
+    void boundaryFunctions(
+            const std::string& tag,
+            BoundaryFunctions& functions) const;
+    void frictionNodes(std::vector<const Dune::BitSetVector<1>*>& nodes) const;
 };
 #endif
diff --git a/src/data-structures/contactnetwork_tmpl.cc b/src/data-structures/contactnetwork_tmpl.cc
index 32c9a280..03374e69 100644
--- a/src/data-structures/contactnetwork_tmpl.cc
+++ b/src/data-structures/contactnetwork_tmpl.cc
@@ -3,5 +3,10 @@
 #endif
 
 #include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
 
-template class ContactNetwork<Grid, MY_DIM>;
+#include "contactnetwork.hh"
+
+using MyContactNetwork =  ContactNetwork<Grid, Vector>;
+
+template class ContactNetwork<Grid, Vector>;
diff --git a/src/data-structures/levelcontactnetwork.cc b/src/data-structures/levelcontactnetwork.cc
index 5edb70fc..f7a34d4a 100644
--- a/src/data-structures/levelcontactnetwork.cc
+++ b/src/data-structures/levelcontactnetwork.cc
@@ -6,6 +6,7 @@
 
 #include <dune/fufem/assemblers/localassemblers/neumannboundaryassembler.hh>
 #include <dune/fufem/functions/constantfunction.hh>
+#include <dune/fufem/facehierarchy.hh>
 
 #include <dune/tectonic/globalratestatefriction.hh>
 #include <dune/tectonic/frictionpotential.hh>
@@ -16,186 +17,51 @@
 #include "../utils/tobool.hh"
 #include "../utils/debugutils.hh"
 
-template <class GridType, int dimension>
-LevelContactNetwork<GridType, dimension>::LevelContactNetwork(
+template <class GridType, class FrictionCouplingPair, class field_type>
+LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::LevelContactNetwork(
         int nBodies,
         int nCouplings,
         int level) :
     level_(level),
     bodies_(nBodies),
     couplings_(nCouplings),
-    deformedGrids_(nBodies),
-    leafViews_(nBodies),
-    levelViews_(nBodies),
-    leafVertexCounts_(nBodies),
-    frictionBoundaries_(nCouplings),
-    stateEnergyNorms_(nBodies),
-    nBodyAssembler_(nBodies, nCouplings)
+    nonmortarPatches_(nCouplings),
+    mortarPatches_(nCouplings),
+    glues_(nCouplings)
 {}
 
-template <class GridType, int dimension>
-LevelContactNetwork<GridType, dimension>::~LevelContactNetwork() {
-    for (size_t i=0; i<nBodies(); i++) {
-        delete frictionBoundaries_[i];
-        delete frictionBoundaryMass_[i];
-        delete stateEnergyNorms_[i];
-    }
-}
-
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::assemble() {
-    using BoundaryPatch = DeformedLeafBoundaryPatch;
-
-    for (size_t i=0; i<nBodies(); i++) {
-        bodies_[i]->assemble();
-        //printBasisDofLocation(bodies_[i]->assembler()->vertexBasis); //TODO remove after debugging
-
-        frictionBoundaries_[i] = new BoundaryPatch(bodies_[i]->leafView(), false);
-    }
-
-    // set up dune-contact nBodyAssembler
-    nBodyAssembler_.setGrids(deformedGrids_);
-
-    for (size_t i=0; i<nCouplings(); i++) {
-      nBodyAssembler_.setCoupling(*couplings_[i], i);
-    }
-
-    nBodyAssembler_.assembleTransferOperator();
-    nBodyAssembler_.assembleObstacle();
-
-    for (size_t i=0; i<nCouplings(); i++) {
-      auto& coupling = couplings_[i];
-      const auto& contactCoupling = nBodyAssembler_.getContactCouplings()[i]; // dual mortar object holding boundary patches
-      const auto nonmortarIdx = coupling->gridIdx_[0];
-      //const auto mortarIdx = coupling->gridIdx_[1];
-
-      frictionBoundaries_[nonmortarIdx]->addPatch(contactCoupling->nonmortarBoundary());
-      //frictionBoundaries_[mortarIdx]->addPatch(contactCoupling->mortarBoundary());
-    }
-
-    // assemble state energy norm
-    frictionBoundaryMass_.resize(nBodies());
-    for (size_t i=0; i<nBodies(); i++) {
-        frictionBoundaryMass_[i] = new ScalarMatrix();
-        bodies_[i]->assembler()->assembleFrictionalBoundaryMass(*frictionBoundaries_[i], *frictionBoundaryMass_[i]);
-        *frictionBoundaryMass_[i] /= frictionBoundaries_[i]->area(); // TODO: weight by individual friction patches?
 
-        stateEnergyNorms_[i] = new EnergyNorm<ScalarMatrix, ScalarVector>(*frictionBoundaryMass_[i]);
-    }
-}
-
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::assembleFriction(
-        const Config::FrictionModel& frictionModel,
-        const std::vector<ScalarVector>& weightedNormalStress) {
-
-      assert(weightedNormalStress.size() == bodies_.size());
-
-      const size_t nBodies = bodies_.size();
-
-      // Lumping of the nonlinearity
-      std::vector<ScalarVector> weights(nBodies);
-      {
-        NeumannBoundaryAssembler<DeformedGridType, typename ScalarVector::block_type>
-            frictionalBoundaryAssembler(std::make_shared<
-                ConstantFunction<LocalVector, typename ScalarVector::block_type>>(
-                1));
-
-        for (size_t i=0; i<nBodies; i++) {
-            bodies_[i]->assembler()->assembleBoundaryFunctional(frictionalBoundaryAssembler, weights[i], *frictionBoundaries_[i]);
-        }
-      }
-
-    /*  globalFriction_ = std::make_shared<GlobalRateStateFriction<
-          Matrix, Vector, ZeroFunction, DeformedGridType>>(
-          nBodyAssembler_.getContactCouplings(), couplings_, weights, weightedNormalStress); */
-
-      switch (frictionModel) {
-        case Config::Truncated:
-          globalFriction_ = std::make_shared<GlobalRateStateFriction<
-              Matrix, Vector, TruncatedRateState, DeformedGridType>>(
-              nBodyAssembler_.getContactCouplings(), couplings_, weights, weightedNormalStress);
-          break;
-        case Config::Regularised:
-          globalFriction_ = std::make_shared<GlobalRateStateFriction<
-              Matrix, Vector, RegularisedRateState, DeformedGridType>>(
-              nBodyAssembler_.getContactCouplings(), couplings_, weights, weightedNormalStress);
-          break;
-        default:
-          assert(false);
-          break;
-      }
-}
-
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::setBodies(const std::vector<std::shared_ptr<Body>> bodies) {
-    assert(nBodies()==bodies.size());
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::setBodies(const std::vector<std::shared_ptr<Body>> bodies) {
+    assert(nBodies() == bodies.size());
     bodies_ = bodies;
-
-    matrices_.elasticity.resize(nBodies());
-    matrices_.damping.resize(nBodies());
-    matrices_.mass.resize(nBodies());
-
-    for (size_t i=0; i<nBodies(); i++) {
-        deformedGrids_[i] = bodies_[i]->deformedGrid();
-
-        leafViews_[i] = std::make_unique<DeformedLeafGridView>(deformedGrids_[i]->leafGridView());
-
-        levelViews_[i].resize(deformedGrids_[i]->maxLevel()+1);
-        for (size_t j=0; j<levelViews_[i].size(); j++) {
-            levelViews_[i][j] = std::make_unique<DeformedLevelGridView>(deformedGrids_[i]->levelGridView(j));
-        }
-
-        leafVertexCounts_[i] = leafViews_[i]->size(dimension);
-
-        matrices_.elasticity[i] = bodies_[i]->matrices().elasticity;
-        matrices_.damping[i] = bodies_[i]->matrices().damping;
-        matrices_.mass[i] = bodies_[i]->matrices().mass;
-    }
 }
 
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::setCouplings(const std::vector<std::shared_ptr<FrictionCouplingPair>> couplings) {
-    assert(this->nCouplings()==couplings.size());
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::setCouplings(const std::vector<std::shared_ptr<FrictionCouplingPair>> couplings) {
+    assert(nCouplings() == couplings.size());
     couplings_ = couplings;
 }
 
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::constructBody(
-        const std::shared_ptr<BodyData<dimension>>& bodyData,
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::constructBody(
+        const std::shared_ptr<BodyData<dimworld>>& bodyData,
         const std::shared_ptr<GridType>& grid,
+        const size_t level,
         std::shared_ptr<Body>& body) const {
 
-    body = std::make_shared<Body>(bodyData, grid);
-}
-
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::constructCoupling(
-        int nonMortarBodyIdx, int mortarBodyIdx,
-        const std::shared_ptr<DeformedLevelBoundaryPatch>& nonmortarPatch,
-        const std::shared_ptr<DeformedLevelBoundaryPatch>& mortarPatch,
-        const std::shared_ptr<ConvexPolyhedron<LocalVector>>& weakeningPatch,
-        const std::shared_ptr<GlobalFrictionData<dimension>>& frictionData,
-        std::shared_ptr<FrictionCouplingPair>& coupling) const {
-
-    coupling = std::make_shared<FrictionCouplingPair>();
-
-    auto contactProjection = std::make_shared<Dune::Contact::NormalProjection<DeformedLeafBoundaryPatch>>();
-    std::shared_ptr<typename FrictionCouplingPair::BackEndType> backend = nullptr;
-    coupling->set(nonMortarBodyIdx, mortarBodyIdx, nonmortarPatch, mortarPatch, 0.1, Dune::Contact::CouplingPairBase::STICK_SLIP, contactProjection, backend);
-    coupling->setWeakeningPatch(weakeningPatch);
-    coupling->setFrictionData(frictionData);
+    body = std::make_shared<Body>(bodyData, grid, level);
 }
 
 // collects all leaf boundary nodes from the different bodies identified by "tag" in a single BitSetVector
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::totalNodes(
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::totalNodes(
         const std::string& tag,
-        Dune::BitSetVector<dimension>& totalNodes) const {
+        Dune::BitSetVector<dimworld>& totalNodes) const {
 
     int totalSize = 0;
     for (size_t i=0; i<nBodies(); i++) {
-        totalSize += this->body(i)->leafVertexCount();
+        totalSize += this->body(i)->nVertices();
     }
 
     totalNodes.resize(totalSize);
@@ -203,14 +69,14 @@ void LevelContactNetwork<GridType, dimension>::totalNodes(
     int idx=0;
     for (size_t i=0; i<nBodies(); i++) {
         const auto& body = this->body(i);
-        std::vector<std::shared_ptr<typename Body::LeafBoundaryCondition>> boundaryConditions;
-        body->leafBoundaryConditions(tag, boundaryConditions);
+        std::vector<std::shared_ptr<typename Body::BoundaryCondition>> boundaryConditions;
+        body->boundaryConditions(tag, boundaryConditions);
 
         const int idxBackup = idx;
         for (size_t bc = 0; bc<boundaryConditions.size(); bc++) {
             const auto& nodes = boundaryConditions[bc]->boundaryNodes();
             for (size_t j=0; j<nodes->size(); j++, idx++)
-                for (int k=0; k<dimension; k++)
+                for (int k=0; k<dimworld; k++)
                     totalNodes[idx][k] = (*nodes)[j][k];
             idx = (bc==boundaryConditions.size()-1 ? idx : idxBackup);
         }
@@ -218,8 +84,8 @@ void LevelContactNetwork<GridType, dimension>::totalNodes(
 }
 
 // collects all leaf boundary nodes from the different bodies identified by "tag" in a vector of BitSetVector
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::boundaryPatchNodes(
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::boundaryPatchNodes(
         const std::string& tag,
         BoundaryPatchNodes& nodes) const {
 
@@ -231,8 +97,8 @@ void LevelContactNetwork<GridType, dimension>::boundaryPatchNodes(
 }
 
 // collects all leaf boundary nodes from the different bodies identified by "tag" in a vector of BitSetVector
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::boundaryNodes(
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::boundaryNodes(
         const std::string& tag,
         BoundaryNodes& nodes) const {
 
@@ -244,8 +110,8 @@ void LevelContactNetwork<GridType, dimension>::boundaryNodes(
 }
 
 // collects all leaf boundary functions from the different bodies identified by "tag"
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::boundaryFunctions(
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::boundaryFunctions(
         const std::string& tag,
         BoundaryFunctions& functions) const {
 
@@ -257,8 +123,8 @@ void LevelContactNetwork<GridType, dimension>::boundaryFunctions(
 }
 
 // collects all leaf boundary patches from the different bodies identified by "tag"
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::boundaryPatches(
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::boundaryPatches(
         const std::string& tag,
         BoundaryPatches& patches) const {
 
@@ -269,141 +135,113 @@ void LevelContactNetwork<GridType, dimension>::boundaryPatches(
     }
 }
 
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::frictionNodes(std::vector<const Dune::BitSetVector<1>*>& nodes) const {
-    nodes.resize(nBodies());
-    for (size_t i=0; i<nBodies(); i++) {
-        nodes[i] = frictionBoundaries_[i]->getVertices();
-    }
-}
-
-
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::stateEnergyNorms() const
--> const StateEnergyNorms& {
-
-    return stateEnergyNorms_;
-}
-
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::level() const
+template <class GridType, class FrictionCouplingPair, class field_type>
+auto LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::level() const
 -> int {
 
     return level_;
 }
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::nBodies() const
+template <class GridType, class FrictionCouplingPair, class field_type>
+auto LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::nBodies() const
 -> size_t {
 
     return bodies_.size();
 }
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::nCouplings() const
+template <class GridType, class FrictionCouplingPair, class field_type>
+auto LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::nCouplings() const
 -> size_t {
 
     return couplings_.size();
 }
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::leafVertexCounts() const
--> const std::vector<size_t>& {
-
-    return leafVertexCounts_;
-}
-
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::body(int i) const
+template <class GridType, class FrictionCouplingPair, class field_type>
+auto LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::body(int i) const
 -> const std::shared_ptr<Body>& {
 
     return bodies_[i];
 }
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::coupling(int i) const
+template <class GridType, class FrictionCouplingPair, class field_type>
+auto LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::coupling(int i) const
 -> const std::shared_ptr<FrictionCouplingPair>& {
 
     return couplings_[i];
 }
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::deformedGrids() const
--> const std::vector<const DeformedGridType*>& {
-
-    return deformedGrids_;
-}
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::couplings() const
+template <class GridType, class FrictionCouplingPair, class field_type>
+auto LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::couplings() const
 -> const std::vector<std::shared_ptr<FrictionCouplingPair>>& {
 
     return couplings_;
 }
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::leafView(int bodyID) const
--> const DeformedLeafGridView& {
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::prolong(const BoundaryPatch& coarsePatch, BoundaryPatch& finePatch, const size_t fineLevel) {
 
-    return *leafViews_[bodyID];
-}
+    if (not(coarsePatch.isInitialized()))
+        DUNE_THROW(Dune::Exception, "Coarse boundary patch has not been set up correctly!");
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::levelViews(int bodyID) const
--> const std::vector<std::unique_ptr<const DeformedLevelGridView>>& {
+    const GridType& grid = coarsePatch.gridView().grid();
 
-    return levelViews_[bodyID];
-}
+    // Set array sizes correctly
+    finePatch.setup(grid.levelGridView(fineLevel));
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::levelView(int bodyID, int level) const
--> const DeformedLevelGridView& {
+    for (const auto& pIt : coarsePatch) {
+        const auto& inside = pIt.inside();
 
-    return *levelViews_[bodyID][level];
-}
+        if (inside.level() == fineLevel)
+            finePatch.addFace(inside, pIt.indexInInside());
+        else {
+            Face<GridType> face(grid, inside, pIt.indexInInside());
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::leafVertexCount(int bodyID) const
--> int {
+            typename Face<GridType>::HierarchicIterator it = face.hbegin(fineLevel);
+            typename Face<GridType>::HierarchicIterator end = face.hend(fineLevel);
 
-    return leafVertexCounts_[bodyID];
+            for(; it!=end; ++it) {
+                if (it->element().level() == fineLevel)
+                    finePatch.addFace(it->element(), it->index());
+            }
+        }
+    }
 }
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::nBodyAssembler()
--> Dune::Contact::NBodyAssembler<DeformedGridType, Vector>& {
-
-    return nBodyAssembler_;
-}
+template <class GridType, class FrictionCouplingPair, class field_type>
+void LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::build(field_type overlap) {
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::nBodyAssembler() const
--> const Dune::Contact::NBodyAssembler<DeformedGridType, Vector>& {
+    for (size_t i=0; i<couplings_.size(); i++) {
+        auto& coupling = *couplings_[i];
 
-    return nBodyAssembler_;
-}
+        const size_t nmBody = coupling.gridIdx_[0];
+        const size_t mBody = coupling.gridIdx_[1];
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::matrices() const
--> const Matrices<Matrix,2>& {
+        this->prolong(*coupling.patch0(), nonmortarPatches_[i], body(nmBody)->level());
+        this->prolong(*coupling.patch1(), mortarPatches_[i], body(mBody)->level());
 
-    return matrices_;
-}
+        using Element = typename GridView::template Codim<0>::Entity;
+        auto desc0 = [&] (const Element& e, unsigned int face) {
+            return nonmortarPatches_[i].contains(e,face);
+        };
+        auto desc1 = [&] (const Element& e, unsigned int face) {
+            return mortarPatches_[i].contains(e,face);
+        };
 
-template <class GridType, int dimension>
-auto LevelContactNetwork<GridType, dimension>::globalFriction() const
--> GlobalFriction& {
+        auto extract0 = std::make_shared<Extractor>(body(nmBody)->gridView(), desc0);
+        auto extract1 = std::make_shared<Extractor>(body(mBody)->gridView(), desc1);
 
-    return *globalFriction_;
+        gridGlueBackend_ = std::make_shared< Dune::GridGlue::ContactMerge<dim, ctype> >(overlap);
+        glues_[i] = std::make_shared<Glue>(extract0, extract1, gridGlueBackend_);
+        glues_[i]->build();
+    }
 }
 
-template <class GridType, int dimension>
-void LevelContactNetwork<GridType, dimension>::externalForces(ExternalForces& externalForces) const {
-    externalForces.resize(nBodies());
+template <class GridType, class FrictionCouplingPair, class field_type>
+auto LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::glue(int i) const
+-> const std::shared_ptr<Glue>& {
 
-    for (size_t i=0; i<nBodies(); i++) {
-        externalForces[i] = &bodies_[i]->externalForce();
-    }
+    return glues_[i];
 }
 
 #include "levelcontactnetwork_tmpl.cc"
diff --git a/src/data-structures/levelcontactnetwork.hh b/src/data-structures/levelcontactnetwork.hh
index 68bb716a..c4976718 100644
--- a/src/data-structures/levelcontactnetwork.hh
+++ b/src/data-structures/levelcontactnetwork.hh
@@ -6,12 +6,18 @@
 
 #include <dune/istl/bvector.hh>
 
+#include <dune/grid-glue/gridglue.hh>
+#include <dune/grid-glue/extractors/codim1extractor.hh>
+#include <dune/grid-glue/merging/merger.hh>
+
 #include <dune/contact/common/deformedcontinuacomplex.hh>
 #include <dune/contact/common/couplingpair.hh>
 #include <dune/contact/assemblers/nbodyassembler.hh>
 //#include <dune/contact/assemblers/dualmortarcoupling.hh>
 #include <dune/contact/projections/normalprojection.hh>
 
+#include <dune/fufem/boundarypatch.hh>
+
 #include <dune/tectonic/bodydata.hh>
 #include <dune/tectonic/globalfriction.hh>
 #include <dune/tectonic/globalfrictiondata.hh>
@@ -23,134 +29,84 @@
 #include "matrices.hh"
 //#include "multi-body-problem-data/myglobalfrictiondata.hh"
 
-template <class GridType, int dimension> class LevelContactNetwork {
-    private:
-        //static const int dimension = typename GridType::dimension;
-        using Vector = Dune::BlockVector<Dune::FieldVector<double, dimension>>;
-
-    public:
-        using Body = Body<GridType, Vector, dimension>;
-
-        using DeformedGridType = typename Body::DeformedGridType;
-        using DeformedLeafGridView = typename Body::DeformedLeafGridView;
-        using DeformedLevelGridView = typename Body::DeformedLevelGridView;
-
-        using DeformedLeafBoundaryPatch = BoundaryPatch<DeformedLeafGridView>;
-        using DeformedLevelBoundaryPatch = BoundaryPatch<DeformedLevelGridView>;
-
-        using Assembler = typename Body::Assembler;
-        using Matrix = typename Assembler::Matrix;
-        using LocalVector = typename Vector::block_type;
-        using ScalarMatrix = typename Assembler::ScalarMatrix;
-        using ScalarVector = typename Assembler::ScalarVector;
-        using field_type = typename Matrix::field_type;
-    
-        using FrictionCouplingPair = FrictionCouplingPair<DeformedGridType, LocalVector, field_type>;
-    
-        using Function = Dune::VirtualFunction<double, double>;
-
-        using BoundaryFunctions = std::vector<typename Body::BoundaryFunctions>;
-        using BoundaryNodes = std::vector<typename Body::BoundaryNodes>;
-        using BoundaryPatchNodes = std::vector<typename Body::BoundaryPatchNodes>;
-        using BoundaryPatches = std::vector<typename Body::BoundaryPatches>;
-
-        using GlobalFriction = GlobalFriction<Matrix, Vector>;
-
-        using StateEnergyNorms = std::vector<const typename Body::StateEnergyNorm *>;
-        using ExternalForces = std::vector<const typename Body::ExternalForce *>;
-
-        using NBodyAssembler = Dune::Contact::NBodyAssembler<DeformedGridType, Vector>;
-
-    public:
-        LevelContactNetwork(int nBodies, int nCouplings, int level = 0);
-        ~LevelContactNetwork();
-
-        void assemble();
-        void assembleFriction(
-                const Config::FrictionModel& frictionModel,
-                const std::vector<ScalarVector>& weightedNormalStress);
-		
-        void setBodies(const std::vector<std::shared_ptr<Body>> bodies);
-        void setCouplings(const std::vector<std::shared_ptr<FrictionCouplingPair>> couplings);
-
-        void constructBody(
-                const std::shared_ptr<BodyData<dimension>>& bodyData,
-                const std::shared_ptr<GridType>& grid,
-                std::shared_ptr<Body>& body) const;
-        void constructCoupling(
-                int nonMortarBodyIdx,
-                int mortarBodyIdx,
-                const std::shared_ptr<DeformedLevelBoundaryPatch>& nonmortarPatch,
-                const std::shared_ptr<DeformedLevelBoundaryPatch>& mortarPatch,
-                const std::shared_ptr<ConvexPolyhedron<LocalVector>>& weakeningPatch,
-                const std::shared_ptr<GlobalFrictionData<dimension>>& frictionData,
-                std::shared_ptr<FrictionCouplingPair>& coupling) const;
-
-        // getter
-        void totalNodes(
-                const std::string& tag,
-                Dune::BitSetVector<dimension>& totalNodes) const;
-        void boundaryPatches(
-                const std::string& tag,
-                BoundaryPatches& patches) const;
-        void boundaryPatchNodes(
-                const std::string& tag,
-                BoundaryPatchNodes& nodes) const;
-        void boundaryNodes(
-                const std::string& tag,
-                BoundaryNodes& nodes) const;
-        void boundaryFunctions(
-                const std::string& tag,
-                BoundaryFunctions& functions) const;
-        void frictionNodes(std::vector<const Dune::BitSetVector<1>*>& nodes) const;
-
-        auto stateEnergyNorms() const -> const StateEnergyNorms&;
-        auto globalFriction() const -> GlobalFriction&;
-        void externalForces(ExternalForces& externalForces) const;
-
-        auto level() const -> int;
-
-        auto nBodies() const -> size_t;
-        auto nCouplings() const -> size_t;
-
-        auto body(int i) const -> const std::shared_ptr<Body>&;
-
-        auto coupling(int i) const -> const std::shared_ptr<FrictionCouplingPair>&;
-        auto couplings() const -> const std::vector<std::shared_ptr<FrictionCouplingPair>>&;
-
-        auto deformedGrids() const -> const std::vector<const DeformedGridType*>& ;
-
-        auto leafVertexCounts() const -> const std::vector<size_t>&;
-        auto leafVertexCount(int bodyID) const -> int;
-
-        auto leafView(int bodyID) const -> const DeformedLeafGridView&;
-        auto levelView(int bodyID, int level = 0) const -> const DeformedLevelGridView&;
-        auto levelViews(int bodyID) const -> const std::vector<std::unique_ptr<const DeformedLevelGridView>>&;
-
-        auto nBodyAssembler() -> Dune::Contact::NBodyAssembler<DeformedGridType, Vector>&;
-        auto nBodyAssembler() const -> const Dune::Contact::NBodyAssembler<DeformedGridType, Vector>&;
-
-        auto matrices() const -> const Matrices<Matrix,2>&;
-
-    private:
-        const int level_;
-
-        std::vector<std::shared_ptr<Body>> bodies_;
-        std::vector<std::shared_ptr<FrictionCouplingPair>> couplings_;
-
-        std::vector<const DeformedGridType*> deformedGrids_;
-        std::vector<std::unique_ptr<const DeformedLeafGridView>> leafViews_;
-        std::vector<std::vector<std::unique_ptr<const DeformedLevelGridView>>> levelViews_;
-        std::vector<size_t> leafVertexCounts_;
-
-        std::vector<DeformedLeafBoundaryPatch*> frictionBoundaries_; // union of all boundary patches per body
-        std::vector<ScalarMatrix*> frictionBoundaryMass_;
-        StateEnergyNorms stateEnergyNorms_;
-
-        NBodyAssembler nBodyAssembler_;
-
-        Matrices<Matrix,2> matrices_;
-
-        std::shared_ptr<GlobalFriction> globalFriction_;
+template <class GridTypeTEMPLATE, class FrictionCouplingPair, class field_type>
+class LevelContactNetwork {
+public:
+    using GridType = GridTypeTEMPLATE;
+
+    enum {dim = GridType::dimension};
+    enum {dimworld = GridType::dimensionworld};
+
+    using ctype = typename GridType::ctype;
+
+    using GridView = typename GridType::LevelGridView;
+    using Body = Body<GridView>;
+
+    using Function = Dune::VirtualFunction<double, double>;
+
+    using BoundaryFunctions = std::vector<typename Body::BoundaryFunctions>;
+    using BoundaryNodes = std::vector<typename Body::BoundaryNodes>;
+    using BoundaryPatchNodes = std::vector<typename Body::BoundaryPatchNodes>;
+    using BoundaryPatches = std::vector<typename Body::BoundaryPatches>;
+    using BoundaryPatch = BoundaryPatch<GridView>;
+
+    using Extractor = Dune::GridGlue::Codim1Extractor<GridView>;
+    using Glue = Dune::GridGlue::GridGlue<Extractor, Extractor>;
+
+public:
+    LevelContactNetwork(int nBodies, int nCouplings, int level = 0);
+
+    void setBodies(const std::vector<std::shared_ptr<Body>> bodies);
+    void setCouplings(const std::vector<std::shared_ptr<FrictionCouplingPair>> couplings);
+
+    void constructBody(
+            const std::shared_ptr<BodyData<dimworld>>& bodyData,
+            const std::shared_ptr<GridType>& grid,
+            const size_t level,
+            std::shared_ptr<Body>& body) const;
+
+    void build(field_type overlap = 1e-2);
+
+    // getter
+    void totalNodes(
+            const std::string& tag,
+            Dune::BitSetVector<dimworld>& totalNodes) const;
+    void boundaryPatches(
+            const std::string& tag,
+            BoundaryPatches& patches) const;
+    void boundaryPatchNodes(
+            const std::string& tag,
+            BoundaryPatchNodes& nodes) const;
+    void boundaryNodes(
+            const std::string& tag,
+            BoundaryNodes& nodes) const;
+    void boundaryFunctions(
+            const std::string& tag,
+            BoundaryFunctions& functions) const;
+
+    auto level() const -> int;
+
+    auto nBodies() const -> size_t;
+    auto nCouplings() const -> size_t;
+
+    auto body(int i) const -> const std::shared_ptr<Body>&;
+
+    auto coupling(int i) const -> const std::shared_ptr<FrictionCouplingPair>&;
+    auto couplings() const -> const std::vector<std::shared_ptr<FrictionCouplingPair>>&;
+
+    auto glue(int i) const -> const std::shared_ptr<Glue>&;
+
+private:
+    void prolong(const BoundaryPatch& coarsePatch, BoundaryPatch& finePatch, const size_t fineLevel);
+
+    const int level_;
+
+    std::vector<std::shared_ptr<Body>> bodies_;
+    std::vector<std::shared_ptr<FrictionCouplingPair>> couplings_;
+
+    std::vector<BoundaryPatch> nonmortarPatches_;
+    std::vector<BoundaryPatch> mortarPatches_;
+    std::shared_ptr< Dune::GridGlue::Merger<field_type, dim-1, dim-1, dim> > gridGlueBackend_;
+    std::vector<std::shared_ptr<Glue>> glues_;
 };
 #endif
diff --git a/src/data-structures/levelcontactnetwork_tmpl.cc b/src/data-structures/levelcontactnetwork_tmpl.cc
index 1bd54512..da253a7f 100644
--- a/src/data-structures/levelcontactnetwork_tmpl.cc
+++ b/src/data-structures/levelcontactnetwork_tmpl.cc
@@ -3,8 +3,10 @@
 #endif
 
 #include "../explicitgrid.hh"
-#include "levelcontactnetwork.hh"
+#include "../explicitvectors.hh"
 
-using MyLevelContactNetwork = LevelContactNetwork<Grid, MY_DIM>;
+#include "../frictioncouplingpair.hh"
+#include "contactnetwork_tmpl.cc"
+#include "levelcontactnetwork.hh"
 
-template class LevelContactNetwork<Grid, MY_DIM>;
+template class LevelContactNetwork<typename MyContactNetwork::GridType, typename MyContactNetwork::FrictionCouplingPair, typename MyContactNetwork::field_type>;
diff --git a/src/data-structures/program_state.hh b/src/data-structures/program_state.hh
index bab650b9..9c5dd4af 100644
--- a/src/data-structures/program_state.hh
+++ b/src/data-structures/program_state.hh
@@ -13,7 +13,7 @@
 #include <dune/tectonic/bodydata.hh>
 
 #include "../assemblers.hh"
-#include "levelcontactnetwork.hh"
+#include "contactnetwork.hh"
 #include "matrices.hh"
 #include "../spatial-solving/solverfactory.hh"
 #include "../spatial-solving/tnnmg/functional.hh"
@@ -86,9 +86,9 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
 
   // Set up initial conditions
   template <class GridType>
-  void setupInitialConditions(const Dune::ParameterTree& parset, const LevelContactNetwork<GridType, dims>& levelContactNetwork) {
-    using Matrix = typename LevelContactNetwork<GridType, dims>::Matrix;
-    const auto& nBodyAssembler = levelContactNetwork.nBodyAssembler();
+  void setupInitialConditions(const Dune::ParameterTree& parset, const ContactNetwork<GridType, Vector>& contactNetwork) {
+    using Matrix = typename ContactNetwork<GridType, Vector>::Matrix;
+    const auto& nBodyAssembler = contactNetwork.nBodyAssembler();
 
     // Solving a linear problem with a multigrid solver
     auto const solveLinearProblem = [&](
@@ -227,14 +227,14 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
       ell0[i].resize(u[i].size());
       ell0[i] = 0.0;
 
-      levelContactNetwork.body(i)->externalForce()(relativeTime, ell0[i]);
+      contactNetwork.body(i)->externalForce()(relativeTime, ell0[i]);
     }
 
     // Initial displacement: Start from a situation of minimal stress,
     // which is automatically attained in the case [v = 0 = a].
     // Assuming dPhi(v = 0) = 0, we thus only have to solve Au = ell0
     Dune::BitSetVector<dims> dirichletNodes;
-    levelContactNetwork.totalNodes("dirichlet", dirichletNodes);
+    contactNetwork.totalNodes("dirichlet", dirichletNodes);
     /*for (size_t i=0; i<dirichletNodes.size(); i++) {
         bool val = false;
         for (size_t d=0; d<dims; d++) {
@@ -247,7 +247,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
         }
     }*/
 
-    solveLinearProblem(dirichletNodes, levelContactNetwork.matrices().elasticity, ell0, u,
+    solveLinearProblem(dirichletNodes, contactNetwork.matrices().elasticity, ell0, u,
                        parset.sub("u0.solver"));
 
     print(u, "initial u:");
@@ -261,9 +261,9 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
 
       // Initial normal stress
 
-      const auto& body = levelContactNetwork.body(i);
-      std::vector<std::shared_ptr<typename LevelContactNetwork<GridType, dims>::Body::LeafBoundaryCondition>> frictionBoundaryConditions;
-      body->leafBoundaryConditions("friction", frictionBoundaryConditions);
+      const auto& body = contactNetwork.body(i);
+      std::vector<std::shared_ptr<typename ContactNetwork<GridType, Vector>::LeafBody::BoundaryCondition>> frictionBoundaryConditions;
+      body->boundaryConditions("friction", frictionBoundaryConditions);
       for (size_t j=0; j<frictionBoundaryConditions.size(); j++) {
           ScalarVector frictionBoundaryStress(weightedNormalStress[i].size());
 
@@ -278,7 +278,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
     }
 
     Dune::BitSetVector<dims> noNodes(dirichletNodes.size(), false);
-    solveLinearProblem(noNodes, levelContactNetwork.matrices().mass, accelerationRHS, a,
+    solveLinearProblem(noNodes, contactNetwork.matrices().mass, accelerationRHS, a,
                        parset.sub("a0.solver"));
 
     print(a, "initial a:");
diff --git a/src/explicitvectors.hh b/src/explicitvectors.hh
index 548c681f..54887ada 100644
--- a/src/explicitvectors.hh
+++ b/src/explicitvectors.hh
@@ -7,12 +7,14 @@
 #include <dune/istl/bcrsmatrix.hh>
 #include <dune/istl/bvector.hh>
 
-using LocalVector = Dune::FieldVector<double, MY_DIM>;
-using LocalMatrix = Dune::FieldMatrix<double, MY_DIM, MY_DIM>;
+using ctype = double;
+
+using LocalVector = Dune::FieldVector<ctype, MY_DIM>;
+using LocalMatrix = Dune::FieldMatrix<ctype, MY_DIM, MY_DIM>;
 using Vector = Dune::BlockVector<LocalVector>;
 using Matrix = Dune::BCRSMatrix<LocalMatrix>;
-using ScalarVector = Dune::BlockVector<Dune::FieldVector<double, 1>>;
-using ScalarMatrix = Dune::BCRSMatrix<Dune::FieldMatrix<double, 1, 1>>;
+using ScalarVector = Dune::BlockVector<Dune::FieldVector<ctype, 1>>;
+using ScalarMatrix = Dune::BCRSMatrix<Dune::FieldMatrix<ctype, 1, 1>>;
 using BitVector = Dune::BitSetVector<MY_DIM>;
 
 #endif
diff --git a/src/factories/contactnetworkfactory.hh b/src/factories/contactnetworkfactory.hh
index 90298ad6..c1968822 100644
--- a/src/factories/contactnetworkfactory.hh
+++ b/src/factories/contactnetworkfactory.hh
@@ -4,45 +4,55 @@
 #include <dune/common/parametertree.hh>
 
 #include "../data-structures/contactnetwork.hh"
-#include "../data-structures/levelcontactnetwork.hh"
 
-#include "levelcontactnetworkfactory.hh"
-
-template <class GridType, int dim>
+template <class HostGridType, class VectorType>
 class ContactNetworkFactory {
 public:
-    using ContactNetwork = ContactNetwork<GridType, dim>;
+    using ContactNetwork = ContactNetwork<HostGridType, VectorType>;
 
 protected:
-    using LevelContactNetworkFactory = LevelContactNetworkFactory<GridType, dim>;
+    using LeafBody = typename ContactNetwork::LeafBody;
+    using FrictionCouplingPair = typename ContactNetwork::FrictionCouplingPair;
 
     const Dune::ParameterTree& parset_;
+    const size_t bodyCount_;
+    const size_t couplingCount_;
 
-    std::vector<std::shared_ptr<LevelContactNetworkFactory>> levelContactNetworkFactories_;
+    std::vector<std::shared_ptr<LeafBody>> bodies_;
+    std::vector<std::shared_ptr<FrictionCouplingPair>> couplings_;
 
     ContactNetwork contactNetwork_;
 
 private:
     virtual void setBodies() = 0;
+    virtual void setLevelBodies() = 0;
     virtual void setCouplings() = 0;
+    virtual void setLevelCouplings() = 0;
     virtual void setBoundaryConditions() = 0;
 
 public:
-    ContactNetworkFactory(const Dune::ParameterTree& parset) :
+    ContactNetworkFactory(const Dune::ParameterTree& parset, size_t bodyCount, size_t couplingCount) :
         parset_(parset),
-        contactNetwork_() {}
+        bodyCount_(bodyCount),
+        couplingCount_(couplingCount),
+        bodies_(bodyCount_),
+        couplings_(couplingCount_),
+        contactNetwork_(bodyCount_, couplingCount_) {}
 
     void build() {
         setBodies();
-        contactNetwork_.setBodies();
+        contactNetwork_.setBodies(bodies_);
 
         setCouplings();
-        contactNetwork_.setCouplings();
+        contactNetwork_.setCouplings(couplings_);
+
+        setLevelBodies();
+        setLevelCouplings();
 
-        setBoundaryConditions();
+        setBoundaryConditions();      
     }
 
-    ContactNetwork& levelContactNetwork() {
+    ContactNetwork& contactNetwork() {
         return contactNetwork_;
     }
 };
diff --git a/src/factories/levelcontactnetworkfactory.hh b/src/factories/levelcontactnetworkfactory.hh
index 833036c6..d85b0853 100644
--- a/src/factories/levelcontactnetworkfactory.hh
+++ b/src/factories/levelcontactnetworkfactory.hh
@@ -1,12 +1,12 @@
-#ifndef SRC_LEVELCONTACTNETWORKFACTORY_HH
-#define SRC_LEVELCONTACTNETWORKFACTORY_HH
+#ifndef SRC_CONTACTNETWORKFACTORY_HH
+#define SRC_CONTACTNETWORKFACTORY_HH
 
 #include <dune/common/parametertree.hh>
 
 #include "../data-structures/levelcontactnetwork.hh"
 
-template <class GridType, int dims>
-class LevelContactNetworkFactory {
+template <class HostGridType>
+class ContactNetworkFactory {
 public:
     using LevelContactNetwork = LevelContactNetwork<GridType, dims>;
 
diff --git a/src/factories/stackedblocksfactory.cc b/src/factories/stackedblocksfactory.cc
index feb057cd..5a2aaaff 100644
--- a/src/factories/stackedblocksfactory.cc
+++ b/src/factories/stackedblocksfactory.cc
@@ -9,7 +9,6 @@
 #include "../multi-body-problem-data/bc.hh"
 #include "../multi-body-problem-data/grid/cuboidgeometry.hh"
 #include "../multi-body-problem-data/myglobalfrictiondata.hh"
-#include "../multi-body-problem-data/weakpatch.hh"
 
 #include "../utils/diameter.hh"
 
diff --git a/src/factories/threeblocksfactory.cc b/src/factories/threeblocksfactory.cc
new file mode 100644
index 00000000..7dded09d
--- /dev/null
+++ b/src/factories/threeblocksfactory.cc
@@ -0,0 +1,204 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <dune/fufem/geometry/convexpolyhedron.hh>
+
+#include <dune/contact/projections/normalprojection.hh>
+
+#include "../multi-body-problem-data/bc.hh"
+#include "../multi-body-problem-data/myglobalfrictiondata.hh"
+
+#include "../utils/diameter.hh"
+
+#include "threeblocksfactory.hh"
+
+template <class HostGridType, class VectorTEMPLATE>
+void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBodies() {
+    // set up cuboid geometries
+
+    std::array<double, 3> lengths = {3.0, 1.0, 1.0};
+    std::array<double, 3> heights = {1.0, 1.0, 1.0};
+
+    std::array<GlobalCoords, 3> origins;
+
+    const auto& subParset = this->parset_.sub("boundary.friction.weakening");
+
+#if MY_DIM == 3 // TODO: not implemented
+        double const depth = 0.60;
+
+        origins[0] = {0, 0, 0};
+        origins[1] = {0, origins[0][1] + widths[0], 0};
+        origins[2] = {origins[1][0] + lengths[1], origins[0][1] + widths[0], 0};
+
+        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lengths[0], heights[0], depth);
+        cuboidGeometries_[0]->addWeakeningPatch(subParset, {origins[0][0], origins[0][1]+ heights[0], 0}, {origins[0][0] + lengths[0], origins[0][1]+ heights[0], 0});
+
+        cuboidGeometries_[1] = std::make_shared<CuboidGeometry>(origins[1], lengths[1], heights[1], depth);
+        cuboidGeometries_[1]->addWeakeningPatch(subParset, origins[1], {origins[1][0] + lengths[1], origins[1][1], 0});
+        cuboidGeometries_[1]->addWeakeningPatch(subParset, origins[1], {origins[1][0] + lengths[1], origins[1][1] + heights[1], 0});
+
+        cuboidGeometries_[2] = std::make_shared<CuboidGeometry>(origins[2], lengths[2], heights[2], depth);
+        cuboidGeometries_[2]->addWeakeningPatch(subParset, origins[2], {origins[2][0] + lengths[2], origins[2][1], 0});
+        cuboidGeometries_[2]->addWeakeningPatch(subParset, origins[2], {origins[2][0], origins[2][1] + widths[2], 0});
+#elif MY_DIM == 2
+        origins[0] = {0, 0};
+        origins[1] = {0, origins[0][1] + heights[0]};
+        origins[2] = {origins[1][0] + lengths[1], origins[0][1] + heights[0]};
+
+        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lengths[0], heights[0]);
+        cuboidGeometries_[0]->addWeakeningPatch(subParset, {origins[0][0], origins[0][1]+ heights[0]}, {origins[0][0] + lengths[0], origins[0][1]+ heights[0]});
+
+        cuboidGeometries_[1] = std::make_shared<CuboidGeometry>(origins[1], lengths[1], heights[1]);
+        cuboidGeometries_[1]->addWeakeningPatch(subParset, origins[1], {origins[1][0] + lengths[1], origins[1][1]});
+        cuboidGeometries_[1]->addWeakeningPatch(subParset, {origins[1][0] + lengths[1], origins[1][1]}, {origins[1][0] + lengths[1], origins[1][1] + heights[1]});
+
+        cuboidGeometries_[2] = std::make_shared<CuboidGeometry>(origins[2], lengths[2], heights[2]);
+        cuboidGeometries_[2]->addWeakeningPatch(subParset, origins[2], {origins[2][0] + lengths[2], origins[2][1]});
+        cuboidGeometries_[2]->addWeakeningPatch(subParset, origins[2], {origins[2][0], origins[2][1] + heights[2]});
+#else
+#error CuboidGeometry only supports 2D and 3D!"
+#endif
+
+    // set up reference grids
+    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
+        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();
+        double maxDiameter = 0.0;
+        for (auto &&e : elements(grids[i]->leafGridView())) {
+          auto const geometry = e.geometry();
+          auto const diam = diameter(geometry);
+          minDiameter = std::min(minDiameter, diam);
+          maxDiameter = std::max(maxDiameter, diam);
+        }
+        std::cout << "Grid" << i << " min diameter: " << minDiameter << std::endl;
+        std::cout << "Grid" << i << " max diameter: " << maxDiameter << std::endl;
+    }
+
+    for (size_t i=0; i<this->bodyCount_; i++) {
+        this->bodies_[i] = std::make_shared<typename Base::LeafBody>(bodyData_, grids[i]);
+    }
+}
+
+template <class HostGridType, class VectorTEMPLATE>
+void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setLevelBodies() {
+    const size_t maxLevel = std::max({this->bodies_[0]->grid()->maxLevel(), this->bodies_[1]->grid()->maxLevel(), this->bodies_[2]->grid()->maxLevel()});
+
+    for (size_t l=0; l<=maxLevel; l++) {
+        std::vector<size_t> bodyLevels(3, l);
+        this->contactNetwork_.addLevel(bodyLevels, l);
+    }
+}
+
+template <class HostGridType, class VectorTEMPLATE>
+void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setCouplings() {
+    for (size_t i=0; i<this->bodyCount_; i++) {
+        const auto& cuboidGeometry = *cuboidGeometries_[i];
+        std::cout << this->bodies_[i]->nVertices() << std::endl;
+        std::cout << (leafFaces_[i] == nullptr) << std::endl;
+        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;
+
+    std::array<std::array<size_t, 2>, 3> couplingIndices;
+
+    nonmortarPatch_[0] = std::make_shared<LevelBoundaryPatch>(levelFaces_[0]->upper);
+    mortarPatch_[0] = std::make_shared<LevelBoundaryPatch>(levelFaces_[1]->lower);
+    weakPatches_[0] = std::make_shared<WeakeningRegion>(cuboidGeometries_[0]->weakeningRegions()[0]);
+    couplingIndices[0] = {0, 1};
+
+    nonmortarPatch_[1] = std::make_shared<LevelBoundaryPatch>(levelFaces_[2]->lower);
+    mortarPatch_[1] = std::make_shared<LevelBoundaryPatch>(levelFaces_[0]->upper);
+    weakPatches_[1] = std::make_shared<WeakeningRegion>(cuboidGeometries_[2]->weakeningRegions()[0]);
+    couplingIndices[1] = {2, 0};
+
+    nonmortarPatch_[2] = std::make_shared<LevelBoundaryPatch>(levelFaces_[1]->right);
+    mortarPatch_[2] = std::make_shared<LevelBoundaryPatch>(levelFaces_[2]->left);
+    weakPatches_[2] = std::make_shared<WeakeningRegion>(cuboidGeometries_[1]->weakeningRegions()[1]);
+    couplingIndices[2] = {1, 2};
+
+    for (size_t i=0; i<this->couplings_.size(); i++) {
+      auto& coupling = this->couplings_[i];
+      coupling = std::make_shared<typename Base::FrictionCouplingPair>();
+
+      coupling->set(couplingIndices[i][0], couplingIndices[i][1], nonmortarPatch_[i], mortarPatch_[i], 0.1, Base::FrictionCouplingPair::CouplingType::STICK_SLIP, contactProjection, backend);
+      coupling->setWeakeningPatch(weakPatches_[i]);
+      coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale));
+    }
+}
+
+template <class HostGridType, class VectorTEMPLATE>
+void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBoundaryConditions() {
+    using LeafBoundaryCondition = BoundaryCondition<LeafGridView, dim>;
+
+    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;
+
+    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>0) {
+            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
+            }
+
+            std::shared_ptr<LeafBoundaryCondition> velocityDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet");
+
+            velocityDirichletBoundary->setBoundaryPatch(body->gridView(), velocityDirichletNodes);
+            velocityDirichletBoundary->setBoundaryFunction(velocityDirichletFunction);
+            body->addBoundaryCondition(velocityDirichletBoundary);
+        }
+    }
+
+    // lower Dirichlet Boundary
+    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<dim; d++) {
+              (*zeroDirichletNodes)[j][d] = true;
+            }
+        }
+    }
+
+    std::shared_ptr<LeafBoundaryCondition> zeroDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet");
+    zeroDirichletBoundary->setBoundaryPatch(firstBody->gridView(), zeroDirichletNodes);
+
+    std::shared_ptr<Function> zeroFunction = std::make_shared<NeumannCondition>();
+    zeroDirichletBoundary->setBoundaryFunction(zeroFunction);
+    firstBody->addBoundaryCondition(zeroDirichletBoundary);
+}
+
+#include "threeblocksfactory_tmpl.cc"
diff --git a/src/factories/threeblocksfactory.hh b/src/factories/threeblocksfactory.hh
new file mode 100644
index 00000000..e3405572
--- /dev/null
+++ b/src/factories/threeblocksfactory.hh
@@ -0,0 +1,84 @@
+#ifndef SRC_THREEBLOCKSFACTORY_HH
+#define SRC_THREEBLOCKSFACTORY_HH
+
+#include <dune/common/bitsetvector.hh>
+#include <dune/common/function.hh>
+#include <dune/common/fvector.hh>
+
+#include <dune/fufem/boundarypatch.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 HostGridType, class VectorType>
+class ThreeBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType>{
+private:
+    using Base = ContactNetworkFactory<HostGridType, VectorType>;
+
+public:
+    using ContactNetwork = typename Base::ContactNetwork;
+
+private:
+    using GlobalCoords = typename ContactNetwork::LocalVector;
+
+    using LeafGridView = typename ContactNetwork::GridView;
+    using LevelGridView = typename ContactNetwork::GridType::LevelGridView;
+
+    using LevelBoundaryPatch = BoundaryPatch<LevelGridView>;
+    using LeafBoundaryPatch = BoundaryPatch<LeafGridView>;
+
+    using LeafFaces = MyFaces<LeafGridView>;
+    using LevelFaces = MyFaces<LevelGridView>;
+
+    using CuboidGeometry= CuboidGeometry<typename GlobalCoords::field_type>;
+    using WeakeningRegion = typename CuboidGeometry::WeakeningRegion;
+
+    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<WeakeningRegion>> weakPatches_;
+
+    std::vector<std::shared_ptr<LevelBoundaryPatch>> nonmortarPatch_;
+    std::vector<std::shared_ptr<LevelBoundaryPatch>> mortarPatch_;
+
+public:
+    ThreeBlocksFactory(const Dune::ParameterTree& parset) :
+        Base(parset, 3, 3),
+        bodyData_(std::make_shared<MyBodyData<dim>>(this->parset_, zenith_())),
+        cuboidGeometries_(3),
+        leafFaces_(3),
+        levelFaces_(3),
+        weakPatches_(3),
+        nonmortarPatch_(3),
+        mortarPatch_(3)
+    {}
+
+    void setBodies();
+    void setLevelBodies();
+    void setCouplings();
+    void setLevelCouplings() {}
+    void setBoundaryConditions();
+
+private:
+    static constexpr Dune::FieldVector<double, MY_DIM> zenith_() {
+        #if MY_DIM == 2
+        return {0, 1};
+        #elif MY_DIM == 3
+        return {0, 1, 0};
+        #endif
+    }
+};
+#endif
+
+
diff --git a/src/factories/threeblocksfactory_tmpl.cc b/src/factories/threeblocksfactory_tmpl.cc
new file mode 100644
index 00000000..9ba11d9d
--- /dev/null
+++ b/src/factories/threeblocksfactory_tmpl.cc
@@ -0,0 +1,8 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
+
+template class ThreeBlocksFactory<Grid, Vector>;
diff --git a/src/multi-body-problem-data/grid/cuboidgeometry.cc b/src/multi-body-problem-data/grid/cuboidgeometry.cc
index 77cd62f9..2fe7b2b5 100644
--- a/src/multi-body-problem-data/grid/cuboidgeometry.cc
+++ b/src/multi-body-problem-data/grid/cuboidgeometry.cc
@@ -12,76 +12,85 @@
 
 #include "cuboidgeometry.hh"
 
-/*
-const CuboidGeometry::LocalVector CuboidGeometry::lift(const double v0, const double v1) {
-  vc = 0;
-  vc[0] = vc2D[0];
-  vc[1] = vc2D[1];
-}
-
-const CuboidGeometry::LocalVector& CuboidGeometry::A() const { return A_; }
-const CuboidGeometry::LocalVector& CuboidGeometry::B() const { return B_; }
-const CuboidGeometry::LocalVector& CuboidGeometry::C() const { return C_; }
-const CuboidGeometry::LocalVector& CuboidGeometry::D() const { return D_; }
-const CuboidGeometry::LocalVector& CuboidGeometry::X() const { return X_; }
-const CuboidGeometry::LocalVector& CuboidGeometry::Y() const { return Y_; }
-double CuboidGeometry::depth() const { return depth_; }
-
-void CuboidGeometry::setupWeak(const LocalVector& weakOrigin, const double weakLength) {
-    lift(weakOrigin, X_);
-    const LocalVector2D Y({X_[0]+weakLength, X_[1]});
-    lift(Y, Y_);
-}
-*/
-
 #if MY_DIM == 3
-CuboidGeometry::CuboidGeometry(const LocalVector& origin,
-                               const LocalVector& lowerWeakOrigin, const LocalVector& upperWeakOrigin,
-                               const double lowerWeakLength, const double upperWeakLength,
-                               const double length const double width, const double depth):
+template <class ctype>
+CuboidGeometry<ctype>::CuboidGeometry(const GlobalCoords& origin,
+                                      const double length = 1.00, const double height = 0.27, const double depth = 0.60) :
     length_(length*lengthScale),
-    width_(width*lengthScale),
-    A(origin),
-    B({origin[0]+length_, origin[1], 0}),
-    C({origin[0]+length_, origin[1]+width_, 0}),
-    D({origin[0], origin[1]+width_, 0}),
-    V(lowerWeakOrigin),
-    W({V[0]+lowerWeakLength*lengthScale, V[1], 0}),
-    X(upperWeakOrigin),
-    Y({X[0]+upperWeakLength*lengthScale, X[1], 0}),
-    depth(depth_*lengthScale) {}
+    height_(height*lengthScale),
+    depth_(depth*lengthScale),
+    lowerLeft_(origin),
+    lowerRight_({origin[0]+length_, origin[1], 0}),
+    upperRight_({origin[0]+length_, origin[1]+height_, 0}),
+    upperLeft_({origin[0], origin[1]+height_, 0})
+    {}
 #else
-CuboidGeometry::CuboidGeometry(const LocalVector& origin,
-                               const LocalVector& lowerWeakOrigin, const LocalVector& upperWeakOrigin,
-                               const double lowerWeakLength, const double upperWeakLength,
-                               const double length, const double width):
+
+template <class ctype>
+CuboidGeometry<ctype>::CuboidGeometry(const GlobalCoords& origin,
+                                      const double length, const double height) :
     length_(length*lengthScale),
-    width_(width*lengthScale),
-    A(origin),
-    B({origin[0]+length_, origin[1]}),
-    C({origin[0]+length_, origin[1]+width_}),
-    D({origin[0], origin[1]+width_}),
-    V(lowerWeakOrigin),
-    W({V[0]+lowerWeakLength*lengthScale, V[1]}),
-    X(upperWeakOrigin),
-    Y({X[0]+upperWeakLength*lengthScale, X[1]}) {}
+    height_(height*lengthScale),
+    lowerLeft_(origin),
+    lowerRight_({origin[0]+length_, origin[1]}),
+    upperRight_({origin[0]+length_, origin[1]+height_}),
+    upperLeft_({origin[0], origin[1]+height_})
+    {}
 #endif
 
+template <class ctype>
+void CuboidGeometry<ctype>::addWeakeningRegion(const WeakeningRegion& weakeningRegion) {
+    weakeningRegions_.emplace_back(weakeningRegion);
+}
+
+template <class ctype>
+void CuboidGeometry<ctype>::addWeakeningPatch(const Dune::ParameterTree& parset, const GlobalCoords& vertex0, const GlobalCoords& vertex1) {
+    WeakeningRegion weakPatch;
+
+#if MY_DIM == 3 // TODO: Does not work yet
+    if (vertex0 != vertex1) {
+        weakPatch.vertices.resize(4);
+        weakPatch.vertices[0] = weakPatch.vertices[2] = vertex0;
+        weakPatch.vertices[1] = weakPatch.vertices[3] = vertex1;
+
+        for (size_t k = 0; k < 2; ++k) {
+            weakPatch.vertices[k][2] = -depth_ / 2.0;
+            weakPatch.vertices[k + 2][2] = depth_ / 2.0;
+        }
+        switch (parset.get<Config::PatchType>("patchType")) {
+            case Config::Rectangular:
+                break;
+            case Config::Trapezoidal:
+                weakPatch.vertices[1][0] += 0.05 * lengthScale;
+                weakPatch.vertices[3][0] -= 0.05 * lengthScale;
+                break;
+            default:
+                assert(false);
+        }
+        addWeakeningRegion(weakPatch);
+    }
+#else
+    if (vertex0 != vertex1) {
+        weakPatch.vertices.resize(2);
+        weakPatch.vertices[0] = vertex0;
+        weakPatch.vertices[1] = vertex1;
+        addWeakeningRegion(weakPatch);
+    }
+#endif
+}
 
-void CuboidGeometry::write() const {
-  std::fstream writer("geometry", std::fstream::out);
-  writer << "A = " << A << std::endl;
-  writer << "B = " << B << std::endl;
-  writer << "C = " << C << std::endl;
-  writer << "D = " << D << std::endl;
-  writer << "V = " << V << std::endl;
-  writer << "W = " << W << std::endl;
-  writer << "X = " << X << std::endl;
-  writer << "Y = " << Y << std::endl;
+template <class ctype>
+void CuboidGeometry<ctype>::write() const {
+    std::fstream writer("geometry", std::fstream::out);
+    writer << "lowerLeft = " << lowerLeft_ << std::endl;
+    writer << "lowerRight = " << lowerRight_ << std::endl;
+    writer << "upperRight = " << upperRight_ << std::endl;
+    writer << "upperLeft = " << upperLeft_ << std::endl;
 }
 
 /*
-void CuboidGeometry::render() const {
+template <class ctype>
+void CuboidGeometry<ctype>::render() const {
 #ifdef HAVE_CAIROMM
   std::string const filename = "geometry.png";
   double const width = 600;
@@ -202,3 +211,5 @@ void CuboidGeometry::render() const {
 #endif
 }
 */
+
+#include "cuboidgeometry_tmpl.cc"
diff --git a/src/multi-body-problem-data/grid/cuboidgeometry.hh b/src/multi-body-problem-data/grid/cuboidgeometry.hh
index 834f3f4d..56998355 100644
--- a/src/multi-body-problem-data/grid/cuboidgeometry.hh
+++ b/src/multi-body-problem-data/grid/cuboidgeometry.hh
@@ -1,51 +1,73 @@
 #ifndef SRC_MULTI_BODY_PROBLEM_DATA_CUBOIDGEOMETRY_HH
 #define SRC_MULTI_BODY_PROBLEM_DATA_CUBOIDGEOMETRY_HH
 
+#include <vector>
+
 #include <dune/common/fvector.hh>
+#include <dune/common/parametertree.hh>
 
-#include "../midpoint.hh"
+#include <dune/fufem/geometry/convexpolyhedron.hh>
 
+template <class ctype = double>
 class CuboidGeometry {
-  public:
-    typedef Dune::FieldVector<double, MY_DIM> LocalVector;
+public:
+    typedef Dune::FieldVector<ctype, MY_DIM> GlobalCoords;
+    using WeakeningRegion = ConvexPolyhedron<GlobalCoords>;
 
     constexpr static double const lengthScale = 1.0; // scaling factor
 
-  private:
-    const double length_;
-    const double width_;
-   // const double lowerWeakLength_;     // length of the lower weak zone
-   // const double upperWeakLength_;     // length of the lower weak zone
+private:
+    const ctype length_;
+    const ctype height_;
+#if MY_DIM == 3
+    const ctype depth_;
+#endif
 
-  public:
     // corners of cube
-    const LocalVector A;
-    const LocalVector B;
-    const LocalVector C;
-    const LocalVector D;
+    const GlobalCoords lowerLeft_;
+    const GlobalCoords lowerRight_;
+    const GlobalCoords upperRight_;
+    const GlobalCoords upperLeft_;
 
-    // corners of lower weakening patch
-    const LocalVector V;
-    const LocalVector W;
-
-    // corners of upper weakening patch
-    const LocalVector X;
-    const LocalVector Y;
+    // weakening regions
+    std::vector<WeakeningRegion> weakeningRegions_;
 
+public:
 #if MY_DIM == 3
-    const double depth;
+    CuboidGeometry(const GlobalCoords& origin,
+                   const double length = 1.00, const double height = 0.27, const double depth = 0.60);
 
-    CuboidGeometry(const LocalVector& origin,
-                   const LocalVector& lowerWeakOrigin, const LocalVector& upperWeakOrigin,
-                   const double lowerWeakLength = 0.20, const double upperWeakLength = 0.20,
-                   const double length = 1.00, const double width = 0.27, const double depth = 0.60);
+    const auto& depth() const {
+        return depth_;
+    }
 #else
-        CuboidGeometry(const LocalVector& origin,
-                       const LocalVector& lowerWeakOrigin, const LocalVector& upperWeakOrigin,
-                       const double lowerWeakLength = 0.20, const double upperWeakLength = 0.20,
-                       const double length = 1.00, const double width = 0.27);
+    CuboidGeometry(const GlobalCoords& origin,
+                       const double length = 1.00, const double height = 0.27);
 #endif
 
+    void addWeakeningRegion(const WeakeningRegion& weakeningRegion);
+    void addWeakeningPatch(const Dune::ParameterTree& parset, const GlobalCoords& vertex0, const GlobalCoords& vertex1);
+
+    const auto& lowerLeft() const {
+        return lowerLeft_;
+    }
+
+    const auto& lowerRight() const {
+        return lowerRight_;
+    }
+
+    const auto& upperRight() const {
+        return upperRight_;
+    }
+
+    const auto& upperLeft() const {
+        return upperLeft_;
+    }
+
+    const auto& weakeningRegions() const {
+        return weakeningRegions_;
+    }
+
     void write() const;
 
    // void render() const;
diff --git a/src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc b/src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc
new file mode 100644
index 00000000..6065a02b
--- /dev/null
+++ b/src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc
@@ -0,0 +1,8 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../../explicitgrid.hh"
+#include "cuboidgeometry.hh"
+
+template class CuboidGeometry<typename Grid::ctype>;
diff --git a/src/multi-body-problem-data/grid/mygrids.cc b/src/multi-body-problem-data/grid/mygrids.cc
index 3d2fafda..e18f316b 100644
--- a/src/multi-body-problem-data/grid/mygrids.cc
+++ b/src/multi-body-problem-data/grid/mygrids.cc
@@ -11,7 +11,7 @@
 #include "simplexmanager.hh"
 
 // Fix: 3D case (still Elias code)
-template <class Grid> GridsConstructor<Grid>::GridsConstructor(std::vector<std::shared_ptr<CuboidGeometry>> const &cuboidGeometries_) :
+template <class Grid> GridsConstructor<Grid>::GridsConstructor(const std::vector<std::shared_ptr<CuboidGeometry<typename Grid::ctype>>>& cuboidGeometries_) :
   cuboidGeometries(cuboidGeometries_)
 {
   size_t const gridCount = cuboidGeometries.size();
@@ -21,10 +21,10 @@ template <class Grid> GridsConstructor<Grid>::GridsConstructor(std::vector<std::
   for (size_t idx=0; idx<grids.size(); idx++) {
     const auto& cuboidGeometry = *cuboidGeometries[idx];
 
-    const auto& A = cuboidGeometry.A;
-    const auto& B = cuboidGeometry.B;
-    const auto& C = cuboidGeometry.C;
-    const auto& D = cuboidGeometry.D;
+    const auto& A = cuboidGeometry.lowerLeft();
+    const auto& B = cuboidGeometry.lowerRight();
+    const auto& C = cuboidGeometry.upperRight();
+    const auto& D = cuboidGeometry.upperLeft();
 
     unsigned int const vc = 4;
 
@@ -51,8 +51,8 @@ template <class Grid> GridsConstructor<Grid>::GridsConstructor(std::vector<std::
 
 #if MY_DIM == 3
     for (size_t k = 0; k < vc; ++k) {
-      vertices[k][2] = -cuboidGeometry.depth / 2.0;
-      vertices[k + vc][2] = cuboidGeometry.depth / 2.0;
+      vertices[k][2] = -cuboidGeometry.depth() / 2.0;
+      vertices[k + vc][2] = cuboidGeometry.depth() / 2.0;
     }
 #endif
 
@@ -96,7 +96,7 @@ std::vector<std::shared_ptr<Grid>>& GridsConstructor<Grid>::getGrids() {
 template <class Grid>
 template <class GridView>
 MyFaces<GridView> GridsConstructor<Grid>::constructFaces(
-    GridView const &gridView, CuboidGeometry const &cuboidGeometry) {
+    GridView const &gridView, const CuboidGeometry<typename Grid::ctype>& cuboidGeometry) {
   return MyFaces<GridView>(gridView, cuboidGeometry);
 }
 
@@ -132,7 +132,7 @@ bool MyFaces<GridView>::xyBetween(Vector const &v1, Vector const &v2,
 }
 
 template <class GridView>
-MyFaces<GridView>::MyFaces(GridView const &gridView, CuboidGeometry const &cuboidGeometry_)
+MyFaces<GridView>::MyFaces(GridView const &gridView, const CuboidGeometry<typename GridView::ctype>& cuboidGeometry_)
       :
   #if MY_DIM == 3
         lower(gridView),
@@ -150,28 +150,28 @@ MyFaces<GridView>::MyFaces(GridView const &gridView, CuboidGeometry const &cuboi
         cuboidGeometry(cuboidGeometry_)
   {
     lower.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-      return xyBetween(cuboidGeometry.A, cuboidGeometry.B, in.geometry().center());
+      return xyBetween(cuboidGeometry.lowerLeft(), cuboidGeometry.lowerRight(), in.geometry().center());
     });
 
     right.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-      return xyBetween(cuboidGeometry.B, cuboidGeometry.C, in.geometry().center());
+      return xyBetween(cuboidGeometry.lowerRight(), cuboidGeometry.upperRight(), in.geometry().center());
     });
 
     upper.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-      return xyBetween(cuboidGeometry.D, cuboidGeometry.C, in.geometry().center());
+      return xyBetween(cuboidGeometry.upperLeft(), cuboidGeometry.upperRight(), in.geometry().center());
     });
 
     left.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-      return xyBetween(cuboidGeometry.A, cuboidGeometry.D, in.geometry().center());
+      return xyBetween(cuboidGeometry.lowerLeft(), cuboidGeometry.upperLeft(), in.geometry().center());
     });
 
   #if MY_DIM == 3
     front.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-      return isClose(cuboidGeometry.depth / 2.0, in.geometry().center()[2]);
+      return isClose(cuboidGeometry.depth() / 2.0, in.geometry().center()[2]);
     });
 
     back.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-      return isClose(-cuboidGeometry.depth / 2.0, in.geometry().center()[2]);
+      return isClose(-cuboidGeometry.depth() / 2.0, in.geometry().center()[2]);
     });
   #endif
   }
diff --git a/src/multi-body-problem-data/grid/mygrids.hh b/src/multi-body-problem-data/grid/mygrids.hh
index f37716eb..574efa1d 100644
--- a/src/multi-body-problem-data/grid/mygrids.hh
+++ b/src/multi-body-problem-data/grid/mygrids.hh
@@ -20,10 +20,10 @@ template <class GridView> struct MyFaces {
   BoundaryPatch<GridView> back;
 #endif
 
-  MyFaces(GridView const &gridView, CuboidGeometry const &cuboidGeometry_);
+  MyFaces(GridView const &gridView, const CuboidGeometry<typename GridView::ctype>& cuboidGeometry_);
 
 private:
-  CuboidGeometry const &cuboidGeometry;
+  const CuboidGeometry<typename GridView::ctype>& cuboidGeometry;
 
   bool isClose(double a, double b) {
     return std::abs(a - b) < 1e-14 * cuboidGeometry.lengthScale;
@@ -46,15 +46,15 @@ template <class GridView> struct MyFaces {
 
 template <class Grid> class GridsConstructor {
 public:
-  GridsConstructor(std::vector<std::shared_ptr<CuboidGeometry>> const &cuboidGeometries_);
+  GridsConstructor(const std::vector<std::shared_ptr<CuboidGeometry<typename Grid::ctype>>>& cuboidGeometries_);
 
   std::vector<std::shared_ptr<Grid>>& getGrids();
 
   template <class GridView>
-  MyFaces<GridView> constructFaces(GridView const &gridView, CuboidGeometry const &cuboidGeometry);
+  MyFaces<GridView> constructFaces(const GridView& gridView, const CuboidGeometry<typename Grid::ctype>& cuboidGeometry);
 
 private:
-  std::vector<std::shared_ptr<CuboidGeometry>> const &cuboidGeometries;
+  const std::vector<std::shared_ptr<CuboidGeometry<typename Grid::ctype>>>& cuboidGeometries;
   std::vector<Dune::GridFactory<Grid>> gridFactories;
   std::vector<std::shared_ptr<Grid>> grids;
 };
diff --git a/src/multi-body-problem-data/grid/mygrids_tmpl.cc b/src/multi-body-problem-data/grid/mygrids_tmpl.cc
index 32a19759..e626dd27 100644
--- a/src/multi-body-problem-data/grid/mygrids_tmpl.cc
+++ b/src/multi-body-problem-data/grid/mygrids_tmpl.cc
@@ -12,10 +12,10 @@ template struct MyFaces<DeformedGrid::LeafGridView>;
 template struct MyFaces<DeformedGrid::LevelGridView>;
 
 template MyFaces<DeformedGrid::LeafGridView> GridsConstructor<Grid>::constructFaces(
-    DeformedGrid::LeafGridView const &gridView, CuboidGeometry const &CuboidGeometry_);
+    DeformedGrid::LeafGridView const &gridView, CuboidGeometry<typename Grid::ctype> const &CuboidGeometry_);
 
 template MyFaces<DeformedGrid::LevelGridView> GridsConstructor<Grid>::constructFaces(
-    DeformedGrid::LevelGridView const &gridView, CuboidGeometry const &CuboidGeometry_);
+    DeformedGrid::LevelGridView const &gridView, CuboidGeometry<typename Grid::ctype> const &CuboidGeometry_);
 
 template void refine<Grid, LocalVector>(
     Grid &grid, ConvexPolyhedron<LocalVector> const &weakPatch,
diff --git a/src/multi-body-problem-data/weakpatch.hh b/src/multi-body-problem-data/weakpatch.hh
deleted file mode 100644
index 047dc482..00000000
--- a/src/multi-body-problem-data/weakpatch.hh
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef SRC_MULTI_BODY_PROBLEM_DATA_WEAKPATCH_HH
-#define SRC_MULTI_BODY_PROBLEM_DATA_WEAKPATCH_HH
-
-#include <dune/common/parametertree.hh>
-
-#include <dune/fufem/geometry/convexpolyhedron.hh>
-
-#include "grid/cuboidgeometry.hh"
-
-template <class LocalVector>
-void getWeakPatch(Dune::ParameterTree const &parset, CuboidGeometry const &cuboidGeometry, ConvexPolyhedron<LocalVector>& lowerWeakPatch, ConvexPolyhedron<LocalVector>& upperWeakPatch) {
-
-#if MY_DIM == 3 // TODO: Does not work yet
-  if (cuboidGeometry.V != cuboidGeometry.W) {
-    lowerWeakPatch.vertices.resize(4);
-    lowerWeakPatch.vertices[0] = lowerWeakPatch.vertices[2] = cuboidGeometry.V;
-    lowerWeakPatch.vertices[1] = lowerWeakPatch.vertices[3] = cuboidGeometry.W;
-    for (size_t k = 0; k < 2; ++k) {
-        lowerWeakPatch.vertices[k][2] = -cuboidGeometry.depth / 2.0;
-        lowerWeakPatch.vertices[k + 2][2] = cuboidGeometry.depth / 2.0;
-    }
-    switch (parset.get<Config::PatchType>("patchType")) {
-        case Config::Rectangular:
-            break;
-        case Config::Trapezoidal:
-            lowerWeakPatch.vertices[1][0] += 0.05 * cuboidGeometry.lengthScale;
-            lowerWeakPatch.vertices[3][0] -= 0.05 * cuboidGeometry.lengthScale;
-            break;
-        default:
-            assert(false);
-    }
-  }
-
-  if (cuboidGeometry.X != cuboidGeometry.Y) {
-    upperWeakPatch.vertices.resize(4);
-    upperWeakPatch.vertices[0] = upperWeakPatch.vertices[2] = cuboidGeometry.X;
-    upperWeakPatch.vertices[1] = upperWeakPatch.vertices[3] = cuboidGeometry.Y;
-    for (size_t k = 0; k < 2; ++k) {
-        upperWeakPatch.vertices[k][2] = -cuboidGeometry.depth / 2.0;
-        upperWeakPatch.vertices[k + 2][2] = cuboidGeometry.depth / 2.0;
-    }
-    switch (parset.get<Config::PatchType>("patchType")) {
-        case Config::Rectangular:
-            break;
-        case Config::Trapezoidal:
-            upperWeakPatch.vertices[1][0] += 0.05 * cuboidGeometry.lengthScale;
-            upperWeakPatch.vertices[3][0] -= 0.05 * cuboidGeometry.lengthScale;
-            break;
-        default:
-            assert(false);
-    }
-  }
-#else
-  if (cuboidGeometry.V != cuboidGeometry.W) {
-    lowerWeakPatch.vertices.resize(2);
-    lowerWeakPatch.vertices[0] = cuboidGeometry.V;
-    lowerWeakPatch.vertices[1] = cuboidGeometry.W;
-  }
-
-  if (cuboidGeometry.X != cuboidGeometry.Y) {
-    upperWeakPatch.vertices.resize(2);
-    upperWeakPatch.vertices[0] = cuboidGeometry.X;
-    upperWeakPatch.vertices[1] = cuboidGeometry.Y;
-  }
-#endif
-};
-#endif
diff --git a/src/multi-body-problem.cc b/src/multi-body-problem.cc
index e20cc637..6ab6c3dd 100644
--- a/src/multi-body-problem.cc
+++ b/src/multi-body-problem.cc
@@ -55,11 +55,11 @@
 
 #include "data-structures/enumparser.hh"
 #include "data-structures/enums.hh"
-#include "data-structures/levelcontactnetwork.hh"
+#include "data-structures/contactnetwork.hh"
 #include "data-structures/matrices.hh"
 #include "data-structures/program_state.hh"
 
-#include "factories/stackedblocksfactory.hh"
+#include "factories/threeblocksfactory.hh"
 
 //#include "io/hdf5-levelwriter.hh"
 #include "io/hdf5/restart-io.hh"
@@ -70,6 +70,7 @@
 #include "multi-body-problem-data/grid/mygrids.hh"
 
 #include "spatial-solving/tnnmg/functional.hh"
+#include "spatial-solving/preconditioners/supportpatchfactory.hh"
 #include "spatial-solving/tnnmg/localbisectionsolver.hh"
 #include "spatial-solving/contact/nbodyassembler.hh"
 #include "spatial-solving/solverfactory.hh"
@@ -90,6 +91,34 @@
 
 size_t const dims = MY_DIM;
 
+template <class SupportPatchFactory>
+void testSuite(const SupportPatchFactory& supportPatchFactory, const size_t bodyID, const int patchDepth = 0) {
+/*    const auto& coarseContactNetwork = supportPatchFactory.coarseContactNetwork();
+    const auto& gridView = coarseContactNetwork.body(bodyID)->gridView();
+
+    for (const auto& e : elements(gridView)) {
+
+    }
+
+    using Patch = typename SupportPatchFactory::Patch;
+    Patch patch0, patch1, patch2, patch3;
+
+    // (const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const int patchDepth = 0)
+
+    // interior patch inside of one body
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch0, patchDepth);
+
+    // patch at friction interface with two bodies in contact
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch1 patchDepth);
+
+    // patch at friction interface with two bodies in contact and with dirichlet boundary
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch2, patchDepth);
+
+    // crosspoint patch, where all 3 bodies are in contact
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch3, patchDepth);*/
+}
+
+
 Dune::ParameterTree getParameters(int argc, char *argv[]) {
   Dune::ParameterTree parset;
   Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem.cfg", parset);
@@ -126,41 +155,99 @@ int main(int argc, char *argv[]) {
     // ----------------------
     // set up contact network
     // ----------------------
-    StackedBlocksFactory<Grid, dims> stackedBlocksFactory(parset);
-    using LevelContactNetwork = typename StackedBlocksFactory<Grid, dims>::LevelContactNetwork;
-    stackedBlocksFactory.build();
+    ThreeBlocksFactory<Grid, Vector> threeBlocksFactory(parset);
+    using ContactNetwork = typename ThreeBlocksFactory<Grid, Vector>::ContactNetwork;
+    threeBlocksFactory.build();
 
-    LevelContactNetwork& levelContactNetwork = stackedBlocksFactory.levelContactNetwork();
-    const size_t bodyCount = levelContactNetwork.nBodies();
+    ContactNetwork& contactNetwork = threeBlocksFactory.contactNetwork();
+    const size_t bodyCount = contactNetwork.nBodies();
 
     for (size_t i=0; i<bodyCount; i++) {
-        printDofLocation(levelContactNetwork.leafView(i));
-     /* Vector def(levelContactNetwork.deformedGrids()[i]->size(dims));
+       // printDofLocation(contactNetwork.body(i)->gridView());
+     /* Vector def(contactNetwork.deformedGrids()[i]->size(dims));
       def = 1;
       deformedGridComplex.setDeformation(def, i);*/
 
-        /*auto& levelViews = levelContactNetwork.levelViews(i);
+        /*auto& levelViews = contactNetwork.levelViews(i);
 
         for (size_t j=0; j<levelViews.size(); j++) {
             writeToVTK(*levelViews[j], "", "body_" + std::to_string(i) + "_level_" + std::to_string(j));
         }
 
-        writeToVTK(levelContactNetwork.leafView(i), "", "body_" + std::to_string(i) + "_leaf"); */
+        writeToVTK(contactNetwork.leafView(i), "", "body_" + std::to_string(i) + "_leaf"); */
     }
 
     // ----------------------------
-    // assemble levelContactNetwork
+    // assemble contactNetwork
     // ----------------------------
+    contactNetwork.assemble();
+
+    const auto & coarseContactNetwork = *contactNetwork.level(0);
+    const auto & fineContactNetwork = *contactNetwork.level(1);
+    SupportPatchFactory<typename ContactNetwork::LevelContactNetwork> supportPatchFactory(coarseContactNetwork, fineContactNetwork);
+    size_t bodyID = 0;
+    size_t patchDepth = 0;
+
+    writeToVTK(fineContactNetwork.body(bodyID)->gridView(), "", "body_" + std::to_string(bodyID) + "_fine");
+    writeToVTK(coarseContactNetwork.body(bodyID)->gridView(), "", "body_" + std::to_string(bodyID) + "_coarse");
+
+    using Patch = typename SupportPatchFactory<typename ContactNetwork::LevelContactNetwork>::Patch;
+    Patch patch;
+
+    const auto& gridView = coarseContactNetwork.body(bodyID)->gridView();
+
+    Dune::PQkLocalFiniteElementCache<double, double, dims, 1> cache;
+    Dune::BitSetVector<1> vertexVisited(gridView.size(dims));
+    vertexVisited.unsetAll();
 
-    levelContactNetwork.assemble();
-    //printMortarBasis<Vector>(levelContactNetwork.nBodyAssembler());
+    for (const auto& e: elements(gridView)) {
+        const auto& refElement = Dune::ReferenceElements<double, dims>::general(e.type());
+
+        for (size_t i=0; i<refElement.size(dims); i++) {
+            auto localIdx = cache.get(e.type()).localCoefficients().localKey(i).subEntity();
+            auto globalIdx = gridView.indexSet().subIndex(e, i, dims);
+
+            if (!vertexVisited[globalIdx][0]) {
+                vertexVisited[globalIdx][0] = true;
+                supportPatchFactory.build(bodyID, e, i, patch, patchDepth);
+
+                print(patch, "patch:");
+
+                size_t c = 0;
+                for (size_t j=0; j<bodyCount; j++) {
+                    const auto& gv = fineContactNetwork.body(j)->gridView();
+
+                    ScalarVector patchVec(gv.size(dims));
+                    for (size_t l=0; l<patchVec.size(); l++) {
+                        if (patch[c++][0]) {
+                            patchVec[l][0] = 1;
+                        }
+                    }
+
+                    print(patchVec, "patchVec");
+
+                    // output patch
+                    writeToVTK(gv, patchVec, "", "patch_" + std::to_string(globalIdx) + "_body_" + std::to_string(j));
+                }
+            }
+
+
+        }
+    }
+    return 1;
+
+    //printMortarBasis<Vector>(contactNetwork.nBodyAssembler());
 
     // -----------------
     // init input/output
     // -----------------
-    const auto& leafVertexCounts = levelContactNetwork.leafVertexCounts();
+    std::vector<size_t> nVertices(bodyCount);
+    for (size_t i=0; i<bodyCount; i++) {
+        nVertices[i] = contactNetwork.body(i)->nVertices();
+    }
+
     using MyProgramState = ProgramState<Vector, ScalarVector>;
-    MyProgramState programState(leafVertexCounts);
+    MyProgramState programState(nVertices);
     auto const firstRestart = parset.get<size_t>("io.restarts.first");
     auto const restartSpacing = parset.get<size_t>("io.restarts.spacing");
     auto const writeRestarts = parset.get<bool>("io.restarts.write");
@@ -181,18 +268,18 @@ int main(int argc, char *argv[]) {
 
     auto restartIO = handleRestarts
                          ? std::make_unique<RestartIO<MyProgramState>>(
-                               *restartFile, leafVertexCounts)
+                               *restartFile, nVertices)
                          : nullptr;
 
     if (firstRestart > 0) // automatically adjusts the time and timestep
       restartIO->read(firstRestart, programState);
     else
-     programState.setupInitialConditions(parset, levelContactNetwork);
+     programState.setupInitialConditions(parset, contactNetwork);
 
 
-    auto& nBodyAssembler = levelContactNetwork.nBodyAssembler();
+    auto& nBodyAssembler = contactNetwork.nBodyAssembler();
     for (size_t i=0; i<bodyCount; i++) {
-      levelContactNetwork.body(i)->setDeformation(programState.u[i]);
+      contactNetwork.body(i)->setDeformation(programState.u[i]);
     }
     nBodyAssembler.assembleTransferOperator();
     nBodyAssembler.assembleObstacle();
@@ -200,9 +287,9 @@ int main(int argc, char *argv[]) {
     // ------------------------
     // assemble global friction
     // ------------------------
-    levelContactNetwork.assembleFriction(parset.get<Config::FrictionModel>("boundary.friction.frictionModel"), programState.weightedNormalStress);
+    contactNetwork.assembleFriction(parset.get<Config::FrictionModel>("boundary.friction.frictionModel"), programState.weightedNormalStress);
 
-    auto& globalFriction = levelContactNetwork.globalFriction();
+    auto& globalFriction = contactNetwork.globalFriction();
     globalFriction.updateAlpha(programState.alpha);
 
     using MyVertexBasis = typename Assembler::VertexBasis;
@@ -212,21 +299,21 @@ int main(int argc, char *argv[]) {
     std::vector<const MyCellBasis* > cellBases(bodyCount);
 
     for (size_t i=0; i<bodyCount; i++) {
-      const auto& body = levelContactNetwork.body(i);
+      const auto& body = contactNetwork.body(i);
       vertexBases[i] = &(body->assembler()->vertexBasis);
       cellBases[i] = &(body->assembler()->cellBasis);
 
       auto& vertexCoords = vertexCoordinates[i];
-      vertexCoords.resize(leafVertexCounts[i]);
+      vertexCoords.resize(nVertices[i]);
 
       Dune::MultipleCodimMultipleGeomTypeMapper<
-          DefLeafGridView, Dune::MCMGVertexLayout> const vertexMapper(body->leafView(), Dune::mcmgVertexLayout());
-      for (auto &&v : vertices(body->leafView()))
+          DefLeafGridView, Dune::MCMGVertexLayout> const vertexMapper(body->gridView(), Dune::mcmgVertexLayout());
+      for (auto &&v : vertices(body->gridView()))
         vertexCoords[vertexMapper.index(v)] = geoToPoint(v.geometry());
     }
 
-    //typename LevelContactNetwork::BoundaryPatches frictionBoundaries;
-    //levelContactNetwork.boundaryPatches("friction", frictionBoundaries);
+    //typename contactNetwork::BoundaryPatches frictionBoundaries;
+    //contactNetwork.boundaryPatches("friction", frictionBoundaries);
 
     /*
     auto dataWriter =
@@ -242,7 +329,7 @@ int main(int argc, char *argv[]) {
 
     auto const report = [&](bool initial = false) {
       /*if (writeData) {
-        dataWriter->reportSolution(programState, levelContactNetwork.globalFriction());
+        dataWriter->reportSolution(programState, contactNetwork.globalFriction());
         if (!initial)
           dataWriter->reportIterations(programState, iterationCount);
         dataFile->flush();
@@ -264,7 +351,7 @@ int main(int argc, char *argv[]) {
         std::vector<ScalarVector> stress(bodyCount);
 
         for (size_t i=0; i<bodyCount; i++) {
-          const auto& body = levelContactNetwork.body(i);
+          const auto& body = contactNetwork.body(i);
           body->assembler()->assembleVonMisesStress(body->data()->getYoungModulus(),
                                            body->data()->getPoissonRatio(),
                                            programState.u[i], stress[i]);
@@ -282,7 +369,7 @@ int main(int argc, char *argv[]) {
     // -------------------
 
     BitVector totalDirichletNodes;
-    levelContactNetwork.totalNodes("dirichlet", totalDirichletNodes);
+    contactNetwork.totalNodes("dirichlet", totalDirichletNodes);
 
     /*for (size_t i=0; i<totalDirichletNodes.size(); i++) {
         bool val = false;
@@ -301,16 +388,16 @@ int main(int argc, char *argv[]) {
     using Functional = Functional<Matrix&, Vector&, GlobalFriction<Matrix, Vector>&, Vector&, Vector&, field_type>;
     using NonlinearFactory = SolverFactory<Functional, BitVector>;
 
-    using BoundaryFunctions = typename LevelContactNetwork::BoundaryFunctions;
-    using BoundaryNodes = typename LevelContactNetwork::BoundaryNodes;
+    using BoundaryFunctions = typename ContactNetwork::BoundaryFunctions;
+    using BoundaryNodes = typename ContactNetwork::BoundaryNodes;
     using Updaters = Updaters<RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>,
                                StateUpdater<ScalarVector, Vector>>;
 
     BoundaryFunctions velocityDirichletFunctions;
-    levelContactNetwork.boundaryFunctions("dirichlet", velocityDirichletFunctions);
+    contactNetwork.boundaryFunctions("dirichlet", velocityDirichletFunctions);
 
     BoundaryNodes dirichletNodes;
-    levelContactNetwork.boundaryNodes("dirichlet", dirichletNodes);
+    contactNetwork.boundaryNodes("dirichlet", dirichletNodes);
 
     for (size_t i=0; i<dirichletNodes.size(); i++) {
         for (size_t j=0; j<dirichletNodes[i].size(); j++) {
@@ -319,7 +406,7 @@ int main(int argc, char *argv[]) {
     }
 
     std::vector<const Dune::BitSetVector<1>*> frictionNodes;
-    levelContactNetwork.frictionNodes(frictionNodes);
+    contactNetwork.frictionNodes(frictionNodes);
 
     for (size_t i=0; i<frictionNodes.size(); i++) {
         print(*frictionNodes[i], "frictionNodes_body_" + std::to_string(i));
@@ -330,7 +417,7 @@ int main(int argc, char *argv[]) {
             parset.get<Config::scheme>("timeSteps.scheme"),
             velocityDirichletFunctions,
             dirichletNodes,
-            levelContactNetwork.matrices(),
+            contactNetwork.matrices(),
             programState.u,
             programState.v,
             programState.a),
@@ -338,13 +425,13 @@ int main(int argc, char *argv[]) {
             parset.get<Config::stateModel>("boundary.friction.stateModel"),
             programState.alpha,
             nBodyAssembler.getContactCouplings(),
-            levelContactNetwork.couplings())
+            contactNetwork.couplings())
             );
 
 
     auto const refinementTolerance = parset.get<double>("timeSteps.refinementTolerance");
 
-    const auto& stateEnergyNorms = levelContactNetwork.stateEnergyNorms();
+    const auto& stateEnergyNorms = contactNetwork.stateEnergyNorms();
 
     auto const mustRefine = [&](Updaters &coarseUpdater,
                                 Updaters &fineUpdater) {
@@ -387,10 +474,10 @@ int main(int argc, char *argv[]) {
     std::signal(SIGINT, handleSignal);
     std::signal(SIGTERM, handleSignal);
 
-    typename LevelContactNetwork::ExternalForces externalForces;
-    levelContactNetwork.externalForces(externalForces);
+    typename ContactNetwork::ExternalForces externalForces;
+    contactNetwork.externalForces(externalForces);
 
-    AdaptiveTimeStepper<NonlinearFactory, std::decay_t<decltype(nBodyAssembler)>, Updaters, EnergyNorm<ScalarMatrix, ScalarVector>>
+    AdaptiveTimeStepper<NonlinearFactory, std::decay_t<decltype(nBodyAssembler)>, Updaters, std::decay_t<decltype(stateEnergyNorms)>>
         adaptiveTimeStepper(parset, nBodyAssembler, totalDirichletNodes, globalFriction, frictionNodes, current,
                             programState.relativeTime, programState.relativeTau,
                             externalForces, stateEnergyNorms, mustRefine);
@@ -412,11 +499,7 @@ int main(int argc, char *argv[]) {
       print(programState.a, "current a:");
       print(programState.alpha, "current alpha:");
 
-      for (size_t i=0; i<bodyCount; i++) {
-        levelContactNetwork.body(i)->setDeformation(programState.u[i]);
-      }
-      nBodyAssembler.assembleTransferOperator();
-      nBodyAssembler.assembleObstacle();
+      contactNetwork.setDeformation(programState.u);
 
       report();
 
diff --git a/src/spatial-solving/contact/dualmortarcoupling.hh b/src/spatial-solving/contact/dualmortarcoupling.hh
index 90bc49dc..81c6e628 100644
--- a/src/spatial-solving/contact/dualmortarcoupling.hh
+++ b/src/spatial-solving/contact/dualmortarcoupling.hh
@@ -93,12 +93,12 @@ class DualMortarCoupling {
     }
 
     /** \brief Setup leaf nonmortar and mortar patches. */
-    /*virtual void setupContactPatch(const LevelBoundaryPatch0& coarseNonmortar,
+    virtual void setupContactPatch(const LevelBoundaryPatch0& coarseNonmortar,
                            const LevelBoundaryPatch1& coarseMortar) {
 
         BoundaryPatchProlongator<GridType0>::prolong(coarseNonmortar,nonmortarBoundary_);
         BoundaryPatchProlongator<GridType1>::prolong(coarseMortar,mortarBoundary_);
-    }*/
+    }
 
     /** \brief Return the nonmortar boundary. */
     const BoundaryPatch0& nonmortarBoundary() const {
diff --git a/src/spatial-solving/fixedpointiterator.cc b/src/spatial-solving/fixedpointiterator.cc
index f600e878..2c741b77 100644
--- a/src/spatial-solving/fixedpointiterator.cc
+++ b/src/spatial-solving/fixedpointiterator.cc
@@ -37,14 +37,14 @@ void FixedPointIterationCounter::operator+=(
   multigridIterations += other.multigridIterations;
 }
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
-FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorm>::FixedPointIterator(
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::FixedPointIterator(
     Dune::ParameterTree const &parset,
     NBodyAssembler& nBodyAssembler,
     const IgnoreVector& ignoreNodes,
     GlobalFriction& globalFriction,
     const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
-    const std::vector<const ErrorNorm* >& errorNorms)
+    const ErrorNorms& errorNorms)
     : parset_(parset),
       nBodyAssembler_(nBodyAssembler),
       ignoreNodes_(ignoreNodes),
@@ -58,9 +58,9 @@ FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorm>::FixedPointIter
       verbosity_(parset.get<Solver::VerbosityMode>("v.solver.verbosity")),
       errorNorms_(errorNorms) {}
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
 FixedPointIterationCounter
-FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorm>::run(
+FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run(
     Updaters updaters, const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs,
     std::vector<Vector>& velocityIterates) {
 
@@ -237,8 +237,8 @@ std::ostream &operator<<(std::ostream &stream,
                 << ")";
 }
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
-void FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorm>::relativeVelocities(
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+void FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::relativeVelocities(
     const Vector& v,
     std::vector<Vector>& v_rel) const {
 
diff --git a/src/spatial-solving/fixedpointiterator.hh b/src/spatial-solving/fixedpointiterator.hh
index fa93c087..867e8058 100644
--- a/src/spatial-solving/fixedpointiterator.hh
+++ b/src/spatial-solving/fixedpointiterator.hh
@@ -23,13 +23,13 @@ struct FixedPointIterationCounter {
 std::ostream &operator<<(std::ostream &stream,
                          FixedPointIterationCounter const &fpic);
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
 class FixedPointIterator {
   using Functional = typename Factory::Functional;
   using ScalarVector = typename Updaters::StateUpdater::ScalarVector;
   using Vector = typename Factory::Vector;
   using Matrix = typename Factory::Matrix;
-  using Nonlinearity = typename Factory::Functional::Nonlinearity;
+  using Nonlinearity = typename Factory::Functional::Nonlinearity; 
 
   const static int dims = Vector::block_type::dimension;
 
@@ -50,7 +50,7 @@ class FixedPointIterator {
                      const IgnoreVector& ignoreNodes,
                      GlobalFriction& globalFriction,
                      const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
-                     const std::vector<const ErrorNorm* >& errorNorms);
+                     const ErrorNorms& errorNorms);
 
   FixedPointIterationCounter run(Updaters updaters,
                                  const std::vector<Matrix>& velocityMatrices,
@@ -72,6 +72,6 @@ class FixedPointIterator {
   size_t velocityMaxIterations_;
   double velocityTolerance_;
   Solver::VerbosityMode verbosity_;
-  const std::vector<const ErrorNorm* >& errorNorms_;
+  const ErrorNorms& errorNorms_;
 };
 #endif
diff --git a/src/spatial-solving/fixedpointiterator_tmpl.cc b/src/spatial-solving/fixedpointiterator_tmpl.cc
index a91a7c6a..33acfce6 100644
--- a/src/spatial-solving/fixedpointiterator_tmpl.cc
+++ b/src/spatial-solving/fixedpointiterator_tmpl.cc
@@ -8,21 +8,21 @@
 #include <dune/solvers/norms/energynorm.hh>
 
 #include "../spatial-solving/solverfactory_tmpl.cc"
-#include "../data-structures/levelcontactnetwork_tmpl.cc"
+#include "../data-structures/contactnetwork_tmpl.cc"
 
 #include "../time-stepping/rate/rateupdater.hh"
 #include "../time-stepping/state/stateupdater.hh"
 #include "../time-stepping/updaters.hh"
 
-using NBodyAssembler = typename MyLevelContactNetwork::NBodyAssembler;
-using BoundaryNodes = typename MyLevelContactNetwork::BoundaryNodes;
-using BoundaryFunctions = typename MyLevelContactNetwork::BoundaryFunctions;
+using NBodyAssembler = typename MyContactNetwork::NBodyAssembler;
+using BoundaryNodes = typename MyContactNetwork::BoundaryNodes;
+using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions;
 
 using MyStateUpdater = StateUpdater<ScalarVector, Vector>;
 using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>;
 using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>;
 
-using ErrorNorm = EnergyNorm<ScalarMatrix, ScalarVector>;
+using ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
 
 
-template class FixedPointIterator<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorm>;
+template class FixedPointIterator<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>;
diff --git a/src/spatial-solving/preconditioners/supportpatchfactory.hh b/src/spatial-solving/preconditioners/supportpatchfactory.hh
index 76d64e37..75db9ad2 100644
--- a/src/spatial-solving/preconditioners/supportpatchfactory.hh
+++ b/src/spatial-solving/preconditioners/supportpatchfactory.hh
@@ -7,6 +7,7 @@
 
 #include <dune/common/bitsetvector.hh>
 #include <dune/common/fvector.hh>
+#include <dune/common/hybridutilities.hh>
 
 #include <dune/fufem/referenceelementhelper.hh>
 #include <dune/grid/common/mcmgmapper.hh>
@@ -19,12 +20,13 @@
 template <class LevelContactNetwork>
 class NetworkIndexMapper {
 private:
+    static const int dim = LevelContactNetwork::dim; //TODO
+    using ctype = typename LevelContactNetwork::GridView::ctype;
+
     using FiniteElementCache = Dune::PQkLocalFiniteElementCache<ctype, ctype, dim, 1>; // P1 finite element cache
-    using GridType = typename LevelContactNetwork::DeformedGridType;
-    using Element = typename GridType::template Codim<0>::Entity;
+    using Element = typename LevelContactNetwork::GridView::template Codim<0>::Entity;
 
-    static const int dim = LevelContactNetwork::dimension; //TODO
-    static const FiniteElementCache cache_;
+    const FiniteElementCache cache_;
 
     const LevelContactNetwork& levelContactNetwork_;
     const size_t nBodies_;
@@ -62,7 +64,7 @@ class NetworkIndexMapper {
     size_t vertexIndex(const size_t bodyID, const Element& elem, const size_t localVertex) const {
         const auto& gridView = levelContactNetwork_.body(bodyID)->gridView();
 
-        auto localIdx = cache_.get(elem.type()).localCoefficients().localKey(localVertex).subEntity();
+        auto localIdx = cache().get(elem.type()).localCoefficients().localKey(localVertex).subEntity();
         return vertexOffSet_[bodyID] + gridView.indexSet().subIndex(elem, localIdx, dim);
     }
 
@@ -82,11 +84,13 @@ class NetworkIndexMapper {
         return elementOffSet_[bodyID] + gridView.indexSet().index(elem);
     }
 
-    static const auto& cache() const {
+    const auto& cache() const {
         return cache_;
     }
 };
 
+
+
 /**
  *  constructs BitSetVector whose entries are
  *      true,   if vertex is outside of patch or part of patch boundary
@@ -99,6 +103,11 @@ class SupportPatchFactory
     using Patch = Dune::BitSetVector<1>;
 
 private:
+    static const int dim = LevelContactNetwork::dim; //TODO
+    using ctype = typename LevelContactNetwork::ctype;
+
+    using Element = typename LevelContactNetwork::GridView::template Codim<0>::Entity;
+
     struct BodyElement {
         size_t bodyID;
         Element element;
@@ -111,40 +120,33 @@ class SupportPatchFactory
 
     struct RemoteIntersection {
         size_t bodyID; // used to store bodyID of outside elem
-        GridGlue& glue;
+        size_t contactCouplingID;
         size_t intersectionID;
 
         bool flip = false;
 
-        void set(const size_t _bodyID, const GridGlue& _glue, const size_t _intersectionID, bool _flip = false) {
+        void set(const size_t _bodyID, const size_t _contactCouplingID, const size_t _intersectionID, const bool _flip = false) {
             bodyID = _bodyID;
-            glue = _glue;
+            contactCouplingID = _contactCouplingID;
             intersectionID = _intersectionID;
             flip = _flip;
         }
 
-        auto& get() {
-            return (flip) ? glue.getIntersection(intersectionID).flip() : glue.getIntersection(intersectionID);
+        template <class GridGlue>
+        const auto& get(const GridGlue& glue) const {
+            return glue.getIntersection(intersectionID);
         }
     };
 
-    static const int dim = LevelContactNetwork::dimension; //TODO
-    using ctype = typename LevelContactNetwork::ctype;
-
-    //using Vertex = typename GridType::template Codim<dim>::Entity;
-
-    using Element = typename LevelContactNetwork::DeformedGridType::template Codim<0>::Entity;
-    using BodyElement = BodyElement<Element>;
-
     using NetworkIndexMapper = NetworkIndexMapper<LevelContactNetwork>;
 
-    using GridGlue = ;
-
     const size_t nBodies_;
 
     const LevelContactNetwork& coarseContactNetwork_;
     const LevelContactNetwork& fineContactNetwork_;
 
+    size_t nVertices_ = 0;
+
     std::map<size_t, std::vector<RemoteIntersection>> coarseIntersectionMapper_; // map faceID to neighbor elements
     std::map<size_t, std::vector<RemoteIntersection>> fineIntersectionMapper_; // map faceID to neighbor elements
     std::map<size_t, std::vector<size_t>> neighborFaceDofs_; // map faceID to neighbor element dofs
@@ -156,7 +158,7 @@ class SupportPatchFactory
 
 public:
     SupportPatchFactory(const LevelContactNetwork& coarseContactNetwork, const LevelContactNetwork& fineContactNetwork) :
-        nBodies_(coarseContactNetwork_.nBodies()),
+        nBodies_(coarseContactNetwork.nBodies()),
         coarseContactNetwork_(coarseContactNetwork),
         fineContactNetwork_(fineContactNetwork),
         coarseIndices_(coarseContactNetwork_),
@@ -164,14 +166,17 @@ class SupportPatchFactory
 
         assert(nBodies_ == fineContactNetwork_.nBodies());
 
+        for (size_t i=0; i<nBodies_; i++) {
+            nVertices_ += fineContactNetwork_.body(i)->nVertices();
+        }
+
         setup(coarseContactNetwork_, coarseIndices_, coarseIntersectionMapper_);
         setup(fineContactNetwork_, fineIndices_, fineIntersectionMapper_);
 
         // setup neighborFaceDofs_
-        const auto& contactCouplings = coarseContactNetwork_.nBodyAssembler().getContactCouplings();
-        for (size_t i=0; i<contactCouplings.size(); i++) {
-                const auto& coupling = nBodyAssembler.getCoupling(i);
-                const auto& glue = *contactCouplings[i].getGlue();
+        for (size_t i=0; i<coarseContactNetwork_.nCouplings(); i++) {
+                const auto& coupling = *coarseContactNetwork_.coupling(i);
+                const auto& glue = *coarseContactNetwork_.glue(i);
 
                 const size_t nmBody = coupling.gridIdx_[0];
                 const size_t mBody = coupling.gridIdx_[1];
@@ -180,7 +185,7 @@ class SupportPatchFactory
                     size_t nmFaceIdx = coarseIndices_.faceIndex(nmBody, rIs.inside(), rIs.indexInInside());
                     size_t mFaceIdx = coarseIndices_.faceIndex(mBody, rIs.outside(), rIs.indexInOutside());
 
-                    std::array<std::set<size_t>, 2> dofs;
+                    std::vector<std::set<size_t>> dofs;
                     remoteIntersectionDofs(coarseIndices_, rIs, nmBody, mBody, dofs);
                     neighborFaceDofs_[nmFaceIdx].insert(neighborFaceDofs_[nmFaceIdx].end(), dofs[1].begin(), dofs[1].end());
                     neighborFaceDofs_[mFaceIdx].insert(neighborFaceDofs_[mFaceIdx].end(), dofs[0].begin(), dofs[0].end());
@@ -207,10 +212,16 @@ class SupportPatchFactory
         */
     }
 
-    void build(const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const int patchDepth = 0) {
-        BodyElement seedElement(bodyID, coarseElement);
+    void build(const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const size_t patchDepth = 0) {
+        std::cout << "Building SupportPatch... ";
+
+        patchDofs.resize(nVertices_);
+        patchDofs.setAll();
+
+        BodyElement seedElement;
+        seedElement.set(bodyID, coarseElement);
 
-        auto isPatchIntersection = [](auto& is, const size_t bodyID, const std::set<size_t>& patchVertices, std::set<size_t>& newPatchVertices) {
+        auto isPatchIntersection = [this](auto& is, const size_t bodyID, const std::set<size_t>& patchVertices, std::set<size_t>& newPatchVertices) {
             std::set<size_t> dofs;
             intersectionDofs(coarseIndices_, is, bodyID, dofs);
 
@@ -255,10 +266,11 @@ class SupportPatchFactory
                 const auto& elem = patchSeed.element;
                 const auto& gridView = coarseContactNetwork_.body(bodyIdx)->gridView();
 
-                for (auto& it : intersections(gridView, elem)) {
+                for (const auto& it : intersections(gridView, elem)) {
                     if (isPatchIntersection(it, bodyIdx, patchVertices, newPatchVertices)) {
                         if (it.neighbor()) {
-                            BodyElement neighbor(bodyIdx, it.outside());
+                            BodyElement neighbor;
+                            neighbor.set(bodyIdx, it.outside());
 
                             if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                 continue;
@@ -272,12 +284,13 @@ class SupportPatchFactory
                                 const auto& intersections = coarseIntersectionMapper_[faceIdx];
                                 for (size_t i=0; i<intersections.size(); i++) {
                                     BodyElement neighbor;
-                                    neighbor.set(intersections[i].bodyID, intersections[i].get().outside());
+                                    const auto& glue = *coarseContactNetwork_.glue(intersections[i].contactCouplingID);
+                                    neighbor.set(intersections[i].bodyID, intersections[i].get(glue).outside());
 
                                     if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                         continue;
 
-                                    patchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
+                                    patchVertices.insert(neighborFaceDofs_[faceIdx].begin(), neighborFaceDofs_[faceIdx].end());
                                     patchElements.emplace_back(neighbor);
                                     patchSeeds.push(neighbor);
                                 }
@@ -285,7 +298,8 @@ class SupportPatchFactory
                         }
                     } else {
                         if (it.neighbor()) {
-                            BodyElement neighbor(bodyIdx, it.outside());
+                            BodyElement neighbor;
+                            neighbor.set(bodyIdx, it.outside());
 
                             if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                 continue;
@@ -298,12 +312,13 @@ class SupportPatchFactory
                                 const auto& intersections = coarseIntersectionMapper_[faceIdx];
                                 for (size_t i=0; i<intersections.size(); i++) {
                                     BodyElement neighbor;
-                                    neighbor.set(intersections[i].bodyID, intersections[i].get().outside());
+                                    const auto& glue = *coarseContactNetwork_.glue(intersections[i].contactCouplingID);
+                                    neighbor.set(intersections[i].bodyID, intersections[i].get(glue).outside());
 
                                     if (visitedElements.count(coarseIndices_.elementIndex(neighbor.bodyID, neighbor.element)))
                                         continue;
 
-                                    newPatchVertices.insert(neighborElementDofs_[faceIdx].begin(), neighborElementDofs_[faceIdx].end());
+                                    newPatchVertices.insert(neighborFaceDofs_[faceIdx].begin(), neighborFaceDofs_[faceIdx].end());
                                     nextSeeds.emplace_back(neighbor);
                                 }
                             }
@@ -319,13 +334,13 @@ class SupportPatchFactory
         }
 
         // construct fine patch
-        using HierarchicLevelIteratorType = HierarchicLevelIterator<typename LevelContactNetwork::DeformedGridType>;
+        using HierarchicLevelIteratorType = HierarchicLevelIterator<typename LevelContactNetwork::GridType>;
         std::set<size_t> patchBoundary;
         for (size_t i=0; i<patchElements.size(); ++i) {
             const auto& coarseElem = patchElements[i];
 
             const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID)->gridView().grid();
-            const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID)->gridView().level();
+            const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID)->level();
 
             // add fine patch elements
             HierarchicLevelIteratorType endHierIt(grid, coarseElem.element, HierarchicLevelIteratorType::PositionFlag::end, fineLevel);
@@ -335,16 +350,19 @@ class SupportPatchFactory
                 addLocalDofs(coarseElem, fineElem, visitedElements, patchBoundary, patchDofs);
             }
         }
+
+        std::cout << "Success!" << std::endl;
+    }
+
+    const auto& coarseContactNetwork() {
+        return coarseContactNetwork_;
     }
 
 private:
     void setup(const LevelContactNetwork& levelContactNetwork, const NetworkIndexMapper& indices, std::map<size_t, std::vector<RemoteIntersection>>& faceToRIntersections) {
-        const auto& nBodyAssembler = levelContactNetwork.nBodyAssembler();
-        const auto& contactCouplings = nBodyAssembler.getContactCouplings();
-
-        for (size_t i=0; i<contactCouplings.size(); i++) {
-            const auto& coupling = nBodyAssembler.getCoupling(i);
-            const auto& glue = *contactCouplings[i].getGlue();
+        for (size_t i=0; i<levelContactNetwork.nCouplings(); i++) {
+            const auto& coupling = *levelContactNetwork.coupling(i);
+            const auto& glue = *levelContactNetwork.glue(i);
 
             const size_t nmBody = coupling.gridIdx_[0];
             const size_t mBody = coupling.gridIdx_[1];
@@ -354,10 +372,12 @@ class SupportPatchFactory
                 size_t nmFaceIdx = indices.faceIndex(nmBody, rIs.inside(), rIs.indexInInside());
                 size_t mFaceIdx = indices.faceIndex(mBody, rIs.outside(), rIs.indexInOutside());
 
-                RemoteIntersection nmIntersection(mBody, glue, rIsID, false);
+                RemoteIntersection nmIntersection;
+                nmIntersection.set(mBody, i, rIsID, false);
                 faceToRIntersections[nmFaceIdx].emplace_back(nmIntersection);
 
-                RemoteIntersection mIntersection(nmBody, glue, rIsID, true);
+                RemoteIntersection mIntersection;
+                mIntersection.set(nmBody, i, rIsID, true);
                 faceToRIntersections[mFaceIdx].emplace_back(mIntersection);
 
                 rIsID++;
@@ -372,7 +392,6 @@ class SupportPatchFactory
       
     void addLocalDofs(const BodyElement& coarseElem, const Element& fineElem, const std::set<size_t>& coarsePatch, std::set<size_t>& patchBoundary, Patch& patchDofs) {
 	    // insert local dofs
-        const auto& lfe = cache_.get(fineElem.type());
         const auto& gridView = fineContactNetwork_.body(coarseElem.bodyID)->gridView();
         const auto& indexSet = gridView.indexSet();
 	    
@@ -394,28 +413,35 @@ class SupportPatchFactory
                     addToPatch(isDofs, patchBoundary, patchDofs);
                 }
             } else {
-                size_t faceIdx = fineIndices_.faceIndex(bodyID, is);
+             /*   size_t faceIdx = fineIndices_.faceIndex(bodyID, is);
                 if (fineIntersectionMapper_.count(faceIdx)) {
-                    const auto& intersections = coarseIntersectionMapper_[faceIdx];
+                    const auto& intersections = fineIntersectionMapper_[faceIdx];
 
                     for (size_t i=0; i<intersections.size(); i++) {
                         const auto& intersection = intersections[i];
-                        const auto& rIs = intersection.get();
+                        const auto& glue = *fineContactNetwork_.glue(intersection.contactCouplingID);
+                        const auto& rIs = intersection.get(glue);
                         const size_t outsideID = intersection.bodyID;
 
-                        std::set<size_t> rIsDofs;
+                        std::vector<std::set<size_t>> rIsDofs;
                         remoteIntersectionDofs(fineIndices_, rIs, bodyID, outsideID, rIsDofs);
 
                         if (rIs.neighbor()) {
-                            auto outsideFather = coarseFather(rIs.outside(), fineContactNetwork_.body(outsideID)->gridView().level());
-
+                            Element outsideFather;
+                            if (intersection.flip)
+                                outsideFather = coarseFather(rIs.inside(), fineContactNetwork_.body(outsideID)->level());
+                            else
+                                outsideFather = coarseFather(rIs.outside(), fineContactNetwork_.body(outsideID)->level());
+
+                            std::set<size_t> totalRIsDofs(rIsDofs[0]);
+                            totalRIsDofs.insert(rIsDofs[1].begin(), rIsDofs[1].end());
                             if (!coarsePatch.count(coarseIndices_.elementIndex(outsideID, outsideFather))) {
-                                addToPatchBoundary(rIsDofs, patchBoundary, patchDofs);
+                                addToPatchBoundary(totalRIsDofs, patchBoundary, patchDofs);
                             } else {
-                                addToPatch(rIsDofs, patchBoundary, patchDofs);
+                                addToPatch(totalRIsDofs, patchBoundary, patchDofs);
                             }
                         } else {
-                            addToPatchBoundary(rIsDofs, patchBoundary, patchDofs);
+                            addToPatchBoundary(rIsDofs[0], patchBoundary, patchDofs);
                         }
                     }
                 } else {
@@ -423,12 +449,12 @@ class SupportPatchFactory
                     intersectionDofs(fineIndices_, is, bodyID, isDofs);
 
                     addToPatchBoundary(isDofs, patchBoundary, patchDofs);
-                }
+                } */
             }
         }
 	}
 
-    auto&& coarseFather(const Element& fineElem, const size_t coarseLevel) const {
+    auto coarseFather(const Element& fineElem, const size_t coarseLevel) const {
         Element coarseElem = fineElem;
         while (coarseElem.level() > coarseLevel) {
             coarseElem = coarseElem.father();
@@ -443,7 +469,6 @@ class SupportPatchFactory
         }
     }
 
-    template <class Intersection>
     void addToPatch(const std::set<size_t>& dofs, const std::set<size_t>& patchBoundary, Patch& patchDofs) {
         for (auto& dof : dofs) {
             if (!patchBoundary.count(dof)) {
@@ -453,8 +478,13 @@ class SupportPatchFactory
     }
 
     template <class RIntersection>
-    void remoteIntersectionDofs(const NetworkIndexMapper& indices, const RIntersection& is, const size_t insideID, const size_t outsideID, std::array<std::set<size_t>, 2>& dofs) {
-        dofs.clear();
+    void remoteIntersectionDofs(const NetworkIndexMapper& indices, const RIntersection& is, const size_t insideID, const size_t outsideID, std::vector<std::set<size_t>>& dofs) {
+        dofs.resize(2);
+        dofs[0].clear();
+        dofs[1].clear();
+
+        const auto& isGeo = is.geometry();
+        const auto& isRefElement = Dune::ReferenceElements<ctype, dim-1>::general(is.type());
 
         const auto& inside = is.inside();
         const auto& insideGeo = inside.geometry();
@@ -468,18 +498,17 @@ class SupportPatchFactory
             }
         }
 
-        const auto& isGeo = is.geometry();
-        const auto& isRefElement = Dune::ReferenceElements<ctype, dim-1>::general(is.type());
-
-        const auto& outside = is.outside();
-        const auto& outsideGeo = outside.geometry();
-        const auto& outsideRefElement = Dune::ReferenceElements<ctype, dim>::general(outside.type());
+        if (is.neighbor()) {
+            const auto& outside = is.outside();
+            const auto& outsideGeo = outside.geometry();
+            const auto& outsideRefElement = Dune::ReferenceElements<ctype, dim>::general(outside.type());
 
-        for (int i=0; i<outsideRefElement.size(dim); i++) {
-            const auto& localCorner = isGeo.local(outsideGeo.corner(i));
+            for (int i=0; i<outsideRefElement.size(dim); i++) {
+                const auto& localCorner = isGeo.local(outsideGeo.corner(i));
 
-            if (isRefElement.checkInside(localCorner)) {
-                dofs[1].insert(indices.vertexIndex(outsideID, outside, i));
+                if (isRefElement.checkInside(localCorner)) {
+                    dofs[1].insert(indices.vertexIndex(outsideID, outside, i));
+                }
             }
         }
     }
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 8ca00f64..b2004776 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,3 +1,4 @@
 dune_add_test(SOURCES globalfrictioncontainertest.cc)
 dune_add_test(SOURCES gridgluefrictiontest.cc)
 dune_add_test(SOURCES nodalweightstest.cc)
+dune_add_test(SOURCES supportpatchfactorytest.cc)
diff --git a/src/tests/supportpatchfactorytest.cc b/src/tests/supportpatchfactorytest.cc
new file mode 100644
index 00000000..5d97ee91
--- /dev/null
+++ b/src/tests/supportpatchfactorytest.cc
@@ -0,0 +1,144 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define MY_DIM 2
+
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/parametertree.hh>
+#include <dune/common/parametertreeparser.hh>
+
+#include <dune/fufem/formatstring.hh>
+
+#include "../assemblers.hh"
+#include "../gridselector.hh"
+#include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
+
+#include "../factories/threeblocksfactory.cc"
+
+#include "../spatial-solving/preconditioners/supportpatchfactory.hh"
+#include "../utils/debugutils.hh"
+
+
+
+//#include <dune/tectonic/transformedglobalratestatefriction.hh>
+
+#include "common.hh"
+
+const int dim = MY_DIM;
+const int n = 5;
+const bool simplexGrid = true;
+
+const std::string path = "";
+const std::string outputFile = "supportpatchfactorytest.log";
+
+Dune::ParameterTree getParameters(int argc, char *argv[]) {
+  Dune::ParameterTree parset;
+  Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem.cfg", parset);
+  Dune::ParameterTreeParser::readINITree(
+      Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem-%dD.cfg", dim), parset);
+  Dune::ParameterTreeParser::readOptions(argc, argv, parset);
+  return parset;
+}
+
+template <class SupportPatchFactory>
+void testSuite(const SupportPatchFactory& supportPatchFactory, const size_t bodyID, const int patchDepth = 0) {
+/*    const auto& coarseContactNetwork = supportPatchFactory.coarseContactNetwork();
+    const auto& gridView = coarseContactNetwork.body(bodyID)->gridView();
+
+    for (const auto& e : elements(gridView)) {
+
+    }
+
+    using Patch = typename SupportPatchFactory::Patch;
+    Patch patch0, patch1, patch2, patch3;
+
+    // (const size_t bodyID, const Element& coarseElement, const size_t localVertex, Patch& patchDofs, const int patchDepth = 0)
+
+    // interior patch inside of one body
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch0, patchDepth);
+
+    // patch at friction interface with two bodies in contact
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch1 patchDepth);
+
+    // patch at friction interface with two bodies in contact and with dirichlet boundary
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch2, patchDepth);
+
+    // crosspoint patch, where all 3 bodies are in contact
+    supportPatchFactory.build(0, const Element& coarseElement, const size_t localVertex, patch3, patchDepth);*/
+}
+
+int main(int argc, char *argv[]) { try {
+    Dune::MPIHelper::instance(argc, argv);
+
+    std::ofstream out(path + outputFile);
+    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buffer
+    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to outputFile
+
+    std::cout << "-------------------------------" << std::endl;
+    std::cout << "-- SupportPatchFactory Test: --" << std::endl;
+    std::cout << "-------------------------------" << std::endl << std::endl;
+
+    const auto parset = getParameters(argc, argv);
+
+    // set up contact network
+    ThreeBlocksFactory<Grid, Vector> threeBlocksFactory(parset);
+    //using ContactNetwork = typename ThreeBlocksFactory<Grid, Vector>::ContactNetwork;
+    //threeBlocksFactory.build();
+
+    //ContactNetwork& contactNetwork = threeBlocksFactory.contactNetwork();
+   // threeBlocksFactory.build();
+
+   // auto& contactNetwork = threeBlocksFactory.contactNetwork();
+    //const size_t bodyCount = contactNetwork.nBodies();
+
+    //for (size_t i=0; i<bodyCount; i++) {
+        //printDofLocation(levelContactNetwork.leafView(i));
+
+        /*auto& levelViews = levelContactNetwork.levelViews(i);
+
+        for (size_t j=0; j<levelViews.size(); j++) {
+            writeToVTK(*levelViews[j], "", "body_" + std::to_string(i) + "_level_" + std::to_string(j));
+        }
+
+        writeToVTK(levelContactNetwork.leafView(i), "", "body_" + std::to_string(i) + "_leaf"); */
+    //}
+
+    // assemble levelContactNetwork
+    //contactNetwork.assemble();
+
+  /*  const auto& coarseContactNetwork = contactNetwork.level(0);
+    const auto& fineContactNetwork = contactNetwork.level(1);
+
+    SupportPatchFactory<decltype(coarseContactNetwork)> supportPatchFactory(coarseContactNetwork, fineContactNetwork);
+
+
+    // set levelContactNetwork
+    LevelContactNetwork levelContactNetwork;
+    NBodyAssembler nBodyAssembler(grids.size(), 1);
+
+    std::vector<const GridType*> grids_ptr(grids.size());
+    for (size_t i=0; i<grids_ptr.size(); i++) {
+        grids_ptr[i] = grids[i].get();
+    }
+
+    nBodyAssembler.setGrids(grids_ptr);
+    nBodyAssembler.setCoupling(coupling, 0);
+
+    nBodyAssembler.assembleTransferOperator();
+    nBodyAssembler.assembleObstacle();*/
+
+    bool passed = true;
+
+    std::cout << "Overall, the test " << (passed ? "was successful!" : "failed!") << std::endl;
+
+    std::cout.rdbuf(coutbuf); //reset to standard output again
+    return passed ? 0 : 1;
+
+} catch (Dune::Exception &e) {
+    Dune::derr << "Dune reported error: " << e << std::endl;
+} catch (std::exception &e) {
+    std::cerr << "Standard exception: " << e.what() << std::endl;
+} // end try
+} // end main
diff --git a/src/time-stepping/adaptivetimestepper.cc b/src/time-stepping/adaptivetimestepper.cc
index 74396864..e2608f9b 100644
--- a/src/time-stepping/adaptivetimestepper.cc
+++ b/src/time-stepping/adaptivetimestepper.cc
@@ -17,8 +17,8 @@ void IterationRegister::reset() {
   finalCount = FixedPointIterationCounter();
 }
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
-AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::AdaptiveTimeStepper(
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::AdaptiveTimeStepper(
         Dune::ParameterTree const &parset,
         NBodyAssembler& nBodyAssembler,
         const IgnoreVector& ignoreNodes,
@@ -28,7 +28,7 @@ AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::AdaptiveTimeS
         double relativeTime,
         double relativeTau,
         ExternalForces& externalForces,
-        const std::vector<const ErrorNorm* >& errorNorms,
+        const ErrorNorms& errorNorms,
         std::function<bool(Updaters &, Updaters &)> mustRefine)
     : relativeTime_(relativeTime),
       relativeTau_(relativeTau),
@@ -44,13 +44,13 @@ AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::AdaptiveTimeS
       mustRefine_(mustRefine),
       errorNorms_(errorNorms) {}
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
-bool AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::reachedEnd() {
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+bool AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::reachedEnd() {
   return relativeTime_ >= 1.0;
 }
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
-IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::advance() {
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::advance() {
   /*
     |     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
@@ -121,9 +121,9 @@ IterationRegister AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNo
   return iterationRegister_;
 }
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
-typename AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::UpdatersWithCount
-AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::step(
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+typename AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::UpdatersWithCount
+AdaptiveTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::step(
     Updaters const &oldUpdaters, double rTime, double rTau) {
   UpdatersWithCount newUpdatersAndCount = {oldUpdaters.clone(), {}};
   newUpdatersAndCount.count =
diff --git a/src/time-stepping/adaptivetimestepper.hh b/src/time-stepping/adaptivetimestepper.hh
index f1f9b07c..af9fb0b1 100644
--- a/src/time-stepping/adaptivetimestepper.hh
+++ b/src/time-stepping/adaptivetimestepper.hh
@@ -15,7 +15,7 @@ struct IterationRegister {
   FixedPointIterationCounter finalCount;
 };
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
 class AdaptiveTimeStepper {
   struct UpdatersWithCount {
     Updaters updaters;
@@ -27,7 +27,7 @@ class AdaptiveTimeStepper {
   //using ConvexProblem = typename Factory::ConvexProblem;
   //using Nonlinearity = typename Factory::Nonlinearity;
 
-  using MyCoupledTimeStepper = CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>;
+  using MyCoupledTimeStepper = CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>;
 
   using GlobalFriction = typename MyCoupledTimeStepper::GlobalFriction;
   using BitVector = typename MyCoupledTimeStepper::BitVector;
@@ -44,7 +44,7 @@ class AdaptiveTimeStepper {
                       double relativeTime,
                       double relativeTau,
                       ExternalForces& externalForces,
-                      const std::vector<const ErrorNorm* >& errorNorms,
+                      const ErrorNorms& errorNorms,
                       std::function<bool(Updaters &, Updaters &)> mustRefine);
 
   bool reachedEnd();
@@ -69,7 +69,7 @@ class AdaptiveTimeStepper {
   UpdatersWithCount R1_;
   ExternalForces& externalForces_;
   std::function<bool(Updaters &, Updaters &)> mustRefine_;
-  const std::vector<const ErrorNorm* >& errorNorms_;
+  const ErrorNorms& errorNorms_;
 
   IterationRegister iterationRegister_;
 };
diff --git a/src/time-stepping/adaptivetimestepper_tmpl.cc b/src/time-stepping/adaptivetimestepper_tmpl.cc
index 7908b085..bda3c4c7 100644
--- a/src/time-stepping/adaptivetimestepper_tmpl.cc
+++ b/src/time-stepping/adaptivetimestepper_tmpl.cc
@@ -8,22 +8,22 @@
 #include <dune/solvers/norms/energynorm.hh>
 
 #include "../spatial-solving/solverfactory_tmpl.cc"
-#include "../data-structures/levelcontactnetwork_tmpl.cc"
+#include "../data-structures/contactnetwork_tmpl.cc"
 
 #include "rate/rateupdater.hh"
 #include "state/stateupdater.hh"
 #include "updaters.hh"
 
-using NBodyAssembler = typename MyLevelContactNetwork::NBodyAssembler;
-using BoundaryNodes = typename MyLevelContactNetwork::BoundaryNodes;
-using BoundaryFunctions = typename MyLevelContactNetwork::BoundaryFunctions;
+using NBodyAssembler = typename MyContactNetwork::NBodyAssembler;
+using BoundaryNodes = typename MyContactNetwork::BoundaryNodes;
+using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions;
 
 using MyStateUpdater = StateUpdater<ScalarVector, Vector>;
 using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>;
 using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>;
 
-using ErrorNorm = EnergyNorm<ScalarMatrix, ScalarVector>;
+using ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
 
-using MyAdaptiveTimeStepper = AdaptiveTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorm>;
+using MyAdaptiveTimeStepper = AdaptiveTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>;
 
-template class AdaptiveTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorm>;
+template class AdaptiveTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>;
diff --git a/src/time-stepping/coupledtimestepper.cc b/src/time-stepping/coupledtimestepper.cc
index c5fbb89e..d3b9b1e2 100644
--- a/src/time-stepping/coupledtimestepper.cc
+++ b/src/time-stepping/coupledtimestepper.cc
@@ -4,15 +4,15 @@
 
 #include "coupledtimestepper.hh"
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
-CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::CoupledTimeStepper(
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::CoupledTimeStepper(
     double finalTime, Dune::ParameterTree const &parset,
     NBodyAssembler& nBodyAssembler,
     const IgnoreVector& ignoreNodes,
     GlobalFriction& globalFriction,
     const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
     Updaters updaters,
-    const std::vector<const ErrorNorm* >& errorNorms,
+    const ErrorNorms& errorNorms,
     ExternalForces& externalForces)
     : finalTime_(finalTime),
       parset_(parset),
@@ -24,9 +24,9 @@ CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::CoupledTimeSte
       externalForces_(externalForces),
       errorNorms_(errorNorms) {}
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
 FixedPointIterationCounter
-CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::step(double relativeTime,
+CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::step(double relativeTime,
                                                        double relativeTau) {
 
   std::cout << "CoupledTimeStepper::step()" << std::endl;
@@ -48,7 +48,7 @@ CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorm>::step(double re
   updaters_.state_->setup(tau); 
   updaters_.rate_->setup(ell, tau, newRelativeTime, velocityRHS, velocityIterate, velocityMatrix);
 
-  FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorm> fixedPointIterator(
+  FixedPointIterator fixedPointIterator(
       parset_, nBodyAssembler_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, errorNorms_);
   auto const iterations = fixedPointIterator.run(updaters_, velocityMatrix,
                                                  velocityRHS, velocityIterate);
diff --git a/src/time-stepping/coupledtimestepper.hh b/src/time-stepping/coupledtimestepper.hh
index 4610c7a7..8b017775 100644
--- a/src/time-stepping/coupledtimestepper.hh
+++ b/src/time-stepping/coupledtimestepper.hh
@@ -8,16 +8,17 @@
 
 #include "../spatial-solving/fixedpointiterator.hh"
 
-template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorm>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
 class CoupledTimeStepper {
   using Vector = typename Factory::Vector;
   using Matrix = typename Factory::Matrix;
   using IgnoreVector = typename Factory::BitVector;
-  //using Nonlinearity = typename Factory::Nonlinearity;
+  using FixedPointIterator = FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>;
+
 public:
-  using GlobalFriction = typename FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorm>::GlobalFriction;
-  using BitVector = typename FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorm>::BitVector;
-  using ExternalForces = std::vector<const std::function<void(double, Vector &)>*>;
+  using GlobalFriction = typename FixedPointIterator::GlobalFriction;
+  using BitVector = typename FixedPointIterator::BitVector;
+  using ExternalForces = std::vector<std::unique_ptr<const std::function<void(double, Vector &)>>>;
 
 public:
   CoupledTimeStepper(double finalTime,
@@ -26,7 +27,8 @@ class CoupledTimeStepper {
                      const IgnoreVector& ignoreNodes,
                      GlobalFriction& globalFriction,
                      const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
-                     Updaters updaters, const std::vector<const ErrorNorm* >& errorNorms,
+                     Updaters updaters,
+                     const ErrorNorms& errorNorms,
                      ExternalForces& externalForces);
 
   FixedPointIterationCounter step(double relativeTime, double relativeTau);
@@ -42,6 +44,6 @@ class CoupledTimeStepper {
 
   Updaters updaters_;
   ExternalForces& externalForces_;
-  const std::vector<const ErrorNorm* >& errorNorms_;
+  const ErrorNorms& errorNorms_;
 };
 #endif
diff --git a/src/time-stepping/coupledtimestepper_tmpl.cc b/src/time-stepping/coupledtimestepper_tmpl.cc
index c70a229f..4d9f7f8e 100644
--- a/src/time-stepping/coupledtimestepper_tmpl.cc
+++ b/src/time-stepping/coupledtimestepper_tmpl.cc
@@ -8,21 +8,21 @@
 #include <dune/solvers/norms/energynorm.hh>
 
 #include "../spatial-solving/solverfactory_tmpl.cc"
-#include "../data-structures/levelcontactnetwork_tmpl.cc"
+#include "../data-structures/contactnetwork_tmpl.cc"
 
 #include "rate/rateupdater.hh"
 #include "state/stateupdater.hh"
 #include "updaters.hh"
 
-using NBodyAssembler = typename MyLevelContactNetwork::NBodyAssembler;
-using BoundaryNodes = typename MyLevelContactNetwork::BoundaryNodes;
-using BoundaryFunctions = typename MyLevelContactNetwork::BoundaryFunctions;
+using NBodyAssembler = typename MyContactNetwork::NBodyAssembler;
+using BoundaryNodes = typename MyContactNetwork::BoundaryNodes;
+using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions;
 
 using MyStateUpdater = StateUpdater<ScalarVector, Vector>;
 using MyRateUpdater = RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>;
 using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>;
 
-using ErrorNorm = EnergyNorm<ScalarMatrix, ScalarVector>;
+using ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
 
 
-template class CoupledTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorm>;
+template class CoupledTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>;
diff --git a/src/time-stepping/rate/rateupdater_tmpl.cc b/src/time-stepping/rate/rateupdater_tmpl.cc
index aa8a7168..09299039 100644
--- a/src/time-stepping/rate/rateupdater_tmpl.cc
+++ b/src/time-stepping/rate/rateupdater_tmpl.cc
@@ -5,10 +5,10 @@
 #include "../../explicitgrid.hh"
 #include "../../explicitvectors.hh"
 
-#include "../../data-structures/levelcontactnetwork.hh"
+#include "../../data-structures/contactnetwork_tmpl.cc"
 
-using BoundaryNodes = typename LevelContactNetwork<Grid, MY_DIM>::BoundaryNodes;
-using BoundaryFunctions = typename LevelContactNetwork<Grid, MY_DIM>::BoundaryFunctions;
+using BoundaryNodes = typename MyContactNetwork::BoundaryNodes;
+using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions;
 
 template class RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>;
 template class Newmark<Vector, Matrix, BoundaryFunctions, BoundaryNodes>;
diff --git a/src/time-stepping/rate_tmpl.cc b/src/time-stepping/rate_tmpl.cc
index 9627a8ce..771a1a0c 100644
--- a/src/time-stepping/rate_tmpl.cc
+++ b/src/time-stepping/rate_tmpl.cc
@@ -1,8 +1,8 @@
-#include "../data-structures/levelcontactnetwork_tmpl.cc"
+#include "../data-structures/contactnetwork_tmpl.cc"
 #include "../explicitvectors.hh"
 
-using BoundaryFunctions = typename LevelContactNetwork<Grid, MY_DIM>::BoundaryFunctions;
-using BoundaryNodes = typename LevelContactNetwork<Grid, MY_DIM>::BoundaryNodes;
+using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions;
+using BoundaryNodes = typename MyContactNetwork::BoundaryNodes;
 
 template
 auto initRateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>(
diff --git a/src/utils/debugutils.hh b/src/utils/debugutils.hh
index 68ef4361..32c923f4 100644
--- a/src/utils/debugutils.hh
+++ b/src/utils/debugutils.hh
@@ -155,6 +155,20 @@
       std::cout << message << " Step " << stepNumber << "!" << std::endl;
    }*/
 
+   template <class GridView, class VectorType>
+   void writeToVTK(const GridView& gridView, const VectorType& x, const std::string path, const std::string name) {
+       Dune::VTKWriter<GridView> vtkwriter(gridView);
+
+       std::ofstream lStream( "garbage.txt" );
+       std::streambuf* lBufferOld = std::cout.rdbuf();
+       std::cout.rdbuf(lStream.rdbuf());
+
+       vtkwriter.addVertexData(x,"data");
+       vtkwriter.pwrite(name, path, path);
+
+       std::cout.rdbuf( lBufferOld );
+   }
+
    template <class GridView>
    void writeToVTK(const GridView& gridView, const std::string path, const std::string name) {
        Dune::VTKWriter<GridView> vtkwriter(gridView);
@@ -168,6 +182,7 @@
        std::cout.rdbuf( lBufferOld );
    }
 
+   /*
    template <class VectorType, class DGBasisType>
    void writeToVTK(const DGBasisType& basis, const VectorType& x, const std::string path, const std::string name) {
        Dune::VTKWriter<typename DGBasisType::GridView> vtkwriter(basis.getGridView());
@@ -183,7 +198,7 @@
        vtkwriter.pwrite(name, path, path);
 
        std::cout.rdbuf( lBufferOld );
-   }
+   }*/
 
    template <class Intersection, class Basis>
    void printIntersection(const Intersection& it, const Basis& basis, std::string message = "") {
-- 
GitLab