diff --git a/dune/tectonic/spatial-solving/fixedpointiterator.cc b/dune/tectonic/spatial-solving/fixedpointiterator.cc
index bef1fea2ba3666075dbe5e1d0fbe6323737977a6..5b5c4c294d5e33aea18b6367bdba82e4027cf230 100644
--- a/dune/tectonic/spatial-solving/fixedpointiterator.cc
+++ b/dune/tectonic/spatial-solving/fixedpointiterator.cc
@@ -5,6 +5,7 @@
 #include <dune/common/exceptions.hh>
 
 #include <dune/matrix-vector/axpy.hh>
+#include <dune/solvers/norms/sumnorm.hh>
 
 #include <dune/tectonic/utils/reductionfactors.hh>
 
@@ -40,6 +41,49 @@ FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::FixedPointIte
       solverParset_(parset.sub("v.solver")),
       errorNorms_(errorNorms) {}
 
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+bool FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::displacementCriterion(const Updaters& updaters, std::vector<Vector>& last_u) const {
+    bool criterion = true;
+
+    std::vector<Vector> u;
+    updaters.rate_->extractDisplacement(u);
+
+    const auto& mats = updaters.rate_->getMatrices();
+
+    for (int i=0; i<u.size(); i++) {
+        const EnergyNorm<Matrix, Vector> ANorm(*mats.elasticity[i]), MNorm(*mats.mass[i]);
+        const SumNorm<Vector> AMNorm(1.0, ANorm, 1.0, MNorm);
+
+        if (u[i].size()==0 || last_u[i].size()==0)
+            continue;
+
+        if (AMNorm.diff(u[i], last_u[i]) >= fixedPointTolerance_) {
+            criterion = false;
+            break;
+        }
+    }
+
+    last_u = u;
+
+    return criterion;
+}
+
+template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
+bool FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::stateCriterion(const std::vector<ScalarVector>& alpha, const std::vector<ScalarVector>& newAlpha) const {
+    bool criterion = true;
+    for (int i=0; i<alpha.size(); i++) {
+        if (alpha[i].size()==0 || newAlpha[i].size()==0)
+            continue;
+
+        if (errorNorms_[i]->diff(alpha[i], newAlpha[i]) >= fixedPointTolerance_) {
+            criterion = false;
+            break;
+        }
+    }
+
+    return criterion;
+}
+
 template <class Factory, class NBodyAssembler, class Updaters, class ErrorNorms>
 template <class LinearSolver>
 FixedPointIterationCounter
