From 7bb4bca8ea1f083231b736ef0973138d185bb61a Mon Sep 17 00:00:00 2001
From: podlesny <podlesny@mi.fu-berlin.de>
Date: Wed, 24 Jul 2019 17:32:04 +0200
Subject: [PATCH] add solverfactorytest

---
 src/CMakeLists.txt                            |  26 +
 src/data-structures/program_state.hh          |   2 +
 src/factories/stackedblocksfactory.cc         |   7 +-
 src/multi-body-problem-2D.cfg                 |   2 +-
 src/multi-body-problem-data/bc.hh             |   3 -
 src/obstaclesolver.hh                         |  48 ++
 src/solverfactorytest.cc                      | 756 ++++++++++++++++++
 src/spatial-solving/fixedpointiterator.cc     |   3 +
 src/spatial-solving/solverfactory.cc          |   9 +-
 src/spatial-solving/solverfactory.hh          |  13 +-
 src/spatial-solving/tnnmg/functional.hh       |  17 +-
 src/spatial-solving/tnnmg/linearcorrection.hh |  18 +-
 src/spatial-solving/tnnmg/tnnmgstep.hh        |  51 +-
 13 files changed, 903 insertions(+), 52 deletions(-)
 create mode 100644 src/obstaclesolver.hh
 create mode 100644 src/solverfactorytest.cc

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e7cf62d6..b9748ffc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -64,17 +64,42 @@ set(UGW_SOURCE_FILES
   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
+)
+
 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})
@@ -82,4 +107,5 @@ foreach(_dim 2 3)
   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 ${_ugw_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
+  set_property(TARGET ${_sft_target} APPEND PROPERTY COMPILE_DEFINITIONS "MY_DIM=${_dim}")
 endforeach()
diff --git a/src/data-structures/program_state.hh b/src/data-structures/program_state.hh
index 382c82b1..afe9075f 100644
--- a/src/data-structures/program_state.hh
+++ b/src/data-structures/program_state.hh
@@ -243,6 +243,8 @@ template <class VectorTEMPLATE, class ScalarVectorTEMPLATE> class ProgramState {
       solver.preprocess();
       solver.solve();
 
+      std::cout << "ProgramState: Energy of TNNMG solution: " << J(tnnmgStep->getSol()) << std::endl;
+
       nBodyAssembler.postprocess(tnnmgStep->getSol(), _x);
 
       Vector res = totalRhs;
diff --git a/src/factories/stackedblocksfactory.cc b/src/factories/stackedblocksfactory.cc
index 9f7fc32a..648518f3 100644
--- a/src/factories/stackedblocksfactory.cc
+++ b/src/factories/stackedblocksfactory.cc
@@ -73,10 +73,13 @@ void StackedBlocksFactory<HostGridType, VectorType>::setBodies() {
 
         for (size_t i=1; i<this->bodyCount_-1; i++) {
             origins[i] = cuboidGeometries_[i-1]->upperLeft();
+            auto height_i = height/3.0;
+
             GlobalCoords lowerWeakOrigin_i = lowerWeakOrigin + origins[i];
-            GlobalCoords upperWeakOrigin_i = upperWeakOrigin + origins[i];
+            GlobalCoords upperWeakOrigin_i = {upperWeakOrigin[0], height_i};
+            upperWeakOrigin_i += origins[i];
 
-            cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], length, height);
+            cuboidGeometries_[i] = std::make_shared<CuboidGeometry>(origins[i], length, height_i);
 
 
             cuboidGeometries_[i]->addWeakeningPatch(subParset, upperWeakOrigin_i, weakBound(upperWeakOrigin_i));
diff --git a/src/multi-body-problem-2D.cfg b/src/multi-body-problem-2D.cfg
index 9112827c..a4a77808 100644
--- a/src/multi-body-problem-2D.cfg
+++ b/src/multi-body-problem-2D.cfg
@@ -1,6 +1,6 @@
 # -*- mode:conf -*-
 [boundary.friction]
-smallestDiameter = 0.1  # 2e-3 [m]
+smallestDiameter = 0.25  # 2e-3 [m]
 
 [timeSteps]
 refinementTolerance = 1e-5 # 1e-5
diff --git a/src/multi-body-problem-data/bc.hh b/src/multi-body-problem-data/bc.hh
index 1b574cd6..c7c919ae 100644
--- a/src/multi-body-problem-data/bc.hh
+++ b/src/multi-body-problem-data/bc.hh
@@ -7,7 +7,6 @@ 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;
     
     std::cout << "VelocityDirichletCondition::evaluate()" << std::endl;
@@ -20,8 +19,6 @@ class VelocityDirichletCondition
     y = (relativeTime <= 0.1)
             ? finalVelocity * (1.0 - std::cos(relativeTime * M_PI / 0.1)) / 2.0
             : finalVelocity;
-            */
-      y = relativeTime;
   }
 };
 
