From 2e4549e51adf461007732f65f450c3b6e56e90c9 Mon Sep 17 00:00:00 2001
From: podlesny <podlesny@mi.fu-berlin.de>
Date: Tue, 3 Sep 2019 17:47:34 +0200
Subject: [PATCH] major file system change

---
 data/2d-dip-contours-performance.tikz         |  91 +++
 data/2d-dip-single-points.tikz                |  51 ++
 data/2d-effort-over-tolerance.tikz            |  17 +
 data/2d-velocity-contours-threequakes.tikz    |  61 ++
 data/2d-velocity-contours-zoom.tikz           |  51 ++
 data/3d-performance.tikz                      |  57 ++
 data/3d-velocity-contours.tikz                | 156 +++++
 data/boxplot.tikz                             |  43 ++
 data/config.ini                               |   4 +
 data/includes.tex                             |  51 ++
 .../2d-dip-contours-performance.tex           |   7 +
 data/standalone/2d-dip-single-points.tex      |   7 +
 data/standalone/2d-effort-over-tolerance.tex  |   7 +
 .../2d-velocity-contours-threequakes.tex      |   7 +
 data/standalone/2d-velocity-contours-zoom.tex |   7 +
 data/standalone/3d-performance.tex            |   7 +
 data/standalone/3d-velocity-contours.tex      |   7 +
 data/standalone/Makefile                      |  18 +
 data/standalone/boxplot.tex                   |   7 +
 data/tools/2d-dip-contours.R                  | 108 ++++
 data/tools/2d-event-writer.R                  |  68 +++
 data/tools/2d-fpi-tolerance.R                 |  41 ++
 data/tools/2d-performance.R                   |  58 ++
 data/tools/2d-velocity-contours.R             |  95 +++
 data/tools/3d-performance.R                   |  62 ++
 data/tools/3d-velocity-contours.R             |  67 ++
 data/tools/comparison:lab-sim.R               |  42 ++
 data/tools/generate-2d.bash                   |  25 +
 data/tools/generate-3d.bash                   |  16 +
 data/tools/generate-others.bash               |  13 +
 data/tools/support/findQuakes.R               |  18 +
 data/tools/support/maxVelocity.cpp            |  29 +
 data/tools/support/negativeStarts.cpp         |  13 +
 data/tools/support/positiveStarts.cpp         |  14 +
 data/tools/support/trapezoidal.cpp            |   9 +
 data/tools/support/writeContours.R            |  11 +
 debugging.m                                   | 577 ++++++++++++++++++
 dune/tectonic/CMakeLists.txt                  |  38 +-
 {src => dune/tectonic}/assemblers.cc          |   4 +-
 {src => dune/tectonic}/assemblers.hh          |   4 +-
 {src => dune/tectonic}/assemblers_tmpl.cc     |   0
 {src => dune/tectonic}/data-structures/.cc    |   0
 dune/tectonic/data-structures/CMakeLists.txt  |  19 +
 .../data-structures/body/CMakeLists.txt       |  13 +
 .../tectonic/data-structures/body}/body.cc    |   0
 .../tectonic/data-structures/body}/body.hh    |  10 +-
 .../data-structures/body}/body_tmpl.cc        |   4 +-
 .../{ => data-structures/body}/bodydata.hh    |   0
 .../body}/boundarycondition.hh                |   0
 .../tectonic}/data-structures/enumparser.cc   |   0
 .../tectonic}/data-structures/enumparser.hh   |   0
 .../tectonic}/data-structures/enums.hh        |   0
 .../data-structures/friction/CMakeLists.txt   |  20 +
 .../friction}/frictioncouplingpair.hh         |   3 +-
 .../friction}/frictiondata.hh                 |   0
 .../friction}/frictionpotential.hh            |   2 +-
 .../friction}/globalfriction.hh               |   6 +-
 .../friction}/globalfrictiondata.hh           |   2 +-
 .../friction}/globalratestatefriction.hh      |  14 +-
 .../friction}/localfriction.hh                |   2 +-
 .../globalfrictioncontainer.cc                |   0
 .../globalfrictioncontainer.hh                |   0
 .../tectonic}/data-structures/matrices.hh     |   0
 .../data-structures/network/CMakeLists.txt    |  12 +
 .../network}/contactnetwork.cc                |   8 +-
 .../network}/contactnetwork.hh                |  19 +-
 .../network/contactnetwork_tmpl.cc            |  10 +
 .../network}/levelcontactnetwork.cc           |  12 +-
 .../network}/levelcontactnetwork.hh           |  19 +-
 .../network}/levelcontactnetwork_tmpl.cc      |  10 +-
 .../data-structures/program_state.hh          |  85 ++-
 {src => dune/tectonic}/explicitgrid.hh        |   0
 {src => dune/tectonic}/explicitvectors.hh     |   0
 dune/tectonic/factories/CMakeLists.txt        |  22 +
 .../tectonic}/factories/cantorfactory.cc      |   0
 .../tectonic}/factories/cantorfactory.hh      |   0
 .../tectonic}/factories/cantorfactory_tmpl.cc |   0
 .../factories/contactnetworkfactory.hh        |   2 +-
 .../factories/levelcontactnetworkfactory.hh   |   0
 .../factories/stackedblocksfactory.cc         |  12 +-
 .../factories/stackedblocksfactory.hh         |  10 +-
 .../factories/stackedblocksfactory_tmpl.cc    |   0
 .../tectonic}/factories/threeblocksfactory.cc |  14 +-
 .../tectonic}/factories/threeblocksfactory.hh |   9 +-
 .../factories/threeblocksfactory_tmpl.cc      |   0
 dune/tectonic/factories/twoblocksfactory.cc   | 199 ++++++
 dune/tectonic/factories/twoblocksfactory.hh   |  87 +++
 .../factories/twoblocksfactory_tmpl.cc        |   8 +
 {src => dune/tectonic}/gridselector.hh        |   0
 dune/tectonic/io/CMakeLists.txt               |  16 +
 {src => dune/tectonic}/io/hdf5-bodywriter.hh  |  27 +-
 {src => dune/tectonic}/io/hdf5-levelwriter.hh |  28 +-
 dune/tectonic/io/hdf5/CMakeLists.txt          |  26 +
 .../io/hdf5/frictionalboundary-writer.cc      |   5 +-
 .../io/hdf5/frictionalboundary-writer.hh      |   0
 .../io/hdf5/frictionalboundary-writer_tmpl.cc |   0
 .../tectonic}/io/hdf5/iteration-writer.cc     |   0
 .../tectonic}/io/hdf5/iteration-writer.hh     |   0
 .../tectonic}/io/hdf5/patchinfo-writer.cc     |  12 +-
 .../tectonic}/io/hdf5/patchinfo-writer.hh     |   8 +-
 .../io/hdf5/patchinfo-writer_tmpl.cc          |   0
 {src => dune/tectonic}/io/hdf5/restart-io.cc  |   0
 {src => dune/tectonic}/io/hdf5/restart-io.hh  |   0
 .../tectonic}/io/hdf5/restart-io_tmpl.cc      |   0
 {src => dune/tectonic}/io/hdf5/restrict.hh    |   0
 .../tectonic}/io/hdf5/surface-writer.cc       |   0
 .../tectonic}/io/hdf5/surface-writer.hh       |   0
 .../tectonic}/io/hdf5/surface-writer_tmpl.cc  |   0
 {src => dune/tectonic}/io/hdf5/time-writer.cc |   0
 {src => dune/tectonic}/io/hdf5/time-writer.hh |   0
 .../tectonic}/io/hdf5/time-writer_tmpl.cc     |   0
 .../tectonic}/io/uniform-grid-writer.cc       |   0
 {src => dune/tectonic}/io/vtk.cc              |   0
 {src => dune/tectonic}/io/vtk.hh              |   0
 {src => dune/tectonic}/io/vtk_tmpl.cc         |   0
 dune/tectonic/minimisation.hh                 |  41 --
 dune/tectonic/myblockproblem.hh               | 273 ---------
 dune/tectonic/problem-data/CMakeLists.txt     |  22 +
 .../tectonic/problem-data}/bc.hh              |  13 +-
 dune/tectonic/{ => problem-data}/gravity.hh   |   0
 .../tectonic/problem-data/grid/CMakeLists.txt |  25 +
 .../tectonic/problem-data}/grid/cube.cc       |   0
 .../tectonic/problem-data}/grid/cube.hh       |   0
 .../tectonic/problem-data}/grid/cube_tmpl.cc  |   0
 .../tectonic/problem-data}/grid/cubefaces.cc  |   0
 .../tectonic/problem-data}/grid/cubefaces.hh  |   0
 .../problem-data}/grid/cubefaces_tmpl.cc      |   0
 .../problem-data}/grid/cubegridconstructor.hh |   0
 .../problem-data}/grid/cuboidgeometry.cc      |  14 +-
 .../problem-data}/grid/cuboidgeometry.hh      |   4 +-
 .../problem-data}/grid/cuboidgeometry_tmpl.cc |   0
 .../problem-data}/grid/gridconstructor.hh     |   0
 .../tectonic/problem-data}/grid/mygrids.cc    |   8 +-
 .../tectonic/problem-data}/grid/mygrids.hh    |   4 +-
 .../problem-data}/grid/mygrids_tmpl.cc        |   0
 .../problem-data}/grid/simplexmanager.cc      |   0
 .../problem-data}/grid/simplexmanager.hh      |   0
 .../tectonic/problem-data}/midpoint.hh        |   0
 .../tectonic/problem-data}/mybody.hh          |  25 +-
 .../problem-data}/myglobalfrictiondata.hh     |   2 +-
 .../tectonic/problem-data}/patchfunction.hh   |   0
 .../problem-data}/segmented-function.hh       |   0
 dune/tectonic/quadraticenergy.hh              |  18 -
 dune/tectonic/spatial-solving/CMakeLists.txt  |  15 +
 .../spatial-solving/fixedpointiterator.cc     | 191 +++---
 .../spatial-solving/fixedpointiterator.hh     |  11 +-
 .../fixedpointiterator_tmpl.cc                |  41 ++
 .../preconditioners/CMakeLists.txt            |  19 +
 .../hierarchicleveliterator.hh                |   0
 .../levelpatchpreconditioner.hh               |  66 +-
 .../multilevelpatchpreconditioner.hh          |  46 +-
 .../preconditioners/nbodycontacttransfer.cc   |  10 +-
 .../preconditioners/nbodycontacttransfer.hh   |   2 +-
 .../preconditioners/patchproblem.hh           | 115 ++++
 .../preconditioners/supportpatchfactory.hh    |   7 +-
 .../tectonic/spatial-solving/solverfactory.cc |  46 ++
 .../spatial-solving/solverfactory.hh          |  23 +-
 .../spatial-solving/solverfactory_ex.cc       |  17 +
 .../spatial-solving/solverfactory_tmpl.cc     |  21 +
 .../spatial-solving/tnnmg/CMakeLists.txt      |  18 +
 .../spatial-solving/tnnmg/functional.hh       |   0
 .../spatial-solving/tnnmg/linearcorrection.hh |   0
 .../spatial-solving/tnnmg/linearization.hh    |   0
 .../spatial-solving/tnnmg/linesearchsolver.hh |   0
 .../tnnmg/localbisectionsolver.hh             |   0
 .../spatial-solving/tnnmg/zerononlinearity.hh |   0
 {src => dune/tectonic}/tests/CMakeLists.txt   |   1 +
 {src => dune/tectonic}/tests/common.hh        |   0
 {src => dune/tectonic}/tests/couplingtest.hh  |   0
 .../tests/globalfrictioncontainertest.cc      |   0
 .../tectonic}/tests/gridgluefrictiontest.cc   |   0
 {src => dune/tectonic/tests}/nodalweights.cc  |   0
 {src => dune/tectonic/tests}/nodalweights.hh  |   0
 .../tectonic}/tests/nodalweightstest.cc       |   0
 .../tests/nonoverlappingcouplingtest.cc       |   0
 .../tectonic/tests}/solverfactorytest.cc      |  40 +-
 .../tests/supportpatchfactorytest.cc          |   0
 dune/tectonic/time-stepping/CMakeLists.txt    |  23 +
 .../time-stepping/adaptivetimestepper.cc      | 276 +++++++++
 .../time-stepping/adaptivetimestepper.hh      |  23 +-
 .../time-stepping/adaptivetimestepper_tmpl.cc |  42 ++
 .../time-stepping/coupledtimestepper.cc       |  29 +-
 .../time-stepping/coupledtimestepper.hh       |  12 +-
 .../time-stepping/coupledtimestepper_tmpl.cc  |  40 ++
 {src => dune/tectonic}/time-stepping/rate.cc  |   0
 {src => dune/tectonic}/time-stepping/rate.hh  |   0
 .../time-stepping/rate/CMakeLists.txt         |  15 +
 .../time-stepping/rate/backward_euler.cc      |   0
 .../time-stepping/rate/backward_euler.hh      |   0
 .../tectonic}/time-stepping/rate/newmark.cc   |   0
 .../tectonic}/time-stepping/rate/newmark.hh   |   0
 .../time-stepping/rate/rateupdater.cc         |   0
 .../time-stepping/rate/rateupdater.hh         |   0
 .../time-stepping/rate/rateupdater_tmpl.cc    |   4 +-
 .../tectonic}/time-stepping/rate_tmpl.cc      |   9 +-
 {src => dune/tectonic}/time-stepping/state.cc |   0
 {src => dune/tectonic}/time-stepping/state.hh |   0
 .../time-stepping/state/CMakeLists.txt        |  14 +
 .../state/ageinglawstateupdater.cc            |   0
 .../state/ageinglawstateupdater.hh            |   0
 .../time-stepping/state/calculation.wxm       |   0
 .../tectonic/time-stepping/state/explicit.aux |   1 +
 .../tectonic/time-stepping/state/explicit.log | 285 +++++++++
 .../tectonic/time-stepping/state/explicit.pdf | Bin 0 -> 82543 bytes
 .../time-stepping/state/explicit.synctex.gz   | Bin 0 -> 2143 bytes
 .../time-stepping/state/explicit.tex          |   0
 .../state/sliplawstateupdater.cc              |   0
 .../state/sliplawstateupdater.hh              |   0
 .../time-stepping/state/stateupdater.hh       |   8 +-
 .../tectonic}/time-stepping/state_tmpl.cc     |   2 +-
 .../tectonic}/time-stepping/updaters.hh       |   0
 dune/tectonic/utils/CMakeLists.txt            |  18 +
 {src => dune/tectonic}/utils/almostequal.hh   |   0
 {src => dune/tectonic}/utils/debugutils.hh    |   0
 {src => dune/tectonic}/utils/diameter.hh      |   0
 dune/tectonic/{ => utils}/geocoordinate.hh    |   0
 .../{ => utils}/index-in-sorted-range.hh      |   0
 {src => dune/tectonic}/utils/tobool.hh        |   0
 program_structure.txt                         |  29 -
 src/CMakeLists.txt                            | 108 +---
 src/data-structures/contactnetwork_tmpl.cc    |  12 -
 src/foam/CMakeLists.txt                       |  43 ++
 .../foam-2D.cfg}                              |   9 +-
 src/foam/foam.cc                              | 483 +++++++++++++++
 src/foam/foam.cfg                             | 107 ++++
 src/multi-body-problem-data/geometry.tex      |  68 ---
 src/multi-body-problem/CMakeLists.txt         |  46 ++
 .../multi-body-problem-2D.cfg                 |   8 +-
 .../multi-body-problem-3D.cfg                 |   0
 .../multi-body-problem.cc                     | 121 ++--
 .../multi-body-problem.cfg                    |  25 +-
 src/one-body-problem-3D.cfg                   |  24 -
 src/one-body-problem-data/bc.hh               |  18 -
 src/one-body-problem-data/geometry.tex        |  68 ---
 src/one-body-problem-data/midpoint.hh         |  12 -
 src/one-body-problem-data/mybody.hh           |  55 --
 src/one-body-problem-data/mygeometry.cc       | 158 -----
 src/one-body-problem-data/mygeometry.hh       |  89 ---
 .../myglobalfrictiondata.hh                   |  42 --
 src/one-body-problem-data/mygrid.cc           | 227 -------
 src/one-body-problem-data/mygrid.hh           |  84 ---
 src/one-body-problem-data/mygrid_tmpl.cc      |  17 -
 src/one-body-problem-data/patchfunction.hh    |  31 -
 .../segmented-function.hh                     |  34 --
 src/one-body-problem-data/weakpatch.hh        |  32 -
 src/one-body-problem.cc                       | 361 -----------
 src/one-body-problem.cfg                      |  70 ---
 src/spatial-solving/CMakeLists.txt            |   2 -
 .../fixedpointiterator_tmpl.cc                |  27 -
 .../preconditioners/CMakeLists.txt            |   8 -
 .../preconditioners/localproblem.hh           | 141 -----
 src/spatial-solving/solverfactory.cc          |  50 --
 src/spatial-solving/solverfactory_tmpl.cc     |  36 --
 src/spatial-solving/tnnmg/CMakeLists.txt      |   8 -
 src/tests/contactmerge.cc                     |  40 --
 src/time-stepping/adaptivetimestepper.cc      | 137 -----
 src/time-stepping/adaptivetimestepper_tmpl.cc |  27 -
 src/time-stepping/coupledtimestepper_tmpl.cc  |  27 -
 todo.txt                                      |  29 -
 259 files changed, 4707 insertions(+), 2868 deletions(-)
 create mode 100644 data/2d-dip-contours-performance.tikz
 create mode 100644 data/2d-dip-single-points.tikz
 create mode 100644 data/2d-effort-over-tolerance.tikz
 create mode 100644 data/2d-velocity-contours-threequakes.tikz
 create mode 100644 data/2d-velocity-contours-zoom.tikz
 create mode 100644 data/3d-performance.tikz
 create mode 100644 data/3d-velocity-contours.tikz
 create mode 100644 data/boxplot.tikz
 create mode 100644 data/config.ini
 create mode 100644 data/includes.tex
 create mode 100644 data/standalone/2d-dip-contours-performance.tex
 create mode 100644 data/standalone/2d-dip-single-points.tex
 create mode 100644 data/standalone/2d-effort-over-tolerance.tex
 create mode 100644 data/standalone/2d-velocity-contours-threequakes.tex
 create mode 100644 data/standalone/2d-velocity-contours-zoom.tex
 create mode 100644 data/standalone/3d-performance.tex
 create mode 100644 data/standalone/3d-velocity-contours.tex
 create mode 100644 data/standalone/Makefile
 create mode 100644 data/standalone/boxplot.tex
 create mode 100644 data/tools/2d-dip-contours.R
 create mode 100644 data/tools/2d-event-writer.R
 create mode 100644 data/tools/2d-fpi-tolerance.R
 create mode 100644 data/tools/2d-performance.R
 create mode 100644 data/tools/2d-velocity-contours.R
 create mode 100644 data/tools/3d-performance.R
 create mode 100644 data/tools/3d-velocity-contours.R
 create mode 100644 data/tools/comparison:lab-sim.R
 create mode 100755 data/tools/generate-2d.bash
 create mode 100755 data/tools/generate-3d.bash
 create mode 100755 data/tools/generate-others.bash
 create mode 100644 data/tools/support/findQuakes.R
 create mode 100644 data/tools/support/maxVelocity.cpp
 create mode 100644 data/tools/support/negativeStarts.cpp
 create mode 100644 data/tools/support/positiveStarts.cpp
 create mode 100644 data/tools/support/trapezoidal.cpp
 create mode 100644 data/tools/support/writeContours.R
 create mode 100644 debugging.m
 rename {src => dune/tectonic}/assemblers.cc (98%)
 rename {src => dune/tectonic}/assemblers.hh (97%)
 rename {src => dune/tectonic}/assemblers_tmpl.cc (100%)
 rename {src => dune/tectonic}/data-structures/.cc (100%)
 create mode 100644 dune/tectonic/data-structures/CMakeLists.txt
 create mode 100644 dune/tectonic/data-structures/body/CMakeLists.txt
 rename {src/data-structures => dune/tectonic/data-structures/body}/body.cc (100%)
 rename {src/data-structures => dune/tectonic/data-structures/body}/body.hh (97%)
 rename {src/data-structures => dune/tectonic/data-structures/body}/body_tmpl.cc (70%)
 rename dune/tectonic/{ => data-structures/body}/bodydata.hh (100%)
 rename {src => dune/tectonic/data-structures/body}/boundarycondition.hh (100%)
 rename {src => dune/tectonic}/data-structures/enumparser.cc (100%)
 rename {src => dune/tectonic}/data-structures/enumparser.hh (100%)
 rename {src => dune/tectonic}/data-structures/enums.hh (100%)
 create mode 100644 dune/tectonic/data-structures/friction/CMakeLists.txt
 rename {src => dune/tectonic/data-structures/friction}/frictioncouplingpair.hh (95%)
 rename dune/tectonic/{ => data-structures/friction}/frictiondata.hh (100%)
 rename dune/tectonic/{ => data-structures/friction}/frictionpotential.hh (99%)
 rename dune/tectonic/{ => data-structures/friction}/globalfriction.hh (93%)
 rename dune/tectonic/{ => data-structures/friction}/globalfrictiondata.hh (96%)
 rename dune/tectonic/{ => data-structures/friction}/globalratestatefriction.hh (91%)
 rename dune/tectonic/{ => data-structures/friction}/localfriction.hh (99%)
 rename {src => dune/tectonic}/data-structures/globalfrictioncontainer.cc (100%)
 rename {src => dune/tectonic}/data-structures/globalfrictioncontainer.hh (100%)
 rename {src => dune/tectonic}/data-structures/matrices.hh (100%)
 create mode 100644 dune/tectonic/data-structures/network/CMakeLists.txt
 rename {src/data-structures => dune/tectonic/data-structures/network}/contactnetwork.cc (98%)
 rename {src/data-structures => dune/tectonic/data-structures/network}/contactnetwork.hh (95%)
 create mode 100644 dune/tectonic/data-structures/network/contactnetwork_tmpl.cc
 rename {src/data-structures => dune/tectonic/data-structures/network}/levelcontactnetwork.cc (97%)
 rename {src/data-structures => dune/tectonic/data-structures/network}/levelcontactnetwork.hh (91%)
 rename {src/data-structures => dune/tectonic/data-structures/network}/levelcontactnetwork_tmpl.cc (54%)
 rename {src => dune/tectonic}/data-structures/program_state.hh (82%)
 rename {src => dune/tectonic}/explicitgrid.hh (100%)
 rename {src => dune/tectonic}/explicitvectors.hh (100%)
 create mode 100644 dune/tectonic/factories/CMakeLists.txt
 rename {src => dune/tectonic}/factories/cantorfactory.cc (100%)
 rename {src => dune/tectonic}/factories/cantorfactory.hh (100%)
 rename {src => dune/tectonic}/factories/cantorfactory_tmpl.cc (100%)
 rename {src => dune/tectonic}/factories/contactnetworkfactory.hh (96%)
 rename {src => dune/tectonic}/factories/levelcontactnetworkfactory.hh (100%)
 rename {src => dune/tectonic}/factories/stackedblocksfactory.cc (97%)
 rename {src => dune/tectonic}/factories/stackedblocksfactory.hh (93%)
 rename {src => dune/tectonic}/factories/stackedblocksfactory_tmpl.cc (100%)
 rename {src => dune/tectonic}/factories/threeblocksfactory.cc (96%)
 rename {src => dune/tectonic}/factories/threeblocksfactory.hh (92%)
 rename {src => dune/tectonic}/factories/threeblocksfactory_tmpl.cc (100%)
 create mode 100644 dune/tectonic/factories/twoblocksfactory.cc
 create mode 100644 dune/tectonic/factories/twoblocksfactory.hh
 create mode 100644 dune/tectonic/factories/twoblocksfactory_tmpl.cc
 rename {src => dune/tectonic}/gridselector.hh (100%)
 create mode 100644 dune/tectonic/io/CMakeLists.txt
 rename {src => dune/tectonic}/io/hdf5-bodywriter.hh (64%)
 rename {src => dune/tectonic}/io/hdf5-levelwriter.hh (67%)
 create mode 100644 dune/tectonic/io/hdf5/CMakeLists.txt
 rename {src => dune/tectonic}/io/hdf5/frictionalboundary-writer.cc (93%)
 rename {src => dune/tectonic}/io/hdf5/frictionalboundary-writer.hh (100%)
 rename {src => dune/tectonic}/io/hdf5/frictionalboundary-writer_tmpl.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/iteration-writer.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/iteration-writer.hh (100%)
 rename {src => dune/tectonic}/io/hdf5/patchinfo-writer.cc (89%)
 rename {src => dune/tectonic}/io/hdf5/patchinfo-writer.hh (83%)
 rename {src => dune/tectonic}/io/hdf5/patchinfo-writer_tmpl.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/restart-io.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/restart-io.hh (100%)
 rename {src => dune/tectonic}/io/hdf5/restart-io_tmpl.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/restrict.hh (100%)
 rename {src => dune/tectonic}/io/hdf5/surface-writer.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/surface-writer.hh (100%)
 rename {src => dune/tectonic}/io/hdf5/surface-writer_tmpl.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/time-writer.cc (100%)
 rename {src => dune/tectonic}/io/hdf5/time-writer.hh (100%)
 rename {src => dune/tectonic}/io/hdf5/time-writer_tmpl.cc (100%)
 rename {src => dune/tectonic}/io/uniform-grid-writer.cc (100%)
 rename {src => dune/tectonic}/io/vtk.cc (100%)
 rename {src => dune/tectonic}/io/vtk.hh (100%)
 rename {src => dune/tectonic}/io/vtk_tmpl.cc (100%)
 delete mode 100644 dune/tectonic/minimisation.hh
 delete mode 100644 dune/tectonic/myblockproblem.hh
 create mode 100644 dune/tectonic/problem-data/CMakeLists.txt
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/bc.hh (69%)
 rename dune/tectonic/{ => problem-data}/gravity.hh (100%)
 create mode 100644 dune/tectonic/problem-data/grid/CMakeLists.txt
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cube.cc (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cube.hh (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cube_tmpl.cc (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubefaces.cc (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubefaces.hh (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubefaces_tmpl.cc (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cubegridconstructor.hh (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cuboidgeometry.cc (94%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cuboidgeometry.hh (95%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/cuboidgeometry_tmpl.cc (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/gridconstructor.hh (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/mygrids.cc (97%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/mygrids.hh (93%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/mygrids_tmpl.cc (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/simplexmanager.cc (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/grid/simplexmanager.hh (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/midpoint.hh (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/mybody.hh (65%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/myglobalfrictiondata.hh (95%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/patchfunction.hh (100%)
 rename {src/multi-body-problem-data => dune/tectonic/problem-data}/segmented-function.hh (100%)
 delete mode 100644 dune/tectonic/quadraticenergy.hh
 create mode 100644 dune/tectonic/spatial-solving/CMakeLists.txt
 rename {src => dune/tectonic}/spatial-solving/fixedpointiterator.cc (61%)
 rename {src => dune/tectonic}/spatial-solving/fixedpointiterator.hh (86%)
 create mode 100644 dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc
 create mode 100644 dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt
 rename {src => dune/tectonic}/spatial-solving/preconditioners/hierarchicleveliterator.hh (100%)
 rename {src => dune/tectonic}/spatial-solving/preconditioners/levelpatchpreconditioner.hh (72%)
 rename {src => dune/tectonic}/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh (86%)
 rename {src => dune/tectonic}/spatial-solving/preconditioners/nbodycontacttransfer.cc (97%)
 rename {src => dune/tectonic}/spatial-solving/preconditioners/nbodycontacttransfer.hh (97%)
 create mode 100644 dune/tectonic/spatial-solving/preconditioners/patchproblem.hh
 rename {src => dune/tectonic}/spatial-solving/preconditioners/supportpatchfactory.hh (98%)
 create mode 100644 dune/tectonic/spatial-solving/solverfactory.cc
 rename {src => dune/tectonic}/spatial-solving/solverfactory.hh (69%)
 create mode 100644 dune/tectonic/spatial-solving/solverfactory_ex.cc
 create mode 100644 dune/tectonic/spatial-solving/solverfactory_tmpl.cc
 create mode 100644 dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt
 rename {src => dune/tectonic}/spatial-solving/tnnmg/functional.hh (100%)
 rename {src => dune/tectonic}/spatial-solving/tnnmg/linearcorrection.hh (100%)
 rename {src => dune/tectonic}/spatial-solving/tnnmg/linearization.hh (100%)
 rename {src => dune/tectonic}/spatial-solving/tnnmg/linesearchsolver.hh (100%)
 rename {src => dune/tectonic}/spatial-solving/tnnmg/localbisectionsolver.hh (100%)
 rename {src => dune/tectonic}/spatial-solving/tnnmg/zerononlinearity.hh (100%)
 rename {src => dune/tectonic}/tests/CMakeLists.txt (81%)
 rename {src => dune/tectonic}/tests/common.hh (100%)
 rename {src => dune/tectonic}/tests/couplingtest.hh (100%)
 rename {src => dune/tectonic}/tests/globalfrictioncontainertest.cc (100%)
 rename {src => dune/tectonic}/tests/gridgluefrictiontest.cc (100%)
 rename {src => dune/tectonic/tests}/nodalweights.cc (100%)
 rename {src => dune/tectonic/tests}/nodalweights.hh (100%)
 rename {src => dune/tectonic}/tests/nodalweightstest.cc (100%)
 rename {src => dune/tectonic}/tests/nonoverlappingcouplingtest.cc (100%)
 rename {src => dune/tectonic/tests}/solverfactorytest.cc (95%)
 rename {src => dune/tectonic}/tests/supportpatchfactorytest.cc (100%)
 create mode 100644 dune/tectonic/time-stepping/CMakeLists.txt
 create mode 100644 dune/tectonic/time-stepping/adaptivetimestepper.cc
 rename {src => dune/tectonic}/time-stepping/adaptivetimestepper.hh (75%)
 create mode 100644 dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc
 rename {src => dune/tectonic}/time-stepping/coupledtimestepper.cc (63%)
 rename {src => dune/tectonic}/time-stepping/coupledtimestepper.hh (77%)
 create mode 100644 dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc
 rename {src => dune/tectonic}/time-stepping/rate.cc (100%)
 rename {src => dune/tectonic}/time-stepping/rate.hh (100%)
 create mode 100644 dune/tectonic/time-stepping/rate/CMakeLists.txt
 rename {src => dune/tectonic}/time-stepping/rate/backward_euler.cc (100%)
 rename {src => dune/tectonic}/time-stepping/rate/backward_euler.hh (100%)
 rename {src => dune/tectonic}/time-stepping/rate/newmark.cc (100%)
 rename {src => dune/tectonic}/time-stepping/rate/newmark.hh (100%)
 rename {src => dune/tectonic}/time-stepping/rate/rateupdater.cc (100%)
 rename {src => dune/tectonic}/time-stepping/rate/rateupdater.hh (100%)
 rename {src => dune/tectonic}/time-stepping/rate/rateupdater_tmpl.cc (80%)
 rename {src => dune/tectonic}/time-stepping/rate_tmpl.cc (77%)
 rename {src => dune/tectonic}/time-stepping/state.cc (100%)
 rename {src => dune/tectonic}/time-stepping/state.hh (100%)
 create mode 100644 dune/tectonic/time-stepping/state/CMakeLists.txt
 rename {src => dune/tectonic}/time-stepping/state/ageinglawstateupdater.cc (100%)
 rename {src => dune/tectonic}/time-stepping/state/ageinglawstateupdater.hh (100%)
 rename {src => dune/tectonic}/time-stepping/state/calculation.wxm (100%)
 create mode 100644 dune/tectonic/time-stepping/state/explicit.aux
 create mode 100644 dune/tectonic/time-stepping/state/explicit.log
 create mode 100644 dune/tectonic/time-stepping/state/explicit.pdf
 create mode 100644 dune/tectonic/time-stepping/state/explicit.synctex.gz
 rename {src => dune/tectonic}/time-stepping/state/explicit.tex (100%)
 rename {src => dune/tectonic}/time-stepping/state/sliplawstateupdater.cc (100%)
 rename {src => dune/tectonic}/time-stepping/state/sliplawstateupdater.hh (100%)
 rename {src => dune/tectonic}/time-stepping/state/stateupdater.hh (85%)
 rename {src => dune/tectonic}/time-stepping/state_tmpl.cc (93%)
 rename {src => dune/tectonic}/time-stepping/updaters.hh (100%)
 create mode 100644 dune/tectonic/utils/CMakeLists.txt
 rename {src => dune/tectonic}/utils/almostequal.hh (100%)
 rename {src => dune/tectonic}/utils/debugutils.hh (100%)
 rename {src => dune/tectonic}/utils/diameter.hh (100%)
 rename dune/tectonic/{ => utils}/geocoordinate.hh (100%)
 rename dune/tectonic/{ => utils}/index-in-sorted-range.hh (100%)
 rename {src => dune/tectonic}/utils/tobool.hh (100%)
 delete mode 100644 program_structure.txt
 delete mode 100644 src/data-structures/contactnetwork_tmpl.cc
 create mode 100644 src/foam/CMakeLists.txt
 rename src/{one-body-problem-2D.cfg => foam/foam-2D.cfg} (55%)
 create mode 100644 src/foam/foam.cc
 create mode 100644 src/foam/foam.cfg
 delete mode 100644 src/multi-body-problem-data/geometry.tex
 create mode 100644 src/multi-body-problem/CMakeLists.txt
 rename src/{ => multi-body-problem}/multi-body-problem-2D.cfg (64%)
 rename src/{ => multi-body-problem}/multi-body-problem-3D.cfg (100%)
 rename src/{ => multi-body-problem}/multi-body-problem.cc (81%)
 rename src/{ => multi-body-problem}/multi-body-problem.cfg (80%)
 delete mode 100644 src/one-body-problem-3D.cfg
 delete mode 100644 src/one-body-problem-data/bc.hh
 delete mode 100644 src/one-body-problem-data/geometry.tex
 delete mode 100644 src/one-body-problem-data/midpoint.hh
 delete mode 100644 src/one-body-problem-data/mybody.hh
 delete mode 100644 src/one-body-problem-data/mygeometry.cc
 delete mode 100644 src/one-body-problem-data/mygeometry.hh
 delete mode 100644 src/one-body-problem-data/myglobalfrictiondata.hh
 delete mode 100644 src/one-body-problem-data/mygrid.cc
 delete mode 100644 src/one-body-problem-data/mygrid.hh
 delete mode 100644 src/one-body-problem-data/mygrid_tmpl.cc
 delete mode 100644 src/one-body-problem-data/patchfunction.hh
 delete mode 100644 src/one-body-problem-data/segmented-function.hh
 delete mode 100644 src/one-body-problem-data/weakpatch.hh
 delete mode 100644 src/one-body-problem.cc
 delete mode 100644 src/one-body-problem.cfg
 delete mode 100644 src/spatial-solving/CMakeLists.txt
 delete mode 100644 src/spatial-solving/fixedpointiterator_tmpl.cc
 delete mode 100644 src/spatial-solving/preconditioners/CMakeLists.txt
 delete mode 100644 src/spatial-solving/preconditioners/localproblem.hh
 delete mode 100644 src/spatial-solving/solverfactory.cc
 delete mode 100644 src/spatial-solving/solverfactory_tmpl.cc
 delete mode 100644 src/spatial-solving/tnnmg/CMakeLists.txt
 delete mode 100644 src/tests/contactmerge.cc
 delete mode 100644 src/time-stepping/adaptivetimestepper.cc
 delete mode 100644 src/time-stepping/adaptivetimestepper_tmpl.cc
 delete mode 100644 src/time-stepping/coupledtimestepper_tmpl.cc
 delete mode 100644 todo.txt

diff --git a/data/2d-dip-contours-performance.tikz b/data/2d-dip-contours-performance.tikz
new file mode 100644
index 00000000..b3aaffa7
--- /dev/null
+++ b/data/2d-dip-contours-performance.tikz
@@ -0,0 +1,91 @@
+\pgfplotsarraynew\heights{%
+  -40\\-20\\-10\\-5\\-2.5\\%
+  0\\%
+  2.5\\5\\10\\20\\40\\%
+}
+\def\fnamebase{2d-dip-contours}
+\def\fname{rfpitol=100e-7}
+
+\newread\threequakesminread
+\openin\threequakesminread=generated/timeframe:min:threequakes:\fname.tex
+\read\threequakesminread to \threequakesmin
+\closein\threequakesminread
+
+\newread\threequakesmaxread
+\openin\threequakesmaxread=generated/timeframe:max:threequakes:\fname.tex
+\read\threequakesmaxread to \threequakesmax
+\closein\threequakesmaxread
+
+\begin{tikzpicture}[trim axis group left, trim axis group right]
+  \begin{groupplot}[
+    xmin=\threequakesmin, xmax=\threequakesmax, max space between ticks=40pt,
+    x tick label style={ /pgf/number format/1000 sep={} },
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    group style={
+      x descriptions at = edge bottom,
+      group size=1 by 4,
+      vertical sep=0cm
+    },
+    width=12cm,
+    enlargelimits=false]
+    \nextgroupplot[
+    semithick,
+    height = 6.5cm,
+    /pgf/number format/1000 sep={},
+    ymax=0.7,
+    colormap/jet,
+    y tick label style={
+      /pgf/number format/.cd,
+      fixed, fixed zerofill, precision=2,
+      /tikz/.cd
+    },
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    legend style={font=\small,
+                  at={(1.05,1)},
+                  anchor=north west,
+                  fill=none},
+    ylabel = distance from trench, y unit = m,
+    legend cell align=right,
+    contour/labels=false,
+    contour prepared]
+    \pgfplotsinvokeforeach{1,...,9} { % level 0 and 10 are empty
+      \pgfplotscolormapaccess[0:10]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \def\fnameX{generated/\fnamebase:\fname:level:%
+        \pgfplotsarrayvalueofelem#1\of\heights.tex}
+      \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX;
+      \addlegendimage{line legend,color=mycolor#1}
+      \addlegendentry{%
+         \SI{\pgfplotsarrayvalueofelem#1\of\heights}{\micro\meter}}
+    };
+    \nextgroupplot[
+    semithick,
+    height = 3.5cm,
+    ylabel style={align=center}, ylabel = time step\\size, y unit = s,
+    ytick={1e-3,1e-2,1e-1},
+    ymax = 1, ymin = 1e-4,
+    ymode = log]
+    \addplot[const plot, mark=none] table[col sep=comma, y=timeIncrement]
+    {generated/2d-performance:\fname.csv};
+    \nextgroupplot[
+    semithick,
+    height = 3.5cm,
+    ylabel style={align=center}, ylabel=fixed-point\\iterations,
+    ytick={2,4,6,8},
+    ymin=0, ymax=10]
+    \addplot[const plot, mark=none] table[col sep=comma, y=fixedPointIterations]
+    {generated/2d-performance:\fname.csv};
+    \nextgroupplot[
+    semithick,
+    height = 3.5cm,
+    xlabel = time, x unit = s,
+    ylabel style={align=center}, ylabel=multigrid\\iterations,
+    ytick={5,10,15,20},
+    ymin=0, ymax=25]
+    \addplot[const plot, mark=none] table[col sep=comma, y=multiGridIterations]
+    {generated/2d-performance:\fname.csv};
+  \end{groupplot}
+\end{tikzpicture}
diff --git a/data/2d-dip-single-points.tikz b/data/2d-dip-single-points.tikz
new file mode 100644
index 00000000..9717932d
--- /dev/null
+++ b/data/2d-dip-single-points.tikz
@@ -0,0 +1,51 @@
+\def\fnamebase{dip-single-points}
+\def\fname{rfpitol=100e-7}
+
+\newread\threequakesminread
+\openin\threequakesminread=generated/timeframe:min:threequakes:\fname.tex
+\read\threequakesminread to \threequakesmin
+\closein\threequakesminread
+
+\newread\threequakesmaxread
+\openin\threequakesmaxread=generated/timeframe:max:threequakes:\fname.tex
+\read\threequakesmaxread to \threequakesmax
+\closein\threequakesmaxread
+
+\begin{tikzpicture}[trim axis left, trim axis right]
+  \begin{axis}[
+    xmin=\threequakesmin, xmax=\threequakesmax, max space between ticks=40pt,
+    /pgf/number format/1000 sep={},
+    x tick label style={
+      /pgf/number format/.cd,
+      1000 sep={},
+      /tikz/.cd
+    },
+    y tick label style={
+      /pgf/number format/.cd,
+      fixed, fixed zerofill, precision=2,
+      /tikz/.cd
+    },
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    legend style={font=\small, at={(1.05,1)},
+                  anchor=north west,
+                  fill=none},
+    legend entries={
+      \SI{15}{\centi\meter},
+      \SI{30}{\centi\meter},
+      \SI{45}{\centi\meter}
+    },
+    ylabel style={align=center}, ylabel=vertical surface\\displacement, y unit = m,
+    change y base, y SI prefix=micro,
+    xlabel = time, x unit=s,
+    width = 12cm,
+    height = 4cm,
+    semithick]
+    \addplot[width=2pt] table[col sep=comma, x index = 0, y index=1]
+      {generated/\fnamebase:\fname.csv};
+    \addplot[width=2pt, dashed] table[col sep=comma, x index = 0, y index=2]
+      {generated/\fnamebase:\fname.csv};
+    \addplot[width=2pt, dotted] table[col sep=comma, x index = 0, y index=3]
+      {generated/\fnamebase:\fname.csv};
+  \end{axis}
+\end{tikzpicture}
diff --git a/data/2d-effort-over-tolerance.tikz b/data/2d-effort-over-tolerance.tikz
new file mode 100644
index 00000000..21f13f59
--- /dev/null
+++ b/data/2d-effort-over-tolerance.tikz
@@ -0,0 +1,17 @@
+\begin{tikzpicture}[trim axis left, trim axis right]
+  \begin{axis}[
+    semithick,
+    width = 12cm,
+    height = 4cm,
+    xmode=log,
+    %ymin = 0,
+    % scaled y ticks=base 10:0,
+    xlabel = fixed point tolerance,
+    ylabel style={align=center}, ylabel = multigrid\\iterations, % (multigrid steps)
+    extra x ticks       = 1e-5,
+    extra x tick labels = { time-stepping\\tolerance },
+    extra x tick style  = { align=center, grid = major, ticklabel pos=right }
+    ]
+    \addplot[mark=+] table[col sep=comma, y=mg] {generated/fpi-data.csv};
+  \end{axis}
+\end{tikzpicture}
diff --git a/data/2d-velocity-contours-threequakes.tikz b/data/2d-velocity-contours-threequakes.tikz
new file mode 100644
index 00000000..a144cefe
--- /dev/null
+++ b/data/2d-velocity-contours-threequakes.tikz
@@ -0,0 +1,61 @@
+\pgfplotsarraynew\contourlevels{%
+  1\\3\\
+  10\\30\\
+  100\\300\\
+  1000\\3000\\
+}
+
+\def\fname{threequakes:rfpitol=100e-7}
+
+\newread\threequakesminread
+\openin\threequakesminread=generated/timeframe:min:\fname.tex
+\read\threequakesminread to \threequakesmin
+\closein\threequakesminread
+
+\newread\threequakesmaxread
+\openin\threequakesmaxread=generated/timeframe:max:\fname.tex
+\read\threequakesmaxread to \threequakesmax
+\closein\threequakesmaxread
+
+\begin{tikzpicture}[trim axis left, trim axis right]
+  \begin{axis}[
+    xmin=\threequakesmin, xmax=\threequakesmax, max space between ticks=40pt,
+    ymax=0.85,
+    colormap/jet,
+    x tick label style={
+      /pgf/number format/.cd,
+      1000 sep={},
+      /tikz/.cd
+    },
+    y tick label style={
+      /pgf/number format/.cd,
+      fixed, fixed zerofill, precision=2,
+      /tikz/.cd
+    },
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    legend style={font=\small,
+                  at={(1.05,1)},
+                  anchor=north west,
+                  fill=none},
+    ylabel = distance from trench, y unit = m,
+    xlabel = time, x unit=s,
+    width = 12cm, height = 6.5cm,
+    legend cell align=right,
+    contour/labels=false,
+    enlargelimits=false,
+    semithick]
+
+    \pgfplotsinvokeforeach{0,2,4,6} {
+      \pgfplotscolormapaccess[0:7]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \def\fnameX{generated/2d-velocity-contours:\fname:level:%
+        \pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX;
+      \addlegendimage{line legend,color=mycolor#1}
+      \addlegendentry{%
+        \SI{\pgfplotsarrayvalueofelem#1\of\contourlevels}{\micro\meter/\second}}
+    };
+  \end{axis}
+\end{tikzpicture}
diff --git a/data/2d-velocity-contours-zoom.tikz b/data/2d-velocity-contours-zoom.tikz
new file mode 100644
index 00000000..24b77cf4
--- /dev/null
+++ b/data/2d-velocity-contours-zoom.tikz
@@ -0,0 +1,51 @@
+\pgfplotsarraynew\contourlevels{%
+  1\\3\\
+  10\\30\\
+  100\\300\\
+  1000\\3000\\
+}
+
+\def\fname{zoom:rfpitol=100e-7}
+\begin{tikzpicture}[trim axis left, trim axis right]
+  \begin{axis}[
+    max space between ticks=40pt,
+    ymax=0.7,
+    colormap/jet,
+    x tick label style={
+      /pgf/number format/.cd,
+      fixed, fixed zerofill, precision=2,
+      1000 sep={},
+      /tikz/.cd
+    },
+    y tick label style={
+      /pgf/number format/.cd,
+      fixed, fixed zerofill, precision=2,
+      /tikz/.cd
+    },
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    legend style={font=\small,
+                  at={(1.05,1)},
+                  anchor=north west,
+                  fill=none},
+    ylabel = distance from trench, y unit = m,
+    xlabel = time, x unit=s,
+    width = 12cm, height = 6.5cm,
+    legend cell align=right,
+    enlargelimits=false,
+    contour/labels=false,
+    semithick]
+
+    \pgfplotsinvokeforeach{0,...,6} { % level 7 is empty
+      \pgfplotscolormapaccess[0:7]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \def\fnameX{generated/2d-velocity-contours:\fname:level:%
+        \pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX;
+      \addlegendimage{line legend,color=mycolor#1}
+      \addlegendentry{%
+        \SI{\pgfplotsarrayvalueofelem#1\of\contourlevels}{\micro\meter/\second}}
+    };
+  \end{axis}
+\end{tikzpicture}
diff --git a/data/3d-performance.tikz b/data/3d-performance.tikz
new file mode 100644
index 00000000..9eba91b8
--- /dev/null
+++ b/data/3d-performance.tikz
@@ -0,0 +1,57 @@
+\def\fname{rtol=1e-5_diam=1e-2}
+
+\newread\threequakesminread
+\openin\threequakesminread=generated/timeframe:min:threequakes:\fname.tex
+\read\threequakesminread to \threequakesmin
+\closein\threequakesminread
+
+\newread\threequakesmaxread
+\openin\threequakesmaxread=generated/timeframe:max:threequakes:\fname.tex
+\read\threequakesmaxread to \threequakesmax
+\closein\threequakesmaxread
+
+\begin{tikzpicture}[trim axis group left, trim axis group right]
+  \begin{groupplot}[
+    xmin=\threequakesmin, xmax=\threequakesmax,
+    max space between ticks=40pt,
+    x tick label style={
+      /pgf/number format/.cd,
+      1000 sep={},
+      /tikz/.cd
+    },
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    group style={
+      x descriptions at = edge bottom,
+      group size=1 by 3,
+      vertical sep=0cm
+    },
+    height=3.5cm, width=12cm,
+    enlargelimits=false]
+
+    \nextgroupplot[
+    semithick,
+    ylabel style={align=center}, ylabel = time step\\size, y unit = s,
+    ytick={1e-3,1e-2,1e-1},
+    ymax = 1, ymin = 1e-4,
+    ymode = log]
+    \addplot[const plot, mark=none] table[col sep=comma, y=timeIncrement]
+    {generated/3d-performance:\fname.csv};
+    \nextgroupplot[
+    semithick,
+    ylabel style={align=center}, ylabel = fixed-point\\iterations,
+    ytick={2,4,6,8},
+    ymin=0, ymax=10]
+    \addplot[const plot, mark=none] table[col sep=comma, y=fixedPointIterations]
+    {generated/3d-performance:\fname.csv};
+    \nextgroupplot[
+    semithick,
+    xlabel = time, x unit = s,
+    ylabel style={align=center}, ylabel=multigrid\\iterations,
+    ytick={5,10,15,20},
+    ymin=0, ymax=25
+    ]
+    \addplot[const plot, mark=none] table[col sep=comma, y=multiGridIterations]
+    {generated/3d-performance:\fname.csv};
+  \end{groupplot}
+\end{tikzpicture}
diff --git a/data/3d-velocity-contours.tikz b/data/3d-velocity-contours.tikz
new file mode 100644
index 00000000..0bd999b9
--- /dev/null
+++ b/data/3d-velocity-contours.tikz
@@ -0,0 +1,156 @@
+\def\fname{generated/3d-velocity-contours:rtol=1e-5_diam=1e-2}
+\pgfplotstableread[col sep=comma]{\fname:times.csv}\myloadedtable
+
+\pgfplotsarraynew\contourlevels{%
+  1\\2\\3\\5\\%
+  10\\20\\30\\50\\%
+  100\\200\\300\\500\\%
+  1000\\
+}
+
+\begin{tikzpicture}[trim axis group left, trim axis group right]
+  \begin{groupplot}[
+    group style={
+      y descriptions at = edge left,
+      group size=6 by 1,
+      horizontal sep=0cm
+    },
+    ymin=-0.30, ymax= 0.30,
+    enlarge x limits=false,
+    colormap/jet,
+    y tick label style={
+      /pgf/number format/.cd,
+      fixed, fixed zerofill, precision=2,
+      /tikz/.cd
+    },
+    ytick = {-0.30,-0.20,-0.10,0.00,0.10,0.20,0.30},
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    width = 3.5cm, height = 6cm,
+    enlargelimits=false,
+    contour/labels=false,
+    %
+    groupplot xlabel={distance from trench [\si{\meter}]},
+    ]
+
+    \nextgroupplot[semithick, xlabel = {
+      \pgfplotstablegetelem{0}{times}\of\myloadedtable%
+      $t_0 \approx
+      \SI[round-mode=places,round-precision=0]{\pgfplotsretval}{\second}$
+    },
+    ylabel = width, y unit = m]
+    \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30);           % X
+    \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y
+    \pgfplotsinvokeforeach{0,...,12} {
+      \pgfplotscolormapaccess[0:14]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+
+      \pgfplotstablegetelem{0}{timeSteps}\of\myloadedtable
+      \edef\fnameX{\fname:%
+        step:\pgfplotsretval:%
+        level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}] table \fnameX;
+    };
+
+    \nextgroupplot[semithick, xlabel = {
+      \pgfplotstablegetelem{1}{timeOffsets}\of\myloadedtable%
+      $t_0 +
+      \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$
+    }]
+    \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30);           % X
+    \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y
+    \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty
+      \pgfplotscolormapaccess[0:14]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \pgfplotstablegetelem{1}{timeSteps}\of\myloadedtable
+      \edef\fnameX{\fname:%
+        step:\pgfplotsretval:%
+        level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}] table \fnameX;
+    };
+
+    \nextgroupplot[semithick, xlabel = {
+      \pgfplotstablegetelem{2}{timeOffsets}\of\myloadedtable%
+      $t_0 +
+      \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$
+    }]
+    \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30);           % X
+    \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y
+    \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty
+      \pgfplotscolormapaccess[0:14]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \pgfplotstablegetelem{2}{timeSteps}\of\myloadedtable
+      \edef\fnameX{\fname:%
+        step:\pgfplotsretval:%
+        level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}] table \fnameX;
+    };
+
+    \nextgroupplot[semithick, xlabel = {
+      \pgfplotstablegetelem{3}{timeOffsets}\of\myloadedtable%
+      $t_0 +
+      \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$
+    },
+    legend columns=4,
+    legend cell align=right,
+    legend style={font=\small,
+                  at={(0,1.05)},
+                  anchor=south,
+                  fill=none},
+    ]
+    \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30);           % X
+    \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y
+    \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty
+      \pgfplotscolormapaccess[0:14]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \pgfplotstablegetelem{3}{timeSteps}\of\myloadedtable
+      \edef\fnameX{\fname:%
+        step:\pgfplotsretval:%
+        level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}, forget plot] table \fnameX;
+      \addlegendimage{line legend,color=mycolor#1}
+      \addlegendentry{%
+        \SI{\pgfplotsarrayvalueofelem#1\of\contourlevels}{\micro\meter/\second}}
+    };
+
+    \nextgroupplot[semithick, xlabel = {
+      \pgfplotstablegetelem{4}{timeOffsets}\of\myloadedtable%
+      $t_0 +
+      \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$
+    }]
+    \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30);           % X
+    \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y
+    \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty
+      \pgfplotscolormapaccess[0:14]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \pgfplotstablegetelem{4}{timeSteps}\of\myloadedtable
+      \edef\fnameX{\fname:%
+        step:\pgfplotsretval:%
+        level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}] table \fnameX;
+    };
+
+    \nextgroupplot[semithick, xlabel = {
+      \pgfplotstablegetelem{5}{timeOffsets}\of\myloadedtable%
+      $t_0 +
+      \SI[round-mode=places,round-precision=2]{\pgfplotsretval}{\second}$
+    }]
+    \draw[color=gray!20] (0.162533,-0.30) -- (0.162533,+0.30);           % X
+    \draw[color=gray!20] (0.362533+0.05,-0.30) -- (0.362533-0.05,+0.30); % Y
+    \pgfplotsinvokeforeach{0,...,12} { % level 13 and 14 are empty
+      \pgfplotscolormapaccess[0:14]{#1}{jet}
+      \def\TEMP{\definecolor{mycolor#1}{rgb}}
+      \expandafter\TEMP\expandafter{\pgfmathresult}
+      \pgfplotstablegetelem{5}{timeSteps}\of\myloadedtable
+      \edef\fnameX{\fname:%
+        step:\pgfplotsretval:%
+        level:\pgfplotsarrayvalueofelem#1\of\contourlevels.tex}
+      \addplot[contour prepared={draw color=mycolor#1}] table \fnameX;
+    };
+  \end{groupplot}
+\end{tikzpicture}
diff --git a/data/boxplot.tikz b/data/boxplot.tikz
new file mode 100644
index 00000000..9f087cc4
--- /dev/null
+++ b/data/boxplot.tikz
@@ -0,0 +1,43 @@
+\def\simulationtag{rfpitol=100e-7}
+\begin{tikzpicture}[trim axis group left, trim axis group right]
+  \begin{groupplot}[
+    tick label style={font=\footnotesize},
+    label style={font=\small},
+    %
+    group style={
+      y descriptions at = edge left,
+      group size=3 by 1,
+      horizontal sep=0.75cm
+    },
+    height=4cm,
+    width=4.5cm,
+    %
+    ytick={1,2,3},
+    yticklabels={experiment, simulation}
+    ]
+    %
+    \nextgroupplot[semithick, xlabel = recurrence time, x unit = s, xmode=log,
+    log ticks with fixed point, xtick={5,10,20,40}]
+    \addplot[mark=+, boxplot={ box extend = 0.5 }]
+    table[y index=0] {generated/boxplot-data:lab:recurrence.tex};
+    \addplot[mark=+, boxplot={ box extend = 0.5 }]
+    table[y index=0] {generated/boxplot-data:simulation:\simulationtag:recurrence.tex};
+    %
+    \nextgroupplot[semithick, xlabel = rupture width, x unit=m, xmin=0, xmax=0.4,
+    extra x ticks       = 0.2,
+    extra x tick labels = ,
+    extra x tick style  = { grid = major }
+    ]
+    \addplot[mark=+, boxplot={ box extend = 0.5 }]
+    table[y index=0] {generated/boxplot-data:lab:ruptureWidth.tex};
+    \addplot[mark=+, boxplot={ box extend = 0.5 }]
+    table[y index=0] {generated/boxplot-data:simulation:\simulationtag:ruptureWidth.tex};
+    %
+    \nextgroupplot[semithick, xlabel = peak slip, x unit=mm, xmode=log, log ticks with fixed point,
+    xtick={0.03, 0.06, 0.12}]
+    \addplot[mark=+, boxplot={ box extend = 0.5 }]
+    table[y index=0] {generated/boxplot-data:lab:peakSlip.tex};
+    \addplot[mark=+, boxplot={ box extend = 0.5 }]
+    table[y index=0] {generated/boxplot-data:simulation:\simulationtag:peakSlip.tex};
+  \end{groupplot}
+\end{tikzpicture}
diff --git a/data/config.ini b/data/config.ini
new file mode 100644
index 00000000..a3a37a49
--- /dev/null
+++ b/data/config.ini
@@ -0,0 +1,4 @@
+[directories]
+simulation = ~/group/publications/2016-PippingKornhuberRosenauOncken
+experiment = ~/group/publications/2016-RosenauCorbiDominguezRudolfRitterPipping
+output     = generated
diff --git a/data/includes.tex b/data/includes.tex
new file mode 100644
index 00000000..32594a4b
--- /dev/null
+++ b/data/includes.tex
@@ -0,0 +1,51 @@
+\usepackage{pgfplots}
+\pgfplotsset{compat=1.11} % FIXME: 1.12 would be nice; debian:8.7 only has 1.11
+\usepackage{pgfplotstable}
+\usepgfplotslibrary{groupplots}
+\usepgfplotslibrary{statistics}
+\usepgfplotslibrary{units}
+
+
+%% Typeset the mu from '[xy] SI prefix=micro' as an upright mu
+%% From https://tex.stackexchange.com/a/224574
+\pgfplotsset{
+  x SI prefix/micro/.style={/pgfplots/axis base prefix={axis x base 6 prefix \micro}},
+  y SI prefix/micro/.style={/pgfplots/axis base prefix={axis y base 6 prefix \micro}},
+  z SI prefix/micro/.style={/pgfplots/axis base prefix={axis z base 6 prefix \micro}},
+  unit code/.code 2 args={\si{#1#2}},
+}
+
+%% Add support for 'groupplot [xy]label'
+%% From http://tex.stackexchange.com/a/117935/16940, see also
+%% https://sourceforge.net/p/pgfplots/feature-requests/48/
+\makeatletter
+\pgfplotsset{
+    groupplot xlabel/.initial={},
+    every groupplot x label/.style={
+        at={($({\pgfplots@group@name\space c1r\pgfplots@group@rows.west}|-{\pgfplots@group@name\space c1r\pgfplots@group@rows.outer south})!0.5!({\pgfplots@group@name\space c\pgfplots@group@columns r\pgfplots@group@rows.east}|-{\pgfplots@group@name\space c\pgfplots@group@columns r\pgfplots@group@rows.outer south})$)},
+        anchor=north,
+    },
+    groupplot ylabel/.initial={},
+    every groupplot y label/.style={
+            rotate=90,
+        at={($({\pgfplots@group@name\space c1r1.north}-|{\pgfplots@group@name\space c1r1.outer
+west})!0.5!({\pgfplots@group@name\space c1r\pgfplots@group@rows.south}-|{\pgfplots@group@name\space c1r\pgfplots@group@rows.outer west})$)},
+        anchor=south
+    },
+    execute at end groupplot/.code={%
+      \node [/pgfplots/every groupplot x label]
+{\pgfkeysvalueof{/pgfplots/groupplot xlabel}};
+      \node [/pgfplots/every groupplot y label]
+{\pgfkeysvalueof{/pgfplots/groupplot ylabel}};
+    }
+}
+
+\def\endpgfplots@environment@groupplot{%
+    \endpgfplots@environment@opt%
+    \pgfkeys{/pgfplots/execute at end groupplot}%
+    \endgroup%
+}
+\makeatother
+
+%% Have \includegraphics{} support tikz files
+\usepackage{tikzscale}
\ No newline at end of file
diff --git a/data/standalone/2d-dip-contours-performance.tex b/data/standalone/2d-dip-contours-performance.tex
new file mode 100644
index 00000000..8df31895
--- /dev/null
+++ b/data/standalone/2d-dip-contours-performance.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\includegraphics{2d-dip-contours-performance.tikz}
+\end{document}
diff --git a/data/standalone/2d-dip-single-points.tex b/data/standalone/2d-dip-single-points.tex
new file mode 100644
index 00000000..eaadd61b
--- /dev/null
+++ b/data/standalone/2d-dip-single-points.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\includegraphics{2d-dip-single-points.tikz}
+\end{document}
diff --git a/data/standalone/2d-effort-over-tolerance.tex b/data/standalone/2d-effort-over-tolerance.tex
new file mode 100644
index 00000000..45f6bc94
--- /dev/null
+++ b/data/standalone/2d-effort-over-tolerance.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\includegraphics{2d-effort-over-tolerance.tikz}
+\end{document}
diff --git a/data/standalone/2d-velocity-contours-threequakes.tex b/data/standalone/2d-velocity-contours-threequakes.tex
new file mode 100644
index 00000000..2e2d9cb1
--- /dev/null
+++ b/data/standalone/2d-velocity-contours-threequakes.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\includegraphics{2d-velocity-contours-threequakes}
+\end{document}
diff --git a/data/standalone/2d-velocity-contours-zoom.tex b/data/standalone/2d-velocity-contours-zoom.tex
new file mode 100644
index 00000000..e24d742d
--- /dev/null
+++ b/data/standalone/2d-velocity-contours-zoom.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\includegraphics{2d-velocity-contours-zoom}
+\end{document}
diff --git a/data/standalone/3d-performance.tex b/data/standalone/3d-performance.tex
new file mode 100644
index 00000000..b1e3456f
--- /dev/null
+++ b/data/standalone/3d-performance.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\includegraphics{3d-performance.tikz}
+\end{document}
diff --git a/data/standalone/3d-velocity-contours.tex b/data/standalone/3d-velocity-contours.tex
new file mode 100644
index 00000000..be7f8c79
--- /dev/null
+++ b/data/standalone/3d-velocity-contours.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\includegraphics{3d-velocity-contours.tikz}
+\end{document}
diff --git a/data/standalone/Makefile b/data/standalone/Makefile
new file mode 100644
index 00000000..c9e461a0
--- /dev/null
+++ b/data/standalone/Makefile
@@ -0,0 +1,18 @@
+PDFs=\
+  2d-dip-contours-performance.pdf \
+  2d-dip-single-points.pdf \
+  2d-effort-over-tolerance.pdf \
+  2d-velocity-contours-threequakes.pdf \
+  2d-velocity-contours-zoom.pdf \
+  3d-performance.pdf \
+  3d-velocity-contours.pdf \
+  boxplot.pdf
+PNGs=$(PDFs:.pdf=.png)
+
+pdf: $(PDFs)
+%.pdf: standalone/%.tex
+	latexmk -pdf $<
+
+png: $(PNGs)
+%.png: %.pdf
+	convert -density 300 $< -quality 100 $@
diff --git a/data/standalone/boxplot.tex b/data/standalone/boxplot.tex
new file mode 100644
index 00000000..1fd38393
--- /dev/null
+++ b/data/standalone/boxplot.tex
@@ -0,0 +1,7 @@
+\documentclass[border={3cm 0cm}]{standalone}
+\usepackage{siunitx}
+\input{includes}
+
+\begin{document}
+\input{boxplot.tikz}
+\end{document}
diff --git a/data/tools/2d-dip-contours.R b/data/tools/2d-dip-contours.R
new file mode 100644
index 00000000..04b36652
--- /dev/null
+++ b/data/tools/2d-dip-contours.R
@@ -0,0 +1,108 @@
+source('tools/support/findQuakes.R')
+source('tools/support/writeContours.R')
+Rcpp::sourceCpp('tools/support/trapezoidal.cpp')
+
+finalTime              <- 1000 # s
+specialTrenchDistances <- c(0.15,0.30,0.45) # m
+convergenceVelocity    <- 5e-5 # m/s
+
+last      <- function(x) x[[length(x)]]
+paste.    <- function(...) paste(..., sep='.')
+pasteColon<- function(...) paste(..., sep=':')
+
+directories <- ini::read.ini('config.ini')$directories
+dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE)
+for (basedir in c("rfpitol=100e-7")) {
+  dir          <- file.path(directories[['simulation']],
+                            '2d-lab-fpi-tolerance', basedir)
+  h5file       <- h5::h5file(file.path(dir, 'output.h5'), 'r')
+  relativeTime <- h5file['relativeTime'][]
+  realTime     <- finalTime * relativeTime
+
+  calcMask     <- relativeTime >= 0.7
+  calcTime     <- realTime[calcMask]
+  calcDuration <- last(calcTime) - calcTime[[1]]
+  calcRange    <- range(which(calcMask))
+  calcLength   <- sum(calcMask)
+
+  ## We are interested in an enlarged time range around actual events here,
+  ## (and no other quantities!) hence we pass a very low velocity here.
+  quakes           <- findQuakes(1e-6 + convergenceVelocity,
+                                 h5file['/frictionalBoundary/velocity'][,,],
+                                 indices = calcRange[1]:calcRange[2])
+  quakes$beginning <- realTime[quakes$beginningIndex]
+  quakes$ending    <- realTime[quakes$endingIndex]
+  quakes$duration  <- quakes$ending - quakes$beginning
+  numQuakes        <- nrow(quakes)
+
+  relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']],
+                               quakes[[numQuakes,  'ending']]), f=0.02)
+  threeQuakeTimeMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]])
+
+  plotMask   <- threeQuakeTimeMask
+  plotTime   <- realTime[plotMask]
+  plotRange  <- range(which(plotMask))
+  plotLength <- sum(plotMask)
+
+  write(relaxedTime[[1]],
+        file.path(directories[['output']],
+                  paste.(pasteColon('timeframe', 'min', 'threequakes', basedir),
+                         'tex')))
+  write(relaxedTime[[2]],
+        file.path(directories[['output']],
+                  paste.(pasteColon('timeframe', 'max', 'threequakes', basedir),
+                         'tex')))
+
+  surfaceCoordinates    <- h5file['/surface/coordinates'][]
+  surfaceTrenchDistance <- surfaceCoordinates[,1] / cos(atan(.27))
+  perm                  <- order(surfaceTrenchDistance)
+
+  displacement <- h5file['/surface/displacement']
+  # This is the displacement imposed through the Dirichlet condition at the last node
+  displacementOffset <- displacement[calcRange[1]:calcRange[2],last(perm),1]
+  balancedSurfaceDisplacement <- matrix(nrow = plotLength, ncol = displacement@dim[2])
+  for (k in 1:displacement@dim[2]) {
+    d <- displacement[calcRange[1]:calcRange[2],k,1:2]
+    d[,,1] <- d[,,1] - displacementOffset
+    # We're in a tilted coordinate system
+    dv <- -sin(atan(.27))*d[,,1] + cos(atan(.27))*d[,,2]
+    meanVertSurfaceDisplacement  <- trapezoidal(calcTime, dv) / calcDuration
+    balancedSurfaceDisplacement[,k] <- (dv - meanVertSurfaceDisplacement)[
+      (plotRange[1] - calcRange[1] + 1):(plotRange[2] - calcRange[1] + 1)
+    ]
+  }
+
+  ## Interpolate velocity to special points from surrounding velocities
+  {
+    data <- matrix(nrow=plotLength, ncol=1+length(specialTrenchDistances))
+    data[,1] <- plotTime
+    for (k in seq(plotLength)) {
+      interpolant <- approxfun(surfaceTrenchDistance[perm],
+                               balancedSurfaceDisplacement[k,perm])
+      for (i in seq(specialTrenchDistances)) {
+        specialTrenchDistance <- specialTrenchDistances[[i]]
+        data[k,i+1] <- interpolant(specialTrenchDistance)
+      }
+    }
+    singleDataName <- file.path(directories[['output']],
+                                paste.(pasteColon('dip-single-points', basedir),
+                                       'csv'))
+    write.csv(data, singleDataName, row.names = FALSE)
+  }
+  h5::h5close(h5file)
+
+  printlevels <- c('-40','-20','-10','-5','-2.5','0','2.5','5','10','20','40')
+  levels      <- as.numeric(printlevels) * 1e-6
+
+  ret <- contourLines(plotTime,
+                      surfaceTrenchDistance[perm],
+                      balancedSurfaceDisplacement[,perm],
+                      levels=levels)
+
+  for (i in seq(printlevels))
+    writeContours(ret, levels[[i]],
+                  file.path(directories[['output']],
+                            paste.(pasteColon('2d-dip-contours', basedir,
+                                              'level', printlevels[[i]]),
+                                   'tex')))
+}
diff --git a/data/tools/2d-event-writer.R b/data/tools/2d-event-writer.R
new file mode 100644
index 00000000..fffe5e28
--- /dev/null
+++ b/data/tools/2d-event-writer.R
@@ -0,0 +1,68 @@
+source('tools/support/findQuakes.R')
+
+finalTime              <- 1000 # s
+convergenceVelocity    <- 5e-5 # m/s
+criticalVelocity       <- 1000e-6 + convergenceVelocity
+
+paste.    <- function(...) paste(..., sep='.')
+pasteColon<- function(...) paste(..., sep=':')
+
+directories <- ini::read.ini('config.ini')$directories
+dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE)
+for (basedir in c("rfpitol=100e-7")) {
+  dir          <- file.path(directories[['simulation']],
+                            '2d-lab-fpi-tolerance', basedir)
+  h5file       <- h5::h5file(file.path(dir, 'output.h5'), 'r')
+  relativeTime <- h5file['relativeTime'][]
+  realTime     <- finalTime * relativeTime
+
+  velocityProxy<- h5file['/frictionalBoundary/velocity']
+
+  quakes <- findQuakes(criticalVelocity, velocityProxy,
+                       indices = 1:dim(velocityProxy)[1], 1)
+
+  basalCoordinates <- h5file['/frictionalBoundary/coordinates'][]
+
+  maximumVelocities<- maxVelocity(velocityProxy[,,1])
+  displacement     <- h5file['/frictionalBoundary/displacement']
+  numVertices      <- dim(displacement)[[2]]
+  for (quakeID in seq(nrow(quakes))) {
+    qb <- quakes[[quakeID,'beginningIndex']]
+    qe <- quakes[[quakeID,'endingIndex']]
+    localSlippingTimes <- abs(velocityProxy[qb:qe,,1][,,1]) > criticalVelocity
+
+    qd   <- displacement[qb:qe,,1]
+    slip <- vector(mode='numeric', length=numVertices)
+    for (i in seq(numVertices)) {
+      if (any(localSlippingTimes[,i])) {
+        begs <- positiveStarts(localSlippingTimes[,i])
+        ends <- negativeStarts(localSlippingTimes[,i])
+        slip[i]<- sum(qd[ends,i,] - qd[begs,i,])
+      }
+    }
+    quakes[quakeID,'peakSlip']     <- max(abs(slip))
+    quakes[quakeID,'peakSlipRate'] <- max(maximumVelocities[qb:qe])
+
+    maxRuptureWidth <- 0
+    for (ts in seq(dim(localSlippingTimes)[[1]])) {
+      st <- localSlippingTimes[ts,]
+      if (!any(st))
+        next;
+
+      slippingCoordinates <- basalCoordinates[st,1] # x-coordinate only
+      maxRuptureWidth <- max(maxRuptureWidth, diff(range(slippingCoordinates)))
+    }
+    quakes[quakeID,'ruptureWidth'] <- maxRuptureWidth
+  }
+  h5::h5close(h5file)
+
+  quakes$beginning <- realTime[quakes$beginningIndex]
+  quakes$ending    <- realTime[quakes$endingIndex]
+
+  write.csv(quakes[c('beginning','ending',
+                     'peakSlip','peakSlipRate',
+                     'ruptureWidth')],
+            row.names = FALSE, quote = FALSE,
+            file = file.path(directories[['output']],
+                             paste.(pasteColon('events', basedir), 'csv')))
+}
diff --git a/data/tools/2d-fpi-tolerance.R b/data/tools/2d-fpi-tolerance.R
new file mode 100644
index 00000000..1442e4e6
--- /dev/null
+++ b/data/tools/2d-fpi-tolerance.R
@@ -0,0 +1,41 @@
+rfpitols <- c('1e-7', '2e-7', '3e-7', '5e-7',
+              '10e-7', '20e-7', '30e-7', '50e-7',
+              '100e-7', '200e-7', '300e-7', '500e-7',
+              '1000e-7', '2000e-7', '3000e-7', '5000e-7',
+              '10000e-7', '20000e-7', '30000e-7', '50000e-7',
+              '100000e-7')
+numEntries <- length(rfpitols)
+
+data <- data.frame(row.names = rfpitols,
+                   tol = rep(NA, numEntries),
+                   time = rep(NA, numEntries),
+                   fpi = rep(NA, numEntries),
+                   mg = rep(NA, numEntries))
+
+directories <- ini::read.ini('config.ini')$directories
+dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE)
+for (rfpitol in rfpitols) {
+  basedir <- paste('rfpitol', rfpitol, sep='=')
+  dir     <- file.path(directories[['simulation']],
+                       '2d-lab-fpi-tolerance', basedir)
+  h5file  <- h5::h5file(file.path(dir, 'output.h5'), 'r')
+
+  data[rfpitol,'tol'] <- as.numeric(rfpitol)
+
+  relativeTimeProxy <- h5file['/relativeTime']
+  relativeTimeLen <- relativeTimeProxy@dim
+  data[rfpitol,'time'] <- relativeTimeProxy[relativeTimeProxy@dim]
+
+  ## FIXME: why do we drop the first entry?
+  fixedPointIterationsProxy <- h5file["/iterations/fixedPoint/total"]
+  fixedPointIterationsLen <- fixedPointIterationsProxy@dim
+  data[rfpitol,'fpi'] <- sum(fixedPointIterationsProxy[2:fixedPointIterationsLen])
+
+  multiGridIterationsProxy <- h5file["/iterations/multiGrid/total"]
+  multiGridIterationsLen <- multiGridIterationsProxy@dim
+  data[rfpitol,'mg'] <- sum(multiGridIterationsProxy[2:multiGridIterationsLen])
+  h5::h5close(h5file)
+}
+
+write.csv(data, file.path(directories[['output']], 'fpi-data.csv'),
+          row.names = FALSE, quote = FALSE)
diff --git a/data/tools/2d-performance.R b/data/tools/2d-performance.R
new file mode 100644
index 00000000..0f3ab59c
--- /dev/null
+++ b/data/tools/2d-performance.R
@@ -0,0 +1,58 @@
+source('tools/support/findQuakes.R')
+
+finalTime           <- 1000 # s
+convergenceVelocity <- 5e-5 # m/s
+
+paste.    <- function(...) paste(..., sep='.')
+pasteColon<- function(...) paste(..., sep=':')
+
+directories <- ini::read.ini('config.ini')$directories
+dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE)
+for (basedir in c("rfpitol=100e-7")) {
+  dir          <- file.path(directories[['simulation']],
+                            '2d-lab-fpi-tolerance', basedir)
+  h5file       <- h5::h5file(file.path(dir, 'output.h5'), 'r')
+  relativeTime <- h5file['relativeTime'][]
+  realTime     <- finalTime * relativeTime
+
+  velocityProxy<- h5file['/frictionalBoundary/velocity']
+
+  ## We are interested in an enlarged time range around actual events here,
+  ## (and no other quantities!) hence we pass a very low velocity here.
+  quakes <- findQuakes(1e-6 + convergenceVelocity, velocityProxy,
+                       indices = 1:dim(velocityProxy)[1], 1)
+  quakes$beginning <- realTime[quakes$beginningIndex]
+  quakes$ending    <- realTime[quakes$endingIndex]
+  quakes$duration  <- quakes$ending - quakes$beginning
+  numQuakes        <- nrow(quakes)
+
+  relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']],
+                               quakes[[numQuakes,  'ending']]), f=0.02)
+  threeQuakeTimeMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]])
+  plotMask   <- threeQuakeTimeMask
+  plotIndices<- which(plotMask)
+  plotIndices<- c(plotIndices[1]-1,plotIndices,plotIndices[length(plotIndices)]+1)
+
+  write(relaxedTime[[1]],
+        file.path(directories[['output']],
+                  paste.(pasteColon('timeframe', 'min', 'threequakes',
+                                    basedir), 'tex')))
+  write(relaxedTime[[2]],
+        file.path(directories[['output']],
+                  paste.(pasteColon('timeframe', 'max', 'threequakes',
+                                    basedir), 'tex')))
+
+  timeWindow = realTime[plotIndices]
+
+  relativeTau          <- h5file['relativeTimeIncrement'][]
+  fixedPointIterations <- h5file['/iterations/fixedPoint/final'][]
+  multiGridIterations  <- h5file['/iterations/multiGrid/final'][]
+  write.csv(data.frame(time = timeWindow,
+                       timeIncrement = finalTime * relativeTau[plotIndices],
+                       fixedPointIterations = fixedPointIterations[plotIndices],
+                       multiGridIterations = multiGridIterations[plotIndices]),
+            file.path(directories[['output']],
+                      paste.(pasteColon('2d-performance', basedir), 'csv')),
+            row.names = FALSE, quote = FALSE)
+  h5::h5close(h5file)
+}
diff --git a/data/tools/2d-velocity-contours.R b/data/tools/2d-velocity-contours.R
new file mode 100644
index 00000000..dd44112c
--- /dev/null
+++ b/data/tools/2d-velocity-contours.R
@@ -0,0 +1,95 @@
+source('tools/support/findQuakes.R')
+source('tools/support/writeContours.R')
+
+finalTime           <- 1000 # s
+convergenceVelocity <- 5e-5 # m/s
+
+paste.    <- function(...) paste(..., sep='.')
+pasteColon<- function(...) paste(..., sep=':')
+
+directories <- ini::read.ini('config.ini')$directories
+dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE)
+for (basedir in c("rfpitol=100e-7")) {
+  dir <- file.path(directories[['simulation']],
+                   '2d-lab-fpi-tolerance', basedir)
+  h5file       <- h5::h5file(file.path(dir, 'output.h5'), 'r')
+  relativeTime <- h5file['relativeTime'][]
+  realTime     <- finalTime * relativeTime
+
+  velocityProxy<- h5file['/frictionalBoundary/velocity']
+
+  basalCoordinates <- h5file['/frictionalBoundary/coordinates'][]
+  basalTrenchDistance <- basalCoordinates[,1]
+  perm                <- order(basalTrenchDistance)
+  sortedBasalTrenchDistance <- basalTrenchDistance[perm]
+
+  {
+    ## We are interested in an enlarged time range around actual events here,
+    ## (and no other quantities!) hence we pass a very low velocity here.
+    quakes <- findQuakes(1e-6 + convergenceVelocity, velocityProxy,
+                         indices = 1:dim(velocityProxy)[1], 1)
+    quakes$beginning <- realTime[quakes$beginningIndex]
+    quakes$ending    <- realTime[quakes$endingIndex]
+    quakes$duration  <- quakes$ending - quakes$beginning
+    numQuakes        <- nrow(quakes)
+
+    relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']],
+                                 quakes[[numQuakes,  'ending']]), f=0.02)
+    plotMask   <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]])
+    plotIndices<- which(plotMask)
+
+    write(relaxedTime[[1]],
+          file.path(directories[['output']],
+                    paste.(pasteColon('timeframe', 'min', 'threequakes',
+                                      basedir), 'tex')))
+    write(relaxedTime[[2]],
+          file.path(directories[['output']],
+                    paste.(pasteColon('timeframe', 'max', 'threequakes',
+                                      basedir), 'tex')))
+
+    printlevels <- c('1000','100','10','1')
+    levels      <- 1e-6 * as.numeric(printlevels) + convergenceVelocity
+    ret <- contourLines(realTime[plotIndices],
+                        sortedBasalTrenchDistance,
+                        abs(velocityProxy[plotIndices,perm,1][,,1]),
+                        levels = levels)
+
+    for (i in seq(printlevels))
+      writeContours(ret, levels[[i]],
+                    file.path(directories[['output']],
+                              paste.(pasteColon('2d-velocity-contours',
+                                                'threequakes', basedir, 'level',
+                                                printlevels[[i]]), 'tex')))
+  }
+  {
+    ## We are interested in an enlarged time range around actual events here,
+    ## (and no other quantities!) hence we pass a rather low velocity here.
+    quakes <- findQuakes(300e-6 + convergenceVelocity, velocityProxy,
+                         indices = 1:dim(velocityProxy)[1], 1)
+    quakes$beginning <- realTime[quakes$beginningIndex]
+    quakes$ending    <- realTime[quakes$endingIndex]
+    quakes$duration  <- quakes$ending - quakes$beginning
+    numQuakes        <- nrow(quakes)
+    quake            <- quakes[numQuakes,]
+    relaxedTime      <-
+      c(quake[['beginning']] - 0.9*(quake[['ending']] - quake[['beginning']]),
+        quake[['ending']]    + 0.1*(quake[['ending']] - quake[['beginning']]))
+    plotMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]])
+    plotIndices<- which(plotMask)
+
+    printlevels <- c('3000','1000','300','100','30','10','3','1')
+    levels      <- 1e-6 * as.numeric(printlevels) + convergenceVelocity
+    ret <- contourLines(realTime[plotIndices],
+                        sortedBasalTrenchDistance,
+                        abs(velocityProxy[plotIndices,perm,1][,,1]),
+                        levels = levels)
+
+    for (i in seq(printlevels))
+      writeContours(ret, levels[[i]],
+                    file.path(directories[['output']],
+                              paste.(pasteColon('2d-velocity-contours',
+                                                'zoom', basedir, 'level',
+                                                printlevels[[i]]), 'tex')))
+  }
+  h5::h5close(h5file)
+}
diff --git a/data/tools/3d-performance.R b/data/tools/3d-performance.R
new file mode 100644
index 00000000..d795a5ca
--- /dev/null
+++ b/data/tools/3d-performance.R
@@ -0,0 +1,62 @@
+source('tools/support/findQuakes.R')
+
+finalTime           <- 1000 # s
+convergenceVelocity <- 5e-5 # m/s
+
+paste.    <- function(...) paste(..., sep='.')
+pasteColon<- function(...) paste(..., sep=':')
+
+directories <- ini::read.ini('config.ini')$directories
+dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE)
+for (basedir in c("rtol=1e-5_diam=1e-2")) {
+  dir          <- file.path(directories[['simulation']],
+                            '3d-lab', basedir)
+  h5file       <- h5::h5file(file.path(dir, 'output.h5'), 'r')
+  relativeTime <- h5file['relativeTime'][]
+  realTime     <- finalTime * relativeTime
+
+  velocityProxy<- h5file['/frictionalBoundary/velocity']
+
+  ## We are interested in an enlarged time range around actual events here,
+  ## (and no other quantities!) hence we pass a very low velocity here.
+  quakes <- findQuakes(1e-6 + convergenceVelocity, velocityProxy,
+                       ## Note: We only look at the last 2000 timesteps here because
+                       ## we're only interested in the last few events. This
+                       ## dramatically reduces RAM usage and runtime.
+                       indices = seq(dim(velocityProxy)[1]-2000,
+                                     dim(velocityProxy)[1]), c(1,3))
+  quakes$beginning <- realTime[quakes$beginningIndex]
+  quakes$ending    <- realTime[quakes$endingIndex]
+  quakes$duration  <- quakes$ending - quakes$beginning
+  numQuakes        <- nrow(quakes)
+
+  relaxedTime <- extendrange(c(quakes[[numQuakes-2,'beginning']],
+                               quakes[[numQuakes,  'ending']]), f=0.02)
+  threeQuakeTimeMask <- (realTime > relaxedTime[[1]]) & (realTime < relaxedTime[[2]])
+  plotMask   <- threeQuakeTimeMask
+  plotIndices<- which(plotMask)
+  plotIndices<- c(plotIndices[1]-1,plotIndices,plotIndices[length(plotIndices)]+1)
+
+  write(relaxedTime[[1]],
+        file.path(directories[['output']],
+                  paste.(pasteColon('timeframe', 'min', 'threequakes',
+                                    basedir), 'tex')))
+  write(relaxedTime[[2]],
+        file.path(directories[['output']],
+                  paste.(pasteColon('timeframe', 'max', 'threequakes',
+                                    basedir), 'tex')))
+
+  timeWindow = realTime[plotIndices]
+
+  relativeTau          <- h5file['relativeTimeIncrement'][]
+  fixedPointIterations <- h5file['/iterations/fixedPoint/final'][]
+  multiGridIterations  <- h5file['/iterations/multiGrid/final'][]
+  write.csv(data.frame(time = timeWindow,
+                       timeIncrement = finalTime * relativeTau[plotIndices],
+                       fixedPointIterations = fixedPointIterations[plotIndices],
+                       multiGridIterations = multiGridIterations[plotIndices]),
+            file.path(directories[['output']],
+                      paste.(pasteColon('3d-performance', basedir), 'csv')),
+            row.names = FALSE, quote = FALSE)
+  h5::h5close(h5file)
+}
diff --git a/data/tools/3d-velocity-contours.R b/data/tools/3d-velocity-contours.R
new file mode 100644
index 00000000..f50845ea
--- /dev/null
+++ b/data/tools/3d-velocity-contours.R
@@ -0,0 +1,67 @@
+source('tools/support/findQuakes.R')
+source('tools/support/writeContours.R')
+
+finalTime           <- 1000 # s
+convergenceVelocity <- 5e-5 # m/s
+printlevels <- c('1','2','3','5',
+                 '10','20','30','50',
+                 '100','200','300','500',
+                 '1000')
+criticalVelocities  <- 1e-6*as.numeric(printlevels) + convergenceVelocity
+
+paste.    <- function(...) paste(..., sep='.')
+pasteColon<- function(...) paste(..., sep=':')
+
+directories <- ini::read.ini('config.ini')$directories
+dir.create(directories[['output']], recursive=TRUE, showWarnings=FALSE)
+for (basedir in c("rtol=1e-5_diam=1e-2")) {
+  dir          <- file.path(directories[['simulation']],
+                            '3d-lab', basedir)
+  h5file       <- h5::h5file(file.path(dir, 'output.h5'), 'r')
+  relativeTime <- h5file['relativeTime'][]
+  realTime     <- finalTime * relativeTime
+
+  velocityProxy<- h5file['/frictionalBoundary/velocity']
+
+  ## We are interested in an enlarged time range around actual events here,
+  ## (and no other quantities!) hence we pass a rather low velocity here.
+  quakes <- findQuakes(200e-6 + convergenceVelocity, velocityProxy,
+                       ## Note: We only look at the last 1000 timesteps here because
+                       ## we're only interested in the last few events. This
+                       ## dramatically reduces RAM usage and runtime.
+                       indices = seq(dim(velocityProxy)[1]-1000,
+                                     dim(velocityProxy)[1]), c(1,3))
+  quake <- quakes[nrow(quakes)-1,] # Q: why did we not need the -1 in julia?
+  
+  weakPatchGridVelocityProxy <- h5file["/weakPatchGrid/velocity"]
+
+  stepSize <- 30 ## note: should/might differ by time/spatial resolution
+  ts <- seq(quake$beginningIndex, quake$endingIndex, by=stepSize)
+  dd <- data.frame(timeSteps = ts,
+                   times = realTime[ts],
+                   timeOffsets = realTime[ts] - realTime[quake$beginningIndex])
+
+  fname = pasteColon('3d-velocity-contours', basedir)
+  write.csv(dd, row.names = FALSE, quote = FALSE,
+            file = file.path(directories[['output']],
+                             paste.(pasteColon(fname, 'times'), 'csv')))
+
+  weakPatchGridXCoordinates <- h5file["/weakPatchGrid/xCoordinates"][]
+  weakPatchGridZCoordinates <- h5file["/weakPatchGrid/zCoordinates"][]
+  
+  for (t in ts) {
+    m <- weakPatchGridVelocityProxy[t,,,]
+    s <- sqrt(m[,,,1]^2 + m[,,,3]^2)
+    ret <- contourLines(weakPatchGridXCoordinates, weakPatchGridZCoordinates, s,
+                        level=criticalVelocities)
+
+    for (i in seq(printlevels))
+      writeContours(ret, criticalVelocities[[i]],
+                    file.path(directories[['output']],
+                              paste.(pasteColon(fname,
+                                                'step', t,
+                                                'level', printlevels[[i]]),
+                                     'tex')))
+  }
+  h5::h5close(h5file)
+}
diff --git a/data/tools/comparison:lab-sim.R b/data/tools/comparison:lab-sim.R
new file mode 100644
index 00000000..9c43c050
--- /dev/null
+++ b/data/tools/comparison:lab-sim.R
@@ -0,0 +1,42 @@
+paste.    <- function(...) paste(..., sep='.')
+pasteColon<- function(...) paste(..., sep=':')
+
+basedir <- 'rfpitol=100e-7'
+
+directories <- ini::read.ini('config.ini')$directories
+labdata <- within(
+  read.table(unz(file.path(directories[['experiment']],
+                           'B_Scale-model-earthquake-data.zip'),
+                 'scaleEQs_12-31_catalogue.txt'),
+             sep='\t', header=FALSE, comment.char='%',
+             col.names=c('frame',
+                         'meanSlipNature', 'meanSlipLab',
+                         'peakSlipNature', 'peakSlipLab',
+                         'ruptureWidthNature', 'ruptureWidthLab',
+                         'ignored', 'ignored', 'ignored', 'ignored', 'ignored')),
+  {
+    recurrenceLab <- c(NA, diff(frame))/10 # (10Hz camera: 10 frames ~ 1s)
+    meanSlipLab   <- meanSlipLab / 1e6     # micro m -> m
+    peakSlipLab   <- peakSlipLab / 1e6})   # micro m -> m
+## NB: We skip the first two quakes here, for compatibility with my old code
+##     Maybe skipping the first was intentional so that each quake would have
+##     a recurrence time. But skipping the second was certainly an accident
+labdata <- labdata[3:nrow(labdata),]
+
+simdata <- read.csv(file.path(directories[['output']],
+                              paste.(pasteColon('events', basedir), 'csv')))
+
+report <- function(lab, sim, quantity) {
+  write.table(lab, file.path(directories[['output']],
+                             paste.(pasteColon('boxplot-data', 'lab',
+                                               quantity), 'tex')),
+              row.names=FALSE, col.names=FALSE)
+  write.table(sim, file.path(directories[['output']],
+                             paste.(pasteColon('boxplot-data', 'simulation',
+                                               basedir, quantity), 'tex')),
+              row.names=FALSE, col.names=FALSE)
+}
+report(labdata$recurrenceLab, diff(simdata$beginning), 'recurrence')
+report(labdata$ruptureWidthLab, simdata$ruptureWidth, 'ruptureWidth')
+# meters -> millimeters
+report(labdata$peakSlipLab * 1000, simdata$peakSlip*1000, 'peakSlip')
diff --git a/data/tools/generate-2d.bash b/data/tools/generate-2d.bash
new file mode 100755
index 00000000..320720cf
--- /dev/null
+++ b/data/tools/generate-2d.bash
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+set -e
+
+rr() {
+    echo "$(date)" Running: Rscript $@
+    Rscript --vanilla --default-packages=grDevices,methods,stats,utils tools/$@
+}
+
+# contours
+rr 2d-velocity-contours.R
+
+# dip
+rr 2d-dip-contours.R
+
+# iterations / adaptivity
+rr 2d-performance.R
+
+# box plot (one half)
+rr 2d-event-writer.R
+
+# fpi data
+rr 2d-fpi-tolerance.R
+
+date
diff --git a/data/tools/generate-3d.bash b/data/tools/generate-3d.bash
new file mode 100755
index 00000000..f4bed78b
--- /dev/null
+++ b/data/tools/generate-3d.bash
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -e
+
+rr() {
+    echo "$(date)" Running: Rscript $@
+    Rscript --vanilla --default-packages=grDevices,methods,stats,utils tools/$@
+}
+
+# performance
+rr 3d-performance.R
+
+# velocity contours
+rr 3d-velocity-contours.R
+
+date
diff --git a/data/tools/generate-others.bash b/data/tools/generate-others.bash
new file mode 100755
index 00000000..6bf2e29c
--- /dev/null
+++ b/data/tools/generate-others.bash
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -e
+
+rr() {
+    echo "$(date)" Running: Rscript $@
+    Rscript --vanilla --default-packages=grDevices,methods,stats,utils tools/$@
+}
+
+# box plot (one half)
+rr comparison:lab-sim.R
+
+date
diff --git a/data/tools/support/findQuakes.R b/data/tools/support/findQuakes.R
new file mode 100644
index 00000000..698b6498
--- /dev/null
+++ b/data/tools/support/findQuakes.R
@@ -0,0 +1,18 @@
+Rcpp::sourceCpp('tools/support/maxVelocity.cpp')
+Rcpp::sourceCpp('tools/support/negativeStarts.cpp')
+Rcpp::sourceCpp('tools/support/positiveStarts.cpp')
+
+findQuakes <- function (criticalVelocity, velocity, indices, dimensions) {
+  maximumVelocities<- maxVelocity(velocity[indices,,dimensions])
+  slippingTimes  <- maximumVelocities > criticalVelocity
+
+  ns <- negativeStarts(slippingTimes) + indices[[1]] - 1
+  ps <- positiveStarts(slippingTimes) + indices[[1]] - 1
+
+  ## NOTE: we drop incomplete quakes here
+  mlen <- min(length(ns), length(ps))
+  ns <- ns[1:mlen]
+  ps <- ps[1:mlen]
+
+  return(data.frame(endingIndex = ns, beginningIndex = ps))
+}
diff --git a/data/tools/support/maxVelocity.cpp b/data/tools/support/maxVelocity.cpp
new file mode 100644
index 00000000..5294e563
--- /dev/null
+++ b/data/tools/support/maxVelocity.cpp
@@ -0,0 +1,29 @@
+#include <Rcpp.h>
+
+// For std::hypot(x,y)
+// [[Rcpp::plugins(cpp11)]]
+
+// Layout of vectors is such that loops over inner indices are traversed first
+// [[Rcpp::export]]
+Rcpp::NumericVector maxVelocity(Rcpp::NumericVector const &x) {
+  Rcpp::IntegerVector size = x.attr("dim");
+  Rcpp::NumericVector ret(size[0]);
+  switch (size[2]) {
+  case 1:
+    for (size_t ts = 0; ts < size[0]; ++ts)
+      for (size_t coord = 0; coord < size[1]; ++coord)
+        ret[ts] = std::max(ret[ts],
+                           std::abs(x[0 * size[1] * size[0] + coord * size[0] + ts]));
+    break;
+  case 2:
+    for (size_t ts = 0; ts < size[0]; ++ts)
+      for (size_t coord = 0; coord < size[1]; ++coord)
+        ret[ts] = std::max(ret[ts],
+                           std::hypot(x[0 * size[1] * size[0] + coord * size[0] + ts],
+                                      x[1 * size[1] * size[0] + coord * size[0] + ts]));
+    break;
+  default:
+    throw std::range_error("Inadmissible value");
+  }
+  return ret;
+}
diff --git a/data/tools/support/negativeStarts.cpp b/data/tools/support/negativeStarts.cpp
new file mode 100644
index 00000000..940765c2
--- /dev/null
+++ b/data/tools/support/negativeStarts.cpp
@@ -0,0 +1,13 @@
+#include <Rcpp.h>
+
+// [[Rcpp::export]]
+Rcpp::NumericVector negativeStarts(Rcpp::NumericVector const &x) {
+  std::vector<size_t> starts(0);
+  bool prev = false;
+  for (size_t i = 0; i < x.size(); ++i) {
+    if (prev && !x[i])
+      starts.push_back(i+1); // R indices start at 1
+    prev = x[i];
+  }
+  return Rcpp::NumericVector(starts.begin(), starts.end());
+}
diff --git a/data/tools/support/positiveStarts.cpp b/data/tools/support/positiveStarts.cpp
new file mode 100644
index 00000000..3e9498c0
--- /dev/null
+++ b/data/tools/support/positiveStarts.cpp
@@ -0,0 +1,14 @@
+#include <Rcpp.h>
+
+// [[Rcpp::export]]
+Rcpp::NumericVector positiveStarts(Rcpp::NumericVector const &x) {
+  std::vector<size_t> starts(0);
+  bool prev = false;
+  for (size_t i = 0; i < x.size(); ++i) {
+    if (!prev && x[i])
+      starts.push_back(i+1); // R indices start at 1
+    prev = x[i];
+  }
+  return Rcpp::NumericVector(starts.begin(), starts.end());
+}
+
diff --git a/data/tools/support/trapezoidal.cpp b/data/tools/support/trapezoidal.cpp
new file mode 100644
index 00000000..3b4833d6
--- /dev/null
+++ b/data/tools/support/trapezoidal.cpp
@@ -0,0 +1,9 @@
+#include <Rcpp.h>
+
+// [[Rcpp::export]]
+double trapezoidal(Rcpp::NumericVector const &x, Rcpp::NumericVector const &y) {
+  double ret = 0;
+  for (size_t i = 1; i < x.size(); ++i)
+    ret += (x[i] - x[i - 1]) * (y[i] + y[i - 1]) / 2;
+  return ret;
+}
diff --git a/data/tools/support/writeContours.R b/data/tools/support/writeContours.R
new file mode 100644
index 00000000..9394bf5f
--- /dev/null
+++ b/data/tools/support/writeContours.R
@@ -0,0 +1,11 @@
+writeContours <- function (contours, level, file) {
+  file.create(file)
+  for (cl in contours[sapply(contours, function(x) x$level) == level]) {
+    conn <- file(file, 'a')
+    write.table(cbind(cl$x, cl$y, level),
+                file = file, row.names = FALSE, col.names = FALSE,
+                append = TRUE)
+    writeLines("\n", conn)
+    close(conn)
+  }
+}
diff --git a/debugging.m b/debugging.m
new file mode 100644
index 00000000..259ae8db
--- /dev/null
+++ b/debugging.m
@@ -0,0 +1,577 @@
+
+A = [...
+];
+
+f = [...
+0;
+-4.33681e-19;
+0;
+1.0842e-19;
+-2.66671e-06;
+-4.94914e-07;
+0;
+-2.71051e-20;
+-4.19923e-06;
+-4.21374e-07;
+-3.92235e-06;
+-8.64817e-07;
+0;
+-5.42101e-20;
+-4.96301e-06;
+-4.13502e-06;
+0;
+0;
+-7.03515e-06;
+-5.84881e-06;
+-4.93309e-06;
+-2.37804e-06;
+0;
+0;
+-2.90755e-06;
+-1.23334e-06;
+0;
+0;
+-2.2449e-06;
+-8.21563e-07;
+0;
+0;
+0;
+0;
+0;
+0;
+-7.24652e-06;
+-8.25293e-07;
+0;
+2.4104e-06;
+-8.19294e-06;
+-1.18617e-06;
+-5.58223e-06;
+-1.69348e-06;
+0;
+1.88001e-06;
+-1.03387e-05;
+-8.22886e-06;
+0;
+0;
+-1.07258e-05;
+-8.62344e-06;
+-9.76077e-06;
+-4.93954e-06;
+-9.10261e-06;
+-7.35307e-06;
+-4.01973e-06;
+-2.38351e-06;
+-5.92659e-06;
+-4.23858e-07;
+-7.9911e-06;
+-4.04139e-06;
+-3.80594e-06;
+-3.06903e-06;
+-3.92924e-06;
+-2.71681e-06;
+-5.12975e-06;
+-1.37642e-06;
+-4.79892e-06;
+-1.14935e-06;
+-7.19726e-06;
+-3.54967e-06;
+-6.62755e-06;
+-6.1499e-07;
+0;
+1.28701e-05;
+0;
+0;
+-1.09944e-05;
+-1.92221e-06;
+0;
+1.17853e-05;
+-1.21456e-05;
+-2.20784e-06;
+-8.3682e-06;
+-2.01449e-06;
+0;
+0;
+-1.43122e-05;
+-1.00938e-05;
+0;
+0;
+-1.48374e-05;
+-1.03947e-05;
+-1.3684e-05;
+-6.31825e-06;
+-1.35318e-05;
+-9.3703e-06;
+-5.76679e-06;
+-1.88878e-06;
+-9.18524e-06;
+-1.51544e-06;
+-1.16296e-05;
+-5.64398e-06;
+-5.20301e-06;
+-2.13559e-06;
+-5.55432e-06;
+-2.017e-06;
+-7.96841e-06;
+-1.7895e-06;
+-7.95375e-06;
+-1.76175e-06;
+-1.0596e-05;
+-5.24553e-06;
+-1.02345e-05;
+-1.74422e-06;
+-2.16064e-05;
+-1.85059e-06;
+-2.24752e-05;
+-3.34957e-07;
+-1.34774e-05;
+-2.51353e-06;
+-2.18312e-05;
+-1.04202e-06;
+-1.99898e-05;
+-1.463e-06;
+-1.94256e-05;
+-2.11821e-06;
+-5e-05;
+5.03269e-07;
+-2.00631e-05;
+-2.41829e-06;
+-2.11637e-05;
+-1.12298e-06;
+-1.61508e-05;
+-1.11752e-05;
+-1.7267e-05;
+-6.9337e-06;
+-1.43931e-05;
+-6.46903e-06;
+-1.70354e-05;
+-2.45177e-06;
+-5e-05;
+-2.50465e-06;
+-5e-05;
+-1.21588e-05;
+-2.01431e-05;
+-1.19797e-05;
+];
+
+d = 0.00075745;
+A2 = [...
+];
+
+f2 = [...
+0;
+0;
+0;
+0;
+-3.01994e-06;
+-1.76298e-07;
+0;
+0;
+-4.78204e-06;
+-2.0995e-07;
+-5.01951e-06;
+1.22653e-06;
+0;
+0;
+-4.98476e-06;
+-3.57931e-06;
+0;
+0;
+-7.06572e-06;
+-4.97786e-06;
+-5.40025e-06;
+-1.91591e-06;
+0;
+0;
+-3.26344e-06;
+-9.4196e-07;
+0;
+0;
+-3.47107e-06;
+1.69693e-06;
+0;
+0;
+0;
+0;
+0;
+0;
+-8.36624e-06;
+-3.21786e-07;
+0;
+0;
+-9.19771e-06;
+-4.8646e-07;
+-9.46319e-06;
+2.13218e-06;
+0;
+0;
+-1.03261e-05;
+-6.78209e-06;
+0;
+0;
+-1.09634e-05;
+-7.09926e-06;
+-1.01615e-05;
+-3.77678e-06;
+-9.09151e-06;
+-6.13484e-06;
+-9.06507e-06;
+4.28268e-06;
+-6.83374e-06;
+-2.4706e-07;
+-8.51881e-06;
+-3.22169e-06;
+-7.83369e-06;
+3.49294e-06;
+-8.45665e-06;
+3.90404e-06;
+-7.913e-06;
+1.91502e-06;
+-7.13457e-06;
+1.77604e-06;
+-7.71821e-06;
+-2.87949e-06;
+-7.58455e-06;
+-3.19117e-07;
+0;
+0;
+0;
+0;
+-1.17905e-05;
+-6.57623e-07;
+0;
+0;
+-1.26738e-05;
+-7.75536e-07;
+-1.28663e-05;
+2.59111e-06;
+0;
+0;
+-1.33726e-05;
+-8.23012e-06;
+0;
+0;
+-1.40382e-05;
+-8.4827e-06;
+-1.3445e-05;
+-4.60248e-06;
+-1.21277e-05;
+-7.7075e-06;
+-1.20933e-05;
+5.59837e-06;
+-1.00511e-05;
+-5.83173e-07;
+-1.16989e-05;
+-4.19969e-06;
+-1.07938e-05;
+5.03904e-06;
+-1.14551e-05;
+5.33497e-06;
+-1.1057e-05;
+2.39173e-06;
+-1.01977e-05;
+2.22842e-06;
+-1.08385e-05;
+-3.93909e-06;
+-1.09119e-05;
+-6.59537e-07;
+-1.51572e-05;
+6.80143e-06;
+-1.97651e-05;
+7.92292e-06;
+-1.3582e-05;
+-8.81729e-07;
+-1.73372e-05;
+7.52177e-06;
+-1.63794e-05;
+2.79237e-06;
+-1.33659e-05;
+2.38778e-06;
+-5e-05;
+7.93536e-06;
+-1.92072e-05;
+-9.96979e-07;
+-1.93357e-05;
+3.15138e-06;
+-1.54595e-05;
+-9.11795e-06;
+-1.68142e-05;
+-5.1397e-06;
+-1.4113e-05;
+-4.66534e-06;
+-1.63265e-05;
+-9.49749e-07;
+-5e-05;
+-1.0631e-06;
+-5e-05;
+-1.02021e-05;
+-1.98778e-05;
+-9.99727e-06;
+];
+
+d2 = 0;
+
+sum(sum(abs(f-f2)>1e-14))
+
+
+sum(sum(abs(A-A2)>1e-14))
+
+
+alpha0 = 100;
+V = 1e-5; %1e-20;
+V0 = 5e-5;
+L = 2.25e-5;
+
+alpha = @(t) log(exp(alpha0 - V.*t./L ) - V0 * (exp(-t./L.*V)-1)./V);
+
+x = [0:0.001:0.1];
+alpha(x)
+plot(x, alpha(x));
+
+%abs(d-d2)
+
+% x = [...
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% -1.2337e-10;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% 0;
+% -1.2337e-10;
+% 0;
+% -1.2337e-10;
+% 0;
+% 0;
+% 0;
+% ];
+% 
+% ignore = [...
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0; 
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 1;
+% 1; 
+% 0;
+% 0; 
+% 1; 
+% 1; 
+% 0;
+% 0; 
+% 1;
+% 1; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 1;
+% 0; 
+% 0;
+% 0; 
+% 0;
+% 0; 
+% 0; 
+% 0; 
+% 0;
+% 0; 
+% 0; 
+% 0; 
+% 0; 
+% 0; 
+% 1;
+% 0; 
+% 1;
+% 0; 
+% 0;
+% 0; 
+% ];
+% 
+% newA = A;
+% newf = f;
+% for i=1:length(ignore)
+%     if (ignore(i)==1)
+%         for j=1:length(ignore)
+%             newA(i,j) = (i==j);
+%         end
+%         newf(i) = x(i);
+%     end
+% end
+% newA
+% newf
+
+% ignore = zeros(1, length(f));
+% for i=1:length(ignore)
+%     if (A(i,i)==0)
+%         ignore(1, i) = 1;
+%     end
+% end
+% 
+% indices = [];
+% for i=1:length(ignore)
+%     if (ignore(i)==0)
+%         indices = [indices i];
+%     end
+% end
+% 
+% len = length(indices);
+% newA = zeros(len, len);
+% newf = zeros(1, len);
+% for i=1:len
+%     newf(i) = f(indices(i));
+% 
+%     for j=1:len
+%         newA(i,j) = A(indices(i), indices(j));
+%     end
+% end
+% newf;
+% newA
+
+%inv(A);
+
+% sol = newA\newf
+% 
+% tnnmgSol = [...
+%     -1.03349;
+% -0.0502635;
+% 0.0161336;
+% -0.00852914;
+% -0.0130659;
+% 0.00660115;
+% -0.434915;
+% -0.0128241;
+% -0.00893317;
+% 0.00884256;
+% -0.0110232;
+% -0.10936;
+% 1.14978;
+% 0.0581132;
+% 0.019598;
+% 0.190758;
+% 0.478393;
+% -0.00433049;
+% 0.0513446;
+% 0.353218;
+% -0.00482644;
+% 0.11758;
+% 0;
+% 0;
+% -0.013677;
+% 0.0512563;
+% 0;
+% 0;
+% -0.00514197;
+% -0.117664;
+% 0;
+% 0;
+% 0.130034;
+% 0.574041;
+% 0.0136965;
+% 0.214953;
+% 0.0335986;
+% -0.00703477;
+% 0.0438202;
+% 0.346506;
+% -0.000896805;
+% 0.127837;
+% 0.041946;
+% 0.217409;
+% -1.2337e-10;
+% 0.112528;
+% -0.00828618;
+% 0.00453345;
+% -0.00898709;
+% 0.0781683;
+% 0.092355;
+% -0.556143;
+% -0.00443686;
+% -0.140953;
+% 0.0424371;
+% -0.250082;
+% -0.00336878;
+% 0.00105471;
+% -1.2337e-10;
+% 0.0188452;
+% -1.2337e-10;
+% -0.14111;
+% 0.00298499;
+% -0.190904;
+% ];
+% 
+% sol-tnnmgSol
\ No newline at end of file
diff --git a/dune/tectonic/CMakeLists.txt b/dune/tectonic/CMakeLists.txt
index 52c9f309..de041acc 100644
--- a/dune/tectonic/CMakeLists.txt
+++ b/dune/tectonic/CMakeLists.txt
@@ -1,16 +1,24 @@
+add_subdirectory("data-structures")
+add_subdirectory("factories")
+add_subdirectory("io")
+add_subdirectory("problem-data")
+add_subdirectory("spatial-solving")
+add_subdirectory("tests")
+add_subdirectory("time-stepping")
+add_subdirectory("utils")
+
+add_custom_target(tectonic_dune SOURCES
+  assemblers.hh
+  assemblers.cc 
+  explicitgrid.hh
+  explicitvectors.hh
+  gridselector.hh
+)
+
+#install headers
 install(FILES
-  bodydata.hh
-  frictiondata.hh
-  frictionpotential.hh
-  globalfrictiondata.hh
-  globalfriction.hh
-  globalratestatefriction.hh
-  gravity.hh
-  localfriction.hh
-  minimisation.hh
-  myblockproblem.hh
-  mydirectionalconvexfunction.hh
-  quadraticenergy.hh
-  tectonic.hh
-  transformedglobalratestatefriction.hh
-  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
+  assemblers.hh
+  explicitgrid.hh
+  explicitvectors.hh
+  gridselector.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/assemblers.cc b/dune/tectonic/assemblers.cc
similarity index 98%
rename from src/assemblers.cc
rename to dune/tectonic/assemblers.cc
index 1160fd59..609436ca 100644
--- a/src/assemblers.cc
+++ b/dune/tectonic/assemblers.cc
@@ -17,8 +17,8 @@
 #include <dune/fufem/functiontools/p0p1interpolation.hh>
 #include <dune/fufem/quadraturerules/quadraturerulecache.hh>
 
-#include <dune/tectonic/frictionpotential.hh>
-#include <dune/tectonic/globalratestatefriction.hh>
+#include "data-structures/friction/frictionpotential.hh"
+#include "data-structures/friction/globalratestatefriction.hh"
 
 #include "assemblers.hh"
 
diff --git a/src/assemblers.hh b/dune/tectonic/assemblers.hh
similarity index 97%
rename from src/assemblers.hh
rename to dune/tectonic/assemblers.hh
index 695a94af..df0b3cd6 100644
--- a/src/assemblers.hh
+++ b/dune/tectonic/assemblers.hh
@@ -14,8 +14,8 @@
 #include <dune/fufem/functionspacebases/p1nodalbasis.hh>
 #include <dune/fufem/boundarypatch.hh>
 
-#include <dune/tectonic/globalfriction.hh>
-#include <dune/tectonic/globalfrictiondata.hh>
+#include "data-structures/friction/globalfriction.hh"
+#include "data-structures/friction/globalfrictiondata.hh"
 
 #include "data-structures/enums.hh"
 
diff --git a/src/assemblers_tmpl.cc b/dune/tectonic/assemblers_tmpl.cc
similarity index 100%
rename from src/assemblers_tmpl.cc
rename to dune/tectonic/assemblers_tmpl.cc
diff --git a/src/data-structures/.cc b/dune/tectonic/data-structures/.cc
similarity index 100%
rename from src/data-structures/.cc
rename to dune/tectonic/data-structures/.cc
diff --git a/dune/tectonic/data-structures/CMakeLists.txt b/dune/tectonic/data-structures/CMakeLists.txt
new file mode 100644
index 00000000..2a5db4e9
--- /dev/null
+++ b/dune/tectonic/data-structures/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_subdirectory("body")
+add_subdirectory("friction")
+add_subdirectory("network")
+
+add_custom_target(tectonic_dune_data-structures SOURCES
+  enumparser.hh
+  enumparser.cc 
+  enums.hh
+  matrices.hh
+  program_state.hh
+)
+
+#install headers
+install(FILES
+  enumparser.hh
+  enums.hh
+  matrices.hh
+  program_state.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/dune/tectonic/data-structures/body/CMakeLists.txt b/dune/tectonic/data-structures/body/CMakeLists.txt
new file mode 100644
index 00000000..699e013f
--- /dev/null
+++ b/dune/tectonic/data-structures/body/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_custom_target(tectonic_dune_data-structures_body SOURCES
+  body.hh
+  body.cc 
+  bodydata.hh
+  boundarycondition.hh
+)
+
+#install headers
+install(FILES
+  body.hh
+  bodydata.hh
+  boundarycondition.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/data-structures/body.cc b/dune/tectonic/data-structures/body/body.cc
similarity index 100%
rename from src/data-structures/body.cc
rename to dune/tectonic/data-structures/body/body.cc
diff --git a/src/data-structures/body.hh b/dune/tectonic/data-structures/body/body.hh
similarity index 97%
rename from src/data-structures/body.hh
rename to dune/tectonic/data-structures/body/body.hh
index 6b5463cd..74809e50 100644
--- a/src/data-structures/body.hh
+++ b/dune/tectonic/data-structures/body/body.hh
@@ -24,12 +24,12 @@
 
 #include <dune/solvers/norms/energynorm.hh>
 
-#include <dune/tectonic/bodydata.hh>
+#include "../../assemblers.hh"
+#include "../enums.hh"
+#include "../matrices.hh"
 
-#include "../assemblers.hh"
-#include "../boundarycondition.hh"
-#include "enums.hh"
-#include "matrices.hh"
+#include "boundarycondition.hh"
+#include "bodydata.hh"
 
 template <class HostGridType, class VectorType>
 class LeafBody {
diff --git a/src/data-structures/body_tmpl.cc b/dune/tectonic/data-structures/body/body_tmpl.cc
similarity index 70%
rename from src/data-structures/body_tmpl.cc
rename to dune/tectonic/data-structures/body/body_tmpl.cc
index d2a5dab1..26ebfd64 100644
--- a/src/data-structures/body_tmpl.cc
+++ b/dune/tectonic/data-structures/body/body_tmpl.cc
@@ -2,8 +2,8 @@
 #error MY_DIM unset
 #endif
 
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
+#include "../../explicitgrid.hh"
+#include "../../explicitvectors.hh"
 
 template class LeafBody<Grid, Vector>;
 
diff --git a/dune/tectonic/bodydata.hh b/dune/tectonic/data-structures/body/bodydata.hh
similarity index 100%
rename from dune/tectonic/bodydata.hh
rename to dune/tectonic/data-structures/body/bodydata.hh
diff --git a/src/boundarycondition.hh b/dune/tectonic/data-structures/body/boundarycondition.hh
similarity index 100%
rename from src/boundarycondition.hh
rename to dune/tectonic/data-structures/body/boundarycondition.hh
diff --git a/src/data-structures/enumparser.cc b/dune/tectonic/data-structures/enumparser.cc
similarity index 100%
rename from src/data-structures/enumparser.cc
rename to dune/tectonic/data-structures/enumparser.cc
diff --git a/src/data-structures/enumparser.hh b/dune/tectonic/data-structures/enumparser.hh
similarity index 100%
rename from src/data-structures/enumparser.hh
rename to dune/tectonic/data-structures/enumparser.hh
diff --git a/src/data-structures/enums.hh b/dune/tectonic/data-structures/enums.hh
similarity index 100%
rename from src/data-structures/enums.hh
rename to dune/tectonic/data-structures/enums.hh
diff --git a/dune/tectonic/data-structures/friction/CMakeLists.txt b/dune/tectonic/data-structures/friction/CMakeLists.txt
new file mode 100644
index 00000000..a9f8efd5
--- /dev/null
+++ b/dune/tectonic/data-structures/friction/CMakeLists.txt
@@ -0,0 +1,20 @@
+add_custom_target(tectonic_dune_data-structures_friction SOURCES
+  frictioncouplingpair.hh
+  frictiondata.hh 
+  frictionpotential.hh
+  globalfriction.hh
+  globalfrictiondata.hh
+  globalratestatefriction.hh
+  localfriction.hh
+)
+
+#install headers
+install(FILES
+  frictioncouplingpair.hh
+  frictiondata.hh 
+  frictionpotential.hh
+  globalfriction.hh
+  globalfrictiondata.hh
+  globalratestatefriction.hh
+  localfriction.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/frictioncouplingpair.hh b/dune/tectonic/data-structures/friction/frictioncouplingpair.hh
similarity index 95%
rename from src/frictioncouplingpair.hh
rename to dune/tectonic/data-structures/friction/frictioncouplingpair.hh
index 7eb36871..a4102b8e 100644
--- a/src/frictioncouplingpair.hh
+++ b/dune/tectonic/data-structures/friction/frictioncouplingpair.hh
@@ -3,7 +3,8 @@
 
 #include <dune/fufem/geometry/convexpolyhedron.hh>
 #include <dune/contact/common/couplingpair.hh>
-#include <dune/tectonic/globalfrictiondata.hh>
+
+#include "globalfrictiondata.hh"
 
 template <class GridType, class LocalVectorType, class field_type = double>
 class FrictionCouplingPair : public Dune::Contact::CouplingPair<GridType, GridType, field_type>{
diff --git a/dune/tectonic/frictiondata.hh b/dune/tectonic/data-structures/friction/frictiondata.hh
similarity index 100%
rename from dune/tectonic/frictiondata.hh
rename to dune/tectonic/data-structures/friction/frictiondata.hh
diff --git a/dune/tectonic/frictionpotential.hh b/dune/tectonic/data-structures/friction/frictionpotential.hh
similarity index 99%
rename from dune/tectonic/frictionpotential.hh
rename to dune/tectonic/data-structures/friction/frictionpotential.hh
index 2ed879b3..8b98b22b 100644
--- a/dune/tectonic/frictionpotential.hh
+++ b/dune/tectonic/data-structures/friction/frictionpotential.hh
@@ -9,7 +9,7 @@
 #include <dune/common/exceptions.hh>
 #include <dune/common/function.hh>
 
-#include <dune/tectonic/frictiondata.hh>
+#include "frictiondata.hh"
 
 class FrictionPotential {
 public:
diff --git a/dune/tectonic/globalfriction.hh b/dune/tectonic/data-structures/friction/globalfriction.hh
similarity index 93%
rename from dune/tectonic/globalfriction.hh
rename to dune/tectonic/data-structures/friction/globalfriction.hh
index 83395851..f3dbabc7 100644
--- a/dune/tectonic/globalfriction.hh
+++ b/dune/tectonic/data-structures/friction/globalfriction.hh
@@ -9,12 +9,10 @@
 
 #include <dune/solvers/common/interval.hh>
 
-#include <dune/tnnmg/functionals/nonsmoothconvexfunctional.hh>
-
-#include <dune/tectonic/localfriction.hh>
+#include "localfriction.hh"
 
 template <class Matrix, class Vector>
-class GlobalFriction { //: public Dune::TNNMG::NonsmoothConvexFunctional<> {
+class GlobalFriction {
 protected:
   using ScalarVector = Dune::BlockVector<Dune::FieldVector<double, 1>>;
 
diff --git a/dune/tectonic/globalfrictiondata.hh b/dune/tectonic/data-structures/friction/globalfrictiondata.hh
similarity index 96%
rename from dune/tectonic/globalfrictiondata.hh
rename to dune/tectonic/data-structures/friction/globalfrictiondata.hh
index 0fffac2c..7646bfcf 100644
--- a/dune/tectonic/globalfrictiondata.hh
+++ b/dune/tectonic/data-structures/friction/globalfrictiondata.hh
@@ -4,7 +4,7 @@
 #include <dune/common/function.hh>
 #include <dune/common/fvector.hh>
 
-#include <dune/tectonic/frictiondata.hh>
+#include "frictiondata.hh"
 
 template <class DomainType>
 double evaluateScalarFunction(
diff --git a/dune/tectonic/globalratestatefriction.hh b/dune/tectonic/data-structures/friction/globalratestatefriction.hh
similarity index 91%
rename from dune/tectonic/globalratestatefriction.hh
rename to dune/tectonic/data-structures/friction/globalratestatefriction.hh
index 078bd85d..0d007d8e 100644
--- a/dune/tectonic/globalratestatefriction.hh
+++ b/dune/tectonic/data-structures/friction/globalratestatefriction.hh
@@ -12,12 +12,12 @@
 
 #include <dune/contact/assemblers/dualmortarcoupling.hh>
 
-#include <dune/tectonic/geocoordinate.hh>
-#include <dune/tectonic/globalfrictiondata.hh>
-#include <dune/tectonic/globalfriction.hh>
-#include <dune/tectonic/index-in-sorted-range.hh>
+#include "globalfrictiondata.hh"
+#include "globalfriction.hh"
+#include "frictioncouplingpair.hh"
 
-#include "../../src/frictioncouplingpair.hh"
+#include "../../utils/geocoordinate.hh"
+#include "../../utils/index-in-sorted-range.hh"
 
 template <class Matrix, class Vector, class ScalarFriction, class GridType>
 class GlobalRateStateFriction : public GlobalFriction<Matrix, Vector> {
@@ -32,7 +32,7 @@ class GlobalRateStateFriction : public GlobalFriction<Matrix, Vector> {
   using typename Base::ScalarVector;
   using typename Base::LocalVectorType;
 
-  using FrictionCouplingPair = FrictionCouplingPair<GridType, LocalVectorType, field_type>;
+  using FrictionCoupling = FrictionCouplingPair<GridType, LocalVectorType, field_type>;
   using ContactCoupling =  Dune::Contact::DualMortarCoupling<field_type, GridType>;
 
   size_t bodyIndex(const size_t globalIdx) {
@@ -47,7 +47,7 @@ class GlobalRateStateFriction : public GlobalFriction<Matrix, Vector> {
 
 public:
   GlobalRateStateFriction(const std::vector<std::shared_ptr<ContactCoupling>>& contactCouplings, // contains nonmortarBoundary
-                          const std::vector<std::shared_ptr<FrictionCouplingPair>>& couplings, // contains frictionInfo
+                          const std::vector<std::shared_ptr<FrictionCoupling>>& couplings, // contains frictionInfo
                           const std::vector<ScalarVector>& weights,
                           const std::vector<ScalarVector>& weightedNormalStress)
       : restrictions_(), localToGlobal_(), zeroFriction_() {
diff --git a/dune/tectonic/localfriction.hh b/dune/tectonic/data-structures/friction/localfriction.hh
similarity index 99%
rename from dune/tectonic/localfriction.hh
rename to dune/tectonic/data-structures/friction/localfriction.hh
index f2fb36ee..67b7f282 100644
--- a/dune/tectonic/localfriction.hh
+++ b/dune/tectonic/data-structures/friction/localfriction.hh
@@ -10,7 +10,7 @@
 #include <dune/fufem/arithmetic.hh>
 #include <dune/solvers/common/interval.hh>
 
-#include <dune/tectonic/frictionpotential.hh>
+#include "frictionpotential.hh"
 
 template <size_t dimension> class LocalFriction {
 public:
diff --git a/src/data-structures/globalfrictioncontainer.cc b/dune/tectonic/data-structures/globalfrictioncontainer.cc
similarity index 100%
rename from src/data-structures/globalfrictioncontainer.cc
rename to dune/tectonic/data-structures/globalfrictioncontainer.cc
diff --git a/src/data-structures/globalfrictioncontainer.hh b/dune/tectonic/data-structures/globalfrictioncontainer.hh
similarity index 100%
rename from src/data-structures/globalfrictioncontainer.hh
rename to dune/tectonic/data-structures/globalfrictioncontainer.hh
diff --git a/src/data-structures/matrices.hh b/dune/tectonic/data-structures/matrices.hh
similarity index 100%
rename from src/data-structures/matrices.hh
rename to dune/tectonic/data-structures/matrices.hh
diff --git a/dune/tectonic/data-structures/network/CMakeLists.txt b/dune/tectonic/data-structures/network/CMakeLists.txt
new file mode 100644
index 00000000..1cfc9596
--- /dev/null
+++ b/dune/tectonic/data-structures/network/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_custom_target(tectonic_dune_data-structures_network SOURCES
+  contactnetwork.hh
+  contactnetwork.cc
+  levelcontactnetwork.hh
+  levelcontactnetwork.cc
+)
+
+#install headers
+install(FILES
+  contactnetwork.hh
+  levelcontactnetwork.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/data-structures/contactnetwork.cc b/dune/tectonic/data-structures/network/contactnetwork.cc
similarity index 98%
rename from src/data-structures/contactnetwork.cc
rename to dune/tectonic/data-structures/network/contactnetwork.cc
index 84517f20..e369614c 100644
--- a/src/data-structures/contactnetwork.cc
+++ b/dune/tectonic/data-structures/network/contactnetwork.cc
@@ -7,13 +7,13 @@
 #include <dune/fufem/assemblers/localassemblers/neumannboundaryassembler.hh>
 #include <dune/fufem/functions/constantfunction.hh>
 
-#include <dune/tectonic/globalratestatefriction.hh>
-#include <dune/tectonic/frictionpotential.hh>
+#include "../friction/globalratestatefriction.hh"
+#include "../friction/frictionpotential.hh"
 
 #include "contactnetwork.hh"
 
-#include "../assemblers.hh"
-#include "../utils/tobool.hh"
+#include "../../assemblers.hh"
+#include "../../utils/tobool.hh"
 
 
 template <class HostGridType, class VectorType>
diff --git a/src/data-structures/contactnetwork.hh b/dune/tectonic/data-structures/network/contactnetwork.hh
similarity index 95%
rename from src/data-structures/contactnetwork.hh
rename to dune/tectonic/data-structures/network/contactnetwork.hh
index 6fb2e48b..fc9f554c 100644
--- a/src/data-structures/contactnetwork.hh
+++ b/dune/tectonic/data-structures/network/contactnetwork.hh
@@ -7,15 +7,16 @@
 
 #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 "../../assemblers.hh"
+#include "../enums.hh"
+#include "../matrices.hh"
+
+#include "../body/body.hh"
+#include "../body/bodydata.hh"
+#include "../friction/frictioncouplingpair.hh"
+#include "../friction/globalfriction.hh"
+#include "../friction/globalfrictiondata.hh"
+
 #include "levelcontactnetwork.hh"
 
 template <class HostGridType, class VectorType>
diff --git a/dune/tectonic/data-structures/network/contactnetwork_tmpl.cc b/dune/tectonic/data-structures/network/contactnetwork_tmpl.cc
new file mode 100644
index 00000000..9979e7c1
--- /dev/null
+++ b/dune/tectonic/data-structures/network/contactnetwork_tmpl.cc
@@ -0,0 +1,10 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../../explicitgrid.hh"
+#include "../../explicitvectors.hh"
+
+#include "contactnetwork.hh"
+
+template class ContactNetwork<Grid, Vector>;
diff --git a/src/data-structures/levelcontactnetwork.cc b/dune/tectonic/data-structures/network/levelcontactnetwork.cc
similarity index 97%
rename from src/data-structures/levelcontactnetwork.cc
rename to dune/tectonic/data-structures/network/levelcontactnetwork.cc
index f7a34d4a..f0c81bdd 100644
--- a/src/data-structures/levelcontactnetwork.cc
+++ b/dune/tectonic/data-structures/network/levelcontactnetwork.cc
@@ -8,14 +8,14 @@
 #include <dune/fufem/functions/constantfunction.hh>
 #include <dune/fufem/facehierarchy.hh>
 
-#include <dune/tectonic/globalratestatefriction.hh>
-#include <dune/tectonic/frictionpotential.hh>
+#include "../../assemblers.hh"
+#include "../../utils/tobool.hh"
+#include "../../utils/debugutils.hh"
 
-#include "levelcontactnetwork.hh"
+#include "../friction/globalratestatefriction.hh"
+#include "../friction/frictionpotential.hh"
 
-#include "../assemblers.hh"
-#include "../utils/tobool.hh"
-#include "../utils/debugutils.hh"
+#include "levelcontactnetwork.hh"
 
 template <class GridType, class FrictionCouplingPair, class field_type>
 LevelContactNetwork<GridType, FrictionCouplingPair, field_type>::LevelContactNetwork(
diff --git a/src/data-structures/levelcontactnetwork.hh b/dune/tectonic/data-structures/network/levelcontactnetwork.hh
similarity index 91%
rename from src/data-structures/levelcontactnetwork.hh
rename to dune/tectonic/data-structures/network/levelcontactnetwork.hh
index c4976718..dc0b4de3 100644
--- a/src/data-structures/levelcontactnetwork.hh
+++ b/dune/tectonic/data-structures/network/levelcontactnetwork.hh
@@ -18,16 +18,15 @@
 
 #include <dune/fufem/boundarypatch.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 "multi-body-problem-data/myglobalfrictiondata.hh"
+#include "../../assemblers.hh"
+#include "../enums.hh"
+#include "../matrices.hh"
+
+#include "../body/body.hh"
+#include "../body/bodydata.hh"
+#include "../friction/frictioncouplingpair.hh"
+#include "../friction/globalfriction.hh"
+#include "../friction/globalfrictiondata.hh"
 
 template <class GridTypeTEMPLATE, class FrictionCouplingPair, class field_type>
 class LevelContactNetwork {
diff --git a/src/data-structures/levelcontactnetwork_tmpl.cc b/dune/tectonic/data-structures/network/levelcontactnetwork_tmpl.cc
similarity index 54%
rename from src/data-structures/levelcontactnetwork_tmpl.cc
rename to dune/tectonic/data-structures/network/levelcontactnetwork_tmpl.cc
index da253a7f..3445a319 100644
--- a/src/data-structures/levelcontactnetwork_tmpl.cc
+++ b/dune/tectonic/data-structures/network/levelcontactnetwork_tmpl.cc
@@ -2,11 +2,13 @@
 #error MY_DIM unset
 #endif
 
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
+#include "../../explicitgrid.hh"
+#include "../../explicitvectors.hh"
 
-#include "../frictioncouplingpair.hh"
-#include "contactnetwork_tmpl.cc"
+#include "../friction/frictioncouplingpair.hh"
+#include "contactnetwork.hh"
 #include "levelcontactnetwork.hh"
 
+using MyContactNetwork = ContactNetwork<Grid, Vector>;
+
 template class LevelContactNetwork<typename MyContactNetwork::GridType, typename MyContactNetwork::FrictionCouplingPair, typename MyContactNetwork::field_type>;
diff --git a/src/data-structures/program_state.hh b/dune/tectonic/data-structures/program_state.hh
similarity index 82%
rename from src/data-structures/program_state.hh
rename to dune/tectonic/data-structures/program_state.hh
index ad0e796e..05198b41 100644
--- a/src/data-structures/program_state.hh
+++ b/dune/tectonic/data-structures/program_state.hh
@@ -6,7 +6,6 @@
 #include <dune/matrix-vector/axpy.hh>
 
 #include <dune/fufem/boundarypatch.hh>
-#include <dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh>
 
 #include <dune/contact/assemblers/nbodyassembler.hh>
 
@@ -14,13 +13,14 @@
 #include <dune/solvers/solvers/loopsolver.hh>
 #include <dune/solvers/iterationsteps/cgstep.hh>
 
-#include <dune/tectonic/bodydata.hh>
+#include "body/bodydata.hh"
 
 #include "../assemblers.hh"
-#include "contactnetwork.hh"
+#include "network/contactnetwork.hh"
 #include "matrices.hh"
 #include "../spatial-solving/preconditioners/multilevelpatchpreconditioner.hh"
 #include "../spatial-solving/solverfactory.hh"
+#include "../spatial-solving/solverfactory.cc"
 #include "../spatial-solving/tnnmg/functional.hh"
 #include "../spatial-solving/tnnmg/zerononlinearity.hh"
 #include "../utils/debugutils.hh"
@@ -102,32 +102,36 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
     using Matrix = typename ContactNetwork::Matrix;
     const auto& nBodyAssembler = contactNetwork.nBodyAssembler();
 
-    const auto& preconditionerParset = parset.sub("solver.tnnmg.linear.preconditioner");
-
     std::cout << "-- setupInitialConditions --" << std::endl;
     std::cout << "----------------------------" << std::endl;
 
-    /*
-    std::cout << "Building preconditioner..." << std::endl;
+    // make linear solver for linear correction in TNNMGStep
+    using Norm =  EnergyNorm<Matrix, Vector>;
     using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>;
+    using LinearSolver = typename Dune::Solvers::LoopSolver<Vector>;
+
+ /*   const auto& preconditionerParset = parset.sub("solver.tnnmg.preconditioner");
+
     Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), true);
-    /*Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), false);
-    activeLevels.back() = true;
-    activeLevels[activeLevels.size()-2] = true;*/
-    /*print(activeLevels, "activeLevels:");
     Preconditioner preconditioner(preconditionerParset, contactNetwork, activeLevels);
+    preconditioner.setPatchDepth(preconditionerParset.template get<size_t>("patchDepth"));
+
+    std::cout << "Building preconditioner..." << std::endl;
     preconditioner.build();
 
-    using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
-    using LinearSolverStep = typename Dune::Solvers::CGStep<Matrix, Vector, BitVector>;
+    auto cgStep = std::make_shared<Dune::Solvers::CGStep<Matrix, Vector>>();
+    cgStep->setPreconditioner(preconditioner);
+
+    Norm norm(*cgStep);
+
+    auto linearSolver = std::make_shared<LinearSolver>(cgStep, parset.get<int>("solver.tnnmg.main.multi"),
+                                                       parset.get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"),
+                                                       norm, Solver::QUIET);
 
-    LinearSolverStep linearSolverStep;
-    linearSolverStep.setPreconditioner(preconditioner);
+*/
+    // set multigrid solver
+    auto smoother = TruncatedBlockGSStep<Matrix, Vector>();
 
-    EnergyNorm<Matrix, Vector> energyNorm(linearSolverStep);
-    LinearSolver linearSolver(linearSolverStep, parset.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset.get<double>("solver.tnnmg.linear.tolerance"), energyNorm, Solver::FULL);
-    */
-    using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
     using TransferOperator = NBodyContactTransfer<ContactNetwork, Vector>;
     using TransferOperators = std::vector<std::shared_ptr<TransferOperator>>;
 
@@ -141,15 +145,14 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
     for (size_t i=0; i<transfer.size(); i++)
         std::dynamic_pointer_cast<TruncatedMGTransfer<Vector> >(transfer[i])->setRecomputeBitField(nullptr);
 
-    auto smoother = TruncatedBlockGSStep<Matrix, Vector>{};
     auto linearMultigridStep = std::make_shared<Dune::Solvers::MultigridStep<Matrix, Vector> >();
     linearMultigridStep->setMGType(1, 3, 3);
-    linearMultigridStep->setSmoother(&smoother);
+    linearMultigridStep->setSmoother(smoother);
     linearMultigridStep->setTransferOperators(transfer);
 
-    EnergyNorm<Matrix, Vector> mgNorm(*linearMultigridStep);
-    LinearSolver mgSolver(linearMultigridStep, parset.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::FULL);
+    Norm norm(*linearMultigridStep);
 
+    auto linearSolver = std::make_shared<LinearSolver>(linearMultigridStep, parset.get<int>("solver.tnnmg.main.multi"), parset.get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), norm, Solver::QUIET);
 
     // Solving a linear problem with a multigrid solver
     auto const solveLinearProblem = [&](
@@ -215,9 +218,10 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
       Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), lower, upper); //TODO
 
       // set up TNMMG solver
-      using Factory = SolverFactory<Functional, BitVector, ContactNetwork>;
+      using Factory = SolverFactory<Functional, BitVector>;
       //Factory factory(parset.sub("solver.tnnmg"), J, linearSolver, _dirichletNodes);
-      Factory factory(parset.sub("solver.tnnmg"), J, mgSolver, _dirichletNodes, contactNetwork);
+      Factory factory(parset.sub("solver.tnnmg"), J, _dirichletNodes);
+      factory.build(linearSolver);
 
      /* std::vector<BitVector> bodyDirichletNodes;
       nBodyAssembler.postprocess(_dirichletNodes, bodyDirichletNodes);
@@ -235,10 +239,9 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
       const EnergyNorm<Matrix, Vector> norm(bilinearForm);
 
       LoopSolver<Vector> solver(
-          tnnmgStep.get(), _localParset.get<size_t>("maximumIterations"),
-          _localParset.get<double>("tolerance"), &norm,
-          _localParset.get<Solver::VerbosityMode>("verbosity"),
-          false); // absolute error
+          *tnnmgStep.get(), _localParset.get<size_t>("maximumIterations"),
+          _localParset.get<double>("tolerance"), norm,
+          _localParset.get<Solver::VerbosityMode>("verbosity")); // absolute error
 
       solver.preprocess();
       solver.solve();
@@ -317,7 +320,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
     solveLinearProblem(dirichletNodes, contactNetwork.matrices().elasticity, ell0, u,
                        parset.sub("u0.solver"));
 
-    print(u, "initial u:");
+    //print(u, "initial u:");
 
     // Initial acceleration: Computed in agreement with Ma = ell0 - Au
     // (without Dirichlet constraints), again assuming dPhi(v = 0) = 0
@@ -329,7 +332,7 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
       // Initial normal stress
 
       const auto& body = contactNetwork.body(i);
-      std::vector<std::shared_ptr<typename ContactNetwork::LeafBody::BoundaryCondition>> frictionBoundaryConditions;
+      /*std::vector<std::shared_ptr<typename ContactNetwork::LeafBody::BoundaryCondition>> frictionBoundaryConditions;
       body->boundaryConditions("friction", frictionBoundaryConditions);
       for (size_t j=0; j<frictionBoundaryConditions.size(); j++) {
           ScalarVector frictionBoundaryStress(weightedNormalStress[i].size());
@@ -339,18 +342,34 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
             body->data()->getPoissonRatio(), u[i]);
 
           weightedNormalStress[i] += frictionBoundaryStress;
-      }
+      }*/
 
       Dune::MatrixVector::subtractProduct(accelerationRHS[i], *body->matrices().elasticity, u[i]);
     }
 
+    for (size_t i=0; i<contactNetwork.nCouplings(); i++) {
+      const auto& coupling = contactNetwork.coupling(i);
+      const auto& contactCoupling = contactNetwork.nBodyAssembler().getContactCouplings()[i];
+
+      const auto nonmortarIdx = coupling->gridIdx_[0];
+      const auto& body = contactNetwork.body(nonmortarIdx);
+
+      ScalarVector frictionBoundaryStress(weightedNormalStress[nonmortarIdx].size());
+
+      body->assembler()->assembleWeightedNormalStress(
+        contactCoupling->nonmortarBoundary(), frictionBoundaryStress, body->data()->getYoungModulus(),
+        body->data()->getPoissonRatio(), u[nonmortarIdx]);
+
+      weightedNormalStress[nonmortarIdx] += frictionBoundaryStress;
+    }
+
     std::cout << "solving linear problem for a..." << std::endl;
 
     BitVector noNodes(dirichletNodes.size(), false);
     solveLinearProblem(noNodes, contactNetwork.matrices().mass, accelerationRHS, a,
                        parset.sub("a0.solver"));
 
-    print(a, "initial a:");
+    //print(a, "initial a:");
   }
 
 private:
diff --git a/src/explicitgrid.hh b/dune/tectonic/explicitgrid.hh
similarity index 100%
rename from src/explicitgrid.hh
rename to dune/tectonic/explicitgrid.hh
diff --git a/src/explicitvectors.hh b/dune/tectonic/explicitvectors.hh
similarity index 100%
rename from src/explicitvectors.hh
rename to dune/tectonic/explicitvectors.hh
diff --git a/dune/tectonic/factories/CMakeLists.txt b/dune/tectonic/factories/CMakeLists.txt
new file mode 100644
index 00000000..b069d44e
--- /dev/null
+++ b/dune/tectonic/factories/CMakeLists.txt
@@ -0,0 +1,22 @@
+add_custom_target(tectonic_dune_factories SOURCES
+  cantorfactory.hh
+  cantorfactory.cc 
+  contactnetworkfactory.hh
+  levelcontactnetworkfactory.hh
+  stackedblocksfactory.hh
+  stackedblocksfactory.cc 
+  threeblocksfactory.hh
+  threeblocksfactory.cc 
+  twoblocksfactory.hh
+  twoblocksfactory.cc 
+)
+
+#install headers
+install(FILES
+  cantorfactory.hh
+  contactnetworkfactory.hh
+  levelcontactnetworkfactory.hh
+  stackedblocksfactory.hh
+  threeblocksfactory.hh
+  twoblocksfactory.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/factories/cantorfactory.cc b/dune/tectonic/factories/cantorfactory.cc
similarity index 100%
rename from src/factories/cantorfactory.cc
rename to dune/tectonic/factories/cantorfactory.cc
diff --git a/src/factories/cantorfactory.hh b/dune/tectonic/factories/cantorfactory.hh
similarity index 100%
rename from src/factories/cantorfactory.hh
rename to dune/tectonic/factories/cantorfactory.hh
diff --git a/src/factories/cantorfactory_tmpl.cc b/dune/tectonic/factories/cantorfactory_tmpl.cc
similarity index 100%
rename from src/factories/cantorfactory_tmpl.cc
rename to dune/tectonic/factories/cantorfactory_tmpl.cc
diff --git a/src/factories/contactnetworkfactory.hh b/dune/tectonic/factories/contactnetworkfactory.hh
similarity index 96%
rename from src/factories/contactnetworkfactory.hh
rename to dune/tectonic/factories/contactnetworkfactory.hh
index c1968822..e62425fd 100644
--- a/src/factories/contactnetworkfactory.hh
+++ b/dune/tectonic/factories/contactnetworkfactory.hh
@@ -3,7 +3,7 @@
 
 #include <dune/common/parametertree.hh>
 
-#include "../data-structures/contactnetwork.hh"
+#include "../data-structures/network/contactnetwork.hh"
 
 template <class HostGridType, class VectorType>
 class ContactNetworkFactory {
diff --git a/src/factories/levelcontactnetworkfactory.hh b/dune/tectonic/factories/levelcontactnetworkfactory.hh
similarity index 100%
rename from src/factories/levelcontactnetworkfactory.hh
rename to dune/tectonic/factories/levelcontactnetworkfactory.hh
diff --git a/src/factories/stackedblocksfactory.cc b/dune/tectonic/factories/stackedblocksfactory.cc
similarity index 97%
rename from src/factories/stackedblocksfactory.cc
rename to dune/tectonic/factories/stackedblocksfactory.cc
index 051afa46..6e6f5428 100644
--- a/src/factories/stackedblocksfactory.cc
+++ b/dune/tectonic/factories/stackedblocksfactory.cc
@@ -6,9 +6,9 @@
 
 #include <dune/contact/projections/normalprojection.hh>
 
-#include "../multi-body-problem-data/bc.hh"
-#include "../multi-body-problem-data/grid/cuboidgeometry.hh"
-#include "../multi-body-problem-data/myglobalfrictiondata.hh"
+#include "../problem-data/bc.hh"
+#include "../problem-data/grid/cuboidgeometry.hh"
+#include "../problem-data/myglobalfrictiondata.hh"
 
 #include "../utils/diameter.hh"
 
@@ -106,7 +106,7 @@ void StackedBlocksFactory<HostGridType, VectorType>::setBodies() {
         // 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);
+            refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale());
         }
 
         // determine minDiameter and maxDiameter
@@ -151,7 +151,7 @@ void StackedBlocksFactory<HostGridType, VectorType>::setCouplings() {
 
       coupling->set(i, 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));
+      coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale()));
     }
 }
 
@@ -185,7 +185,7 @@ void StackedBlocksFactory<HostGridType, VectorType>::setBoundaryConditions() {
     std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>();
     std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>();
 
-    const double lengthScale = CuboidGeometry::lengthScale;
+    const double lengthScale = CuboidGeometry::lengthScale();
 
     for (size_t i=0; i<this->bodyCount_; i++) {
         const auto& body = this->contactNetwork_.body(i);
diff --git a/src/factories/stackedblocksfactory.hh b/dune/tectonic/factories/stackedblocksfactory.hh
similarity index 93%
rename from src/factories/stackedblocksfactory.hh
rename to dune/tectonic/factories/stackedblocksfactory.hh
index b9471853..e8f9454f 100644
--- a/src/factories/stackedblocksfactory.hh
+++ b/dune/tectonic/factories/stackedblocksfactory.hh
@@ -9,9 +9,9 @@
 
 #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"
+#include "../problem-data/mybody.hh"
+#include "../problem-data/grid/mygrids.hh"
+#include "../problem-data/grid/cuboidgeometry.hh"
 
 template <class HostGridType, class VectorType> class StackedBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType>{
 private:
@@ -69,6 +69,10 @@ template <class HostGridType, class VectorType> class StackedBlocksFactory : pub
     void setLevelCouplings() {}
     void setBoundaryConditions();
 
+    auto& weakPatches() {
+        return weakPatches_;
+    }
+
 private:
     static constexpr Dune::FieldVector<double, MY_DIM> zenith_() {
         #if MY_DIM == 2
diff --git a/src/factories/stackedblocksfactory_tmpl.cc b/dune/tectonic/factories/stackedblocksfactory_tmpl.cc
similarity index 100%
rename from src/factories/stackedblocksfactory_tmpl.cc
rename to dune/tectonic/factories/stackedblocksfactory_tmpl.cc
diff --git a/src/factories/threeblocksfactory.cc b/dune/tectonic/factories/threeblocksfactory.cc
similarity index 96%
rename from src/factories/threeblocksfactory.cc
rename to dune/tectonic/factories/threeblocksfactory.cc
index 7dded09d..61275c63 100644
--- a/src/factories/threeblocksfactory.cc
+++ b/dune/tectonic/factories/threeblocksfactory.cc
@@ -6,8 +6,8 @@
 
 #include <dune/contact/projections/normalprojection.hh>
 
-#include "../multi-body-problem-data/bc.hh"
-#include "../multi-body-problem-data/myglobalfrictiondata.hh"
+#include "../problem-data/bc.hh"
+#include "../problem-data/myglobalfrictiondata.hh"
 
 #include "../utils/diameter.hh"
 
@@ -28,8 +28,8 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBodies() {
         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};
+        origins[1] = {0, origins[0][1] + heights[0], 0};
+        origins[2] = {origins[1][0] + lengths[1], origins[0][1] + heights[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});
@@ -70,7 +70,7 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBodies() {
         // 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);
+            refine(*grids[i], weakeningRegions[j], this->parset_.template get<double>("boundary.friction.smallestDiameter"), CuboidGeometry::lengthScale());
         }
 
         // determine minDiameter and maxDiameter
@@ -137,7 +137,7 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setCouplings() {
 
       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));
+      coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[i], CuboidGeometry::lengthScale()));
     }
 }
 
@@ -149,7 +149,7 @@ void ThreeBlocksFactory<HostGridType, VectorTEMPLATE>::setBoundaryConditions() {
     std::shared_ptr<Function> neumannFunction = std::make_shared<NeumannCondition>();
     std::shared_ptr<Function> velocityDirichletFunction = std::make_shared<VelocityDirichletCondition>();
 
-    const double lengthScale = CuboidGeometry::lengthScale;
+    const double lengthScale = CuboidGeometry::lengthScale();
 
     for (size_t i=0; i<this->bodyCount_; i++) {
         const auto& body = this->contactNetwork_.body(i);
diff --git a/src/factories/threeblocksfactory.hh b/dune/tectonic/factories/threeblocksfactory.hh
similarity index 92%
rename from src/factories/threeblocksfactory.hh
rename to dune/tectonic/factories/threeblocksfactory.hh
index e3405572..e72c7f1c 100644
--- a/src/factories/threeblocksfactory.hh
+++ b/dune/tectonic/factories/threeblocksfactory.hh
@@ -9,9 +9,9 @@
 
 #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"
+#include "../problem-data/mybody.hh"
+#include "../problem-data/grid/mygrids.hh"
+#include "../problem-data/grid/cuboidgeometry.hh"
 
 template <class HostGridType, class VectorType>
 class ThreeBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType>{
@@ -70,6 +70,9 @@ class ThreeBlocksFactory : public ContactNetworkFactory<HostGridType, VectorType
     void setLevelCouplings() {}
     void setBoundaryConditions();
 
+    auto& weakPatches() {
+        return weakPatches_;
+    }
 private:
     static constexpr Dune::FieldVector<double, MY_DIM> zenith_() {
         #if MY_DIM == 2
diff --git a/src/factories/threeblocksfactory_tmpl.cc b/dune/tectonic/factories/threeblocksfactory_tmpl.cc
similarity index 100%
rename from src/factories/threeblocksfactory_tmpl.cc
rename to dune/tectonic/factories/threeblocksfactory_tmpl.cc
diff --git a/dune/tectonic/factories/twoblocksfactory.cc b/dune/tectonic/factories/twoblocksfactory.cc
new file mode 100644
index 00000000..f58defd7
--- /dev/null
+++ b/dune/tectonic/factories/twoblocksfactory.cc
@@ -0,0 +1,199 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <dune/fufem/geometry/convexpolyhedron.hh>
+
+#include <dune/contact/projections/normalprojection.hh>
+
+#include "../problem-data/bc.hh"
+#include "../problem-data/myglobalfrictiondata.hh"
+
+#include "../utils/diameter.hh"
+
+#include "twoblocksfactory.hh"
+
+template <class HostGridType, class VectorTEMPLATE>
+void TwoBlocksFactory<HostGridType, VectorTEMPLATE>::setBodies() {
+    // set up cuboid geometries
+
+    std::array<double, 2> lengths = {this->parset_.template get<double>("body0.length"), this->parset_.template get<double>("body1.length")};
+    std::array<double, 2> heights = {this->parset_.template get<double>("body0.height"), this->parset_.template get<double>("body1.height")};
+
+    std::array<GlobalCoords, 2> origins;
+
+    const auto& frictionParset = this->parset_.sub("boundary.friction");
+
+#if MY_DIM == 3 // TODO: not implemented
+        std::array<double, 2> depths = {this->parset_.template get<double>("body0.depth"), this->parset_.template get<double>("body1.depth")};
+
+        origins[0] = {0, 0, 0};
+        origins[1] = {lengths[0]/2.0, origins[0][1] + heights[0], 0};
+
+        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lengths[0], heights[0], depths[0]);
+        cuboidGeometries_[0]->addWeakeningPatch(frictionParset, {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], depths[1]);
+        cuboidGeometries_[1]->addWeakeningPatch(frictionParset, origins[1], {origins[1][0] + lengths[1], origins[1][1], 0});
+        cuboidGeometries_[1]->addWeakeningPatch(frictionParset, origins[1], {origins[1][0] + lengths[1], origins[1][1] + heights[1], 0});
+
+#elif MY_DIM == 2
+        origins[0] = {0, 0};
+        origins[1] = {lengths[0]/2.0, origins[0][1] + heights[0]};
+
+        cuboidGeometries_[0] = std::make_shared<CuboidGeometry>(origins[0], lengths[0], heights[0]);
+        cuboidGeometries_[0]->addWeakeningPatch(frictionParset, {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(frictionParset, origins[1], {origins[1][0] + lengths[1], origins[1][1]});
+        cuboidGeometries_[1]->addWeakeningPatch(frictionParset, {origins[1][0] + lengths[1], origins[1][1]}, {origins[1][0] + lengths[1], origins[1][1] + heights[1]});
+#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;
+    }
+
+    bodyData_[0] = std::make_shared<MyBodyData<dim>>(this->parset_.sub("body0"), this->parset_.template get<double>("gravity"), zenith_());
+    this->bodies_[0] = std::make_shared<typename Base::LeafBody>(bodyData_[0], grids[0]);
+
+    bodyData_[1] = std::make_shared<MyBodyData<dim>>(this->parset_.sub("body1"), this->parset_.template get<double>("gravity"), zenith_());
+    this->bodies_[1] = std::make_shared<typename Base::LeafBody>(bodyData_[1], grids[1]);
+}
+
+template <class HostGridType, class VectorTEMPLATE>
+void TwoBlocksFactory<HostGridType, VectorTEMPLATE>::setLevelBodies() {
+    const size_t maxLevel = std::max({this->bodies_[0]->grid()->maxLevel(), this->bodies_[1]->grid()->maxLevel()});
+
+    for (size_t l=0; l<=maxLevel; l++) {
+        std::vector<size_t> bodyLevels(2, l);
+        this->contactNetwork_.addLevel(bodyLevels, l);
+    }
+}
+
+template <class HostGridType, class VectorTEMPLATE>
+void TwoBlocksFactory<HostGridType, VectorTEMPLATE>::setCouplings() {
+    for (size_t i=0; i<this->bodyCount_; i++) {
+        const auto& cuboidGeometry = *cuboidGeometries_[i];
+        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>>();
+
+    nonmortarPatch_[0] = std::make_shared<LevelBoundaryPatch>(levelFaces_[1]->lower);
+    mortarPatch_[0] = std::make_shared<LevelBoundaryPatch>(levelFaces_[0]->upper);
+    weakPatches_[0] = std::make_shared<WeakeningRegion>(cuboidGeometries_[1]->weakeningRegions()[0]);
+
+    auto& coupling = this->couplings_[0];
+    coupling = std::make_shared<typename Base::FrictionCouplingPair>();
+
+    coupling->set(1, 0, nonmortarPatch_[0], mortarPatch_[0], 0.1, Base::FrictionCouplingPair::CouplingType::STICK_SLIP, contactProjection, nullptr);
+    coupling->setWeakeningPatch(weakPatches_[0]);
+    coupling->setFrictionData(std::make_shared<MyGlobalFrictionData<GlobalCoords>>(this->parset_.sub("boundary.friction"), *weakPatches_[0], CuboidGeometry::lengthScale()));
+}
+
+template <class HostGridType, class VectorTEMPLATE>
+void TwoBlocksFactory<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();
+
+    // body0: Dirichlet boundary (lower)
+    const auto& body0 = this->contactNetwork_.body(0);
+    const auto& leafVertexCount0 = body0->nVertices();
+    std::shared_ptr<Dune::BitSetVector<dim>> zeroDirichletNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount0);
+    for (int j=0; j<leafVertexCount0; 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(body0->gridView(), zeroDirichletNodes);
+
+    std::shared_ptr<Function> zeroFunction = std::make_shared<NeumannCondition>();
+    zeroDirichletBoundary->setBoundaryFunction(zeroFunction);
+    body0->addBoundaryCondition(zeroDirichletBoundary);
+
+    // body1: Dirichlet boundary (upper)
+    const auto& body1 = this->contactNetwork_.body(1);
+    const auto& leafVertexCount1 = body1->nVertices();
+    std::shared_ptr<Dune::BitSetVector<dim>> velocityDirichletNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount1);
+    for (int j=0; j<leafVertexCount1; j++) {
+        if (leafFaces_[1]->upper.containsVertex(j))
+            (*velocityDirichletNodes)[j][0] = true;
+
+        #if MY_DIM == 3 //TODO: wrong, needs revision
+        if (leafFaces_[1]->front.containsVertex(j) || leafFaces_[1]->back.containsVertex(j))
+            zeroDirichletNodes->at(j)[2] = true;
+        #endif
+    }
+
+    std::shared_ptr<LeafBoundaryCondition> velocityDirichletBoundary = std::make_shared<LeafBoundaryCondition>("dirichlet");
+
+    velocityDirichletBoundary->setBoundaryPatch(body1->gridView(), velocityDirichletNodes);
+    velocityDirichletBoundary->setBoundaryFunction(velocityDirichletFunction);
+    body1->addBoundaryCondition(velocityDirichletBoundary);
+
+    // body0, body1: natural boundary conditions
+    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);
+    }
+
+    // body1: Neumann boundary (upper)
+    // normal load
+    std::shared_ptr<Dune::BitSetVector<dim>> loadNeumannNodes = std::make_shared<Dune::BitSetVector<dim>>(leafVertexCount1);
+    for (int j=0; j<leafVertexCount1; j++) {
+        if (leafFaces_[1]->upper.containsVertex(j))
+            (*loadNeumannNodes)[j][1] = true;
+
+        #if MY_DIM == 3 //TODO: wrong, needs revision
+        if (leafFaces_[1]->front.containsVertex(j) || leafFaces_[1]->back.containsVertex(j))
+            zeroDirichletNodes->at(j)[2] = true;
+        #endif
+    }
+
+    std::shared_ptr<LeafBoundaryCondition> loadNeumannBoundary = std::make_shared<LeafBoundaryCondition>("neumann");
+    std::shared_ptr<Function> constantFunction = std::make_shared<NeumannCondition>(this->parset_.template get<double>("boundary.neumann.sigmaN"));
+
+    loadNeumannBoundary->setBoundaryPatch(body1->gridView(), loadNeumannNodes);
+    loadNeumannBoundary->setBoundaryFunction(constantFunction);
+    body1->addBoundaryCondition(loadNeumannBoundary);
+}
+
+#include "twoblocksfactory_tmpl.cc"
diff --git a/dune/tectonic/factories/twoblocksfactory.hh b/dune/tectonic/factories/twoblocksfactory.hh
new file mode 100644
index 00000000..a02cd74a
--- /dev/null
+++ b/dune/tectonic/factories/twoblocksfactory.hh
@@ -0,0 +1,87 @@
+#ifndef DUNE_TECTONIC_FACTORIES_TWOBLOCKSFACTORY_HH
+#define DUNE_TECTONIC_FACTORIES_TWOBLOCKSFACTORY_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 "../problem-data/mybody.hh"
+#include "../problem-data/grid/mygrids.hh"
+#include "../problem-data/grid/cuboidgeometry.hh"
+
+template <class HostGridType, class VectorType> class TwoBlocksFactory : 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;
+
+    std::vector<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:
+    TwoBlocksFactory(const Dune::ParameterTree& parset) :
+        Base(parset, 2, 1),
+        bodyData_(2),
+        cuboidGeometries_(2),
+        leafFaces_(2),
+        levelFaces_(2),
+        weakPatches_(2),
+        nonmortarPatch_(1),
+        mortarPatch_(1)
+    {}
+
+    void setBodies();
+    void setLevelBodies();
+    void setCouplings();
+    void setLevelCouplings() {}
+    void setBoundaryConditions();
+
+    auto& weakPatches() {
+        return weakPatches_;
+    }
+
+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/dune/tectonic/factories/twoblocksfactory_tmpl.cc b/dune/tectonic/factories/twoblocksfactory_tmpl.cc
new file mode 100644
index 00000000..4a373e81
--- /dev/null
+++ b/dune/tectonic/factories/twoblocksfactory_tmpl.cc
@@ -0,0 +1,8 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
+
+template class TwoBlocksFactory<Grid, Vector>;
diff --git a/src/gridselector.hh b/dune/tectonic/gridselector.hh
similarity index 100%
rename from src/gridselector.hh
rename to dune/tectonic/gridselector.hh
diff --git a/dune/tectonic/io/CMakeLists.txt b/dune/tectonic/io/CMakeLists.txt
new file mode 100644
index 00000000..c1aada25
--- /dev/null
+++ b/dune/tectonic/io/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_subdirectory("hdf5")
+
+add_custom_target(tectonic_dune_io SOURCES
+  hdf5-bodywriter.hh
+  hdf5-levelwriter.hh 
+  uniform-grid-writer.cc
+  vtk.hh
+  vtk.cc
+)
+
+#install headers
+install(FILES
+  hdf5-bodywriter.hh
+  hdf5-levelwriter.hh 
+  vtk.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/io/hdf5-bodywriter.hh b/dune/tectonic/io/hdf5-bodywriter.hh
similarity index 64%
rename from src/io/hdf5-bodywriter.hh
rename to dune/tectonic/io/hdf5-bodywriter.hh
index 549062c7..dfb2b3aa 100644
--- a/src/io/hdf5-bodywriter.hh
+++ b/dune/tectonic/io/hdf5-bodywriter.hh
@@ -11,15 +11,17 @@
 template <class ProgramState, class VertexBasis, class GridView>
 class HDF5BodyWriter {
 private:
+    using PatchInfoWriter = PatchInfoWriter<ProgramState, VertexBasis, GridView>;
+    using FrictionalBoundaryWriter = FrictionalBoundaryWriter<ProgramState, GridView>;
+public:
     using VertexCoordinates = typename ProgramState::Vector;
     using FrictionPatches = std::vector<const BoundaryPatch<GridView>* >;
     using WeakPatches = std::vector<const ConvexPolyhedron<LocalVector>* >;
 
     using LocalVector = typename VertexCoordinates::block_type;
 
-    friend class HDF5LevelWriter<ProgramState, VertexBasis, GridView>;
+    //friend class HDF5LevelWriter<ProgramState, VertexBasis, GridView>;
 
-public:
     HDF5BodyWriter(
             HDF5::Grouplike &file,
             const VertexCoordinates& vertexCoordinates,
@@ -37,31 +39,22 @@ class HDF5BodyWriter {
 
         for (size_t i=0; i<patchCount_; i++) {
 #if MY_DIM == 3
-            patchInfoWriters_[i] = new PatchInfoWriter<ProgramState, VertexBasis, GridView>(file_, vertexBasis, *frictionPatches[i], *weakPatches[i], i);
-#endif
-            frictionBoundaryWriters_[i] = new FrictionalBoundaryWriter<ProgramState, GridView>(file_, vertexCoordinates, *frictionPatches[i], i);
-        }
-    }
-
-    ~HDF5BodyWriter() {
-        for (size_t i=0; i<patchCount_; i++) {
-#if MY_DIM == 3
-            delete patchInfoWriters_[i];
+            patchInfoWriters_[i] = std::make_unique<PatchInfoWriter>(file_, vertexBasis, *frictionPatches[i], *weakPatches[i], i);
 #endif
-            delete frictionBoundaryWriters_[i];
+            frictionBoundaryWriters_[i] = std::make_unique<FrictionalBoundaryWriter>(file_, vertexCoordinates, *frictionPatches[i], i);
         }
     }
 
     template <class Friction>
     void reportSolution(ProgramState const &programState,
                       // for the friction coefficient
-                      std::vector<std::shared_ptr<Friction>>& friction) {
+                      Friction& friction) {
 
         for (size_t i=0; i<patchCount_; i++) {
 #if MY_DIM == 3
             patchInfoWriters_[i]->write(programState);
 #endif
-            frictionBoundaryWriters_[i]->write(programState, *friction[i]);
+            frictionBoundaryWriters_[i]->write(programState, friction);
         }
     }
 
@@ -71,9 +64,9 @@ class HDF5BodyWriter {
     HDF5::Grouplike &file_;
 
 #if MY_DIM == 3
-    std::vector<PatchInfoWriter<ProgramState, VertexBasis, GridView>* > patchInfoWriters_;
+    std::vector<std::unique_ptr<PatchInfoWriter>> patchInfoWriters_;
 #endif
 
-    std::vector<FrictionalBoundaryWriter<ProgramState, GridView>* > frictionBoundaryWriters_;
+    std::vector<std::unique_ptr<FrictionalBoundaryWriter>> frictionBoundaryWriters_;
 };
 #endif
diff --git a/src/io/hdf5-levelwriter.hh b/dune/tectonic/io/hdf5-levelwriter.hh
similarity index 67%
rename from src/io/hdf5-levelwriter.hh
rename to dune/tectonic/io/hdf5-levelwriter.hh
index 66e3c048..4edabd8b 100644
--- a/src/io/hdf5-levelwriter.hh
+++ b/dune/tectonic/io/hdf5-levelwriter.hh
@@ -9,16 +9,14 @@
 
 template <class ProgramState, class VertexBasis, class GridView>
 class HDF5LevelWriter {
-private:
+public:
     using HDF5BodyWriter = HDF5BodyWriter<ProgramState, VertexBasis, GridView>;
     using VertexCoordinates = std::vector<typename HDF5BodyWriter::VertexCoordinates>;
-    using VertexBases = std::vector<VertexBasis>;
+    using VertexBases = std::vector<const VertexBasis*>;
     using FrictionPatches = std::vector<typename HDF5BodyWriter::FrictionPatches>;
     using WeakPatches = std::vector<typename HDF5BodyWriter::WeakPatches>;
 
-    friend class HDF5NetworkWriter<ProgramState, VertexBasis, GridView>;
-
-public:
+    //friend class HDF5NetworkWriter<ProgramState, VertexBasis, GridView>;
 
     HDF5LevelWriter(HDF5::Grouplike &file,
              const VertexCoordinates& vertexCoordinates,
@@ -32,31 +30,25 @@ class HDF5LevelWriter {
         bodyWriters_(bodyCount_) {
 
         for (size_t i=0; i<bodyCount_; i++) {
-            bodyWriters_[i] = new HDF5BodyWriter<ProgramState, VertexBasis, GridView>(file_, vertexCoordinates[i], vertexBases[i], frictionBoundaries[i], weakPatches[i]);
-        }
-    }
-
-    ~HDF5LevelWriter() {
-        for (size_t i=0; i<bodyCount_; i++) {
-            delete bodyWriters_[i];
+            bodyWriters_[i] = std::make_unique<HDF5BodyWriter>(file_, vertexCoordinates[i], *vertexBases[i], frictionBoundaries[i], weakPatches[i]);
         }
     }
 
     template <class Friction>
     void reportSolution(
-            ProgramState const &programState,
+            const ProgramState& programState,
             // for the friction coefficient
-            std::vector<std::shared_ptr<Friction>>& friction) {
+            Friction& friction) {
         timeWriter_.write(programState);
 
         for (size_t i=0; i<bodyCount_; i++) {
-            bodyWriters_[i]->reportSolution(programState, *friction[i]); //TODO
+            bodyWriters_[i]->reportSolution(programState, friction); //TODO
         }
     }
 
     void reportIterations(
-            ProgramState const &programState,
-            IterationRegister const &iterationCount) {
+            const ProgramState& programState,
+            const IterationRegister& iterationCount) {
         iterationWriter_.write(programState.timeStep, iterationCount);
   }
 
@@ -68,6 +60,6 @@ class HDF5LevelWriter {
   IterationWriter iterationWriter_;
   TimeWriter<ProgramState> timeWriter_;
 
-  std::vector<HDF5BodyWriter* > bodyWriters_;
+  std::vector<std::unique_ptr<HDF5BodyWriter>> bodyWriters_;
 };
 #endif
diff --git a/dune/tectonic/io/hdf5/CMakeLists.txt b/dune/tectonic/io/hdf5/CMakeLists.txt
new file mode 100644
index 00000000..511ce682
--- /dev/null
+++ b/dune/tectonic/io/hdf5/CMakeLists.txt
@@ -0,0 +1,26 @@
+add_custom_target(tectonic_dune_io_hdf5 SOURCES
+  frictionalboundary-writer.hh
+  frictionalboundary-writer.cc
+  iteration-writer.hh 
+  iteration-writer.cc
+  patchinfo-writer.hh 
+  patchinfo-writer.cc
+  restart-io.hh
+  restart-io.cc
+  restrict.hh
+  surface-writer.hh
+  surface-writer.cc
+  time-writer.hh
+  time-writer.cc
+)
+
+#install headers
+install(FILES
+  frictionalboundary-writer.hh
+  iteration-writer.hh 
+  patchinfo-writer.hh 
+  restart-io.hh
+  restrict.hh
+  surface-writer.hh
+  time-writer.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/io/hdf5/frictionalboundary-writer.cc b/dune/tectonic/io/hdf5/frictionalboundary-writer.cc
similarity index 93%
rename from src/io/hdf5/frictionalboundary-writer.cc
rename to dune/tectonic/io/hdf5/frictionalboundary-writer.cc
index 19641aa5..0cb5e01a 100644
--- a/src/io/hdf5/frictionalboundary-writer.cc
+++ b/dune/tectonic/io/hdf5/frictionalboundary-writer.cc
@@ -52,12 +52,13 @@ void FrictionalBoundaryWriter<ProgramState, GridView>::write(
   addEntry(frictionalBoundaryStateWriter_, programState.timeStep,
            frictionalBoundaryStates);
 
-  friction.updateAlpha(programState.alpha);
+  //TODO: needs to transform programState.v to relative velocities with nBodyAssembler
+  /*friction.updateAlpha(programState.alpha);
   auto const c = friction.coefficientOfFriction(programState.v[id_]);
   auto const frictionalBoundaryCoefficient =
       restrictToSurface(c, frictionalBoundary_);
   addEntry(frictionalBoundaryCoefficientWriter_, programState.timeStep,
-           frictionalBoundaryCoefficient);
+           frictionalBoundaryCoefficient);*/
 }
 
 #include "frictionalboundary-writer_tmpl.cc"
diff --git a/src/io/hdf5/frictionalboundary-writer.hh b/dune/tectonic/io/hdf5/frictionalboundary-writer.hh
similarity index 100%
rename from src/io/hdf5/frictionalboundary-writer.hh
rename to dune/tectonic/io/hdf5/frictionalboundary-writer.hh
diff --git a/src/io/hdf5/frictionalboundary-writer_tmpl.cc b/dune/tectonic/io/hdf5/frictionalboundary-writer_tmpl.cc
similarity index 100%
rename from src/io/hdf5/frictionalboundary-writer_tmpl.cc
rename to dune/tectonic/io/hdf5/frictionalboundary-writer_tmpl.cc
diff --git a/src/io/hdf5/iteration-writer.cc b/dune/tectonic/io/hdf5/iteration-writer.cc
similarity index 100%
rename from src/io/hdf5/iteration-writer.cc
rename to dune/tectonic/io/hdf5/iteration-writer.cc
diff --git a/src/io/hdf5/iteration-writer.hh b/dune/tectonic/io/hdf5/iteration-writer.hh
similarity index 100%
rename from src/io/hdf5/iteration-writer.hh
rename to dune/tectonic/io/hdf5/iteration-writer.hh
diff --git a/src/io/hdf5/patchinfo-writer.cc b/dune/tectonic/io/hdf5/patchinfo-writer.cc
similarity index 89%
rename from src/io/hdf5/patchinfo-writer.cc
rename to dune/tectonic/io/hdf5/patchinfo-writer.cc
index 82b394ea..c7a38dda 100644
--- a/src/io/hdf5/patchinfo-writer.cc
+++ b/dune/tectonic/io/hdf5/patchinfo-writer.cc
@@ -8,19 +8,19 @@
 #include "patchinfo-writer.hh"
 
 template <class LocalVector, class GridView>
-GridEvaluator<LocalVector, GridView>::GridEvaluator(
+GridEvaluator<LocalVector, GridView>::GridEvaluator(const CuboidGeometry& cuboidGeometry,
     ConvexPolyhedron<LocalVector> const &weakPatch, GridView const &gridView) {
-  double const bufferWidth = 0.05 * MyGeometry::lengthScale;
+  double const bufferWidth = 0.05 * cuboidGeometry.lengthScale();
   auto const xminmax = std::minmax_element(
       weakPatch.vertices.begin(), weakPatch.vertices.end(),
       [](LocalVector const &a, LocalVector const &b) { return a[0] < b[0]; });
   double const xmin = (*xminmax.first)[0] - bufferWidth;
   double const xspan = (*xminmax.second)[0] + bufferWidth - xmin;
 
-  double const zmin = -MyGeometry::depth / 2.0;
-  double const zspan = MyGeometry::depth;
+  double const zmin = -cuboidGeometry.depth() / 2.0;
+  double const zspan = cuboidGeometry.depth();
 
-  double spatialResolution = 0.01 * MyGeometry::lengthScale;
+  double spatialResolution = 0.01 * cuboidGeometry.lengthScale();
   size_t const xsteps = std::round(xspan / spatialResolution);
   size_t const zsteps = std::round(zspan / spatialResolution);
 
@@ -32,7 +32,7 @@ GridEvaluator<LocalVector, GridView>::GridEvaluator(
     zCoordinates[zi] = zmin + zi * zspan / zsteps;
 
   HierarchicApproximation<typename GridView::Grid, GridView> const
-      hApproximation(gridView.grid(), gridView, 1e-6 * MyGeometry::lengthScale);
+      hApproximation(gridView.grid(), gridView, 1e-6 * cuboidGeometry.lengthScale());
 
   LocalVector global(0);
   localInfo.resize(xsteps + 1);
diff --git a/src/io/hdf5/patchinfo-writer.hh b/dune/tectonic/io/hdf5/patchinfo-writer.hh
similarity index 83%
rename from src/io/hdf5/patchinfo-writer.hh
rename to dune/tectonic/io/hdf5/patchinfo-writer.hh
index cd446534..567c36e9 100644
--- a/src/io/hdf5/patchinfo-writer.hh
+++ b/dune/tectonic/io/hdf5/patchinfo-writer.hh
@@ -8,14 +8,16 @@
 #include <dune/fufem/geometry/convexpolyhedron.hh>
 #include <dune/fufem/hdf5/sequenceio.hh>
 
-#include "../../one-body-problem-data/mygeometry.hh"
+#include "../../problem-data/grid/cuboidgeometry.hh"
 
 template <class LocalVector, class GridView> class GridEvaluator {
   using Element = typename GridView::Grid::template Codim<0>::Entity;
+  using CuboidGeometry = CuboidGeometry<typename LocalVector::field_type>;
 
 public:
-  GridEvaluator(ConvexPolyhedron<LocalVector> const &weakPatch,
-                GridView const &gridView);
+  GridEvaluator(const CuboidGeometry& cuboidGeometry,
+                const ConvexPolyhedron<LocalVector>& weakPatch,
+                const GridView& gridView);
 
   template <class Function>
   Dune::Matrix<typename Function::RangeType> evaluate(Function const &f) const;
diff --git a/src/io/hdf5/patchinfo-writer_tmpl.cc b/dune/tectonic/io/hdf5/patchinfo-writer_tmpl.cc
similarity index 100%
rename from src/io/hdf5/patchinfo-writer_tmpl.cc
rename to dune/tectonic/io/hdf5/patchinfo-writer_tmpl.cc
diff --git a/src/io/hdf5/restart-io.cc b/dune/tectonic/io/hdf5/restart-io.cc
similarity index 100%
rename from src/io/hdf5/restart-io.cc
rename to dune/tectonic/io/hdf5/restart-io.cc
diff --git a/src/io/hdf5/restart-io.hh b/dune/tectonic/io/hdf5/restart-io.hh
similarity index 100%
rename from src/io/hdf5/restart-io.hh
rename to dune/tectonic/io/hdf5/restart-io.hh
diff --git a/src/io/hdf5/restart-io_tmpl.cc b/dune/tectonic/io/hdf5/restart-io_tmpl.cc
similarity index 100%
rename from src/io/hdf5/restart-io_tmpl.cc
rename to dune/tectonic/io/hdf5/restart-io_tmpl.cc
diff --git a/src/io/hdf5/restrict.hh b/dune/tectonic/io/hdf5/restrict.hh
similarity index 100%
rename from src/io/hdf5/restrict.hh
rename to dune/tectonic/io/hdf5/restrict.hh
diff --git a/src/io/hdf5/surface-writer.cc b/dune/tectonic/io/hdf5/surface-writer.cc
similarity index 100%
rename from src/io/hdf5/surface-writer.cc
rename to dune/tectonic/io/hdf5/surface-writer.cc
diff --git a/src/io/hdf5/surface-writer.hh b/dune/tectonic/io/hdf5/surface-writer.hh
similarity index 100%
rename from src/io/hdf5/surface-writer.hh
rename to dune/tectonic/io/hdf5/surface-writer.hh
diff --git a/src/io/hdf5/surface-writer_tmpl.cc b/dune/tectonic/io/hdf5/surface-writer_tmpl.cc
similarity index 100%
rename from src/io/hdf5/surface-writer_tmpl.cc
rename to dune/tectonic/io/hdf5/surface-writer_tmpl.cc
diff --git a/src/io/hdf5/time-writer.cc b/dune/tectonic/io/hdf5/time-writer.cc
similarity index 100%
rename from src/io/hdf5/time-writer.cc
rename to dune/tectonic/io/hdf5/time-writer.cc
diff --git a/src/io/hdf5/time-writer.hh b/dune/tectonic/io/hdf5/time-writer.hh
similarity index 100%
rename from src/io/hdf5/time-writer.hh
rename to dune/tectonic/io/hdf5/time-writer.hh
diff --git a/src/io/hdf5/time-writer_tmpl.cc b/dune/tectonic/io/hdf5/time-writer_tmpl.cc
similarity index 100%
rename from src/io/hdf5/time-writer_tmpl.cc
rename to dune/tectonic/io/hdf5/time-writer_tmpl.cc
diff --git a/src/io/uniform-grid-writer.cc b/dune/tectonic/io/uniform-grid-writer.cc
similarity index 100%
rename from src/io/uniform-grid-writer.cc
rename to dune/tectonic/io/uniform-grid-writer.cc
diff --git a/src/io/vtk.cc b/dune/tectonic/io/vtk.cc
similarity index 100%
rename from src/io/vtk.cc
rename to dune/tectonic/io/vtk.cc
diff --git a/src/io/vtk.hh b/dune/tectonic/io/vtk.hh
similarity index 100%
rename from src/io/vtk.hh
rename to dune/tectonic/io/vtk.hh
diff --git a/src/io/vtk_tmpl.cc b/dune/tectonic/io/vtk_tmpl.cc
similarity index 100%
rename from src/io/vtk_tmpl.cc
rename to dune/tectonic/io/vtk_tmpl.cc
diff --git a/dune/tectonic/minimisation.hh b/dune/tectonic/minimisation.hh
deleted file mode 100644
index 7933b7d8..00000000
--- a/dune/tectonic/minimisation.hh
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef DUNE_TECTONIC_MINIMISATION_HH
-#define DUNE_TECTONIC_MINIMISATION_HH
-
-#include <dune/common/fmatrix.hh>
-#include <dune/common/fvector.hh>
-#include <dune/common/stdstreams.hh>
-
-#include <dune/fufem/arithmetic.hh>
-#include <dune/fufem/interval.hh>
-#include <dune/tnnmg/problem-classes/bisection.hh>
-
-#include <dune/tectonic/mydirectionalconvexfunction.hh>
-
-// Warning: this exploits the property v*x = 0
-template <class Functional>
-double lineSearch(Functional const &J,
-                  typename Functional::LocalVector const &x,
-                  typename Functional::LocalVector const &v,
-                  Bisection const &bisection) {
-  MyDirectionalConvexFunction<typename Functional::Nonlinearity> const JRest(
-      J.alpha * v.two_norm2(), J.b * v, J.phi, x, v);
-  int count;
-  return bisection.minimize(JRest, 0.0, 0.0, count);
-}
-
-/** Minimise a quadratic problem, for which both the quadratic and the
-    nonlinear term have gradients which point in the direction of
-    their arguments */
-template <class Functional>
-void minimise(Functional const &J, typename Functional::LocalVector &x,
-              Bisection const &bisection) {
-  auto v = J.b;
-  double const vnorm = v.two_norm();
-  if (vnorm <= 0.0)
-    return;
-  v /= vnorm;
-
-  double const alpha = lineSearch(J, x, v, bisection);
-  Arithmetic::addProduct(x, alpha, v);
-}
-#endif
diff --git a/dune/tectonic/myblockproblem.hh b/dune/tectonic/myblockproblem.hh
deleted file mode 100644
index 78cf36f4..00000000
--- a/dune/tectonic/myblockproblem.hh
+++ /dev/null
@@ -1,273 +0,0 @@
-#ifndef DUNE_TECTONIC_MYBLOCKPROBLEM_HH
-#define DUNE_TECTONIC_MYBLOCKPROBLEM_HH
-
-// Based on dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh
-
-#include <dune/common/bitsetvector.hh>
-#include <dune/common/parametertree.hh>
-#include <dune/common/fmatrixev.hh>
-
-#include <dune/fufem/arithmetic.hh>
-#include <dune/solvers/common/interval.hh>
-#include <dune/solvers/computeenergy.hh>
-#include <dune/tnnmg/problem-classes/bisection.hh>
-#include <dune/tnnmg/problem-classes/blocknonlineargsproblem.hh>
-
-#include <dune/tectonic/globalfriction.hh>
-#include <dune/tectonic/minimisation.hh>
-#include <dune/tectonic/mydirectionalconvexfunction.hh>
-#include <dune/tectonic/quadraticenergy.hh>
-
-/** \brief Base class for problems where each block can be solved with a
- * modified gradient method */
-template <class ConvexProblem>
-class MyBlockProblem : /* not public */ BlockNonlinearGSProblem<ConvexProblem> {
-private:
-  typedef BlockNonlinearGSProblem<ConvexProblem> Base;
-
-public:
-  using typename Base::ConvexProblemType;
-  using typename Base::LocalMatrixType;
-  using typename Base::LocalVectorType;
-  using typename Base::MatrixType;
-  using typename Base::VectorType;
-
-  size_t static const block_size = ConvexProblem::block_size;
-  size_t static const coarse_block_size = block_size;
-
-  /** \brief Solves one local system */
-  class IterateObject;
-
-  struct Linearization {
-    size_t static const block_size = coarse_block_size;
-
-    using LocalMatrix = typename MyBlockProblem<ConvexProblem>::LocalMatrixType;
-    using MatrixType = Dune::BCRSMatrix<typename Linearization::LocalMatrix>;
-    using VectorType =
-        Dune::BlockVector<Dune::FieldVector<double, Linearization::block_size>>;
-    using BitVectorType = Dune::BitSetVector<Linearization::block_size>;
-
-    typename Linearization::MatrixType A;
-    typename Linearization::VectorType b;
-    typename Linearization::BitVectorType ignore;
-
-    Dune::BitSetVector<Linearization::block_size> truncation;
-  };
-
-  MyBlockProblem(Dune::ParameterTree const &parset, ConvexProblem &problem)
-      : Base(parset, problem),
-        maxEigenvalues_(problem.f.size()),
-        localBisection(0.0, 1.0, 0.0, 0.0) {
-    for (size_t i = 0; i < problem.f.size(); ++i) {
-      LocalVectorType eigenvalues;
-      Dune::FMatrixHelp::eigenValues(problem.A[i][i], eigenvalues);
-      maxEigenvalues_[i] =
-          *std::max_element(std::begin(eigenvalues), std::end(eigenvalues));
-    }
-  }
-
-  std::string getOutput(bool header = false) const {
-    if (header) {
-      outStream.str("");
-      for (size_t j = 0; j < block_size; ++j)
-        outStream << "  trunc" << std::setw(2) << j;
-    }
-    std::string s = outStream.str();
-    outStream.str("");
-    return s;
-  }
-
-  double computeEnergy(const VectorType &v) const {
-    return 0.0; // FIXME
-    // return ::computeEnergy(problem_.A, v, problem_.f) + problem_.phi(v);
-  }
-
-  void projectCoarseCorrection(VectorType const &u,
-                               typename Linearization::VectorType const &v,
-                               VectorType &projected_v,
-                               Linearization const &linearization) const {
-    projected_v = v;
-    for (size_t i = 0; i < v.size(); ++i)
-      for (size_t j = 0; j < block_size; ++j)
-        if (linearization.truncation[i][j])
-          projected_v[i][j] = 0;
-  }
-
-  double computeDampingParameter(VectorType const &u,
-                                 VectorType const &projected_v) const {
-    VectorType v = projected_v;
-
-    double const vnorm = v.two_norm();
-    if (vnorm <= 0)
-      return 1.0;
-
-    v /= vnorm; // Rescale for numerical stability
-
-    auto const psi = restrict(problem_.A, problem_.f, u, v, problem_.phi);
-    Dune::Solvers::Interval<double> D;
-    psi.subDiff(0, D);
-    if (D[1] > 0) // NOTE: Numerical instability can actually get us here
-      return 0;
-
-    int bisectionsteps = 0;
-    Bisection const globalBisection; // NOTE: defaults
-    return globalBisection.minimize(psi, vnorm, 0.0, bisectionsteps) / vnorm;
-  }
-
-  void assembleTruncate(VectorType const &u, Linearization &linearization,
-                        Dune::BitSetVector<block_size> const &ignore) const {
-    // we can just copy the ignore information
-    linearization.ignore = ignore;
-
-    // determine truncation pattern
-    linearization.truncation.resize(u.size());
-    linearization.truncation.unsetAll();
-    for (size_t i = 0; i < u.size(); ++i) {
-      if (problem_.phi.regularity(i, u[i]) > 1e8) { // TODO: Make customisable
-        linearization.truncation[i] = true;
-        continue;
-      }
-
-      for (size_t j = 0; j < block_size; ++j)
-        if (linearization.ignore[i][j])
-          linearization.truncation[i][j] = true;
-    }
-
-    // construct sparsity pattern for linearization
-    Dune::MatrixIndexSet indices(problem_.A.N(), problem_.A.M());
-    indices.import(problem_.A);
-    problem_.phi.addHessianIndices(indices);
-
-    // construct matrix from pattern and initialize it
-    indices.exportIdx(linearization.A);
-    linearization.A = 0.0;
-
-    // compute quadratic part of hessian (linearization.A += problem_.A)
-    for (size_t i = 0; i < problem_.A.N(); ++i) {
-      auto const end = std::end(problem_.A[i]);
-      for (auto it = std::begin(problem_.A[i]); it != end; ++it)
-        linearization.A[i][it.index()] += *it;
-    }
-
-    // compute nonlinearity part of hessian
-    problem_.phi.addHessian(u, linearization.A);
-
-    // compute quadratic part of gradient
-    linearization.b.resize(u.size());
-    problem_.A.mv(u, linearization.b);
-    linearization.b -= problem_.f;
-
-    // compute nonlinearity part of gradient
-    problem_.phi.addGradient(u, linearization.b);
-
-    // -grad is needed for Newton step
-    linearization.b *= -1.0;
-
-    // apply truncation to stiffness matrix and rhs
-    for (size_t row = 0; row < linearization.A.N(); ++row) {
-      auto const col_end = std::end(linearization.A[row]);
-      for (auto col_it = std::begin(linearization.A[row]); col_it != col_end;
-           ++col_it) {
-        size_t const col = col_it.index();
-        for (size_t i = 0; i < col_it->N(); ++i) {
-          auto const blockEnd = std::end((*col_it)[i]);
-          for (auto blockIt = std::begin((*col_it)[i]); blockIt != blockEnd;
-               ++blockIt)
-            if (linearization.truncation[row][i] or
-                linearization.truncation[col][blockIt.index()])
-              *blockIt = 0.0;
-        }
-      }
-      for (size_t j = 0; j < block_size; ++j)
-        if (linearization.truncation[row][j])
-          linearization.b[row][j] = 0.0;
-    }
-    for (size_t j = 0; j < block_size; ++j)
-      outStream << std::setw(9) << linearization.truncation.countmasked(j);
-  }
-
-  /** \brief Constructs and returns an iterate object */
-  IterateObject getIterateObject() {
-    return IterateObject(localBisection, problem_, maxEigenvalues_);
-  }
-
-private:
-  std::vector<double> maxEigenvalues_;
-
-  // problem data
-  using Base::problem_;
-
-  Bisection const localBisection;
-
-  mutable std::ostringstream outStream;
-};
-
-/** \brief Solves one local system using a scalar Gauss-Seidel method */
-template <class ConvexProblem>
-class MyBlockProblem<ConvexProblem>::IterateObject {
-  friend class MyBlockProblem;
-
-protected:
-  /** \brief Constructor, protected so only friends can instantiate it
-   * \param bisection The class used to do a scalar bisection
-   * \param problem The problem including quadratic part and nonlinear part
-   */
-  IterateObject(Bisection const &bisection, ConvexProblem const &problem,
-                std::vector<double> const &maxEigenvalues)
-      : problem(problem),
-        maxEigenvalues_(maxEigenvalues),
-        bisection_(bisection) {}
-
-public:
-  /** \brief Set the current iterate */
-  void setIterate(VectorType &u) {
-    this->u = u;
-    return;
-  }
-
-  /** \brief Update the i-th block of the current iterate */
-  void updateIterate(LocalVectorType const &ui, size_t i) {
-    u[i] = ui;
-    return;
-  }
-
-  /** \brief Minimise a local problem
-   * \param[out] ui The solution
-   * \param m Block number
-   * \param ignore Set of degrees of freedom to leave untouched
-   */
-  void solveLocalProblem(
-      LocalVectorType &ui, size_t m,
-      typename Dune::BitSetVector<block_size>::const_reference ignore) {
-    {
-      LocalVectorType localb = problem.f[m];
-      auto const end = std::end(problem.A[m]);
-      for (auto it = std::begin(problem.A[m]); it != end; ++it) {
-        size_t const j = it.index();
-        Arithmetic::subtractProduct(localb, *it, u[j]); // also the diagonal!
-      }
-      Arithmetic::addProduct(localb, maxEigenvalues_[m], u[m]);
-
-      // We minimise over an affine subspace
-      for (size_t j = 0; j < block_size; ++j)
-        if (ignore[j])
-          localb[j] = 0;
-        else
-          ui[j] = 0;
-
-      QuadraticEnergy<
-          typename ConvexProblem::NonlinearityType::LocalNonlinearity>
-          localJ(maxEigenvalues_[m], localb, problem.phi.restriction(m));
-      minimise(localJ, ui, bisection_);
-    }
-  }
-
-private:
-  ConvexProblem const &problem;
-  std::vector<double> maxEigenvalues_;
-  Bisection const bisection_;
-  // state data for smoothing procedure used by:
-  // setIterate, updateIterate, solveLocalProblem
-  VectorType u;
-};
-#endif
diff --git a/dune/tectonic/problem-data/CMakeLists.txt b/dune/tectonic/problem-data/CMakeLists.txt
new file mode 100644
index 00000000..8b975765
--- /dev/null
+++ b/dune/tectonic/problem-data/CMakeLists.txt
@@ -0,0 +1,22 @@
+add_subdirectory("grid")
+
+add_custom_target(tectonic_dune_problem-data SOURCES
+  bc.hh
+  gravity.hh 
+  midpoint.hh
+  mybody.hh
+  myglobalfrictiondata.hh
+  patchfunction.hh
+  segmented-function.hh
+)
+
+#install headers
+install(FILES
+  bc.hh
+  gravity.hh 
+  midpoint.hh
+  mybody.hh
+  myglobalfrictiondata.hh
+  patchfunction.hh
+  segmented-function.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/multi-body-problem-data/bc.hh b/dune/tectonic/problem-data/bc.hh
similarity index 69%
rename from src/multi-body-problem-data/bc.hh
rename to dune/tectonic/problem-data/bc.hh
index f9e167ac..2d478035 100644
--- a/src/multi-body-problem-data/bc.hh
+++ b/dune/tectonic/problem-data/bc.hh
@@ -7,14 +7,14 @@ class VelocityDirichletCondition
     : public Dune::VirtualFunction<double, double> {
   void evaluate(double const &relativeTime, double &y) const {
     // Assumed to vanish at time zero
-      double const finalVelocity = -5e-5;
+      double const finalVelocity = 5e-5;
     
     //std::cout << "VelocityDirichletCondition::evaluate()" << std::endl;
     
-    if (relativeTime <= 0.1)
+    /*if (relativeTime <= 0.1)
         std::cout << "- loading phase" << std::endl;
     else
-        std::cout << "- final velocity reached" << std::endl;
+        std::cout << "- final velocity reached" << std::endl;*/
     
     y = (relativeTime <= 0.1)
             ? finalVelocity * (1.0 - std::cos(relativeTime * M_PI / 0.1)) / 2.0
@@ -23,6 +23,11 @@ class VelocityDirichletCondition
 };
 
 class NeumannCondition : public Dune::VirtualFunction<double, double> {
-  void evaluate(double const &relativeTime, double &y) const { y = 0.0; }
+  public:
+    NeumannCondition(double c = 0.0) : c_(c) {}
+    void evaluate(double const &relativeTime, double &y) const { y = c_; }
+
+  private:
+    double c_;
 };
 #endif
diff --git a/dune/tectonic/gravity.hh b/dune/tectonic/problem-data/gravity.hh
similarity index 100%
rename from dune/tectonic/gravity.hh
rename to dune/tectonic/problem-data/gravity.hh
diff --git a/dune/tectonic/problem-data/grid/CMakeLists.txt b/dune/tectonic/problem-data/grid/CMakeLists.txt
new file mode 100644
index 00000000..e0fd59ba
--- /dev/null
+++ b/dune/tectonic/problem-data/grid/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_custom_target(tectonic_dune_problem-data_grid SOURCES
+  cube.hh
+  cube.cc 
+  cubefaces.hh
+  cubefaces.cc
+  cubegridconstructor.hh
+  cuboidgeometry.hh
+  cuboidgeometry.cc
+  gridconstructor.hh
+  mygrids.hh
+  mygrids.cc
+  simplexmanager.hh
+  simplexmanager.cc
+)
+
+#install headers
+install(FILES
+  cube.hh
+  cubefaces.hh
+  cubegridconstructor.hh
+  cuboidgeometry.hh
+  gridconstructor.hh
+  mygrids.hh
+  simplexmanager.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/multi-body-problem-data/grid/cube.cc b/dune/tectonic/problem-data/grid/cube.cc
similarity index 100%
rename from src/multi-body-problem-data/grid/cube.cc
rename to dune/tectonic/problem-data/grid/cube.cc
diff --git a/src/multi-body-problem-data/grid/cube.hh b/dune/tectonic/problem-data/grid/cube.hh
similarity index 100%
rename from src/multi-body-problem-data/grid/cube.hh
rename to dune/tectonic/problem-data/grid/cube.hh
diff --git a/src/multi-body-problem-data/grid/cube_tmpl.cc b/dune/tectonic/problem-data/grid/cube_tmpl.cc
similarity index 100%
rename from src/multi-body-problem-data/grid/cube_tmpl.cc
rename to dune/tectonic/problem-data/grid/cube_tmpl.cc
diff --git a/src/multi-body-problem-data/grid/cubefaces.cc b/dune/tectonic/problem-data/grid/cubefaces.cc
similarity index 100%
rename from src/multi-body-problem-data/grid/cubefaces.cc
rename to dune/tectonic/problem-data/grid/cubefaces.cc
diff --git a/src/multi-body-problem-data/grid/cubefaces.hh b/dune/tectonic/problem-data/grid/cubefaces.hh
similarity index 100%
rename from src/multi-body-problem-data/grid/cubefaces.hh
rename to dune/tectonic/problem-data/grid/cubefaces.hh
diff --git a/src/multi-body-problem-data/grid/cubefaces_tmpl.cc b/dune/tectonic/problem-data/grid/cubefaces_tmpl.cc
similarity index 100%
rename from src/multi-body-problem-data/grid/cubefaces_tmpl.cc
rename to dune/tectonic/problem-data/grid/cubefaces_tmpl.cc
diff --git a/src/multi-body-problem-data/grid/cubegridconstructor.hh b/dune/tectonic/problem-data/grid/cubegridconstructor.hh
similarity index 100%
rename from src/multi-body-problem-data/grid/cubegridconstructor.hh
rename to dune/tectonic/problem-data/grid/cubegridconstructor.hh
diff --git a/src/multi-body-problem-data/grid/cuboidgeometry.cc b/dune/tectonic/problem-data/grid/cuboidgeometry.cc
similarity index 94%
rename from src/multi-body-problem-data/grid/cuboidgeometry.cc
rename to dune/tectonic/problem-data/grid/cuboidgeometry.cc
index 2fe7b2b5..3b86bc10 100644
--- a/src/multi-body-problem-data/grid/cuboidgeometry.cc
+++ b/dune/tectonic/problem-data/grid/cuboidgeometry.cc
@@ -16,9 +16,9 @@
 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),
-    height_(height*lengthScale),
-    depth_(depth*lengthScale),
+    length_(length*lengthScale()),
+    height_(height*lengthScale()),
+    depth_(depth*lengthScale()),
     lowerLeft_(origin),
     lowerRight_({origin[0]+length_, origin[1], 0}),
     upperRight_({origin[0]+length_, origin[1]+height_, 0}),
@@ -29,8 +29,8 @@ CuboidGeometry<ctype>::CuboidGeometry(const GlobalCoords& origin,
 template <class ctype>
 CuboidGeometry<ctype>::CuboidGeometry(const GlobalCoords& origin,
                                       const double length, const double height) :
-    length_(length*lengthScale),
-    height_(height*lengthScale),
+    length_(length*lengthScale()),
+    height_(height*lengthScale()),
     lowerLeft_(origin),
     lowerRight_({origin[0]+length_, origin[1]}),
     upperRight_({origin[0]+length_, origin[1]+height_}),
@@ -61,8 +61,8 @@ void CuboidGeometry<ctype>::addWeakeningPatch(const Dune::ParameterTree& parset,
             case Config::Rectangular:
                 break;
             case Config::Trapezoidal:
-                weakPatch.vertices[1][0] += 0.05 * lengthScale;
-                weakPatch.vertices[3][0] -= 0.05 * lengthScale;
+                weakPatch.vertices[1][0] += 0.05 * lengthScale();
+                weakPatch.vertices[3][0] -= 0.05 * lengthScale();
                 break;
             default:
                 assert(false);
diff --git a/src/multi-body-problem-data/grid/cuboidgeometry.hh b/dune/tectonic/problem-data/grid/cuboidgeometry.hh
similarity index 95%
rename from src/multi-body-problem-data/grid/cuboidgeometry.hh
rename to dune/tectonic/problem-data/grid/cuboidgeometry.hh
index 56998355..2b382ac1 100644
--- a/src/multi-body-problem-data/grid/cuboidgeometry.hh
+++ b/dune/tectonic/problem-data/grid/cuboidgeometry.hh
@@ -14,7 +14,9 @@ class CuboidGeometry {
     typedef Dune::FieldVector<ctype, MY_DIM> GlobalCoords;
     using WeakeningRegion = ConvexPolyhedron<GlobalCoords>;
 
-    constexpr static double const lengthScale = 1.0; // scaling factor
+    static constexpr double lengthScale() {
+        return 1.0;
+    } // scaling factor
 
 private:
     const ctype length_;
diff --git a/src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc b/dune/tectonic/problem-data/grid/cuboidgeometry_tmpl.cc
similarity index 100%
rename from src/multi-body-problem-data/grid/cuboidgeometry_tmpl.cc
rename to dune/tectonic/problem-data/grid/cuboidgeometry_tmpl.cc
diff --git a/src/multi-body-problem-data/grid/gridconstructor.hh b/dune/tectonic/problem-data/grid/gridconstructor.hh
similarity index 100%
rename from src/multi-body-problem-data/grid/gridconstructor.hh
rename to dune/tectonic/problem-data/grid/gridconstructor.hh
diff --git a/src/multi-body-problem-data/grid/mygrids.cc b/dune/tectonic/problem-data/grid/mygrids.cc
similarity index 97%
rename from src/multi-body-problem-data/grid/mygrids.cc
rename to dune/tectonic/problem-data/grid/mygrids.cc
index 874f4c6e..e3179f2a 100644
--- a/src/multi-body-problem-data/grid/mygrids.cc
+++ b/dune/tectonic/problem-data/grid/mygrids.cc
@@ -115,11 +115,11 @@ bool MyFaces<GridView>::xyBoxed(Vector const &v1, Vector const &v2,
   auto const minmax0 = std::minmax(v1[0], v2[0]);
   auto const minmax1 = std::minmax(v1[1], v2[1]);
 
-  if (minmax0.first - 1e-14 * cuboidGeometry.lengthScale > x[0] or
-      x[0] > minmax0.second + 1e-14 * cuboidGeometry.lengthScale)
+  if (minmax0.first - 1e-14 * cuboidGeometry.lengthScale() > x[0] or
+      x[0] > minmax0.second + 1e-14 * cuboidGeometry.lengthScale())
     return false;
-  if (minmax1.first - 1e-14 * cuboidGeometry.lengthScale > x[1] or
-      x[1] > minmax1.second + 1e-14 * cuboidGeometry.lengthScale)
+  if (minmax1.first - 1e-14 * cuboidGeometry.lengthScale() > x[1] or
+      x[1] > minmax1.second + 1e-14 * cuboidGeometry.lengthScale())
     return false;
 
   return true;
diff --git a/src/multi-body-problem-data/grid/mygrids.hh b/dune/tectonic/problem-data/grid/mygrids.hh
similarity index 93%
rename from src/multi-body-problem-data/grid/mygrids.hh
rename to dune/tectonic/problem-data/grid/mygrids.hh
index 574efa1d..62b440f5 100644
--- a/src/multi-body-problem-data/grid/mygrids.hh
+++ b/dune/tectonic/problem-data/grid/mygrids.hh
@@ -26,12 +26,12 @@ template <class GridView> struct MyFaces {
   const CuboidGeometry<typename GridView::ctype>& cuboidGeometry;
 
   bool isClose(double a, double b) {
-    return std::abs(a - b) < 1e-14 * cuboidGeometry.lengthScale;
+    return std::abs(a - b) < 1e-14 * cuboidGeometry.lengthScale();
   }
 
   bool isClose2(double a, double b) {
     return std::abs(a - b) <
-           1e-14 * cuboidGeometry.lengthScale * cuboidGeometry.lengthScale;
+           1e-14 * cuboidGeometry.lengthScale() * cuboidGeometry.lengthScale();
   }
 
   template <class Vector>
diff --git a/src/multi-body-problem-data/grid/mygrids_tmpl.cc b/dune/tectonic/problem-data/grid/mygrids_tmpl.cc
similarity index 100%
rename from src/multi-body-problem-data/grid/mygrids_tmpl.cc
rename to dune/tectonic/problem-data/grid/mygrids_tmpl.cc
diff --git a/src/multi-body-problem-data/grid/simplexmanager.cc b/dune/tectonic/problem-data/grid/simplexmanager.cc
similarity index 100%
rename from src/multi-body-problem-data/grid/simplexmanager.cc
rename to dune/tectonic/problem-data/grid/simplexmanager.cc
diff --git a/src/multi-body-problem-data/grid/simplexmanager.hh b/dune/tectonic/problem-data/grid/simplexmanager.hh
similarity index 100%
rename from src/multi-body-problem-data/grid/simplexmanager.hh
rename to dune/tectonic/problem-data/grid/simplexmanager.hh
diff --git a/src/multi-body-problem-data/midpoint.hh b/dune/tectonic/problem-data/midpoint.hh
similarity index 100%
rename from src/multi-body-problem-data/midpoint.hh
rename to dune/tectonic/problem-data/midpoint.hh
diff --git a/src/multi-body-problem-data/mybody.hh b/dune/tectonic/problem-data/mybody.hh
similarity index 65%
rename from src/multi-body-problem-data/mybody.hh
rename to dune/tectonic/problem-data/mybody.hh
index c0160dde..e50e1793 100644
--- a/src/multi-body-problem-data/mybody.hh
+++ b/dune/tectonic/problem-data/mybody.hh
@@ -5,9 +5,8 @@
 
 #include <dune/fufem/functions/constantfunction.hh>
 
-#include <dune/tectonic/bodydata.hh>
-#include <dune/tectonic/gravity.hh>
-
+#include "../data-structures/body/bodydata.hh"
+#include "gravity.hh"
 #include "grid/cuboidgeometry.hh"
 #include "segmented-function.hh"
 
@@ -16,21 +15,21 @@ template <int dimension> class MyBodyData : public BodyData<dimension> {
   using typename BodyData<dimension>::VectorField;
 
 public:
-  MyBodyData(Dune::ParameterTree const &parset, const Dune::FieldVector<double, dimension>& zenith)
-      : poissonRatio_(parset.get<double>("body.poissonRatio")),
-        youngModulus_(3.0 * parset.get<double>("body.bulkModulus") *
+  MyBodyData(Dune::ParameterTree const &parset, const double gravity, const Dune::FieldVector<double, dimension>& zenith)
+      : poissonRatio_(parset.get<double>("poissonRatio")),
+        youngModulus_(3.0 * parset.get<double>("bulkModulus") *
                       (1.0 - 2.0 * poissonRatio_)),
         zenith_(zenith),
         shearViscosityField_(
-            parset.get<double>("body.elastic.shearViscosity"),
-            parset.get<double>("body.viscoelastic.shearViscosity")),
+            parset.get<double>("elastic.shearViscosity"),
+            parset.get<double>("viscoelastic.shearViscosity")),
         bulkViscosityField_(
-            parset.get<double>("body.elastic.bulkViscosity"),
-            parset.get<double>("body.viscoelastic.bulkViscosity")),
-        densityField_(parset.get<double>("body.elastic.density"),
-                      parset.get<double>("body.viscoelastic.density")),
+            parset.get<double>("elastic.bulkViscosity"),
+            parset.get<double>("viscoelastic.bulkViscosity")),
+        densityField_(parset.get<double>("elastic.density"),
+                      parset.get<double>("viscoelastic.density")),
         gravityField_(densityField_, zenith_,
-                      parset.get<double>("gravity")) {}
+                      gravity) {}
 
   double getPoissonRatio() const override { return poissonRatio_; }
   double getYoungModulus() const override { return youngModulus_; }
diff --git a/src/multi-body-problem-data/myglobalfrictiondata.hh b/dune/tectonic/problem-data/myglobalfrictiondata.hh
similarity index 95%
rename from src/multi-body-problem-data/myglobalfrictiondata.hh
rename to dune/tectonic/problem-data/myglobalfrictiondata.hh
index 7666a467..f416f492 100644
--- a/src/multi-body-problem-data/myglobalfrictiondata.hh
+++ b/dune/tectonic/problem-data/myglobalfrictiondata.hh
@@ -3,7 +3,7 @@
 
 #include <dune/common/function.hh>
 
-#include <dune/tectonic/globalfrictiondata.hh>
+#include "../data-structures/friction/globalfrictiondata.hh"
 
 #include "patchfunction.hh"
 
diff --git a/src/multi-body-problem-data/patchfunction.hh b/dune/tectonic/problem-data/patchfunction.hh
similarity index 100%
rename from src/multi-body-problem-data/patchfunction.hh
rename to dune/tectonic/problem-data/patchfunction.hh
diff --git a/src/multi-body-problem-data/segmented-function.hh b/dune/tectonic/problem-data/segmented-function.hh
similarity index 100%
rename from src/multi-body-problem-data/segmented-function.hh
rename to dune/tectonic/problem-data/segmented-function.hh
diff --git a/dune/tectonic/quadraticenergy.hh b/dune/tectonic/quadraticenergy.hh
deleted file mode 100644
index 9f3b8c9e..00000000
--- a/dune/tectonic/quadraticenergy.hh
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef DUNE_TECTONIC_QUADRATICENERGY_HH
-#define DUNE_TECTONIC_QUADRATICENERGY_HH
-
-#include <memory>
-
-template <class NonlinearityTEMPLATE> class QuadraticEnergy {
-public:
-  using Nonlinearity = NonlinearityTEMPLATE;
-  using LocalVector = typename Nonlinearity::VectorType;
-
-  QuadraticEnergy(double alpha, LocalVector const &b, Nonlinearity const &phi)
-      : alpha(alpha), b(b), phi(phi) {}
-
-  double const alpha;
-  LocalVector const &b;
-  Nonlinearity const &phi;
-};
-#endif
diff --git a/dune/tectonic/spatial-solving/CMakeLists.txt b/dune/tectonic/spatial-solving/CMakeLists.txt
new file mode 100644
index 00000000..75fd6237
--- /dev/null
+++ b/dune/tectonic/spatial-solving/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_subdirectory("tnnmg")
+add_subdirectory("preconditioners")
+
+add_custom_target(tectonic_dune_spatial-solving SOURCES
+  fixedpointiterator.hh
+  fixedpointiterator.cc
+  solverfactory.hh
+  solverfactory.cc
+)
+
+#install headers
+install(FILES
+  fixedpointiterator.hh
+  solverfactory.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/spatial-solving/fixedpointiterator.cc b/dune/tectonic/spatial-solving/fixedpointiterator.cc
similarity index 61%
rename from src/spatial-solving/fixedpointiterator.cc
rename to dune/tectonic/spatial-solving/fixedpointiterator.cc
index 43df107c..298e2f94 100644
--- a/src/spatial-solving/fixedpointiterator.cc
+++ b/dune/tectonic/spatial-solving/fixedpointiterator.cc
@@ -25,7 +25,7 @@
 #include "../data-structures/enums.hh"
 #include "../data-structures/enumparser.hh"
 
-#include "fixedpointiterator.hh"
+
 
 #include "../utils/tobool.hh"
 #include "../utils/debugutils.hh"
@@ -38,7 +38,8 @@
 
 #include "tnnmg/functional.hh"
 #include "tnnmg/zerononlinearity.hh"
-#include "solverfactory.hh"
+
+#include "fixedpointiterator.hh"
 
 void FixedPointIterationCounter::operator+=(
     FixedPointIterationCounter const &other) {
@@ -46,16 +47,16 @@ void FixedPointIterationCounter::operator+=(
   multigridIterations += other.multigridIterations;
 }
 
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
-FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::FixedPointIterator(
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::FixedPointIterator(
     Dune::ParameterTree const &parset,
-    const ContactNetwork& contactNetwork,
+    const NBodyAssembler& nBodyAssembler,
     const IgnoreVector& ignoreNodes,
     GlobalFriction& globalFriction,
     const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
     const ErrorNorms& errorNorms)
     : parset_(parset),
-      contactNetwork_(contactNetwork),
+      nBodyAssembler_(nBodyAssembler),
       ignoreNodes_(ignoreNodes),
       globalFriction_(globalFriction),
       bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries),
@@ -67,24 +68,23 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::FixedPointIte
       verbosity_(parset.get<Solver::VerbosityMode>("v.solver.verbosity")),
       errorNorms_(errorNorms) {}
 
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+template <class LinearSolver>
 FixedPointIterationCounter
-FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run(
-    Updaters updaters,
+FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run(
+    Updaters updaters, std::shared_ptr<LinearSolver>& linearSolver,
     const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs,
     std::vector<Vector>& velocityIterates) {
 
-  std::cout << "FixedPointIterator::run()" << std::endl;
-
-  const auto& nBodyAssembler = contactNetwork_.nBodyAssembler();
+  //std::cout << "FixedPointIterator::run()" << std::endl;
 
   // debugging
-  const auto& contactCouplings = nBodyAssembler.getContactCouplings();
+  /*const auto& contactCouplings = nBodyAssembler_.getContactCouplings();
   for (size_t i=0; i<contactCouplings.size(); i++) {
     print(*contactCouplings[i]->nonmortarBoundary().getVertices(), "nonmortarBoundaries:");
-  }
+  }*/
 
-  const auto nBodies = nBodyAssembler.nGrids();
+  const auto nBodies = nBodyAssembler_.nGrids();
 
   std::vector<const Matrix*> matrices_ptr(nBodies);
   for (int i=0; i<nBodies; i++) {
@@ -93,17 +93,17 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run(
 
   // assemble full global contact problem
   Matrix bilinearForm;
-  nBodyAssembler.assembleJacobian(matrices_ptr, bilinearForm);
+  nBodyAssembler_.assembleJacobian(matrices_ptr, bilinearForm);
 
-  print(bilinearForm, "bilinearForm:");
+  //print(bilinearForm, "bilinearForm:");
 
   Vector totalRhs;
-  nBodyAssembler.assembleRightHandSide(velocityRHSs, totalRhs);
+  nBodyAssembler_.assembleRightHandSide(velocityRHSs, totalRhs);
 
-  print(totalRhs, "totalRhs:");
+  //print(totalRhs, "totalRhs:");
 
   // get lower and upper obstacles
-  const auto& totalObstacles = nBodyAssembler.totalObstacles_;
+  const auto& totalObstacles = nBodyAssembler_.totalObstacles_;
   Vector lower(totalObstacles.size());
   Vector upper(totalObstacles.size());
 
@@ -117,159 +117,160 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run(
     }
   }
 
-  print(totalObstacles, "totalObstacles:");
+  //print(totalObstacles, "totalObstacles:");
 
-  print(lower, "lower obstacles:");
-  print(upper, "upper obstacles:");
+  //print(lower, "lower obstacles:");
+  //print(upper, "upper obstacles:");
 
   // compute velocity obstacles
-  Vector vLower, vUpper;
+  /*Vector vLower, vUpper;
   std::vector<Vector> u0, v0;
   updaters.rate_->extractOldVelocity(v0);
   updaters.rate_->extractOldDisplacement(u0);
 
   Vector totalu0, totalv0;
-  nBodyAssembler.concatenateVectors(u0, totalu0);
-  nBodyAssembler.concatenateVectors(v0, totalv0);
+  nBodyAssembler_.concatenateVectors(u0, totalu0);
+  nBodyAssembler_.concatenateVectors(v0, totalv0);
 
   updaters.rate_->velocityObstacles(totalu0, lower, totalv0, vLower);
-  updaters.rate_->velocityObstacles(totalu0, upper, totalv0, vUpper);
-
-  print(vLower, "vLower obstacles:");
-  print(vUpper, "vUpper obstacles:");
+  updaters.rate_->velocityObstacles(totalu0, upper, totalv0, vUpper); */
 
-  std::cout << "- Problem assembled: success" << std::endl;
+  //print(vLower, "vLower obstacles:");
+  //print(vUpper, "vUpper obstacles:");
 
-  using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, IgnoreVector>;
-  using TransferOperator = NBodyContactTransfer<ContactNetwork, Vector>;
-  using TransferOperators = std::vector<std::shared_ptr<TransferOperator>>;
+  //std::cout << "- Problem assembled: success" << std::endl;
 
-  TransferOperators transfer(contactNetwork_.nLevels()-1);
-  for (size_t i=0; i<transfer.size(); i++) {
-      transfer[i] = std::make_shared<TransferOperator>();
-      transfer[i]->setup(contactNetwork_, i, i+1);
-  }
-
-  // Remove any recompute filed so that initially the full transferoperator is assembled
-  for (size_t i=0; i<transfer.size(); i++)
-      std::dynamic_pointer_cast<TruncatedMGTransfer<Vector> >(transfer[i])->setRecomputeBitField(nullptr);
-
-  auto smoother = TruncatedBlockGSStep<Matrix, Vector>{};
-  auto linearMultigridStep = std::make_shared<Dune::Solvers::MultigridStep<Matrix, Vector> >();
-  linearMultigridStep->setMGType(1, 3, 3);
-  linearMultigridStep->setSmoother(smoother);
-  linearMultigridStep->setTransferOperators(transfer);
-
-  EnergyNorm<Matrix, Vector> mgNorm(*linearMultigridStep);
-  LinearSolver mgSolver(linearMultigridStep, parset_.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset_.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::QUIET);
-
-  print(ignoreNodes_, "ignoreNodes:");
+  //print(ignoreNodes_, "ignoreNodes:");
 
   // set up functional and TNMMG solver
-  using ZeroSolverFactory = SolverFactory<Functional, IgnoreVector>;
-  Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), vLower, vUpper);
-  ZeroSolverFactory solverFactory(parset_.sub("solver.tnnmg"), J, mgSolver, ignoreNodes_);
-  /*Functional J(bilinearForm, totalRhs, globalFriction_, vLower, vUpper);
-  Factory solverFactory(parset_.sub("solver.tnnmg"), J, mgSolver, ignoreNodes_);*/
+  //using ZeroSolverFactory = SolverFactory<Functional, IgnoreVector>;
+  //Functional J(bilinearForm, totalRhs, ZeroNonlinearity(), vLower, vUpper);
+  //ZeroSolverFactory solverFactory(parset_.sub("solver.tnnmg"), J, mgSolver, ignoreNodes_);
+  Functional J(bilinearForm, totalRhs, globalFriction_, lower, upper);
+  Factory solverFactory(parset_.sub("solver.tnnmg"), J, ignoreNodes_);
+  solverFactory.build(linearSolver);
+
   auto step = solverFactory.step();
 
-  std::cout << "- Functional and TNNMG step setup: success" << std::endl;
+  //std::cout << "- Functional and TNNMG step setup: success" << std::endl;
 
   EnergyNorm<Matrix, Vector> energyNorm(bilinearForm);
   LoopSolver<Vector> velocityProblemSolver(*step.get(), velocityMaxIterations_,
                                            velocityTolerance_, energyNorm,
-                                           verbosity_, false); // absolute error
+                                           verbosity_);
 
   size_t fixedPointIteration;
   size_t multigridIterations = 0;
   std::vector<ScalarVector> alpha(nBodies);
   updaters.state_->extractAlpha(alpha);
+
+  Vector totalVelocityIterate;
+  nBodyAssembler_.nodalToTransformed(velocityIterates, totalVelocityIterate);
+
+  // project in onto admissible set
+  const size_t blocksize = Vector::block_type::dimension;
+  for (size_t i=0; i<totalVelocityIterate.size(); i++) {
+      for (size_t j=0; j<blocksize; j++) {
+          if (totalVelocityIterate[i][j] < lower[i][j]) {
+              totalVelocityIterate[i][j] = lower[i][j];
+          }
+
+          if (totalVelocityIterate[i][j] > upper[i][j]) {
+              totalVelocityIterate[i][j] = upper[i][j];
+          }
+      }
+  }
+
+  Vector old_v = totalVelocityIterate;
+
   for (fixedPointIteration = 0; fixedPointIteration < fixedPointMaxIterations_;
        ++fixedPointIteration) {
 
-    print(alpha, "alpha:");
+    //print(alpha, "alpha:");
 
     // contribution from nonlinearity
     globalFriction_.updateAlpha(alpha);
 
-    Vector totalVelocityIterate;
-    nBodyAssembler.nodalToTransformed(velocityIterates, totalVelocityIterate);
-
     //print(velocityIterates, "velocityIterates:");
     //print(totalVelocityIterate, "totalVelocityIterate:");
-    std::cout << "- FixedPointIteration iterate" << std::endl;
+    //std::cout << "- FixedPointIteration iterate" << std::endl;
 
     // solve a velocity problem
     solverFactory.setProblem(totalVelocityIterate);
 
-    std::cout << "- Velocity problem set" << std::endl;
+    //std::cout << "- Velocity problem set" << std::endl;
 
     velocityProblemSolver.preprocess();
-    std::cout << "-- Preprocessed" << std::endl;
+    //std::cout << "-- Preprocessed" << std::endl;
     velocityProblemSolver.solve();
-    std::cout << "-- Solved" << std::endl;
+    //std::cout << "-- Solved" << std::endl;
 
     const auto& tnnmgSol = step->getSol();
 
-    std::cout << "FixPointIterator: Energy of TNNMG solution: " << J(tnnmgSol) << std::endl;
+    //std::cout << "FixPointIterator: Energy of TNNMG solution: " << J(tnnmgSol) << std::endl;
 
-    nBodyAssembler.postprocess(tnnmgSol, velocityIterates);
-    //nBodyAssembler.postprocess(totalVelocityIterate, velocityIterates);
+    nBodyAssembler_.postprocess(tnnmgSol, velocityIterates);
+    //nBodyAssembler_.postprocess(totalVelocityIterate, velocityIterates);
 
-    print(totalVelocityIterate, "totalVelocityIterate:");
-    print(velocityIterates, "velocityIterates:");
+    //print(totalVelocityIterate, "totalVelocityIterate:");
+    //print(velocityIterates, "velocityIterates:");
 
     //DUNE_THROW(Dune::Exception, "Just need to stop here!");
 
     multigridIterations += velocityProblemSolver.getResult().iterations;
 
-    std::vector<Vector> v_m;
-    updaters.rate_->extractOldVelocity(v_m);
-
-    for (size_t i=0; i<v_m.size(); i++) {
-      v_m[i] *= 1.0 - lambda_;
-      Dune::MatrixVector::addProduct(v_m[i], lambda_, velocityIterates[i]);
-    }
+    Vector v_m = old_v;
+    v_m *= 1.0 - lambda_;
+    Dune::MatrixVector::addProduct(v_m, lambda_, tnnmgSol);
 
     // extract relative velocities in mortar basis
     std::vector<Vector> v_rel;
-    relativeVelocities(tnnmgSol, v_rel);
+    relativeVelocities(v_m, v_rel);
+
+    //print(v_m, "v_m: ");
 
     //print(v_rel, "v_rel");
 
-    std::cout << "- State problem set" << std::endl;
+    //std::cout << "- State problem set" << std::endl;
 
     // solve a state problem
     updaters.state_->solve(v_rel);
 
-    std::cout << "-- Solved" << std::endl;
+    //std::cout << "-- Solved" << std::endl;
 
     std::vector<ScalarVector> newAlpha(nBodies);
     updaters.state_->extractAlpha(newAlpha);
 
+    //print(newAlpha, "new alpha:");
+
     bool breakCriterion = true;
     for (int i=0; i<nBodies; i++) {
         if (alpha[i].size()==0 || newAlpha[i].size()==0)
             continue;
 
-        print(alpha[i], "alpha i:");
-        print(newAlpha[i], "new alpha i:");
+        //print(alpha[i], "alpha i:");
+        //print(newAlpha[i], "new alpha i:");
         if (errorNorms_[i]->diff(alpha[i], newAlpha[i]) >= fixedPointTolerance_) {
             breakCriterion = false;
-            std::cout << "fixedPoint error: " << errorNorms_[i]->diff(alpha[i], newAlpha[i]) << std::endl;
+            //std::cout << "fixedPoint error: " << errorNorms_[i]->diff(alpha[i], newAlpha[i]) << std::endl;
             break;
         }
     }
 
     if (lambda_ < 1e-12 or breakCriterion) {
-      std::cout << "-FixedPointIteration finished! " << (lambda_ < 1e-12 ? "lambda" : "breakCriterion") << std::endl;
+      //std::cout << "-FixedPointIteration finished! " << (lambda_ < 1e-12 ? "lambda" : "breakCriterion") << std::endl;
       fixedPointIteration++;
       break;
     }
     alpha = newAlpha;
   }
 
-  std::cout << "-FixedPointIteration finished! " << std::endl;
+  //TODO: recently added, might be wrong or superfluous
+  globalFriction_.updateAlpha(alpha);
+
+  //print(alpha, "alpha: ");
+
+  //std::cout << "-FixedPointIteration finished! " << std::endl;
 
   if (fixedPointIteration == fixedPointMaxIterations_)
     DUNE_THROW(Dune::Exception, "FPI failed to converge");
@@ -284,19 +285,18 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run(
   return ret;
 }
 
-std::ostream &operator<<(std::ostream &stream,
+/*std::ostream &operator<<(std::ostream &stream,
                          FixedPointIterationCounter const &fpic) {
   return stream << "(" << fpic.iterations << "," << fpic.multigridIterations
                 << ")";
-}
+}*/
 
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
-void FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::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 {
 
-    const auto& nBodyAssembler = contactNetwork_.nBodyAssembler();
-    const size_t nBodies = nBodyAssembler.nGrids();
+    const size_t nBodies = nBodyAssembler_.nGrids();
    // const auto& contactCouplings = nBodyAssembler.getContactCouplings();
 
     size_t globalIdx = 0;
@@ -345,5 +345,4 @@ void FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::relative
     }*/
 }
 
-
 #include "fixedpointiterator_tmpl.cc"
diff --git a/src/spatial-solving/fixedpointiterator.hh b/dune/tectonic/spatial-solving/fixedpointiterator.hh
similarity index 86%
rename from src/spatial-solving/fixedpointiterator.hh
rename to dune/tectonic/spatial-solving/fixedpointiterator.hh
index c4839a79..ae0912ad 100644
--- a/src/spatial-solving/fixedpointiterator.hh
+++ b/dune/tectonic/spatial-solving/fixedpointiterator.hh
@@ -27,13 +27,13 @@ struct FixedPointIterationCounter {
 std::ostream &operator<<(std::ostream &stream,
                          FixedPointIterationCounter const &fpic);
 
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
 class FixedPointIterator {
   using ScalarVector = typename Updaters::StateUpdater::ScalarVector;
   using Vector = typename Factory::Vector;
   using Matrix = typename Factory::Matrix;
 
-  using Functional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, double>; //typename Factory::Functional;
+  using Functional = typename Factory::Functional; //Functional<Matrix&, Vector&, &, Vector&, Vector&, double>; //;
   using Nonlinearity = typename Factory::Functional::Nonlinearity;
 
   const static int dims = Vector::block_type::dimension;
@@ -51,20 +51,22 @@ class FixedPointIterator {
 
 public:
   FixedPointIterator(const Dune::ParameterTree& parset,
-                     const ContactNetwork& contactNetwork,
+                     const NBodyAssembler& nBodyAssembler,
                      const IgnoreVector& ignoreNodes,
                      GlobalFriction& globalFriction,
                      const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
                      const ErrorNorms& errorNorms);
 
+  template <class LinearSolver>
   FixedPointIterationCounter run(Updaters updaters,
+                                 std::shared_ptr<LinearSolver>& linearSolver,
                                  const std::vector<Matrix>& velocityMatrices,
                                  const std::vector<Vector>& velocityRHSs,
                                  std::vector<Vector>& velocityIterates);
 
 private:
   const Dune::ParameterTree& parset_;
-  const ContactNetwork& contactNetwork_;
+  const NBodyAssembler& nBodyAssembler_;
   const IgnoreVector& ignoreNodes_;
 
   GlobalFriction& globalFriction_;
@@ -79,4 +81,5 @@ class FixedPointIterator {
   Solver::VerbosityMode verbosity_;
   const ErrorNorms& errorNorms_;
 };
+
 #endif
diff --git a/dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc b/dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc
new file mode 100644
index 00000000..bae2cc32
--- /dev/null
+++ b/dune/tectonic/spatial-solving/fixedpointiterator_tmpl.cc
@@ -0,0 +1,41 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
+
+#include <dune/solvers/norms/energynorm.hh>
+#include <dune/solvers/solvers/loopsolver.hh>
+
+#include "../spatial-solving/solverfactory.hh"
+#include "../data-structures/network/contactnetwork.hh"
+#include "../data-structures/friction/globalfriction.hh"
+
+#include "tnnmg/functional.hh"
+
+#include "../time-stepping/rate/rateupdater.hh"
+#include "../time-stepping/state/stateupdater.hh"
+#include "../time-stepping/updaters.hh"
+
+using MyContactNetwork = ContactNetwork<Grid, Vector>;
+
+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 LinearSolver = Dune::Solvers::LoopSolver<Vector>;
+using ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
+using NBodyAssembler = typename MyContactNetwork::NBodyAssembler;
+
+using MyGlobalFriction = GlobalFriction<Matrix, Vector>;
+using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>;
+using MySolverFactory = SolverFactory<MyFunctional, BitVector>;
+
+template class FixedPointIterator<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>;
+
+template FixedPointIterationCounter FixedPointIterator<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>::run<LinearSolver>(
+    MyUpdaters, std::shared_ptr<LinearSolver>&, const std::vector<Matrix>&, const std::vector<Vector>&, std::vector<Vector>&);
diff --git a/dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt b/dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt
new file mode 100644
index 00000000..bcff7b9f
--- /dev/null
+++ b/dune/tectonic/spatial-solving/preconditioners/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_custom_target(tectonic_dune_spatial-solving_preconditioners SOURCES
+  hierarchicleveliterator.hh
+  levelpatchpreconditioner.hh
+  patchproblem.hh
+  multilevelpatchpreconditioner.hh
+  nbodycontacttransfer.hh
+  nbodycontacttransfer.cc
+  supportpatchfactory.hh
+)
+
+#install headers
+install(FILES
+  hierarchicleveliterator.hh
+  levelpatchpreconditioner.hh
+  patchproblem.hh
+  multilevelpatchpreconditioner.hh
+  nbodycontacttransfer.hh
+  supportpatchfactory.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/spatial-solving/preconditioners/hierarchicleveliterator.hh b/dune/tectonic/spatial-solving/preconditioners/hierarchicleveliterator.hh
similarity index 100%
rename from src/spatial-solving/preconditioners/hierarchicleveliterator.hh
rename to dune/tectonic/spatial-solving/preconditioners/hierarchicleveliterator.hh
diff --git a/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh b/dune/tectonic/spatial-solving/preconditioners/levelpatchpreconditioner.hh
similarity index 72%
rename from src/spatial-solving/preconditioners/levelpatchpreconditioner.hh
rename to dune/tectonic/spatial-solving/preconditioners/levelpatchpreconditioner.hh
index a515f6e5..5ac982f6 100644
--- a/src/spatial-solving/preconditioners/levelpatchpreconditioner.hh
+++ b/dune/tectonic/spatial-solving/preconditioners/levelpatchpreconditioner.hh
@@ -10,8 +10,9 @@
 #include <dune/solvers/iterationsteps/lineariterationstep.hh>
 #include <dune/solvers/common/numproc.hh>
 
-#include "../../data-structures/levelcontactnetwork.hh"
+#include "../../data-structures/network/levelcontactnetwork.hh"
 
+#include "patchproblem.hh"
 #include "supportpatchfactory.hh"
 
 #include <dune/localfunctions/lagrange/pqkfactory.hh>
@@ -49,6 +50,7 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
 
     using PatchFactory = SupportPatchFactory<LevelContactNetwork>;
     using Patch = typename PatchFactory::Patch;
+    using PatchProblem = PatchProblem<MatrixType, VectorType>;
 
     const MPPMode mode_;
 
@@ -59,7 +61,7 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
 
     PatchFactory patchFactory_;
     std::vector<Patch> patches_;
-
+    std::vector<std::unique_ptr<PatchProblem>> patchProblems_;
     std::shared_ptr<PatchSolver> patchSolver_;
     size_t patchDepth_;
 
@@ -113,7 +115,7 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
             for (const auto& e : elements(gridView)) {
                 const auto& refElement = Dune::ReferenceElements<double, dim>::general(e.type());
 
-                for (size_t i=0; i<refElement.size(dim); i++) {
+                for (int i=0; i<refElement.size(dim); i++) {
                     auto globalIdx = levelIndices.vertexIndex(bodyIdx, e, i);
 
                     if (!vertexVisited[globalIdx][0]) {
@@ -148,7 +150,18 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
         this->verbosity_ = verbosity;
     }
 
-    virtual void iterate() {
+    void setMatrix(const MatrixType& mat) override {
+        Base::setMatrix(mat);
+
+        patchProblems_.resize(patches_.size());
+        for (size_t i=0; i<patches_.size(); i++) {
+            patchProblems_[i] = std::make_unique<PatchProblem>(mat, patches_[i]);
+        }
+
+        //std::cout << "matrix set!" << std::endl;
+    }
+
+    void iterate() override {
         if (mode_ == additive)
             iterateAdd();
         else
@@ -159,9 +172,20 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
         *(this->x_) = 0;	
         VectorType x = *(this->x_);
 
-        for (const auto& p : patches_) {
+        Dune::Timer timer;
+        timer.start();
+
+        size_t systemSize = 0;
+        size_t count = 0;
+
+        //std::cout << "level::iterate() ... patches: " << patches_.size() << " level size: " << x.size() << std::endl;
+
+        for (size_t i=0; i<patches_.size(); i++) {
             x = 0;
 
+            /*
+            const auto& p = patches_[i];
+
             auto ignore = this->ignore();
             for (size_t i=0; i<ignore.size(); i++) {
                 for (size_t d=0; d<dim; d++) {
@@ -172,14 +196,46 @@ class LevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorTy
 
             auto& step = patchSolver_->getIterationStep();
             dynamic_cast<LinearIterationStep<MatrixType, VectorType>&>(step).setProblem(*this->mat_, x, *this->rhs_);
+            step.setIgnore(ignore);*/
+
+            const auto& patchMat = patchProblems_[i]->mat();
+
+            patchProblems_[i]->setRhs(*this->rhs_);
+            const auto& patchRhs = patchProblems_[i]->rhs();
+
+            VectorType patchX(patchMat.M());
+            patchX = 0;
+
+            auto& step = patchSolver_->getIterationStep();
+            dynamic_cast<LinearIterationStep<MatrixType, VectorType>&>(step).setProblem(patchMat, patchX, patchRhs);
+
+            // empty ignore
+            Dune::Solvers::DefaultBitVector_t<VectorType> ignore(patchX.size());
+            ignore.unsetAll();
             step.setIgnore(ignore);
 
             patchSolver_->check();
             patchSolver_->preprocess();
             patchSolver_->solve();
 
+            patchProblems_[i]->prolong(patchX, x);
+
             *(this->x_) += x;
+
+            /*if (count*1.0/patches_.size() >= 0.1) {
+                std::cout << (int) (i*1.0/patches_.size()*100) << " %. Elapsed time: " << timer.elapsed() << std::endl;
+                count = 0;
+            }
+            count++;
+            systemSize += patchX.size();*/
         }
+
+       /* timer.stop();
+
+        std::cout << "Total elapsed time: " << timer.elapsed() << std::endl;
+        std::cout << "Average time per patch: " << timer.elapsed()*1.0/patches_.size() << std::endl;
+        std::cout << "Average patch size: " << systemSize*1.0/patches_.size() << std::endl;
+        std::cout << "-------------------------------" << std::endl << std::endl;*/
     }
 
     void iterateMult() {
diff --git a/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh b/dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
similarity index 86%
rename from src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
rename to dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
index b187da53..88de3c32 100644
--- a/src/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
+++ b/dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh
@@ -10,25 +10,22 @@
 
 #include <dune/solvers/norms/energynorm.hh>
 #include <dune/solvers/solvers/loopsolver.hh>
-#include <dune/solvers/solvers/umfpacksolver.hh>
 #include <dune/solvers/iterationsteps/blockgssteps.hh>
-//#include <dune/solvers/iterationsteps/blockgsstep.hh>
 #include <dune/solvers/iterationsteps/cgstep.hh>
 #include <dune/solvers/iterationsteps/lineariterationstep.hh>
 #include <dune/solvers/iterationsteps/truncatedblockgsstep.hh>
 
 #include "nbodycontacttransfer.hh"
 #include "levelpatchpreconditioner.hh"
-#include "localproblem.hh"
 
 template <class ContactNetwork, class MatrixType, class VectorType>
 class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorType> {
 private:
     using Base = LinearIterationStep<MatrixType, VectorType>;
 
-    using PatchSolver = LoopSolver<Vector, BitVector>;
+    using PatchSolver = LoopSolver<VectorType>;
     using PatchSolverStep = TruncatedBlockGSStep<MatrixType, VectorType>;
-    using CoarseSolver = Dune::Solvers::UMFPackSolver<MatrixType, VectorType>;
+    using Norm = EnergyNorm<MatrixType, VectorType>;
 
     using LevelContactNetwork = typename ContactNetwork::LevelContactNetwork;
     using LevelPatchPreconditioner = LevelPatchPreconditioner<LevelContactNetwork, PatchSolver, MatrixType, VectorType>;
@@ -54,7 +51,6 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
     std::vector<std::shared_ptr<EnergyNorm<MatrixType, VectorType>>> levelErrorNorms_;
     std::vector<std::shared_ptr<LinearIterationStep<MatrixType, VectorType>>> levelItSteps_;
     std::vector<std::shared_ptr<PatchSolver>> levelSolvers_;
-    CoarseSolver coarseSolver_;
 
     //std::vector<BitVector> recompute_;
     std::vector<std::shared_ptr<MGTransfer>> mgTransfer_;
@@ -100,15 +96,23 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
         levelItSteps_.resize(size());
         levelErrorNorms_.resize(size());
 
+        // set basesolver
+        levelItSteps_[0] = std::make_shared<PatchSolverStep>();
+        levelErrorNorms_[0] = std::make_shared<Norm>(*levelItSteps_[0].get());
+        levelSolvers_[0] = std::make_shared<PatchSolver>(*levelItSteps_[0].get(),
+                                   parset.get<size_t>("basesolver.maximumIterations"),
+                                   parset.get<double>("basesolver.tolerance"),
+                                   *levelErrorNorms_[0].get(),
+                                   parset.get<Solver::VerbosityMode>("basesolver.verbosity"));
+
         for (size_t i=1; i<levelSolvers_.size(); i++) {
-            //auto gsStep = Dune::Solvers::BlockGSStepFactory<MatrixType, VectorType>::create(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0));
-            levelItSteps_[i] = std::make_shared<TruncatedBlockGSStep<MatrixType, VectorType>>(); //Dune::Solvers::BlockGSStepFactory<MatrixType, VectorType>::createPtr(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0));
-            levelErrorNorms_[i] = std::make_shared<EnergyNorm<MatrixType, VectorType>>(*levelItSteps_[i].get());
+            levelItSteps_[i] = std::make_shared<PatchSolverStep>();
+            levelErrorNorms_[i] = std::make_shared<Norm>(*levelItSteps_[i].get());
             levelSolvers_[i] = std::make_shared<PatchSolver>(*levelItSteps_[i].get(),
-                                       parset.get<size_t>("maximumIterations"),
-                                       parset.get<double>("tolerance"),
+                                       parset.get<size_t>("patchsolver.maximumIterations"),
+                                       parset.get<double>("patchsolver.tolerance"),
                                        *levelErrorNorms_[i].get(),
-                                       parset.get<Solver::VerbosityMode>("verbosity"));
+                                       parset.get<Solver::VerbosityMode>("patchsolver.verbosity"));
             levelPatchPreconditioners_[i]->setPatchSolver(levelSolvers_[i]);
         }
 
@@ -171,7 +175,9 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
         Dune::MatrixVector::resize(levelX_[0], levelMat_[0]);
    }
 
-    void iterate() {
+    void iterate() override {
+        //std::cout << "multi::iterate()" << std::endl;
+
         size_t maxLevel = levelPatchPreconditioners_.size()-1;
         levelX_[maxLevel] = *this->getIterate();
         levelRhs_[maxLevel] = *Base::rhs_;
@@ -201,13 +207,21 @@ class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, Vec
         VectorType x;
 
         // solve coarse global problem
-        LocalProblem<MatrixType, VectorType> localProblem(levelMat_[0], levelRhs_[0], ignoreHierarchy_[0]);
-        Vector newR;
+        /*LocalProblem<MatrixType, VectorType> localProblem(levelMat_[0], levelRhs_[0], ignoreHierarchy_[0]);
+        VectorType newR;
         localProblem.getLocalRhs(levelX_[0], newR);
 
         coarseSolver_.setProblem(localProblem.getMat(), levelX_[0], newR);
         coarseSolver_.preprocess();
-        coarseSolver_.solve();
+        coarseSolver_.solve(); */
+
+        auto& step = levelSolvers_[0]->getIterationStep();
+        dynamic_cast<LinearIterationStep<MatrixType, VectorType>&>(step).setProblem(levelMat_[0], levelX_[0], levelRhs_[0]);
+        step.setIgnore(ignoreHierarchy_[0]);
+
+        levelSolvers_[0]->check();
+        levelSolvers_[0]->preprocess();
+        levelSolvers_[0]->solve();
 
         mgTransfer_[0]->prolong(levelX_[0], x);
 
diff --git a/src/spatial-solving/preconditioners/nbodycontacttransfer.cc b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.cc
similarity index 97%
rename from src/spatial-solving/preconditioners/nbodycontacttransfer.cc
rename to dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.cc
index 1bb9ce37..347e2a22 100644
--- a/src/spatial-solving/preconditioners/nbodycontacttransfer.cc
+++ b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.cc
@@ -12,7 +12,7 @@
 #include <dune/solvers/transferoperators/densemultigridtransfer.hh>
 
 template<class ContactNetwork, class VectorType>
-void NBodyContactTransfer<ContactNetwork, VectorType>::setup(const ContactNetwork& contactNetwork, const int coarseLevel, const int fineLevel) {
+void NBodyContactTransfer<ContactNetwork, VectorType>::setup(const ContactNetwork& contactNetwork, const size_t coarseLevel, const size_t fineLevel) {
     const size_t nBodies     = contactNetwork.nBodies();
     const size_t nCouplings = contactNetwork.nCouplings();
 
@@ -75,11 +75,11 @@ void NBodyContactTransfer<ContactNetwork, VectorType>::setup(const ContactNetwor
         const auto& nBodyAssembler = contactNetwork.nBodyAssembler();
         const auto& contactCouplings = nBodyAssembler.getContactCouplings();
 
-        std::vector<const MatrixType*> mortarTransferOperators(nBodyAssembler.nCouplings());
-        std::vector<const Dune::BitSetVector<1>*> fineHasObstacle(nBodyAssembler.nCouplings());
-        std::vector<std::array<int,2> > gridIdx(nBodyAssembler.nCouplings());
+        std::vector<const MatrixType*> mortarTransferOperators(nCouplings);
+        std::vector<const Dune::BitSetVector<1>*> fineHasObstacle(nCouplings);
+        std::vector<std::array<int,2> > gridIdx(nCouplings);
 
-        for (size_t i=0; i<nBodyAssembler.nCouplings(); i++) {
+        for (size_t i=0; i<nCouplings; i++) {
             mortarTransferOperators[i] = &contactCouplings[i]->mortarLagrangeMatrix();
             fineHasObstacle[i] = contactCouplings[i]->nonmortarBoundary().getVertices();
             gridIdx[i] = nBodyAssembler.getCoupling(i).gridIdx_;
diff --git a/src/spatial-solving/preconditioners/nbodycontacttransfer.hh b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.hh
similarity index 97%
rename from src/spatial-solving/preconditioners/nbodycontacttransfer.hh
rename to dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.hh
index 61d4e7c0..855851e2 100644
--- a/src/spatial-solving/preconditioners/nbodycontacttransfer.hh
+++ b/dune/tectonic/spatial-solving/preconditioners/nbodycontacttransfer.hh
@@ -58,7 +58,7 @@ class NBodyContactTransfer : public TruncatedDenseMGTransfer<VectorType> {
      *  \param fineHasObstacle  Bitfields determining for each coupling which fine grid nodes belong to the nonmortar boundary.
      *  \param gridIdx  For each coupling store the indices of the nonmortar and mortar grid.
     */
-    void setup(const ContactNetwork& contactNetwork, const int coarseLevel, const int fineLevel);
+    void setup(const ContactNetwork& contactNetwork, const size_t coarseLevel, const size_t fineLevel);
 
 
 protected:
diff --git a/dune/tectonic/spatial-solving/preconditioners/patchproblem.hh b/dune/tectonic/spatial-solving/preconditioners/patchproblem.hh
new file mode 100644
index 00000000..321a96f3
--- /dev/null
+++ b/dune/tectonic/spatial-solving/preconditioners/patchproblem.hh
@@ -0,0 +1,115 @@
+#ifndef SRC_SPATIAL_SOLVING_PRECONDITIONERS_PATCH_PROBLEM_HH
+#define SRC_SPATIAL_SOLVING_PRECONDITIONERS_PATCH_PROBLEM_HH
+
+#include <math.h>   
+#include <dune/common/fmatrix.hh>
+#include <dune/common/function.hh>
+#include <dune/common/timer.hh>
+
+#include <dune/istl/matrixindexset.hh>
+//#include <dune/istl/superlu.hh>
+#include <dune/istl/umfpack.hh>
+
+#include <dune/fufem/assemblers/localoperatorassembler.hh>
+
+#include "../../utils/debugutils.hh"
+
+template <class MatrixType, class DomainType, class RangeType = DomainType>
+class PatchProblem {
+  
+private:    
+    const static size_t dim = DomainType::block_type::dimension;
+
+    using BitVector = Dune::BitSetVector<dim>;
+
+    const MatrixType& mat_;
+
+    std::vector<size_t> localToGlobal_;
+
+    MatrixType localMat_;
+    RangeType localRhs_;
+
+
+public:
+    PatchProblem(const MatrixType& mat, const Dune::BitSetVector<1>& patch) :
+        mat_(mat) {
+	  
+        // construct localToGlobal map
+        localToGlobal_.clear();
+        for (size_t i=0; i<patch.size(); ++i) {
+            if (!patch[i][0]) {
+                localToGlobal_.push_back(i);
+            }
+        }
+
+        // build local matrix
+        auto localDim = localToGlobal_.size();
+        Dune::MatrixIndexSet localIdxSet(localDim, localDim);
+
+        for(size_t rowIdx=0; rowIdx<localDim; rowIdx++) {
+            const auto globalRowIdx = localToGlobal_[rowIdx];
+            const auto& row = mat_[globalRowIdx];
+
+            const auto cEndIt = row.end();
+            for(auto cIt=row.begin(); cIt!=cEndIt; ++cIt) {
+                const auto globalColIdx = cIt.index();
+
+                auto localColIdx = std::find(localToGlobal_.begin(), localToGlobal_.end(), globalColIdx);
+                if (localColIdx!=localToGlobal_.end()) {
+                    localIdxSet.add(rowIdx, localColIdx-localToGlobal_.begin());
+                }
+            }
+        }
+
+        localIdxSet.exportIdx(localMat_);
+
+        for(size_t rowIdx=0; rowIdx<localMat_.N(); rowIdx++) {
+            auto& row = localMat_[rowIdx];
+            const auto& globalRow = mat_[localToGlobal_[rowIdx]];
+
+
+            const auto cEndIt = row.end();
+            for(auto cIt=row.begin(); cIt!=cEndIt; ++cIt) {
+                row[cIt.index()] = globalRow[localToGlobal_[cIt.index()]];
+            }
+        }
+
+        // init local rhs
+        localRhs_.resize(localDim);
+        localRhs_ = 0;
+    }
+
+    const MatrixType& mat() {
+        return localMat_;
+    }
+    
+    const RangeType& rhs() {
+        return localRhs_;
+    }
+
+    void setRhs(const RangeType& rhs){
+        for (size_t i=0; i<localRhs_.size(); i++) {
+            localRhs_[i] = rhs[localToGlobal_[i]];
+        }
+    }
+
+    void prolong(const DomainType& x, DomainType& res){
+        res.resize(mat_.N());
+        res = 0;
+
+        for (size_t i=0; i<x.size(); i++) {
+                res[localToGlobal_[i]] = x[i];
+        }
+    }
+
+    void restrict(const RangeType& x, RangeType& res){
+        res.resize(localToGlobal_.size());
+        res = 0;
+
+        for (size_t i=0; i<res.size(); i++) {
+            res[i] = x[localToGlobal_[i]];
+        }
+    }
+};
+
+#endif
diff --git a/src/spatial-solving/preconditioners/supportpatchfactory.hh b/dune/tectonic/spatial-solving/preconditioners/supportpatchfactory.hh
similarity index 98%
rename from src/spatial-solving/preconditioners/supportpatchfactory.hh
rename to dune/tectonic/spatial-solving/preconditioners/supportpatchfactory.hh
index 3dbc81d5..06c478cf 100644
--- a/src/spatial-solving/preconditioners/supportpatchfactory.hh
+++ b/dune/tectonic/spatial-solving/preconditioners/supportpatchfactory.hh
@@ -105,7 +105,7 @@ class SupportPatchFactory
     static const int dim = LevelContactNetwork::dim; //TODO
     using ctype = typename LevelContactNetwork::ctype;
 
-    using Patch = Dune::BitSetVector<dim>;
+    using Patch = Dune::BitSetVector<1>;
 
 private:
     using Element = typename LevelContactNetwork::GridView::template Codim<0>::Entity;
@@ -216,7 +216,6 @@ class SupportPatchFactory
                 //std::cout << "elemID: " << coarseIndices_.elementIndex(i, e) << std::endl;
                 //std::cout << "vertexIDs: ";
                 const int dimElement = Element::dimension;
-                const auto& refElement = Dune::ReferenceElements<double, dimElement>::general(e.type());
 
                 /*for (int j=0; j<refElement.size(dim); j++) {
                     std::cout << coarseIndices_.vertexIndex(i, e, j) << " ";
@@ -423,8 +422,6 @@ class SupportPatchFactory
         for (size_t i=0; i<patchElements.size(); ++i) {
             const auto& coarseElem = patchElements[i];
 
-            size_t elemIdx = coarseIndices_.elementIndex(coarseElem.bodyID, coarseElem.element);
-
             const auto& grid = coarseContactNetwork_.body(coarseElem.bodyID)->gridView().grid();
             const auto fineLevel = fineContactNetwork_.body(coarseElem.bodyID)->level();
 
@@ -545,7 +542,7 @@ class SupportPatchFactory
         }
 	}
 
-    auto coarseFather(const Element& fineElem, const size_t coarseLevel) const {
+    auto coarseFather(const Element& fineElem, const int coarseLevel) const {
         Element coarseElem = fineElem;
         while (coarseElem.level() > coarseLevel) {
             coarseElem = coarseElem.father();
diff --git a/dune/tectonic/spatial-solving/solverfactory.cc b/dune/tectonic/spatial-solving/solverfactory.cc
new file mode 100644
index 00000000..004253db
--- /dev/null
+++ b/dune/tectonic/spatial-solving/solverfactory.cc
@@ -0,0 +1,46 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <dune/solvers/common/wrapownshare.hh>
+#include <dune/solvers/iterationsteps/blockgssteps.hh>
+#include <dune/solvers/solvers/umfpacksolver.hh>
+
+#include "solverfactory.hh"
+
+#include "../utils/debugutils.hh"
+
+template <class Functional, class BitVector>
+SolverFactory<Functional, BitVector>::SolverFactory(
+    const Dune::ParameterTree& parset,
+    Functional& J,
+    const BitVector& ignoreNodes) :
+        parset_(parset),
+        J_(Dune::Solvers::wrap_own_share<const Functional>(std::forward<Functional>(J))),
+        ignoreNodes_(ignoreNodes)
+{}
+
+template <class Functional, class BitVector>
+template <class LinearSolver>
+void SolverFactory<Functional, BitVector>::build(std::shared_ptr<LinearSolver>& linearSolver) {
+    nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, LocalSolver());
+
+    tnnmgStep_ = std::make_shared<Step>(*J_, dummyIterate_, nonlinearSmoother_, linearSolver, DefectProjection(), LineSearchSolver());
+    tnnmgStep_->setPreSmoothingSteps(parset_.get<int>("main.pre"));
+    tnnmgStep_->setIgnore(ignoreNodes_);
+}
+
+template <class Functional, class BitVector>
+void SolverFactory<Functional, BitVector>::setProblem(Vector& x) {
+    nonlinearSmoother_->setProblem(x);
+    tnnmgStep_->setProblem(x);
+}
+
+
+template <class Functional, class BitVector>
+auto SolverFactory<Functional, BitVector>::step()
+-> std::shared_ptr<Step> {
+    return tnnmgStep_;
+}
+
+#include "solverfactory_ex.cc"
diff --git a/src/spatial-solving/solverfactory.hh b/dune/tectonic/spatial-solving/solverfactory.hh
similarity index 69%
rename from src/spatial-solving/solverfactory.hh
rename to dune/tectonic/spatial-solving/solverfactory.hh
index 703d0f9a..a93b65d8 100644
--- a/src/spatial-solving/solverfactory.hh
+++ b/dune/tectonic/spatial-solving/solverfactory.hh
@@ -15,12 +15,11 @@
 #include <dune/tnnmg/projections/obstacledefectprojection.hh>
 #include <dune/tnnmg/localsolvers/scalarobstaclesolver.hh>
 
-//#include "tnnmg/tnnmgstep.hh"
 #include "tnnmg/linearization.hh"
 #include "tnnmg/linesearchsolver.hh"
 #include "tnnmg/localbisectionsolver.hh"
 
-template <class FunctionalTEMPLATE, class BitVectorType, class ContactNetwork>
+template <class FunctionalTEMPLATE, class BitVectorType>
 class SolverFactory {
 public:
     using Functional = FunctionalTEMPLATE;
@@ -28,28 +27,30 @@ class SolverFactory {
     using Vector = typename Functional::Vector;
     using BitVector = BitVectorType;
 
-    using LocalSolver = LocalBisectionSolver; //Dune::TNNMG::ScalarObstacleSolver;//LocalBisectionSolver;
-    using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, LocalBisectionSolver, BitVector>; //Dune::TNNMG::NonlinearGSStep<Functional, Dune::TNNMG::GaussSeidelLocalSolver<LocalSolver>, BitVector>;
+    using LocalSolver = LocalBisectionSolver;
+    using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, LocalBisectionSolver, BitVector>;
     using Linearization = Linearization<Functional, BitVector>;
     using DefectProjection = typename Dune::TNNMG::ObstacleDefectProjection;
 
-    using Step = Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver, ContactNetwork>;
-    //using Step = Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, Dune::TNNMG::ScalarObstacleSolver>;
+    using Step = Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver>;
 
-  template <class LinearSolver>
   SolverFactory(const Dune::ParameterTree&,
                 Functional&,
-                LinearSolver&&,
-                const BitVector&,
-                const ContactNetwork&);
+                const BitVector&);
+
+  template <class LinearSolver>
+  void build(std::shared_ptr<LinearSolver>& linearSolver);
 
   void setProblem(Vector& x);
 
   auto step() -> std::shared_ptr<Step>;
 
 private:
+  const Dune::ParameterTree& parset_;
+
   Vector dummyIterate_;
   std::shared_ptr<const Functional> J_;
+  const BitVector& ignoreNodes_;
 
   // nonlinear smoother
   std::shared_ptr<NonlinearSmoother> nonlinearSmoother_;
@@ -58,6 +59,4 @@ class SolverFactory {
   std::shared_ptr<Step> tnnmgStep_;
 };
 
-#include "solverfactory.cc"
-
 #endif
diff --git a/dune/tectonic/spatial-solving/solverfactory_ex.cc b/dune/tectonic/spatial-solving/solverfactory_ex.cc
new file mode 100644
index 00000000..73811d05
--- /dev/null
+++ b/dune/tectonic/spatial-solving/solverfactory_ex.cc
@@ -0,0 +1,17 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include <dune/solvers/solvers/loopsolver.hh>
+
+#include "solverfactory_tmpl.cc"
+
+using MyLinearSolver = Dune::Solvers::LoopSolver<Vector, BitVector>;
+
+template class SolverFactory<MyFunctional, BitVector>;
+template void SolverFactory<MyFunctional, BitVector>::build<MyLinearSolver>(std::shared_ptr<MyLinearSolver>&);
+
+template class SolverFactory<MyZeroFunctional, BitVector>;
+template void SolverFactory<MyZeroFunctional, BitVector>::build<MyLinearSolver>(std::shared_ptr<MyLinearSolver>&);
+
+
diff --git a/dune/tectonic/spatial-solving/solverfactory_tmpl.cc b/dune/tectonic/spatial-solving/solverfactory_tmpl.cc
new file mode 100644
index 00000000..d86fa485
--- /dev/null
+++ b/dune/tectonic/spatial-solving/solverfactory_tmpl.cc
@@ -0,0 +1,21 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
+
+#include "../data-structures/friction/globalfriction.hh"
+#include "tnnmg/functional.hh"
+#include "tnnmg/zerononlinearity.hh"
+
+#include "solverfactory.hh"
+
+using MyLinearSolver = Dune::Solvers::LoopSolver<Vector, BitVector>;
+using MyGlobalFriction = GlobalFriction<Matrix, Vector>;
+
+using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>;
+using MySolverFactory = SolverFactory<MyFunctional, BitVector>;
+
+using MyZeroFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, double>;
+using MyZeroSolverFactory = SolverFactory<MyZeroFunctional, BitVector>;
diff --git a/dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt b/dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt
new file mode 100644
index 00000000..ee2910cf
--- /dev/null
+++ b/dune/tectonic/spatial-solving/tnnmg/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_custom_target(tectonic_dune_spatial-solving_tnnmg SOURCES
+  functional.hh
+  linearcorrection.hh
+  linearization.hh
+  linesearchsolver.hh
+  localbisectionsolver.hh
+  zerononlinearity.hh
+)
+
+#install headers
+install(FILES
+  functional.hh
+  linearcorrection.hh
+  linearization.hh
+  linesearchsolver.hh
+  localbisectionsolver.hh
+  zerononlinearity.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/spatial-solving/tnnmg/functional.hh b/dune/tectonic/spatial-solving/tnnmg/functional.hh
similarity index 100%
rename from src/spatial-solving/tnnmg/functional.hh
rename to dune/tectonic/spatial-solving/tnnmg/functional.hh
diff --git a/src/spatial-solving/tnnmg/linearcorrection.hh b/dune/tectonic/spatial-solving/tnnmg/linearcorrection.hh
similarity index 100%
rename from src/spatial-solving/tnnmg/linearcorrection.hh
rename to dune/tectonic/spatial-solving/tnnmg/linearcorrection.hh
diff --git a/src/spatial-solving/tnnmg/linearization.hh b/dune/tectonic/spatial-solving/tnnmg/linearization.hh
similarity index 100%
rename from src/spatial-solving/tnnmg/linearization.hh
rename to dune/tectonic/spatial-solving/tnnmg/linearization.hh
diff --git a/src/spatial-solving/tnnmg/linesearchsolver.hh b/dune/tectonic/spatial-solving/tnnmg/linesearchsolver.hh
similarity index 100%
rename from src/spatial-solving/tnnmg/linesearchsolver.hh
rename to dune/tectonic/spatial-solving/tnnmg/linesearchsolver.hh
diff --git a/src/spatial-solving/tnnmg/localbisectionsolver.hh b/dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh
similarity index 100%
rename from src/spatial-solving/tnnmg/localbisectionsolver.hh
rename to dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh
diff --git a/src/spatial-solving/tnnmg/zerononlinearity.hh b/dune/tectonic/spatial-solving/tnnmg/zerononlinearity.hh
similarity index 100%
rename from src/spatial-solving/tnnmg/zerononlinearity.hh
rename to dune/tectonic/spatial-solving/tnnmg/zerononlinearity.hh
diff --git a/src/tests/CMakeLists.txt b/dune/tectonic/tests/CMakeLists.txt
similarity index 81%
rename from src/tests/CMakeLists.txt
rename to dune/tectonic/tests/CMakeLists.txt
index b2004776..ef87c47f 100644
--- a/src/tests/CMakeLists.txt
+++ b/dune/tectonic/tests/CMakeLists.txt
@@ -2,3 +2,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)
+dune_add_test(SOURCES solverfactorytest.cc)
diff --git a/src/tests/common.hh b/dune/tectonic/tests/common.hh
similarity index 100%
rename from src/tests/common.hh
rename to dune/tectonic/tests/common.hh
diff --git a/src/tests/couplingtest.hh b/dune/tectonic/tests/couplingtest.hh
similarity index 100%
rename from src/tests/couplingtest.hh
rename to dune/tectonic/tests/couplingtest.hh
diff --git a/src/tests/globalfrictioncontainertest.cc b/dune/tectonic/tests/globalfrictioncontainertest.cc
similarity index 100%
rename from src/tests/globalfrictioncontainertest.cc
rename to dune/tectonic/tests/globalfrictioncontainertest.cc
diff --git a/src/tests/gridgluefrictiontest.cc b/dune/tectonic/tests/gridgluefrictiontest.cc
similarity index 100%
rename from src/tests/gridgluefrictiontest.cc
rename to dune/tectonic/tests/gridgluefrictiontest.cc
diff --git a/src/nodalweights.cc b/dune/tectonic/tests/nodalweights.cc
similarity index 100%
rename from src/nodalweights.cc
rename to dune/tectonic/tests/nodalweights.cc
diff --git a/src/nodalweights.hh b/dune/tectonic/tests/nodalweights.hh
similarity index 100%
rename from src/nodalweights.hh
rename to dune/tectonic/tests/nodalweights.hh
diff --git a/src/tests/nodalweightstest.cc b/dune/tectonic/tests/nodalweightstest.cc
similarity index 100%
rename from src/tests/nodalweightstest.cc
rename to dune/tectonic/tests/nodalweightstest.cc
diff --git a/src/tests/nonoverlappingcouplingtest.cc b/dune/tectonic/tests/nonoverlappingcouplingtest.cc
similarity index 100%
rename from src/tests/nonoverlappingcouplingtest.cc
rename to dune/tectonic/tests/nonoverlappingcouplingtest.cc
diff --git a/src/solverfactorytest.cc b/dune/tectonic/tests/solverfactorytest.cc
similarity index 95%
rename from src/solverfactorytest.cc
rename to dune/tectonic/tests/solverfactorytest.cc
index ef3ad5a5..07e919f7 100644
--- a/src/solverfactorytest.cc
+++ b/dune/tectonic/tests/solverfactorytest.cc
@@ -159,7 +159,7 @@ void solveProblem(const ContactNetwork& contactNetwork,
 
     using Linearization = Dune::TNNMG::BoxConstrainedQuadraticFunctionalConstrainedLinearization<ContactFunctional, BitVector>;
     using DefectProjection = Dune::TNNMG::ObstacleDefectProjection;
-    using Step = Dune::TNNMG::TNNMGStep<ContactFunctional, BitVector, Linearization, DefectProjection, LocalSolver, ContactNetwork>;
+    using Step = Dune::TNNMG::TNNMGStep<ContactFunctional, BitVector, Linearization, DefectProjection, LocalSolver>;
 
     // set multigrid solver
     auto smoother = TruncatedBlockGSStep<Matrix, Vector>();
@@ -183,12 +183,11 @@ void solveProblem(const ContactNetwork& contactNetwork,
     linearMultigridStep->setTransferOperators(transfer);
 
     int mu = parset.get<int>("solver.tnnmg.main.multi"); // #multigrid steps in Newton step
-    auto step = Step(I, refX, nonlinearSmoother, linearMultigridStep, mu, DefectProjection(), LocalSolver(), contactNetwork);
+    auto step = Step(I, refX, nonlinearSmoother, linearMultigridStep, mu, DefectProjection(), LocalSolver());
 
     // compute reference solution with generic functional and solver
     auto norm = Norm(mat);
 
-    if (initial) {
     auto refSolver = Solver(step, parset.get<size_t>("u0.solver.maximumIterations"),
                             parset.get<double>("u0.solver.tolerance"), norm, Solver::FULL);
 
@@ -235,22 +234,10 @@ void solveProblem(const ContactNetwork& contactNetwork,
 
     //print(refX, "refX: ");
 
-        x = refX;
-        return;
-    }
     // set up solver factory solver
-    using PatchSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
     using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>;
 
-    const auto& preconditionerParset = parset.sub("solver.tnnmg.linear.preconditioner");
-
-    auto gsStep = Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::create(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0));
-    PatchSolver patchSolver(gsStep,
-                               preconditionerParset.get<size_t>("maximumIterations"),
-                               preconditionerParset.get<double>("tolerance"),
-                               nullptr,
-                               preconditionerParset.get<Solver::VerbosityMode>("verbosity"),
-                               false); // absolute error
+    const auto& preconditionerParset = parset.sub("solver.tnnmg.preconditioner");
 
     Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), true);
     Preconditioner preconditioner(preconditionerParset, contactNetwork, activeLevels);
@@ -270,10 +257,10 @@ void solveProblem(const ContactNetwork& contactNetwork,
 
      print(ignore, "ignore: ");*/
 
-    using MyFunctional = Functional<Matrix&, Vector&, std::decay_t<decltype(globalFriction)>&, Vector&, Vector&, typename Matrix::field_type>;
-    MyFunctional J(mat, rhs, globalFriction, lower, upper);
-    //using MyFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity, Vector&, Vector&, typename Matrix::field_type>;
-    //MyFunctional J(mat, rhs, ZeroNonlinearity(), lower, upper);
+    //using MyFunctional = Functional<Matrix&, Vector&, std::decay_t<decltype(globalFriction)>&, Vector&, Vector&, typename Matrix::field_type>;
+    //MyFunctional J(mat, rhs, globalFriction, lower, upper);
+    using MyFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity, Vector&, Vector&, typename Matrix::field_type>;
+    MyFunctional J(mat, rhs, ZeroNonlinearity(), lower, upper);
 
     //std::cout << "ref energy: " << J(refX) << std::endl;
 
@@ -282,10 +269,11 @@ void solveProblem(const ContactNetwork& contactNetwork,
     //Norm mgNorm(*linearMultigridStep);
     //auto mgSolver = std::make_shared<Solver>(linearMultigridStep, parset.get<size_t>("solver.tnnmg.linear.maximumIterations"), parset.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::QUIET);
     Norm mgNorm(*cgStep);
-    auto mgSolver = std::make_shared<Solver>(cgStep, parset.get<int>("solver.tnnmg.main.multi"), parset.get<double>("solver.tnnmg.linear.tolerance"), mgNorm, Solver::QUIET);
+    auto mgSolver = std::make_shared<Solver>(cgStep, parset.get<int>("solver.tnnmg.main.multi"), parset.get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), mgNorm, Solver::QUIET);
 
-    using Factory = SolverFactory<MyFunctional, BitVector, ContactNetwork>;
-    Factory factory(parset.sub("solver.tnnmg"), J, *mgSolver, ignore, contactNetwork);
+    using Factory = SolverFactory<MyFunctional, BitVector>;
+    Factory factory(parset.sub("solver.tnnmg"), J, ignore);
+    factory.build(mgSolver);
 
    /* std::vector<BitVector> bodyDirichletNodes;
     nBodyAssembler.postprocess(_dirichletNodes, bodyDirichletNodes);
@@ -311,7 +299,7 @@ void solveProblem(const ContactNetwork& contactNetwork,
             },
             "   energy      ");
 
-    double initialEnergy = J(x);
+    initialEnergy = J(x);
     solver.addCriterion(
             [&](){
             static double oldEnergy=initialEnergy;
@@ -335,10 +323,10 @@ void solveProblem(const ContactNetwork& contactNetwork,
             "   truncated   ");
 
 
-    std::vector<double> factors;
+    /*std::vector<double> factors;
     solver.addCriterion(reductionFactorCriterion(*tnnmgStep, norm, factors));
 
-    solver.addCriterion(energyCriterion(*tnnmgStep, J, factors));
+    solver.addCriterion(energyCriterion(*tnnmgStep, J, factors));*/
 
     solver.preprocess();
     solver.solve();
diff --git a/src/tests/supportpatchfactorytest.cc b/dune/tectonic/tests/supportpatchfactorytest.cc
similarity index 100%
rename from src/tests/supportpatchfactorytest.cc
rename to dune/tectonic/tests/supportpatchfactorytest.cc
diff --git a/dune/tectonic/time-stepping/CMakeLists.txt b/dune/tectonic/time-stepping/CMakeLists.txt
new file mode 100644
index 00000000..f316e155
--- /dev/null
+++ b/dune/tectonic/time-stepping/CMakeLists.txt
@@ -0,0 +1,23 @@
+add_subdirectory("rate")
+add_subdirectory("state")
+
+add_custom_target(tectonic_dune_time-stepping SOURCES
+  adaptivetimestepper.hh
+  adaptivetimestepper.cc
+  coupledtimestepper.hh
+  coupledtimestepper.cc 
+  rate.hh
+  rate.cc
+  state.hh
+  state.cc
+  updaters.hh
+)
+
+#install headers
+install(FILES
+  adaptivetimestepper.hh
+  coupledtimestepper.hh
+  rate.hh
+  state.hh
+  updaters.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/dune/tectonic/time-stepping/adaptivetimestepper.cc b/dune/tectonic/time-stepping/adaptivetimestepper.cc
new file mode 100644
index 00000000..79bad14f
--- /dev/null
+++ b/dune/tectonic/time-stepping/adaptivetimestepper.cc
@@ -0,0 +1,276 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <dune/solvers/norms/energynorm.hh>
+#include <dune/solvers/iterationsteps/cgstep.hh>
+#include <dune/solvers/solvers/loopsolver.hh>
+
+#include "../spatial-solving/preconditioners/multilevelpatchpreconditioner.hh"
+
+#include "adaptivetimestepper.hh"
+
+void IterationRegister::registerCount(FixedPointIterationCounter count) {
+  totalCount += count;
+}
+
+void IterationRegister::registerFinalCount(FixedPointIterationCounter count) {
+  finalCount = count;
+}
+
+void IterationRegister::reset() {
+  totalCount = FixedPointIterationCounter();
+  finalCount = FixedPointIterationCounter();
+}
+
+template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::AdaptiveTimeStepper(
+        Dune::ParameterTree const &parset,
+        ContactNetwork& contactNetwork,
+        const IgnoreVector& ignoreNodes,
+        GlobalFriction& globalFriction,
+        const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
+        Updaters &current,
+        double relativeTime,
+        double relativeTau,
+        ExternalForces& externalForces,
+        const ErrorNorms& errorNorms,
+        std::function<bool(Updaters &, Updaters &)> mustRefine)
+    : relativeTime_(relativeTime),
+      relativeTau_(relativeTau),
+      finalTime_(parset.get<double>("problem.finalTime")),
+      parset_(parset),
+      contactNetwork_(contactNetwork),
+      ignoreNodes_(ignoreNodes),
+      globalFriction_(globalFriction),
+      bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries),
+      current_(current),
+      R1_(),
+      externalForces_(externalForces),
+      mustRefine_(mustRefine),
+      errorNorms_(errorNorms) {}
+
+template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+bool AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::reachedEnd() {
+  return relativeTime_ >= 1.0;
+}
+
+template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+auto AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::makeLinearSolver() const {
+    // make linear solver for linear correction in TNNMGStep
+    using Norm =  EnergyNorm<Matrix, Vector>;
+    using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>;
+    using LinearSolver = typename Dune::Solvers::LoopSolver<Vector>;
+
+    const auto& preconditionerParset = parset_.sub("solver.tnnmg.linear.preconditioner");
+
+    Dune::BitSetVector<1> activeLevels(contactNetwork_.nLevels(), true);
+    Preconditioner preconditioner(preconditionerParset, contactNetwork_, activeLevels);
+    preconditioner.setPatchDepth(preconditionerParset.template get<size_t>("patchDepth"));
+    preconditioner.build();
+
+    auto cgStep = std::make_shared<Dune::Solvers::CGStep<Matrix, Vector>>();
+    cgStep->setPreconditioner(preconditioner);
+
+    Norm norm(*cgStep);
+
+    return std::make_shared<LinearSolver>(cgStep, parset_.template get<int>("solver.tnnmg.main.multi"), parset_.template get<double>("solver.tnnmg.linear.tolerance"), norm, Solver::QUIET);
+}
+
+template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+IterationRegister AdaptiveTimeStepper<Factory, ContactNetwork, 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
+    |F1|F2|     | the result of (R1+R2) with C, i.e. two steps of size
+                  tau with one of size 2*tau. To check if we need to
+    refine, we compare the result of (F1+F2) with R1, i.e. two steps
+    of size tau/2 with one of size tau. The method makes multiple
+    coarsening/refining attempts, with coarsening coming first. */
+
+  std::cout << "AdaptiveTimeStepper::advance()" << std::endl;
+
+  // patch preconditioner only needs to be computed once per advance()
+  // make linear solver for linear correction in TNNMGStep
+  using Norm =  EnergyNorm<Matrix, Vector>;
+  using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, Matrix, Vector>;
+  using LinearSolver = typename Dune::Solvers::LoopSolver<Vector>;
+
+  /*const auto& preconditionerParset = parset_.sub("solver.tnnmg.preconditioner");
+
+  Dune::BitSetVector<1> activeLevels(contactNetwork_.nLevels(), true);
+  Preconditioner preconditioner(preconditionerParset, contactNetwork_, activeLevels);
+  preconditioner.setPatchDepth(preconditionerParset.template get<size_t>("patchDepth"));
+  preconditioner.build();
+
+  auto cgStep = std::make_shared<Dune::Solvers::CGStep<Matrix, Vector>>();
+  cgStep->setPreconditioner(preconditioner);
+
+  Norm norm(*cgStep);
+
+  auto linearSolver = std::make_shared<LinearSolver>(cgStep, parset_.template get<int>("solver.tnnmg.main.multi"), parset_.template get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), norm, Solver::QUIET);
+*/
+  // set multigrid solver
+  auto smoother = TruncatedBlockGSStep<Matrix, Vector>();
+
+  using TransferOperator = NBodyContactTransfer<ContactNetwork, Vector>;
+  using TransferOperators = std::vector<std::shared_ptr<TransferOperator>>;
+
+  TransferOperators transfer(contactNetwork_.nLevels()-1);
+  for (size_t i=0; i<transfer.size(); i++) {
+      transfer[i] = std::make_shared<TransferOperator>();
+      transfer[i]->setup(contactNetwork_, i, i+1);
+  }
+
+  // Remove any recompute filed so that initially the full transferoperator is assembled
+  for (size_t i=0; i<transfer.size(); i++)
+      std::dynamic_pointer_cast<TruncatedMGTransfer<Vector> >(transfer[i])->setRecomputeBitField(nullptr);
+
+  auto linearMultigridStep = std::make_shared<Dune::Solvers::MultigridStep<Matrix, Vector> >();
+  linearMultigridStep->setMGType(1, 3, 3);
+  linearMultigridStep->setSmoother(smoother);
+  linearMultigridStep->setTransferOperators(transfer);
+
+  Norm norm(*linearMultigridStep);
+
+  auto linearSolver = std::make_shared<LinearSolver>(linearMultigridStep, parset_.template get<int>("solver.tnnmg.main.multi"), parset_.template get<double>("solver.tnnmg.preconditioner.basesolver.tolerance"), norm, Solver::QUIET);
+
+  const auto& currentNBodyAssembler = contactNetwork_.nBodyAssembler();
+
+  if (R1_.updaters == Updaters()) {
+    //setDeformation(current_);
+    R1_ = step(current_, currentNBodyAssembler, linearSolver, relativeTime_, relativeTau_);
+  }
+
+  //std::cout << "AdaptiveTimeStepper Step 1" << std::endl;
+
+  size_t coarseningCount = 0;
+  size_t refineCount = 0;
+
+  bool didCoarsen = false;
+  iterationRegister_.reset();
+  UpdatersWithCount R2;
+  UpdatersWithCount C;
+
+  while (relativeTime_ + relativeTau_ <= 1.0) {
+    std::cout << "tau: " << relativeTau_ << std::endl;
+
+    setDeformation(current_);
+    C = step(current_, currentNBodyAssembler, linearSolver, relativeTime_, 2 * relativeTau_);
+    std::cout << "AdaptiveTimeStepper C computed!" << std::endl << std::endl;
+
+    /*using ScalarVector = typename Updaters::StateUpdater::ScalarVector;
+    std::vector<ScalarVector> cAlpha(contactNetwork_.nBodies());
+    C.updaters.state_->extractAlpha(cAlpha);
+    print(cAlpha, "cAlpha: ");*/
+
+    setDeformation(R1_.updaters);
+    auto&& nBodyAssembler = step(currentNBodyAssembler);
+    R2 = step(R1_.updaters, nBodyAssembler, linearSolver, relativeTime_ + relativeTau_, relativeTau_);
+    std::cout << "AdaptiveTimeStepper R2 computed!" << std::endl << std::endl;
+
+
+    /*std::vector<ScalarVector> rAlpha(contactNetwork_.nBodies());
+    R2.updaters.state_->extractAlpha(rAlpha);
+    print(rAlpha, "rAlpha: ");*/
+
+
+    if (mustRefine_(C.updaters, R2.updaters))
+      break;
+
+    didCoarsen = true;
+    relativeTau_ *= 2;
+    R1_ = C;
+
+    coarseningCount++;
+  }
+
+  UpdatersWithCount F1;
+  UpdatersWithCount F2;
+  if (!didCoarsen) {
+    while (true) {
+      setDeformation(current_);
+      F1 = step(current_, currentNBodyAssembler, linearSolver, relativeTime_, relativeTau_ / 2.0);
+      std::cout << "AdaptiveTimeStepper F1 computed!" << std::endl << std::endl;
+
+      setDeformation(F1.updaters);
+      auto&& nBodyAssembler = step(currentNBodyAssembler);
+      F2 = step(F1.updaters, nBodyAssembler, linearSolver, relativeTime_ + relativeTau_ / 2.0,
+                relativeTau_ / 2.0);
+      std::cout << "AdaptiveTimeStepper F2 computed!" << std::endl << std::endl;
+      if (!mustRefine_(R1_.updaters, F2.updaters)) {
+        std::cout << "Sufficiently refined!" << std::endl;
+        break;
+      }
+
+      relativeTau_ /= 2.0;
+      R1_ = F1;
+      R2 = F2;
+
+      refineCount++;
+    }
+  }
+
+  std::cout << "AdaptiveTimeStepper::advance() ...";
+
+  iterationRegister_.registerFinalCount(R1_.count);
+  relativeTime_ += relativeTau_;
+  current_ = R1_.updaters;
+
+  //UpdatersWithCount emptyR1;
+  //R1_ = emptyR1;
+  R1_ = R2;
+
+  std::cout << " done with coarseningCount: " << coarseningCount << " and refineCount: " << refineCount << std::endl;
+
+  return iterationRegister_;
+}
+
+template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+void AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::setDeformation(const Updaters& updaters) {
+    std::vector<Vector> u;
+    updaters.rate_->extractDisplacement(u);
+
+    for (size_t i=0; i<contactNetwork_.nBodies(); i++) {
+        contactNetwork_.body(i)->setDeformation(u[i]);
+    }
+
+    // note: levelContactNetworks are not up-to-date; build() has to be called in order to update;
+    // unnecessary for standard multigrid as linear solver, might have to be called for patch preconditioner
+}
+
+template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+typename AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::NBodyAssembler
+AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(const NBodyAssembler& oldNBodyAssembler) const {
+    NBodyAssembler nBodyAssembler = oldNBodyAssembler;
+
+    nBodyAssembler.assembleTransferOperator();
+    nBodyAssembler.assembleObstacle();
+
+    return nBodyAssembler;
+}
+
+template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+template <class LinearSolver>
+typename AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::UpdatersWithCount
+AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(
+    const Updaters& oldUpdaters, const NBodyAssembler& nBodyAssembler, std::shared_ptr<LinearSolver>& linearSolver, double rTime, double rTau) {
+
+  UpdatersWithCount newUpdatersAndCount = {oldUpdaters.clone(), {}};
+
+  MyCoupledTimeStepper coupledTimeStepper(finalTime_, parset_, nBodyAssembler,
+                                          ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_,
+                                          newUpdatersAndCount.updaters, errorNorms_, externalForces_);
+
+  newUpdatersAndCount.count = coupledTimeStepper.step(linearSolver, rTime, rTau);
+  iterationRegister_.registerCount(newUpdatersAndCount.count);
+
+  /*using ScalarVector = typename Updaters::StateUpdater::ScalarVector;
+  std::vector<ScalarVector> alpha(contactNetwork_.nBodies());
+  newUpdatersAndCount.updaters.state_->extractAlpha(alpha);
+  print(alpha, "step alpha: ");
+  */
+  return newUpdatersAndCount;
+}
+
+#include "adaptivetimestepper_tmpl.cc"
diff --git a/src/time-stepping/adaptivetimestepper.hh b/dune/tectonic/time-stepping/adaptivetimestepper.hh
similarity index 75%
rename from src/time-stepping/adaptivetimestepper.hh
rename to dune/tectonic/time-stepping/adaptivetimestepper.hh
index ce090c01..391170a0 100644
--- a/src/time-stepping/adaptivetimestepper.hh
+++ b/dune/tectonic/time-stepping/adaptivetimestepper.hh
@@ -23,11 +23,14 @@ class AdaptiveTimeStepper {
   };
 
   using Vector = typename Factory::Vector;
+  using Matrix = typename Factory::Matrix;
   using IgnoreVector = typename Factory::BitVector;
   //using ConvexProblem = typename Factory::ConvexProblem;
   //using Nonlinearity = typename Factory::Nonlinearity;
 
-  using MyCoupledTimeStepper = CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>;
+  using NBodyAssembler = typename ContactNetwork::NBodyAssembler;
+
+  using MyCoupledTimeStepper = CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>;
 
   using GlobalFriction = typename MyCoupledTimeStepper::GlobalFriction;
   using BitVector = typename MyCoupledTimeStepper::BitVector;
@@ -36,7 +39,7 @@ class AdaptiveTimeStepper {
 public:
   AdaptiveTimeStepper(
                       Dune::ParameterTree const &parset,
-                      const ContactNetwork& contactNetwork,
+                      ContactNetwork& contactNetwork,
                       const IgnoreVector& ignoreNodes,
                       GlobalFriction& globalFriction,
                       const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
@@ -49,18 +52,27 @@ class AdaptiveTimeStepper {
 
   bool reachedEnd();
 
+  auto makeLinearSolver() const;
+
   IterationRegister advance();
 
   double relativeTime_;
   double relativeTau_;
 
 private:
-  UpdatersWithCount step(Updaters const &oldUpdaters, double rTime,
-                         double rTau);
+  void setDeformation(const Updaters& updaters);
+
+  NBodyAssembler step(const NBodyAssembler& oldNBodyAssembler) const;
+
+
+  template <class LinearSolver>
+  UpdatersWithCount step(const Updaters& oldUpdaters, const NBodyAssembler& nBodyAssembler,
+                         std::shared_ptr<LinearSolver>& linearSolver,
+                         double rTime, double rTau);
 
   double finalTime_;
   Dune::ParameterTree const &parset_;
-  const ContactNetwork& contactNetwork_;
+  ContactNetwork& contactNetwork_;
   const IgnoreVector& ignoreNodes_;
 
   GlobalFriction& globalFriction_;
@@ -74,4 +86,5 @@ class AdaptiveTimeStepper {
 
   IterationRegister iterationRegister_;
 };
+
 #endif
diff --git a/dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc b/dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc
new file mode 100644
index 00000000..0e7cd4f9
--- /dev/null
+++ b/dune/tectonic/time-stepping/adaptivetimestepper_tmpl.cc
@@ -0,0 +1,42 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
+
+#include <dune/solvers/norms/energynorm.hh>
+#include <dune/solvers/solvers/loopsolver.hh>
+
+#include "../spatial-solving/tnnmg/functional.hh"
+#include "../spatial-solving/solverfactory.hh"
+
+#include "../data-structures/network/contactnetwork.hh"
+#include "../data-structures/friction/globalfriction.hh"
+
+#include "rate/rateupdater.hh"
+#include "state/stateupdater.hh"
+#include "updaters.hh"
+
+using MyContactNetwork = ContactNetwork<Grid, Vector>;
+
+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 LinearSolver = Dune::Solvers::LoopSolver<Vector>;
+using ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
+using NBodyAssembler = typename MyContactNetwork::NBodyAssembler;
+
+using MyGlobalFriction = GlobalFriction<Matrix, Vector>;
+using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>;
+using MySolverFactory = SolverFactory<MyFunctional, BitVector>;
+
+template class AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>;
+
+template typename AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>::UpdatersWithCount
+AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>::step<LinearSolver>(
+        const MyUpdaters&, const NBodyAssembler&, std::shared_ptr<LinearSolver>&, double, double);
diff --git a/src/time-stepping/coupledtimestepper.cc b/dune/tectonic/time-stepping/coupledtimestepper.cc
similarity index 63%
rename from src/time-stepping/coupledtimestepper.cc
rename to dune/tectonic/time-stepping/coupledtimestepper.cc
index 1df54774..42659d41 100644
--- a/src/time-stepping/coupledtimestepper.cc
+++ b/dune/tectonic/time-stepping/coupledtimestepper.cc
@@ -4,10 +4,12 @@
 
 #include "coupledtimestepper.hh"
 
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
-CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::CoupledTimeStepper(
+#include "../utils/debugutils.hh"
+
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::CoupledTimeStepper(
     double finalTime, Dune::ParameterTree const &parset,
-    const ContactNetwork& contactNetwork,
+    const NBodyAssembler& nBodyAssembler,
     const IgnoreVector& ignoreNodes,
     GlobalFriction& globalFriction,
     const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
@@ -16,7 +18,7 @@ CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::CoupledTimeSt
     ExternalForces& externalForces)
     : finalTime_(finalTime),
       parset_(parset),
-      contactNetwork_(contactNetwork),
+      nBodyAssembler_(nBodyAssembler),
       ignoreNodes_(ignoreNodes),
       globalFriction_(globalFriction),
       bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries),
@@ -24,12 +26,13 @@ CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::CoupledTimeSt
       externalForces_(externalForces),
       errorNorms_(errorNorms) {}
 
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+template <class LinearSolver>
 FixedPointIterationCounter
-CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(double relativeTime,
+CoupledTimeStepper<Factory, NBodyAssembler, Updaters, ErrorNorms>::step(std::shared_ptr<LinearSolver>& linearSolver, double relativeTime,
                                                        double relativeTau) {
 
-  std::cout << "CoupledTimeStepper::step()" << std::endl;
+  //std::cout << "CoupledTimeStepper::step()" << std::endl;
 
   updaters_.state_->nextTimeStep();
   updaters_.rate_->nextTimeStep();
@@ -48,9 +51,17 @@ CoupledTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(double r
   updaters_.state_->setup(tau); 
   updaters_.rate_->setup(ell, tau, newRelativeTime, velocityRHS, velocityIterate, velocityMatrix);
 
+/*  std::cout << "tau: " << tau << std::endl;
+  print(ell, "ell: ");
+  print(velocityRHS, "velocityRHS: ");
+  print(velocityIterate, "velocityIterate: ");
+  for (size_t i=0; i<velocityMatrix.size(); i++) {
+        print(velocityMatrix[i], "velocityMatrix: ");
+  }*/
+
   FixedPointIterator fixedPointIterator(
-      parset_, contactNetwork_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, errorNorms_);
-  auto const iterations = fixedPointIterator.run(updaters_,
+      parset_, nBodyAssembler_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_, errorNorms_);
+  auto const iterations = fixedPointIterator.template run<LinearSolver>(updaters_, linearSolver,
                                                  velocityMatrix, velocityRHS, velocityIterate);
   return iterations;
 }
diff --git a/src/time-stepping/coupledtimestepper.hh b/dune/tectonic/time-stepping/coupledtimestepper.hh
similarity index 77%
rename from src/time-stepping/coupledtimestepper.hh
rename to dune/tectonic/time-stepping/coupledtimestepper.hh
index fc619036..07391d9f 100644
--- a/src/time-stepping/coupledtimestepper.hh
+++ b/dune/tectonic/time-stepping/coupledtimestepper.hh
@@ -8,12 +8,12 @@
 
 #include "../spatial-solving/fixedpointiterator.hh"
 
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
+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 FixedPointIterator = FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>;
+  using FixedPointIterator = FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>;
 
 public:
   using GlobalFriction = typename FixedPointIterator::GlobalFriction;
@@ -23,7 +23,7 @@ class CoupledTimeStepper {
 public:
   CoupledTimeStepper(double finalTime,
                      Dune::ParameterTree const &parset,
-                     const ContactNetwork& contactNetwork,
+                     const NBodyAssembler& nBodyAssembler,
                      const IgnoreVector& ignoreNodes,
                      GlobalFriction& globalFriction,
                      const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
@@ -31,12 +31,13 @@ class CoupledTimeStepper {
                      const ErrorNorms& errorNorms,
                      ExternalForces& externalForces);
 
-  FixedPointIterationCounter step(double relativeTime, double relativeTau);
+  template <class LinearSolver>
+  FixedPointIterationCounter step(std::shared_ptr<LinearSolver>& linearSolver, double relativeTime, double relativeTau);
 
 private:
   double finalTime_;
   Dune::ParameterTree const &parset_;
-  const ContactNetwork& contactNetwork_;
+  const NBodyAssembler& nBodyAssembler_;
   const IgnoreVector& ignoreNodes_;
 
   GlobalFriction& globalFriction_;
@@ -46,4 +47,5 @@ class CoupledTimeStepper {
   ExternalForces& externalForces_;
   const ErrorNorms& errorNorms_;
 };
+
 #endif
diff --git a/dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc b/dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc
new file mode 100644
index 00000000..e09f3f89
--- /dev/null
+++ b/dune/tectonic/time-stepping/coupledtimestepper_tmpl.cc
@@ -0,0 +1,40 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../explicitgrid.hh"
+#include "../explicitvectors.hh"
+
+#include <dune/solvers/norms/energynorm.hh>
+#include <dune/solvers/solvers/loopsolver.hh>
+
+#include "../spatial-solving/tnnmg/functional.hh"
+#include "../spatial-solving/solverfactory.hh"
+
+#include "../data-structures/network/contactnetwork.hh"
+#include "../data-structures/friction/globalfriction.hh"
+
+#include "rate/rateupdater.hh"
+#include "state/stateupdater.hh"
+#include "updaters.hh"
+
+using MyContactNetwork = ContactNetwork<Grid, Vector>;
+
+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 LinearSolver = Dune::Solvers::LoopSolver<Vector>;
+using ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
+using NBodyAssembler = typename MyContactNetwork::NBodyAssembler;
+
+using MyGlobalFriction = GlobalFriction<Matrix, Vector>;
+using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>;
+using MySolverFactory = SolverFactory<MyFunctional, BitVector>;
+
+template class CoupledTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>;
+
+template FixedPointIterationCounter CoupledTimeStepper<MySolverFactory, NBodyAssembler, MyUpdaters, ErrorNorms>::step<LinearSolver>(std::shared_ptr<LinearSolver>&, double, double);
diff --git a/src/time-stepping/rate.cc b/dune/tectonic/time-stepping/rate.cc
similarity index 100%
rename from src/time-stepping/rate.cc
rename to dune/tectonic/time-stepping/rate.cc
diff --git a/src/time-stepping/rate.hh b/dune/tectonic/time-stepping/rate.hh
similarity index 100%
rename from src/time-stepping/rate.hh
rename to dune/tectonic/time-stepping/rate.hh
diff --git a/dune/tectonic/time-stepping/rate/CMakeLists.txt b/dune/tectonic/time-stepping/rate/CMakeLists.txt
new file mode 100644
index 00000000..a4b6508b
--- /dev/null
+++ b/dune/tectonic/time-stepping/rate/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_custom_target(tectonic_dune_time-stepping_rate SOURCES
+  backward_euler.hh
+  backward_euler.cc
+  newmark.hh
+  newmark.cc
+  rateupdater.hh
+  rateupdater.cc
+)
+
+#install headers
+install(FILES
+  backward_euler.hh
+  newmark.hh
+  rateupdater.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/time-stepping/rate/backward_euler.cc b/dune/tectonic/time-stepping/rate/backward_euler.cc
similarity index 100%
rename from src/time-stepping/rate/backward_euler.cc
rename to dune/tectonic/time-stepping/rate/backward_euler.cc
diff --git a/src/time-stepping/rate/backward_euler.hh b/dune/tectonic/time-stepping/rate/backward_euler.hh
similarity index 100%
rename from src/time-stepping/rate/backward_euler.hh
rename to dune/tectonic/time-stepping/rate/backward_euler.hh
diff --git a/src/time-stepping/rate/newmark.cc b/dune/tectonic/time-stepping/rate/newmark.cc
similarity index 100%
rename from src/time-stepping/rate/newmark.cc
rename to dune/tectonic/time-stepping/rate/newmark.cc
diff --git a/src/time-stepping/rate/newmark.hh b/dune/tectonic/time-stepping/rate/newmark.hh
similarity index 100%
rename from src/time-stepping/rate/newmark.hh
rename to dune/tectonic/time-stepping/rate/newmark.hh
diff --git a/src/time-stepping/rate/rateupdater.cc b/dune/tectonic/time-stepping/rate/rateupdater.cc
similarity index 100%
rename from src/time-stepping/rate/rateupdater.cc
rename to dune/tectonic/time-stepping/rate/rateupdater.cc
diff --git a/src/time-stepping/rate/rateupdater.hh b/dune/tectonic/time-stepping/rate/rateupdater.hh
similarity index 100%
rename from src/time-stepping/rate/rateupdater.hh
rename to dune/tectonic/time-stepping/rate/rateupdater.hh
diff --git a/src/time-stepping/rate/rateupdater_tmpl.cc b/dune/tectonic/time-stepping/rate/rateupdater_tmpl.cc
similarity index 80%
rename from src/time-stepping/rate/rateupdater_tmpl.cc
rename to dune/tectonic/time-stepping/rate/rateupdater_tmpl.cc
index 09299039..b626865f 100644
--- a/src/time-stepping/rate/rateupdater_tmpl.cc
+++ b/dune/tectonic/time-stepping/rate/rateupdater_tmpl.cc
@@ -5,7 +5,9 @@
 #include "../../explicitgrid.hh"
 #include "../../explicitvectors.hh"
 
-#include "../../data-structures/contactnetwork_tmpl.cc"
+#include "../../data-structures/network/contactnetwork.hh"
+
+using MyContactNetwork = ContactNetwork<Grid, Vector>;
 
 using BoundaryNodes = typename MyContactNetwork::BoundaryNodes;
 using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions;
diff --git a/src/time-stepping/rate_tmpl.cc b/dune/tectonic/time-stepping/rate_tmpl.cc
similarity index 77%
rename from src/time-stepping/rate_tmpl.cc
rename to dune/tectonic/time-stepping/rate_tmpl.cc
index 771a1a0c..a2daf9d7 100644
--- a/src/time-stepping/rate_tmpl.cc
+++ b/dune/tectonic/time-stepping/rate_tmpl.cc
@@ -1,5 +1,12 @@
-#include "../data-structures/contactnetwork_tmpl.cc"
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include "../explicitgrid.hh"
 #include "../explicitvectors.hh"
+#include "../data-structures/network/contactnetwork.hh"
+
+using MyContactNetwork = ContactNetwork<Grid, Vector>;
 
 using BoundaryFunctions = typename MyContactNetwork::BoundaryFunctions;
 using BoundaryNodes = typename MyContactNetwork::BoundaryNodes;
diff --git a/src/time-stepping/state.cc b/dune/tectonic/time-stepping/state.cc
similarity index 100%
rename from src/time-stepping/state.cc
rename to dune/tectonic/time-stepping/state.cc
diff --git a/src/time-stepping/state.hh b/dune/tectonic/time-stepping/state.hh
similarity index 100%
rename from src/time-stepping/state.hh
rename to dune/tectonic/time-stepping/state.hh
diff --git a/dune/tectonic/time-stepping/state/CMakeLists.txt b/dune/tectonic/time-stepping/state/CMakeLists.txt
new file mode 100644
index 00000000..9fe69dc1
--- /dev/null
+++ b/dune/tectonic/time-stepping/state/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_custom_target(tectonic_dune_time-stepping_state SOURCES
+  ageinglawstateupdater.hh
+  ageinglawstateupdater.cc
+  sliplawstateupdater.hh
+  sliplawstateupdater.cc
+  stateupdater.hh
+)
+
+#install headers
+install(FILES
+  ageinglawstateupdater.hh
+  sliplawstateupdater.hh
+  stateupdater.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/time-stepping/state/ageinglawstateupdater.cc b/dune/tectonic/time-stepping/state/ageinglawstateupdater.cc
similarity index 100%
rename from src/time-stepping/state/ageinglawstateupdater.cc
rename to dune/tectonic/time-stepping/state/ageinglawstateupdater.cc
diff --git a/src/time-stepping/state/ageinglawstateupdater.hh b/dune/tectonic/time-stepping/state/ageinglawstateupdater.hh
similarity index 100%
rename from src/time-stepping/state/ageinglawstateupdater.hh
rename to dune/tectonic/time-stepping/state/ageinglawstateupdater.hh
diff --git a/src/time-stepping/state/calculation.wxm b/dune/tectonic/time-stepping/state/calculation.wxm
similarity index 100%
rename from src/time-stepping/state/calculation.wxm
rename to dune/tectonic/time-stepping/state/calculation.wxm
diff --git a/dune/tectonic/time-stepping/state/explicit.aux b/dune/tectonic/time-stepping/state/explicit.aux
new file mode 100644
index 00000000..f23e5468
--- /dev/null
+++ b/dune/tectonic/time-stepping/state/explicit.aux
@@ -0,0 +1 @@
+\relax 
diff --git a/dune/tectonic/time-stepping/state/explicit.log b/dune/tectonic/time-stepping/state/explicit.log
new file mode 100644
index 00000000..5f51474a
--- /dev/null
+++ b/dune/tectonic/time-stepping/state/explicit.log
@@ -0,0 +1,285 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016/Debian) (preloaded format=pdflatex 2018.9.22)  2 SEP 2019 17:19
+entering extended mode
+ restricted \write18 enabled.
+ %&-line parsing enabled.
+**explicit.tex
+(./explicit.tex
+LaTeX2e <2017/01/01> patch level 3
+Babel <3.9r> and hyphenation patterns for 83 language(s) loaded.
+(/usr/share/texlive/texmf-dist/tex/latex/standalone/standalone.cls
+Document Class: standalone 2015/07/15 v1.2 Class to compile TeX sub-files stand
+alone
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifluatex.sty
+Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO)
+Package ifluatex Info: LuaTeX not detected.
+)
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ifpdf.sty
+Package: ifpdf 2016/05/14 v3.1 Provides the ifpdf switch
+)
+(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty
+Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional
+)
+(/usr/share/texlive/texmf-dist/tex/latex/xkeyval/xkeyval.sty
+Package: xkeyval 2014/12/03 v2.7a package option processing (HA)
+
+(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkeyval.tex
+(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkvutils.tex
+\XKV@toks=\toks14
+\XKV@tempa@toks=\toks15
+
+(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/keyval.tex))
+\XKV@depth=\count79
+File: xkeyval.tex 2014/12/03 v2.7a key=value parser (HA)
+))
+\sa@internal=\count80
+\c@sapage=\count81
+
+(/usr/share/texlive/texmf-dist/tex/latex/standalone/standalone.cfg
+File: standalone.cfg 2015/07/15 v1.2 Default configuration file for 'standalone
+' class
+)
+(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
+(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
+)
+\c@part=\count82
+\c@section=\count83
+\c@subsection=\count84
+\c@subsubsection=\count85
+\c@paragraph=\count86
+\c@subparagraph=\count87
+\c@figure=\count88
+\c@table=\count89
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(/usr/share/texmf/tex/latex/preview/preview.sty
+Package: preview 2010/02/14 11.90 (AUCTeX/preview-latex)
+
+(/usr/share/texmf/tex/latex/preview/prtightpage.def
+\PreviewBorder=\dimen103
+)
+\pr@snippet=\count90
+\pr@box=\box26
+\pr@output=\toks16
+))
+(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty
+Package: amsmath 2016/11/05 v2.16a AMS math features
+\@mathmargin=\skip43
+
+For additional information on amsmath, use the `?' option.
+(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty
+Package: amstext 2000/06/29 v2.01 AMS text
+
+(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty
+File: amsgen.sty 1999/11/30 v2.0 generic functions
+\@emptytoks=\toks17
+\ex@=\dimen104
+))
+(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty
+Package: amsbsy 1999/11/29 v1.2d Bold Symbols
+\pmbraise@=\dimen105
+)
+(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty
+Package: amsopn 2016/03/08 v2.02 operator names
+)
+\inf@bad=\count91
+LaTeX Info: Redefining \frac on input line 213.
+\uproot@=\count92
+\leftroot@=\count93
+LaTeX Info: Redefining \overline on input line 375.
+\classnum@=\count94
+\DOTSCASE@=\count95
+LaTeX Info: Redefining \ldots on input line 472.
+LaTeX Info: Redefining \dots on input line 475.
+LaTeX Info: Redefining \cdots on input line 596.
+\Mathstrutbox@=\box27
+\strutbox@=\box28
+\big@size=\dimen106
+LaTeX Font Info:    Redeclaring font encoding OML on input line 712.
+LaTeX Font Info:    Redeclaring font encoding OMS on input line 713.
+\macc@depth=\count96
+\c@MaxMatrixCols=\count97
+\dotsspace@=\muskip10
+\c@parentequation=\count98
+\dspbrk@lvl=\count99
+\tag@help=\toks18
+\row@=\count100
+\column@=\count101
+\maxfields@=\count102
+\andhelp@=\toks19
+\eqnshift@=\dimen107
+\alignsep@=\dimen108
+\tagshift@=\dimen109
+\tagwidth@=\dimen110
+\totwidth@=\dimen111
+\lineht@=\dimen112
+\@envbody=\toks20
+\multlinegap=\skip44
+\multlinetaggap=\skip45
+\mathdisplay@stack=\toks21
+LaTeX Info: Redefining \[ on input line 2817.
+LaTeX Info: Redefining \] on input line 2818.
+)
+(/usr/share/texlive/texmf-dist/tex/latex/mathtools/mathtools.sty
+Package: mathtools 2015/11/12 v1.18 mathematical typesetting tools
+
+(/usr/share/texlive/texmf-dist/tex/latex/tools/calc.sty
+Package: calc 2014/10/28 v4.3 Infix arithmetic (KKT,FJ)
+\calc@Acount=\count103
+\calc@Bcount=\count104
+\calc@Adimen=\dimen113
+\calc@Bdimen=\dimen114
+\calc@Askip=\skip46
+\calc@Bskip=\skip47
+LaTeX Info: Redefining \setlength on input line 80.
+LaTeX Info: Redefining \addtolength on input line 81.
+\calc@Ccount=\count105
+\calc@Cskip=\skip48
+)
+(/usr/share/texlive/texmf-dist/tex/latex/mathtools/mhsetup.sty
+Package: mhsetup 2010/01/21 v1.2a programming setup (MH)
+)
+LaTeX Info: Thecontrolsequence`\('isalreadyrobust on input line 129.
+LaTeX Info: Thecontrolsequence`\)'isalreadyrobust on input line 129.
+LaTeX Info: Thecontrolsequence`\['isalreadyrobust on input line 129.
+LaTeX Info: Thecontrolsequence`\]'isalreadyrobust on input line 129.
+\g_MT_multlinerow_int=\count106
+\l_MT_multwidth_dim=\dimen115
+\origjot=\skip49
+\l_MT_shortvdotswithinadjustabove_dim=\dimen116
+\l_MT_shortvdotswithinadjustbelow_dim=\dimen117
+\l_MT_above_intertext_sep=\dimen118
+\l_MT_below_intertext_sep=\dimen119
+\l_MT_above_shortintertext_sep=\dimen120
+\l_MT_below_shortintertext_sep=\dimen121
+)
+No file explicit.aux.
+\openout1 = `explicit.aux'.
+
+LaTeX Font Info:    Checking defaults for OML/cmm/m/it on input line 6.
+LaTeX Font Info:    ... okay on input line 6.
+LaTeX Font Info:    Checking defaults for T1/cmr/m/n on input line 6.
+LaTeX Font Info:    ... okay on input line 6.
+LaTeX Font Info:    Checking defaults for OT1/cmr/m/n on input line 6.
+LaTeX Font Info:    ... okay on input line 6.
+LaTeX Font Info:    Checking defaults for OMS/cmsy/m/n on input line 6.
+LaTeX Font Info:    ... okay on input line 6.
+LaTeX Font Info:    Checking defaults for OMX/cmex/m/n on input line 6.
+LaTeX Font Info:    ... okay on input line 6.
+LaTeX Font Info:    Checking defaults for U/cmr/m/n on input line 6.
+LaTeX Font Info:    ... okay on input line 6.
+Preview: Fontsize 10pt
+Preview: PDFoutput 1
+(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty
+Package: graphicx 2014/10/28 v1.0g Enhanced LaTeX Graphics (DPC,SPQR)
+
+(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty
+Package: graphics 2016/10/09 v1.0u Standard LaTeX Graphics (DPC,SPQR)
+
+(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty
+Package: trig 2016/01/03 v1.10 sin cos tan (DPC)
+)
+(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/graphics.cfg
+File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration
+)
+Package graphics Info: Driver file: pdftex.def on input line 99.
+
+(/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def
+File: pdftex.def 2017/01/12 v0.06k Graphics/color for pdfTeX
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/infwarerr.sty
+Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO)
+)
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty
+Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO)
+)
+\Gread@gobject=\count107
+
+(/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii
+[Loading MPS to PDF converter (version 2006.09.02).]
+\scratchcounter=\count108
+\scratchdimen=\dimen122
+\scratchbox=\box29
+\nofMPsegments=\count109
+\nofMParguments=\count110
+\everyMPshowfont=\toks22
+\MPscratchCnt=\count111
+\MPscratchDim=\dimen123
+\MPnumerator=\count112
+\makeMPintoPDFobject=\count113
+\everyMPtoPDFconversion=\toks23
+))) (/usr/share/texlive/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty
+Package: pdftexcmds 2016/05/21 v0.22 Utility functions of pdfTeX for LuaTeX (HO
+)
+Package pdftexcmds Info: LuaTeX not detected.
+Package pdftexcmds Info: \pdf@primitive is available.
+Package pdftexcmds Info: \pdf@ifprimitive is available.
+Package pdftexcmds Info: \pdfdraftmode found.
+)
+(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty
+Package: epstopdf-base 2016/05/15 v2.6 Base part for package epstopdf
+
+(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty
+Package: grfext 2016/05/16 v1.2 Manage graphics extensions (HO)
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvdefinekeys.sty
+Package: kvdefinekeys 2016/05/16 v1.4 Define keys (HO)
+))
+(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty
+Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO)
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty
+Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO)
+
+(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/etexcmds.sty
+Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO)
+Package etexcmds Info: Could not find \expanded.
+(etexcmds)             That can mean that you are not using pdfTeX 1.50 or
+(etexcmds)             that some package has redefined \expanded.
+(etexcmds)             In the latter case, load this package earlier.
+)))
+Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4
+38.
+Package grfext Info: Graphics extension search list:
+(grfext)             [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE
+G,.JBIG2,.JB2,.eps]
+(grfext)             \AppendGraphicsExtensions on input line 456.
+
+(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
+File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
+e
+))
+\Gin@req@height=\dimen124
+\Gin@req@width=\dimen125
+)
+Preview: Tightpage 0 0 0 0
+[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./explicit.aux) ) 
+Here is how much of TeX's memory you used:
+ 3166 strings out of 493013
+ 46673 string characters out of 6135682
+ 112782 words of memory out of 5000000
+ 6679 multiletter control sequences out of 15000+600000
+ 4094 words of font info for 16 fonts, out of 8000000 for 9000
+ 1141 hyphenation exceptions out of 8191
+ 53i,12n,56p,255b,147s stack positions out of 5000i,500n,10000p,200000b,80000s
+</usr/
+share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb></usr/share/
+texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/texliv
+e/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb></usr/share/texlive/texmf
+-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/share/texlive/texmf-dist/f
+onts/type1/public/amsfonts/cm/cmr10.pfb></usr/share/texlive/texmf-dist/fonts/ty
+pe1/public/amsfonts/cm/cmr5.pfb></usr/share/texlive/texmf-dist/fonts/type1/publ
+ic/amsfonts/cm/cmr7.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfo
+nts/cm/cmsy10.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm
+/cmsy5.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.
+pfb>
+Output written on explicit.pdf (1 page, 82543 bytes).
+PDF statistics:
+ 48 PDF objects out of 1000 (max. 8388607)
+ 34 compressed objects within 1 object stream
+ 0 named destinations out of 1000 (max. 500000)
+ 1 words of extra memory for PDF output out of 10000 (max. 10000000)
+
diff --git a/dune/tectonic/time-stepping/state/explicit.pdf b/dune/tectonic/time-stepping/state/explicit.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..6fc65f44258d5ae805d73b226c4f89a33a3fa730
GIT binary patch
literal 82543
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
ZC5c5P6-B9OToy)#CYD^Ps;>TSTmX6=DDnUR

literal 0
HcmV?d00001

diff --git a/dune/tectonic/time-stepping/state/explicit.synctex.gz b/dune/tectonic/time-stepping/state/explicit.synctex.gz
new file mode 100644
index 0000000000000000000000000000000000000000..187abd95b93a078a4fa804ae4b3fde5124d9a8d6
GIT binary patch
literal 2143
zcmb2|=3oE==B-gD^Bx})yZc#tSEEi&!?rBBEoZg56&UX|u=MI&F;W%0#xkks$@dTc
z{?1ieZ6TsLyG%f0!;<LbeED~+$|vmp|FJ6Ozwz(4r}uAObjJU<s&AduJpHSa^u%{x
zR*aVUboA$!E$2@?e!a*hca?p(>$ZwrGPC3PL$|H-J6>~l#x4KQx)XAzw5;cUeq0t9
zwpuINMsL&W%K7U*zuI_e-9N*eojax+U3AAXYR31U-hZoZ*w{QxeR@ytoA!5UmE+5=
z{%bj2k}rS#_a)<xl0LWJ%n&Vj|HW2&-lsQ}6Z5}`AO9B-wtk*_P2clBTV75)!9U^2
z?CfWDzpu-6&yt<<y7=3#O}E;w%eDV&P&f20_k9+uqd#5i{&ZWZ-<-21>QDI-dNyZU
zW7oN5zxHWuKDuhfr?30gTUo^)Fm;~!UwttP%W?;S*WWh0d}}Fw(|g`u$++t8UdeOs
z-3WhrJGL|~ck}V(Il|x0O-y&*Vl|~bbSwAzTJ~qFH@i3Wht5ywvvF6M;4weB&%#~i
z{^{#>$7NFcEc~ADlh4_wC+k>h_4f3;*!dazw4^6}&D#I&{rvSO=PB<tTCMlo?(Ced
zTNiS=uU1Z9fBM6+_#-#wG+Fr?bDXL<yUiqYV*YQD&!W;Aask>_`MVAseD-?VQm22q
z7gS?9-v>>sU9zd{?Xw+)wL3I^E&uINm^<^^)zaFESM0OSPyG0+q-5ruD_ag1&(lA3
z`sbeqvljdoS@Ddc@=1{J;v1`f&dTfDR2(_?z_$l`-V~n|FFU<e*X;1AqxPoiHv1pE
z`kdUh%*^6$P2u+ye$TmtZ#Sg(9a5j;^y;`=ZA#t?CA-4H&#R07N}sy*<o3IFr>?8L
zuiF{Y$G7as^Q+%x<bV3QY888!lgFp^$$d)m{(O5n{VZF1<fJFx-@WbkTXQ^XW=-m?
zRZsSt{B#T6qCd&#;8eHB1Rufd$ZU_3GACqxO$C-jANJqGeeK!f&A)Fj-r9b$Y{!H<
z)^;UnX*^rcEC~rnG<BVC>LjQdbgES}X4w>jRZD%=na(M8TKS0a-P$IO?9%kRW?{!9
z7b>q23n`XP)_ojRer>m=_A&uymf|TBi|?})__7|jWT0uW=+KTWA5<RoI9!T2-1$Aw
zYmr4V?=s%d8!JUzMRu*7@@QV@p6!mkX2HrGq3>;PEZ*?D|5whU=uBrvR&}3#r-yRx
z(K~j>C|Pfr7Na?vOKt61*T#=!9dp$TLLO`RZjld=RxVWXRN+i4f49GzvA>Ex*yjh=
z1T(J!F$cZ4?<e_%)qgzLsJ6h#Gbu<>b!kL;)CadqDJyq8n052RlINcO*`GVEUW!uQ
zUFBPNazX360u|nKF5a_@*L^5F_1@n>_v#_NolEbmnzGXB@QNo+D}J>wWGM#NNGbfu
zT_crweygmTg~U?FgjmK$F45DP)~wSC(MUd2m&a*%$@y?yeuz`#6c@Fn*9y2CubZeQ
zF89_uZM&lMgvZf>4u=~Oy3QvR*M8g=W_zZirSYcq`;F7QZ{AI5b~$OTQB}gR)aAjw
zr4sY@ZB+`Iz<o^mR8PZii~V_bm%9{anSRuWSIOEfBvtjL{J4s;Ok%r->V-3R=l&5W
zGw)nGd0E(X^Zj`&&)c@e_!&0csaSX1t98K*G3|hs9Ue;qLRyl8*3Jk#=FIH4AxU}r
zI<v&(PhOM+Y3tv1IH0m;*%9aFsf!ym-h8<BJMPb({2gqbxzA<X|M2=c3k7lM?&#sQ
zxWmfuHhAUh7_BvJzUSKB8Q)p*de&xXCAY+PJ5S7<s3&~ytYz0R{@TfAFK5k{Z|inm
z>UQn7^taubuY;m`GY|NE;kce>v3!|rRPayb$0aZ8`9rS%`|fabim>^r|6A*{R&6QD
zEtHTyS$OuC%gi+jwqB7ft{FQ*j1EaHF<z*2=#kgV0INe$D)w7#wrPoY2wtCYqN@IK
zow)?NL}}C;(~6^}s}j15G%Af_HcG?<e-Lzi(dyjh*v)^zy!wysg#{<?Gl>TC?Z5cU
z{rHYTi#N;tZXZ4zo2_#!RzyhHkVQK$u-JFny5gO7S|3;&b|?BqCowl)_;8vnCqW`A
zHa+Eql5-QkL;2+kj=INpO<_8my1TC_XX~80tcFF>iBh})TXI^Cn``sMYdGFxnKC_L
zyR@mlQLfwW`O;G^op8OhC`LI!?a0}rRgc~-y1&R!c;RdQ?Ioq#n0uTrOgWL;{OFR#
za-I6M|4d%ktn+2dZZ-|rH&yMBRHotQjS{Onuh_Qj)_nc8aH6g*TYXmpThsGfQo=0^
z$I9#t&GtR0W<RsBMESMQ<9;!nsqfTE^fx|tD!+Weqe86uVf1c2UN%M3zajjtUP)Kk
zUM%otPMyP4(rx78^>jVkZo{a=dmp;%xQ}uiN!{YUZBlOR6DehfKQSD$%Ku0tFEwL)
z#c5UicdN`~p<|)n*ZM8`bJ;BQLoClFmz^IsL``+vySD$aL)jzOQ=GXL-6Ece$EVu}
zdkUT9KAD@mR=H5ZS-Stp#hDN1ZAd$*vx@mk#!{gr)+|XKjtwj`=5N|~Kw|NXWy!Y^
z<^>yS2Fvg#1fJ|Un}798<&C?%IVy1~8jbg!%-M7^@&20G62YN=@2cv}dHZj>w)#E`
zgQa&9Y(lLLo?Cm-X4PB?{iQ}Ncl74zJ_`HF(<`d#m3U)Ov(?evD-BOf7e4&zXNmRB
zckI(HZZpX3V;8%}TV=~<y=k9u{yxk0J>6PrvNKJK+;&Q)ozpNsd_i*I;VY60w-yLL
z(|Er%=mo!tTk;g+rk4|MF36RVo4jDLhVsz|^IXj<w~4D2oJ};6UB6vu^4*{x$yWoC
z_^$kqPXAoqXaC`|==p$?{}0u3J^1$iPdwx5)22VYH2v#r6W@NQov%At-hcYy-|BV~
eYg(1_9(wQ8`&3+NsWbUM^Vv<eZ1*TIFaQ7xr!2Gp

literal 0
HcmV?d00001

diff --git a/src/time-stepping/state/explicit.tex b/dune/tectonic/time-stepping/state/explicit.tex
similarity index 100%
rename from src/time-stepping/state/explicit.tex
rename to dune/tectonic/time-stepping/state/explicit.tex
diff --git a/src/time-stepping/state/sliplawstateupdater.cc b/dune/tectonic/time-stepping/state/sliplawstateupdater.cc
similarity index 100%
rename from src/time-stepping/state/sliplawstateupdater.cc
rename to dune/tectonic/time-stepping/state/sliplawstateupdater.cc
diff --git a/src/time-stepping/state/sliplawstateupdater.hh b/dune/tectonic/time-stepping/state/sliplawstateupdater.hh
similarity index 100%
rename from src/time-stepping/state/sliplawstateupdater.hh
rename to dune/tectonic/time-stepping/state/sliplawstateupdater.hh
diff --git a/src/time-stepping/state/stateupdater.hh b/dune/tectonic/time-stepping/state/stateupdater.hh
similarity index 85%
rename from src/time-stepping/state/stateupdater.hh
rename to dune/tectonic/time-stepping/state/stateupdater.hh
index ed7a5241..016e08c0 100644
--- a/src/time-stepping/state/stateupdater.hh
+++ b/dune/tectonic/time-stepping/state/stateupdater.hh
@@ -65,7 +65,13 @@ template <class ScalarVectorTEMPLATE, class Vector> class StateUpdater {
   }
 
   std::shared_ptr<StateUpdater<ScalarVector, Vector>> virtual clone() const {
-      return std::make_shared<StateUpdater<ScalarVector, Vector>>(*this);
+      auto updater = std::make_shared<StateUpdater<ScalarVector, Vector>>();
+
+      for (size_t i=0; i<localStateUpdaters_.size(); i++) {
+          auto localUpdater = localStateUpdaters_[i]->clone();
+          updater->addLocalUpdater(localUpdater);
+      }
+      return updater; // std::make_shared<StateUpdater<ScalarVector, Vector>>(*this);
   }
 
 private:
diff --git a/src/time-stepping/state_tmpl.cc b/dune/tectonic/time-stepping/state_tmpl.cc
similarity index 93%
rename from src/time-stepping/state_tmpl.cc
rename to dune/tectonic/time-stepping/state_tmpl.cc
index 39fd6bd4..d4d99038 100644
--- a/src/time-stepping/state_tmpl.cc
+++ b/dune/tectonic/time-stepping/state_tmpl.cc
@@ -4,7 +4,7 @@
 #include <dune/common/promotiontraits.hh>
 #include <dune/contact/assemblers/dualmortarcoupling.hh>
 
-#include "../frictioncouplingpair.hh"
+#include "../data-structures/friction/frictioncouplingpair.hh"
 
 using field_type = typename Dune::PromotionTraits<typename Vector::field_type,
                                             typename DeformedGrid::ctype>::PromotedType;
diff --git a/src/time-stepping/updaters.hh b/dune/tectonic/time-stepping/updaters.hh
similarity index 100%
rename from src/time-stepping/updaters.hh
rename to dune/tectonic/time-stepping/updaters.hh
diff --git a/dune/tectonic/utils/CMakeLists.txt b/dune/tectonic/utils/CMakeLists.txt
new file mode 100644
index 00000000..c5498570
--- /dev/null
+++ b/dune/tectonic/utils/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_custom_target(tectonic_dune_utils SOURCES
+  almostequal.hh
+  debugutils.hh 
+  diameter.hh
+  geocoordinate.hh
+  index-in-sorted-range.hh
+  tobool.hh
+)
+
+#install headers
+install(FILES
+  almostequal.hh
+  debugutils.hh 
+  diameter.hh
+  geocoordinate.hh
+  index-in-sorted-range.hh
+  tobool.hh
+DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/tectonic)
diff --git a/src/utils/almostequal.hh b/dune/tectonic/utils/almostequal.hh
similarity index 100%
rename from src/utils/almostequal.hh
rename to dune/tectonic/utils/almostequal.hh
diff --git a/src/utils/debugutils.hh b/dune/tectonic/utils/debugutils.hh
similarity index 100%
rename from src/utils/debugutils.hh
rename to dune/tectonic/utils/debugutils.hh
diff --git a/src/utils/diameter.hh b/dune/tectonic/utils/diameter.hh
similarity index 100%
rename from src/utils/diameter.hh
rename to dune/tectonic/utils/diameter.hh
diff --git a/dune/tectonic/geocoordinate.hh b/dune/tectonic/utils/geocoordinate.hh
similarity index 100%
rename from dune/tectonic/geocoordinate.hh
rename to dune/tectonic/utils/geocoordinate.hh
diff --git a/dune/tectonic/index-in-sorted-range.hh b/dune/tectonic/utils/index-in-sorted-range.hh
similarity index 100%
rename from dune/tectonic/index-in-sorted-range.hh
rename to dune/tectonic/utils/index-in-sorted-range.hh
diff --git a/src/utils/tobool.hh b/dune/tectonic/utils/tobool.hh
similarity index 100%
rename from src/utils/tobool.hh
rename to dune/tectonic/utils/tobool.hh
diff --git a/program_structure.txt b/program_structure.txt
deleted file mode 100644
index a2db29cd..00000000
--- a/program_structure.txt
+++ /dev/null
@@ -1,29 +0,0 @@
---------------------------
---  Program structure:  --
---------------------------
-
-
-1. build n-body system 
-    - contains grids, couplings, gridViews, assembler 
-    
-    Data structure: LevelContactNetwork
-    Factories:      StackedBlocksFactory
-    
-2. initialize/set up program state
-    - holds bodyStates, u, v, a, alpha for each body
-    - defines time, timeStep
-    - computes initial conditions
-    
-    Data structure: ProgramState
-
--- tested until here
-
-3. assemble RSD friction
-
-4. set up TNNMG solver
-    - rate updater
-    - state updater
-    
-5. adaptive time stepper
-
- 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b45d06d1..e41c1f9a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,113 +1,19 @@
-add_subdirectory("tests")
-add_subdirectory("spatial-solving")
-
-set(SW_SOURCE_FILES
-  assemblers.cc
-  data-structures/body.cc
-  data-structures/enumparser.cc
-  io/vtk.cc
-  io/hdf5/frictionalboundary-writer.cc
-  io/hdf5/iteration-writer.cc
-  io/hdf5/patchinfo-writer.cc
-  io/hdf5/restart-io.cc
-  io/hdf5/surface-writer.cc
-  io/hdf5/time-writer.cc
-#  one-body-problem-data/mygeometry.cc
-#  one-body-problem-data/mygrid.cc
-#  one-body-problem.cc
-  spatial-solving/fixedpointiterator.cc
-  spatial-solving/solverfactory.cc
-  time-stepping/adaptivetimestepper.cc
-  time-stepping/coupledtimestepper.cc
-  time-stepping/rate.cc
-  time-stepping/rate/rateupdater.cc
-  time-stepping/state.cc
-)
-
-set(MSW_SOURCE_FILES
-  assemblers.cc
-  #nodalweights.cc
-  data-structures/body.cc
-  data-structures/levelcontactnetwork.cc
-  data-structures/contactnetwork.cc
-  data-structures/enumparser.cc
-  #factories/cantorfactory.cc
-  factories/threeblocksfactory.cc
-  factories/stackedblocksfactory.cc
-  io/vtk.cc
-  io/hdf5/frictionalboundary-writer.cc
-  io/hdf5/iteration-writer.cc
-  io/hdf5/patchinfo-writer.cc
-  io/hdf5/restart-io.cc
-  io/hdf5/surface-writer.cc
-  io/hdf5/time-writer.cc
-  #multi-body-problem-data/grid/cube.cc
-  #multi-body-problem-data/grid/cubefaces.cc
-  multi-body-problem-data/grid/cuboidgeometry.cc
-  multi-body-problem-data/grid/mygrids.cc
-  multi-body-problem-data/grid/simplexmanager.cc
-  multi-body-problem.cc
-  #spatial-solving/solverfactory.cc
-  spatial-solving/fixedpointiterator.cc
-  #spatial-solving/solverfactory_old.cc
-  time-stepping/adaptivetimestepper.cc
-  time-stepping/coupledtimestepper.cc
-  time-stepping/rate.cc
-  time-stepping/rate/rateupdater.cc
-  time-stepping/state.cc
-)
+add_subdirectory("foam")
+add_subdirectory("multi-body-problem")
 
 set(UGW_SOURCE_FILES
-  assemblers.cc # FIXME
-  io/uniform-grid-writer.cc
-  io/vtk.cc
-  one-body-problem-data/mygrid.cc
-)
-
-set(SFT_SOURCE_FILES
-  assemblers.cc
-  data-structures/body.cc
-  data-structures/levelcontactnetwork.cc
-  data-structures/contactnetwork.cc
-  data-structures/enumparser.cc
-  factories/stackedblocksfactory.cc
-  io/vtk.cc
-  multi-body-problem-data/grid/cuboidgeometry.cc
-  multi-body-problem-data/grid/mygrids.cc
-  multi-body-problem-data/grid/simplexmanager.cc
-  #spatial-solving/solverfactory.cc
-  #spatial-solving/fixedpointiterator.cc
-  #spatial-solving/solverfactory_old.cc
-  #time-stepping/adaptivetimestepper.cc
-  #time-stepping/coupledtimestepper.cc
-  time-stepping/rate.cc
-  time-stepping/rate/rateupdater.cc
-  time-stepping/state.cc
-  solverfactorytest.cc
+  ../dune/tectonic/assemblers.cc # FIXME
+  ../dune/tectonic/io/uniform-grid-writer.cc
+  ../dune/tectonic/io/vtk.cc
+  ../dune/tectonic/problem-data/grid/mygrids.cc
 )
 
 foreach(_dim 2 3)
-  set(_sw_target one-body-problem-${_dim}D)
-  set(_msw_target multi-body-problem-${_dim}D)
   set(_ugw_target uniform-grid-writer-${_dim}D)
-  set(_sft_target solverfactorytest-${_dim}D)
 
-  add_executable(${_sw_target} ${SW_SOURCE_FILES})
-  add_executable(${_msw_target} ${MSW_SOURCE_FILES})
   add_executable(${_ugw_target} ${UGW_SOURCE_FILES})
-  add_executable(${_sft_target} ${SFT_SOURCE_FILES})
-  add_dune_ug_flags(${_sw_target})
-  add_dune_ug_flags(${_msw_target})
+  
   add_dune_ug_flags(${_ugw_target})
-  add_dune_ug_flags(${_sft_target})
-
-  add_dune_hdf5_flags(${_sw_target})
-  add_dune_hdf5_flags(${_msw_target})
 
-  set_property(TARGET ${_sw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
-  set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
-  #set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1")
   set_property(TARGET ${_ugw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
-  set_property(TARGET ${_sft_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
-  #set_property(TARGET ${_sft_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1")
 endforeach()
diff --git a/src/data-structures/contactnetwork_tmpl.cc b/src/data-structures/contactnetwork_tmpl.cc
deleted file mode 100644
index 03374e69..00000000
--- a/src/data-structures/contactnetwork_tmpl.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef MY_DIM
-#error MY_DIM unset
-#endif
-
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
-
-#include "contactnetwork.hh"
-
-using MyContactNetwork =  ContactNetwork<Grid, Vector>;
-
-template class ContactNetwork<Grid, Vector>;
diff --git a/src/foam/CMakeLists.txt b/src/foam/CMakeLists.txt
new file mode 100644
index 00000000..ab24974c
--- /dev/null
+++ b/src/foam/CMakeLists.txt
@@ -0,0 +1,43 @@
+add_custom_target(tectonic_src_foam SOURCES
+  foam.cfg
+  foam-2D.cfg
+) 
+
+set(FOAM_SOURCE_FILES
+  ../../dune/tectonic/assemblers.cc
+  ../../dune/tectonic/data-structures/body/body.cc
+  ../../dune/tectonic/data-structures/network/levelcontactnetwork.cc
+  ../../dune/tectonic/data-structures/network/contactnetwork.cc
+  ../../dune/tectonic/data-structures/enumparser.cc
+  ../../dune/tectonic/factories/twoblocksfactory.cc
+  ../../dune/tectonic/io/vtk.cc
+  ../../dune/tectonic/io/hdf5/frictionalboundary-writer.cc
+  ../../dune/tectonic/io/hdf5/iteration-writer.cc
+  #../../dune/tectonic/io/hdf5/patchinfo-writer.cc
+  ../../dune/tectonic/io/hdf5/restart-io.cc
+  ../../dune/tectonic/io/hdf5/surface-writer.cc
+  ../../dune/tectonic/io/hdf5/time-writer.cc
+  ../../dune/tectonic/problem-data/grid/cuboidgeometry.cc
+  ../../dune/tectonic/problem-data/grid/mygrids.cc
+  ../../dune/tectonic/problem-data/grid/simplexmanager.cc
+  ../../dune/tectonic/spatial-solving/solverfactory.cc
+  ../../dune/tectonic/spatial-solving/fixedpointiterator.cc
+  ../../dune/tectonic/time-stepping/coupledtimestepper.cc
+  ../../dune/tectonic/time-stepping/adaptivetimestepper.cc
+  ../../dune/tectonic/time-stepping/rate.cc
+  ../../dune/tectonic/time-stepping/rate/rateupdater.cc
+  ../../dune/tectonic/time-stepping/state.cc
+  foam.cc
+)
+
+foreach(_dim 2 3)
+  set(_foam_target foam-${_dim}D)
+
+  add_executable(${_foam_target} ${FOAM_SOURCE_FILES})
+
+  add_dune_ug_flags(${_foam_target})
+  add_dune_hdf5_flags(${_foam_target})
+
+  set_property(TARGET ${_foam_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
+  #set_property(TARGET ${_foam_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1")
+endforeach()
diff --git a/src/one-body-problem-2D.cfg b/src/foam/foam-2D.cfg
similarity index 55%
rename from src/one-body-problem-2D.cfg
rename to src/foam/foam-2D.cfg
index a61cfba2..6efcb38b 100644
--- a/src/one-body-problem-2D.cfg
+++ b/src/foam/foam-2D.cfg
@@ -1,9 +1,9 @@
 # -*- mode:conf -*-
 [boundary.friction]
-smallestDiameter= 2e-3  # [m]
+smallestDiameter = 0.005  # 2e-3 [m]
 
 [timeSteps]
-refinementTolerance = 1e-5
+refinementTolerance = 1e-5 # 1e-5
 
 [u0.solver]
 tolerance         = 1e-8
@@ -17,5 +17,8 @@ tolerance         = 1e-8
 [v.fpi]
 tolerance         = 1e-5
 
-[solver.tnnmg.linear]
+[solver.tnnmg.preconditioner.basesolver]
+tolerance          = 1e-10
+
+[solver.tnnmg.preconditioner.patchsolver]
 tolerance          = 1e-10
diff --git a/src/foam/foam.cc b/src/foam/foam.cc
new file mode 100644
index 00000000..fe95424f
--- /dev/null
+++ b/src/foam/foam.cc
@@ -0,0 +1,483 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_IPOPT
+#undef HAVE_IPOPT
+#endif
+
+#include <atomic>
+#include <cmath>
+#include <csignal>
+#include <exception>
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <memory>
+
+#include <dune/common/bitsetvector.hh>
+#include <dune/common/exceptions.hh>
+#include <dune/common/fmatrix.hh>
+#include <dune/common/function.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/parametertree.hh>
+#include <dune/common/parametertreeparser.hh>
+
+#include <dune/grid/common/mcmgmapper.hh>
+#include <dune/istl/bcrsmatrix.hh>
+#include <dune/istl/bvector.hh>
+
+#include <dune/fufem/boundarypatch.hh>
+#include <dune/fufem/geometry/convexpolyhedron.hh>
+#include <dune/fufem/formatstring.hh>
+#include <dune/fufem/hdf5/file.hh>
+
+#include <dune/solvers/norms/energynorm.hh>
+#include <dune/solvers/solvers/loopsolver.hh>
+#include <dune/solvers/iterationsteps/blockgssteps.hh>
+
+#include <dune/contact/common/deformedcontinuacomplex.hh>
+#include <dune/contact/common/couplingpair.hh>
+#include <dune/contact/projections/normalprojection.hh>
+
+
+#include <dune/tectonic/assemblers.hh>
+#include <dune/tectonic/gridselector.hh>
+#include <dune/tectonic/explicitgrid.hh>
+#include <dune/tectonic/explicitvectors.hh>
+
+#include <dune/tectonic/data-structures/enumparser.hh>
+#include <dune/tectonic/data-structures/enums.hh>
+#include <dune/tectonic/data-structures/network/contactnetwork.hh>
+#include <dune/tectonic/data-structures/matrices.hh>
+#include <dune/tectonic/data-structures/program_state.hh>
+#include <dune/tectonic/data-structures/friction/globalfriction.hh>
+
+#include <dune/tectonic/factories/twoblocksfactory.hh>
+
+#include <dune/tectonic/io/hdf5-levelwriter.hh>
+#include <dune/tectonic/io/hdf5/restart-io.hh>
+#include <dune/tectonic/io/vtk.hh>
+
+#include <dune/tectonic/problem-data/bc.hh>
+#include <dune/tectonic/problem-data/mybody.hh>
+#include <dune/tectonic/problem-data/grid/mygrids.hh>
+
+#include <dune/tectonic/spatial-solving/tnnmg/functional.hh>
+//#include <dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh>
+#include <dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh>
+#include <dune/tectonic/spatial-solving/solverfactory.hh>
+
+#include <dune/tectonic/time-stepping/adaptivetimestepper.hh>
+#include <dune/tectonic/time-stepping/rate.hh>
+#include <dune/tectonic/time-stepping/state.hh>
+#include <dune/tectonic/time-stepping/updaters.hh>
+
+#include <dune/tectonic/utils/debugutils.hh>
+#include <dune/tectonic/utils/diameter.hh>
+#include <dune/tectonic/utils/geocoordinate.hh>
+
+// for getcwd
+#include <unistd.h>
+
+//#include <tbb/tbb.h> //TODO multi threading preconditioner?
+//#include <pthread.h>
+
+size_t const dims = MY_DIM;
+
+Dune::ParameterTree getParameters(int argc, char *argv[]) {
+  Dune::ParameterTree parset;
+  Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/foam/foam.cfg", parset);
+  Dune::ParameterTreeParser::readINITree(
+      Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/foam/foam-%dD.cfg", dims), parset);
+  Dune::ParameterTreeParser::readOptions(argc, argv, parset);
+  return parset;
+}
+
+static std::atomic<bool> terminationRequested(false);
+void handleSignal(int signum) { terminationRequested = true; }
+
+int main(int argc, char *argv[]) {
+  try {
+    Dune::MPIHelper::instance(argc, argv);
+
+    char buffer[256];
+    char *val = getcwd(buffer, sizeof(buffer));
+    if (val) {
+        std::cout << buffer << std::endl;
+        std::cout << argv[0] << std::endl;
+    }
+
+    std::ofstream out("foam.log");
+    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buffer
+    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to log.txt
+
+    auto const parset = getParameters(argc, argv);
+
+    using Assembler = MyAssembler<DefLeafGridView, dims>;
+    using field_type = Matrix::field_type;
+
+    // ----------------------
+    // set up contact network
+    // ----------------------
+    TwoBlocksFactory<Grid, Vector> twoBlocksFactory(parset);
+    using ContactNetwork = typename TwoBlocksFactory<Grid, Vector>::ContactNetwork;
+    twoBlocksFactory.build();
+
+    ContactNetwork& contactNetwork = twoBlocksFactory.contactNetwork();
+
+    /*ThreeBlocksFactory<Grid, Vector> threeBlocksFactory(parset);
+    using ContactNetwork = typename ThreeBlocksFactory<Grid, Vector>::ContactNetwork;
+    threeBlocksFactory.build();
+
+    ContactNetwork& contactNetwork = threeBlocksFactory.contactNetwork(); */
+
+    const size_t bodyCount = contactNetwork.nBodies();
+
+    for (size_t i=0; i<contactNetwork.nLevels(); i++) {
+        // printDofLocation(contactNetwork.body(i)->gridView());
+
+        //Vector def(contactNetwork.deformedGrids()[i]->size(dims));
+        //def = 1;
+        //deformedGridComplex.setDeformation(def, i);
+
+        const auto& level = *contactNetwork.level(i);
+
+        for (size_t j=0; j<level.nBodies(); j++) {
+            writeToVTK(level.body(j)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(j) + "_level_" + std::to_string(i));
+        }
+    }
+
+    for (size_t i=0; i<bodyCount; i++) {
+        writeToVTK(contactNetwork.body(i)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(i) + "_leaf");
+    }
+
+    // ----------------------------
+    // assemble contactNetwork
+    // ----------------------------
+    contactNetwork.assemble();
+
+    //printMortarBasis<Vector>(contactNetwork.nBodyAssembler());
+
+    // -----------------
+    // init input/output
+    // -----------------
+    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(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");
+    auto const writeData = parset.get<bool>("io.data.write");
+    bool const handleRestarts = writeRestarts or firstRestart > 0;
+
+
+    auto dataFile =
+        writeData ? std::make_unique<HDF5::File>("output.h5") : nullptr;
+
+    auto restartFile = handleRestarts
+                           ? std::make_unique<HDF5::File>(
+                                 "restarts.h5",
+                                 writeRestarts ? HDF5::Access::READWRITE
+                                               : HDF5::Access::READONLY)
+                           : nullptr;
+
+
+    auto restartIO = handleRestarts
+                         ? std::make_unique<RestartIO<MyProgramState>>(
+                               *restartFile, nVertices)
+                         : nullptr;
+
+    if (firstRestart > 0) // automatically adjusts the time and timestep
+      restartIO->read(firstRestart, programState);
+    else
+     programState.setupInitialConditions(parset, contactNetwork);
+
+
+    //DUNE_THROW(Dune::Exception, "Just need to stop here!");
+
+    auto& nBodyAssembler = contactNetwork.nBodyAssembler();
+    for (size_t i=0; i<bodyCount; i++) {
+      contactNetwork.body(i)->setDeformation(programState.u[i]);
+    }
+    nBodyAssembler.assembleTransferOperator();
+    nBodyAssembler.assembleObstacle();
+
+    // ------------------------
+    // assemble global friction
+    // ------------------------
+    contactNetwork.assembleFriction(parset.get<Config::FrictionModel>("boundary.friction.frictionModel"), programState.weightedNormalStress);
+
+    auto& globalFriction = contactNetwork.globalFriction();
+    globalFriction.updateAlpha(programState.alpha);
+
+    using MyVertexBasis = typename Assembler::VertexBasis;
+    using MyCellBasis = typename Assembler::CellBasis;
+    std::vector<Vector> vertexCoordinates(bodyCount);
+    std::vector<const MyVertexBasis* > vertexBases(bodyCount);
+    std::vector<const MyCellBasis* > cellBases(bodyCount);
+
+    auto& wPatches = twoBlocksFactory.weakPatches();
+    std::vector<std::vector<const ConvexPolyhedron<LocalVector>*>> weakPatches(bodyCount);
+
+
+    for (size_t i=0; i<bodyCount; i++) {
+      const auto& body = contactNetwork.body(i);
+      vertexBases[i] = &(body->assembler()->vertexBasis);
+      cellBases[i] = &(body->assembler()->cellBasis);
+
+      weakPatches[i].resize(1);
+      weakPatches[i][0] = wPatches[i].get();
+
+      auto& vertexCoords = vertexCoordinates[i];
+      vertexCoords.resize(nVertices[i]);
+
+      Dune::MultipleCodimMultipleGeomTypeMapper<
+          DefLeafGridView, Dune::MCMGVertexLayout> const vertexMapper(body->gridView(), Dune::mcmgVertexLayout());
+      for (auto &&v : vertices(body->gridView()))
+        vertexCoords[vertexMapper.index(v)] = geoToPoint(v.geometry());
+    }
+
+    typename ContactNetwork::BoundaryPatches frictionBoundaries;
+    contactNetwork.boundaryPatches("friction", frictionBoundaries);
+
+    auto dataWriter =
+        writeData ? std::make_unique<
+                        HDF5LevelWriter<MyProgramState, MyVertexBasis, DefLeafGridView>>(
+                        *dataFile, vertexCoordinates, vertexBases,
+                        frictionBoundaries, weakPatches)
+                  : nullptr;
+
+    const MyVTKWriter<MyVertexBasis, MyCellBasis> vtkWriter(cellBases, vertexBases, "/storage/mi/podlesny/software/dune/dune-tectonic/body");
+
+    IterationRegister iterationCount;
+
+    auto const report = [&](bool initial = false) {
+      if (writeData) {
+        dataWriter->reportSolution(programState, globalFriction);
+        if (!initial)
+          dataWriter->reportIterations(programState, iterationCount);
+        dataFile->flush();
+      }
+
+      if (writeRestarts and !initial and
+          programState.timeStep % restartSpacing == 0) {
+        restartIO->write(programState);
+        restartFile->flush();
+      }
+
+      if (parset.get<bool>("io.printProgress"))
+        std::cout << "timeStep = " << std::setw(6) << programState.timeStep
+                  << ", time = " << std::setw(12) << programState.relativeTime
+                  << ", tau = " << std::setw(12) << programState.relativeTau
+                  << std::endl;
+
+      if (parset.get<bool>("io.vtk.write")) {
+        std::vector<ScalarVector> stress(bodyCount);
+
+        for (size_t i=0; i<bodyCount; i++) {
+          const auto& body = contactNetwork.body(i);
+          body->assembler()->assembleVonMisesStress(body->data()->getYoungModulus(),
+                                           body->data()->getPoissonRatio(),
+                                           programState.u[i], stress[i]);
+
+        }
+
+        vtkWriter.write(programState.timeStep, programState.u, programState.v,
+                        programState.alpha, stress);
+      }
+    };
+    report(true);
+
+    // -------------------
+    // Set up TNNMG solver
+    // -------------------
+
+    BitVector totalDirichletNodes;
+    contactNetwork.totalNodes("dirichlet", totalDirichletNodes);
+
+    /*for (size_t i=0; i<totalDirichletNodes.size(); i++) {
+        bool val = false;
+        for (size_t d=0; d<dims; d++) {
+            val = val || totalDirichletNodes[i][d];
+        }
+
+        totalDirichletNodes[i] = val;
+        for (size_t d=0; d<dims; d++) {
+            totalDirichletNodes[i][d] = val;
+        }
+    }*/
+
+    //print(totalDirichletNodes, "totalDirichletNodes:");
+
+    //using Functional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, field_type>;
+    using Functional = Functional<Matrix&, Vector&, GlobalFriction<Matrix, Vector>&, Vector&, Vector&, field_type>;
+    using NonlinearFactory = SolverFactory<Functional, BitVector>;
+
+    using BoundaryFunctions = typename ContactNetwork::BoundaryFunctions;
+    using BoundaryNodes = typename ContactNetwork::BoundaryNodes;
+    using Updaters = Updaters<RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>,
+                               StateUpdater<ScalarVector, Vector>>;
+
+    BoundaryFunctions velocityDirichletFunctions;
+    contactNetwork.boundaryFunctions("dirichlet", velocityDirichletFunctions);
+
+    BoundaryNodes dirichletNodes;
+    contactNetwork.boundaryNodes("dirichlet", dirichletNodes);
+
+    /*for (size_t i=0; i<dirichletNodes.size(); i++) {
+        for (size_t j=0; j<dirichletNodes[i].size(); j++) {
+        print(*dirichletNodes[i][j], "dirichletNodes_body_" + std::to_string(i) + "_boundary_" + std::to_string(j));
+        }
+    }*/
+
+    std::vector<const Dune::BitSetVector<1>*> frictionNodes;
+    contactNetwork.frictionNodes(frictionNodes);
+
+    /*for (size_t i=0; i<frictionNodes.size(); i++) {
+        print(*frictionNodes[i], "frictionNodes_body_" + std::to_string(i));
+    }*/
+
+    Updaters current(
+        initRateUpdater(
+            parset.get<Config::scheme>("timeSteps.scheme"),
+            velocityDirichletFunctions,
+            dirichletNodes,
+            contactNetwork.matrices(),
+            programState.u,
+            programState.v,
+            programState.a),
+        initStateUpdater<ScalarVector, Vector>(
+            parset.get<Config::stateModel>("boundary.friction.stateModel"),
+            programState.alpha,
+            nBodyAssembler.getContactCouplings(),
+            contactNetwork.couplings())
+            );
+
+
+    auto const refinementTolerance = parset.get<double>("timeSteps.refinementTolerance");
+
+    const auto& stateEnergyNorms = contactNetwork.stateEnergyNorms();
+
+    auto const mustRefine = [&](Updaters &coarseUpdater,
+                                Updaters &fineUpdater) {
+
+        //return false;
+      //std::cout << "Step 1" << std::endl;
+
+      std::vector<ScalarVector> coarseAlpha;
+      coarseAlpha.resize(bodyCount);
+      coarseUpdater.state_->extractAlpha(coarseAlpha);
+
+      //print(coarseAlpha, "coarseAlpha:");
+
+      std::vector<ScalarVector> fineAlpha;
+      fineAlpha.resize(bodyCount);
+      fineUpdater.state_->extractAlpha(fineAlpha);
+
+      //print(fineAlpha, "fineAlpha:");
+
+      //std::cout << "Step 3" << std::endl;
+
+      ScalarVector::field_type energyNorm = 0;
+      for (size_t i=0; i<stateEnergyNorms.size(); i++) {
+          //std::cout << "for " << i << std::endl;
+
+          //std::cout << not stateEnergyNorms[i] << std::endl;
+
+          if (coarseAlpha[i].size()==0 || fineAlpha[i].size()==0)
+              continue;
+
+          energyNorm += stateEnergyNorms[i]->diff(fineAlpha[i], coarseAlpha[i]);
+      }
+      std::cout << "energy norm: " << energyNorm << " tol: " << refinementTolerance <<  std::endl;
+      std::cout << "must refine: " << (energyNorm > refinementTolerance) <<  std::endl;
+      return energyNorm > refinementTolerance;
+    };
+
+
+    std::signal(SIGXCPU, handleSignal);
+    std::signal(SIGINT, handleSignal);
+    std::signal(SIGTERM, handleSignal);
+
+/*
+    // set patch preconditioner for linear correction in TNNMG method
+    using PatchSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
+    using Preconditioner = MultilevelPatchPreconditioner<ContactNetwork, PatchSolver, Matrix, Vector>;
+
+    const auto& preconditionerParset = parset.sub("solver.tnnmg.linear.preconditioner");
+
+    auto gsStep = Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::create(Dune::Solvers::BlockGS::LocalSolvers::direct(0.0));
+    PatchSolver patchSolver(gsStep,
+                               preconditionerParset.get<size_t>("maximumIterations"),
+                               preconditionerParset.get<double>("tolerance"),
+                               nullptr,
+                               preconditionerParset.get<Solver::VerbosityMode>("verbosity"),
+                               false); // absolute error
+
+    Dune::BitSetVector<1> activeLevels(contactNetwork.nLevels(), true);
+    Preconditioner preconditioner(contactNetwork, activeLevels, preconditionerParset.get<Preconditioner::Mode>("mode"));
+    preconditioner.setPatchSolver(patchSolver);
+    preconditioner.setPatchDepth(preconditionerParset.get<size_t>("patchDepth"));
+*/
+    // set adaptive time stepper
+    typename ContactNetwork::ExternalForces externalForces;
+    contactNetwork.externalForces(externalForces);
+
+    AdaptiveTimeStepper<NonlinearFactory, std::decay_t<decltype(contactNetwork)>, Updaters, std::decay_t<decltype(stateEnergyNorms)>>
+        adaptiveTimeStepper(parset, contactNetwork, totalDirichletNodes, globalFriction, frictionNodes, current,
+                            programState.relativeTime, programState.relativeTau,
+                            externalForces, stateEnergyNorms, mustRefine);
+
+    size_t timeSteps = parset.get<size_t>("timeSteps.timeSteps");
+
+    while (!adaptiveTimeStepper.reachedEnd()) {
+      programState.timeStep++;
+
+      //preconditioner.build();
+      iterationCount = adaptiveTimeStepper.advance();
+
+      programState.relativeTime = adaptiveTimeStepper.relativeTime_;
+      programState.relativeTau = adaptiveTimeStepper.relativeTau_;
+      current.rate_->extractDisplacement(programState.u);
+      current.rate_->extractVelocity(programState.v);
+      current.rate_->extractAcceleration(programState.a);
+      current.state_->extractAlpha(programState.alpha);
+      globalFriction.updateAlpha(programState.alpha);
+
+      /*print(programState.u, "current u:");
+      print(programState.v, "current v:");
+      print(programState.a, "current a:");
+      print(programState.alpha, "current alpha:");*/
+
+      contactNetwork.setDeformation(programState.u);
+
+      report();
+
+      if (programState.timeStep==timeSteps) {
+        std::cout << "limit of timeSteps reached!" << std::endl;
+        break; // TODO remove after debugging
+      }
+
+      if (terminationRequested) {
+        std::cerr << "Terminating prematurely" << std::endl;
+        break;
+      }
+
+
+    }
+
+
+    std::cout.rdbuf(coutbuf); //reset to standard output again
+
+  } catch (Dune::Exception &e) {
+    Dune::derr << "Dune reported error: " << e << std::endl;
+  } catch (std::exception &e) {
+    std::cerr << "Standard exception: " << e.what() << std::endl;
+  }
+}
diff --git a/src/foam/foam.cfg b/src/foam/foam.cfg
new file mode 100644
index 00000000..7c801610
--- /dev/null
+++ b/src/foam/foam.cfg
@@ -0,0 +1,107 @@
+# -*- mode:conf -*-
+gravity         = 9.81     # [m/s^2]
+
+[body0]
+length          = 0.4      # [m]
+height          = 0.04     # [m]
+depth           = 0.04     # [m]
+bulkModulus     = 2190     # [Pa]
+poissonRatio    = 0.11     # [1]
+[body0.elastic]
+density         = 750      # [kg/m^3]
+shearViscosity  = 0        # [Pas]
+bulkViscosity   = 0        # [Pas]
+[body0.viscoelastic]
+density         = 750      # [kg/m^3]
+shearViscosity  = 0        # [Pas]
+bulkViscosity   = 0        # [Pas]
+
+[body1]
+length          = 0.04     # [m]
+height          = 0.04     # [m]
+depth           = 0.04     # [m]
+bulkModulus     = 2190     # [Pa]
+poissonRatio    = 0.11     # [1]
+[body1.elastic]
+density         = 750      # [kg/m^3]
+shearViscosity  = 0        # [Pas]
+bulkViscosity   = 0        # [Pas]
+[body1.viscoelastic]
+density         = 750      # [kg/m^3]
+shearViscosity  = 0        # [Pas]
+bulkViscosity   = 0        # [Pas]
+
+[boundary.friction]
+C               = 10       # [Pa]
+mu0             = 0.7      # [ ]
+V0              = 5e-5     # [m/s]
+L               = 2.25e-5  # [m]
+initialAlpha    = 0        # [ ]
+stateModel      = AgeingLaw
+frictionModel   = Truncated #Regularised
+[boundary.friction.weakening]
+a               = 0.025    # [ ]
+b               = 0.005    # [ ]
+[boundary.friction.strengthening]
+a               = 0.025    # [ ]
+b               = 0.005    # [ ]
+
+[boundary.neumann]
+sigmaN          = 0.0      # [Pa]
+
+[io]
+data.write      = false
+printProgress   = true
+restarts.first  = 0
+restarts.spacing= 20
+restarts.write  = false #true
+vtk.write       = true
+
+[problem]
+finalTime       = 1000     # [s] #1000
+bodyCount       = 2
+
+[initialTime]
+timeStep = 0
+relativeTime = 0.0
+relativeTau = 5e-4 # 1e-6
+
+[timeSteps]
+scheme = newmark
+timeSteps = 100000
+
+[u0.solver]
+maximumIterations = 100
+verbosity         = full
+
+[a0.solver]
+maximumIterations = 100
+verbosity         = full
+
+[v.solver]
+maximumIterations = 100
+verbosity         = quiet
+
+[v.fpi]
+maximumIterations = 10000
+lambda            = 0.5
+
+[solver.tnnmg.preconditioner]
+mode         = additive
+patchDepth   = 1
+maximumIterations = 2
+verbosity         = quiet
+[solver.tnnmg.preconditioner.patchsolver]
+maximumIterations = 100
+verbosity         = quiet
+[solver.tnnmg.preconditioner.basesolver]
+maximumIterations = 10000
+verbosity         = quiet
+
+[solver.tnnmg.main]
+pre   = 1
+multi = 5 # number of multigrid steps
+post  = 0
+
+
+
diff --git a/src/multi-body-problem-data/geometry.tex b/src/multi-body-problem-data/geometry.tex
deleted file mode 100644
index 32d63b6e..00000000
--- a/src/multi-body-problem-data/geometry.tex
+++ /dev/null
@@ -1,68 +0,0 @@
-\documentclass[tikz]{minimal}
-
-\usepackage{tikz}
-\usetikzlibrary{calc}
-\usetikzlibrary{decorations.pathreplacing}
-
-\usepackage{siunitx}
-
-\begin{document}
-\pgfmathsetmacro{\rightleg}{0.27}
-\pgfmathsetmacro{\leftleg}{1.00}
-\pgfmathsetmacro{\leftangle}{atan(\rightleg/\leftleg)}
-\begin{tikzpicture}[scale=12, rotate=\leftangle]
-  \pgfmathsetmacro{\mysin}{sin(\leftangle)}
-  \pgfmathsetmacro{\mycos}{cos(\leftangle)}
-  \pgfmathsetmacro{\viscoheight}{0.06}
-  \pgfmathsetmacro{\Zx}{0.35}
-  \pgfmathsetmacro{\weaklen}{0.20}
-
-  \coordinate (A) at (0,0);
-  \node at (A) [left] {A};
-  \coordinate (B) at (\leftleg,-\rightleg);
-  \node at (B) [right] {B};
-  \coordinate (C) at (\leftleg,0);
-  \node at (C) [right] {C};
-
-  \draw (A) -- (B) -- (C) -- node [above=.5cm, sloped] {$\overline{AC}=\SI{100}{cm}$} (A);
-
-  \coordinate (Z) at (\Zx,0);
-  \node at (Z) [above] {Z};
-  \coordinate (Y) at ($(\Zx,-\Zx/\leftleg * \rightleg)$);
-  \node at (Y) [below] {Y};
-  \coordinate (X) at ($(Y) + (-\weaklen*\mycos,\weaklen*\mysin)$);
-  \node at (X) [below] {X};
-  \path let \p1 = (X) in coordinate (U) at ($(\x1, 0)$);
-  \node at (U) [above] {U};
-
-  \path (A) -- node [above=.25cm, sloped] {$\overline{AZ} = \SI{35}{cm}$} (Z);
-
-  \draw[color=red, thick] (X) -- node [below=.25cm] {$\overline{XY}=\SI{20}{cm}$} (Y);
-  \draw[dashed] (Y) -- (Z);
-  \draw[dashed] (U) -- (X);
-
-  \coordinate (K) at ($(B) + (-\leftleg * \viscoheight / \rightleg,\viscoheight)$);
-  \node at (K) [below] {K};
-  \coordinate (M) at ($(B) + (0, \viscoheight)$);
-  \node at (M) [right] {M};
-  \path (C) -- node [right=.5cm] {$\overline{CM} = \SI{21}{cm}$} (M);
-
-  \path[fill=blue] (K) -- (B) -- node [right=.75cm] {$\overline{BM}=\SI{6}{cm}$} (M) -- cycle;
-
-  \coordinate (G) at ($(A) ! 0.5 ! (X)$);
-  \node at (G) [below] {G};
-  \coordinate (H) at ($(X) ! 0.5 ! (Y)$);
-  \node at (H) [below] {H};
-  \coordinate (J) at ($(Y) ! 0.5 ! (B)$);
-  \node at (J) [below] {J};
-
-  \coordinate (I) at ($(Y) + (G)$);
-  \node at (I) [below] {I};
-
-  \node[align=left] at (0.5,-0.225) {
-    $Z$: coast line\\
-    $\overline{XY}$: velocity weakening zone\\
-    $BKM$: visco-elastic domain};
-\end{tikzpicture}
-
-\end{document}
diff --git a/src/multi-body-problem/CMakeLists.txt b/src/multi-body-problem/CMakeLists.txt
new file mode 100644
index 00000000..15a48074
--- /dev/null
+++ b/src/multi-body-problem/CMakeLists.txt
@@ -0,0 +1,46 @@
+add_custom_target(tectonic_src_multi-body-problem SOURCES
+  multi-body-problem.cfg
+  multi-body-problem-2D.cfg
+  multi-body-problem-3D.cfg
+) 
+
+set(MSW_SOURCE_FILES
+  ../../dune/tectonic/assemblers.cc
+  ../../dune/tectonic/data-structures/body/body.cc
+  ../../dune/tectonic/data-structures/network/levelcontactnetwork.cc
+  ../../dune/tectonic/data-structures/network/contactnetwork.cc
+  ../../dune/tectonic/data-structures/enumparser.cc
+  #../../dune/tectonic/factories/cantorfactory.cc
+  ../../dune/tectonic/factories/threeblocksfactory.cc
+  ../../dune/tectonic/factories/stackedblocksfactory.cc
+  ../../dune/tectonic/io/vtk.cc
+  ../../dune/tectonic/io/hdf5/frictionalboundary-writer.cc
+  ../../dune/tectonic/io/hdf5/iteration-writer.cc
+  #../../dune/tectonic/io/hdf5/patchinfo-writer.cc
+  ../../dune/tectonic/io/hdf5/restart-io.cc
+  ../../dune/tectonic/io/hdf5/surface-writer.cc
+  ../../dune/tectonic/io/hdf5/time-writer.cc
+  ../../dune/tectonic/problem-data/grid/cuboidgeometry.cc
+  ../../dune/tectonic/problem-data/grid/mygrids.cc
+  ../../dune/tectonic/problem-data/grid/simplexmanager.cc
+  ../../dune/tectonic/spatial-solving/solverfactory.cc
+  ../../dune/tectonic/spatial-solving/fixedpointiterator.cc
+  ../../dune/tectonic/time-stepping/coupledtimestepper.cc
+  ../../dune/tectonic/time-stepping/adaptivetimestepper.cc
+  ../../dune/tectonic/time-stepping/rate.cc
+  ../../dune/tectonic/time-stepping/rate/rateupdater.cc
+  ../../dune/tectonic/time-stepping/state.cc
+  multi-body-problem.cc
+)
+
+foreach(_dim 2 3)
+  set(_msw_target multi-body-problem-${_dim}D)
+
+  add_executable(${_msw_target} ${MSW_SOURCE_FILES})
+  
+  add_dune_ug_flags(${_msw_target})
+  add_dune_hdf5_flags(${_msw_target})
+
+  set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
+  #set_property(TARGET ${_msw_target} APPEND PROPERTY COMPILE_DEFINITIONS "NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY=1")
+endforeach()
diff --git a/src/multi-body-problem-2D.cfg b/src/multi-body-problem/multi-body-problem-2D.cfg
similarity index 64%
rename from src/multi-body-problem-2D.cfg
rename to src/multi-body-problem/multi-body-problem-2D.cfg
index 4f122195..641078a7 100644
--- a/src/multi-body-problem-2D.cfg
+++ b/src/multi-body-problem/multi-body-problem-2D.cfg
@@ -1,6 +1,6 @@
 # -*- mode:conf -*-
 [boundary.friction]
-smallestDiameter = 0.5  # 2e-3 [m]
+smallestDiameter = 0.05  # 2e-3 [m]
 
 [timeSteps]
 refinementTolerance = 1e-5 # 1e-5
@@ -17,8 +17,8 @@ tolerance         = 1e-8
 [v.fpi]
 tolerance         = 1e-5
 
-[solver.tnnmg.linear]
-tolerance          = 1e-8 #1e-10
+[solver.tnnmg.preconditioner.basesolver]
+tolerance          = 1e-10
 
-[solver.tnnmg.linear.preconditioner]
+[solver.tnnmg.preconditioner.patchsolver]
 tolerance          = 1e-10
diff --git a/src/multi-body-problem-3D.cfg b/src/multi-body-problem/multi-body-problem-3D.cfg
similarity index 100%
rename from src/multi-body-problem-3D.cfg
rename to src/multi-body-problem/multi-body-problem-3D.cfg
diff --git a/src/multi-body-problem.cc b/src/multi-body-problem/multi-body-problem.cc
similarity index 81%
rename from src/multi-body-problem.cc
rename to src/multi-body-problem/multi-body-problem.cc
index 4582a652..715acca3 100644
--- a/src/multi-body-problem.cc
+++ b/src/multi-body-problem/multi-body-problem.cc
@@ -29,6 +29,7 @@
 #include <dune/istl/bvector.hh>
 
 #include <dune/fufem/boundarypatch.hh>
+#include <dune/fufem/geometry/convexpolyhedron.hh>
 #include <dune/fufem/formatstring.hh>
 #include <dune/fufem/hdf5/file.hh>
 
@@ -40,44 +41,43 @@
 #include <dune/contact/common/couplingpair.hh>
 #include <dune/contact/projections/normalprojection.hh>
 
-#include <dune/tectonic/geocoordinate.hh>
-#include <dune/tectonic/globalfriction.hh>
 
-#include "assemblers.hh"
-#include "gridselector.hh"
-#include "explicitgrid.hh"
-#include "explicitvectors.hh"
+#include <dune/tectonic/assemblers.hh>
+#include <dune/tectonic/gridselector.hh>
+#include <dune/tectonic/explicitgrid.hh>
+#include <dune/tectonic/explicitvectors.hh>
 
-#include "data-structures/enumparser.hh"
-#include "data-structures/enums.hh"
-#include "data-structures/contactnetwork.hh"
-#include "data-structures/matrices.hh"
-#include "data-structures/program_state.hh"
+#include <dune/tectonic/data-structures/enumparser.hh>
+#include <dune/tectonic/data-structures/enums.hh>
+#include <dune/tectonic/data-structures/network/contactnetwork.hh>
+#include <dune/tectonic/data-structures/matrices.hh>
+#include <dune/tectonic/data-structures/program_state.hh>
+#include <dune/tectonic/data-structures/friction/globalfriction.hh>
 
-#include "factories/stackedblocksfactory.hh"
-#include "factories/threeblocksfactory.hh"
+#include <dune/tectonic/factories/stackedblocksfactory.hh>
+#include <dune/tectonic/factories/threeblocksfactory.hh>
 
-//#include "io/hdf5-levelwriter.hh"
-#include "io/hdf5/restart-io.hh"
-#include "io/vtk.hh"
+#include <dune/tectonic/io/hdf5-levelwriter.hh>
+#include <dune/tectonic/io/hdf5/restart-io.hh>
+#include <dune/tectonic/io/vtk.hh>
 
-#include "multi-body-problem-data/bc.hh"
-#include "multi-body-problem-data/mybody.hh"
-#include "multi-body-problem-data/grid/mygrids.hh"
+#include <dune/tectonic/problem-data/bc.hh>
+#include <dune/tectonic/problem-data/mybody.hh>
+#include <dune/tectonic/problem-data/grid/mygrids.hh>
 
-#include "spatial-solving/tnnmg/functional.hh"
-//#include "spatial-solving/preconditioners/multilevelpatchpreconditioner.hh"
-#include "spatial-solving/tnnmg/localbisectionsolver.hh"
-#include "spatial-solving/contact/nbodyassembler.hh"
-#include "spatial-solving/solverfactory.hh"
+#include <dune/tectonic/spatial-solving/tnnmg/functional.hh>
+//#include <dune/tectonic/spatial-solving/preconditioners/multilevelpatchpreconditioner.hh>
+#include <dune/tectonic/spatial-solving/tnnmg/localbisectionsolver.hh>
+#include <dune/tectonic/spatial-solving/solverfactory.hh>
 
-#include "time-stepping/adaptivetimestepper.hh"
-#include "time-stepping/rate.hh"
-#include "time-stepping/state.hh"
-#include "time-stepping/updaters.hh"
+#include <dune/tectonic/time-stepping/adaptivetimestepper.hh>
+#include <dune/tectonic/time-stepping/rate.hh>
+#include <dune/tectonic/time-stepping/state.hh>
+#include <dune/tectonic/time-stepping/updaters.hh>
 
-#include "utils/debugutils.hh"
-#include "utils/diameter.hh"
+#include <dune/tectonic/utils/debugutils.hh>
+#include <dune/tectonic/utils/diameter.hh>
+#include <dune/tectonic/utils/geocoordinate.hh>
 
 // for getcwd
 #include <unistd.h>
@@ -89,9 +89,9 @@ size_t const dims = MY_DIM;
 
 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("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem/multi-body-problem.cfg", parset);
   Dune::ParameterTreeParser::readINITree(
-      Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem-%dD.cfg", dims), parset);
+      Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem/multi-body-problem-%dD.cfg", dims), parset);
   Dune::ParameterTreeParser::readOptions(argc, argv, parset);
   return parset;
 }
@@ -146,12 +146,12 @@ int main(int argc, char *argv[]) {
         const auto& level = *contactNetwork.level(i);
 
         for (size_t j=0; j<level.nBodies(); j++) {
-            writeToVTK(level.body(j)->gridView(), "debug_print/bodies/", "body_" + std::to_string(j) + "_level_" + std::to_string(i));
+            writeToVTK(level.body(j)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(j) + "_level_" + std::to_string(i));
         }
     }
 
     for (size_t i=0; i<bodyCount; i++) {
-        writeToVTK(contactNetwork.body(i)->gridView(), "debug_print/bodies/", "body_" + std::to_string(i) + "_leaf");
+        writeToVTK(contactNetwork.body(i)->gridView(), "../debug_print/bodies/", "body_" + std::to_string(i) + "_leaf");
     }
 
     // ----------------------------
@@ -223,11 +223,18 @@ int main(int argc, char *argv[]) {
     std::vector<const MyVertexBasis* > vertexBases(bodyCount);
     std::vector<const MyCellBasis* > cellBases(bodyCount);
 
+    auto& wPatches = stackedBlocksFactory.weakPatches();
+    std::vector<std::vector<const ConvexPolyhedron<LocalVector>*>> weakPatches(bodyCount);
+
+
     for (size_t i=0; i<bodyCount; i++) {
       const auto& body = contactNetwork.body(i);
       vertexBases[i] = &(body->assembler()->vertexBasis);
       cellBases[i] = &(body->assembler()->cellBasis);
 
+      weakPatches[i].resize(1);
+      weakPatches[i][0] = wPatches[i].get();
+
       auto& vertexCoords = vertexCoordinates[i];
       vertexCoords.resize(nVertices[i]);
 
@@ -237,24 +244,23 @@ int main(int argc, char *argv[]) {
         vertexCoords[vertexMapper.index(v)] = geoToPoint(v.geometry());
     }
 
-    //typename contactNetwork::BoundaryPatches frictionBoundaries;
-    //contactNetwork.boundaryPatches("friction", frictionBoundaries);
+    typename ContactNetwork::BoundaryPatches frictionBoundaries;
+    contactNetwork.boundaryPatches("friction", frictionBoundaries);
 
-    /*
     auto dataWriter =
         writeData ? std::make_unique<
-                        HDF5Writer<MyProgramState, MyVertexBasis, DefLeafGridView>>(
+                        HDF5LevelWriter<MyProgramState, MyVertexBasis, DefLeafGridView>>(
                         *dataFile, vertexCoordinates, vertexBases,
-                        frictionBoundaries) //, weakPatches)
-                  : nullptr;*/
+                        frictionBoundaries, weakPatches)
+                  : nullptr;
 
     const MyVTKWriter<MyVertexBasis, MyCellBasis> vtkWriter(cellBases, vertexBases, "/storage/mi/podlesny/software/dune/dune-tectonic/body");
 
     IterationRegister iterationCount;
 
     auto const report = [&](bool initial = false) {
-      /*if (writeData) {
-        dataWriter->reportSolution(programState, contactNetwork.globalFriction());
+      if (writeData) {
+        dataWriter->reportSolution(programState, globalFriction);
         if (!initial)
           dataWriter->reportIterations(programState, iterationCount);
         dataFile->flush();
@@ -264,7 +270,7 @@ int main(int argc, char *argv[]) {
           programState.timeStep % restartSpacing == 0) {
         restartIO->write(programState);
         restartFile->flush();
-      }*/
+      }
 
       if (parset.get<bool>("io.printProgress"))
         std::cout << "timeStep = " << std::setw(6) << programState.timeStep
@@ -308,7 +314,7 @@ int main(int argc, char *argv[]) {
         }
     }*/
 
-    print(totalDirichletNodes, "totalDirichletNodes:");
+    //print(totalDirichletNodes, "totalDirichletNodes:");
 
     //using Functional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, field_type>;
     using Functional = Functional<Matrix&, Vector&, GlobalFriction<Matrix, Vector>&, Vector&, Vector&, field_type>;
@@ -334,9 +340,9 @@ int main(int argc, char *argv[]) {
     std::vector<const Dune::BitSetVector<1>*> frictionNodes;
     contactNetwork.frictionNodes(frictionNodes);
 
-    for (size_t i=0; i<frictionNodes.size(); i++) {
+    /*for (size_t i=0; i<frictionNodes.size(); i++) {
         print(*frictionNodes[i], "frictionNodes_body_" + std::to_string(i));
-    }
+    }*/
 
     Updaters current(
         initRateUpdater(
@@ -363,27 +369,27 @@ int main(int argc, char *argv[]) {
                                 Updaters &fineUpdater) {
 
         //return false;
-      std::cout << "Step 1" << std::endl;
+      //std::cout << "Step 1" << std::endl;
 
       std::vector<ScalarVector> coarseAlpha;
       coarseAlpha.resize(bodyCount);
       coarseUpdater.state_->extractAlpha(coarseAlpha);
 
-      print(coarseAlpha, "coarseAlpha:");
+      //print(coarseAlpha, "coarseAlpha:");
 
       std::vector<ScalarVector> fineAlpha;
       fineAlpha.resize(bodyCount);
       fineUpdater.state_->extractAlpha(fineAlpha);
 
-      print(fineAlpha, "fineAlpha:");
+      //print(fineAlpha, "fineAlpha:");
 
-      std::cout << "Step 3" << std::endl;
+      //std::cout << "Step 3" << std::endl;
 
       ScalarVector::field_type energyNorm = 0;
       for (size_t i=0; i<stateEnergyNorms.size(); i++) {
-          std::cout << "for " << i << std::endl;
+          //std::cout << "for " << i << std::endl;
 
-          std::cout << not stateEnergyNorms[i] << std::endl;
+          //std::cout << not stateEnergyNorms[i] << std::endl;
 
           if (coarseAlpha[i].size()==0 || fineAlpha[i].size()==0)
               continue;
@@ -429,6 +435,8 @@ int main(int argc, char *argv[]) {
                             programState.relativeTime, programState.relativeTau,
                             externalForces, stateEnergyNorms, mustRefine);
 
+    size_t timeSteps = parset.get<size_t>("timeSteps.timeSteps");
+
     while (!adaptiveTimeStepper.reachedEnd()) {
       programState.timeStep++;
 
@@ -441,17 +449,18 @@ int main(int argc, char *argv[]) {
       current.rate_->extractVelocity(programState.v);
       current.rate_->extractAcceleration(programState.a);
       current.state_->extractAlpha(programState.alpha);
+      globalFriction.updateAlpha(programState.alpha);
 
-      print(programState.u, "current u:");
+      /*print(programState.u, "current u:");
       print(programState.v, "current v:");
       print(programState.a, "current a:");
-      print(programState.alpha, "current alpha:");
+      print(programState.alpha, "current alpha:");*/
 
       contactNetwork.setDeformation(programState.u);
 
       report();
 
-      if (programState.timeStep==50) {
+      if (programState.timeStep==timeSteps) {
         std::cout << "limit of timeSteps reached!" << std::endl;
         break; // TODO remove after debugging
       }
@@ -460,6 +469,8 @@ int main(int argc, char *argv[]) {
         std::cerr << "Terminating prematurely" << std::endl;
         break;
       }
+
+
     }
 
 
diff --git a/src/multi-body-problem.cfg b/src/multi-body-problem/multi-body-problem.cfg
similarity index 80%
rename from src/multi-body-problem.cfg
rename to src/multi-body-problem/multi-body-problem.cfg
index eaade420..4be02c1c 100644
--- a/src/multi-body-problem.cfg
+++ b/src/multi-body-problem/multi-body-problem.cfg
@@ -2,7 +2,7 @@
 gravity         = 9.81  # [m/s^2]
 
 [io]
-data.write      = false #true
+data.write      = false
 printProgress   = true
 restarts.first  = 0
 restarts.spacing= 20
@@ -10,7 +10,7 @@ restarts.write  = false #true
 vtk.write       = true
 
 [problem]
-finalTime       = 100  # [s] #1000
+finalTime       = 10000  # [s] #1000
 bodyCount       = 2
 
 [body]
@@ -43,11 +43,11 @@ b               = 0.005 # [ ]
 [initialTime]
 timeStep = 0
 relativeTime = 0.0
-relativeTau = 1e-4 # 1e-6
+relativeTau = 5e-4 # 1e-6
 
 [timeSteps]
 scheme = newmark
-timeSteps = 1
+timeSteps = 100000
 
 [u0.solver]
 maximumIterations = 100
@@ -59,20 +59,21 @@ verbosity         = full
 
 [v.solver]
 maximumIterations = 100
-verbosity         = full
+verbosity         = quiet
 
 [v.fpi]
 maximumIterations = 10000
 lambda            = 0.5
 
-[solver.tnnmg.linear]
-maximumIterations = 100
-pre                = 3
-cycle              = 1  # 1 = V, 2 = W, etc.
-post               = 3
-[solver.tnnmg.linear.preconditioner]
+[solver.tnnmg.preconditioner]
 mode         = additive
-patchDepth   = 0
+patchDepth   = 1
+maximumIterations = 2
+verbosity         = quiet
+[solver.tnnmg.preconditioner.patchsolver]
+maximumIterations = 100
+verbosity         = quiet
+[solver.tnnmg.preconditioner.basesolver]
 maximumIterations = 10000
 verbosity         = quiet
 
diff --git a/src/one-body-problem-3D.cfg b/src/one-body-problem-3D.cfg
deleted file mode 100644
index 3ff0794d..00000000
--- a/src/one-body-problem-3D.cfg
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- mode:conf -*-
-[boundary.friction]
-smallestDiameter= 2e-2  # [m]
-
-[boundary.friction.weakening]
-patchType       = Trapezoidal
-
-[timeSteps]
-refinementTolerance = 1e-5
-
-[u0.solver]
-tolerance         = 1e-6
-
-[a0.solver]
-tolerance         = 1e-6
-
-[v.solver]
-tolerance         = 1e-6
-
-[v.fpi]
-tolerance         = 1e-5
-
-[solver.tnnmg.linear]
-tolerance          = 1e-10
diff --git a/src/one-body-problem-data/bc.hh b/src/one-body-problem-data/bc.hh
deleted file mode 100644
index 7c29cf08..00000000
--- a/src/one-body-problem-data/bc.hh
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef SRC_ONE_BODY_PROBLEM_DATA_BC_HH
-#define SRC_ONE_BODY_PROBLEM_DATA_BC_HH
-
-class VelocityDirichletCondition
-    : public Dune::VirtualFunction<double, double> {
-  void evaluate(double const &relativeTime, double &y) const {
-    // Assumed to vanish at time zero
-    double const finalVelocity = -5e-5;
-    y = (relativeTime <= 0.1)
-            ? finalVelocity * (1.0 - std::cos(relativeTime * M_PI / 0.1)) / 2.0
-            : finalVelocity;
-  }
-};
-
-class NeumannCondition : public Dune::VirtualFunction<double, double> {
-  void evaluate(double const &relativeTime, double &y) const { y = 0.0; }
-};
-#endif
diff --git a/src/one-body-problem-data/geometry.tex b/src/one-body-problem-data/geometry.tex
deleted file mode 100644
index 32d63b6e..00000000
--- a/src/one-body-problem-data/geometry.tex
+++ /dev/null
@@ -1,68 +0,0 @@
-\documentclass[tikz]{minimal}
-
-\usepackage{tikz}
-\usetikzlibrary{calc}
-\usetikzlibrary{decorations.pathreplacing}
-
-\usepackage{siunitx}
-
-\begin{document}
-\pgfmathsetmacro{\rightleg}{0.27}
-\pgfmathsetmacro{\leftleg}{1.00}
-\pgfmathsetmacro{\leftangle}{atan(\rightleg/\leftleg)}
-\begin{tikzpicture}[scale=12, rotate=\leftangle]
-  \pgfmathsetmacro{\mysin}{sin(\leftangle)}
-  \pgfmathsetmacro{\mycos}{cos(\leftangle)}
-  \pgfmathsetmacro{\viscoheight}{0.06}
-  \pgfmathsetmacro{\Zx}{0.35}
-  \pgfmathsetmacro{\weaklen}{0.20}
-
-  \coordinate (A) at (0,0);
-  \node at (A) [left] {A};
-  \coordinate (B) at (\leftleg,-\rightleg);
-  \node at (B) [right] {B};
-  \coordinate (C) at (\leftleg,0);
-  \node at (C) [right] {C};
-
-  \draw (A) -- (B) -- (C) -- node [above=.5cm, sloped] {$\overline{AC}=\SI{100}{cm}$} (A);
-
-  \coordinate (Z) at (\Zx,0);
-  \node at (Z) [above] {Z};
-  \coordinate (Y) at ($(\Zx,-\Zx/\leftleg * \rightleg)$);
-  \node at (Y) [below] {Y};
-  \coordinate (X) at ($(Y) + (-\weaklen*\mycos,\weaklen*\mysin)$);
-  \node at (X) [below] {X};
-  \path let \p1 = (X) in coordinate (U) at ($(\x1, 0)$);
-  \node at (U) [above] {U};
-
-  \path (A) -- node [above=.25cm, sloped] {$\overline{AZ} = \SI{35}{cm}$} (Z);
-
-  \draw[color=red, thick] (X) -- node [below=.25cm] {$\overline{XY}=\SI{20}{cm}$} (Y);
-  \draw[dashed] (Y) -- (Z);
-  \draw[dashed] (U) -- (X);
-
-  \coordinate (K) at ($(B) + (-\leftleg * \viscoheight / \rightleg,\viscoheight)$);
-  \node at (K) [below] {K};
-  \coordinate (M) at ($(B) + (0, \viscoheight)$);
-  \node at (M) [right] {M};
-  \path (C) -- node [right=.5cm] {$\overline{CM} = \SI{21}{cm}$} (M);
-
-  \path[fill=blue] (K) -- (B) -- node [right=.75cm] {$\overline{BM}=\SI{6}{cm}$} (M) -- cycle;
-
-  \coordinate (G) at ($(A) ! 0.5 ! (X)$);
-  \node at (G) [below] {G};
-  \coordinate (H) at ($(X) ! 0.5 ! (Y)$);
-  \node at (H) [below] {H};
-  \coordinate (J) at ($(Y) ! 0.5 ! (B)$);
-  \node at (J) [below] {J};
-
-  \coordinate (I) at ($(Y) + (G)$);
-  \node at (I) [below] {I};
-
-  \node[align=left] at (0.5,-0.225) {
-    $Z$: coast line\\
-    $\overline{XY}$: velocity weakening zone\\
-    $BKM$: visco-elastic domain};
-\end{tikzpicture}
-
-\end{document}
diff --git a/src/one-body-problem-data/midpoint.hh b/src/one-body-problem-data/midpoint.hh
deleted file mode 100644
index 407b55f9..00000000
--- a/src/one-body-problem-data/midpoint.hh
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef SRC_MIDPOINT_HH
-#define SRC_MIDPOINT_HH
-
-#include <dune/solvers/common/arithmetic.hh>
-
-template <class Vector> Vector midPoint(Vector const &x, Vector const &y) {
-  Vector ret(0);
-  Arithmetic::addProduct(ret, 0.5, x);
-  Arithmetic::addProduct(ret, 0.5, y);
-  return ret;
-}
-#endif
diff --git a/src/one-body-problem-data/mybody.hh b/src/one-body-problem-data/mybody.hh
deleted file mode 100644
index 6e98d289..00000000
--- a/src/one-body-problem-data/mybody.hh
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef SRC_ONE_BODY_PROBLEM_DATA_MYBODY_HH
-#define SRC_ONE_BODY_PROBLEM_DATA_MYBODY_HH
-
-#include <dune/common/fvector.hh>
-
-#include <dune/fufem/functions/constantfunction.hh>
-
-#include <dune/tectonic/body.hh>
-#include <dune/tectonic/gravity.hh>
-
-#include "mygeometry.hh"
-#include "segmented-function.hh"
-
-template <int dimension> class MyBody : public Body<dimension> {
-  using typename Body<dimension>::ScalarFunction;
-  using typename Body<dimension>::VectorField;
-
-public:
-  MyBody(Dune::ParameterTree const &parset)
-      : poissonRatio_(parset.get<double>("body.poissonRatio")),
-        youngModulus_(3.0 * parset.get<double>("body.bulkModulus") *
-                      (1.0 - 2.0 * poissonRatio_)),
-        shearViscosityField_(
-            parset.get<double>("body.elastic.shearViscosity"),
-            parset.get<double>("body.viscoelastic.shearViscosity")),
-        bulkViscosityField_(
-            parset.get<double>("body.elastic.bulkViscosity"),
-            parset.get<double>("body.viscoelastic.bulkViscosity")),
-        densityField_(parset.get<double>("body.elastic.density"),
-                      parset.get<double>("body.viscoelastic.density")),
-        gravityField_(densityField_, MyGeometry::zenith,
-                      parset.get<double>("gravity")) {}
-
-  double getPoissonRatio() const override { return poissonRatio_; }
-  double getYoungModulus() const override { return youngModulus_; }
-  ScalarFunction const &getShearViscosityField() const override {
-    return shearViscosityField_;
-  }
-  ScalarFunction const &getBulkViscosityField() const override {
-    return bulkViscosityField_;
-  }
-  ScalarFunction const &getDensityField() const override {
-    return densityField_;
-  }
-  VectorField const &getGravityField() const override { return gravityField_; }
-
-private:
-  double const poissonRatio_;
-  double const youngModulus_;
-  SegmentedFunction const shearViscosityField_;
-  SegmentedFunction const bulkViscosityField_;
-  SegmentedFunction const densityField_;
-  Gravity<dimension> const gravityField_;
-};
-#endif
diff --git a/src/one-body-problem-data/mygeometry.cc b/src/one-body-problem-data/mygeometry.cc
deleted file mode 100644
index fef8452a..00000000
--- a/src/one-body-problem-data/mygeometry.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <fstream>
-
-#ifdef HAVE_CAIROMM
-#include <cairomm/context.h>
-#include <cairomm/fontface.h>
-#include <cairomm/surface.h>
-#endif
-
-#include "mygeometry.hh"
-
-void MyGeometry::write() {
-  std::fstream writer("geometry", std::fstream::out);
-  writer << "A = " << A << std::endl;
-  writer << "B = " << B << std::endl;
-  writer << "C = " << C << std::endl;
-  writer << "Y = " << Y << std::endl;
-  writer << "X = " << X << std::endl;
-  writer << "Z = " << Z << std::endl;
-  writer << "U = " << U << std::endl;
-  writer << "K = " << K << std::endl;
-  writer << "M = " << M << std::endl;
-  writer << "G = " << G << std::endl;
-  writer << "H = " << H << std::endl;
-  writer << "J = " << J << std::endl;
-  writer << "I = " << I << std::endl;
-  writer << "zenith = " << zenith << std::endl;
-}
-
-void MyGeometry::render() {
-#ifdef HAVE_CAIROMM
-  std::string const filename = "geometry.png";
-  double const width = 600;
-  double const height = 400;
-  double const widthScale = 400;
-  double const heightScale = 400;
-
-  auto surface =
-      Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
-  auto cr = Cairo::Context::create(surface);
-
-  auto const setRGBColor = [&](int colour) {
-    cr->set_source_rgb(((colour & 0xFF0000) >> 16) / 255.0,
-                       ((colour & 0x00FF00) >> 8) / 255.0,
-                       ((colour & 0x0000FF) >> 0) / 255.0);
-  };
-  auto const moveTo = [&](LocalVector2D const &v) { cr->move_to(v[0], -v[1]); };
-  auto const lineTo = [&](LocalVector2D const &v) { cr->line_to(v[0], -v[1]); };
-
-  cr->scale(widthScale, heightScale);
-  cr->translate(0.1, 0.1);
-  cr->set_line_width(0.0025);
-
-  // triangle
-  {
-    moveTo(reference::A);
-    lineTo(reference::B);
-    lineTo(reference::C);
-    cr->close_path();
-    cr->stroke();
-  }
-
-  // dashed lines
-  {
-    cr->save();
-    std::vector<double> dashPattern = { 0.005 };
-    cr->set_dash(dashPattern, 0);
-    moveTo(reference::Z);
-    lineTo(reference::Y);
-    moveTo(reference::U);
-    lineTo(reference::X);
-    cr->stroke();
-    cr->restore();
-  }
-
-  // fill viscoelastic region
-  {
-    cr->save();
-    setRGBColor(0x0097E0);
-    moveTo(reference::B);
-    lineTo(reference::K);
-    lineTo(reference::M);
-    cr->fill();
-    cr->restore();
-  }
-
-  // mark weakening region
-  {
-    cr->save();
-    setRGBColor(0x7AD3FF);
-    cr->set_line_width(0.005);
-    moveTo(reference::X);
-    lineTo(reference::Y);
-    cr->stroke();
-    cr->restore();
-  }
-
-  // mark points
-  {
-    auto const drawCircle = [&](LocalVector2D const &v) {
-      cr->arc(v[0], -v[1], 0.0075, -M_PI, M_PI); // x,y,radius,angle1,angle2
-      cr->fill();
-    };
-
-    cr->save();
-    setRGBColor(0x002F47);
-    drawCircle(reference::A);
-    drawCircle(reference::B);
-    drawCircle(reference::C);
-    drawCircle(reference::Y);
-    drawCircle(reference::X);
-    drawCircle(reference::Z);
-    drawCircle(reference::U);
-    drawCircle(reference::K);
-    drawCircle(reference::M);
-    drawCircle(reference::G);
-    drawCircle(reference::H);
-    drawCircle(reference::J);
-    drawCircle(reference::I);
-    cr->restore();
-  }
-
-  // labels
-  {
-    auto const label = [&](LocalVector2D const &v, std::string l) {
-      moveTo(v);
-      cr->rel_move_to(0.005, -0.02);
-      cr->show_text(l);
-    };
-    auto font = Cairo::ToyFontFace::create(
-        "monospace", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL);
-
-    cr->save();
-    cr->set_font_face(font);
-    cr->set_font_size(0.03);
-
-    label(reference::A, "A");
-    label(reference::B, "B");
-    label(reference::C, "C");
-    label(reference::K, "K");
-    label(reference::M, "M");
-    label(reference::U, "U");
-    label(reference::X, "X");
-    label(reference::Y, "Y");
-    label(reference::Z, "Z");
-    label(reference::G, "G");
-    label(reference::H, "H");
-    label(reference::J, "J");
-    label(reference::I, "I");
-    cr->restore();
-  }
-
-  surface->write_to_png(filename);
-#endif
-}
diff --git a/src/one-body-problem-data/mygeometry.hh b/src/one-body-problem-data/mygeometry.hh
deleted file mode 100644
index dbfa722a..00000000
--- a/src/one-body-problem-data/mygeometry.hh
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef SRC_MYGEOMETRY_HH
-#define SRC_MYGEOMETRY_HH
-
-#include <dune/common/fvector.hh>
-
-#include "midpoint.hh"
-
-namespace MyGeometry {
-namespace {
-  using LocalVector2D = Dune::FieldVector<double, 2>;
-  using LocalMatrix2D = Dune::FieldMatrix<double, 2, 2>;
-
-  using LocalVector = Dune::FieldVector<double, MY_DIM>;
-}
-
-namespace reference {
-  double const s = 1.0; // scaling factor
-
-  double const rightLeg = 0.27 * s;
-  double const leftLeg = 1.00 * s;
-  double const leftAngle = atan(rightLeg / leftLeg);
-  double const viscoHeight = 0.06 * s; // Height of the viscous bottom layer
-  double const weakLen = 0.20 * s;     // Length of the weak zone
-
-  double const zDistance = 0.35;
-
-  LocalVector2D const A = {0, 0};
-  LocalVector2D const B = {leftLeg, -rightLeg};
-  LocalVector2D const C = {leftLeg, 0};
-
-  LocalVector2D const Z = {zDistance * s, 0};
-  LocalVector2D const Y = {zDistance * s, -zDistance *s / leftLeg *rightLeg};
-  LocalVector2D const X = {Y[0] - weakLen * std::cos(leftAngle),
-                           Y[1] + weakLen *std::sin(leftAngle)};
-
-  LocalVector2D const U = {X[0], 0};
-
-  LocalVector2D const K = {B[0] - leftLeg * viscoHeight / rightLeg,
-                           B[1] + viscoHeight};
-  LocalVector2D const M = {B[0], B[1] + viscoHeight};
-
-  LocalVector2D const G = midPoint(A, X);
-  LocalVector2D const H = midPoint(X, Y);
-  LocalVector2D const J = midPoint(Y, B);
-
-  LocalVector2D const I = {Y[0] + G[0], Y[1] + G[1]};
-
-  LocalVector2D const zenith = {0, 1};
-
-  LocalMatrix2D const rotation = {{std::cos(leftAngle), -std::sin(leftAngle)},
-                                  {std::sin(leftAngle), std::cos(leftAngle)}};
-}
-
-namespace {
-  LocalVector rotate(LocalVector2D const &x) {
-    LocalVector2D ret2D;
-    reference::rotation.mv(x, ret2D);
-    LocalVector ret(0);
-    ret[0] = ret2D[0];
-    ret[1] = ret2D[1];
-    return ret;
-  }
-}
-
-double const lengthScale = reference::s;
-
-double const depth = 0.60 * lengthScale;
-
-LocalVector const A = rotate(reference::A);
-LocalVector const B = rotate(reference::B);
-LocalVector const C = rotate(reference::C);
-LocalVector const G = rotate(reference::G);
-LocalVector const H = rotate(reference::H);
-LocalVector const I = rotate(reference::I);
-LocalVector const J = rotate(reference::J);
-LocalVector const K = rotate(reference::K);
-LocalVector const M = rotate(reference::M);
-LocalVector const U = rotate(reference::U);
-LocalVector const X = rotate(reference::X);
-LocalVector const Y = rotate(reference::Y);
-LocalVector const Z = rotate(reference::Z);
-
-LocalVector const zenith = rotate(reference::zenith);
-
-void write();
-
-void render();
-}
-#endif
diff --git a/src/one-body-problem-data/myglobalfrictiondata.hh b/src/one-body-problem-data/myglobalfrictiondata.hh
deleted file mode 100644
index d92e7223..00000000
--- a/src/one-body-problem-data/myglobalfrictiondata.hh
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef SRC_ONE_BODY_PROBLEM_DATA_MYGLOBALFRICTIONDATA_HH
-#define SRC_ONE_BODY_PROBLEM_DATA_MYGLOBALFRICTIONDATA_HH
-
-#include <dune/common/function.hh>
-
-#include <dune/tectonic/globalfrictiondata.hh>
-
-#include "patchfunction.hh"
-
-template <class LocalVector>
-class MyGlobalFrictionData : public GlobalFrictionData<LocalVector::dimension> {
-private:
-  using typename GlobalFrictionData<LocalVector::dimension>::VirtualFunction;
-
-public:
-  MyGlobalFrictionData(Dune::ParameterTree const &parset,
-                       ConvexPolyhedron<LocalVector> const &segment)
-      : C_(parset.get<double>("C")),
-        L_(parset.get<double>("L")),
-        V0_(parset.get<double>("V0")),
-        a_(parset.get<double>("strengthening.a"),
-           parset.get<double>("weakening.a"), segment),
-        b_(parset.get<double>("strengthening.b"),
-           parset.get<double>("weakening.b"), segment),
-        mu0_(parset.get<double>("mu0")) {}
-
-  double const &C() const override { return C_; }
-  double const &L() const override { return L_; }
-  double const &V0() const override { return V0_; }
-  VirtualFunction const &a() const override { return a_; }
-  VirtualFunction const &b() const override { return b_; }
-  double const &mu0() const override { return mu0_; }
-
-private:
-  double const C_;
-  double const L_;
-  double const V0_;
-  PatchFunction const a_;
-  PatchFunction const b_;
-  double const mu0_;
-};
-#endif
diff --git a/src/one-body-problem-data/mygrid.cc b/src/one-body-problem-data/mygrid.cc
deleted file mode 100644
index 7188f73a..00000000
--- a/src/one-body-problem-data/mygrid.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <dune/fufem/geometry/polyhedrondistance.hh>
-
-#include "mygrid.hh"
-#include "midpoint.hh"
-#include "../utils/diameter.hh"
-
-#if MY_DIM == 3
-SimplexManager::SimplexManager(unsigned int shift) : shift_(shift) {}
-#endif
-
-// back-to-front, front-to-back, front-to-back
-void SimplexManager::addFromVerticesFBB(unsigned int U, unsigned int V,
-                                        unsigned int W) {
-#if MY_DIM == 3
-  unsigned int const U2 = U + shift_;
-  unsigned int const V2 = V + shift_;
-  unsigned int const W2 = W + shift_;
-
-  simplices_.push_back({ U, V, W, U2 });
-  simplices_.push_back({ V, V2, W2, U2 });
-  simplices_.push_back({ W, W2, U2, V });
-#else
-  simplices_.push_back({ U, V, W });
-#endif
-}
-
-// back-to-front, back-to-front, front-to-back
-void SimplexManager::addFromVerticesFFB(unsigned int U, unsigned int V,
-                                        unsigned int W) {
-#if MY_DIM == 3
-  unsigned int const U2 = U + shift_;
-  unsigned int const V2 = V + shift_;
-  unsigned int const W2 = W + shift_;
-
-  simplices_.push_back({ U, V, W, U2 });
-  simplices_.push_back({ V, V2, W, U2 });
-  simplices_.push_back({ V2, W, U2, W2 });
-#else
-  simplices_.push_back({ U, V, W });
-#endif
-}
-
-auto SimplexManager::getSimplices() -> SimplexList const & {
-  return simplices_;
-}
-
-template <class Grid> GridConstructor<Grid>::GridConstructor() {
-  auto const &A = MyGeometry::A;
-  auto const &B = MyGeometry::B;
-  auto const &C = MyGeometry::C;
-
-  unsigned int const vc = 3;
-
-#if MY_DIM == 3
-  Dune::FieldMatrix<double, 2 * vc, MY_DIM> vertices;
-#else
-  Dune::FieldMatrix<double, vc, MY_DIM> vertices;
-#endif
-  for (size_t i = 0; i < 2; ++i) {
-#if MY_DIM == 3
-    size_t numXYplanes = 2;
-#else
-    size_t numXYplanes = 1;
-#endif
-    size_t k = 0;
-    for (size_t j = 1; j <= numXYplanes; ++j) {
-      vertices[k++][i] = A[i];
-      vertices[k++][i] = B[i];
-      vertices[k++][i] = C[i];
-      assert(k == j * vc);
-    }
-  }
-
-#if MY_DIM == 3
-  for (size_t k = 0; k < vc; ++k) {
-    vertices[k][2] = -MyGeometry::depth / 2.0;
-    vertices[k + vc][2] = MyGeometry::depth / 2.0;
-  }
-#endif
-
-  for (size_t i = 0; i < vertices.N(); ++i)
-    gridFactory.insertVertex(vertices[i]);
-
-  Dune::GeometryType cell;
-#if MY_DIM == 3
-  cell.makeTetrahedron();
-#else
-  cell.makeTriangle();
-#endif
-
-#if MY_DIM == 3
-  SimplexManager sm(vc);
-#else
-  SimplexManager sm;
-#endif
-  sm.addFromVerticesFFB(1, 2, 0);
-  auto const &simplices = sm.getSimplices();
-
-  // sanity-check choices of simplices
-  for (size_t i = 0; i < simplices.size(); ++i) {
-    Dune::FieldMatrix<double, MY_DIM, MY_DIM> check;
-    for (size_t j = 0; j < MY_DIM; ++j)
-      check[j] = vertices[simplices[i][j + 1]] - vertices[simplices[i][j]];
-    assert(check.determinant() > 0);
-    gridFactory.insertElement(cell, simplices[i]);
-  }
-}
-
-template <class Grid> std::shared_ptr<Grid> GridConstructor<Grid>::getGrid() {
-  return std::shared_ptr<Grid>(gridFactory.createGrid());
-}
-
-template <class Grid>
-template <class GridView>
-MyFaces<GridView> GridConstructor<Grid>::constructFaces(
-    GridView const &gridView) {
-  return MyFaces<GridView>(gridView);
-}
-
-template <class GridView>
-template <class Vector>
-bool MyFaces<GridView>::xyCollinear(Vector const &a, Vector const &b,
-                                    Vector const &c) {
-  return isClose2((b[0] - a[0]) * (c[1] - a[1]), (b[1] - a[1]) * (c[0] - a[0]));
-}
-
-template <class GridView>
-template <class Vector>
-bool MyFaces<GridView>::xyBoxed(Vector const &v1, Vector const &v2,
-                                Vector const &x) {
-  auto const minmax0 = std::minmax(v1[0], v2[0]);
-  auto const minmax1 = std::minmax(v1[1], v2[1]);
-
-  if (minmax0.first - 1e-14 * MyGeometry::lengthScale > x[0] or
-      x[0] > minmax0.second + 1e-14 * MyGeometry::lengthScale)
-    return false;
-  if (minmax1.first - 1e-14 * MyGeometry::lengthScale > x[1] or
-      x[1] > minmax1.second + 1e-14 * MyGeometry::lengthScale)
-    return false;
-
-  return true;
-}
-
-template <class GridView>
-template <class Vector>
-bool MyFaces<GridView>::xyBetween(Vector const &v1, Vector const &v2,
-                                  Vector const &x) {
-  return xyCollinear(v1, v2, x) && xyBoxed(v1, v2, x);
-}
-
-template <class GridView>
-MyFaces<GridView>::MyFaces(GridView const &gridView)
-    :
-#if MY_DIM == 3
-      lower(gridView),
-      right(gridView),
-      upper(gridView),
-      front(gridView),
-      back(gridView)
-#else
-      lower(gridView),
-      right(gridView),
-      upper(gridView)
-#endif
-{
-  assert(isClose(MyGeometry::A[1], 0));
-  assert(isClose(MyGeometry::B[1], 0));
-  lower.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-    return isClose(0, in.geometry().center()[1]);
-  });
-#if MY_DIM == 3
-  front.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-    return isClose(MyGeometry::depth / 2.0, in.geometry().center()[2]);
-  });
-
-  back.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-    return isClose(-MyGeometry::depth / 2.0, in.geometry().center()[2]);
-  });
-#endif
-
-  upper.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-    return xyBetween(MyGeometry::A, MyGeometry::C, in.geometry().center());
-  });
-
-  right.insertFacesByProperty([&](typename GridView::Intersection const &in) {
-    return xyBetween(MyGeometry::B, MyGeometry::C, in.geometry().center());
-  });
-}
-
-double computeAdmissibleDiameter(double distance, double smallestDiameter) {
-  return (distance / 0.0125 / MyGeometry::lengthScale + 1.0) * smallestDiameter;
-}
-
-template <class Grid, class LocalVector>
-void refine(Grid &grid, ConvexPolyhedron<LocalVector> const &weakPatch,
-            double smallestDiameter) {
-  bool needRefine = true;
-  while (true) {
-    needRefine = false;
-    for (auto &&e : elements(grid.leafGridView())) {
-      auto const geometry = e.geometry();
-
-      auto const weakeningRegionDistance =
-          distance(weakPatch, geometry, 1e-6 * MyGeometry::lengthScale);
-      auto const admissibleDiameter =
-          computeAdmissibleDiameter(weakeningRegionDistance, smallestDiameter);
-
-      if (diameter(geometry) <= admissibleDiameter)
-        continue;
-
-      needRefine = true;
-      grid.mark(1, e);
-    }
-    if (!needRefine)
-      break;
-
-    grid.preAdapt();
-    grid.adapt();
-    grid.postAdapt();
-  }
-}
-
-#include "mygrid_tmpl.cc"
diff --git a/src/one-body-problem-data/mygrid.hh b/src/one-body-problem-data/mygrid.hh
deleted file mode 100644
index 3508048d..00000000
--- a/src/one-body-problem-data/mygrid.hh
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef SRC_ONE_BODY_PROBLEM_DATA_MYGRID_HH
-#define SRC_ONE_BODY_PROBLEM_DATA_MYGRID_HH
-
-#include <dune/common/fmatrix.hh>
-#include <dune/grid/common/gridfactory.hh>
-
-#include <dune/fufem/boundarypatch.hh>
-#include <dune/fufem/geometry/convexpolyhedron.hh>
-
-#include "mygeometry.hh"
-
-template <class GridView> struct MyFaces {
-  BoundaryPatch<GridView> lower;
-  BoundaryPatch<GridView> right;
-  BoundaryPatch<GridView> upper;
-
-#if MY_DIM == 3
-  BoundaryPatch<GridView> front;
-  BoundaryPatch<GridView> back;
-#endif
-
-  MyFaces(GridView const &gridView);
-
-private:
-  bool isClose(double a, double b) {
-    return std::abs(a - b) < 1e-14 * MyGeometry::lengthScale;
-  };
-
-  bool isClose2(double a, double b) {
-    return std::abs(a - b) <
-           1e-14 * MyGeometry::lengthScale * MyGeometry::lengthScale;
-  };
-
-  template <class Vector>
-  bool xyBoxed(Vector const &v1, Vector const &v2, Vector const &x);
-
-  template <class Vector>
-  bool xyCollinear(Vector const &a, Vector const &b, Vector const &c);
-
-  template <class Vector>
-  bool xyBetween(Vector const &v1, Vector const &v2, Vector const &x);
-};
-
-class SimplexManager {
-public:
-  using SimplexList = std::vector<std::vector<unsigned int>>;
-
-#if MY_DIM == 3
-  SimplexManager(unsigned int shift);
-#endif
-
-  void addFromVerticesFBB(unsigned int U, unsigned int V, unsigned int W);
-  void addFromVerticesFFB(unsigned int U, unsigned int V, unsigned int W);
-
-  SimplexList const &getSimplices();
-
-private:
-  SimplexList simplices_;
-
-#if MY_DIM == 3
-  unsigned int const shift_;
-#endif
-};
-
-template <class Grid> class GridConstructor {
-public:
-  GridConstructor();
-
-  std::shared_ptr<Grid> getGrid();
-
-  template <class GridView>
-  MyFaces<GridView> constructFaces(GridView const &gridView);
-
-private:
-  Dune::GridFactory<Grid> gridFactory;
-};
-
-double computeAdmissibleDiameter(double distance, double smallestDiameter);
-
-template <class Grid, class LocalVector>
-void refine(Grid &grid, ConvexPolyhedron<LocalVector> const &weakPatch,
-            double smallestDiameter);
-
-#endif
diff --git a/src/one-body-problem-data/mygrid_tmpl.cc b/src/one-body-problem-data/mygrid_tmpl.cc
deleted file mode 100644
index acedf87e..00000000
--- a/src/one-body-problem-data/mygrid_tmpl.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef MY_DIM
-#error MY_DIM unset
-#endif
-
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
-
-template class GridConstructor<Grid>;
-
-template struct MyFaces<GridView>;
-
-template MyFaces<GridView> GridConstructor<Grid>::constructFaces(
-    GridView const &gridView);
-
-template void refine<Grid, LocalVector>(
-    Grid &grid, ConvexPolyhedron<LocalVector> const &weakPatch,
-    double smallestDiameter);
diff --git a/src/one-body-problem-data/patchfunction.hh b/src/one-body-problem-data/patchfunction.hh
deleted file mode 100644
index 72cdc867..00000000
--- a/src/one-body-problem-data/patchfunction.hh
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef SRC_ONE_BODY_PROBLEM_DATA_PATCHFUNCTION_HH
-#define SRC_ONE_BODY_PROBLEM_DATA_PATCHFUNCTION_HH
-
-#include <dune/common/function.hh>
-#include <dune/common/fvector.hh>
-#include <dune/common/parametertree.hh>
-
-#include <dune/fufem/geometry/polyhedrondistance.hh>
-
-class PatchFunction
-    : public Dune::VirtualFunction<Dune::FieldVector<double, MY_DIM>,
-                                   Dune::FieldVector<double, 1>> {
-private:
-  using Polyhedron = ConvexPolyhedron<Dune::FieldVector<double, MY_DIM>>;
-
-  double const v1_;
-  double const v2_;
-  Polyhedron const &segment_;
-
-public:
-  PatchFunction(double v1, double v2, Polyhedron const &segment)
-      : v1_(v1), v2_(v2), segment_(segment) {}
-
-  void evaluate(Dune::FieldVector<double, MY_DIM> const &x,
-                Dune::FieldVector<double, 1> &y) const {
-    y = distance(x, segment_, 1e-6 * MyGeometry::lengthScale) <= 1e-5 ? v2_
-                                                                      : v1_;
-  }
-};
-
-#endif
diff --git a/src/one-body-problem-data/segmented-function.hh b/src/one-body-problem-data/segmented-function.hh
deleted file mode 100644
index 652ba03b..00000000
--- a/src/one-body-problem-data/segmented-function.hh
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef SRC_ONE_BODY_PROBLEM_DATA_SEGMENTED_FUNCTION_HH
-#define SRC_ONE_BODY_PROBLEM_DATA_SEGMENTED_FUNCTION_HH
-
-#include <dune/common/function.hh>
-#include <dune/common/fvector.hh>
-#include <dune/common/parametertree.hh>
-
-#include "mygeometry.hh"
-
-class SegmentedFunction
-    : public Dune::VirtualFunction<Dune::FieldVector<double, MY_DIM>,
-                                   Dune::FieldVector<double, 1>> {
-private:
-  bool liesBelow(Dune::FieldVector<double, MY_DIM> const &x,
-                 Dune::FieldVector<double, MY_DIM> const &y,
-                 Dune::FieldVector<double, MY_DIM> const &z) const {
-    return x[1] + (z[0] - x[0]) * (y[1] - x[1]) / (y[0] - x[0]) >= z[1];
-  };
-  bool insideRegion2(Dune::FieldVector<double, MY_DIM> const &z) const {
-    return liesBelow(MyGeometry::K, MyGeometry::M, z);
-  };
-
-  double const _v1;
-  double const _v2;
-
-public:
-  SegmentedFunction(double v1, double v2) : _v1(v1), _v2(v2) {}
-
-  void evaluate(Dune::FieldVector<double, MY_DIM> const &x,
-                Dune::FieldVector<double, 1> &y) const {
-    y = insideRegion2(x) ? _v2 : _v1;
-  }
-};
-#endif
diff --git a/src/one-body-problem-data/weakpatch.hh b/src/one-body-problem-data/weakpatch.hh
deleted file mode 100644
index 59a65306..00000000
--- a/src/one-body-problem-data/weakpatch.hh
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef SRC_ONE_BODY_PROBLEM_DATA_WEAKPATCH_HH
-#define SRC_ONE_BODY_PROBLEM_DATA_WEAKPATCH_HH
-
-template <class LocalVector>
-ConvexPolyhedron<LocalVector> getWeakPatch(Dune::ParameterTree const &parset) {
-  ConvexPolyhedron<LocalVector> weakPatch;
-#if MY_DIM == 3
-  weakPatch.vertices.resize(4);
-  weakPatch.vertices[0] = weakPatch.vertices[2] = MyGeometry::X;
-  weakPatch.vertices[1] = weakPatch.vertices[3] = MyGeometry::Y;
-  for (size_t k = 0; k < 2; ++k) {
-    weakPatch.vertices[k][2] = -MyGeometry::depth / 2.0;
-    weakPatch.vertices[k + 2][2] = MyGeometry::depth / 2.0;
-  }
-  switch (parset.get<Config::PatchType>("patchType")) {
-    case Config::Rectangular:
-      break;
-    case Config::Trapezoidal:
-      weakPatch.vertices[1][0] += 0.05 * MyGeometry::lengthScale;
-      weakPatch.vertices[3][0] -= 0.05 * MyGeometry::lengthScale;
-      break;
-    default:
-      assert(false);
-  }
-#else
-  weakPatch.vertices.resize(2);
-  weakPatch.vertices[0] = MyGeometry::X;
-  weakPatch.vertices[1] = MyGeometry::Y;
-#endif
-  return weakPatch;
-};
-#endif
diff --git a/src/one-body-problem.cc b/src/one-body-problem.cc
deleted file mode 100644
index b95f4cd1..00000000
--- a/src/one-body-problem.cc
+++ /dev/null
@@ -1,361 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_IPOPT
-#undef HAVE_IPOPT
-#endif
-
-#include <atomic>
-#include <cmath>
-#include <csignal>
-#include <exception>
-#include <fstream>
-#include <iostream>
-#include <iomanip>
-
-#include <dune/common/bitsetvector.hh>
-#include <dune/common/exceptions.hh>
-#include <dune/common/fmatrix.hh>
-#include <dune/common/function.hh>
-#include <dune/common/fvector.hh>
-#include <dune/common/parallel/mpihelper.hh>
-#include <dune/common/parametertree.hh>
-#include <dune/common/parametertreeparser.hh>
-
-#include <dune/grid/common/mcmgmapper.hh>
-#include <dune/istl/bcrsmatrix.hh>
-#include <dune/istl/bvector.hh>
-
-#include <dune/fufem/boundarypatch.hh>
-#include <dune/fufem/formatstring.hh>
-
-#include <dune/solvers/norms/energynorm.hh>
-
-
-/*
-#include <dune/solvers/solvers/loopsolver.hh>
-#include <dune/solvers/solvers/solver.hh>
-#include <dune/tnnmg/problem-classes/convexproblem.hh>
-*/
-
-
-#include <dune/tectonic/geocoordinate.hh>
-#include <dune/tectonic/myblockproblem.hh>
-#include <dune/tectonic/globalfriction.hh>
-#include <dune/fufem/hdf5/file.hh>
-
-#include "assemblers.hh"
-#include "boundarycondition.hh"
-#include "gridselector.hh"
-
-#include "data-structures/enumparser.hh"
-#include "data-structures/enums.hh"
-#include "data-structures/matrices.hh"
-#include "data-structures/program_state.hh"
-
-#include "io/hdf5-writer.hh"
-#include "io/hdf5/restart-io.hh"
-#include "io/vtk.hh"
-
-#include "one-body-problem-data/bc.hh"
-#include "one-body-problem-data/mybody.hh"
-#include "one-body-problem-data/mygeometry.hh"
-#include "one-body-problem-data/myglobalfrictiondata.hh"
-#include "one-body-problem-data/mygrid.hh"
-#include "one-body-problem-data/weakpatch.hh"
-
-#include "spatial-solving/solverfactory.hh"
-
-#include "time-stepping/adaptivetimestepper.hh"
-#include "time-stepping/rate.hh"
-#include "time-stepping/state.hh"
-#include "time-stepping/updaters.hh"
-
-#include "utils/diameter.hh"
-
-// for getcwd
-#include <unistd.h>
-
-#define USE_OLD_TNNMG
-
-size_t const dims = MY_DIM;
-
-Dune::ParameterTree getParameters(int argc, char *argv[]) {
-  Dune::ParameterTree parset;
-  Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/one-body-problem.cfg", parset);
-  Dune::ParameterTreeParser::readINITree(
-      Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/one-body-problem-%dD.cfg", dims), parset);
-  Dune::ParameterTreeParser::readOptions(argc, argv, parset);
-  return parset;
-}
-
-static std::atomic<bool> terminationRequested(false);
-void handleSignal(int signum) { terminationRequested = true; }
-
-int main(int argc, char *argv[]) {
-  try {
-    Dune::MPIHelper::instance(argc, argv);
-
-    char buffer[256];
-    char *val = getcwd(buffer, sizeof(buffer));
-    if (val) {
-        std::cout << buffer << std::endl;
-        std::cout << argv[0] << std::endl;
-    }
-
-    auto const parset = getParameters(argc, argv);
-
-    MyGeometry::render();
-    MyGeometry::write();
-
-    using GridView = Grid::LeafGridView;
-    using MyAssembler = MyAssembler<GridView, dims>;
-    using Matrix = MyAssembler::Matrix;
-    using Vector = MyAssembler::Vector;
-    using LocalVector = Vector::block_type;
-    using ScalarMatrix = MyAssembler::ScalarMatrix;
-    using ScalarVector = MyAssembler::ScalarVector;
-
-    auto const weakPatch =
-        getWeakPatch<LocalVector>(parset.sub("boundary.friction.weakening"));
-
-    // {{{ Set up grid
-    GridConstructor<Grid> gridConstructor;
-    auto grid = gridConstructor.getGrid();
-
-    refine(*grid, weakPatch,
-           parset.get<double>("boundary.friction.smallestDiameter"));
-
-    double minDiameter = std::numeric_limits<double>::infinity();
-    double maxDiameter = 0.0;
-    for (auto &&e : elements(grid->leafGridView())) {
-      auto const geometry = e.geometry();
-      auto const diam = diameter(geometry);
-      minDiameter = std::min(minDiameter, diam);
-      maxDiameter = std::max(maxDiameter, diam);
-    }
-    std::cout << "min diameter: " << minDiameter << std::endl;
-    std::cout << "max diameter: " << maxDiameter << std::endl;
-
-    auto const leafView = grid->leafGridView();
-    auto const leafVertexCount = leafView.size(dims);
-
-    std::cout << "Number of DOFs: " << leafVertexCount << std::endl;
-
-    auto myFaces = gridConstructor.constructFaces(leafView);
-
-    BoundaryPatch<GridView> const neumannBoundary(leafView);
-    BoundaryPatch<GridView> const &frictionalBoundary = myFaces.lower;
-    BoundaryPatch<GridView> const &surface = myFaces.upper;
-
-    // Dirichlet Boundary
-    Dune::BitSetVector<dims> noNodes(leafVertexCount);
-    Dune::BitSetVector<dims> dirichletNodes(leafVertexCount);
-    for (size_t i = 0; i < leafVertexCount; ++i) {
-      if (myFaces.right.containsVertex(i))
-        dirichletNodes[i][0] = true;
-
-      if (myFaces.lower.containsVertex(i))
-        dirichletNodes[i][1] = true;
-
-#if MY_DIM == 3
-      if (myFaces.front.containsVertex(i) || myFaces.back.containsVertex(i))
-        dirichletNodes[i][2] = true;
-#endif
-    }
-
-
-    // Set up functions for time-dependent boundary conditions
-    using Function = Dune::VirtualFunction<double, double>;
-    Function const &velocityDirichletFunction = VelocityDirichletCondition();
-    Function const &neumannFunction = NeumannCondition();
-
-    MyAssembler const myAssembler(leafView);
-
-    MyBody<dims> const body(parset);
-
-    Matrices<Matrix> matrices;
-    myAssembler.assembleElasticity(body.getYoungModulus(),
-                                   body.getPoissonRatio(), matrices.elasticity);
-    myAssembler.assembleViscosity(body.getShearViscosityField(),
-                                  body.getBulkViscosityField(),
-                                  matrices.damping);
-    myAssembler.assembleMass(body.getDensityField(), matrices.mass);
-
-    ScalarMatrix relativeFrictionalBoundaryMass;
-    myAssembler.assembleFrictionalBoundaryMass(frictionalBoundary,
-                                               relativeFrictionalBoundaryMass);
-    relativeFrictionalBoundaryMass /= frictionalBoundary.area();
-    EnergyNorm<ScalarMatrix, ScalarVector> const stateEnergyNorm(
-        relativeFrictionalBoundaryMass);
-
-    // Assemble forces
-    Vector gravityFunctional;
-    myAssembler.assembleBodyForce(body.getGravityField(), gravityFunctional);
-
-    // Problem formulation: right-hand side
-    std::function<void(double, Vector &)> computeExternalForces =
-        [&](double _relativeTime, Vector &_ell) {
-          myAssembler.assembleNeumann(neumannBoundary, _ell, neumannFunction,
-                                      _relativeTime);
-          _ell += gravityFunctional;
-        };
-
-    using MyProgramState = ProgramState<Vector, ScalarVector>;
-    MyProgramState programState(leafVertexCount);
-    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");
-    auto const writeData = parset.get<bool>("io.data.write");
-    bool const handleRestarts = writeRestarts or firstRestart > 0;
-
-    /*
-    auto dataFile =
-        writeData ? std::make_unique<HDF5::File>("output.h5") : nullptr;
-
-    auto restartFile = handleRestarts
-                           ? std::make_unique<HDF5::File>(
-                                 "restarts.h5",
-                                 writeRestarts ? HDF5::Access::READWRITE
-                                               : HDF5::Access::READONLY)
-                           : nullptr;
-    auto restartIO = handleRestarts
-                         ? std::make_unique<RestartIO<MyProgramState>>(
-                               *restartFile, leafVertexCount)
-                         : nullptr;
-
-    if (firstRestart > 0) // automatically adjusts the time and timestep
-      restartIO->read(firstRestart, programState);
-    else
-      programState.setupInitialConditions(parset, computeExternalForces,
-                                          matrices, myAssembler, dirichletNodes,
-                                          noNodes, frictionalBoundary, body);
-
-    MyGlobalFrictionData<LocalVector> frictionInfo(
-        parset.sub("boundary.friction"), weakPatch);
-    auto myGlobalFriction = myAssembler.assembleFrictionNonlinearity(
-        parset.get<Config::FrictionModel>("boundary.friction.frictionModel"),
-        frictionalBoundary, frictionInfo, programState.weightedNormalStress);
-    myGlobalFriction->updateAlpha(programState.alpha);
-
-    Vector vertexCoordinates(leafVertexCount);
-    {
-      Dune::MultipleCodimMultipleGeomTypeMapper<
-          GridView, Dune::MCMGVertexLayout> const vertexMapper(leafView, Dune::mcmgVertexLayout());
-      for (auto &&v : vertices(leafView))
-        vertexCoordinates[vertexMapper.index(v)] = geoToPoint(v.geometry());
-    }
-
-    using MyVertexBasis = typename MyAssembler::VertexBasis;
-    auto dataWriter =
-        writeData ? std::make_unique<
-                        HDF5Writer<MyProgramState, MyVertexBasis, GridView>>(
-                        *dataFile, vertexCoordinates, myAssembler.vertexBasis,
-                        surface, frictionalBoundary, weakPatch)
-                  : nullptr;
-    MyVTKWriter<MyVertexBasis, typename MyAssembler::CellBasis> const vtkWriter(
-        myAssembler.cellBasis, myAssembler.vertexBasis, "obs");
-
-
-    IterationRegister iterationCount;
-    auto const report = [&](bool initial = false) {
-      if (writeData) {
-        dataWriter->reportSolution(programState, *myGlobalFriction);
-        if (!initial)
-          dataWriter->reportIterations(programState, iterationCount);
-        dataFile->flush();
-      }
-
-      if (writeRestarts and !initial and
-          programState.timeStep % restartSpacing == 0) {
-        restartIO->write(programState);
-        restartFile->flush();
-      }
-
-      if (parset.get<bool>("io.printProgress"))
-        std::cout << "timeStep = " << std::setw(6) << programState.timeStep
-                  << ", time = " << std::setw(12) << programState.relativeTime
-                  << ", tau = " << std::setw(12) << programState.relativeTau
-                  << std::endl;
-
-      if (parset.get<bool>("io.vtk.write")) {
-        ScalarVector stress;
-        myAssembler.assembleVonMisesStress(body.getYoungModulus(),
-                                           body.getPoissonRatio(),
-                                           programState.u, stress);
-        vtkWriter.write(programState.timeStep, programState.u, programState.v,
-                        programState.alpha, stress);
-      }
-    };
-    report(true);
-
-
-    // Set up TNNMG solver
-    using NonlinearFactory = SolverFactory<
-        dims,
-        MyBlockProblem<ConvexProblem<GlobalFriction<Matrix, Vector>, Matrix>>,
-        Grid>;
-    NonlinearFactory factory(parset.sub("solver.tnnmg"), *grid, dirichletNodes);
-
-    using MyUpdater = Updaters<RateUpdater<Vector, Matrix, Function, dims>,
-                               StateUpdater<ScalarVector, Vector>>;
-    MyUpdater current(
-        initRateUpdater(parset.get<Config::scheme>("timeSteps.scheme"),
-                        velocityDirichletFunction, dirichletNodes, matrices,
-                        programState.u, programState.v, programState.a),
-        initStateUpdater<ScalarVector, Vector>(
-            parset.get<Config::stateModel>("boundary.friction.stateModel"),
-            programState.alpha, *frictionalBoundary.getVertices(),
-            parset.get<double>("boundary.friction.L"),
-            parset.get<double>("boundary.friction.V0")));
-
-    auto const refinementTolerance =
-        parset.get<double>("timeSteps.refinementTolerance");
-    auto const mustRefine = [&](MyUpdater &coarseUpdater,
-                                MyUpdater &fineUpdater) {
-      ScalarVector coarseAlpha;
-      coarseUpdater.state_->extractAlpha(coarseAlpha);
-
-      ScalarVector fineAlpha;
-      fineUpdater.state_->extractAlpha(fineAlpha);
-
-      return stateEnergyNorm.diff(fineAlpha, coarseAlpha) > refinementTolerance;
-    };
-
-    std::signal(SIGXCPU, handleSignal);
-    std::signal(SIGINT, handleSignal);
-    std::signal(SIGTERM, handleSignal);
-
-    AdaptiveTimeStepper<NonlinearFactory, MyUpdater,
-                        EnergyNorm<ScalarMatrix, ScalarVector>>
-        adaptiveTimeStepper(factory, parset, myGlobalFriction, current,
-                            programState.relativeTime, programState.relativeTau,
-                            computeExternalForces, stateEnergyNorm, mustRefine);
-    while (!adaptiveTimeStepper.reachedEnd()) {
-      programState.timeStep++;
-
-      iterationCount = adaptiveTimeStepper.advance();
-
-      programState.relativeTime = adaptiveTimeStepper.relativeTime_;
-      programState.relativeTau = adaptiveTimeStepper.relativeTau_;
-      current.rate_->extractDisplacement(programState.u);
-      current.rate_->extractVelocity(programState.v);
-      current.rate_->extractAcceleration(programState.a);
-      current.state_->extractAlpha(programState.alpha);
-
-      report();
-
-      if (terminationRequested) {
-        std::cerr << "Terminating prematurely" << std::endl;
-        break;
-      }
-    }
-
-    */
-  } catch (Dune::Exception &e) {
-    Dune::derr << "Dune reported error: " << e << std::endl;
-  } catch (std::exception &e) {
-    std::cerr << "Standard exception: " << e.what() << std::endl;
-  }
-}
diff --git a/src/one-body-problem.cfg b/src/one-body-problem.cfg
deleted file mode 100644
index 7336759c..00000000
--- a/src/one-body-problem.cfg
+++ /dev/null
@@ -1,70 +0,0 @@
-# -*- mode:conf -*-
-gravity         = 9.81  # [m/s^2]
-
-[io]
-data.write      = true
-printProgress   = false
-restarts.first  = 0
-restarts.spacing= 20
-restarts.write  = true
-vtk.write       = false
-
-[problem]
-finalTime       = 1000  # [s]
-
-[body]
-bulkModulus     = 0.5e5 # [Pa]
-poissonRatio    = 0.3   # [1]
-[body.elastic]
-density         = 900   # [kg/m^3]
-shearViscosity  = 1e3   # [Pas]
-bulkViscosity   = 1e3   # [Pas]
-[body.viscoelastic]
-density         = 1000  # [kg/m^3]
-shearViscosity  = 1e4   # [Pas]
-bulkViscosity   = 1e4   # [Pas]
-
-[boundary.friction]
-C               = 10    # [Pa]
-mu0             = 0.7   # [ ]
-V0              = 5e-5  # [m/s]
-L               = 2.25e-5 # [m]
-initialAlpha    = 0     # [ ]
-stateModel      = AgeingLaw
-frictionModel   = Regularised
-[boundary.friction.weakening]
-a               = 0.002 # [ ]
-b               = 0.017 # [ ]
-[boundary.friction.strengthening]
-a               = 0.020 # [ ]
-b               = 0.005 # [ ]
-
-[timeSteps]
-scheme = newmark
-
-[u0.solver]
-maximumIterations = 100000
-verbosity         = quiet
-
-[a0.solver]
-maximumIterations = 100000
-verbosity         = quiet
-
-[v.solver]
-maximumIterations = 100000
-verbosity         = quiet
-
-[v.fpi]
-maximumIterations = 10000
-lambda            = 0.5
-
-[solver.tnnmg.linear]
-maximumIterations = 100000
-pre                = 3
-cycle              = 1  # 1 = V, 2 = W, etc.
-post               = 3
-
-[solver.tnnmg.main]
-pre   = 1
-multi = 5 # number of multigrid steps
-post  = 0
diff --git a/src/spatial-solving/CMakeLists.txt b/src/spatial-solving/CMakeLists.txt
deleted file mode 100644
index e683042b..00000000
--- a/src/spatial-solving/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-add_subdirectory("tnnmg")
-add_subdirectory("preconditioners")
diff --git a/src/spatial-solving/fixedpointiterator_tmpl.cc b/src/spatial-solving/fixedpointiterator_tmpl.cc
deleted file mode 100644
index 5f4b30cf..00000000
--- a/src/spatial-solving/fixedpointiterator_tmpl.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef MY_DIM
-#error MY_DIM unset
-#endif
-
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
-
-#include <dune/solvers/norms/energynorm.hh>
-
-#include "../spatial-solving/solverfactory_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 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 ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
-
-
-template class FixedPointIterator<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>;
diff --git a/src/spatial-solving/preconditioners/CMakeLists.txt b/src/spatial-solving/preconditioners/CMakeLists.txt
deleted file mode 100644
index 00e132a9..00000000
--- a/src/spatial-solving/preconditioners/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-add_custom_target(dune-tectonic_spatial-solving_preconditioners_src SOURCES
-  hierarchicleveliterator.hh
-  levelpatchpreconditioner.hh
-  localproblem.hh
-  multilevelpatchpreconditioner.hh
-  nbodycontacttransfer.hh
-  supportpatchfactory.hh
-)
diff --git a/src/spatial-solving/preconditioners/localproblem.hh b/src/spatial-solving/preconditioners/localproblem.hh
deleted file mode 100644
index 8d202afc..00000000
--- a/src/spatial-solving/preconditioners/localproblem.hh
+++ /dev/null
@@ -1,141 +0,0 @@
-#ifndef OSC_LOCAL_PROBLEM_HH
-#define OSC_LOCAL_PROBLEM_HH
-
-#include <math.h>   
-#include <dune/common/fmatrix.hh>
-#include <dune/common/function.hh>
-#include <dune/common/timer.hh>
-
-#include <dune/istl/matrixindexset.hh>
-//#include <dune/istl/superlu.hh>
-#include <dune/istl/umfpack.hh>
-
-#include <dune/fufem/assemblers/localoperatorassembler.hh>
-
-#include "../../utils/debugutils.hh"
-
-template <class MatrixType, class DomainType, class RangeType = DomainType>
-class LocalProblem {
-  
-private:    
-    typedef typename MatrixType::block_type block_type;
-    typedef typename MatrixType::field_type ctype;
-
-    const static size_t dim = DomainType::block_type::dimension;
-
-    using BitVector = Dune::BitSetVector<dim>;
-
-    MatrixType localMat;
-    const RangeType& rhs_;
-    const BitVector& ignoreNodes_;
-
-   /* size_t flatIndex(const size_t blockIdx, const size_t localBlockIdx) {
-        return blockIdx*dim + localBlockIdx;
-    }
-
-    bool isAllIgnored(const size_t blockIdx) {
-        bool res = true;
-        size_t flatIdx = blockIdx*dim;
-
-        for (size_t d=0; d<dim; d++) {
-            res = res && (globalToLocal_[flatIdx+d] == -1);
-        }
-
-        return res;
-    }*/
-    template <class LocalMat, class LocalBitVector>
-    void computeLocalMat(LocalMat& localMat, const LocalMat& refMat, const LocalBitVector& localIgnore, bool isDiagonal=false) {
-        if (isDiagonal) {
-            for (size_t i=0; i<refMat.N(); i++) {
-                bool isIgnored = localIgnore[i];
-                for (size_t j=0; j<refMat.M(); j++) {
-                    if (isIgnored || refMat[i][j]==0)
-                        localMat[i][j] = (double) (i==j);
-                    else
-                        localMat[i][j] = refMat[i][j];
-                }
-            }
-        } else {
-            for (size_t i=0; i<refMat.N(); i++) {
-                bool isIgnored = localIgnore[i];
-                for (size_t j=0; j<refMat.M(); j++) {
-                    if (isIgnored)
-                        localMat[i][j] = 0;
-                    else
-                        localMat[i][j] = refMat[i][j];
-                }
-            }
-        }
-    }
-
-public:
-    LocalProblem(const MatrixType& mat,
-                 const RangeType& rhs,
-                 const BitVector& ignoreNodes) :
-      rhs_(rhs),
-      ignoreNodes_(ignoreNodes)
-	{
-	  
-	// construct globalToLocal map
-       /* std::vector<int, int> localToGlobal;
-        std::vector<int, int> globalToLocal(ignoreNodes.size()*dim, -1);
-        int localIdx = 0;
-        for (size_t i=0; i<ignoreNodes.size(); ++i) {
-            const auto& ignoreNode = ignoreNodes[i];
-            for (size_t d=0; d<dim; d++) {
-                if (not toBool(ignoreNode[d])) {
-                    size_t flatIdx = flatIndex(i, d);
-                    localToGlobal[localIdx] = flatIdx;
-                    globalToLocal[flatIdx] = localIdx;
-                    localIdx++;
-                }
-            }
-        }*/
-
-	// build local stiffness matrix
-        localMat = mat;
-	
-        for(size_t rowIdx = 0; rowIdx<localMat.N(); rowIdx++) {
-            const auto& row = mat[rowIdx];
-	    
-            auto colIt = row.begin();
-            const auto& colEndIt = row.end();
-            for(; colIt!=colEndIt; ++colIt) {
-                const auto colIdx = colIt.index();
-                computeLocalMat(localMat[rowIdx][colIdx], row[colIdx], ignoreNodes_[rowIdx], rowIdx==colIdx);
-            }
-        }   
-    }
-
-    MatrixType& getMat() {
-	return localMat;
-    }
-    
-    void getLocalRhs(const DomainType& iterate, RangeType& newRhs) {
-        newRhs = rhs_;
-
-        for (size_t i=0; i<newRhs.size(); i++) {
-            for (size_t d=0; d<dim; d++) {
-                if (ignoreNodes_[i][d]) {
-                    newRhs[i][d] = iterate[i][d];
-                }
-            }
-        }
-    }
-
-  /*  void solve(DomainType& x){
-        #if HAVE_SUPERLU
-            RangeType localRhsCopy(localRhs);
-            Dune::InverseOperatorResult res;
-
-            x.resize(localMat.M());
-
-            Dune::UMFPack<MatrixType> directSolver(localMat);
-            directSolver.apply(x, localRhsCopy, res);
-        #else
-        #error No SuperLU!
-        #endif
-    }*/
-};
-
-#endif
diff --git a/src/spatial-solving/solverfactory.cc b/src/spatial-solving/solverfactory.cc
deleted file mode 100644
index 017f981d..00000000
--- a/src/spatial-solving/solverfactory.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-//#ifdef HAVE_CONFIG_H
-//#include "config.h"
-//#endif
-
-#include <dune/solvers/common/wrapownshare.hh>
-#include <dune/solvers/iterationsteps/blockgssteps.hh>
-#include <dune/solvers/solvers/umfpacksolver.hh>
-
-//#include "solverfactory.hh"
-
-#include "../utils/debugutils.hh"
-
-template <class Functional, class BitVector, class ContactNetwork>
-template <class LinearSolver>
-SolverFactory<Functional, BitVector, ContactNetwork>::SolverFactory(
-    const Dune::ParameterTree& parset,
-    Functional& J,
-    LinearSolver&& linearSolver,
-    const BitVector& ignoreNodes,
-    const ContactNetwork& contactNetwork) :
-        J_(Dune::Solvers::wrap_own_share<const Functional>(std::forward<Functional>(J))) {
-
-    //auto localSolver = Dune::TNNMG::gaussSeidelLocalSolver(LocalSolver());
-    //nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, localSolver);
-
-    nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, LocalSolver());
-
-    auto linearSolver_ptr = Dune::Solvers::wrap_own_share<std::decay_t<LinearSolver>>(std::forward<LinearSolver>(linearSolver));
-
-    //tnnmgStep_ = std::make_shared<Step>(*J_, dummyIterate_, nonlinearSmoother_, linearSolver_ptr, DefectProjection(), Dune::TNNMG::ScalarObstacleSolver());
-
-    tnnmgStep_ = std::make_shared<Step>(*J_, dummyIterate_, nonlinearSmoother_, linearSolver_ptr, DefectProjection(), LineSearchSolver(), contactNetwork);
-    tnnmgStep_->setPreSmoothingSteps(parset.get<int>("main.pre"));
-    tnnmgStep_->setIgnore(ignoreNodes);
-}
-
-template <class Functional, class BitVector, class ContactNetwork>
-void SolverFactory<Functional, BitVector, ContactNetwork>::setProblem(Vector& x) {
-    nonlinearSmoother_->setProblem(x);
-    tnnmgStep_->setProblem(x);
-}
-
-
-template <class Functional, class BitVector, class ContactNetwork>
-auto SolverFactory<Functional, BitVector, ContactNetwork>::step()
--> std::shared_ptr<Step> {
-    return tnnmgStep_;
-}
-
-//#include "solverfactory_tmpl.cc"
diff --git a/src/spatial-solving/solverfactory_tmpl.cc b/src/spatial-solving/solverfactory_tmpl.cc
deleted file mode 100644
index 996e7360..00000000
--- a/src/spatial-solving/solverfactory_tmpl.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef MY_DIM
-#error MY_DIM unset
-#endif
-
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
-
-#include <dune/solvers/solvers/loopsolver.hh>
-
-#include "../../dune/tectonic/globalfriction.hh"
-#include "tnnmg/functional.hh"
-#include "tnnmg/zerononlinearity.hh"
-
-#include "../data-structures/contactnetwork.hh"
-
-#include "solverfactory.hh"
-
-using MyGlobalFriction = GlobalFriction<Matrix, Vector>;
-
-using MyFunctional = Functional<Matrix&, Vector&, MyGlobalFriction&, Vector&, Vector&, double>;
-using MyZeroFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, double>;
-
-using MyLinearSolver = Dune::Solvers::LoopSolver<Vector>;
-
-using MyContactNetwork =  ContactNetwork<Grid, Vector>;
-
-using MySolverFactory = SolverFactory<MyFunctional, BitVector>;
-template class SolverFactory<MyFunctional, BitVector>;
-template<> template<> SolverFactory<MyFunctional, BitVector>::SolverFactory(const Dune::ParameterTree&, MyFunctional&, MyLinearSolver&&, const BitVector&, const MyContactNetwork&);
-
-using MyZeroSolverFactory = SolverFactory<MyZeroFunctional, BitVector>;
-template class SolverFactory<MyZeroFunctional, BitVector>;
-/*template<> SolverFactory<MyZeroFunctional, BitVector>::SolverFactory(Dune::ParameterTree const &,
-                                                               MyZeroFunctional&,
-                                                               MyLinearSolver&&,
-                                                               const BitVector&);*/
diff --git a/src/spatial-solving/tnnmg/CMakeLists.txt b/src/spatial-solving/tnnmg/CMakeLists.txt
deleted file mode 100644
index d32080a3..00000000
--- a/src/spatial-solving/tnnmg/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-add_custom_target(dune-tectonic_spatial-solving_tnnmg_src SOURCES
-  functional.hh
-  linearization.hh
-  linearcorrection.hh
-  linesearchsolver.hh
-  localbisectionsolver.hh
-  zerononlinearity.hh
-)
diff --git a/src/tests/contactmerge.cc b/src/tests/contactmerge.cc
deleted file mode 100644
index 5bf8d918..00000000
--- a/src/tests/contactmerge.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <dune/common/parallel/mpihelper.hh>
-#include <dune/grid/yaspgrid.hh>
-#include <dune/grid-glue/adapter/gridgluevtkwriter.hh>
-#include <dune/grid-glue/extractors/codim1extractor.hh>
-#include <dune/grid-glue/gridglue.hh>
-#include <dune/grid-glue/merging/contactmerge.hh>
-
-const unsigned dim = 3;
-using Coordinates = Dune::EquidistantOffsetCoordinates<double, dim>;
-using Grid = Dune::YaspGrid<dim, Coordinates>;
-using Element = Grid::Codim<0>::Entity;
-using Extractor = Dune::GridGlue::Codim1Extractor<Grid::LeafGridView>;
-using GridGlue = Dune::GridGlue::GridGlue<Extractor, Extractor>;
-using ContactMerge = Dune::GridGlue::ContactMerge<dim, Grid::ctype>;
-
-int main(int argc, char** argv)
-{
-  Dune::MPIHelper::instance(argc, argv);
-
-  Grid grid0{{0., 0., 0.}, {1., 1., 1.}, {10, 10, 10}};
-  Grid grid1{{.12, 0.23, 1.05}, {1.12, 1.23, 2.05}, {10, 10, 10}};
-
-  auto truePredicate = [](const Element&, unsigned int) { return true; };
-
-  auto extractor0 = std::make_shared<Extractor>(grid0.leafGridView(), truePredicate);
-  auto extractor1 = std::make_shared<Extractor>(grid1.leafGridView(), truePredicate);
-
-  auto merger = std::make_shared<ContactMerge>();
-
-  GridGlue glue(extractor0, extractor1, merger);
-  glue.build();
-
-  Dune::GridGlue::GridGlueVtkWriter::write(glue, "contactmerge");
-
-  return 0;
-}
diff --git a/src/time-stepping/adaptivetimestepper.cc b/src/time-stepping/adaptivetimestepper.cc
deleted file mode 100644
index 96aa6ecc..00000000
--- a/src/time-stepping/adaptivetimestepper.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "adaptivetimestepper.hh"
-
-void IterationRegister::registerCount(FixedPointIterationCounter count) {
-  totalCount += count;
-}
-
-void IterationRegister::registerFinalCount(FixedPointIterationCounter count) {
-  finalCount = count;
-}
-
-void IterationRegister::reset() {
-  totalCount = FixedPointIterationCounter();
-  finalCount = FixedPointIterationCounter();
-}
-
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
-AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::AdaptiveTimeStepper(
-        Dune::ParameterTree const &parset,
-        const ContactNetwork& contactNetwork,
-        const IgnoreVector& ignoreNodes,
-        GlobalFriction& globalFriction,
-        const std::vector<const BitVector*>& bodywiseNonmortarBoundaries,
-        Updaters &current,
-        double relativeTime,
-        double relativeTau,
-        ExternalForces& externalForces,
-        const ErrorNorms& errorNorms,
-        std::function<bool(Updaters &, Updaters &)> mustRefine)
-    : relativeTime_(relativeTime),
-      relativeTau_(relativeTau),
-      finalTime_(parset.get<double>("problem.finalTime")),
-      parset_(parset),
-      contactNetwork_(contactNetwork),
-      ignoreNodes_(ignoreNodes),
-      globalFriction_(globalFriction),
-      bodywiseNonmortarBoundaries_(bodywiseNonmortarBoundaries),
-      current_(current),
-      R1_(),
-      externalForces_(externalForces),
-      mustRefine_(mustRefine),
-      errorNorms_(errorNorms) {}
-
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
-bool AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::reachedEnd() {
-  return relativeTime_ >= 1.0;
-}
-
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
-IterationRegister AdaptiveTimeStepper<Factory, ContactNetwork, 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
-    |F1|F2|     | the result of (R1+R2) with C, i.e. two steps of size
-                  tau with one of size 2*tau. To check if we need to
-    refine, we compare the result of (F1+F2) with R1, i.e. two steps
-    of size tau/2 with one of size tau. The method makes multiple
-    coarsening/refining attempts, with coarsening coming first. */
-
-  std::cout << "AdaptiveTimeStepper::advance()" << std::endl;
-
-  if (R1_.updaters == Updaters())
-    R1_ = step(current_, relativeTime_, relativeTau_);
-
-  std::cout << "AdaptiveTimeStepper Step 1" << std::endl;
-
-  bool didCoarsen = false;
-  iterationRegister_.reset();
-  UpdatersWithCount R2; /*
-  UpdatersWithCount C;
-  while (relativeTime_ + relativeTau_ <= 1.0) {
-    R2 = step(R1_.updaters, relativeTime_ + relativeTau_, relativeTau_);
-    std::cout << "AdaptiveTimeStepper R2 computed!" << std::endl << std::endl;
-    C = step(current_, relativeTime_, 2 * relativeTau_);
-    std::cout << "AdaptiveTimeStepper C computed!" << std::endl << std::endl;
-    if (mustRefine_(R2.updaters, C.updaters))
-      break;
-
-    didCoarsen = true;
-    relativeTau_ *= 2;
-    R1_ = C;
-  }
-
-  std::cout << "AdaptiveTimeStepper Step 1" << std::endl;
-  UpdatersWithCount F1;
-  UpdatersWithCount F2;
-  if (!didCoarsen) {
-    while (true) {
-      F1 = step(current_, relativeTime_, relativeTau_ / 2.0);
-      std::cout << "AdaptiveTimeStepper F1 computed!" << std::endl << std::endl;
-      F2 = step(F1.updaters, relativeTime_ + relativeTau_ / 2.0,
-                relativeTau_ / 2.0);
-      std::cout << "AdaptiveTimeStepper F2 computed!" << std::endl << std::endl;
-      if (!mustRefine_(F2.updaters, R1_.updaters)) {
-        std::cout << "Sufficiently refined!" << std::endl;
-        break;
-      }
-
-      relativeTau_ /= 2.0;
-      R1_ = F1;
-      R2 = F2;
-    }
-  }
- */
-  std::cout << "AdaptiveTimeStepper::advance() ...";
-
-  iterationRegister_.registerFinalCount(R1_.count);
-  relativeTime_ += relativeTau_;
-  current_ = R1_.updaters;
-
-  //UpdatersWithCount emptyR1;
-  //R1_ = emptyR1;
-  R1_ = R2;
-
-  std::cout << " done" << std::endl;
-
-  return iterationRegister_;
-}
-
-template <class Factory, class ContactNetwork, class Updaters, class ErrorNorms>
-typename AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::UpdatersWithCount
-AdaptiveTimeStepper<Factory, ContactNetwork, Updaters, ErrorNorms>::step(
-    Updaters const &oldUpdaters, double rTime, double rTau) {
-  UpdatersWithCount newUpdatersAndCount = {oldUpdaters.clone(), {}};
-  newUpdatersAndCount.count =
-      MyCoupledTimeStepper(finalTime_, parset_, contactNetwork_, ignoreNodes_, globalFriction_, bodywiseNonmortarBoundaries_,
-                           newUpdatersAndCount.updaters, errorNorms_,
-                           externalForces_)
-          .step(rTime, rTau);
-  iterationRegister_.registerCount(newUpdatersAndCount.count);
-  return newUpdatersAndCount;
-}
-
-#include "adaptivetimestepper_tmpl.cc"
diff --git a/src/time-stepping/adaptivetimestepper_tmpl.cc b/src/time-stepping/adaptivetimestepper_tmpl.cc
deleted file mode 100644
index fcb100f4..00000000
--- a/src/time-stepping/adaptivetimestepper_tmpl.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef MY_DIM
-#error MY_DIM unset
-#endif
-
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
-
-#include <dune/solvers/norms/energynorm.hh>
-
-#include "../spatial-solving/solverfactory_tmpl.cc"
-#include "../data-structures/contactnetwork_tmpl.cc"
-
-#include "rate/rateupdater.hh"
-#include "state/stateupdater.hh"
-#include "updaters.hh"
-
-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 ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
-
-using MyAdaptiveTimeStepper = AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>;
-template class AdaptiveTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>;
diff --git a/src/time-stepping/coupledtimestepper_tmpl.cc b/src/time-stepping/coupledtimestepper_tmpl.cc
deleted file mode 100644
index 3df79591..00000000
--- a/src/time-stepping/coupledtimestepper_tmpl.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef MY_DIM
-#error MY_DIM unset
-#endif
-
-#include "../explicitgrid.hh"
-#include "../explicitvectors.hh"
-
-#include <dune/solvers/norms/energynorm.hh>
-
-#include "../spatial-solving/solverfactory_tmpl.cc"
-#include "../data-structures/contactnetwork_tmpl.cc"
-
-#include "rate/rateupdater.hh"
-#include "state/stateupdater.hh"
-#include "updaters.hh"
-
-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 ErrorNorms = typename MyContactNetwork::StateEnergyNorms;
-
-
-template class CoupledTimeStepper<MySolverFactory, MyContactNetwork, MyUpdaters, ErrorNorms>;
diff --git a/todo.txt b/todo.txt
deleted file mode 100644
index 1a337f71..00000000
--- a/todo.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-------------
---  ToDo  --
-------------
-
-
-1. LevelContactNetwork
-
-    
-1. build n-body system 
-    Data structure: LevelContactNetwork
-    Factories:      StackedBlocksFactory
-    
-    - extend to multilevel LevelContactNetwork
-    - write new multilevel Cantor network factory
-    
-2. initialize/set up program state
-    Data structure: ProgramState
-    
-    - test setupInitialConditions()
-
-3. assemble RSD friction
-
-4. set up TNNMG solver
-    - rate updater
-    - state updater
-    
-5. adaptive time stepper
-
-
-- 
GitLab