diff --git a/data/2d-dip-contours-performance.tikz b/data/2d-dip-contours-performance.tikz
new file mode 100644
index 0000000000000000000000000000000000000000..b3aaffa788381122f5e0c78342f3adfbf14afc16
--- /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 0000000000000000000000000000000000000000..9717932db47cabec416871f3a03ad28836ae3042
--- /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 0000000000000000000000000000000000000000..21f13f598b8fc05ea9339efec2553958dc794cf1
--- /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 0000000000000000000000000000000000000000..a144cefee0bd363893e71ab185227634747ad32b
--- /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 0000000000000000000000000000000000000000..24b77cf4e14f72e136334b6c852f363efe825f12
--- /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 0000000000000000000000000000000000000000..9eba91b8dd26eebd8955c789db82b74be73b6ea4
--- /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 0000000000000000000000000000000000000000..0bd999b93532365192a8791570a6963fb17a1f86
--- /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 0000000000000000000000000000000000000000..9f087cc48e6ffebda54f840234f3640d97e7dd16
--- /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 0000000000000000000000000000000000000000..a3a37a49ee4e8a594affaebd9e10bb6f7aa7213c
--- /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 0000000000000000000000000000000000000000..32594a4be1b5e031a02c20e24d0340e69a24c1b7
--- /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 0000000000000000000000000000000000000000..8df3189579d0dd746cfc6d1a31cad469b83df4f9
--- /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 0000000000000000000000000000000000000000..eaadd61bc4f290aafebda289e2f7330ab7bf79fb
--- /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 0000000000000000000000000000000000000000..45f6bc94b2088a2da58a5de9c89730822d15e428
--- /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 0000000000000000000000000000000000000000..2e2d9cb1c4e78beec3a4ed16f2c6768685a74457
--- /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 0000000000000000000000000000000000000000..e24d742de120650bea5d5f0ae19cf5b73151d44b
--- /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 0000000000000000000000000000000000000000..b1e3456f9b76eab8e3ff8675830923b4dcfc53c8
--- /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 0000000000000000000000000000000000000000..be7f8c798c97e088b3eb4d2f03290283c985034d
--- /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 0000000000000000000000000000000000000000..c9e461a0074cfbf873b08e83b02544e9c2db7d2e
--- /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 0000000000000000000000000000000000000000..1fd383931417a7bdecdcaabc9cfabfb83c87025e
--- /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 0000000000000000000000000000000000000000..04b36652d5611d468be9ab3c552a471e60eea09d
--- /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 0000000000000000000000000000000000000000..fffe5e28efc3dd2c2d7d142f360ffb87453a62a9
--- /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 0000000000000000000000000000000000000000..1442e4e6441ca57aaae12607e2ba64996638297b
--- /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 0000000000000000000000000000000000000000..0f3ab59ce6abdc57c32e2f06b148a5a00a9bf50c
--- /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 0000000000000000000000000000000000000000..dd44112ca5a8f7fe85624fbfdfbb76961e0fe0e4
--- /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 0000000000000000000000000000000000000000..d795a5caedb1227e5b47da77bc2852b7bc46e6f5
--- /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 0000000000000000000000000000000000000000..f50845ea7a72f9cc9d2ad130415202df9394caa3
--- /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 0000000000000000000000000000000000000000..9c43c0503a1bc3e9af6214d605ed307d5d7885f3
--- /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 0000000000000000000000000000000000000000..320720cf056e90ae72716af293e5f2232ad6de92
--- /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 0000000000000000000000000000000000000000..f4bed78be342adc51d5ba944b01a802296c243b7
--- /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 0000000000000000000000000000000000000000..6bf2e29c96241a2af657abb4faa4233d3a0d9c58
--- /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 0000000000000000000000000000000000000000..698b649848329ea192b62ff76502447ad053b4db
--- /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 0000000000000000000000000000000000000000..5294e563d99c149fe580368c9df415f73e7bf0d9
--- /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 0000000000000000000000000000000000000000..940765c2d1a55074308c986d6b232c7458404ca3
--- /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 0000000000000000000000000000000000000000..3e9498c05dc4425918d4351095cd86a807f2c562
--- /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 0000000000000000000000000000000000000000..3b4833d65cefddead8f84c8d368113edc07a3c4f
--- /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 0000000000000000000000000000000000000000..9394bf5ffdf32afe3a182b07547a2936cfce9d54
--- /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 0000000000000000000000000000000000000000..259ae8dbe47c9706bf3ad7e21670e12ad7a0a2c9
--- /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 52c9f30954d86f677012aa80c396b20fc96592eb..de041accbf959ae3928646a83ab796ed97e1545a 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 1160fd590d8f91deaef6287a159d846ae536c350..609436ca6d4f5b0a2192d1414f373032704b9e2b 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 695a94af7d92f1319247e48d3b8aa43ed576d03f..df0b3cd61d26f298253348f8c8292ae5a7a4092e 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 0000000000000000000000000000000000000000..2a5db4e93898e27864344b22ce34545954fc5b16
--- /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 0000000000000000000000000000000000000000..699e013f0fc1cb434cb777c6d5a3701c138e351d
--- /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 6b5463cd6669f231a57cc7ee6c871c48551a16bf..74809e5048f1b488baf4226da9d9473fb9f1721a 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 d2a5dab1b259d908b93c84ba994b59af6d491252..26ebfd64f022592a89001f441a65552bb60a187a 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 0000000000000000000000000000000000000000..a9f8efd5638be67ab9e61083de5ad810cfc2cb15
--- /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 7eb36871f961e616fa393e812e7550a6121ed601..a4102b8ec6ca9e9dd4c05aa774071be9a94e63fa 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 2ed879b301e9753914fcfff75e048326f8a53980..8b98b22b11c46637389fb6875d7e8fac3c804069 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 83395851e8d44379d1abfa05045169556f010381..f3dbabc79a81ad003f20f703b1780ccec9368118 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 0fffac2c6f2da295bef86d5c39c27224f866d9e4..7646bfcf3822937d4d7d174c8e2149f605140646 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 078bd85dc9cf1ab19e5a7427ecd160a91dc3f9aa..0d007d8e26b8293bb82fd16704221d793b35bc94 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 f2fb36ee4073e9a8e56e887469a58eece0c20689..67b7f2823a6ec677e37923fa69244683512505a1 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 0000000000000000000000000000000000000000..1cfc9596c2ea195640809cdd5f1532113ba70fcc
--- /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 84517f203a370cca87a3ecf6c58b2a5a2d39f29f..e369614c3fede5271a1d53334770d25aa10bc833 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 6fb2e48b703c705643bf2f7c2c663f182202f030..fc9f554ccfe1d7207cbf7c0d9f49ebbe91e0cfed 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 0000000000000000000000000000000000000000..9979e7c1e4f9856c526234cd6827182b404de582
--- /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 f7a34d4ab578bb78cb561a73956b9ea285420bd6..f0c81bdd8240f2cf620a8a12d86b5447a18d34fa 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 c4976718f5c835c377d5bf25c63453ae758a94d7..dc0b4de35f9873d9d211ca84832cb4cfe8904616 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 da253a7f458ee069251140dae1c227d88f47d93b..3445a319985801ab06ecb442f4f9f33f9f2801e9 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 ad0e796ebf07ab35938648b1578688ddf42eebb5..05198b414a7fdef54c0db0da14c89b991703d1c5 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 0000000000000000000000000000000000000000..b069d44ecd7aa139e575dab38614453c52a0b4b9
--- /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 c1968822164abc61d2854bfa09ca40d831803a45..e62425fd6446ed3289d098d59b40bb92f41d96a6 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 051afa4623f3fe9e13bb398bbd124b2a363a9402..6e6f5428d5a4658d36ddea4a446bcbc082f68839 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 b94718536d543a15f4575910f055a41747de2157..e8f9454f191023f7a0c2ac99582608dbd78a7246 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 7dded09dcad8dedd12b0220e3ac8666540ea931b..61275c639eca0d5bf9f88d88d2bec22b99eb9d47 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 e34055729335ffc00f47df7088c2719f7e5269a1..e72c7f1c77f50c5fc5e3e76f84c5fe853ec31d16 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 0000000000000000000000000000000000000000..f58defd7d1f47874e282569ec9b8ddc228173cf3
--- /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 0000000000000000000000000000000000000000..a02cd74a5d7f9351b7a4e647366b5cc1a4f516f4
--- /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 0000000000000000000000000000000000000000..4a373e81ebd218788caa0b28d466df499461ed77
--- /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 0000000000000000000000000000000000000000..c1aada259d784676cd81e738eab0012e7bf37341
--- /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 549062c706b1c617b779f0f6c884ace4aafb6bf7..dfb2b3aae6a5667907041e846f16e75359a0b936 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 66e3c048b7787a742fd3cd4797346b8cbbf3ea16..4edabd8b0a5d1efe61b310035b0e9efcee9f309a 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 0000000000000000000000000000000000000000..511ce68219d2969ae308ba866715f16c6d2fdb68
--- /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 19641aa5a4182b761a0373ae93965b2edc94f21e..0cb5e01ae17a7dc96121ba54310e199d13150759 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 82b394ea14a42f6902e95c1051682c5e9d4b3bd0..c7a38dda5f00b73272669717a12692bed56a8b8d 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 cd44653427a458c467a95ae8320d15ed3c86ab88..567c36e987002807c9797d53cd5b8fea81e9b2cc 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 7933b7d86f53191847f10d5571c028d61b26381f..0000000000000000000000000000000000000000
--- 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 78cf36f4036c67991866258eb0ebcad8c7e89838..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..8b9757651afab9ddefab43fc3b9e2ce494c53886
--- /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 f9e167ac4612408af492a2973914c8ae93807c19..2d47803538f33ea73ea26fb29452e469f6f00473 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 0000000000000000000000000000000000000000..e0fd59ba782da240ba71a80f550fb62082faef71
--- /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 2fe7b2b5d392ad4491d0516ea0d04698a0b8306f..3b86bc1085a60bca6c4e23269264cc79af67591a 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 5699835559a748c6b466a019fca94a263998051f..2b382ac192ac4e3e8d1525d01a8e07c39a1ceddc 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 874f4c6edadb6a6dff2e1db1b5e00cf303d66756..e3179f2a84c78e6eb87bd920c9c458ab68261956 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 574efa1d91b8adf046a1b090fa38effcd86a9e55..62b440f5068d51827bcd28065258df13b989550a 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 c0160dde33964101263ba0b70cd13ac7f4ce55d4..e50e1793dfb184c81536eba8dfb86191028f0ce0 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 7666a467ccfff0472f6bd71d5fe76f27d7441800..f416f4923653e80e5fe05278b7d5c6e268e6bcd6 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 9f3b8c9ec1342dd468f14741b6e6c895e106b324..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..75fd6237669e0022c8304dc463775b465c0887b7
--- /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 43df107c866393c0acc0a0a13fb02e355dd48f40..298e2f944109c5e1f75430344994faa9e13aa024 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 c4839a793b64bb3823004ff59718f067100d7a26..ae0912ada2180b9bd976b5eb4124544f9a17034a 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 0000000000000000000000000000000000000000..bae2cc32a6f0660e51c6d2f84a9729648b824d65
--- /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 0000000000000000000000000000000000000000..bcff7b9ff1be92af3c892c7ac15e61a368a73c23
--- /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 a515f6e5b6405f767168c5734995a0ccca108095..5ac982f601a73ec14aa1403f548a9aedbb41704e 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 b187da5372f084a446c27b99205c71db66d73d4f..88de3c3226f39bc19d7574ddf6446c107cb1ca34 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 1bb9ce37eaefac50b2fd523e54115d180538bbfb..347e2a22bd70770701aaf325d7a56f198129e505 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 61d4e7c06d5c157786fccf01964ad95018284910..855851e27fb48adf38b3b31f11882de07c6f08db 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 0000000000000000000000000000000000000000..321a96f3899dbe2715fec498a0d0e9e0d0262a5f
--- /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 3dbc81d5f01ca3e2dc3725ce2ee1a37ee2ee0321..06c478cf2779489ee660942718e1bc025ca933dd 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 0000000000000000000000000000000000000000..004253dbdeb7df55991ccee628df684a924e17cb
--- /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 703d0f9a962467a99c598f8f71565f809c75e39b..a93b65d882bba2949b1ec9e5304633e8b12a9d39 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 0000000000000000000000000000000000000000..73811d05768d03e7edf532087ef2ef106b134801
--- /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 0000000000000000000000000000000000000000..d86fa4858f39d4fc34b4eec0677ab383cd4b9bf2
--- /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 0000000000000000000000000000000000000000..ee2910cfa139c18bbdcb5dffdd7bf471a9ef2192
--- /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 b20047766e556f1c9b9fde9930ab5c27df4652bd..ef87c47fd75541469dd3517ec5512b832c27a5e0 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 ef3ad5a509aabfe8c60df072fc3b5185cb3529f7..07e919f71034436e521dab3d320c5e2e11bdb98d 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 0000000000000000000000000000000000000000..f316e155b1534e4751fcc7e0732f0fc64f311e28
--- /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 0000000000000000000000000000000000000000..79bad14fa28c8a8e4ad81ab41e7aed7aac78be3e
--- /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 ce090c012658d23ff9b34dd9f182ffe2421df013..391170a0f94f47dafa8a5f97be0967167cd3047a 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 0000000000000000000000000000000000000000..0e7cd4f96e51f8521b566f63b34fc1db4f014a42
--- /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 1df547741bee8de1cfb4e2b339f77b72badc8308..42659d4142bcd00f49efe27838605ed495d344e4 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 fc619036f26c54137f0d7a2c48d53f4fb593d6d4..07391d9f9a55cd5f6c8d3c3152fe3ee07ce01e76 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 0000000000000000000000000000000000000000..e09f3f893554f987b93f7d37114283d36e619950
--- /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 0000000000000000000000000000000000000000..a4b6508bcd00a70dede28d7fdebd4cfa306cbefe
--- /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 09299039f65c1b3e3ea4b02014d938560e6dec6a..b626865fa53053173c858e28b93bef1d7cf2cfab 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 771a1a0c324db0eb1bd29862dc100d479be30966..a2daf9d7ddbb3d2c3ca91790c0032266df4377f9 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 0000000000000000000000000000000000000000..9fe69dc16d1249f946458a9291fcc40c350d24c8
--- /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 0000000000000000000000000000000000000000..f23e54680b733bda6c050da350d99bdea7fb9933
--- /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 0000000000000000000000000000000000000000..5f51474a127c501485a9a7241cf5afd02c27ff5b
--- /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
Binary files /dev/null and b/dune/tectonic/time-stepping/state/explicit.pdf differ
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
Binary files /dev/null and b/dune/tectonic/time-stepping/state/explicit.synctex.gz differ
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 ed7a5241b491df82e903f104a5ab494c63ff6196..016e08c03042b887d9887ab5c97af53796ced090 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 39fd6bd485f4218ae3b2fb0e138d43a01fddc6aa..d4d9903841ae3b592a4c34ddb77df056cdcfbf00 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 0000000000000000000000000000000000000000..c5498570ef7e4d0d2cda6605b547975b838fb1fd
--- /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 a2db29cdfb2d6791876342fd694022dc111f93fb..0000000000000000000000000000000000000000
--- 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 b45d06d1d4300c6595585061b29d4baed13b2782..e41c1f9a41b515001c8da63b4485f9b83d67ec25 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 03374e6915298d572f79019039d60061af6732ac..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..ab24974cb7acf4b09d54775f2ab0f54963a0c01d
--- /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 a61cfba2e7668aeba078d447f55ac2edf83f28a8..6efcb38b3aa3637d41b65307d5c97f2cb2136428 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 0000000000000000000000000000000000000000..fe95424f3676d3797d2a0b3549a57870d8216edc
--- /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 0000000000000000000000000000000000000000..7c8016105e83a5a03566458f4be8128cd5a12a4a
--- /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 32d63b6e55cc1ee056dafdcaea8c784399ac177e..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..15a48074443bbe6fd2c7eddb2b8642b430148c77
--- /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 4f122195f6389a96bea5d4b8799e157ff147c0bb..641078a70876d7286c6691333b63f81740c6898d 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 4582a652eebaf6d4874b7d5d9770697d8a4f20f7..715acca3c6f7799397abd2b12653be5b36122969 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 eaade42018a6e0e4c1928ba41fe1af43f9632222..4be02c1cf175f8fbcaaf32e168f8117d6f2d73d6 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 3ff0794d1a6ddd68e3338995b925dea90a158f94..0000000000000000000000000000000000000000
--- 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 7c29cf087571f8aca3e98d987ad3e711e991122d..0000000000000000000000000000000000000000
--- 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 32d63b6e55cc1ee056dafdcaea8c784399ac177e..0000000000000000000000000000000000000000
--- 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 407b55f9bb2bb39657342c05661d067f48918d2d..0000000000000000000000000000000000000000
--- 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 6e98d2898468cf5ae06ab02c2a21be981b010558..0000000000000000000000000000000000000000
--- 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 fef8452a2c698e745ba5e8545df0a07188b02270..0000000000000000000000000000000000000000
--- 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 dbfa722ad47e92a1ba04ef8ed3fd932d86d4f36e..0000000000000000000000000000000000000000
--- 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 d92e7223b20d6e257b5dc3168169b93cdbfa8eb2..0000000000000000000000000000000000000000
--- 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 7188f73a0c0ab5b295a5aca2174c3087144ee1cc..0000000000000000000000000000000000000000
--- 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 3508048dc91d779e391f41743f2263528747ae22..0000000000000000000000000000000000000000
--- 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 acedf87ed2781d1c7b3a233e01d22cd0d336e4bb..0000000000000000000000000000000000000000
--- 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 72cdc867cffd4eba8091a0a2da0fa366e196627d..0000000000000000000000000000000000000000
--- 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 652ba03bf41ae67e17e764456f14869576fa20c3..0000000000000000000000000000000000000000
--- 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 59a653063be7f9758f58b7f0a1a6c9f756870203..0000000000000000000000000000000000000000
--- 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 b95f4cd1fc66565592485c632074ae186f7774e5..0000000000000000000000000000000000000000
--- 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 7336759ce77ba8ff4d3183a3f34f6bdbf5af4eb5..0000000000000000000000000000000000000000
--- 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 e683042b12f4a2e84ed1ea781d911b427d878e63..0000000000000000000000000000000000000000
--- 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 5f4b30cff6d376cb6550cb2388b1b176a61df764..0000000000000000000000000000000000000000
--- 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 00e132a99faa7bc54408ea5df6ead98b1a9c4cd5..0000000000000000000000000000000000000000
--- 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 8d202afce3305a1d7a294a60e60f67513ad1c680..0000000000000000000000000000000000000000
--- 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 017f981daf015689dfc33fac414ab24630fbe2c2..0000000000000000000000000000000000000000
--- 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 996e73605c18a0621b7bb0e0cfb004c3bd56fba2..0000000000000000000000000000000000000000
--- 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 d32080a39f211c3f91f60516d56274e94808dd29..0000000000000000000000000000000000000000
--- 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 5bf8d91811d7090899006998a1128b67a52ab06d..0000000000000000000000000000000000000000
--- 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 96aa6eccdfa4bf88cd88fcbc1e514555e4e2f211..0000000000000000000000000000000000000000
--- 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 fcb100f47dbda5697fc26954bd10e140e206bcde..0000000000000000000000000000000000000000
--- 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 3df79591219c4b017965e642c088cc922b676025..0000000000000000000000000000000000000000
--- 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 1a337f71f11c8961aa97e3238bb001b76ca36d85..0000000000000000000000000000000000000000
--- 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
-
-