diff --git a/src/one-body-sample.cc b/src/one-body-sample.cc
index db42af2df4b4afe693c56663c541e81eed96a2b8..ce74f64e102dbc5f5fe74722d70dc6365581f696 100644
--- a/src/one-body-sample.cc
+++ b/src/one-body-sample.cc
@@ -15,6 +15,8 @@
 
 #include "boost/format.hpp"
 
+#include <cmath>
+
 #include "LambertW.h"
 
 #include <dune/common/bitsetvector.hh>
@@ -58,6 +60,7 @@
 #include <dune/tectonic/globalruinanonlinearity.hh>
 #include <dune/tectonic/myconvexproblem.hh>
 #include <dune/tectonic/myblockproblem.hh>
+#include <dune/tectonic/mydirectionalconvexfunction.hh>
 #include <dune/grid/io/file/vtk/vtkwriter.hh>
 
 int const dim = 3;
@@ -180,6 +183,41 @@ assemble_nonlinearity(
   }
 }
 
+// The nonlinearity exp(-x)
+class DecayingExponential {
+public:
+  typedef Dune::FieldVector<double, 1> VectorType;
+  typedef Dune::FieldMatrix<double, 1, 1> MatrixType;
+
+  double operator()(VectorType const &u) const { return exp(-u[0]); }
+
+  void directionalSubDiff(VectorType const &u, VectorType const &v,
+                          Interval<double> &D) const {
+    D[0] = D[1] = v[0] * (-exp(-u[0]));
+  }
+
+  void directionalDomain(VectorType const &, VectorType const &,
+                         Interval<double> &dom) const {
+    dom[0] = -std::numeric_limits<double>::max();
+    dom[1] = std::numeric_limits<double>::max();
+  }
+};
+
+double compute_state_update_bisection(double h, double unorm, double L,
+                                      double old_state) {
+  MyDirectionalConvexFunction<DecayingExponential> const Jplus(
+      1.0 / h, (old_state - unorm / L) / h, DecayingExponential(), 0, 1);
+  int bisectionsteps = 0;
+  Bisection const bisection(0.0, 1.0, 1e-12, true, 0); // TODO
+  return bisection.minimize(Jplus, 0.0, 0.0, bisectionsteps);
+}
+
+double compute_state_update_lambert(double h, double unorm, double L,
+                                    double old_state) {
+  double const rhs = unorm / L - old_state;
+  return LambertW(0, h * exp(rhs)) - rhs;
+}
+
 int main(int argc, char *argv[]) {
   try {
     Dune::ParameterTree parset;
@@ -258,12 +296,21 @@ int main(int argc, char *argv[]) {
     VectorType u3 = u1;
     VectorType u4 = u1;
 
+    Dune::BlockVector<Dune::FieldVector<double, 1>> s4_old(
+        grid->size(grid->maxLevel(), dim));
+    s4_old = 50; // FIXME: magic value (-500 is still workable; -1000 is not)
+
     VectorType u1_diff(grid->size(grid->maxLevel(), dim));
     u1_diff = 0.0; // Has to be zero!
     VectorType u2_diff = u1_diff;
     VectorType u3_diff = u1_diff;
     VectorType u4_diff = u1_diff;
 
+    auto s4_new =
+        Dune::make_shared<Dune::BlockVector<Dune::FieldVector<double, 1>>>(
+            grid->size(grid->maxLevel(), dim));
+    *s4_new = s4_old;
+
     CellVectorType vonMisesStress;
 
     VectorType b1;
@@ -360,27 +407,47 @@ int main(int argc, char *argv[]) {
       u1 += u1_diff;
 
       if (parset.get<bool>("solver.tnnmg.use")) {
-        auto state =
-            Dune::make_shared<Dune::BlockVector<Dune::FieldVector<double, 1>>>(
-                grid->size(grid->maxLevel(), dim));
-        *state = 0.0;
-        auto myGlobalNonlinearity =
-            assemble_nonlinearity<VectorType, OperatorType>(
-                grid->size(grid->maxLevel(), dim), parset, nodalIntegrals,
-                state, h);
-        MyConvexProblemType myConvexProblem(stiffnessMatrix,
-                                            *myGlobalNonlinearity, b4);
-
-        MyBlockProblemType myBlockProblem(parset, myConvexProblem);
-        multigridStep.setProblem(u4_diff, myBlockProblem);
-
-        LoopSolver<VectorType> overallSolver(
-            &multigridStep, parset.get<size_t>("solver.tnnmg.maxiterations"),
-            solver_tolerance, &energyNorm, verbosity);
-        overallSolver.solve();
+        for (int state_fpi = 0; state_fpi < parset.get<int>("state.iterations");
+             ++state_fpi) {
+          auto myGlobalNonlinearity =
+              assemble_nonlinearity<VectorType, OperatorType>(
+                  grid->size(grid->maxLevel(), dim), parset, nodalIntegrals,
+                  s4_new, h);
+          MyConvexProblemType myConvexProblem(stiffnessMatrix,
+                                              *myGlobalNonlinearity, b4);
+
+          MyBlockProblemType myBlockProblem(parset, myConvexProblem);
+          multigridStep.setProblem(u4_diff, myBlockProblem);
+
+          LoopSolver<VectorType> overallSolver(
+              &multigridStep, parset.get<size_t>("solver.tnnmg.maxiterations"),
+              solver_tolerance, &energyNorm, verbosity);
+          overallSolver.solve();
+
+          if (parset.get<bool>("state.enable")) {
+            for (size_t i = 0; i < frictionalNodes.size(); ++i)
+              if (frictionalNodes[i][0]) {
+                double const L = 1e-4; // FIXME: magic value
+                double const unorm = u4_diff[i].two_norm();
+
+                double ret1 =
+                    compute_state_update_bisection(h, unorm, L, s4_old[i][0]);
+                assert(abs(1.0 / h * ret1 - (s4_old[i] - unorm / L) / h -
+                           exp(-ret1)) < 1e-12);
+                double ret2 =
+                    compute_state_update_lambert(h, unorm, L, s4_old[i][0]);
+                assert(abs(1.0 / h * ret2 - (s4_old[i] - unorm / L) / h -
+                           exp(-ret2)) < 1e-12);
+                assert(abs(ret2 - ret1) < 1e-14);
+
+                (*s4_new)[i][0] = ret1;
+              }
+          }
+        }
       }
 
       u4 += u4_diff;
+      s4_old = *s4_new;
 
       // Compute von Mises stress and write everything to a file
       if (parset.get<bool>("writeVTK")) {
diff --git a/src/one-body-sample.parset b/src/one-body-sample.parset
index 168373a2254da878201ddcc86cd3df3e317ae012..008757d6dea7e27358753d3ca1b171e6381edfdb 100644
--- a/src/one-body-sample.parset
+++ b/src/one-body-sample.parset
@@ -8,6 +8,10 @@ printDifference = false
 
 writeVTK = false
 
+[state]
+enable = true
+iterations = 6
+
 [grid]
 refinements = 3