diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 373792ddb6765373c36941a89a150045c381666d..debb516bb7b190057c222e4488f448070e3219e9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,5 @@
 set(SOURCE_FILES
+  adaptivetimestepper.cc
   assemblers.cc
   boundary_writer.cc
   coupledtimestepper.cc
diff --git a/src/adaptivetimestepper.cc b/src/adaptivetimestepper.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2739e711c784b61b40b6f2cfc8efbf47a8f71989
--- /dev/null
+++ b/src/adaptivetimestepper.cc
@@ -0,0 +1,121 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "adaptivetimestepper.hh"
+
+template <class Factory, class Updaters, class ErrorNorm>
+AdaptiveTimeStepper<Factory, Updaters, ErrorNorm>::AdaptiveTimeStepper(
+    Factory &factory, Dune::ParameterTree const &parset,
+    std::shared_ptr<Nonlinearity> globalFriction, Updaters &current,
+    double relativeTime, double relativeTau,
+    std::function<void(double, Vector &)> externalForces,
+    ErrorNorm const &errorNorm,
+    std::function<bool(Updaters &, Updaters &)> mustRefine)
+    : relativeTime_(relativeTime),
+      relativeTau_(relativeTau),
+      finalTime_(parset.get<double>("problem.finalTime")),
+      factory_(factory),
+      parset_(parset),
+      globalFriction_(globalFriction),
+      current_(current),
+      R1_(current_.clone()),
+      externalForces_(externalForces),
+      mustRefine_(mustRefine),
+      iterationWriter_("iterations", std::fstream::out),
+      errorNorm_(errorNorm) {
+  MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
+                                          globalFriction_, R1_, errorNorm,
+                                          externalForces_);
+  stepAndReport("R1", coupledTimeStepper, relativeTime_, relativeTau_);
+  iterationWriter_ << std::endl;
+}
+
+template <class Factory, class Updaters, class ErrorNorm>
+bool AdaptiveTimeStepper<Factory, Updaters, ErrorNorm>::reachedEnd() {
+  return relativeTime_ >= 1.0;
+}
+
+template <class Factory, class Updaters, class ErrorNorm>
+bool AdaptiveTimeStepper<Factory, Updaters, ErrorNorm>::coarsen() {
+  bool didCoarsen = false;
+
+  while (relativeTime_ + relativeTau_ < 1.0) {
+    R2_ = R1_.clone();
+    {
+      MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
+                                              globalFriction_, R2_, errorNorm_,
+                                              externalForces_);
+      stepAndReport("R2", coupledTimeStepper, relativeTime_ + relativeTau_,
+                    relativeTau_);
+    }
+
+    Updaters C = current_.clone();
+    {
+      MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
+                                              globalFriction_, C, errorNorm_,
+                                              externalForces_);
+
+      stepAndReport("C", coupledTimeStepper, relativeTime_, 2.0 * relativeTau_);
+    }
+
+    if (!mustRefine_(C, R2_)) {
+      R2_ = { nullptr, nullptr };
+      R1_ = C;
+      relativeTau_ *= 2.0;
+      didCoarsen = true;
+    } else {
+      break;
+    }
+  }
+  return didCoarsen;
+}
+
+template <class Factory, class Updaters, class ErrorNorm>
+void AdaptiveTimeStepper<Factory, Updaters, ErrorNorm>::refine() {
+  while (true) {
+    Updaters F2 = current_.clone();
+    Updaters F1;
+    {
+      MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
+                                              globalFriction_, F2, errorNorm_,
+                                              externalForces_);
+      stepAndReport("F1", coupledTimeStepper, relativeTime_,
+                    relativeTau_ / 2.0);
+
+      F1 = F2.clone();
+      stepAndReport("F2", coupledTimeStepper,
+                    relativeTime_ + relativeTau_ / 2.0, relativeTau_ / 2.0);
+    }
+
+    if (!mustRefine_(R1_, F2)) {
+      break;
+    } else {
+      R1_ = F1;
+      R2_ = F2;
+      relativeTau_ /= 2.0;
+    }
+  }
+}
+
+template <class Factory, class Updaters, class ErrorNorm>
+void AdaptiveTimeStepper<Factory, Updaters, ErrorNorm>::advance() {
+  if (!coarsen())
+    refine();
+
+  iterationWriter_ << std::endl;
+
+  current_ = R1_;
+  R1_ = R2_;
+  relativeTime_ += relativeTau_;
+}
+
+template <class Factory, class Updaters, class ErrorNorm>
+void AdaptiveTimeStepper<Factory, Updaters, ErrorNorm>::stepAndReport(
+    std::string type, MyCoupledTimeStepper &stepper, double rTime,
+    double rTau) {
+  iterationWriter_ << type << " " << stepper.step(rTime, rTau) << " "
+                   << std::flush;
+}
+
+#include "adaptivetimestepper_tmpl.cc"
diff --git a/src/adaptivetimestepper.hh b/src/adaptivetimestepper.hh
index c8b9a02978765686caf30a87045d17368e30b3cc..7fa6298c33cb6848948ab131432b3d347c7a83e0 100644
--- a/src/adaptivetimestepper.hh
+++ b/src/adaptivetimestepper.hh
@@ -1,3 +1,8 @@
+#ifndef SRC_ADAPTIVETIMESTEPPER_HH
+#define SRC_ADAPTIVETIMESTEPPER_HH
+
+#include <fstream>
+
 #include "coupledtimestepper.hh"
 
 template <class Factory, class Updaters, class ErrorNorm>