@@ -48,16 +92,14 @@ FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run(
     const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs,
     std::vector<Vector>& velocityIterates) {
 
-  //std::cout << "FixedPointIterator::run()" << std::endl;
+    // debugging
+    /*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();
 
-  // debugging
-  /*const auto& contactCouplings = nBodyAssembler_.getContactCouplings();
-  for (size_t i=0; i<contactCouplings.size(); i++) {
-    print(*contactCouplings[i]->nonmortarBoundary().getVertices(), "nonmortarBoundaries:");
-  }*/
-
   FunctionalFactory<std::decay_t<decltype(nBodyAssembler_)>, decltype(globalFriction_), Matrix, Vector> functionalFactory(nBodyAssembler_, globalFriction_, velocityMatrices, velocityRHSs);
   functionalFactory.build();
   auto functional = functionalFactory.functional();
@@ -66,91 +108,60 @@ FixedPointIterator<Factory, NBodyAssembler, Updaters, ErrorNorms>::run(
 
   size_t fixedPointIteration;
   size_t multigridIterations = 0;
+
+  std::vector<Vector> last_u;
+  updaters.rate_->extractOldDisplacement(last_u);
+
   std::vector<ScalarVector> alpha(nBodies);
   updaters.state_->extractAlpha(alpha);
 
-  Vector totalVelocityIterate, old_v;
-  nBodyAssembler_.nodalToTransformed(velocityIterates, totalVelocityIterate);
-  old_v = totalVelocityIterate;
+  std::vector<Vector> v_o;
+  updaters.rate_->extractOldVelocity(v_o);
+
+  Vector total_v_o;
+  nBodyAssembler_.nodalToTransformed(v_o, total_v_o);
+
+  Vector total_v;
+  nBodyAssembler_.nodalToTransformed(velocityIterates, total_v);
 
   for (fixedPointIteration = 0; fixedPointIteration < fixedPointMaxIterations_;
        ++fixedPointIteration) {
 
-    //print(alpha, "alpha:");
-
-    // contribution from nonlinearity
+    // update friction
     globalFriction_.updateAlpha(alpha);
 
-    auto res = solver.solve(solverParset_, totalVelocityIterate);
-
-    nBodyAssembler_.postprocess(totalVelocityIterate, velocityIterates);
-    //nBodyAssembler_.postprocess(totalVelocityIterate, velocityIterates);
-
-    //print(totalVelocityIterate, "totalVelocityIterate:");
-    //print(velocityIterates, "velocityIterates:");
-
-    //DUNE_THROW(Dune::Exception, "Just need to stop here!");
-
+    // solve rate problem
+    auto res = solver.solve(solverParset_, total_v);
     multigridIterations += res.iterations;
 
-    Vector v_m = old_v;
+    Vector v_m = total_v_o;
     v_m *= 1.0 - lambda_;
-    Dune::MatrixVector::addProduct(v_m, lambda_, totalVelocityIterate);
+    Dune::MatrixVector::addProduct(v_m, lambda_, total_v);
 
     // extract relative velocities in mortar basis
     std::vector<Vector> v_rel;
     split(v_m, v_rel);
 
-    //print(v_m, "v_m: ");
-
-    //print(v_rel, "v_rel");
-
-    //std::cout << "- State problem set" << std::endl;
-
-    // solve a state problem
+    // solve state problem
     updaters.state_->solve(v_rel);
-
-    //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:");
-        if (errorNorms_[i]->diff(alpha[i], newAlpha[i]) >= fixedPointTolerance_) {
-            breakCriterion = false;
-            //std::cout << "fixedPoint error: " << errorNorms_[i]->diff(alpha[i], newAlpha[i]) << std::endl;
-            break;
-        }
-    }
-
-    //std::cout << fixedPointIteration << std::endl;
+    nBodyAssembler_.postprocess(total_v, velocityIterates);
+    updaters.rate_->postProcess(velocityIterates);
+    bool breakCriterion = displacementCriterion(updaters, last_u); //stateCriterion(alpha, newAlpha);
 
     if (lambda_ < 1e-12 or breakCriterion) {
-      //std::cout << "-FixedPointIteration finished! " << (lambda_ < 1e-12 ? "lambda" : "breakCriterion") << std::endl;
       fixedPointIteration++;
       break;
     }
     alpha = newAlpha;
   }
 
-  //TODO: recently added, might be wrong or superfluous
-  globalFriction_.updateAlpha(alpha);
-
-  //print(alpha, "alpha: ");
-
-  //std::cout << "-FixedPointIteration finished with " << fixedPointIteration << " iterations, lambda " << lambda_ <<  "! " << std::endl;
-
   if (fixedPointIteration == fixedPointMaxIterations_)
     DUNE_THROW(Dune::Exception, "FPI failed to converge");
 
+  nBodyAssembler_.postprocess(total_v, velocityIterates);
   updaters.rate_->postProcess(velocityIterates);
 
   // Cannot use return { fixedPointIteration, multigridIterations };
diff --git a/dune/tectonic/spatial-solving/fixedpointiterator.hh b/dune/tectonic/spatial-solving/fixedpointiterator.hh
index 3742ed987aefad6bd569a10611e6bbf3e7892106..d9a844e7db52ad7326935c5b55357d8532304f05 100644
--- a/dune/tectonic/spatial-solving/fixedpointiterator.hh
+++ b/dune/tectonic/spatial-solving/fixedpointiterator.hh
@@ -45,6 +45,8 @@ class FixedPointIterator {
 
 private:
   void split(const Vector& v, std::vector<Vector>& v_rel) const;
+  bool displacementCriterion(const Updaters& updaters, std::vector<Vector>& last_u) const;
+  bool stateCriterion(const std::vector<ScalarVector>& alpha, const std::vector<ScalarVector>& newAlpha) const;
 
 public:
   FixedPointIterator(const Dune::ParameterTree& parset,
diff --git a/dune/tectonic/time-stepping/rate/rateupdater.cc b/dune/tectonic/time-stepping/rate/rateupdater.cc
index 3b2d9272ec5a769d6ace38006a1fff547d0ba17c..d6cde5688423e7bf6e09f60cd96ba3ce62d80692 100644
--- a/dune/tectonic/time-stepping/rate/rateupdater.cc
+++ b/dune/tectonic/time-stepping/rate/rateupdater.cc
@@ -59,6 +59,12 @@ void RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>::extractAccel
     acceleration = a;
 }
 
+template <class Vector, class Matrix, class BoundaryFunctions, class BoundaryNodes>
+const Matrices<Matrix,2>& RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>::getMatrices() const {
+    return matrices;
+}
+
+
 #include "backward_euler.cc"
 #include "newmark.cc"
 #include "rateupdater_tmpl.cc"
diff --git a/dune/tectonic/time-stepping/rate/rateupdater.hh b/dune/tectonic/time-stepping/rate/rateupdater.hh
index 8a332206f1de86e96b6b47b65fb82ae3ff46fa55..7020b546a3a538c7eab07160afebe5784c559544 100644
--- a/dune/tectonic/time-stepping/rate/rateupdater.hh
+++ b/dune/tectonic/time-stepping/rate/rateupdater.hh
@@ -36,6 +36,8 @@ class RateUpdater {
   void extractOldVelocity(std::vector<Vector>& velocity) const;
   void extractAcceleration(std::vector<Vector>& acceleration) const;
 
+  const Matrices<Matrix,2>& getMatrices() const;
+
   std::shared_ptr<RateUpdater<Vector, Matrix, BoundaryFunctions, BoundaryNodes>> virtual clone() const = 0;
 
 protected: