From 1094fd78a5d95fbc650b3196fe7aefa9cc5633d5 Mon Sep 17 00:00:00 2001
From: Elias Pipping <elias.pipping@fu-berlin.de>
Date: Wed, 5 Sep 2012 16:11:54 +0200
Subject: [PATCH] Add a two-step implicit time stepping scheme

---
 src/one-body-sample.cc     | 174 +++++++++++++++++++++++++++++++++----
 src/one-body-sample.parset |   2 +
 src/one-body-sample.py     |  12 +--
 3 files changed, 162 insertions(+), 26 deletions(-)

diff --git a/src/one-body-sample.cc b/src/one-body-sample.cc
index a39f1f2b..aa9e475a 100644
--- a/src/one-body-sample.cc
+++ b/src/one-body-sample.cc
@@ -101,6 +101,119 @@ void setup_boundary(GridView const &gridView,
   }
 }
 
+// Implicit Euler: Solve the problem
+//
+// a(Delta u_new, v - Delta u_new) + j_tau(v) - j_tau(Delta u_new)
+// >= l(w - Delta u_new) - a(u_new, v - Delta u_new)
+//
+// Setup: Substract a(u_new, .) from rhs
+template <class VectorType, class MatrixType, class FunctionType, int dim>
+void implicitEulerSetup(VectorType const &ell, MatrixType const &A,
+                        VectorType const &u_old, VectorType const *u_old_old,
+                        VectorType &problem_rhs, VectorType &problem_iterate,
+                        MatrixType &problem_A,
+                        Dune::BitSetVector<dim> const &dirichletNodes,
+                        FunctionType const &dirichletFunction, double time) {
+  problem_A = A;
+  problem_rhs = ell;
+  problem_A.mmv(u_old, problem_rhs);
+
+  problem_iterate = u_old;
+  if (u_old_old)
+    problem_iterate -= *u_old_old;
+
+  for (size_t i = 0; i < dirichletNodes.size(); ++i)
+    if (dirichletNodes[i].count() == dim) {
+      double val;
+      dirichletFunction.evaluate(time, val);
+      problem_iterate[i] = 0;                    // Everything prescribed
+      problem_iterate[i][0] = val - u_old[i][0]; // Time-dependent X direction
+    } else if (dirichletNodes[i][1])
+      problem_iterate[i][1] = 0; // Y direction described
+}
+
+// Extraction: Add previous solution
+template <class VectorType>
+void implicitEulerExtract(VectorType const &u_old, VectorType const *u_old_old,
+                          VectorType const &problem_iterate,
+                          VectorType &solution) {
+  solution = u_old;
+  solution += problem_iterate;
+}
+
+template <class VectorType>
+void implicitEulerExtractVelocity(VectorType const &u_old,
+                                  VectorType const *u_old_old,
+                                  VectorType const &problem_iterate,
+                                  VectorType &diff) {
+  diff = problem_iterate;
+}
+
+// two-Stage implicit algorithm: Solve the problem
+//
+// a(Delta u_new, v - Delta u_new) + j_tau(v) - j_tau(Delta u_new)
+// >= l(w - Delta u_new) - a(u_new, v - Delta u_new)
+//
+// Setup: Substract a(u_new, .) from rhs
+template <class VectorType, class MatrixType, class FunctionType, int dim>
+void twoStageImplicitSetup(VectorType const &ell, MatrixType const &A,
+                           VectorType const &u_old, VectorType const *u_old_old,
+                           VectorType &problem_rhs, VectorType &problem_iterate,
+                           MatrixType &problem_A,
+                           Dune::BitSetVector<dim> const &dirichletNodes,
+                           FunctionType const &dirichletFunction, double time) {
+  problem_A = A;
+  problem_A /= 1.5;
+  problem_rhs = ell;
+  problem_A.usmv(-2, u_old, problem_rhs);
+  problem_A.usmv(.5, *u_old_old, problem_rhs);
+
+  // The finite difference makes a good start
+  problem_iterate = u_old;
+  problem_iterate -= *u_old_old;
+
+  for (size_t i = 0; i < dirichletNodes.size(); ++i)
+    if (dirichletNodes[i].count() == dim) {
+      double val;
+      dirichletFunction.evaluate(time, val);
+      problem_iterate[i] = 0;
+      problem_iterate[i].axpy(-2, u_old[i]);
+      problem_iterate[i].axpy(.5, (*u_old_old)[i]);
+      problem_iterate[i][0] =
+          1.5 * val - 2 * u_old[i][0] + .5 * (*u_old_old)[i][0];
+    } else if (dirichletNodes[i][1])
+      // Y direction described
+      problem_iterate[i][1] = -2 * u_old[i][1] + .5 * (*u_old_old)[i][1];
+}
+
+template <class VectorType>
+void twoStageImplicitExtract(VectorType const &u_old,
+                             VectorType const *u_old_old,
+                             VectorType const &problem_iterate,
+                             VectorType &solution) {
+  solution = problem_iterate;
+  solution.axpy(2, u_old);
+  solution.axpy(-.5, *u_old_old);
+  solution *= 2.0 / 3.0;
+
+  // Check if we split correctly
+  {
+    VectorType test = problem_iterate;
+    test.axpy(-1.5, solution);
+    test.axpy(+2, u_old);
+    test.axpy(-.5, *u_old_old);
+    assert(test.two_norm() < 1e-10);
+  }
+}
+
+template <class VectorType>
+void twoStageImplicitExtractVelocity(VectorType const &u_old,
+                                     VectorType const *u_old_old,
+                                     VectorType const &problem_iterate,
+                                     VectorType &diff) {
+  diff = problem_iterate;
+}
+
 int main(int argc, char *argv[]) {
   try {
     typedef SharedPointerMap<std::string, Dune::VirtualFunction<double, double>>
@@ -191,15 +304,18 @@ int main(int argc, char *argv[]) {
     // {{{ Initialise vectors
     VectorType u(finestSize);
     u = 0.0; // Has to be zero!
+    VectorType u_previous;
     VectorType u_diff(finestSize);
     u_diff = 0.0; // Has to be zero!
 
+    // temporary storage for u
+    VectorType solution(finestSize);
+
     SingletonVectorType alpha_old(finestSize);
     alpha_old = parset.get<double>("boundary.friction.state.initial");
     SingletonVectorType alpha(alpha_old);
 
     SingletonVectorType vonMisesStress;
-    VectorType rhs;
     // }}}
 
     typedef MyConvexProblem<MatrixType, VectorType> MyConvexProblemType;
@@ -244,36 +360,61 @@ int main(int argc, char *argv[]) {
     for (size_t run = 1; run <= timesteps; ++run) {
       double const time = tau * run;
       {
+        VectorType ell(finestSize);
         assemble_neumann<GridType, GridView, SmallVector, P1Basis>(
-            leafView, p1Basis, neumannNodes, rhs, neumannFunction, time);
-        stiffnessMatrix.mmv(u, rhs);
-        // Apply Dirichlet condition
-        for (size_t i = 0; i < finestSize; ++i)
-          if (ignoreNodes[i].count() == dim) {
-            dirichletFunction.evaluate(time, u_diff[i][0]);
-            u_diff[i][0] /= timesteps;
-          }
+            leafView, p1Basis, neumannNodes, ell, neumannFunction, time);
+
+        MatrixType problem_A;
+        VectorType problem_rhs(finestSize);
+        VectorType problem_iterate(finestSize);
+
+        auto setupFunc =
+            (run == 1 || !parset.get<bool>("twoStageImplicit"))
+                ? &implicitEulerSetup<VectorType, MatrixType,
+                                      decltype(dirichletFunction), dim>
+                : &twoStageImplicitSetup<VectorType, MatrixType,
+                                         decltype(dirichletFunction), dim>;
 
+        VectorType *u_old_old_ptr = (run == 1) ? nullptr : &u_previous;
+        setupFunc(ell, stiffnessMatrix, u, u_old_old_ptr, problem_rhs,
+                  problem_iterate, problem_A, ignoreNodes, dirichletFunction,
+                  time);
+
+        VectorType solution_saved = u;
         auto const state_fpi_max =
             parset.get<size_t>("solver.tnnmg.fixed_point_iterations");
         for (size_t state_fpi = 1; state_fpi <= state_fpi_max; ++state_fpi) {
           auto myGlobalNonlinearity =
               assemble_nonlinearity<MatrixType, VectorType>(
                   parset.sub("boundary.friction"), *nodalIntegrals, alpha, tau);
-          MyConvexProblemType const myConvexProblem(stiffnessMatrix,
-                                                    *myGlobalNonlinearity, rhs);
 
+          MyConvexProblemType const myConvexProblem(
+              problem_A, *myGlobalNonlinearity, problem_rhs);
           MyBlockProblemType myBlockProblem(parset, myConvexProblem);
           auto multigridStep = mySolver.getSolver();
-          multigridStep->setProblem(u_diff, myBlockProblem);
+          multigridStep->setProblem(problem_iterate, myBlockProblem);
 
-          VectorType const u_diff_saved = u_diff;
           LoopSolver<VectorType> overallSolver(
               multigridStep, parset.get<size_t>("solver.tnnmg.maxiterations"),
               solver_tolerance, &energyNorm, verbosity,
               false); // absolute error
           overallSolver.solve();
 
+          auto extractFunc = (run == 1 || !parset.get<bool>("twoStageImplicit"))
+                                 ? implicitEulerExtract<VectorType>
+                                 : twoStageImplicitExtract<VectorType>;
+
+          // Extract solution from solver
+          extractFunc(u, u_old_old_ptr, problem_iterate, solution);
+
+          auto extractDiffFunc =
+              (run == 1 || !parset.get<bool>("twoStageImplicit"))
+                  ? implicitEulerExtractVelocity<VectorType>
+                  : twoStageImplicitExtractVelocity<VectorType>;
+
+          // Extract difference from solver
+          extractDiffFunc(u, u_old_old_ptr, problem_iterate, u_diff);
+
           // Update the state
           for (size_t i = 0; i < frictionalNodes.size(); ++i) {
             if (frictionalNodes[i][0]) {
@@ -299,9 +440,11 @@ int main(int argc, char *argv[]) {
             std::cerr << '.';
             std::cerr.flush();
           }
-          if (energyNorm.diff(u_diff_saved, u_diff) <
+          if (energyNorm.diff(solution_saved, solution) <
               parset.get<double>("solver.tnnmg.fixed_point_tolerance"))
             break;
+          else
+            solution_saved = solution;
 
           if (state_fpi == state_fpi_max)
             std::cerr << "[ref = " << refinements
@@ -363,7 +506,8 @@ int main(int argc, char *argv[]) {
             std::cout << u_diff[i][0] * timesteps << " ";
         std::cout << std::endl;
       }
-      u += u_diff;
+      u_previous = u;
+      u = solution;
       alpha_old = alpha;
 
       // Compute von Mises stress and write everything to a file
diff --git a/src/one-body-sample.parset b/src/one-body-sample.parset
index 63bfca90..3a623491 100644
--- a/src/one-body-sample.parset
+++ b/src/one-body-sample.parset
@@ -13,6 +13,8 @@ printVelocitySteppingComparison = false
 
 enable_timer = false
 
+twoStageImplicit = false
+
 [grid]
 refinements = 4
 
diff --git a/src/one-body-sample.py b/src/one-body-sample.py
index e6db78f3..77b2f491 100644
--- a/src/one-body-sample.py
+++ b/src/one-body-sample.py
@@ -13,17 +13,7 @@ class neumannCondition:
 
 class dirichletCondition:
     def __call__(self, x):
-        return .005
-        # return 0
-        fst = 3e-1
-        snd = 5e-1
-        trd = 3e-1
-        if x < 1.0/5:
-            return fst
-        elif x < 3.0/5:
-            return snd
-        else:
-            return trd
+        return x * .005
 
 Functions = {
     'neumannCondition' : neumannCondition(),
-- 
GitLab