diff --git a/src/obstaclesolver.hh b/src/obstaclesolver.hh
new file mode 100644
index 00000000..49b4d7cb
--- /dev/null
+++ b/src/obstaclesolver.hh
@@ -0,0 +1,48 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifndef DUNE_TECTONIC_OBSTACLESOLVER_HH
+#define DUNE_TECTONIC_OBSTACLESOLVER_HH
+
+#include "spatial-solving/tnnmg/localproblem.hh"
+
+
+/**
+ * \brief A local solver for quadratic obstacle problems
+ *
+ * \todo Add concept check for the function interface
+ */
+class ObstacleSolver
+{
+public:
+  template<class Vector, class Functional, class BitVector>
+  constexpr void operator()(Vector& x, const Functional& f, const BitVector& ignore) const
+  {
+      auto& A = f.quadraticPart();
+      auto& r = f.linearPart();
+
+      LocalProblem<std::decay_t<decltype(A)> , std::decay_t<decltype(r)>> localProblem(A, r, ignore);
+      Vector newR;
+      localProblem.getLocalRhs(x, newR);
+
+      auto directSolver = Dune::Solvers::UMFPackSolver<std::decay_t<decltype(A)>, std::decay_t<decltype(r)>>();
+
+      directSolver->setProblem(localProblem.getMat(), x, newR);
+      directSolver->preprocess();
+      directSolver->solve();
+
+      const auto& lower = f.lowerObstacle();
+      const auto& upper = f.upperObstacle();
+
+      for (size_t i=0; i<x.size(); i++) {
+        if (ignore[i][0])
+            continue;
+
+        if (x[i] < lower[i])
+            x[i] = lower[i];
+        if (x[i] > upper[i])
+            x[i] = upper[i];
+      }
+  }
+};
+
+#endif
diff --git a/src/solverfactorytest.cc b/src/solverfactorytest.cc
new file mode 100644
index 00000000..19b68965
--- /dev/null
+++ b/src/solverfactorytest.cc
@@ -0,0 +1,756 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define MY_DIM 2
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <exception>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/stdstreams.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/function.hh>
+#include <dune/common/bitsetvector.hh>
+#include <dune/common/parametertree.hh>
+#include <dune/common/parametertreeparser.hh>
+
+#include <dune/fufem/formatstring.hh>
+
+#include <dune/tnnmg/functionals/boxconstrainedquadraticfunctional.hh>
+#include <dune/tnnmg/functionals/bcqfconstrainedlinearization.hh>
+#include <dune/tnnmg/localsolvers/scalarobstaclesolver.hh>
+#include <dune/tnnmg/iterationsteps/tnnmgstep.hh>
+
+#include <dune/tectonic/geocoordinate.hh>
+
+#include "assemblers.hh"
+#include "gridselector.hh"
+#include "explicitgrid.hh"
+#include "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 "io/vtk.hh"
+
+#include "spatial-solving/tnnmg/tnnmgstep.hh"
+#include "spatial-solving/tnnmg/linesearchsolver.hh"
+#include "spatial-solving/preconditioners/nbodycontacttransfer.hh"
+#include "obstaclesolver.hh"
+
+#include "factories/stackedblocksfactory.hh"
+
+#include "time-stepping/rate.hh"
+#include "time-stepping/state.hh"
+#include "time-stepping/updaters.hh"
+
+#include "utils/tobool.hh"
+#include "utils/debugutils.hh"
+
+
+const int dim = MY_DIM;
+
+const int timeSteps = 1;
+
+Dune::ParameterTree parset;
+size_t bodyCount;
+
+std::vector<BodyState<Vector, ScalarVector>* > bodyStates;
+std::vector<Vector> u;
+std::vector<Vector> v;
+std::vector<Vector> a;
+std::vector<ScalarVector> alpha;
+std::vector<ScalarVector> weightedNormalStress;
+double relativeTime;
+double relativeTau;
+size_t timeStep = 0;
+
+const std::string path = "";
+const std::string outputFile = "solverfactorytest.log";
+
+template <class ContactNetwork>
+void solveProblem(const ContactNetwork& contactNetwork,
+                  const Matrix& mat, const Vector& rhs, Vector& x,
+                  const BitVector& ignore, const Vector& lower, const Vector& upper) {
+
+    using Solver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;
+    using Norm =  EnergyNorm<Matrix, Vector>;
+
+    //using LocalSolver = LocalBisectionSolver;
+    //using Linearization = Linearization<Functional, BitVector>;
+
+    // set up reference solver
+    Vector refX = x;
+    using ContactFunctional = Dune::TNNMG::BoxConstrainedQuadraticFunctional<Matrix&, Vector&, Vector&, Vector&, double>;
+    auto I = ContactFunctional(mat, rhs, lower, upper);
+
+    using LocalSolver = Dune::TNNMG::ScalarObstacleSolver;
+    auto localSolver = Dune::TNNMG::gaussSeidelLocalSolver(LocalSolver());
+
+    using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<ContactFunctional, decltype(localSolver), BitVector>;
+    auto nonlinearSmoother = std::make_shared<NonlinearSmoother>(I, refX, localSolver);
+
+    using Linearization = Dune::TNNMG::BoxConstrainedQuadraticFunctionalConstrainedLinearization<ContactFunctional, BitVector>;
+    using DefectProjection = Dune::TNNMG::ObstacleDefectProjection;
+    using Step = Dune::TNNMG::TNNMGStep<ContactFunctional, BitVector, Linearization, DefectProjection, LocalSolver>;
+
+    // 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);
+
+    int mu = parset.get<int>("solver.tnnmg.main.multi"); // #multigrid steps in Newton step
+    auto step = Step(I, refX, nonlinearSmoother, linearMultigridStep, mu, DefectProjection(), LocalSolver());
+
+    // compute reference solution with generic functional and solver
+    auto norm = Norm(mat);
+    auto refSolver = Solver(step, parset.get<size_t>("u0.solver.maximumIterations"),
+                            parset.get<double>("u0.solver.tolerance"), norm, Solver::FULL);
+
+    step.setIgnore(ignore);
+    step.setPreSmoothingSteps(parset.get<int>("solver.tnnmg.main.pre"));
+
+    refSolver.addCriterion(
+            [&](){
+            return Dune::formatString("   % 12.5e", I(x));
+            },
+            "   energy      ");
+
+    double initialEnergy = I(x);
+    refSolver.addCriterion(
+            [&](){
+            static double oldEnergy=initialEnergy;
+            double currentEnergy = I(x);
+            double decrease = currentEnergy - oldEnergy;
+            oldEnergy = currentEnergy;
+            return Dune::formatString("   % 12.5e", decrease);
+            },
+            "   decrease    ");
+
+    refSolver.addCriterion(
+            [&](){
+            return Dune::formatString("   % 12.5e", step.lastDampingFactor());
+            },
+            "   damping     ");
+
+
+    refSolver.addCriterion(
+            [&](){
+            return Dune::formatString("   % 12d", step.linearization().truncated().count());
+            },
+            "   truncated   ");
+
+
+    std::vector<double> correctionNorms;
+    refSolver.addCriterion(Dune::Solvers::correctionNormCriterion(step, norm, 1e-10, correctionNorms));
+
+    refSolver.preprocess();
+    refSolver.solve();
+    std::cout << correctionNorms.size() << std::endl;
+
+
+    // set up solver factory solver
+
+    // set up functional
+    using MyFunctional = Functional<Matrix&, Vector&, ZeroNonlinearity&, Vector&, Vector&, typename Matrix::field_type>;
+    MyFunctional J(mat, rhs, ZeroNonlinearity(), lower, upper);
+
+    // set up TNMMG solver
+    // dummy solver, uses direct solver for linear correction no matter what is set here
+    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);
+
+    using Factory = SolverFactory<MyFunctional, BitVector>;
+    Factory factory(parset.sub("solver.tnnmg"), J, *mgSolver, ignore);
+
+   /* std::vector<BitVector> bodyDirichletNodes;
+    nBodyAssembler.postprocess(_dirichletNodes, bodyDirichletNodes);
+    for (size_t i=0; i<bodyDirichletNodes.size(); i++) {
+      print(bodyDirichletNodes[i], "bodyDirichletNodes_" + std::to_string(i) + ": ");
+    }*/
+
+   /* print(bilinearForm, "matrix: ");
+    print(totalX, "totalX: ");
+    print(totalRhs, "totalRhs: ");*/
+
+    auto tnnmgStep = factory.step();
+    factory.setProblem(x);
+
+    LoopSolver<Vector> solver(
+        tnnmgStep.get(), parset.get<size_t>("u0.solver.maximumIterations"),
+                parset.get<double>("u0.solver.tolerance"), &norm,
+        Solver::FULL, true, &refX); // absolute error
+
+    solver.preprocess();
+    solver.solve();
+
+    auto diff = x;
+    diff -= refX;
+    std::cout << "Solver error in energy norm: " << norm(diff) << std::endl;
+
+    x = refX;
+}
+
+
+template <class ContactNetwork>
+void setupInitialConditions(const ContactNetwork& contactNetwork) {
+  using Matrix = typename ContactNetwork::Matrix;
+  const auto& nBodyAssembler = contactNetwork.nBodyAssembler();
+
+  std::cout << std::endl << "-- setupInitialConditions --" << std::endl;
+  std::cout << "----------------------------" << std::endl;
+
+  // Solving a linear problem with a multigrid solver
+  auto const solveLinearProblem = [&](
+      const BitVector& _dirichletNodes, const std::vector<std::shared_ptr<Matrix>>& _matrices,
+      const std::vector<Vector>& _rhs, std::vector<Vector>& _x) {
+
+    std::vector<const Matrix*> matrices_ptr(_matrices.size());
+    for (size_t i=0; i<matrices_ptr.size(); i++) {
+          matrices_ptr[i] = _matrices[i].get();
+    }
+
+    // assemble full global contact problem
+    Matrix bilinearForm;
+
+    nBodyAssembler.assembleJacobian(matrices_ptr, bilinearForm);
+
+    Vector totalRhs, oldTotalRhs;
+    nBodyAssembler.assembleRightHandSide(_rhs, totalRhs);
+    oldTotalRhs = totalRhs;
+
+    Vector totalX, oldTotalX;
+    nBodyAssembler.nodalToTransformed(_x, totalX);
+    oldTotalX = totalX;
+
+    // get lower and upper obstacles
+    const auto& totalObstacles = nBodyAssembler.totalObstacles_;
+    Vector lower(totalObstacles.size());
+    Vector upper(totalObstacles.size());
+
+    for (size_t j=0; j<totalObstacles.size(); ++j) {
+        const auto& totalObstaclesj = totalObstacles[j];
+        auto& lowerj = lower[j];
+        auto& upperj = upper[j];
+      for (size_t d=0; d<dim; ++d) {
+          lowerj[d] = totalObstaclesj[d][0];
+          upperj[d] = totalObstaclesj[d][1];
+      }
+    }
+
+    // print problem
+   /* print(bilinearForm, "bilinearForm");
+    print(totalRhs, "totalRhs");
+    print(_dirichletNodes, "ignore");
+    print(totalObstacles, "totalObstacles");
+    print(lower, "lower");
+    print(upper, "upper");*/
+
+    solveProblem(contactNetwork, bilinearForm, totalRhs, totalX, _dirichletNodes, lower, upper);
+
+    nBodyAssembler.postprocess(totalX, _x);
+  };
+
+  timeStep = parset.get<size_t>("initialTime.timeStep");
+  relativeTime = parset.get<double>("initialTime.relativeTime");
+  relativeTau = parset.get<double>("initialTime.relativeTau");
+
+  bodyStates.resize(bodyCount);
+  u.resize(bodyCount);
+  v.resize(bodyCount);
+  a.resize(bodyCount);
+  alpha.resize(bodyCount);
+  weightedNormalStress.resize(bodyCount);
+
+  for (size_t i=0; i<bodyCount; i++) {
+    size_t leafVertexCount =  contactNetwork.body(i)->nVertices();
+
+    u[i].resize(leafVertexCount),
+    v[i].resize(leafVertexCount),
+    a[i].resize(leafVertexCount),
+    alpha[i].resize(leafVertexCount),
+    weightedNormalStress[i].resize(leafVertexCount),
+
+    bodyStates[i] = new BodyState<Vector, ScalarVector>(&u[i], &v[i], &a[i], &alpha[i], &weightedNormalStress[i]);
+  }
+
+  std::vector<Vector> ell0(bodyCount);
+  for (size_t i=0; i<bodyCount; i++) {
+    // Initial velocity
+    u[i] = 0.0;
+    v[i] = 0.0;
+
+    ell0[i].resize(u[i].size());
+    ell0[i] = 0.0;
+
+    contactNetwork.body(i)->externalForce()(relativeTime, ell0[i]);
+  }
+
+  // Initial displacement: Start from a situation of minimal stress,
+  // which is automatically attained in the case [v = 0 = a].
+  // Assuming dPhi(v = 0) = 0, we thus only have to solve Au = ell0
+  BitVector dirichletNodes;
+  contactNetwork.totalNodes("dirichlet", dirichletNodes);
+  /*for (size_t i=0; i<dirichletNodes.size(); i++) {
+      bool val = false;
+      for (size_t d=0; d<dims; d++) {
+          val = val || dirichletNodes[i][d];
+      }
+
+      dirichletNodes[i] = val;
+      for (size_t d=0; d<dims; d++) {
+          dirichletNodes[i][d] = val;
+      }
+  }*/
+
+  std::cout << "solving linear problem for u..." << std::endl;
+
+  solveLinearProblem(dirichletNodes, contactNetwork.matrices().elasticity, ell0, u);
+
+  //print(u, "initial u:");
+
+  // Initial acceleration: Computed in agreement with Ma = ell0 - Au
+  // (without Dirichlet constraints), again assuming dPhi(v = 0) = 0
+  std::vector<Vector> accelerationRHS = ell0;
+  for (size_t i=0; i<bodyCount; i++) {
+    // Initial state
+    alpha[i] = parset.get<double>("boundary.friction.initialAlpha");
+
+    // Initial normal stress
+
+    const auto& body = contactNetwork.body(i);
+    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());
+
+        body->assembler()->assembleWeightedNormalStress(
+          *frictionBoundaryConditions[j]->boundaryPatch(), frictionBoundaryStress, body->data()->getYoungModulus(),
+          body->data()->getPoissonRatio(), u[i]);
+
+        weightedNormalStress[i] += frictionBoundaryStress;
+    }
+
+    Dune::MatrixVector::subtractProduct(accelerationRHS[i], *body->matrices().elasticity, u[i]);
+  }
+
+  std::cout << "solving linear problem for a..." << std::endl;
+
+  BitVector noNodes(dirichletNodes.size(), false);
+  solveLinearProblem(noNodes, contactNetwork.matrices().mass, accelerationRHS, a);
+
+  //print(a, "initial a:");
+}
+
+template <class ContactNetwork>
+void relativeVelocities(const ContactNetwork& contactNetwork, const Vector& v, std::vector<Vector>& v_rel) {
+
+    const auto& nBodyAssembler = contactNetwork.nBodyAssembler();
+    const size_t nBodies = nBodyAssembler.nGrids();
+   // const auto& contactCouplings = nBodyAssembler.getContactCouplings();
+
+    std::vector<const Dune::BitSetVector<1>*> bodywiseNonmortarBoundaries;
+    contactNetwork.frictionNodes(bodywiseNonmortarBoundaries);
+
+    size_t globalIdx = 0;
+    v_rel.resize(nBodies);
+    for (size_t bodyIdx=0; bodyIdx<nBodies; bodyIdx++) {
+        const auto& nonmortarBoundary = *bodywiseNonmortarBoundaries[bodyIdx];
+        auto& v_rel_ = v_rel[bodyIdx];
+
+        v_rel_.resize(nonmortarBoundary.size());
+
+        for (size_t i=0; i<v_rel_.size(); i++) {
+            if (toBool(nonmortarBoundary[i])) {
+                v_rel_[i] = v[globalIdx];
+            }
+            globalIdx++;
+        }
+    }
+
+}
+
+template <class Updaters, class ContactNetwork>
+void run(Updaters& updaters, ContactNetwork& contactNetwork,
+    const std::vector<Matrix>& velocityMatrices, const std::vector<Vector>& velocityRHSs,
+    std::vector<Vector>& velocityIterates) {
+
+  const auto& nBodyAssembler = contactNetwork.nBodyAssembler();
+  const auto nBodies = nBodyAssembler.nGrids();
+
+  std::vector<const Matrix*> matrices_ptr(nBodies);
+  for (int i=0; i<nBodies; i++) {
+      matrices_ptr[i] = &velocityMatrices[i];
+  }
+
+  // assemble full global contact problem
+  Matrix bilinearForm;
+  nBodyAssembler.assembleJacobian(matrices_ptr, bilinearForm);
+
+  Vector totalRhs;
+  nBodyAssembler.assembleRightHandSide(velocityRHSs, totalRhs);
+
+  // get lower and upper obstacles
+  const auto& totalObstacles = nBodyAssembler.totalObstacles_;
+  Vector lower(totalObstacles.size());
+  Vector upper(totalObstacles.size());
+
+  for (size_t j=0; j<totalObstacles.size(); ++j) {
+      const auto& totalObstaclesj = totalObstacles[j];
+      auto& lowerj = lower[j];
+      auto& upperj = upper[j];
+    for (size_t d=0; d<dim; ++d) {
+        lowerj[d] = totalObstaclesj[d][0];
+        upperj[d] = totalObstaclesj[d][1];
+    }
+  }
+
+  // compute velocity obstacles
+  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);
+
+  updaters.rate_->velocityObstacles(totalu0, lower, totalv0, vLower);
+  updaters.rate_->velocityObstacles(totalu0, upper, totalv0, vUpper);
+
+  const auto& errorNorms = contactNetwork.stateEnergyNorms();
+
+  auto& globalFriction = contactNetwork.globalFriction();
+
+  BitVector totalDirichletNodes;
+  contactNetwork.totalNodes("dirichlet", totalDirichletNodes);
+
+  size_t fixedPointMaxIterations = parset.get<size_t>("v.fpi.maximumIterations");
+  double fixedPointTolerance = parset.get<double>("v.fpi.tolerance");
+  double lambda = parset.get<double>("v.fpi.lambda");
+
+  size_t fixedPointIteration;
+  size_t multigridIterations = 0;
+  std::vector<ScalarVector> alpha(nBodies);
+  updaters.state_->extractAlpha(alpha);
+  for (fixedPointIteration = 0; fixedPointIteration < fixedPointMaxIterations;
+       ++fixedPointIteration) {
+
+    // contribution from nonlinearity
+    globalFriction.updateAlpha(alpha);
+
+    Vector totalVelocityIterate;
+    nBodyAssembler.nodalToTransformed(velocityIterates, totalVelocityIterate);
+
+    solveProblem(contactNetwork, bilinearForm, totalRhs, totalVelocityIterate, totalDirichletNodes, vLower, vUpper);
+
+    nBodyAssembler.postprocess(totalVelocityIterate, velocityIterates);
+
+    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]);
+    }
+
+    // extract relative velocities in mortar basis
+    std::vector<Vector> v_rel;
+    relativeVelocities(contactNetwork, totalVelocityIterate, v_rel);
+
+    std::cout << "- State problem set" << std::endl;
+
+    // solve a state problem
+    updaters.state_->solve(v_rel);
+
+    std::cout << "-- Solved" << std::endl;
+
+    std::vector<ScalarVector> newAlpha(nBodies);
+    updaters.state_->extractAlpha(newAlpha);
+
+    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;
+        }
+    }
+
+    if (lambda < 1e-12 or breakCriterion) {
+      std::cout << "-FixedPointIteration finished! " << (lambda < 1e-12 ? "lambda" : "breakCriterion") << std::endl;
+      fixedPointIteration++;
+      break;
+    }
+    alpha = newAlpha;
+  }
+
+  std::cout << "-FixedPointIteration finished! " << std::endl;
+
+  if (fixedPointIteration == fixedPointMaxIterations)
+    DUNE_THROW(Dune::Exception, "FPI failed to converge");
+
+  updaters.rate_->postProcess(velocityIterates);
+}
+
+
+template <class Updaters, class ContactNetwork>
+void step(Updaters& updaters, ContactNetwork& contactNetwork)  {
+  updaters.state_->nextTimeStep();
+  updaters.rate_->nextTimeStep();
+
+  auto const newRelativeTime = relativeTime + relativeTau;
+  typename ContactNetwork::ExternalForces externalForces;
+  contactNetwork.externalForces(externalForces);
+  std::vector<Vector> ell(externalForces.size());
+  for (size_t i=0; i<externalForces.size(); i++) {
+    (*externalForces[i])(newRelativeTime, ell[i]);
+  }
+
+  std::vector<Matrix> velocityMatrix;
+  std::vector<Vector> velocityRHS;
+  std::vector<Vector> velocityIterate;
+
+  double finalTime = parset.get<double>("problem.finalTime");
+  auto const tau = relativeTau * finalTime;
+  updaters.state_->setup(tau);
+  updaters.rate_->setup(ell, tau, newRelativeTime, velocityRHS, velocityIterate, velocityMatrix);
+
+  run(updaters, contactNetwork, velocityMatrix, velocityRHS, velocityIterate);
+}
+
+template <class Updaters, class ContactNetwork>
+void advanceStep(Updaters& current, ContactNetwork& contactNetwork) {
+    step(current, contactNetwork);
+    relativeTime += relativeTau;
+}
+
+void getParameters(int argc, char *argv[]) {
+  Dune::ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem.cfg", parset);
+  Dune::ParameterTreeParser::readINITree(
+      Dune::Fufem::formatString("/home/mi/podlesny/software/dune/dune-tectonic/src/multi-body-problem-%dD.cfg", dim), parset);
+  Dune::ParameterTreeParser::readOptions(argc, argv, parset);
+}
+
+int main(int argc, char *argv[]) { try {
+    Dune::MPIHelper::instance(argc, argv);
+
+    std::ofstream out(path + outputFile);
+    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buffer
+    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to outputFile
+
+    std::cout << "-------------------------" << std::endl;
+    std::cout << "-- SolverFactory Test: --" << std::endl;
+    std::cout << "-------------------------" << std::endl << std::endl;
+
+    getParameters(argc, argv);
+
+    // ----------------------
+    // set up contact network
+    // ----------------------
+    StackedBlocksFactory<Grid, Vector> stackedBlocksFactory(parset);
+    using ContactNetwork = typename StackedBlocksFactory<Grid, Vector>::ContactNetwork;
+    stackedBlocksFactory.build();
+
+    ContactNetwork& contactNetwork = stackedBlocksFactory.contactNetwork();
+    bodyCount = contactNetwork.nBodies();
+
+    for (size_t i=0; i<contactNetwork.nLevels(); 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
+    // -----------------
+
+    setupInitialConditions(contactNetwork);
+
+    auto& nBodyAssembler = contactNetwork.nBodyAssembler();
+    for (size_t i=0; i<bodyCount; i++) {
+      contactNetwork.body(i)->setDeformation(u[i]);
+    }
+    nBodyAssembler.assembleTransferOperator();
+    nBodyAssembler.assembleObstacle();
+
+    // ------------------------
+    // assemble global friction
+    // ------------------------
+    contactNetwork.assembleFriction(parset.get<Config::FrictionModel>("boundary.friction.frictionModel"), weightedNormalStress);
+
+    auto& globalFriction = contactNetwork.globalFriction();
+    globalFriction.updateAlpha(alpha);
+
+    using Assembler = MyAssembler<DefLeafGridView, dim>;
+    using field_type = Matrix::field_type;
+    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);
+
+    for (size_t i=0; i<bodyCount; i++) {
+      const auto& body = contactNetwork.body(i);
+      vertexBases[i] = &(body->assembler()->vertexBasis);
+      cellBases[i] = &(body->assembler()->cellBasis);
+
+      auto& vertexCoords = vertexCoordinates[i];
+      vertexCoords.resize(body->nVertices());
+
+      Dune::MultipleCodimMultipleGeomTypeMapper<
+          DefLeafGridView, Dune::MCMGVertexLayout> const vertexMapper(body->gridView(), Dune::mcmgVertexLayout());
+      for (auto &&v : vertices(body->gridView()))
+        vertexCoords[vertexMapper.index(v)] = geoToPoint(v.geometry());
+    }
+
+    const MyVTKWriter<MyVertexBasis, MyCellBasis> vtkWriter(cellBases, vertexBases, "/storage/mi/podlesny/software/dune/dune-tectonic/body");
+
+    auto const report = [&](bool initial = false) {
+      if (parset.get<bool>("io.printProgress"))
+        std::cout << "timeStep = " << std::setw(6) << timeStep
+                  << ", time = " << std::setw(12) << relativeTime
+                  << ", tau = " << std::setw(12) << 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(),
+                                           u[i], stress[i]);
+
+        }
+
+        vtkWriter.write(timeStep, u, v, alpha, stress);
+      }
+    };
+    report(true);
+
+    // -------------------
+    // Set up TNNMG solver
+    // -------------------
+
+    BitVector totalDirichletNodes;
+    contactNetwork.totalNodes("dirichlet", 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>;
+    //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));
+        }
+    }*/
+
+
+    /*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(),
+            u,
+            v,
+            a),
+        initStateUpdater<ScalarVector, Vector>(
+            parset.get<Config::stateModel>("boundary.friction.stateModel"),
+            alpha,
+            nBodyAssembler.getContactCouplings(),
+            contactNetwork.couplings())
+            );
+
+
+
+    //const auto& stateEnergyNorms = contactNetwork.stateEnergyNorms();
+
+    for (timeStep=1; timeStep<=timeSteps; timeStep++) {
+
+      advanceStep(current, contactNetwork);
+
+      relativeTime += relativeTau;
+
+      current.rate_->extractDisplacement(u);
+      current.rate_->extractVelocity(v);
+      current.rate_->extractAcceleration(a);
+      current.state_->extractAlpha(alpha);
+
+      contactNetwork.setDeformation(u);
+
+      report();
+    }
+
+    bool passed = true;
+
+    std::cout << "Overall, the test " << (passed ? "was successful!" : "failed!") << std::endl;
+
+    std::cout.rdbuf(coutbuf); //reset to standard output again
+    return passed ? 0 : 1;
+
+} catch (Dune::Exception &e) {
+    Dune::derr << "Dune reported error: " << e << std::endl;
+} catch (std::exception &e) {
+    std::cerr << "Standard exception: " << e.what() << std::endl;
+} // end try
+} // end main
diff --git a/src/spatial-solving/fixedpointiterator.cc b/src/spatial-solving/fixedpointiterator.cc
index d84f5f09..43df107c 100644
--- a/src/spatial-solving/fixedpointiterator.cc
+++ b/src/spatial-solving/fixedpointiterator.cc
@@ -210,6 +210,9 @@ FixedPointIterator<Factory, ContactNetwork, Updaters, ErrorNorms>::run(
     std::cout << "-- Solved" << std::endl;
 
     const auto& tnnmgSol = step->getSol();
+
+    std::cout << "FixPointIterator: Energy of TNNMG solution: " << J(tnnmgSol) << std::endl;
+
     nBodyAssembler.postprocess(tnnmgSol, velocityIterates);
     //nBodyAssembler.postprocess(totalVelocityIterate, velocityIterates);
 
diff --git a/src/spatial-solving/solverfactory.cc b/src/spatial-solving/solverfactory.cc
index cfe36305..5f02147e 100644
--- a/src/spatial-solving/solverfactory.cc
+++ b/src/spatial-solving/solverfactory.cc
@@ -19,7 +19,14 @@ SolverFactory<Functional, BitVector>::SolverFactory(
     const BitVector& ignoreNodes) :
         J_(Dune::Solvers::wrap_own_share<const Functional>(std::forward<Functional>(J))) {
 
-    nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, LocalSolver());
+    auto localSolver = Dune::TNNMG::gaussSeidelLocalSolver(LocalSolver());
+    //nonlinearSmoother_ = std::make_shared<NonlinearSmoother>(*J_, dummyIterate_, localSolver);
+
+    //using MyNonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, decltype(localSolver), BitVector>;
+    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));
 
diff --git a/src/spatial-solving/solverfactory.hh b/src/spatial-solving/solverfactory.hh
index 5d4a5aa2..5fe7e62f 100644
--- a/src/spatial-solving/solverfactory.hh
+++ b/src/spatial-solving/solverfactory.hh
@@ -10,11 +10,12 @@
 #include <dune/solvers/solvers/loopsolver.hh>
 #include <dune/solvers/iterationsteps/cgstep.hh>
 
-//#include <dune/tnnmg/iterationsteps/tnnmgstep.hh>
+#include <dune/tnnmg/iterationsteps/tnnmgstep.hh>
 #include <dune/tnnmg/iterationsteps/nonlineargsstep.hh>
 #include <dune/tnnmg/projections/obstacledefectprojection.hh>
+#include <dune/tnnmg/localsolvers/scalarobstaclesolver.hh>
 
-#include "tnnmg/tnnmgstep.hh"
+//#include "tnnmg/tnnmgstep.hh"
 #include "tnnmg/linearization.hh"
 #include "tnnmg/linesearchsolver.hh"
 #include "tnnmg/localbisectionsolver.hh"
@@ -27,13 +28,13 @@ class SolverFactory {
     using Vector = typename Functional::Vector;
     using BitVector = BitVectorType;
 
-    using LocalSolver = LocalBisectionSolver;
-    using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, LocalSolver>;
+    using LocalSolver = Dune::TNNMG::ScalarObstacleSolver;//LocalBisectionSolver;
+    using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, Dune::TNNMG::GaussSeidelLocalSolver<LocalSolver>, BitVector>;
     using Linearization = Linearization<Functional, BitVector>;
     using DefectProjection = typename Dune::TNNMG::ObstacleDefectProjection;
 
-    using Step = typename Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver>;
-
+    //using Step = TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver>;
+    using Step = Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver>;
 
   template <class LinearSolver>
   SolverFactory(const Dune::ParameterTree&,
diff --git a/src/spatial-solving/tnnmg/functional.hh b/src/spatial-solving/tnnmg/functional.hh
index 4bad3e3f..098c7208 100644
--- a/src/spatial-solving/tnnmg/functional.hh
+++ b/src/spatial-solving/tnnmg/functional.hh
@@ -16,6 +16,12 @@
 
 #include <dune/tnnmg/functionals/boxconstrainedquadraticfunctional.hh>
 
+template<class M, class V, class N, class R>
+class ShiftedFunctional;
+
+template <class M, class V, class N, class L, class U, class R>
+class Functional;
+
 /** \brief Coordinate restriction of box constrained quadratic functional with nonlinearity;
  *         mainly used for presmoothing in TNNMG algorithm
  *
@@ -346,12 +352,13 @@ auto coordinateRestriction(const ShiftedFunctional<M, V, Nonlinearity, R>& f, co
 
   auto&& phii = f.phi().restriction(i);
 
-  auto v = ri;
+  /*auto v = ri;
   double const vnorm = v.two_norm();
   if (vnorm > 1.0)
-        v /= vnorm;
+        v /= vnorm;*/
 