@@ -15,109 +20,19 @@ class AdaptiveTimeStepper {
                       double relativeTau,
                       std::function<void(double, Vector &)> externalForces,
                       ErrorNorm const &errorNorm,
-                      std::function<bool(Updaters &, Updaters &)> mustRefine)
-      : relativeTime_(relativeTime),
-        relativeTau_(relativeTau),
-        finalTime_(parset.get<double>("problem.finalTime")),
-        factory_(factory),
-        parset_(parset),
-        globalFriction_(globalFriction),
-        current_(current),
-        R1_(current_.clone()),
-        externalForces_(externalForces),
-        mustRefine_(mustRefine),
-        iterationWriter_("iterations", std::fstream::out),
-        errorNorm_(errorNorm) {
-    MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
-                                            globalFriction_, R1_, errorNorm,
-                                            externalForces_);
-    stepAndReport("R1", coupledTimeStepper, relativeTime_, relativeTau_);
-    iterationWriter_ << std::endl;
-  }
-
-  bool reachedEnd() { return relativeTime_ >= 1.0; }
-
-  bool coarsen() {
-    bool didCoarsen = false;
-
-    while (relativeTime_ + relativeTau_ < 1.0) {
-      R2_ = R1_.clone();
-      {
-        MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
-                                                globalFriction_, R2_,
-                                                errorNorm_, externalForces_);
-        stepAndReport("R2", coupledTimeStepper, relativeTime_ + relativeTau_,
-                      relativeTau_);
-      }
-
-      Updaters C = current_.clone();
-      {
-        MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
-                                                globalFriction_, C, errorNorm_,
-                                                externalForces_);
-
-        stepAndReport("C", coupledTimeStepper, relativeTime_,
-                      2.0 * relativeTau_);
-      }
-
-      if (!mustRefine_(C, R2_)) {
-        R2_ = { nullptr, nullptr };
-        R1_ = C;
-        relativeTau_ *= 2.0;
-        didCoarsen = true;
-      } else {
-        break;
-      }
-    }
-    return didCoarsen;
-  }
-
-  void refine() {
-    while (true) {
-      Updaters F2 = current_.clone();
-      Updaters F1;
-      {
-        MyCoupledTimeStepper coupledTimeStepper(finalTime_, factory_, parset_,
-                                                globalFriction_, F2, errorNorm_,
-                                                externalForces_);
-        stepAndReport("F1", coupledTimeStepper, relativeTime_,
-                      relativeTau_ / 2.0);
-
-        F1 = F2.clone();
-        stepAndReport("F2", coupledTimeStepper,
-                      relativeTime_ + relativeTau_ / 2.0, relativeTau_ / 2.0);
-      }
-
-      if (!mustRefine_(R1_, F2)) {
-        break;
-      } else {
-        R1_ = F1;
-        R2_ = F2;
-        relativeTau_ /= 2.0;
-      }
-    }
-  }
-
-  void advance() {
-    if (!coarsen())
-      refine();
-
-    iterationWriter_ << std::endl;
+                      std::function<bool(Updaters &, Updaters &)> mustRefine);
 