-  return FirstOrderModelFunctional<LocalVector, decltype(phii), LocalLowerObstacle, LocalUpperObstacle, LocalVector, LocalVector, Range>(*Aii_p, std::move(ri), std::move(phii), std::move(dli), std::move(dui), std::move(f.origin()[i]), std::move(v));
+  //return FirstOrderModelFunctional<LocalVector, decltype(phii), LocalLowerObstacle, LocalUpperObstacle, LocalVector, LocalVector, Range>(*Aii_p, std::move(ri), std::move(phii), std::move(dli), std::move(dui), std::move(f.origin()[i]), std::move(v));
+  return Functional<LocalMatrix&, LocalVector, decltype(phii), LocalLowerObstacle, LocalUpperObstacle, Range>(*Aii_p, std::move(ri), std::move(phii), std::move(dli), std::move(dui));
 }
 
 
@@ -389,8 +396,8 @@ class Functional : public Dune::TNNMG::BoxConstrainedQuadraticFunctional<M, V, L
           MM&& matrix,
           VV&& linearPart,
           NN&& phi,
-          LL& lower,
-          UU& upper) :
+          LL&& lower,
+          UU&& upper) :
     Base(std::forward<MM>(matrix), std::forward<VV>(linearPart), std::forward<LL>(lower), std::forward<UU>(upper)),
     phi_(std::forward<NN>(phi))
   {}
diff --git a/src/spatial-solving/tnnmg/linearcorrection.hh b/src/spatial-solving/tnnmg/linearcorrection.hh
index c26f13df..188d580f 100644
--- a/src/spatial-solving/tnnmg/linearcorrection.hh
+++ b/src/spatial-solving/tnnmg/linearcorrection.hh
@@ -1,5 +1,5 @@
-#ifndef DUNE_TNNMG_ITERATIONSTEPS_LINEARCORRECTION_HH
-#define DUNE_TNNMG_ITERATIONSTEPS_LINEARCORRECTION_HH 1
+#ifndef DUNE_TECTONIC_ITERATIONSTEPS_LINEARCORRECTION_HH
+#define DUNE_TECTONIC_ITERATIONSTEPS_LINEARCORRECTION_HH
 
 #include <functional>
 #include <memory>
@@ -38,7 +38,7 @@ emptyIgnore(const Vector& v)
 
 template<typename Matrix, typename Vector>
 LinearCorrection<Matrix, Vector>
-makeLinearCorrection(std::shared_ptr< Dune::Solvers::LinearSolver<Matrix, Vector> > linearSolver)
+buildLinearCorrection(std::shared_ptr< Dune::Solvers::LinearSolver<Matrix, Vector> > linearSolver)
 {
   return [=](const Matrix& A, Vector& x, const Vector& b, const Dune::Solvers::DefaultBitVector_t<Vector>& ignore) {
 
@@ -56,7 +56,7 @@ makeLinearCorrection(std::shared_ptr< Dune::Solvers::LinearSolver<Matrix, Vector
 
 template<typename Matrix, typename Vector>
 LinearCorrection<Matrix, Vector>
-makeLinearCorrection(std::shared_ptr< Dune::Solvers::IterativeSolver<Vector> > iterativeSolver)
+buildLinearCorrection(std::shared_ptr< Dune::Solvers::IterativeSolver<Vector> > iterativeSolver)
 {
   return [=](const Matrix& A, Vector& x, const Vector& b, const Dune::Solvers::DefaultBitVector_t<Vector>& ignore) {
 
@@ -76,16 +76,16 @@ makeLinearCorrection(std::shared_ptr< Dune::Solvers::IterativeSolver<Vector> > i
       directSolver->preprocess();
       directSolver->solve();
 
-      x = directX;
-    /*using LinearIterationStep = Dune::Solvers::LinearIterationStep<Matrix, Vector>;
+      //x = directX;
+    using LinearIterationStep = Dune::Solvers::LinearIterationStep<Matrix, Vector>;
 
     auto linearIterationStep = dynamic_cast<LinearIterationStep*>(&iterativeSolver->getIterationStep());
     if (not linearIterationStep)
       DUNE_THROW(Dune::Exception, "iterative solver must use a linear iteration step");
 
     auto empty = emptyIgnore(x);
-
     linearIterationStep->setIgnore(empty);
+    //linearIterationStep->setIgnore(ignore);
     linearIterationStep->setProblem(A, x, b);
     iterativeSolver->preprocess();
     iterativeSolver->solve();
@@ -94,13 +94,13 @@ makeLinearCorrection(std::shared_ptr< Dune::Solvers::IterativeSolver<Vector> > i
     const auto& norm = iterativeSolver->getErrorNorm();
     auto error = norm.diff(linearIterationStep->getSol(), directX);
 
-    std::cout << "Linear solver iterations: " << iterativeSolver->getResult().iterations << " Error: " << error << std::endl;*/
+    std::cout << "Linear solver iterations: " << iterativeSolver->getResult().iterations << " Error: " << error << std::endl;
   };
 }
 
 template<typename Matrix, typename Vector>
 LinearCorrection<Matrix, Vector>
-makeLinearCorrection(std::shared_ptr< Dune::Solvers::LinearIterationStep<Matrix, Vector> > linearIterationStep, int nIterationSteps = 1)
+buildLinearCorrection(std::shared_ptr< Dune::Solvers::LinearIterationStep<Matrix, Vector> > linearIterationStep, int nIterationSteps = 1)
 {
   return [=](const Matrix& A, Vector& x, const Vector& b, const Dune::Solvers::DefaultBitVector_t<Vector>& ignore) {
     linearIterationStep->setIgnore(ignore);
diff --git a/src/spatial-solving/tnnmg/tnnmgstep.hh b/src/spatial-solving/tnnmg/tnnmgstep.hh
index 44979dcf..1d439664 100644
--- a/src/spatial-solving/tnnmg/tnnmgstep.hh
+++ b/src/spatial-solving/tnnmg/tnnmgstep.hh
@@ -1,5 +1,5 @@
-#ifndef DUNE_TNNMG_ITERATIONSTEPS_TRUNCATED_NONSMOOTH_NEWTON_MULTIGRID_HH
-#define DUNE_TNNMG_ITERATIONSTEPS_TRUNCATED_NONSMOOTH_NEWTON_MULTIGRID_HH
+#ifndef DUNE_TECTONIC_TRUNCATED_NONSMOOTH_NEWTON_MULTIGRID_HH
+#define DUNE_TECTONIC_TRUNCATED_NONSMOOTH_NEWTON_MULTIGRID_HH
 
 #include <string>
 #include <sstream>
@@ -24,8 +24,6 @@
 
 #include <dune/tectonic/../../src/utils/debugutils.hh>
 
-namespace Dune {
-namespace TNNMG {
 
 /**
  * \brief One iteration of the TNNMG method
@@ -49,8 +47,8 @@ class TNNMGStep :
   using BitVector = typename Base::BitVector;
   using ConstrainedBitVector = typename Linearization::ConstrainedBitVector;
   using Functional = F;
-  using IterativeSolver = Solvers::IterativeSolver< ConstrainedVector, Solvers::DefaultBitVector_t<ConstrainedVector> >;
-  using LinearSolver = Solvers::LinearSolver< ConstrainedMatrix,  ConstrainedVector >;
+  using IterativeSolver = Dune::Solvers::IterativeSolver< ConstrainedVector, Dune::Solvers::DefaultBitVector_t<ConstrainedVector> >;
+  using LinearSolver = Dune::Solvers::LinearSolver< ConstrainedMatrix,  ConstrainedVector >;
 
   /** \brief Constructor with an iterative solver object for the linear correction
    * \param iterativeSolver This is a callback used to solve the constrained linearized system
@@ -67,7 +65,7 @@ class TNNMGStep :
   : Base(x),
     f_(&f),
     nonlinearSmoother_(nonlinearSmoother),
-    linearCorrection_(makeLinearCorrection<ConstrainedMatrix>(iterativeSolver)),
+    linearCorrection_(buildLinearCorrection<ConstrainedMatrix>(iterativeSolver)),
     projection_(projection),
     lineSolver_(lineSolver)
   {}
@@ -87,7 +85,7 @@ class TNNMGStep :
   : Base(x),
     f_(&f),
     nonlinearSmoother_(nonlinearSmoother),
-    linearCorrection_(makeLinearCorrection(linearSolver)),
+    linearCorrection_(buildLinearCorrection(linearSolver)),
     projection_(projection),
     lineSolver_(lineSolver)
   {}
@@ -100,15 +98,15 @@ class TNNMGStep :
    */
   TNNMGStep(const Functional& f,
             Vector& x,
-            std::shared_ptr<Solvers::IterationStep<Vector,BitVector> > nonlinearSmoother,
-            std::shared_ptr<Solvers::LinearIterationStep<ConstrainedMatrix,ConstrainedVector> > linearIterationStep,
+            std::shared_ptr<Dune::Solvers::IterationStep<Vector,BitVector> > nonlinearSmoother,
+            std::shared_ptr<Dune::Solvers::LinearIterationStep<ConstrainedMatrix,ConstrainedVector> > linearIterationStep,
             unsigned int noOfLinearIterationSteps,
             const DefectProjection& projection,
             const LineSearchSolver& lineSolver)
   : Base(x),
     f_(&f),
     nonlinearSmoother_(nonlinearSmoother),
-    linearCorrection_(makeLinearCorrection(linearIterationStep, noOfLinearIterationSteps)),
+    linearCorrection_(buildLinearCorrection(linearIterationStep, noOfLinearIterationSteps)),
     projection_(projection),
     lineSolver_(lineSolver)
   {}
@@ -145,24 +143,24 @@ class TNNMGStep :
     const auto& ignore = (*this->ignoreNodes_);
     auto& x = *getIterate();
 
-    std::cout << "TNNMGStep::iterate " << std::endl;
+    //std::cout << "TNNMGStep::iterate " << std::endl;
 
     //print(f.quadraticPart(), "f.quadraticPart():");
 
     //print(f.linearPart(), "f.linearPart():");
 
-    std::cout << "-- energy before smoothing: " << f(x) << std::endl;
+    //std::cout << "-- energy before smoothing: " << f(x) << std::endl;
 
-    print(x, "TNNMG iterate after smoothing:");
+    //print(x, "TNNMG iterate after smoothing:");
 
     // Nonlinear presmoothing
     for (std::size_t i=0; i<preSmoothingSteps_; ++i)
         nonlinearSmoother_->iterate();
 
     //std::cout << "- nonlinear presmoothing: success" << std::endl;
-    print(x, "TNNMG iterate after smoothing:");
+    //print(x, "TNNMG iterate after smoothing:");
 
-    std::cout << "-- energy after presmoothing: " << f(x) << std::endl;
+    //std::cout << "-- energy after presmoothing: " << f(x) << std::endl;
 
     // Compute constraint/truncated linearization
     if (not linearization_)
@@ -173,20 +171,20 @@ class TNNMGStep :
     auto&& A = linearization_->hessian();
     auto&& r = linearization_->negativeGradient();
 
-    print(A, "TNNMG Linear problem matrix:");
+    /*print(A, "TNNMG Linear problem matrix:");
     print(r, "TNNMG Linear problem rhs:");
     print(ignore, "ignore:");
-    print(linearization_->truncated(), "truncation:");
+    print(linearization_->truncated(), "truncation:");*/
 
     // Compute inexact solution of the linearized problem
-    Solvers::resizeInitializeZero(correction_, x);
-    Solvers::resizeInitializeZero(constrainedCorrection_, r);
+    Dune::Solvers::resizeInitializeZero(correction_, x);
+    Dune::Solvers::resizeInitializeZero(constrainedCorrection_, r);
 
 
 
     //print(constrainedCorrection_compare, "direct solver solution:");
 
-    std::cout << "- computing linear correction..." << std::endl;
+    //std::cout << "- computing linear correction..." << std::endl;
 
     //linearCorrection_(A, constrainedCorrection_, r, ignore);
 
@@ -207,9 +205,13 @@ class TNNMGStep :
     //std::cout << "- extended correction: success" << std::endl;
     //print(correction_, "correction:");
 
+    //std::cout << "-- energy before projection: " << f(x) << std::endl;
+
     // Project onto admissible set
     projection_(f, x, correction_);
 
+    //std::cout << "-- energy after projection: " << f(x) << std::endl;
+
     //std::cout << "- projection onto admissible set: success" << std::endl;
 
     //print(correction_, "correction:");
@@ -231,6 +233,8 @@ class TNNMGStep :
     dampingFactor_ = 0;
     lineSolver_(dampingFactor_, fv, false);
 
+    //std::cout << "damping factor: " << dampingFactor_ << std::endl;
+
    // std::cout << "- computing damping factor: success" << std::endl;
     if (std::isnan(dampingFactor_))
       dampingFactor_ = 0;
@@ -240,7 +244,7 @@ class TNNMGStep :
 
     x += correction_;
 
-    std::cout << "-- energy after correction: " << energy(x) << std::endl;
+    //std::cout << "-- energy after correction: " << energy(x) << std::endl;
   }
 
   /**
@@ -279,7 +283,4 @@ class TNNMGStep :
 };
 
 
-} // end namespace TNNMG
-} // end namespace Dune
-
 #endif
-- 
GitLab