-    current_ = R1_;
-    R1_ = R2_;
-    relativeTime_ += relativeTau_;
-  }
+  bool reachedEnd();
+  bool coarsen();
+  void refine();
+  void advance();
 
   double relativeTime_;
   double relativeTau_;
 
 private:
   void stepAndReport(std::string type, MyCoupledTimeStepper &stepper,
-                     double rTime, double rTau) {
-    iterationWriter_ << type << " " << stepper.step(rTime, rTau) << " "
-                     << std::flush;
-  }
+                     double rTime, double rTau);
 
   double finalTime_;
   Factory &factory_;
@@ -131,3 +46,4 @@ class AdaptiveTimeStepper {
   std::fstream iterationWriter_;
   ErrorNorm const &errorNorm_;
 };
+#endif
diff --git a/src/adaptivetimestepper_tmpl.cc b/src/adaptivetimestepper_tmpl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..45eb2de313573ae0fdef5b6a6a7fc6fdaca8b537
--- /dev/null
+++ b/src/adaptivetimestepper_tmpl.cc
@@ -0,0 +1,32 @@
+#ifndef MY_DIM
+#error MY_DIM unset
+#endif
+
+#include <dune/common/function.hh>
+
+#include <dune/solvers/norms/energynorm.hh>
+#include <dune/tnnmg/problem-classes/convexproblem.hh>
+
+#include <dune/tectonic/globalfriction.hh>
+#include <dune/tectonic/myblockproblem.hh>
+
+#include "explicitgrid.hh"
+#include "explicitvectors.hh"
+
+#include "rate/rateupdater.hh"
+#include "solverfactory.hh"
+#include "state/stateupdater.hh"
+#include "updaters.hh"
+
+using Function = Dune::VirtualFunction<double, double>;
+using Factory = SolverFactory<
+    MY_DIM,
+    MyBlockProblem<ConvexProblem<GlobalFriction<Matrix, Vector>, Matrix>>,
+    Grid>;
+using MyStateUpdater = StateUpdater<ScalarVector, Vector>;
+using MyRateUpdater = RateUpdater<Vector, Matrix, Function, MY_DIM>;
+using MyUpdaters = Updaters<MyRateUpdater, MyStateUpdater>;
+
+using ErrorNorm = EnergyNorm<ScalarMatrix, ScalarVector>;
+
+template class AdaptiveTimeStepper<Factory, MyUpdaters, ErrorNorm>;
diff --git a/src/sand-wedge.cc b/src/sand-wedge.cc
index 47dff61d8f1399eff7c47ac7e171d08e1adbd1da..675110ac0258b096e635dc7c883aeb10f942df85 100644
--- a/src/sand-wedge.cc
+++ b/src/sand-wedge.cc
@@ -52,7 +52,7 @@
 #include <dune/tectonic/myblockproblem.hh>
 #include <dune/tectonic/globalfriction.hh>
 
-#include "adaptivetimestepper.hh" // FIXME
+#include "adaptivetimestepper.hh"
 #include "assemblers.hh"
 #include "distances.hh"
 #include "enumparser.hh"