diff --git a/examples/python/CMakeLists.txt b/examples/python/CMakeLists.txt
index e7439f6f2..9bea05474 100644
--- a/examples/python/CMakeLists.txt
+++ b/examples/python/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_subdirectory(plate-hole)
-add_subdirectory(custom-material-dynamics)
+add_subdirectory(custom-material)
 
 package_add_files_to_package(
   examples/python/README.rst
   )
diff --git a/examples/python/custom-material/CMakeLists.txt b/examples/python/custom-material/CMakeLists.txt
index b9e6e0952..abaacb68f 100644
--- a/examples/python/custom-material/CMakeLists.txt
+++ b/examples/python/custom-material/CMakeLists.txt
@@ -1,3 +1,7 @@
-register_example(newmark
-  SCRIPT newmark.py
+register_example(bi-material
+  SCRIPT bi-material.py
+  FILES_TO_COPY material.dat square.geo)
+
+register_example(custom-material
+  SCRIPT custom-material.py
   FILES_TO_COPY material.dat bar.geo)
diff --git a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
index 2dcdbaab9..59cedd99d 100644
--- a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
+++ b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
@@ -1,196 +1,202 @@
 /**
  * @file   material_FE2.cc
  *
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @brief Material for multi-scale simulations. It stores an
  * underlying RVE on each integration point of the material.
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "material_FE2.hh"
 #include "communicator.hh"
 #include "solid_mechanics_model_RVE.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 MaterialFE2<spatial_dimension>::MaterialFE2(SolidMechanicsModel & model,
                                             const ID & id)
     : Parent(model, id), C("material_stiffness", *this) {
   AKANTU_DEBUG_IN();
 
   this->C.initialize(voigt_h::size * voigt_h::size);
   this->initialize();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 MaterialFE2<spatial_dimension>::~MaterialFE2() = default;
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim> void MaterialFE2<dim>::initialize() {
   this->registerParam("element_type", el_type, _triangle_3,
                       _pat_parsable | _pat_modifiable,
                       "element type in RVE mesh");
   this->registerParam("mesh_file", mesh_file, _pat_parsable | _pat_modifiable,
                       "the mesh file for the RVE");
   this->registerParam("nb_gel_pockets", nb_gel_pockets,
                       _pat_parsable | _pat_modifiable,
                       "the number of gel pockets in each RVE");
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::initMaterial() {
   AKANTU_DEBUG_IN();
   Parent::initMaterial();
 
   /// create a Mesh and SolidMechanicsModel on each integration point of the
   /// material
   const auto & comm = this->model.getMesh().getCommunicator();
   UInt prank = comm.whoAmI();
   auto C_it = this->C(this->el_type).begin(voigt_h::size, voigt_h::size);
 
   for (auto && data :
        enumerate(make_view(C(this->el_type), voigt_h::size, voigt_h::size))) {
     auto q = std::get<0>(data);
     auto & C = std::get<1>(data);
 
     meshes.emplace_back(std::make_unique<Mesh>(
-        spatial_dimension, "RVE_mesh_" + std::to_string(prank), q + 1));
+        spatial_dimension, "RVE_mesh_" + std::to_string(q), q + 1));
 
     auto & mesh = *meshes.back();
     mesh.read(mesh_file);
 
     RVEs.emplace_back(std::make_unique<SolidMechanicsModelRVE>(
         mesh, true, this->nb_gel_pockets, _all_dimensions,
-        "SMM_RVE_" + std::to_string(prank), q + 1));
+        "SMM_RVE_" + std::to_string(q), q + 1));
 
     auto & RVE = *RVEs.back();
     RVE.initFull(_analysis_method = _static);
 
     /// compute intial stiffness of the RVE
     RVE.homogenizeStiffness(C);
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::computeStress(ElementType el_type,
                                                    GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   // Compute thermal stresses first
 
   Parent::computeStress(el_type, ghost_type);
   Array<Real>::const_scalar_iterator sigma_th_it =
       this->sigma_th(el_type, ghost_type).begin();
 
   // Wikipedia convention:
   // 2*eps_ij (i!=j) = voigt_eps_I
   // http://en.wikipedia.org/wiki/Voigt_notation
 
   Array<Real>::const_matrix_iterator C_it =
       this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size);
 
   // create vectors to store stress and strain in Voigt notation
   // for efficient computation of stress
   Vector<Real> voigt_strain(voigt_h::size);
   Vector<Real> voigt_stress(voigt_h::size);
 
   MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type);
 
   const Matrix<Real> & C_mat = *C_it;
   const Real & sigma_th = *sigma_th_it;
 
   /// copy strains in Voigt notation
   for (UInt I = 0; I < voigt_h::size; ++I) {
     /// copy stress in
     Real voigt_factor = voigt_h::factors[I];
     UInt i = voigt_h::vec[I][0];
     UInt j = voigt_h::vec[I][1];
 
     voigt_strain(I) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.;
   }
 
   // compute stresses in Voigt notation
   voigt_stress.mul<false>(C_mat, voigt_strain);
 
   /// copy stresses back in full vectorised notation
   for (UInt I = 0; I < voigt_h::size; ++I) {
     UInt i = voigt_h::vec[I][0];
     UInt j = voigt_h::vec[I][1];
     sigma(i, j) = sigma(j, i) = voigt_stress(I) + (i == j) * sigma_th;
   }
 
   ++C_it;
   ++sigma_th_it;
 
   MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END;
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::computeTangentModuli(
     const ElementType & el_type, Array<Real> & tangent_matrix,
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Array<Real>::const_matrix_iterator C_it =
       this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size);
 
   MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix);
   tangent.copy(*C_it);
   ++C_it;
   MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::advanceASR(
     const Matrix<Real> & prestrain) {
   AKANTU_DEBUG_IN();
 
   for (auto && data :
        zip(RVEs, make_view(this->gradu(this->el_type), spatial_dimension,
                            spatial_dimension),
            make_view(this->eigengradu(this->el_type), spatial_dimension,
                      spatial_dimension),
-           make_view(this->C(this->el_type), voigt_h::size, voigt_h::size))) {
+           make_view(this->C(this->el_type), voigt_h::size, voigt_h::size),
+           this->delta_T(this->el_type))) {
     auto & RVE = *(std::get<0>(data));
 
     /// apply boundary conditions based on the current macroscopic displ.
     /// gradient
     RVE.applyBoundaryConditions(std::get<1>(data));
 
+    /// apply homogeneous temperature field to each RVE to obtain thermoelastic
+    /// effect
+    RVE.applyHomogeneousTemperature(std::get<4>(data));
+
+
     /// advance the ASR in every RVE
     RVE.advanceASR(prestrain);
 
     /// compute the average eigen_grad_u
     RVE.homogenizeEigenGradU(std::get<2>(data));
 
     /// compute the new effective stiffness of the RVE
     RVE.homogenizeStiffness(std::get<3>(data));
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 INSTANTIATE_MATERIAL(material_FE2, MaterialFE2);
 
 } // namespace akantu
diff --git a/extra_packages/extra-materials/src/material_FE2/material_FE2.hh b/extra_packages/extra-materials/src/material_FE2/material_FE2.hh
index 64d6c4fa4..0d24d5168 100644
--- a/extra_packages/extra-materials/src/material_FE2/material_FE2.hh
+++ b/extra_packages/extra-materials/src/material_FE2/material_FE2.hh
@@ -1,122 +1,112 @@
 /**
  * @file   material_FE2.hh
  *
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  *
  * @brief Material for multi-scale simulations. It stores an
  * underlying RVE on each integration point of the material.
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "material.hh"
 #include "material_thermal.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_MATERIAL_FE_2_HH__
 #define __AKANTU_MATERIAL_FE_2_HH__
 
 namespace akantu {
 class SolidMechanicsModelRVE;
 }
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /// /!\ This material works ONLY for meshes with a single element type!!!!!
 /* -------------------------------------------------------------------------- */
 
 /**
  * MaterialFE2
  *
  * parameters in the material files :
  *   - mesh_file
  */
-// Emil - 27.01.2018 - re-inheriting from MaterialThermal and PlaneStressToolBox
-
-// template<UInt DIM>
-// class MaterialFE2 : public virtual Material {
-//  /* ------------------------------------------------------------------------
-//  */
-//  /* Constructors/Destructors */
-//  /* ------------------------------------------------------------------------
-//  */
 template <UInt DIM> class MaterialFE2 : public MaterialThermal<DIM> {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 private:
   typedef MaterialThermal<DIM> Parent;
 
-  // Emil - 27.01.2018
 public:
   MaterialFE2(SolidMechanicsModel & model, const ID & id = "");
 
   virtual ~MaterialFE2();
 
   typedef VoigtHelper<DIM> voigt_h;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   virtual void initMaterial();
 
   /// constitutive law for all element of a type
   virtual void computeStress(ElementType el_type,
                              GhostType ghost_type = _not_ghost);
 
   /// compute the tangent stiffness matrix for an element type
   void computeTangentModuli(const ElementType & el_type,
                             Array<Real> & tangent_matrix,
                             GhostType ghost_type = _not_ghost);
 
   /// advance alkali-silica reaction
   void advanceASR(const Matrix<Real> & prestrain);
 
 private:
   void initialize();
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// Underlying RVE at each integration point
   std::vector<std::unique_ptr<SolidMechanicsModelRVE>> RVEs;
 
   /// Meshes for all RVEs
   std::vector<std::unique_ptr<Mesh>> meshes;
 
   /// the element type of the associated mesh (this material handles only one
   /// type!!)
   ElementType el_type;
 
   /// the name of RVE mesh file
   ID mesh_file;
 
   /// Elastic stiffness tensor at each Gauss point (in voigt notation)
   InternalField<Real> C;
 
   /// number of gel pockets in each underlying RVE
   UInt nb_gel_pockets;
 };
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 
 #include "material_FE2_inline_impl.cc"
 
 } // namespace akantu
 
 #endif /* __AKANTU_MATERIAL_FE_2_HH__ */
diff --git a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc
index c8d7ac833..f30dec1bd 100644
--- a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc
+++ b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc
@@ -1,553 +1,604 @@
 /**
  * @file   solid_mechanics_model_RVE.cc
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @date   Wed Jan 13 15:32:35 2016
  *
  * @brief  Implementation of SolidMechanicsModelRVE
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "solid_mechanics_model_RVE.hh"
 #include "element_group.hh"
 #include "material_damage_iterative.hh"
 #include "node_group.hh"
 #include "non_linear_solver.hh"
 #include "parser.hh"
 #include "sparse_matrix.hh"
+#include <string>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModelRVE::SolidMechanicsModelRVE(Mesh & mesh,
                                                bool use_RVE_mat_selector,
                                                UInt nb_gel_pockets, UInt dim,
                                                const ID & id,
                                                const MemoryID & memory_id)
     : SolidMechanicsModel(mesh, dim, id, memory_id), volume(0.),
       use_RVE_mat_selector(use_RVE_mat_selector),
       nb_gel_pockets(nb_gel_pockets), nb_dumps(0) {
   AKANTU_DEBUG_IN();
   /// find the four corner nodes of the RVE
   findCornerNodes();
 
   /// remove the corner nodes from the surface node groups:
   /// This most be done because corner nodes a not periodic
   mesh.getElementGroup("top").removeNode(corner_nodes(2));
   mesh.getElementGroup("top").removeNode(corner_nodes(3));
   mesh.getElementGroup("left").removeNode(corner_nodes(3));
   mesh.getElementGroup("left").removeNode(corner_nodes(0));
   mesh.getElementGroup("bottom").removeNode(corner_nodes(1));
   mesh.getElementGroup("bottom").removeNode(corner_nodes(0));
   mesh.getElementGroup("right").removeNode(corner_nodes(2));
   mesh.getElementGroup("right").removeNode(corner_nodes(1));
 
   const auto & bottom = mesh.getElementGroup("bottom").getNodeGroup();
   bottom_nodes.insert(bottom.begin(), bottom.end());
 
   const auto & left = mesh.getElementGroup("left").getNodeGroup();
   left_nodes.insert(left.begin(), left.end());
 
   // /// enforce periodicity on the displacement fluctuations
   // auto surface_pair_1 = std::make_pair("top", "bottom");
   // auto surface_pair_2 = std::make_pair("right", "left");
   // SurfacePairList surface_pairs_list;
   // surface_pairs_list.push_back(surface_pair_1);
   // surface_pairs_list.push_back(surface_pair_2);
   // TODO: To Nicolas correct the PBCs
   // this->setPBC(surface_pairs_list);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModelRVE::~SolidMechanicsModelRVE() = default;
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::initFullImpl(const ModelOptions & options) {
   AKANTU_DEBUG_IN();
 
   auto options_cp(options);
   options_cp.analysis_method = AnalysisMethod::_static;
 
   SolidMechanicsModel::initFullImpl(options_cp);
 
-  this->initMaterials();
-
+  //this->initMaterials();
   auto & fem = this->getFEEngine("SolidMechanicsFEEngine");
 
   /// compute the volume of the RVE
   GhostType gt = _not_ghost;
-  for (auto element_type : this->mesh.elementTypes(spatial_dimension, gt, _ek_not_defined)) {
+  for (auto element_type :
+       this->mesh.elementTypes(spatial_dimension, gt, _ek_not_defined)) {
     Array<Real> Volume(this->mesh.getNbElement(element_type) *
                            fem.getNbIntegrationPoints(element_type),
                        1, 1.);
     this->volume = fem.integrate(Volume, element_type);
   }
 
   std::cout << "The volume of the RVE is " << this->volume << std::endl;
 
   /// dumping
   std::stringstream base_name;
   base_name << this->id; // << this->memory_id - 1;
   this->setBaseName(base_name.str());
   this->addDumpFieldVector("displacement");
   this->addDumpField("stress");
   this->addDumpField("grad_u");
   this->addDumpField("eigen_grad_u");
   this->addDumpField("blocked_dofs");
   this->addDumpField("material_index");
   this->addDumpField("damage");
   this->addDumpField("Sc");
   this->addDumpField("external_force");
   this->addDumpField("equivalent_stress");
   this->addDumpField("internal_force");
+  this->addDumpField("delta_T");
 
   this->dump();
   this->nb_dumps += 1;
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::applyBoundaryConditions(
     const Matrix<Real> & displacement_gradient) {
   AKANTU_DEBUG_IN();
   /// get the position of the nodes
   const Array<Real> & pos = mesh.getNodes();
   /// storage for the coordinates of a given node and the displacement that will
   /// be applied
   Vector<Real> x(spatial_dimension);
   Vector<Real> appl_disp(spatial_dimension);
 
   /// fix top right node
   UInt node = this->corner_nodes(2);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
   // (*this->blocked_dofs)(node,0) = true; (*this->displacement)(node,0) = 0.;
   // (*this->blocked_dofs)(node,1) = true; (*this->displacement)(node,1) = 0.;
 
   /// apply Hx at all the other corner nodes; H: displ. gradient
   node = this->corner_nodes(0);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
 
   node = this->corner_nodes(1);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
 
   node = this->corner_nodes(3);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelRVE::applyHomogeneousTemperature(
+    const Real & temperature) {
+
+  for (UInt m = 0; m < this->getNbMaterials(); ++m) {
+    Material & mat = this->getMaterial(m);
+
+    const ElementTypeMapArray<UInt> & filter_map = mat.getElementFilter();
+
+    Mesh::type_iterator type_it = filter_map.firstType(spatial_dimension);
+    Mesh::type_iterator type_end = filter_map.lastType(spatial_dimension);
+    // Loop over all element types
+    for (; type_it != type_end; ++type_it) {
+      const Array<UInt> & filter = filter_map(*type_it);
+      if (filter.size() == 0)
+        continue;
+
+      Array<Real> & delta_T = mat.getArray<Real>("delta_T", *type_it);
+      Array<Real>::scalar_iterator delta_T_it = delta_T.begin();
+      Array<Real>::scalar_iterator delta_T_end = delta_T.end();
+
+      for (; delta_T_it != delta_T_end; ++delta_T_it) {
+        *delta_T_it = temperature;
+      }
+    }
+  }
+}
+
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::findCornerNodes() {
   AKANTU_DEBUG_IN();
 
   // find corner nodes
   const auto & position = mesh.getNodes();
   const auto & lower_bounds = mesh.getLowerBounds();
   const auto & upper_bounds = mesh.getUpperBounds();
 
   AKANTU_DEBUG_ASSERT(spatial_dimension == 2, "This is 2D only!");
   corner_nodes.resize(4);
   corner_nodes.set(UInt(-1));
 
   for (auto && data : enumerate(make_view(position, spatial_dimension))) {
     auto node = std::get<0>(data);
     const auto & X = std::get<1>(data);
 
     auto distance = X.distance(lower_bounds);
     // node 1
     if (Math::are_float_equal(distance, 0)) {
       corner_nodes(0) = node;
     }
     // node 2
     else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
              Math::are_float_equal(X(_y), lower_bounds(_y))) {
       corner_nodes(1) = node;
     }
     // node 3
     else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
              Math::are_float_equal(X(_y), upper_bounds(_y))) {
       corner_nodes(2) = node;
     }
     // node 4
     else if (Math::are_float_equal(X(_x), lower_bounds(_x)) &&
              Math::are_float_equal(X(_y), upper_bounds(_y))) {
       corner_nodes(3) = node;
     }
   }
 
   for (UInt i = 0; i < corner_nodes.size(); ++i) {
     if (corner_nodes(i) == UInt(-1))
       AKANTU_ERROR("The corner node " << i + 1 << " wasn't found");
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::advanceASR(const Matrix<Real> & prestrain) {
   AKANTU_DEBUG_IN();
   AKANTU_DEBUG_ASSERT(spatial_dimension == 2, "This is 2D only!");
 
   /// apply the new eigenstrain
-  for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) {
+  for (auto element_type :
+       mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) {
     Array<Real> & prestrain_vect =
         const_cast<Array<Real> &>(this->getMaterial("gel").getInternal<Real>(
             "eigen_grad_u")(element_type));
     auto prestrain_it =
         prestrain_vect.begin(spatial_dimension, spatial_dimension);
     auto prestrain_end =
         prestrain_vect.end(spatial_dimension, spatial_dimension);
 
     for (; prestrain_it != prestrain_end; ++prestrain_it)
       (*prestrain_it) = prestrain;
   }
 
   /// advance the damage
   MaterialDamageIterative<2> & mat_paste =
       dynamic_cast<MaterialDamageIterative<2> &>(*this->materials[1]);
   MaterialDamageIterative<2> & mat_aggregate =
       dynamic_cast<MaterialDamageIterative<2> &>(*this->materials[0]);
   UInt nb_damaged_elements = 0;
   Real max_eq_stress_aggregate = 0;
   Real max_eq_stress_paste = 0;
 
   auto & solver = this->getNonLinearSolver();
   solver.set("max_iterations", 2);
   solver.set("threshold", 1e-6);
   solver.set("convergence_type", _scc_solution);
 
   do {
     this->solveStep();
 
     /// compute damage
     max_eq_stress_aggregate = mat_aggregate.getNormMaxEquivalentStress();
     max_eq_stress_paste = mat_paste.getNormMaxEquivalentStress();
 
     nb_damaged_elements = 0;
     if (max_eq_stress_aggregate > max_eq_stress_paste)
       nb_damaged_elements = mat_aggregate.updateDamage();
     else if (max_eq_stress_aggregate < max_eq_stress_paste)
       nb_damaged_elements = mat_paste.updateDamage();
     else
       nb_damaged_elements =
           (mat_paste.updateDamage() + mat_aggregate.updateDamage());
 
     std::cout << "the number of damaged elements is " << nb_damaged_elements
               << std::endl;
   } while (nb_damaged_elements);
 
   if (this->nb_dumps % 10 == 0) {
     this->dump();
   }
   this->nb_dumps += 1;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModelRVE::averageTensorField(UInt row_index, UInt col_index,
                                                 const ID & field_type) {
   AKANTU_DEBUG_IN();
   auto & fem = this->getFEEngine("SolidMechanicsFEEngine");
   Real average = 0;
 
-  for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) {
+  GhostType gt = _not_ghost;
+  for (auto element_type :
+       mesh.elementTypes(spatial_dimension, gt, _ek_not_defined)) {
     if (field_type == "stress") {
       for (UInt m = 0; m < this->materials.size(); ++m) {
         const auto & stress_vec = this->materials[m]->getStress(element_type);
         const auto & elem_filter =
             this->materials[m]->getElementFilter(element_type);
         Array<Real> int_stress_vec(elem_filter.size(),
                                    spatial_dimension * spatial_dimension,
                                    "int_of_stress");
 
         fem.integrate(stress_vec, int_stress_vec,
                       spatial_dimension * spatial_dimension, element_type,
                       _not_ghost, elem_filter);
 
         for (UInt k = 0; k < elem_filter.size(); ++k)
-          average += int_stress_vec(
-              k, row_index * spatial_dimension + col_index); // 3 is the value
-                                                             // for the yy (in
-                                                             // 3D, the value is
-                                                             // 4)
+          average += int_stress_vec(k, row_index * spatial_dimension +
+                                           col_index); // 3 is the value
+                                                       // for the yy (in
+                                                       // 3D, the value is
+                                                       // 4)
       }
     } else if (field_type == "strain") {
       for (UInt m = 0; m < this->materials.size(); ++m) {
         const auto & gradu_vec = this->materials[m]->getGradU(element_type);
         const auto & elem_filter =
             this->materials[m]->getElementFilter(element_type);
         Array<Real> int_gradu_vec(elem_filter.size(),
                                   spatial_dimension * spatial_dimension,
                                   "int_of_gradu");
 
         fem.integrate(gradu_vec, int_gradu_vec,
                       spatial_dimension * spatial_dimension, element_type,
                       _not_ghost, elem_filter);
 
         for (UInt k = 0; k < elem_filter.size(); ++k)
           /// averaging is done only for normal components, so stress and strain
           /// are equal
           average +=
               0.5 *
               (int_gradu_vec(k, row_index * spatial_dimension + col_index) +
                int_gradu_vec(k, col_index * spatial_dimension + row_index));
       }
     } else if (field_type == "eigen_grad_u") {
       for (UInt m = 0; m < this->materials.size(); ++m) {
         const auto & eigen_gradu_vec =
             this->materials[m]->getInternal<Real>("eigen_grad_u")(element_type);
         const auto & elem_filter =
             this->materials[m]->getElementFilter(element_type);
         Array<Real> int_eigen_gradu_vec(elem_filter.size(),
                                         spatial_dimension * spatial_dimension,
                                         "int_of_gradu");
 
         fem.integrate(eigen_gradu_vec, int_eigen_gradu_vec,
                       spatial_dimension * spatial_dimension, element_type,
                       _not_ghost, elem_filter);
 
         for (UInt k = 0; k < elem_filter.size(); ++k)
           /// averaging is done only for normal components, so stress and strain
           /// are equal
           average +=
               int_eigen_gradu_vec(k, row_index * spatial_dimension + col_index);
       }
     } else {
       AKANTU_ERROR("Averaging not implemented for this field!!!");
     }
   }
 
   return average / this->volume;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::homogenizeStiffness(Matrix<Real> & C_macro) {
   AKANTU_DEBUG_IN();
   const UInt dim = 2;
   AKANTU_DEBUG_ASSERT(this->spatial_dimension == dim,
                       "Is only implemented for 2D!!!");
 
   /// apply three independent loading states to determine C
   /// 1. eps_el = (1;0;0) 2. eps_el = (0,1,0) 3. eps_el = (0,0,0.5)
 
   /// clear the eigenstrain
   Matrix<Real> zero_eigengradu(dim, dim, 0.);
   GhostType gt = _not_ghost;
   for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
     auto & prestrain_vect =
         const_cast<Array<Real> &>(this->getMaterial("gel").getInternal<Real>(
             "eigen_grad_u")(element_type));
     auto prestrain_it =
         prestrain_vect.begin(spatial_dimension, spatial_dimension);
     auto prestrain_end =
         prestrain_vect.end(spatial_dimension, spatial_dimension);
 
     for (; prestrain_it != prestrain_end; ++prestrain_it)
       (*prestrain_it) = zero_eigengradu;
   }
 
   /// storage for results of 3 different loading states
   UInt voigt_size = VoigtHelper<dim>::size;
   Matrix<Real> stresses(voigt_size, voigt_size, 0.);
   Matrix<Real> strains(voigt_size, voigt_size, 0.);
   Matrix<Real> H(dim, dim, 0.);
 
   /// save the damage state before filling up cracks
   // ElementTypeMapReal saved_damage("saved_damage");
   // saved_damage.initialize(getFEEngine(), _nb_component = 1, _default_value =
   // 0);
   // this->fillCracks(saved_damage);
 
   /// virtual test 1:
   H(0, 0) = 0.01;
   this->performVirtualTesting(H, stresses, strains, 0);
 
   /// virtual test 2:
   H.clear();
   H(1, 1) = 0.01;
   this->performVirtualTesting(H, stresses, strains, 1);
 
   /// virtual test 3:
   H.clear();
   H(0, 1) = 0.01;
   this->performVirtualTesting(H, stresses, strains, 2);
 
   /// drain cracks
   // this->drainCracks(saved_damage);
   /// compute effective stiffness
   Matrix<Real> eps_inverse(voigt_size, voigt_size);
   eps_inverse.inverse(strains);
   C_macro.mul<false, false>(stresses, eps_inverse);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::performVirtualTesting(const Matrix<Real> & H,
                                                    Matrix<Real> & eff_stresses,
                                                    Matrix<Real> & eff_strains,
                                                    const UInt test_no) {
   AKANTU_DEBUG_IN();
   this->applyBoundaryConditions(H);
 
   auto & solver = this->getNonLinearSolver();
   solver.set("max_iterations", 2);
   solver.set("threshold", 1e-6);
   solver.set("convergence_type", _scc_solution);
   this->solveStep();
 
   /// get average stress and strain
   eff_stresses(0, test_no) = this->averageTensorField(0, 0, "stress");
   eff_strains(0, test_no) = this->averageTensorField(0, 0, "strain");
   eff_stresses(1, test_no) = this->averageTensorField(1, 1, "stress");
   eff_strains(1, test_no) = this->averageTensorField(1, 1, "strain");
   eff_stresses(2, test_no) = this->averageTensorField(1, 0, "stress");
   eff_strains(2, test_no) = 2. * this->averageTensorField(1, 0, "strain");
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::homogenizeEigenGradU(
     Matrix<Real> & eigen_gradu_macro) {
   AKANTU_DEBUG_IN();
   eigen_gradu_macro(0, 0) = this->averageTensorField(0, 0, "eigen_grad_u");
   eigen_gradu_macro(1, 1) = this->averageTensorField(1, 1, "eigen_grad_u");
   eigen_gradu_macro(0, 1) = this->averageTensorField(0, 1, "eigen_grad_u");
   eigen_gradu_macro(1, 0) = this->averageTensorField(1, 0, "eigen_grad_u");
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::initMaterials() {
   AKANTU_DEBUG_IN();
 
   // make sure the material are instantiated
   if (!are_materials_instantiated)
     instantiateMaterials();
 
   if (use_RVE_mat_selector) {
     const Vector<Real> & lowerBounds = mesh.getLowerBounds();
     const Vector<Real> & upperBounds = mesh.getUpperBounds();
     Real bottom = lowerBounds(1);
     Real top = upperBounds(1);
     Real box_size = std::abs(top - bottom);
     Real eps = box_size * 1e-6;
 
     auto tmp = std::make_shared<GelMaterialSelector>(*this, box_size, "gel",
                                                      this->nb_gel_pockets, eps);
     tmp->setFallback(material_selector);
     material_selector = tmp;
   }
 
-  SolidMechanicsModel::initMaterials();
+  this->assignMaterialToElements();
+  // synchronize the element material arrays
+  this->synchronize(_gst_material_id);
+
+  for (auto & material : materials) {
+    /// init internals properties
+    const auto type = material->getID();
+    if (type.find("material_FE2") != std::string::npos)
+      continue;
+    material->initMaterial();
+  }
+
+  this->synchronize(_gst_smm_init_mat);
+
+  if (this->non_local_manager) {
+    this->non_local_manager->initialize();
+  }
+  //SolidMechanicsModel::initMaterials();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::fillCracks(ElementTypeMapReal & saved_damage) {
   const auto & mat_gel = this->getMaterial("gel");
   Real E_gel = mat_gel.get("E");
   Real E_homogenized = 0.;
 
   for (auto && mat : materials) {
     if (mat->getName() == "gel" || mat->getName() == "FE2_mat")
       continue;
 
     Real E = mat->get("E");
     auto & damage = mat->getInternal<Real>("damage");
 
     for (auto && type : damage.elementTypes()) {
       const auto & elem_filter = mat->getElementFilter(type);
       auto nb_integration_point = getFEEngine().getNbIntegrationPoints(type);
 
       auto sav_dam_it =
           make_view(saved_damage(type), nb_integration_point).begin();
       for (auto && data :
            zip(elem_filter, make_view(damage(type), nb_integration_point))) {
         auto el = std::get<0>(data);
         auto & dam = std::get<1>(data);
         Vector<Real> sav_dam = sav_dam_it[el];
 
         sav_dam = dam;
 
         for (auto q : arange(dam.size())) {
           E_homogenized = (E_gel - E) * dam(q) + E;
           dam(q) = 1. - (E_homogenized / E);
         }
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::drainCracks(
     const ElementTypeMapReal & saved_damage) {
   for (auto && mat : materials) {
     if (mat->getName() == "gel" || mat->getName() == "FE2_mat")
       continue;
     auto & damage = mat->getInternal<Real>("damage");
 
     for (auto && type : damage.elementTypes()) {
       const auto & elem_filter = mat->getElementFilter(type);
       auto nb_integration_point = getFEEngine().getNbIntegrationPoints(type);
 
-      auto sav_dam_it = make_view(saved_damage(type), nb_integration_point).begin();
+      auto sav_dam_it =
+          make_view(saved_damage(type), nb_integration_point).begin();
       for (auto && data :
            zip(elem_filter, make_view(damage(type), nb_integration_point))) {
         auto el = std::get<0>(data);
         auto & dam = std::get<1>(data);
         Vector<Real> sav_dam = sav_dam_it[el];
 
         dam = sav_dam;
       }
     }
   }
 }
 
 } // namespace akantu
diff --git a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.hh b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.hh
index c38055a1a..b509066c6 100644
--- a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.hh
+++ b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.hh
@@ -1,230 +1,234 @@
 /**
  * @file   solid_mechanics_model_RVE.hh
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @date   Wed Jan 13 14:54:18 2016
  *
  * @brief  SMM for RVE computations in FE2 simulations
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #ifndef __AKANTU_SOLID_MECHANICS_MODEL_RVE_HH__
 #define __AKANTU_SOLID_MECHANICS_MODEL_RVE_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_grid_dynamic.hh"
 #include "solid_mechanics_model.hh"
 #include <unordered_set>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 class SolidMechanicsModelRVE : public SolidMechanicsModel {
 
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 
 public:
   SolidMechanicsModelRVE(Mesh & mesh, bool use_RVE_mat_selector = true,
                          UInt nb_gel_pockets = 400,
                          UInt spatial_dimension = _all_dimensions,
                          const ID & id = "solid_mechanics_model",
                          const MemoryID & memory_id = 0);
 
   virtual ~SolidMechanicsModelRVE();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 protected:
   void initFullImpl(const ModelOptions & option) override;
 
   /// initialize the materials
   void initMaterials() override;
 
 public:
   /// apply boundary contions based on macroscopic deformation gradient
   virtual void
   applyBoundaryConditions(const Matrix<Real> & displacement_gradient);
 
-  /// advance the reactions -> grow gel and apply homogenized properties
+  /// apply homogeneous temperature field from the macroscale level to the RVEs
+  virtual void
+  applyHomogeneousTemperature(const Real & temperature);
+
+/// advance the reactions -> grow gel and apply homogenized properties
   void advanceASR(const Matrix<Real> & prestrain);
 
   /// compute average stress or strain in the model
   Real averageTensorField(UInt row_index, UInt col_index,
                           const ID & field_type);
 
   /// compute effective stiffness of the RVE
   void homogenizeStiffness(Matrix<Real> & C_macro);
 
   /// compute average eigenstrain
   void homogenizeEigenGradU(Matrix<Real> & eigen_gradu_macro);
 
   /* ------------------------------------------------------------------------ */
   /* Data Accessor inherited members                                          */
   /* ------------------------------------------------------------------------ */
 
   inline void unpackData(CommunicationBuffer & buffer,
                          const Array<UInt> & index,
                          const SynchronizationTag & tag) override;
 
   /* ------------------------------------------------------------------------ */
   /* Accessors */
   /* ------------------------------------------------------------------------ */
 public:
   AKANTU_GET_MACRO(CornerNodes, corner_nodes, const Array<UInt> &);
   AKANTU_GET_MACRO(Volume, volume, Real);
 
 private:
   /// find the corner nodes
   void findCornerNodes();
 
   /// perform virtual testing
   void performVirtualTesting(const Matrix<Real> & H,
                              Matrix<Real> & eff_stresses,
                              Matrix<Real> & eff_strains, const UInt test_no);
 
   void fillCracks(ElementTypeMapReal & saved_damage);
   void drainCracks(const ElementTypeMapReal & saved_damage);
   /* ------------------------------------------------------------------------ */
   /* Members */
   /* ------------------------------------------------------------------------ */
 
   /// volume of the RVE
   Real volume;
 
   /// corner nodes 1, 2, 3, 4 (see Leonardo's thesis, page 98)
   Array<UInt> corner_nodes;
 
   /// bottom nodes
   std::unordered_set<UInt> bottom_nodes;
 
   /// left nodes
   std::unordered_set<UInt> left_nodes;
 
   /// standard mat selector or user one
   bool use_RVE_mat_selector;
 
   /// the number of gel pockets inside the RVE
   UInt nb_gel_pockets;
 
   /// dump counter
   UInt nb_dumps;
 };
 
 inline void SolidMechanicsModelRVE::unpackData(CommunicationBuffer & buffer,
                                                const Array<UInt> & index,
                                                const SynchronizationTag & tag) {
   SolidMechanicsModel::unpackData(buffer, index, tag);
 
-  if (tag == _gst_smm_uv) {
-    auto disp_it = displacement->begin(spatial_dimension);
-
-    for (auto node : index) {
-      Vector<Real> current_disp(disp_it[node]);
-
-      // if node is at the bottom, u_bottom = u_top +u_2 -u_3
-      if (bottom_nodes.count(node)) {
-        current_disp += Vector<Real>(disp_it[corner_nodes(1)]);
-        current_disp -= Vector<Real>(disp_it[corner_nodes(2)]);
-      }
-      // if node is at the left, u_left = u_right +u_4 -u_3
-      else if (left_nodes.count(node)) {
-        current_disp += Vector<Real>(disp_it[corner_nodes(3)]);
-        current_disp -= Vector<Real>(disp_it[corner_nodes(2)]);
-      }
-    }
-  }
+//  if (tag == _gst_smm_uv) {
+//    auto disp_it = displacement->begin(spatial_dimension);
+//
+//    for (auto node : index) {
+//      Vector<Real> current_disp(disp_it[node]);
+//
+//      // if node is at the bottom, u_bottom = u_top +u_2 -u_3
+//      if (bottom_nodes.count(node)) {
+//        current_disp += Vector<Real>(disp_it[corner_nodes(1)]);
+//        current_disp -= Vector<Real>(disp_it[corner_nodes(2)]);
+//      }
+//      // if node is at the left, u_left = u_right +u_4 -u_3
+//      else if (left_nodes.count(node)) {
+//        current_disp += Vector<Real>(disp_it[corner_nodes(3)]);
+//        current_disp -= Vector<Real>(disp_it[corner_nodes(2)]);
+//      }
+//    }
+//  }
 }
 
 /* -------------------------------------------------------------------------- */
 /* ASR material selector                                                      */
 /* -------------------------------------------------------------------------- */
 class GelMaterialSelector : public MeshDataMaterialSelector<std::string> {
 public:
   GelMaterialSelector(SolidMechanicsModel & model, const Real box_size,
                       const std::string & gel_material,
                       const UInt nb_gel_pockets, Real /*tolerance*/ = 0.)
       : MeshDataMaterialSelector<std::string>("physical_names", model),
         model(model), gel_material(gel_material),
         nb_gel_pockets(nb_gel_pockets), nb_placed_gel_pockets(0),
         box_size(box_size) {
     Mesh & mesh = this->model.getMesh();
     UInt spatial_dimension = model.getSpatialDimension();
     Element el{_triangle_3, 0, _not_ghost};
     UInt nb_element = mesh.getNbElement(el.type, el.ghost_type);
     Array<Real> barycenter(nb_element, spatial_dimension);
 
     for (auto && data : enumerate(make_view(barycenter, spatial_dimension))) {
       el.element = std::get<0>(data);
       auto & bary = std::get<1>(data);
       mesh.getBarycenter(el, bary);
     }
 
     /// generate the gel pockets
     srand(0.);
     Vector<Real> center(spatial_dimension);
     UInt placed_gel_pockets = 0;
     std::set<int> checked_baries;
     while (placed_gel_pockets != nb_gel_pockets) {
       /// get a random bary center
       UInt bary_id = rand() % nb_element;
       if (checked_baries.find(bary_id) != checked_baries.end())
         continue;
       checked_baries.insert(bary_id);
       el.element = bary_id;
       if (MeshDataMaterialSelector<std::string>::operator()(el) == 1)
         continue; /// element belongs to paste
       gel_pockets.push_back(el);
       placed_gel_pockets += 1;
     }
   }
 
   UInt operator()(const Element & elem) {
     UInt temp_index = MeshDataMaterialSelector<std::string>::operator()(elem);
     if (temp_index == 1)
       return temp_index;
     std::vector<Element>::const_iterator iit = gel_pockets.begin();
     std::vector<Element>::const_iterator eit = gel_pockets.end();
     if (std::find(iit, eit, elem) != eit) {
       nb_placed_gel_pockets += 1;
       std::cout << nb_placed_gel_pockets << " gelpockets placed" << std::endl;
       return model.getMaterialIndex(gel_material);
       ;
     }
     return 0;
   }
 
 protected:
   SolidMechanicsModel & model;
   std::string gel_material;
   std::vector<Element> gel_pockets;
   UInt nb_gel_pockets;
   UInt nb_placed_gel_pockets;
   Real box_size;
 };
 
 } // namespace akantu
 
 ///#include "material_selector_tmpl.hh"
 
 #endif /* __AKANTU_SOLID_MECHANICS_MODEL_RVE_HH__ */
diff --git a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc
index 6818c8ddc..08fcce9f9 100644
--- a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc
+++ b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc
@@ -1,211 +1,212 @@
 /**
  * @file   element_class_kirchhoff_shell_inline_impl.cc
  *
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 04 2014
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Element class Kirchhoff Shell
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "element_class_structural.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__
 #define __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(
     _itp_discrete_kirchhoff_triangle_18, _itp_lagrange_triangle_3, 6, 6, 21);
 AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(
     _discrete_kirchhoff_triangle_18, _gt_triangle_3,
     _itp_discrete_kirchhoff_triangle_18, _triangle_3, _ek_structural, 3,
     _git_triangle, 2);
 
 /* -------------------------------------------------------------------------- */
 namespace detail {
   inline void computeBasisChangeMatrix(Matrix<Real> & P,
                                        const Matrix<Real> & X) {
     Vector<Real> X1 = X(0);
     Vector<Real> X2 = X(1);
     Vector<Real> X3 = X(2);
 
     Vector<Real> a1 = X2 - X1;
     Vector<Real> a2 = X3 - X1;
 
     a1.normalize();
     Vector<Real> e3 = a1.crossProduct(a2);
     e3.normalize();
     Vector<Real> e2 = e3.crossProduct(a1);
 
     P(0) = a1;
     P(1) = e2;
     P(2) = e3;
+    P = P.transpose();
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 ElementClass<_discrete_kirchhoff_triangle_18>::computeRotationMatrix(
     Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> &) {
   auto dim = X.rows();
   Matrix<Real> P(dim, dim);
   detail::computeBasisChangeMatrix(P, X);
 
   R.clear();
   for (UInt i = 0; i < dim; ++i)
     for (UInt j = 0; j < dim; ++j)
-      R(i + dim, j + dim) = R(i, j) = P(j, i);
+      R(i + dim, j + dim) = R(i, j) = P(i, j);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeShapes(
     const Vector<Real> & /*natural_coords*/,
     const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*N*/) {}
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeDNDS(
     const Vector<Real> & natural_coords, const Matrix<Real> & real_coordinates,
     Matrix<Real> & B) {
 
   auto dim = real_coordinates.cols();
   Matrix<Real> P(dim, dim);
   detail::computeBasisChangeMatrix(P, real_coordinates);
   auto X = P * real_coordinates;
   Vector<Real> X1 = X(0);
   Vector<Real> X2 = X(1);
   Vector<Real> X3 = X(2);
 
   std::array<Vector<Real>, 3> A = {X2 - X1, X3 - X2, X1 - X3};
   std::array<Real, 3> L, C, S;
 
   // Setting all last coordinates to 0
   std::for_each(A.begin(), A.end(), [](auto & a) { a(2) = 0; });
   // Computing lengths
   std::transform(A.begin(), A.end(), L.begin(),
-                 [](Vector<Real> & a) { return a.norm<L_2>(); });
+                 [](auto & a) { return a.template norm<L_2>(); });
   // Computing cosines
   std::transform(A.begin(), A.end(), L.begin(), C.begin(),
-                 [](Vector<Real> & a, Real & l) { return a(0) / l; });
+                 [](auto & a, auto & l) { return a(0) / l; });
   // Computing sines
   std::transform(A.begin(), A.end(), L.begin(), S.begin(),
-                 [](Vector<Real> & a, Real & l) { return a(1) / l; });
+                 [](auto & a, auto & l) { return a(1) / l; });
 
   // Natural coordinates
   Real xi = natural_coords(0);
   Real eta = natural_coords(1);
 
   // Derivative of quadratic interpolation functions
   Matrix<Real> dP = {{4 * (1 - 2 * xi - eta), 4 * eta, -4 * eta},
                      {-4 * xi, 4 * xi, 4 * (1 - xi - 2 * eta)}};
 
   Matrix<Real> dNx1 = {
       {3. / 2 * (dP(0, 0) * C[0] / L[0] - dP(0, 2) * C[2] / L[2]),
        3. / 2 * (dP(0, 1) * C[1] / L[1] - dP(0, 0) * C[0] / L[0]),
        3. / 2 * (dP(0, 2) * C[2] / L[2] - dP(0, 1) * C[1] / L[1])},
       {3. / 2 * (dP(1, 0) * C[0] / L[0] - dP(1, 2) * C[2] / L[2]),
        3. / 2 * (dP(1, 1) * C[1] / L[1] - dP(1, 0) * C[0] / L[0]),
        3. / 2 * (dP(1, 2) * C[2] / L[2] - dP(1, 1) * C[1] / L[1])}};
   Matrix<Real> dNx2 = {
       // clang-format off
       {-1 - 3. / 4 * (dP(0, 0) * C[0] * C[0] + dP(0, 2) * C[2] * C[2]),
 	1 - 3. / 4 * (dP(0, 1) * C[1] * C[1] + dP(0, 0) * C[0] * C[0]),
-	   -3. / 4 * (dP(0, 2) * C[2] * C[2] + dP(0, 1) * C[1] * C[1])},
+	  - 3. / 4 * (dP(0, 2) * C[2] * C[2] + dP(0, 1) * C[1] * C[1])},
       {-1 - 3. / 4 * (dP(1, 0) * C[0] * C[0] + dP(1, 2) * C[2] * C[2]),
-	   -3. / 4 * (dP(1, 1) * C[1] * C[1] + dP(1, 0) * C[0] * C[0]),
+	  - 3. / 4 * (dP(1, 1) * C[1] * C[1] + dP(1, 0) * C[0] * C[0]),
 	1 - 3. / 4 * (dP(1, 2) * C[2] * C[2] + dP(1, 1) * C[1] * C[1])}};
   // clang-format on
   Matrix<Real> dNx3 = {
       {-3. / 4 * (dP(0, 0) * C[0] * S[0] + dP(0, 2) * C[2] * S[2]),
        -3. / 4 * (dP(0, 1) * C[1] * S[1] + dP(0, 0) * C[0] * S[0]),
        -3. / 4 * (dP(0, 2) * C[2] * S[2] + dP(0, 1) * C[1] * S[1])},
       {-3. / 4 * (dP(1, 0) * C[0] * S[0] + dP(1, 2) * C[2] * S[2]),
        -3. / 4 * (dP(1, 1) * C[1] * S[1] + dP(1, 0) * C[0] * S[0]),
        -3. / 4 * (dP(1, 2) * C[2] * S[2] + dP(1, 1) * C[1] * S[1])}};
   Matrix<Real> dNy1 = {
       {3. / 2 * (dP(0, 0) * S[0] / L[0] - dP(0, 2) * S[2] / L[2]),
        3. / 2 * (dP(0, 1) * S[1] / L[1] - dP(0, 0) * S[0] / L[0]),
        3. / 2 * (dP(0, 2) * S[2] / L[2] - dP(0, 1) * S[1] / L[1])},
       {3. / 2 * (dP(1, 0) * S[0] / L[0] - dP(1, 2) * S[2] / L[2]),
        3. / 2 * (dP(1, 1) * S[1] / L[1] - dP(1, 0) * S[0] / L[0]),
        3. / 2 * (dP(1, 2) * S[2] / L[2] - dP(1, 1) * S[1] / L[1])}};
   Matrix<Real> dNy2 = dNx3;
   Matrix<Real> dNy3 = {
       // clang-format off
       {-1 - 3. / 4 * (dP(0, 0) * S[0] * S[0] + dP(0, 2) * S[2] * S[2]),
 	1 - 3. / 4 * (dP(0, 1) * S[1] * S[1] + dP(0, 0) * S[0] * S[0]),
-	   -3. / 4 * (dP(0, 2) * S[2] * S[2] + dP(0, 1) * S[1] * S[1])},
+	  - 3. / 4 * (dP(0, 2) * S[2] * S[2] + dP(0, 1) * S[1] * S[1])},
       {-1 - 3. / 4 * (dP(1, 0) * S[0] * S[0] + dP(1, 2) * S[2] * S[2]),
-	   -3. / 4 * (dP(1, 1) * S[1] * S[1] + dP(1, 0) * S[0] * S[0]),
+	  - 3. / 4 * (dP(1, 1) * S[1] * S[1] + dP(1, 0) * S[0] * S[0]),
 	1 - 3. / 4 * (dP(1, 2) * S[2] * S[2] + dP(1, 1) * S[1] * S[1])}};
   // clang-format on
 
   // Derivative of linear (membrane mode) functions
   Matrix<Real> dNm(2, 3);
   InterpolationElement<_itp_lagrange_triangle_3, _itk_lagrangian>::computeDNDS(
       natural_coords, dNm);
   
   UInt i = 0;
   for (const Matrix<Real> & mat : {dNm, dNx1, dNx2, dNx3, dNy1, dNy2, dNy3}) {
     B.block(mat, 0, i);
     i += mat.cols();
   }
 }
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_discrete_kirchhoff_triangle_18,
                      _itk_structural>::arrangeInVoigt(const Matrix<Real> & dnds,
                                                       Matrix<Real> & B) {
   Matrix<Real> dNm(2, 3), dNx1(2, 3), dNx2(2, 3), dNx3(2, 3), dNy1(2, 3),
       dNy2(2, 3), dNy3(2, 3);
   UInt i = 0;
   for (Matrix<Real> * mat : {&dNm, &dNx1, &dNx2, &dNx3, &dNy1, &dNy2, &dNy3}) {
     *mat = dnds.block(0, i, 2, 3);
     i += mat->cols();
   }
 
-  // clang-format off
-  B = {
-    // Membrane shape functions; TODO use the triangle_3 shapes
-    {dNm(0, 0), 0,         0, 0, 0, 0, dNm(0, 1), 0,         0, 0, 0, 0, dNm(0, 2), 0,         0, 0, 0, 0, },
-    {0,         dNm(1, 0), 0, 0, 0, 0, 0,         dNm(1, 1), 0, 0, 0, 0, 0,         dNm(1, 2), 0, 0, 0, 0, },
-    {dNm(1, 0), dNm(0, 0), 0, 0, 0, 0, dNm(1, 1), dNm(0, 1), 0, 0, 0, 0, dNm(1, 2), dNm(0, 2), 0, 0, 0, 0, },
-
-    // Bending shape functions
-    {0, 0, dNx1(0, 0),              -dNx3(0, 0),              dNx2(0, 0),              0, 0, 0, dNx1(0, 1),              -dNx3(0, 1),              dNx2(0, 1),              0, 0, 0, dNx1(0, 2),              -dNx3(0, 2),              dNx2(0, 2),              0},
-    {0, 0, dNy1(1, 0),              -dNy3(1, 0),              dNy2(1, 0),              0, 0, 0, dNy1(1, 1),              -dNy3(1, 1),              dNy2(1, 1),              0, 0, 0, dNy1(1, 2),              -dNy3(1, 2),              dNy2(1, 2),              0},
-    {0, 0, dNx1(1, 0) + dNy1(0, 0), -dNx3(1, 0) - dNy3(0, 0), dNx2(1, 0) + dNy2(1, 0), 0, 0, 0, dNx1(1, 1) + dNy1(0, 1), -dNx3(1, 1) - dNy3(0, 0), dNx2(1, 1) + dNy2(1, 1), 0, 0, 0, dNx1(1, 2) + dNy1(0, 2), -dNx3(1, 2) - dNy3(0, 2), dNx2(1, 2) + dNy2(1, 2), 0}};
-  // clang-format on
+  for (UInt i = 0; i < 3; ++i) {
+    // clang-format off
+    Matrix<Real> Bm = {{dNm(0, i), 0,         0, 0, 0, 0},
+                       {0,         dNm(1, i), 0, 0, 0, 0},
+                       {dNm(1, i), dNm(0, i), 0, 0, 0, 0}};
+    Matrix<Real> Bf = {{0, 0, dNx1(0, i),              -dNx3(0, i),              dNx2(0, i),              0},
+                       {0, 0, dNy1(1, i),              -dNy3(1, i),              dNy2(1, i),              0},
+                       {0, 0, dNx1(1, i) + dNy1(0, i), -dNx3(1, i) - dNy3(0, i), dNx2(1, i) + dNy2(0, i), 0}};
+    // clang-format on
+    B.block(Bm, 0, i * 6);
+    B.block(Bf, 3, i * 6);
+  }
 }
 
 } // namespace akantu
 
 #endif /* __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ */
diff --git a/src/fe_engine/shape_structural_inline_impl.cc b/src/fe_engine/shape_structural_inline_impl.cc
index bf1c2fce1..978c89071 100644
--- a/src/fe_engine/shape_structural_inline_impl.cc
+++ b/src/fe_engine/shape_structural_inline_impl.cc
@@ -1,389 +1,432 @@
 /**
  * @file   shape_structural_inline_impl.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Dec 13 2010
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  ShapeStructural inline implementation
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "mesh_iterators.hh"
 #include "shape_structural.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__
 #define __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__
 
 namespace akantu {
 
 namespace {
   /// Extract nodal coordinates per elements
   template <ElementType type>
   std::unique_ptr<Array<Real>>
   getNodesPerElement(const Mesh & mesh, const Array<Real> & nodes,
                      const GhostType & ghost_type) {
     const auto dim = ElementClass<type>::getSpatialDimension();
     const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 
     auto nodes_per_element = std::make_unique<Array<Real>>(0, dim * nb_nodes_per_element);
     FEEngine::extractNodalToElementField(mesh, nodes, *nodes_per_element, type, ghost_type);
     return nodes_per_element;
   }
 }
 
 template <ElementKind kind>
 inline void ShapeStructural<kind>::initShapeFunctions(
     const Array<Real> & /* unused */, const Matrix<Real> & /* unused */,
     const ElementType & /* unused */, const GhostType & /* unused */) {
   AKANTU_TO_IMPLEMENT();
 }
 
 /* -------------------------------------------------------------------------- */
 #define INIT_SHAPE_FUNCTIONS(type)                                             \
   setIntegrationPointsByType<type>(integration_points, ghost_type);            \
   precomputeRotationMatrices<type>(nodes, ghost_type);                         \
   precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type);                \
   precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type);
 
 template <>
 inline void ShapeStructural<_ek_structural>::initShapeFunctions(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     const ElementType & type, const GhostType & ghost_type) {
   AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS);
 }
 
 #undef INIT_SHAPE_FUNCTIONS
 
 /* -------------------------------------------------------------------------- */
 template <>
 template <ElementType type>
 void ShapeStructural<_ek_structural>::computeShapesOnIntegrationPoints(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     Array<Real> & shapes, const GhostType & ghost_type,
     const Array<UInt> & filter_elements) const {
 
   UInt nb_points = integration_points.cols();
   UInt nb_element = mesh.getConnectivity(type, ghost_type).size();
 
   shapes.resize(nb_element * nb_points);
 
   UInt ndof = ElementClass<type>::getNbDegreeOfFreedom();
 
 #if !defined(AKANTU_NDEBUG)
   UInt size_of_shapes = ElementClass<type>::getShapeSize();
   AKANTU_DEBUG_ASSERT(shapes.getNbComponent() == size_of_shapes,
                       "The shapes array does not have the correct "
                           << "number of component");
 #endif
 
   auto shapes_it = shapes.begin_reinterpret(
       ElementClass<type>::getNbNodesPerInterpolationElement(), ndof, nb_points,
       nb_element);
 
   auto shapes_begin = shapes_it;
   if (filter_elements != empty_filter) {
     nb_element = filter_elements.size();
   }
 
   auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type);
   auto nodes_it = nodes_per_element->begin(mesh.getSpatialDimension(),
                                            Mesh::getNbNodesPerElement(type));
   auto nodes_begin = nodes_it;
 
   for (UInt elem = 0; elem < nb_element; ++elem) {
     if (filter_elements != empty_filter) {
       shapes_it = shapes_begin + filter_elements(elem);
       nodes_it = nodes_begin + filter_elements(elem);
     }
 
     Tensor3<Real> & N = *shapes_it;
     auto & real_coord = *nodes_it;
     ElementClass<type>::computeShapes(integration_points, real_coord, N);
 
     if (filter_elements == empty_filter)
       ++shapes_it;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::precomputeRotationMatrices(
     const Array<Real> & nodes, const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   const auto spatial_dimension = mesh.getSpatialDimension();
   const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   const auto nb_element = mesh.getNbElement(type, ghost_type);
   const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom();
 
   if (not this->rotation_matrices.exists(type, ghost_type)) {
     this->rotation_matrices.alloc(0, nb_dof * nb_dof, type, ghost_type);
   }
 
   auto & rot_matrices = this->rotation_matrices(type, ghost_type);
   rot_matrices.resize(nb_element);
 
   Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element);
   FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type);
 
   bool has_extra_normal = mesh.hasData<Real>("extra_normal", type, ghost_type);
   Array<Real>::const_vector_iterator extra_normal;
   if (has_extra_normal)
     extra_normal = mesh.getData<Real>("extra_normal", type, ghost_type)
                        .begin(spatial_dimension);
 
   for (auto && tuple :
        zip(make_view(x_el, spatial_dimension, nb_nodes_per_element),
            make_view(rot_matrices, nb_dof, nb_dof))) {
     // compute shape derivatives
     auto & X = std::get<0>(tuple);
     auto & R = std::get<1>(tuple);
 
     if (has_extra_normal) {
       ElementClass<type>::computeRotationMatrix(R, X, *extra_normal);
       ++extra_normal;
     } else {
       ElementClass<type>::computeRotationMatrix(
           R, X, Vector<Real>(spatial_dimension));
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::precomputeShapesOnIntegrationPoints(
     const Array<Real> & nodes, const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   const auto & natural_coords = integration_points(type, ghost_type);
   auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   auto nb_points = integration_points(type, ghost_type).cols();
   auto nb_element = mesh.getNbElement(type, ghost_type);
   auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom();
   const auto dim = ElementClass<type>::getSpatialDimension();
 
   auto itp_type = FEEngine::getInterpolationType(type);
   if (not shapes.exists(itp_type, ghost_type)) {
     auto size_of_shapes = this->getShapeSize(type);
     this->shapes.alloc(0, size_of_shapes, itp_type, ghost_type);
   }
 
   auto & shapes_ = this->shapes(itp_type, ghost_type);
   shapes_.resize(nb_element * nb_points);
 
   auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type);
 
   for (auto && tuple :
 	 zip(make_view(shapes_, nb_dof, nb_dof * nb_nodes_per_element, nb_points),
 	     make_view(*nodes_per_element, dim, nb_nodes_per_element))) {
     auto & N = std::get<0>(tuple);
     auto & real_coord = std::get<1>(tuple);
     ElementClass<type>::computeShapes(natural_coords, real_coord, N);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::precomputeShapeDerivativesOnIntegrationPoints(
     const Array<Real> & nodes, const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   const auto & natural_coords = integration_points(type, ghost_type);
   const auto spatial_dimension = mesh.getSpatialDimension();
   const auto natural_spatial_dimension =
       ElementClass<type>::getNaturalSpaceDimension();
   const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   const auto nb_points = natural_coords.cols();
   const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom();
   const auto nb_element = mesh.getNbElement(type, ghost_type);
   const auto nb_stress_components = ElementClass<type>::getNbStressComponents();
 
   auto itp_type = FEEngine::getInterpolationType(type);
   if (not this->shapes_derivatives.exists(itp_type, ghost_type)) {
     auto size_of_shapesd = this->getShapeDerivativesSize(type);
     this->shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type);
   }
 
   auto & rot_matrices = this->rotation_matrices(type, ghost_type);
 
   Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element);
   FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type);
 
   auto & shapesd = this->shapes_derivatives(itp_type, ghost_type);
   shapesd.resize(nb_element * nb_points);
 
 
   for (auto && tuple :
        zip(make_view(x_el, spatial_dimension, nb_nodes_per_element),
            make_view(shapesd, nb_stress_components,
                      nb_nodes_per_element * nb_dof, nb_points),
            make_view(rot_matrices, nb_dof, nb_dof))) {
     // compute shape derivatives
     auto & X = std::get<0>(tuple);
     auto & B = std::get<1>(tuple);
     auto & RDOFs = std::get<2>(tuple);
 
 
-    // /!\ This is a temporary variable with no specified size for columns !
-    // It is up to the element to resize
     Tensor3<Real> dnds(natural_spatial_dimension,
                        ElementClass<type>::interpolation_property::dnds_columns,
                        B.size(2));
     ElementClass<type>::computeDNDS(natural_coords, X, dnds);
 
-    Tensor3<Real> J(natural_spatial_dimension, natural_coords.rows(), natural_coords.cols());
+    Tensor3<Real> J(natural_spatial_dimension, natural_spatial_dimension,
+                    natural_coords.cols());
 
     // Computing the coordinates of the element in the natural space
     auto R = RDOFs.block(0, 0, spatial_dimension, spatial_dimension);
-    Matrix<Real> T(B.size(1), B.size(1));
-    T.block(RDOFs, 0, 0);
-    T.block(RDOFs, RDOFs.rows(), RDOFs.rows());
+    Matrix<Real> T(B.size(1), B.size(1), 0);
+
+    for (UInt i = 0; i < nb_nodes_per_element; ++i) {
+      T.block(RDOFs, i * RDOFs.rows(), i * RDOFs.rows());
+    }
 
     // Rotate to local basis
     auto x =
         (R * X).block(0, 0, natural_spatial_dimension, nb_nodes_per_element);
 
     ElementClass<type>::computeJMat(natural_coords, x, J);
     ElementClass<type>::computeShapeDerivatives(J, dnds, T, B);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::interpolateOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_dof,
     const GhostType & ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(out_uq.getNbComponent() == nb_dof,
                       "The output array shape is not correct");
 
   auto itp_type = FEEngine::getInterpolationType(type);
   const auto & shapes_ = shapes(itp_type, ghost_type);
 
   auto nb_element = mesh.getNbElement(type, ghost_type);
   auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement();
   auto nb_quad_points_per_element = integration_points(type, ghost_type).cols();
 
   Array<Real> u_el(0, nb_nodes_per_element * nb_dof);
   FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type,
                                        filter_elements);
 
   auto nb_quad_points = nb_quad_points_per_element * u_el.size();
   out_uq.resize(nb_quad_points);
 
   auto out_it = out_uq.begin_reinterpret(nb_dof, 1, nb_quad_points_per_element,
                                          u_el.size());
   auto shapes_it =
       shapes_.begin_reinterpret(nb_dof, nb_dof * nb_nodes_per_element,
                                 nb_quad_points_per_element, nb_element);
   auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1,
                                      nb_quad_points_per_element, u_el.size());
 
   for_each_element(nb_element, filter_elements, [&](auto && el) {
     auto & uq = *out_it;
     const auto & u = *u_it;
     auto N = Tensor3<Real>(shapes_it[el]);
 
     for (auto && q : arange(uq.size(2))) {
       auto uq_q = Matrix<Real>(uq(q));
       auto u_q = Matrix<Real>(u(q));
       auto N_q = Matrix<Real>(N(q));
 
       uq_q.mul<false, false>(N_q, u_q);
     }
 
     ++out_it;
     ++u_it;
   });
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::gradientOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_nablauq, UInt nb_dof,
     const GhostType & ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   auto itp_type = FEEngine::getInterpolationType(type);
   const auto & shapesd = shapes_derivatives(itp_type, ghost_type);
 
   auto nb_element = mesh.getNbElement(type, ghost_type);
   auto element_dimension = ElementClass<type>::getSpatialDimension();
   auto nb_quad_points_per_element = integration_points(type, ghost_type).cols();
   auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement();
 
   Array<Real> u_el(0, nb_nodes_per_element * nb_dof);
   FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type,
                                        filter_elements);
 
   auto nb_quad_points = nb_quad_points_per_element * u_el.size();
   out_nablauq.resize(nb_quad_points);
 
   auto out_it = out_nablauq.begin_reinterpret(
       element_dimension, 1, nb_quad_points_per_element, u_el.size());
   auto shapesd_it = shapesd.begin_reinterpret(
       element_dimension, nb_dof * nb_nodes_per_element,
       nb_quad_points_per_element, nb_element);
   auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1,
                                      nb_quad_points_per_element, u_el.size());
 
   for_each_element(nb_element, filter_elements, [&](auto && el) {
     auto & nablau = *out_it;
     const auto & u = *u_it;
     auto B = Tensor3<Real>(shapesd_it[el]);
 
     for (auto && q : arange(nablau.size(2))) {
       auto nablau_q = Matrix<Real>(nablau(q));
       auto u_q = Matrix<Real>(u(q));
       auto B_q = Matrix<Real>(B(q));
 
       nablau_q.mul<false, false>(B_q, u_q);
     }
 
     ++out_it;
     ++u_it;
   });
 
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+template <>
+template <ElementType type>
+void ShapeStructural<_ek_structural>::computeBtD(
+    const Array<Real> & Ds, Array<Real> & BtDs,
+    GhostType ghost_type, const Array<UInt> & filter_elements) const {
+  auto itp_type = ElementClassProperty<type>::interpolation_type;
+
+  auto nb_stress = ElementClass<type>::getNbStressComponents();
+  auto nb_dof_per_element = ElementClass<type>::getNbDegreeOfFreedom() *
+                            mesh.getNbNodesPerElement(type);
+
+  const auto & shapes_derivatives =
+      this->shapes_derivatives(itp_type, ghost_type);
+
+  Array<Real> shapes_derivatives_filtered(0,
+                                          shapes_derivatives.getNbComponent());
+  auto && view = make_view(shapes_derivatives, nb_stress, nb_dof_per_element);
+  auto B_it = view.begin();
+  auto B_end = view.end();
+
+  if (filter_elements != empty_filter) {
+    FEEngine::filterElementalData(this->mesh, shapes_derivatives,
+                                  shapes_derivatives_filtered, type, ghost_type,
+                                  filter_elements);
+    auto && view =
+        make_view(shapes_derivatives_filtered, nb_stress, nb_dof_per_element);
+    B_it = view.begin();
+    B_end = view.end();
+  }
+
+  for (auto && values :
+       zip(range(B_it, B_end),
+           make_view(Ds, nb_stress),
+           make_view(BtDs, BtDs.getNbComponent()))) {
+    const auto & B = std::get<0>(values);
+    const auto & D = std::get<1>(values);
+    auto & Bt_D = std::get<2>(values);
+    Bt_D.template mul<true>(B, D);
+  }
+}
+
 } // namespace akantu
 
 #endif /* __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ */
diff --git a/src/mesh/element_type_map.cc b/src/mesh/element_type_map.cc
index 10ed4c342..ee0fc8cca 100644
--- a/src/mesh/element_type_map.cc
+++ b/src/mesh/element_type_map.cc
@@ -1,59 +1,71 @@
 /**
  * @file   element_type_map.cc
  *
  * @author Nicolas Richart
  *
  * @date creation  Tue Jun 27 2017
  *
  * @brief A Documented file.
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "fe_engine.hh"
 #include "mesh.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
-FEEngineElementTypeMapArrayInializer::FEEngineElementTypeMapArrayInializer(
+FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer(
     const FEEngine & fe_engine, UInt nb_component, UInt spatial_dimension,
     const GhostType & ghost_type, const ElementKind & element_kind)
-    : MeshElementTypeMapArrayInializer(
-          fe_engine.getMesh(),
-          nb_component,
+    : MeshElementTypeMapArrayInitializer(
+          fe_engine.getMesh(), nb_component,
           spatial_dimension == UInt(-2)
               ? fe_engine.getMesh().getSpatialDimension()
               : spatial_dimension,
           ghost_type, element_kind, true, false),
       fe_engine(fe_engine) {}
 
-UInt FEEngineElementTypeMapArrayInializer::size(
+FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer(
+    const FEEngine & fe_engine,
+    const ElementTypeMapArrayInitializer::CompFunc & nb_component,
+    UInt spatial_dimension, const GhostType & ghost_type,
+    const ElementKind & element_kind)
+    : MeshElementTypeMapArrayInitializer(
+          fe_engine.getMesh(), nb_component,
+          spatial_dimension == UInt(-2)
+              ? fe_engine.getMesh().getSpatialDimension()
+              : spatial_dimension,
+          ghost_type, element_kind, true, false),
+      fe_engine(fe_engine) {}
+
+UInt FEEngineElementTypeMapArrayInitializer::size(
     const ElementType & type) const {
-  return MeshElementTypeMapArrayInializer::size(type) *
+  return MeshElementTypeMapArrayInitializer::size(type) *
          fe_engine.getNbIntegrationPoints(type, this->ghost_type);
 }
 
-FEEngineElementTypeMapArrayInializer::ElementTypesIteratorHelper
-FEEngineElementTypeMapArrayInializer::elementTypes() const {
+FEEngineElementTypeMapArrayInitializer::ElementTypesIteratorHelper
+FEEngineElementTypeMapArrayInitializer::elementTypes() const {
   return this->fe_engine.elementTypes(spatial_dimension, ghost_type,
                                       element_kind);
 }
 } // namespace akantu
diff --git a/src/mesh/element_type_map.hh b/src/mesh/element_type_map.hh
index 2b132a0ee..f3aefd368 100644
--- a/src/mesh/element_type_map.hh
+++ b/src/mesh/element_type_map.hh
@@ -1,444 +1,449 @@
 /**
  * @file   element_type_map.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Aug 31 2011
  * @date last modification: Fri Oct 02 2015
  *
  * @brief  storage class by element type
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_array.hh"
 #include "aka_memory.hh"
 #include "aka_named_argument.hh"
 #include "element.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_TYPE_MAP_HH__
 #define __AKANTU_ELEMENT_TYPE_MAP_HH__
 
 namespace akantu {
 class FEEngine;
 } // namespace akantu
 
 namespace akantu {
 
 namespace {
   DECLARE_NAMED_ARGUMENT(all_ghost_types);
   DECLARE_NAMED_ARGUMENT(default_value);
   DECLARE_NAMED_ARGUMENT(element_kind);
   DECLARE_NAMED_ARGUMENT(ghost_type);
   DECLARE_NAMED_ARGUMENT(nb_component);
   DECLARE_NAMED_ARGUMENT(nb_component_functor);
   DECLARE_NAMED_ARGUMENT(with_nb_element);
   DECLARE_NAMED_ARGUMENT(with_nb_nodes_per_element);
   DECLARE_NAMED_ARGUMENT(spatial_dimension);
   DECLARE_NAMED_ARGUMENT(do_not_default);
 } // namespace
 
 template <class Stored, typename SupportType = ElementType>
 class ElementTypeMap;
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMapBase */
 /* -------------------------------------------------------------------------- */
 /// Common non templated base class for the ElementTypeMap class
 class ElementTypeMapBase {
 public:
   virtual ~ElementTypeMapBase() = default;
 };
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMap */
 /* -------------------------------------------------------------------------- */
 
 template <class Stored, typename SupportType>
 class ElementTypeMap : public ElementTypeMapBase {
 
 public:
   ElementTypeMap();
   ~ElementTypeMap() override;
 
   inline static std::string printType(const SupportType & type,
                                       const GhostType & ghost_type);
 
   /*! Tests whether a type is present in the object
    *  @param type the type to check for
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return true if the type is present. */
   inline bool exists(const SupportType & type,
                      const GhostType & ghost_type = _not_ghost) const;
 
   /*! get the stored data corresponding to a type
    *  @param type the type to check for
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return stored data corresponding to type. */
   inline const Stored &
   operator()(const SupportType & type,
              const GhostType & ghost_type = _not_ghost) const;
 
   /*! get the stored data corresponding to a type
    *  @param type the type to check for
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return stored data corresponding to type. */
   inline Stored & operator()(const SupportType & type,
                              const GhostType & ghost_type = _not_ghost);
 
   /*! insert data of a new type (not yet present) into the map. THIS METHOD IS
    *  NOT ARRAY SAFE, when using ElementTypeMapArray, use setArray instead
    *  @param data to insert
    *  @param type type of data (if this type is already present in the map,
    *         an exception is thrown).
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return stored data corresponding to type. */
   template <typename U>
   inline Stored & operator()(U && insertee, const SupportType & type,
                              const GhostType & ghost_type = _not_ghost);
 
 public:
   /// print helper
   virtual void printself(std::ostream & stream, int indent = 0) const;
 
   /* ------------------------------------------------------------------------ */
   /* Element type Iterator                                                    */
   /* ------------------------------------------------------------------------ */
   /*! iterator allows to iterate over type-data pairs of the map. The interface
    *  expects the SupportType to be ElementType. */
   using DataMap = std::map<SupportType, Stored>;
   class type_iterator
       : private std::iterator<std::forward_iterator_tag, const SupportType> {
   public:
     using value_type = const SupportType;
     using pointer = const SupportType *;
     using reference = const SupportType &;
 
   protected:
     using DataMapIterator =
         typename ElementTypeMap<Stored>::DataMap::const_iterator;
 
   public:
     type_iterator(DataMapIterator & list_begin, DataMapIterator & list_end,
                   UInt dim, ElementKind ek);
 
     type_iterator(const type_iterator & it);
     type_iterator() = default;
 
     inline reference operator*();
     inline reference operator*() const;
     inline type_iterator & operator++();
     type_iterator operator++(int);
     inline bool operator==(const type_iterator & other) const;
     inline bool operator!=(const type_iterator & other) const;
     type_iterator & operator=(const type_iterator & other);
 
   private:
     DataMapIterator list_begin;
     DataMapIterator list_end;
     UInt dim;
     ElementKind kind;
   };
 
   /// helper class to use in range for constructions
   class ElementTypesIteratorHelper {
   public:
     using Container = ElementTypeMap<Stored, SupportType>;
     using iterator = typename Container::type_iterator;
 
     ElementTypesIteratorHelper(const Container & container, UInt dim,
                                GhostType ghost_type, ElementKind kind)
         : container(std::cref(container)), dim(dim), ghost_type(ghost_type),
           kind(kind) {}
 
     template <typename... pack>
     ElementTypesIteratorHelper(const Container & container, use_named_args_t,
                                pack &&... _pack)
         : ElementTypesIteratorHelper(
               container, OPTIONAL_NAMED_ARG(spatial_dimension, _all_dimensions),
               OPTIONAL_NAMED_ARG(ghost_type, _not_ghost),
               OPTIONAL_NAMED_ARG(element_kind, _ek_regular)) {}
 
     ElementTypesIteratorHelper(const ElementTypesIteratorHelper &) = default;
     ElementTypesIteratorHelper &
     operator=(const ElementTypesIteratorHelper &) = default;
     ElementTypesIteratorHelper &
     operator=(ElementTypesIteratorHelper &&) = default;
 
     iterator begin() {
       return container.get().firstType(dim, ghost_type, kind);
     }
     iterator end() { return container.get().lastType(dim, ghost_type, kind); }
 
   private:
     std::reference_wrapper<const Container> container;
     UInt dim;
     GhostType ghost_type;
     ElementKind kind;
   };
 
 private:
   ElementTypesIteratorHelper
   elementTypesImpl(UInt dim = _all_dimensions,
                    GhostType ghost_type = _not_ghost,
                    ElementKind kind = _ek_regular) const;
 
   template <typename... pack>
   ElementTypesIteratorHelper
   elementTypesImpl(const use_named_args_t & /*unused*/, pack &&... _pack) const;
 
 public:
+  /*!
+   * \param _spatial_dimension optional: filter for elements of given spatial
+   * dimension
+   * \param _ghost_type optional: filter for a certain ghost_type
+   * \param _element_kind optional: filter for elements of given kind
+   */
   template <typename... pack>
   std::enable_if_t<are_named_argument<pack...>::value,
                    ElementTypesIteratorHelper>
   elementTypes(pack &&... _pack) const {
     return elementTypesImpl(use_named_args,
                             std::forward<decltype(_pack)>(_pack)...);
   }
 
   template <typename... pack>
   std::enable_if_t<not are_named_argument<pack...>::value,
                    ElementTypesIteratorHelper>
   elementTypes(pack &&... _pack) const {
     return elementTypesImpl(std::forward<decltype(_pack)>(_pack)...);
   }
 
 public:
   /*! Get an iterator to the beginning of a subset datamap. This method expects
    *  the SupportType to be ElementType.
    *  @param dim optional: iterate over data of dimension dim (e.g. when
    *         iterating over (surface) facets of a 3D mesh, dim would be 2).
    *         by default, all dimensions are considered.
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is iterated over.
    *  @param kind optional: the kind of element to search for (see
    *         aka_common.hh), by default all kinds are considered
    *  @return an iterator to the first stored data matching the filters
    *          or an iterator to the end of the map if none match*/
   inline type_iterator firstType(UInt dim = _all_dimensions,
                                  GhostType ghost_type = _not_ghost,
                                  ElementKind kind = _ek_not_defined) const;
   /*! Get an iterator to the end of a subset datamap. This method expects
    *  the SupportType to be ElementType.
    *  @param dim optional: iterate over data of dimension dim (e.g. when
    *         iterating over (surface) facets of a 3D mesh, dim would be 2).
    *         by default, all dimensions are considered.
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is iterated over.
    *  @param kind optional: the kind of element to search for (see
    *         aka_common.hh), by default all kinds are considered
    *  @return an iterator to the last stored data matching the filters
    *          or an iterator to the end of the map if none match */
   inline type_iterator lastType(UInt dim = _all_dimensions,
                                 GhostType ghost_type = _not_ghost,
                                 ElementKind kind = _ek_not_defined) const;
 
 protected:
   /*! Direct access to the underlying data map. for internal use by daughter
    *  classes only
    *  @param ghost_type whether to return the data map or the ghost_data map
    *  @return the raw map */
   inline DataMap & getData(GhostType ghost_type);
   /*! Direct access to the underlying data map. for internal use by daughter
    *  classes only
    *  @param ghost_type whether to return the data map or the ghost_data map
    *  @return the raw map */
   inline const DataMap & getData(GhostType ghost_type) const;
 
   /* ------------------------------------------------------------------------ */
 protected:
   DataMap data;
   DataMap ghost_data;
 };
 
 /* -------------------------------------------------------------------------- */
 /* Some typedefs                                                              */
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 class ElementTypeMapArray : public ElementTypeMap<Array<T> *, SupportType>,
                             public Memory {
 public:
   using type = T;
   using array_type = Array<T>;
 
 protected:
   using parent = ElementTypeMap<Array<T> *, SupportType>;
   using DataMap = typename parent::DataMap;
 
 public:
   using type_iterator = typename parent::type_iterator;
 
   /// standard assigment (copy) operator
   void operator=(const ElementTypeMapArray &) = delete;
   ElementTypeMapArray(const ElementTypeMapArray &) = delete;
 
   /// explicit copy
   void copy(const ElementTypeMapArray & other);
 
   /*! Constructor
    *  @param id optional: identifier (string)
    *  @param parent_id optional: parent identifier. for organizational purposes
    *         only
    *  @param memory_id optional: choose a specific memory, defaults to memory 0
    */
   ElementTypeMapArray(const ID & id = "by_element_type_array",
                       const ID & parent_id = "no_parent",
                       const MemoryID & memory_id = 0)
       : parent(), Memory(parent_id + ":" + id, memory_id), name(id){};
 
   /*! allocate memory for a new array
    *  @param size number of tuples of the new array
    *  @param nb_component tuple size
    *  @param type the type under which the array is indexed in the map
    *  @param ghost_type whether to add the field to the data map or the
    *         ghost_data map
    *  @return a reference to the allocated array */
   inline Array<T> & alloc(UInt size, UInt nb_component,
                           const SupportType & type,
                           const GhostType & ghost_type,
                           const T & default_value = T());
 
   /*! allocate memory for a new array in both the data and the ghost_data map
    *  @param size number of tuples of the new array
    *  @param nb_component tuple size
    *  @param type the type under which the array is indexed in the map*/
   inline void alloc(UInt size, UInt nb_component, const SupportType & type,
                     const T & default_value = T());
 
   /* get a reference to the array of certain type
    * @param type data filed under type is returned
    * @param ghost_type optional: by default the non-ghost map is searched
    * @return a reference to the array */
   inline const Array<T> &
   operator()(const SupportType & type,
              const GhostType & ghost_type = _not_ghost) const;
 
   /// access the data of an element, this combine the map and array accessor
   inline const T & operator()(const Element & element,
                               UInt component = 0) const;
 
   /// access the data of an element, this combine the map and array accessor
   inline T & operator()(const Element & element, UInt component = 0);
 
   /* get a reference to the array of certain type
    * @param type data filed under type is returned
    * @param ghost_type optional: by default the non-ghost map is searched
    * @return a const reference to the array */
   inline Array<T> & operator()(const SupportType & type,
                                const GhostType & ghost_type = _not_ghost);
 
   /*! insert data of a new type (not yet present) into the map.
    *  @param type type of data (if this type is already present in the map,
    *         an exception is thrown).
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @param vect the vector to include into the map
    *  @return stored data corresponding to type. */
   inline void setArray(const SupportType & type, const GhostType & ghost_type,
                        const Array<T> & vect);
   /*! frees all memory related to the data*/
   inline void free();
 
   /*! set all values in the ElementTypeMap to zero*/
   inline void clear();
 
   /*! set all values in the ElementTypeMap to value */
   template <typename ST> inline void set(const ST & value);
 
   /*! deletes and reorders entries in the stored arrays
    *  @param new_numbering a ElementTypeMapArray of new indices. UInt(-1)
    * indicates
    *         deleted entries. */
   inline void
   onElementsRemoved(const ElementTypeMapArray<UInt> & new_numbering);
 
   /// text output helper
   void printself(std::ostream & stream, int indent = 0) const override;
 
   /*! set the id
    *  @param id the new name
    */
   inline void setID(const ID & id) { this->id = id; }
 
   ElementTypeMap<UInt>
   getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost,
                   ElementKind kind = _ek_not_defined) const {
 
     ElementTypeMap<UInt> nb_components;
 
     for (auto & type : this->elementTypes(dim, ghost_type, kind)) {
       UInt nb_comp = (*this)(type, ghost_type).getNbComponent();
       nb_components(type, ghost_type) = nb_comp;
     }
 
     return nb_components;
   }
 
   /* ------------------------------------------------------------------------ */
   /* more evolved allocators                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// initialize the arrays in accordance to a functor
-  template <class Func, class CompFunc>
-  void initialize(const Func & f, const T & default_value, bool do_not_default,
-                  CompFunc && func);
+  template <class Func>
+  void initialize(const Func & f, const T & default_value, bool do_not_default);
 
   /// initialize with sizes and number of components in accordance of a mesh
   /// content
   template <typename... pack>
   void initialize(const Mesh & mesh, pack &&... _pack);
 
   /// initialize with sizes and number of components in accordance of a fe
   /// engine content (aka integration points)
   template <typename... pack>
   void initialize(const FEEngine & fe_engine, pack &&... _pack);
 
   /* ------------------------------------------------------------------------ */
   /* Accesssors                                                               */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the name of the internal field
   AKANTU_GET_MACRO(Name, name, ID);
 
   /// name of the elment type map: e.g. connectivity, grad_u
   ID name;
 };
 
 /// to store data Array<Real> by element type
 using ElementTypeMapReal = ElementTypeMapArray<Real>;
 /// to store data Array<Int> by element type
 using ElementTypeMapInt = ElementTypeMapArray<Int>;
 /// to store data Array<UInt> by element type
 using ElementTypeMapUInt = ElementTypeMapArray<UInt, ElementType>;
 
 /// Map of data of type UInt stored in a mesh
 using UIntDataMap = std::map<std::string, Array<UInt> *>;
 using ElementTypeMapUIntDataMap = ElementTypeMap<UIntDataMap, ElementType>;
 
 } // namespace akantu
 
 #endif /* __AKANTU_ELEMENT_TYPE_MAP_HH__ */
diff --git a/src/mesh/element_type_map_tmpl.hh b/src/mesh/element_type_map_tmpl.hh
index 1c333a3a8..6793158a1 100644
--- a/src/mesh/element_type_map_tmpl.hh
+++ b/src/mesh/element_type_map_tmpl.hh
@@ -1,696 +1,747 @@
 /**
  * @file   element_type_map_tmpl.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Aug 31 2011
  * @date last modification: Fri Oct 02 2015
  *
  * @brief  implementation of template functions of the ElementTypeMap and
  * ElementTypeMapArray classes
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_static_if.hh"
 #include "element_type_map.hh"
 #include "mesh.hh"
 /* -------------------------------------------------------------------------- */
 #include "element_type_conversion.hh"
 /* -------------------------------------------------------------------------- */
 #include <functional>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__
 #define __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMap                                                             */
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline std::string
 ElementTypeMap<Stored, SupportType>::printType(const SupportType & type,
                                                const GhostType & ghost_type) {
   std::stringstream sstr;
   sstr << "(" << ghost_type << ":" << type << ")";
   return sstr.str();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline bool ElementTypeMap<Stored, SupportType>::exists(
     const SupportType & type, const GhostType & ghost_type) const {
   return this->getData(ghost_type).find(type) !=
          this->getData(ghost_type).end();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline const Stored & ElementTypeMap<Stored, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) const {
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end())
     AKANTU_SILENT_EXCEPTION("No element of type "
                             << ElementTypeMap::printType(type, ghost_type)
                             << " in this ElementTypeMap<"
                             << debug::demangle(typeid(Stored).name())
                             << "> class");
   return it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline Stored & ElementTypeMap<Stored, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) {
   return this->getData(ghost_type)[type];
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 template <typename U>
 inline Stored & ElementTypeMap<Stored, SupportType>::
 operator()(U && insertee, const SupportType & type,
            const GhostType & ghost_type) {
   auto it = this->getData(ghost_type).find(type);
 
   if (it != this->getData(ghost_type).end()) {
     AKANTU_SILENT_EXCEPTION("Element of type "
                             << ElementTypeMap::printType(type, ghost_type)
                             << " already in this ElementTypeMap<"
                             << debug::demangle(typeid(Stored).name())
                             << "> class");
   } else {
     auto & data = this->getData(ghost_type);
     const auto & res =
         data.insert(std::make_pair(type, std::forward<U>(insertee)));
     it = res.first;
   }
 
   return it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::DataMap &
 ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) {
   if (ghost_type == _not_ghost)
     return data;
 
   return ghost_data;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline const typename ElementTypeMap<Stored, SupportType>::DataMap &
 ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) const {
   if (ghost_type == _not_ghost)
     return data;
 
   return ghost_data;
 }
 
 /* -------------------------------------------------------------------------- */
 /// Works only if stored is a pointer to a class with a printself method
 template <class Stored, typename SupportType>
 void ElementTypeMap<Stored, SupportType>::printself(std::ostream & stream,
                                                     int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   stream << space << "ElementTypeMap<" << debug::demangle(typeid(Stored).name())
          << "> [" << std::endl;
   for (auto gt : ghost_types) {
     const DataMap & data = getData(gt);
     for (auto & pair : data) {
       stream << space << space << ElementTypeMap::printType(pair.first, gt)
              << std::endl;
     }
   }
 
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::ElementTypeMap() = default;
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::~ElementTypeMap() = default;
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMapArray                                                        */
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 void ElementTypeMapArray<T, SupportType>::copy(
     const ElementTypeMapArray & other) {
   for (auto ghost_type : ghost_types) {
     for (auto type :
          this->elementTypes(_all_dimensions, ghost_types, _ek_not_defined)) {
       const auto & array_to_copy = other(type, ghost_type);
       auto & array =
           this->alloc(0, array_to_copy.getNbComponent(), type, ghost_type);
       array.copy(array_to_copy);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline Array<T> & ElementTypeMapArray<T, SupportType>::alloc(
     UInt size, UInt nb_component, const SupportType & type,
     const GhostType & ghost_type, const T & default_value) {
   std::string ghost_id = "";
   if (ghost_type == _ghost)
     ghost_id = ":ghost";
 
   Array<T> * tmp;
 
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end()) {
     std::stringstream sstr;
     sstr << this->id << ":" << type << ghost_id;
     tmp = &(Memory::alloc<T>(sstr.str(), size, nb_component, default_value));
     std::stringstream sstrg;
     sstrg << ghost_type;
     // tmp->setTag(sstrg.str());
     this->getData(ghost_type)[type] = tmp;
   } else {
     AKANTU_DEBUG_INFO(
         "The vector "
         << this->id << this->printType(type, ghost_type)
         << " already exists, it is resized instead of allocated.");
     tmp = it->second;
     it->second->resize(size);
   }
 
   return *tmp;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void
 ElementTypeMapArray<T, SupportType>::alloc(UInt size, UInt nb_component,
                                            const SupportType & type,
                                            const T & default_value) {
   this->alloc(size, nb_component, type, _not_ghost, default_value);
   this->alloc(size, nb_component, type, _ghost, default_value);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void ElementTypeMapArray<T, SupportType>::free() {
   AKANTU_DEBUG_IN();
 
   for (auto gt : ghost_types) {
     auto & data = this->getData(gt);
     for (auto & pair : data) {
       dealloc(pair.second->getID());
     }
     data.clear();
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void ElementTypeMapArray<T, SupportType>::clear() {
   for (auto gt : ghost_types) {
     auto & data = this->getData(gt);
     for (auto & vect : data) {
       vect.second->clear();
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 template <typename ST>
 inline void ElementTypeMapArray<T, SupportType>::set(const ST & value) {
   for (auto gt : ghost_types) {
     auto & data = this->getData(gt);
     for (auto & vect : data) {
       vect.second->set(value);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline const Array<T> & ElementTypeMapArray<T, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) const {
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end())
     AKANTU_SILENT_EXCEPTION("No element of type "
                             << ElementTypeMapArray::printType(type, ghost_type)
                             << " in this const ElementTypeMapArray<"
                             << debug::demangle(typeid(T).name()) << "> class(\""
                             << this->id << "\")");
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline Array<T> & ElementTypeMapArray<T, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) {
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end())
     AKANTU_SILENT_EXCEPTION("No element of type "
                             << ElementTypeMapArray::printType(type, ghost_type)
                             << " in this ElementTypeMapArray<"
                             << debug::demangle(typeid(T).name())
                             << "> class (\"" << this->id << "\")");
 
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void
 ElementTypeMapArray<T, SupportType>::setArray(const SupportType & type,
                                               const GhostType & ghost_type,
                                               const Array<T> & vect) {
   auto it = this->getData(ghost_type).find(type);
 
   if (AKANTU_DEBUG_TEST(dblWarning) && it != this->getData(ghost_type).end() &&
       it->second != &vect) {
     AKANTU_DEBUG_WARNING(
         "The Array "
         << this->printType(type, ghost_type)
         << " is already registred, this call can lead to a memory leak.");
   }
 
   this->getData(ghost_type)[type] = &(const_cast<Array<T> &>(vect));
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void ElementTypeMapArray<T, SupportType>::onElementsRemoved(
     const ElementTypeMapArray<UInt> & new_numbering) {
   for (auto gt : ghost_types) {
     for (auto & type :
          new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) {
       auto support_type = convertType<ElementType, SupportType>(type);
       if (this->exists(support_type, gt)) {
         const auto & renumbering = new_numbering(type, gt);
         if (renumbering.size() == 0)
           continue;
 
         auto & vect = this->operator()(support_type, gt);
         auto nb_component = vect.getNbComponent();
         Array<T> tmp(renumbering.size(), nb_component);
         UInt new_size = 0;
 
         for (UInt i = 0; i < vect.size(); ++i) {
           UInt new_i = renumbering(i);
           if (new_i != UInt(-1)) {
             memcpy(tmp.storage() + new_i * nb_component,
                    vect.storage() + i * nb_component, nb_component * sizeof(T));
             ++new_size;
           }
         }
         tmp.resize(new_size);
         vect.copy(tmp);
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 void ElementTypeMapArray<T, SupportType>::printself(std::ostream & stream,
                                                     int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   stream << space << "ElementTypeMapArray<" << debug::demangle(typeid(T).name())
          << "> [" << std::endl;
   for (UInt g = _not_ghost; g <= _ghost; ++g) {
     auto gt = (GhostType)g;
 
     const DataMap & data = this->getData(gt);
     typename DataMap::const_iterator it;
     for (it = data.begin(); it != data.end(); ++it) {
       stream << space << space << ElementTypeMapArray::printType(it->first, gt)
              << " [" << std::endl;
       it->second->printself(stream, indent + 3);
       stream << space << space << " ]" << std::endl;
     }
   }
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 /* SupportType Iterator                                                       */
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator(
     DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim,
     ElementKind ek)
     : list_begin(list_begin), list_end(list_end), dim(dim), kind(ek) {}
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator(
     const type_iterator & it)
     : list_begin(it.list_begin), list_end(it.list_end), dim(it.dim),
       kind(it.kind) {}
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 typename ElementTypeMap<Stored, SupportType>::type_iterator &
 ElementTypeMap<Stored, SupportType>::type_iterator::
 operator=(const type_iterator & it) {
   if (this != &it) {
     list_begin = it.list_begin;
     list_end = it.list_end;
     dim = it.dim;
     kind = it.kind;
   }
   return *this;
 }
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference
     ElementTypeMap<Stored, SupportType>::type_iterator::operator*() {
   return list_begin->first;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference
     ElementTypeMap<Stored, SupportType>::type_iterator::operator*() const {
   return list_begin->first;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator &
     ElementTypeMap<Stored, SupportType>::type_iterator::operator++() {
   ++list_begin;
   while ((list_begin != list_end) &&
          (((dim != _all_dimensions) &&
            (dim != Mesh::getSpatialDimension(list_begin->first))) ||
           ((kind != _ek_not_defined) &&
            (kind != Mesh::getKind(list_begin->first)))))
     ++list_begin;
   return *this;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 typename ElementTypeMap<Stored, SupportType>::type_iterator
     ElementTypeMap<Stored, SupportType>::type_iterator::operator++(int) {
   type_iterator tmp(*this);
   operator++();
   return tmp;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline bool ElementTypeMap<Stored, SupportType>::type_iterator::
 operator==(const type_iterator & other) const {
   return this->list_begin == other.list_begin;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline bool ElementTypeMap<Stored, SupportType>::type_iterator::
 operator!=(const type_iterator & other) const {
   return this->list_begin != other.list_begin;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper
 ElementTypeMap<Stored, SupportType>::elementTypesImpl(UInt dim,
                                                       GhostType ghost_type,
                                                       ElementKind kind) const {
   return ElementTypesIteratorHelper(*this, dim, ghost_type, kind);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 template <typename... pack>
 typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper
 ElementTypeMap<Stored, SupportType>::elementTypesImpl(
     const use_named_args_t & unused, pack &&... _pack) const {
   return ElementTypesIteratorHelper(*this, unused, _pack...);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator
 ElementTypeMap<Stored, SupportType>::firstType(UInt dim, GhostType ghost_type,
                                                ElementKind kind) const {
   typename DataMap::const_iterator b, e;
   b = getData(ghost_type).begin();
   e = getData(ghost_type).end();
 
   // loop until the first valid type
   while ((b != e) &&
          (((dim != _all_dimensions) &&
            (dim != Mesh::getSpatialDimension(b->first))) ||
           ((kind != _ek_not_defined) && (kind != Mesh::getKind(b->first)))))
     ++b;
 
   return typename ElementTypeMap<Stored, SupportType>::type_iterator(b, e, dim,
                                                                      kind);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator
 ElementTypeMap<Stored, SupportType>::lastType(UInt dim, GhostType ghost_type,
                                               ElementKind kind) const {
   typename DataMap::const_iterator e;
   e = getData(ghost_type).end();
   return typename ElementTypeMap<Stored, SupportType>::type_iterator(e, e, dim,
                                                                      kind);
 }
 
 /* -------------------------------------------------------------------------- */
 
 /// standard output stream operator
 template <class Stored, typename SupportType>
 inline std::ostream &
 operator<<(std::ostream & stream,
            const ElementTypeMap<Stored, SupportType> & _this) {
   _this.printself(stream);
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
-class ElementTypeMapArrayInializer {
+class ElementTypeMapArrayInitializer {
+protected:
+  using CompFunc = std::function<UInt(const ElementType &, const GhostType &)>;
+
 public:
-  ElementTypeMapArrayInializer(UInt spatial_dimension = _all_dimensions,
-                               UInt nb_component = 1,
-                               const GhostType & ghost_type = _not_ghost,
-                               const ElementKind & element_kind = _ek_regular)
-      : spatial_dimension(spatial_dimension), nb_component(nb_component),
+  ElementTypeMapArrayInitializer(const CompFunc & comp_func,
+                                 UInt spatial_dimension = _all_dimensions,
+                                 const GhostType & ghost_type = _not_ghost,
+                                 const ElementKind & element_kind = _ek_regular)
+      : comp_func(comp_func), spatial_dimension(spatial_dimension),
         ghost_type(ghost_type), element_kind(element_kind) {}
 
   const GhostType & ghostType() const { return ghost_type; }
 
+  virtual UInt nbComponent(const ElementType & type) const {
+    return comp_func(type, ghostType());
+  }
+
 protected:
+  CompFunc comp_func;
   UInt spatial_dimension;
-  UInt nb_component;
   GhostType ghost_type;
   ElementKind element_kind;
 };
 
 /* -------------------------------------------------------------------------- */
-class MeshElementTypeMapArrayInializer : public ElementTypeMapArrayInializer {
+class MeshElementTypeMapArrayInitializer
+    : public ElementTypeMapArrayInitializer {
+  using CompFunc = ElementTypeMapArrayInitializer::CompFunc;
+
 public:
-  MeshElementTypeMapArrayInializer(
+  MeshElementTypeMapArrayInitializer(
       const Mesh & mesh, UInt nb_component = 1,
       UInt spatial_dimension = _all_dimensions,
       const GhostType & ghost_type = _not_ghost,
       const ElementKind & element_kind = _ek_regular,
       bool with_nb_element = false, bool with_nb_nodes_per_element = false)
-      : ElementTypeMapArrayInializer(spatial_dimension, nb_component,
-                                     ghost_type, element_kind),
+      : MeshElementTypeMapArrayInitializer(
+            mesh,
+            [nb_component](const ElementType &, const GhostType &) -> UInt {
+              return nb_component;
+            },
+            spatial_dimension, ghost_type, element_kind, with_nb_element,
+            with_nb_nodes_per_element) {}
+
+  MeshElementTypeMapArrayInitializer(
+      const Mesh & mesh, const CompFunc & comp_func,
+      UInt spatial_dimension = _all_dimensions,
+      const GhostType & ghost_type = _not_ghost,
+      const ElementKind & element_kind = _ek_regular,
+      bool with_nb_element = false, bool with_nb_nodes_per_element = false)
+      : ElementTypeMapArrayInitializer(comp_func, spatial_dimension, ghost_type,
+                                       element_kind),
         mesh(mesh), with_nb_element(with_nb_element),
         with_nb_nodes_per_element(with_nb_nodes_per_element) {}
 
   decltype(auto) elementTypes() const {
     return mesh.elementTypes(this->spatial_dimension, this->ghost_type,
                              this->element_kind);
   }
 
   virtual UInt size(const ElementType & type) const {
     if (with_nb_element)
       return mesh.getNbElement(type, this->ghost_type);
 
     return 0;
   }
 
-  UInt nbComponent(const ElementType & type) const {
+  UInt nbComponent(const ElementType & type) const override {
+    UInt res = ElementTypeMapArrayInitializer::nbComponent(type);
     if (with_nb_nodes_per_element)
-      return (this->nb_component * mesh.getNbNodesPerElement(type));
+      return (res * mesh.getNbNodesPerElement(type));
 
-    return this->nb_component;
+    return res;
   }
 
 protected:
   const Mesh & mesh;
   bool with_nb_element;
   bool with_nb_nodes_per_element;
 };
 
 /* -------------------------------------------------------------------------- */
-class FEEngineElementTypeMapArrayInializer
-    : public MeshElementTypeMapArrayInializer {
+class FEEngineElementTypeMapArrayInitializer
+    : public MeshElementTypeMapArrayInitializer {
 public:
-  FEEngineElementTypeMapArrayInializer(
+  FEEngineElementTypeMapArrayInitializer(
       const FEEngine & fe_engine, UInt nb_component = 1,
       UInt spatial_dimension = _all_dimensions,
       const GhostType & ghost_type = _not_ghost,
       const ElementKind & element_kind = _ek_regular);
 
+  FEEngineElementTypeMapArrayInitializer(
+      const FEEngine & fe_engine,
+      const ElementTypeMapArrayInitializer::CompFunc & nb_component,
+      UInt spatial_dimension = _all_dimensions,
+      const GhostType & ghost_type = _not_ghost,
+      const ElementKind & element_kind = _ek_regular);
+
   UInt size(const ElementType & type) const override;
 
   using ElementTypesIteratorHelper =
       ElementTypeMapArray<Real, ElementType>::ElementTypesIteratorHelper;
 
   ElementTypesIteratorHelper elementTypes() const;
 
 protected:
   const FEEngine & fe_engine;
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
-template <class Func, class CompFunc>
+template <class Func>
 void ElementTypeMapArray<T, SupportType>::initialize(const Func & f,
                                                      const T & default_value,
-                                                     bool do_not_default,
-                                                     CompFunc && comp_func) {
+                                                     bool do_not_default) {
   auto ghost_type = f.ghostType();
   for (auto & type : f.elementTypes()) {
     if (not this->exists(type, ghost_type))
       if (do_not_default) {
-        auto & array =
-            this->alloc(0, comp_func(type, ghost_type), type, ghost_type);
+        auto & array = this->alloc(0, f.nbComponent(type), type, ghost_type);
         array.resize(f.size(type));
       } else {
-        this->alloc(f.size(type), comp_func(type, ghost_type), type, ghost_type,
+        this->alloc(f.size(type), f.nbComponent(type), type, ghost_type,
                     default_value);
       }
     else {
       auto & array = this->operator()(type, ghost_type);
       if (not do_not_default)
         array.resize(f.size(type), default_value);
       else
         array.resize(f.size(type));
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * All parameters are named optionals
+ *  \param _nb_component a functor giving the number of components per
+ *  (ElementType, GhostType) pair or a scalar giving a unique number of
+ * components
+ *  regardless of type
+ *  \param _spatial_dimension a filter for the elements of a specific dimension
+ *  \param _element_kind filter with element kind (_ek_regular, _ek_structural,
+ * ...)
+ *  \param _with_nb_element allocate the arrays with the number of elements for
+ * each
+ *  type in the mesh
+ *  \param _with_nb_nodes_per_element multiply the number of components by the
+ *  number of nodes per element
+ *  \param _default_value default inital value
+ *  \param _do_not_default do not initialize the allocated arrays
+ *  \param _ghost_type filter a type of ghost
+ */
 template <typename T, typename SupportType>
 template <typename... pack>
 void ElementTypeMapArray<T, SupportType>::initialize(const Mesh & mesh,
                                                      pack &&... _pack) {
   GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _casper);
   bool all_ghost_types = requested_ghost_type == _casper;
 
   for (auto ghost_type : ghost_types) {
     if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types))
       continue;
 
-    auto functor = MeshElementTypeMapArrayInializer(
-        mesh, OPTIONAL_NAMED_ARG(nb_component, 1),
+    // This thing should have a UInt or functor type
+    auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1);
+    auto functor = MeshElementTypeMapArrayInitializer(
+        mesh, std::forward<decltype(nb_components)>(nb_components),
         OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()),
         ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular),
         OPTIONAL_NAMED_ARG(with_nb_element, false),
         OPTIONAL_NAMED_ARG(with_nb_nodes_per_element, false));
 
-    std::function<UInt(const ElementType &, const GhostType &)>
-        nb_component_functor =
-            [&](const ElementType & type, const GhostType &
-                /*ghost_type*/) -> UInt { return functor.nbComponent(type); };
-
-    this->initialize(
-        functor, OPTIONAL_NAMED_ARG(default_value, T()),
-        OPTIONAL_NAMED_ARG(do_not_default, false),
-        OPTIONAL_NAMED_ARG(nb_component_functor, nb_component_functor));
+    this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()),
+                     OPTIONAL_NAMED_ARG(do_not_default, false));
   }
 }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * All parameters are named optionals
+ *  \param _nb_component a functor giving the number of components per
+ *  (ElementType, GhostType) pair or a scalar giving a unique number of
+ * components
+ *  regardless of type
+ *  \param _spatial_dimension a filter for the elements of a specific dimension
+ *  \param _element_kind filter with element kind (_ek_regular, _ek_structural,
+ * ...)
+ *  \param _default_value default inital value
+ *  \param _do_not_default do not initialize the allocated arrays
+ *  \param _ghost_type filter a specific ghost type
+ *  \param _all_ghost_types get all ghost types
+ */
 template <typename T, typename SupportType>
 template <typename... pack>
 void ElementTypeMapArray<T, SupportType>::initialize(const FEEngine & fe_engine,
                                                      pack &&... _pack) {
   bool all_ghost_types = OPTIONAL_NAMED_ARG(all_ghost_types, true);
   GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _not_ghost);
 
   for (auto ghost_type : ghost_types) {
     if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types))
       continue;
 
-    auto functor = FEEngineElementTypeMapArrayInializer(
-        fe_engine, OPTIONAL_NAMED_ARG(nb_component, 1),
+    auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1);
+    auto functor = FEEngineElementTypeMapArrayInitializer(
+        fe_engine, std::forward<decltype(nb_components)>(nb_components),
         OPTIONAL_NAMED_ARG(spatial_dimension, UInt(-2)), ghost_type,
         OPTIONAL_NAMED_ARG(element_kind, _ek_regular));
 
-    std::function<UInt(const ElementType &, const GhostType &)>
-        nb_component_functor =
-            [&](const ElementType & type, const GhostType &
-                /*ghost_type*/) -> UInt { return functor.nbComponent(type); };
-
-    this->initialize(
-        functor, OPTIONAL_NAMED_ARG(default_value, T()),
-        OPTIONAL_NAMED_ARG(do_not_default, false),
-        OPTIONAL_NAMED_ARG(nb_component_functor, nb_component_functor));
+    this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()),
+                     OPTIONAL_NAMED_ARG(do_not_default, false));
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <class T, typename SupportType>
 inline T & ElementTypeMapArray<T, SupportType>::
 operator()(const Element & element, UInt component) {
   return this->operator()(element.type, element.ghost_type)(element.element,
                                                             component);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class T, typename SupportType>
 inline const T & ElementTypeMapArray<T, SupportType>::
 operator()(const Element & element, UInt component) const {
   return this->operator()(element.type, element.ghost_type)(element.element,
                                                             component);
 }
 
 } // namespace akantu
 
 #endif /* __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ */
diff --git a/src/model/dof_manager.cc b/src/model/dof_manager.cc
index 7b574f25a..7aaa2fccc 100644
--- a/src/model/dof_manager.cc
+++ b/src/model/dof_manager.cc
@@ -1,592 +1,604 @@
 /**
  * @file   dof_manager.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Aug 12 09:52:30 2015
  *
  * @brief  Implementation of the common parts of the DOFManagers
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "dof_manager.hh"
+#include "communicator.hh"
 #include "element_group.hh"
 #include "mesh.hh"
 #include "mesh_utils.hh"
 #include "node_group.hh"
 #include "non_linear_solver.hh"
 #include "sparse_matrix.hh"
-#include "communicator.hh"
 #include "time_step_solver.hh"
 /* -------------------------------------------------------------------------- */
 #include <memory>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 DOFManager::DOFManager(const ID & id, const MemoryID & memory_id)
     : Memory(id, memory_id),
       communicator(Communicator::getStaticCommunicator()) {}
 
 /* -------------------------------------------------------------------------- */
 DOFManager::DOFManager(Mesh & mesh, const ID & id, const MemoryID & memory_id)
     : Memory(id, memory_id), mesh(&mesh), local_system_size(0),
       pure_local_system_size(0), system_size(0),
       communicator(mesh.getCommunicator()) {
   this->mesh->registerEventHandler(*this, _ehp_dof_manager);
 }
 
 /* -------------------------------------------------------------------------- */
 DOFManager::~DOFManager() = default;
 
 /* -------------------------------------------------------------------------- */
 // void DOFManager::getEquationsNumbers(const ID &, Array<UInt> &) {
 //   AKANTU_TO_IMPLEMENT();
 // }
 
 /* -------------------------------------------------------------------------- */
 std::vector<ID> DOFManager::getDOFIDs() const {
   std::vector<ID> keys;
   for (const auto & dof_data : this->dofs)
     keys.push_back(dof_data.first);
 
   return keys;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::assembleElementalArrayLocalArray(
     const Array<Real> & elementary_vect, Array<Real> & array_assembeled,
     const ElementType & type, const GhostType & ghost_type, Real scale_factor,
     const Array<UInt> & filter_elements) {
   AKANTU_DEBUG_IN();
 
   UInt nb_element;
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_degree_of_freedom =
       elementary_vect.getNbComponent() / nb_nodes_per_element;
 
   UInt * filter_it = nullptr;
   if (filter_elements != empty_filter) {
     nb_element = filter_elements.size();
     filter_it = filter_elements.storage();
   } else {
     nb_element = this->mesh->getNbElement(type, ghost_type);
   }
 
   AKANTU_DEBUG_ASSERT(elementary_vect.size() == nb_element,
                       "The vector elementary_vect("
                           << elementary_vect.getID()
                           << ") has not the good size.");
 
   const Array<UInt> & connectivity =
       this->mesh->getConnectivity(type, ghost_type);
   // Array<UInt>::const_vector_iterator conn_begin =
   //     connectivity.begin(nb_nodes_per_element);
   // Array<UInt>::const_vector_iterator conn_it = conn_begin;
 
   Array<Real>::const_matrix_iterator elem_it =
       elementary_vect.begin(nb_degree_of_freedom, nb_nodes_per_element);
 
   for (UInt el = 0; el < nb_element; ++el, ++elem_it) {
     UInt element = el;
     if (filter_it != nullptr) {
       // conn_it = conn_begin + *filter_it;
       element = *filter_it;
     }
 
     // const Vector<UInt> & conn = *conn_it;
     const Matrix<Real> & elemental_val = *elem_it;
     for (UInt n = 0; n < nb_nodes_per_element; ++n) {
       UInt offset_node = connectivity(element, n) * nb_degree_of_freedom;
       Vector<Real> assemble(array_assembeled.storage() + offset_node,
                             nb_degree_of_freedom);
       Vector<Real> elem_val = elemental_val(n);
       assemble.aXplusY(elem_val, scale_factor);
     }
 
     if (filter_it != nullptr)
       ++filter_it;
     //    else
     //      ++conn_it;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::assembleElementalArrayToResidual(
     const ID & dof_id, const Array<Real> & elementary_vect,
     const ElementType & type, const GhostType & ghost_type, Real scale_factor,
     const Array<UInt> & filter_elements) {
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_degree_of_freedom =
       elementary_vect.getNbComponent() / nb_nodes_per_element;
   Array<Real> array_localy_assembeled(this->mesh->getNbNodes(),
                                       nb_degree_of_freedom);
 
   array_localy_assembeled.clear();
 
   this->assembleElementalArrayLocalArray(
       elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor,
       filter_elements);
 
   this->assembleToResidual(dof_id, array_localy_assembeled, 1);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::assembleElementalArrayToLumpedMatrix(
     const ID & dof_id, const Array<Real> & elementary_vect,
     const ID & lumped_mtx, const ElementType & type,
     const GhostType & ghost_type, Real scale_factor,
     const Array<UInt> & filter_elements) {
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_degree_of_freedom =
       elementary_vect.getNbComponent() / nb_nodes_per_element;
   Array<Real> array_localy_assembeled(this->mesh->getNbNodes(),
                                       nb_degree_of_freedom);
 
   array_localy_assembeled.clear();
 
   this->assembleElementalArrayLocalArray(
       elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor,
       filter_elements);
 
   this->assembleToLumpedMatrix(dof_id, array_localy_assembeled, lumped_mtx, 1);
 
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+void DOFManager::assembleMatMulDOFsToResidual(const ID & A_id,
+                                              Real scale_factor) {
+  for (auto & pair : this->dofs) {
+    const auto & dof_id = pair.first;
+    auto & dof_data = *pair.second;
+
+    this->assembleMatMulVectToResidual(dof_id, A_id, *dof_data.dof,
+                                       scale_factor);
+  }
+}
+
 /* -------------------------------------------------------------------------- */
 DOFManager::DOFData::DOFData(const ID & dof_id)
     : support_type(_dst_generic), group_support("__mesh__"), dof(nullptr),
       blocked_dofs(nullptr), increment(nullptr), previous(nullptr),
       solution(0, 1, dof_id + ":solution"),
       local_equation_number(0, 1, dof_id + ":local_equation_number") {}
 
 /* -------------------------------------------------------------------------- */
 DOFManager::DOFData::~DOFData() = default;
 
 /* -------------------------------------------------------------------------- */
 DOFManager::DOFData & DOFManager::getNewDOFData(const ID & dof_id) {
   auto it = this->dofs.find(dof_id);
   if (it != this->dofs.end()) {
     AKANTU_EXCEPTION("This dof array has already been registered");
   }
 
   std::unique_ptr<DOFData> dofs_storage = std::make_unique<DOFData>(dof_id);
   this->dofs[dof_id] = std::move(dofs_storage);
   return *dofs_storage;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFsInternal(const ID & dof_id,
                                       Array<Real> & dofs_array) {
   DOFData & dofs_storage = this->getDOFData(dof_id);
   dofs_storage.dof = &dofs_array;
 
   UInt nb_local_dofs = 0;
   UInt nb_pure_local = 0;
 
   const DOFSupportType & support_type = dofs_storage.support_type;
 
   switch (support_type) {
   case _dst_nodal: {
     UInt nb_nodes = 0;
     const ID & group = dofs_storage.group_support;
 
     NodeGroup * node_group = nullptr;
     if (group == "__mesh__") {
       nb_nodes = this->mesh->getNbNodes();
     } else {
       node_group = &this->mesh->getElementGroup(group).getNodeGroup();
       nb_nodes = node_group->size();
     }
 
     nb_local_dofs = nb_nodes;
     AKANTU_DEBUG_ASSERT(
         dofs_array.size() == nb_local_dofs,
         "The array of dof is too shot to be associated to nodes.");
 
     for (UInt n = 0; n < nb_nodes; ++n) {
       UInt node = n;
       if (node_group)
         node = node_group->getNodes()(n);
 
       nb_pure_local += this->mesh->isLocalOrMasterNode(node) ? 1 : 0;
     }
 
     nb_pure_local *= dofs_array.getNbComponent();
     nb_local_dofs *= dofs_array.getNbComponent();
     break;
   }
   case _dst_generic: {
     nb_local_dofs = nb_pure_local =
         dofs_array.size() * dofs_array.getNbComponent();
     break;
   }
   default: { AKANTU_EXCEPTION("This type of dofs is not handled yet."); }
   }
 
   this->pure_local_system_size += nb_pure_local;
   this->local_system_size += nb_local_dofs;
 
   communicator.allReduce(nb_pure_local, SynchronizerOperation::_sum);
 
   this->system_size += nb_pure_local;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array,
                               const DOFSupportType & support_type) {
   DOFData & dofs_storage = this->getNewDOFData(dof_id);
   dofs_storage.support_type = support_type;
 
   this->registerDOFsInternal(dof_id, dofs_array);
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array,
                               const ID & support_group) {
   DOFData & dofs_storage = this->getNewDOFData(dof_id);
   dofs_storage.support_type = _dst_nodal;
   dofs_storage.group_support = support_group;
 
   this->registerDOFsInternal(dof_id, dofs_array);
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFsPrevious(const ID & dof_id, Array<Real> & array) {
   DOFData & dof = this->getDOFData(dof_id);
 
   if (dof.previous != nullptr) {
     AKANTU_EXCEPTION("The previous dofs array for "
                      << dof_id << " has already been registered");
   }
 
   dof.previous = &array;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFsIncrement(const ID & dof_id, Array<Real> & array) {
   DOFData & dof = this->getDOFData(dof_id);
 
   if (dof.increment != nullptr) {
     AKANTU_EXCEPTION("The dofs increment array for "
                      << dof_id << " has already been registered");
   }
 
   dof.increment = &array;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFsDerivative(const ID & dof_id, UInt order,
                                         Array<Real> & dofs_derivative) {
   DOFData & dof = this->getDOFData(dof_id);
   std::vector<Array<Real> *> & derivatives = dof.dof_derivatives;
 
   if (derivatives.size() < order) {
     derivatives.resize(order, nullptr);
   } else {
     if (derivatives[order - 1] != nullptr) {
       AKANTU_EXCEPTION("The dof derivatives of order "
                        << order << " already been registered for this dof ("
                        << dof_id << ")");
     }
   }
 
   derivatives[order - 1] = &dofs_derivative;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerBlockedDOFs(const ID & dof_id,
                                      Array<bool> & blocked_dofs) {
   DOFData & dof = this->getDOFData(dof_id);
 
   if (dof.blocked_dofs != nullptr) {
     AKANTU_EXCEPTION("The blocked dofs array for "
                      << dof_id << " has already been registered");
   }
 
   dof.blocked_dofs = &blocked_dofs;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::splitSolutionPerDOFs() {
   auto it = this->dofs.begin();
   auto end = this->dofs.end();
 
   for (; it != end; ++it) {
     DOFData & dof_data = *it->second;
     dof_data.solution.resize(dof_data.dof->size() *
                              dof_data.dof->getNbComponent());
     this->getSolutionPerDOFs(it->first, dof_data.solution);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 SparseMatrix &
 DOFManager::registerSparseMatrix(const ID & matrix_id,
                                  std::unique_ptr<SparseMatrix> & matrix) {
   SparseMatricesMap::const_iterator it = this->matrices.find(matrix_id);
   if (it != this->matrices.end()) {
     AKANTU_EXCEPTION("The matrix " << matrix_id << " already exists in "
                                    << this->id);
   }
 
   SparseMatrix & ret = *matrix;
   this->matrices[matrix_id] = std::move(matrix);
   return ret;
 }
 
 /* -------------------------------------------------------------------------- */
 /// Get an instance of a new SparseMatrix
 Array<Real> & DOFManager::getNewLumpedMatrix(const ID & id) {
   ID matrix_id = this->id + ":lumped_mtx:" + id;
   LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(matrix_id);
   if (it != this->lumped_matrices.end()) {
     AKANTU_EXCEPTION("The lumped matrix " << matrix_id << " already exists in "
                                           << this->id);
   }
 
   auto mtx =
       std::make_unique<Array<Real>>(this->local_system_size, 1, matrix_id);
   this->lumped_matrices[matrix_id] = std::move(mtx);
   return *this->lumped_matrices[matrix_id];
 }
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolver & DOFManager::registerNonLinearSolver(
     const ID & non_linear_solver_id,
     std::unique_ptr<NonLinearSolver> & non_linear_solver) {
   NonLinearSolversMap::const_iterator it =
       this->non_linear_solvers.find(non_linear_solver_id);
   if (it != this->non_linear_solvers.end()) {
     AKANTU_EXCEPTION("The non linear solver " << non_linear_solver_id
                                               << " already exists in "
                                               << this->id);
   }
 
   NonLinearSolver & ret = *non_linear_solver;
   this->non_linear_solvers[non_linear_solver_id] = std::move(non_linear_solver);
 
   return ret;
 }
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolver & DOFManager::registerTimeStepSolver(
     const ID & time_step_solver_id,
     std::unique_ptr<TimeStepSolver> & time_step_solver) {
   TimeStepSolversMap::const_iterator it =
       this->time_step_solvers.find(time_step_solver_id);
   if (it != this->time_step_solvers.end()) {
     AKANTU_EXCEPTION("The non linear solver " << time_step_solver_id
                                               << " already exists in "
                                               << this->id);
   }
 
   TimeStepSolver & ret = *time_step_solver;
   this->time_step_solvers[time_step_solver_id] = std::move(time_step_solver);
   return ret;
 }
 
 /* -------------------------------------------------------------------------- */
 SparseMatrix & DOFManager::getMatrix(const ID & id) {
   ID matrix_id = this->id + ":mtx:" + id;
   SparseMatricesMap::const_iterator it = this->matrices.find(matrix_id);
   if (it == this->matrices.end()) {
     AKANTU_SILENT_EXCEPTION("The matrix " << matrix_id << " does not exists in "
                                           << this->id);
   }
 
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 bool DOFManager::hasMatrix(const ID & id) const {
   ID mtx_id = this->id + ":mtx:" + id;
   auto it = this->matrices.find(mtx_id);
   return it != this->matrices.end();
 }
 
 /* -------------------------------------------------------------------------- */
 Array<Real> & DOFManager::getLumpedMatrix(const ID & id) {
   ID matrix_id = this->id + ":lumped_mtx:" + id;
   LumpedMatricesMap::const_iterator it = this->lumped_matrices.find(matrix_id);
   if (it == this->lumped_matrices.end()) {
     AKANTU_SILENT_EXCEPTION("The lumped matrix "
                             << matrix_id << " does not exists in " << this->id);
   }
 
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 const Array<Real> & DOFManager::getLumpedMatrix(const ID & id) const {
   ID matrix_id = this->id + ":lumped_mtx:" + id;
   auto it = this->lumped_matrices.find(matrix_id);
   if (it == this->lumped_matrices.end()) {
     AKANTU_SILENT_EXCEPTION("The lumped matrix "
                             << matrix_id << " does not exists in " << this->id);
   }
 
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 bool DOFManager::hasLumpedMatrix(const ID & id) const {
   ID mtx_id = this->id + ":lumped_mtx:" + id;
   auto it = this->lumped_matrices.find(mtx_id);
   return it != this->lumped_matrices.end();
 }
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolver & DOFManager::getNonLinearSolver(const ID & id) {
   ID non_linear_solver_id = this->id + ":nls:" + id;
   NonLinearSolversMap::const_iterator it =
       this->non_linear_solvers.find(non_linear_solver_id);
   if (it == this->non_linear_solvers.end()) {
     AKANTU_EXCEPTION("The non linear solver " << non_linear_solver_id
                                               << " does not exists in "
                                               << this->id);
   }
 
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 bool DOFManager::hasNonLinearSolver(const ID & id) const {
   ID solver_id = this->id + ":nls:" + id;
   auto it = this->non_linear_solvers.find(solver_id);
   return it != this->non_linear_solvers.end();
 }
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolver & DOFManager::getTimeStepSolver(const ID & id) {
   ID time_step_solver_id = this->id + ":tss:" + id;
   TimeStepSolversMap::const_iterator it =
       this->time_step_solvers.find(time_step_solver_id);
   if (it == this->time_step_solvers.end()) {
     AKANTU_EXCEPTION("The non linear solver " << time_step_solver_id
                                               << " does not exists in "
                                               << this->id);
   }
 
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 bool DOFManager::hasTimeStepSolver(const ID & solver_id) const {
   ID time_step_solver_id = this->id + ":tss:" + solver_id;
   auto it = this->time_step_solvers.find(time_step_solver_id);
   return it != this->time_step_solvers.end();
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::savePreviousDOFs(const ID & dofs_id) {
   this->getPreviousDOFs(dofs_id).copy(this->getDOFs(dofs_id));
 }
 
 /* -------------------------------------------------------------------------- */
 /* Mesh Events                                                                */
 /* -------------------------------------------------------------------------- */
 std::pair<UInt, UInt>
 DOFManager::updateNodalDOFs(const ID & dof_id, const Array<UInt> & nodes_list) {
   auto & dof_data = this->getDOFData(dof_id);
   UInt nb_new_local_dofs = 0;
   UInt nb_new_pure_local = 0;
 
   nb_new_local_dofs = nodes_list.size();
   for (const auto & node : nodes_list) {
     nb_new_pure_local += this->mesh->isLocalOrMasterNode(node) ? 1 : 0;
   }
 
   const auto & dof_array = *dof_data.dof;
   nb_new_pure_local *= dof_array.getNbComponent();
   nb_new_local_dofs *= dof_array.getNbComponent();
 
   this->pure_local_system_size += nb_new_pure_local;
   this->local_system_size += nb_new_local_dofs;
 
   UInt nb_new_global = nb_new_pure_local;
   communicator.allReduce(nb_new_global, SynchronizerOperation::_sum);
 
   this->system_size += nb_new_global;
 
   return std::make_pair(nb_new_local_dofs, nb_new_pure_local);
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::onNodesAdded(const Array<UInt> & nodes_list,
                               const NewNodesEvent &) {
   for (auto & pair : this->dofs) {
     const auto & dof_id = pair.first;
     auto & dof_data = this->getDOFData(dof_id);
     if (dof_data.support_type != _dst_nodal)
       continue;
 
     const auto & group = dof_data.group_support;
 
     if (group == "__mesh__") {
       this->updateNodalDOFs(dof_id, nodes_list);
     } else {
       const auto & node_group =
           this->mesh->getElementGroup(group).getNodeGroup();
       Array<UInt> new_nodes_list;
       for (const auto & node : nodes_list) {
         if (node_group.find(node) != UInt(-1))
           new_nodes_list.push_back(node);
       }
 
       this->updateNodalDOFs(dof_id, new_nodes_list);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::onNodesRemoved(const Array<UInt> &, const Array<UInt> &,
                                 const RemovedNodesEvent &) {}
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::onElementsAdded(const Array<Element> &,
                                  const NewElementsEvent &) {}
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::onElementsRemoved(const Array<Element> &,
                                    const ElementTypeMapArray<UInt> &,
                                    const RemovedElementsEvent &) {}
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::onElementsChanged(const Array<Element> &,
                                    const Array<Element> &,
                                    const ElementTypeMapArray<UInt> &,
                                    const ChangedElementsEvent &) {}
 
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/model/dof_manager.hh b/src/model/dof_manager.hh
index 47b4516ef..a6e5d903f 100644
--- a/src/model/dof_manager.hh
+++ b/src/model/dof_manager.hh
@@ -1,468 +1,472 @@
 /**
  * @file   dof_manager.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Jul 22 11:43:43 2015
  *
  * @brief  Class handling the different types of dofs
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_memory.hh"
 #include "aka_factory.hh"
 #include "mesh.hh"
 /* -------------------------------------------------------------------------- */
 #include <map>
 #include <set>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_DOF_MANAGER_HH__
 #define __AKANTU_DOF_MANAGER_HH__
 
 namespace akantu {
 class TermsToAssemble;
 class NonLinearSolver;
 class TimeStepSolver;
 class SparseMatrix;
 } // namespace akantu
 
 namespace akantu {
 
 class DOFManager : protected Memory, protected MeshEventHandler {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   DOFManager(const ID & id = "dof_manager", const MemoryID & memory_id = 0);
   DOFManager(Mesh & mesh, const ID & id = "dof_manager",
              const MemoryID & memory_id = 0);
   ~DOFManager() override;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 private:
   /// common function to help registering dofs
   void registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array);
 
 public:
   /// register an array of degree of freedom
   virtual void registerDOFs(const ID & dof_id, Array<Real> & dofs_array,
                             const DOFSupportType & support_type);
 
   /// the dof as an implied type of _dst_nodal and is defined only on a subset
   /// of nodes
   virtual void registerDOFs(const ID & dof_id, Array<Real> & dofs_array,
                             const ID & group_support);
 
   /// register an array of previous values of the degree of freedom
   virtual void registerDOFsPrevious(const ID & dof_id,
                                     Array<Real> & dofs_array);
 
   /// register an array of increment of degree of freedom
   virtual void registerDOFsIncrement(const ID & dof_id,
                                      Array<Real> & dofs_array);
 
   /// register an array of derivatives for a particular dof array
   virtual void registerDOFsDerivative(const ID & dof_id, UInt order,
                                       Array<Real> & dofs_derivative);
 
   /// register array representing the blocked degree of freedoms
   virtual void registerBlockedDOFs(const ID & dof_id,
                                    Array<bool> & blocked_dofs);
 
   /// Assemble an array to the global residual array
   virtual void assembleToResidual(const ID & dof_id,
                                   const Array<Real> & array_to_assemble,
                                   Real scale_factor = 1.) = 0;
 
   /// Assemble an array to the global lumped matrix array
   virtual void assembleToLumpedMatrix(const ID & dof_id,
                                       const Array<Real> & array_to_assemble,
                                       const ID & lumped_mtx,
                                       Real scale_factor = 1.) = 0;
 
   /**
    * Assemble elementary values to a local array of the size nb_nodes *
    * nb_dof_per_node. The dof number is implicitly considered as
    * conn(el, n) * nb_nodes_per_element + d.
    * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node
    **/
   virtual void assembleElementalArrayLocalArray(
       const Array<Real> & elementary_vect, Array<Real> & array_assembeled,
       const ElementType & type, const GhostType & ghost_type,
       Real scale_factor = 1.,
       const Array<UInt> & filter_elements = empty_filter);
 
   /**
    * Assemble elementary values to the global residual array. The dof number is
    * implicitly considered as conn(el, n) * nb_nodes_per_element + d.
    * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node
    **/
   virtual void assembleElementalArrayToResidual(
       const ID & dof_id, const Array<Real> & elementary_vect,
       const ElementType & type, const GhostType & ghost_type,
       Real scale_factor = 1.,
       const Array<UInt> & filter_elements = empty_filter);
 
   /**
    * Assemble elementary values to a global array corresponding to a lumped
    * matrix
    */
   virtual void assembleElementalArrayToLumpedMatrix(
       const ID & dof_id, const Array<Real> & elementary_vect,
       const ID & lumped_mtx, const ElementType & type,
       const GhostType & ghost_type, Real scale_factor = 1.,
       const Array<UInt> & filter_elements = empty_filter);
 
   /**
    * Assemble elementary values to the global residual array. The dof number is
    * implicitly considered as conn(el, n) * nb_nodes_per_element + d.  With 0 <
    * n < nb_nodes_per_element and 0 < d < nb_dof_per_node
    **/
   virtual void assembleElementalMatricesToMatrix(
       const ID & matrix_id, const ID & dof_id,
       const Array<Real> & elementary_mat, const ElementType & type,
       const GhostType & ghost_type = _not_ghost,
       const MatrixType & elemental_matrix_type = _symmetric,
       const Array<UInt> & filter_elements = empty_filter) = 0;
 
   /// multiply a vector by a matrix and assemble the result to the residual
   virtual void assembleMatMulVectToResidual(const ID & dof_id, const ID & A_id,
                                             const Array<Real> & x,
                                             Real scale_factor = 1) = 0;
 
+  /// multiply the dofs by a matrix and assemble the result to the residual
+  virtual void assembleMatMulDOFsToResidual(const ID & A_id,
+                                            Real scale_factor = 1);
+
   /// multiply a vector by a lumped matrix and assemble the result to the
   /// residual
   virtual void assembleLumpedMatMulVectToResidual(const ID & dof_id,
                                                   const ID & A_id,
                                                   const Array<Real> & x,
                                                   Real scale_factor = 1) = 0;
 
   /// assemble coupling terms between to dofs
   virtual void assemblePreassembledMatrix(const ID & dof_id_m,
                                           const ID & dof_id_n,
                                           const ID & matrix_id,
                                           const TermsToAssemble & terms) = 0;
 
   /// sets the residual to 0
   virtual void clearResidual() = 0;
   /// sets the matrix to 0
   virtual void clearMatrix(const ID & mtx) = 0;
   /// sets the lumped matrix to 0
   virtual void clearLumpedMatrix(const ID & mtx) = 0;
 
   /// splits the solution storage from a global view to the per dof storages
   void splitSolutionPerDOFs();
 
   /// extract a lumped matrix part corresponding to a given dof
   virtual void getLumpedMatrixPerDOFs(const ID & dof_id, const ID & lumped_mtx,
                                       Array<Real> & lumped) = 0;
 
 protected:
   /// minimum functionality to implement per derived version of the DOFManager
   /// to allow the splitSolutionPerDOFs function to work
   virtual void getSolutionPerDOFs(const ID & dof_id,
                                   Array<Real> & solution_array) = 0;
 
 protected:
   /* ------------------------------------------------------------------------ */
   /// register a matrix
   SparseMatrix & registerSparseMatrix(const ID & matrix_id,
                                       std::unique_ptr<SparseMatrix> & matrix);
 
   /// register a non linear solver instantiated by a derived class
   NonLinearSolver &
   registerNonLinearSolver(const ID & non_linear_solver_id,
                           std::unique_ptr<NonLinearSolver> & non_linear_solver);
 
   /// register a time step solver instantiated by a derived class
   TimeStepSolver &
   registerTimeStepSolver(const ID & time_step_solver_id,
                          std::unique_ptr<TimeStepSolver> & time_step_solver);
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// Get the equation numbers corresponding to a dof_id. This might be used to
   /// access the matrix.
   inline const Array<UInt> & getEquationsNumbers(const ID & dof_id) const;
 
   /// Global number of dofs
   AKANTU_GET_MACRO(SystemSize, this->system_size, UInt);
 
   /// Local number of dofs
   AKANTU_GET_MACRO(LocalSystemSize, this->local_system_size, UInt);
 
   /// Retrieve all the registered DOFs
   std::vector<ID> getDOFIDs() const;
 
   /* ------------------------------------------------------------------------ */
   /* DOFs and derivatives accessors                                          */
   /* ------------------------------------------------------------------------ */
   /// Get a reference to the registered dof array for a given id
   inline Array<Real> & getDOFs(const ID & dofs_id);
 
   /// Get the support type of a given dof
   inline DOFSupportType getSupportType(const ID & dofs_id) const;
 
   /// are the dofs registered
   inline bool hasDOFs(const ID & dofs_id) const;
 
   /// Get a reference to the registered dof derivatives array for a given id
   inline Array<Real> & getDOFsDerivatives(const ID & dofs_id, UInt order);
 
   /// Does the dof has derivatives
   inline bool hasDOFsDerivatives(const ID & dofs_id, UInt order) const;
 
   /// Get a reference to the blocked dofs array registered for the given id
   inline const Array<bool> & getBlockedDOFs(const ID & dofs_id) const;
 
   /// Does the dof has a blocked array
   inline bool hasBlockedDOFs(const ID & dofs_id) const;
 
   /// Get a reference to the registered dof increment array for a given id
   inline Array<Real> & getDOFsIncrement(const ID & dofs_id);
 
   /// Does the dof has a increment array
   inline bool hasDOFsIncrement(const ID & dofs_id) const;
 
   /// Does the dof has a previous array
   inline Array<Real> & getPreviousDOFs(const ID & dofs_id);
 
   /// Get a reference to the registered dof array for previous step values a
   /// given id
   inline bool hasPreviousDOFs(const ID & dofs_id) const;
 
   /// saves the values from dofs to previous dofs
   virtual void savePreviousDOFs(const ID & dofs_id);
 
   /// Get a reference to the solution array registered for the given id
   inline const Array<Real> & getSolution(const ID & dofs_id) const;
 
   /* ------------------------------------------------------------------------ */
   /* Matrices accessors                                                       */
   /* ------------------------------------------------------------------------ */
   /// Get an instance of a new SparseMatrix
   virtual SparseMatrix & getNewMatrix(const ID & matrix_id,
                                       const MatrixType & matrix_type) = 0;
 
   /// Get an instance of a new SparseMatrix as a copy of the SparseMatrix
   /// matrix_to_copy_id
   virtual SparseMatrix & getNewMatrix(const ID & matrix_id,
                                       const ID & matrix_to_copy_id) = 0;
 
   /// Get the reference of an existing matrix
   SparseMatrix & getMatrix(const ID & matrix_id);
 
   /// check if the given matrix exists
   bool hasMatrix(const ID & matrix_id) const;
 
   /// Get an instance of a new lumped matrix
   virtual Array<Real> & getNewLumpedMatrix(const ID & matrix_id);
   /// Get the lumped version of a given matrix
   const Array<Real> & getLumpedMatrix(const ID & matrix_id) const;
   /// Get the lumped version of a given matrix
   Array<Real> & getLumpedMatrix(const ID & matrix_id);
 
   /// check if the given matrix exists
   bool hasLumpedMatrix(const ID & matrix_id) const;
 
   /* ------------------------------------------------------------------------ */
   /* Non linear system solver                                                 */
   /* ------------------------------------------------------------------------ */
   /// Get instance of a non linear solver
   virtual NonLinearSolver & getNewNonLinearSolver(
       const ID & nls_solver_id,
       const NonLinearSolverType & _non_linear_solver_type) = 0;
 
   /// get instance of a non linear solver
   virtual NonLinearSolver & getNonLinearSolver(const ID & nls_solver_id);
 
   /// check if the given solver exists
   bool hasNonLinearSolver(const ID & solver_id) const;
 
   /* ------------------------------------------------------------------------ */
   /* Time-Step Solver                                                         */
   /* ------------------------------------------------------------------------ */
   /// Get instance of a time step solver
   virtual TimeStepSolver &
   getNewTimeStepSolver(const ID & time_step_solver_id,
                        const TimeStepSolverType & type,
                        NonLinearSolver & non_linear_solver) = 0;
 
   /// get instance of a time step solver
   virtual TimeStepSolver & getTimeStepSolver(const ID & time_step_solver_id);
 
   /// check if the given solver exists
   bool hasTimeStepSolver(const ID & solver_id) const;
 
   /* ------------------------------------------------------------------------ */
   const Mesh & getMesh() {
     if (mesh) {
       return *mesh;
     } else {
       AKANTU_EXCEPTION("No mesh registered in this dof manager");
     }
   }
 
   /* ------------------------------------------------------------------------ */
   AKANTU_GET_MACRO(Communicator, communicator, const auto &);
   AKANTU_GET_MACRO_NOT_CONST(Communicator, communicator, auto &);
 
   /* ------------------------------------------------------------------------ */
   /* MeshEventHandler interface                                               */
   /* ------------------------------------------------------------------------ */
 protected:
   /// helper function for the DOFManager::onNodesAdded method
   virtual std::pair<UInt, UInt> updateNodalDOFs(const ID & dof_id,
                                                 const Array<UInt> & nodes_list);
 public:
   /// function to implement to react on  akantu::NewNodesEvent
   void onNodesAdded(const Array<UInt> & nodes_list,
                     const NewNodesEvent & event) override;
   /// function to implement to react on  akantu::RemovedNodesEvent
   void onNodesRemoved(const Array<UInt> & nodes_list,
                       const Array<UInt> & new_numbering,
                       const RemovedNodesEvent & event) override;
   /// function to implement to react on  akantu::NewElementsEvent
   void onElementsAdded(const Array<Element> & elements_list,
                        const NewElementsEvent & event) override;
   /// function to implement to react on  akantu::RemovedElementsEvent
   void onElementsRemoved(const Array<Element> & elements_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const RemovedElementsEvent & event) override;
   /// function to implement to react on  akantu::ChangedElementsEvent
   void onElementsChanged(const Array<Element> & old_elements_list,
                          const Array<Element> & new_elements_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const ChangedElementsEvent & event) override;
 
 protected:
   struct DOFData;
   inline DOFData & getDOFData(const ID & dof_id);
   inline const DOFData & getDOFData(const ID & dof_id) const;
   template <class _DOFData>
   inline _DOFData & getDOFDataTyped(const ID & dof_id);
   template <class _DOFData>
   inline const _DOFData & getDOFDataTyped(const ID & dof_id) const;
 
   virtual DOFData & getNewDOFData(const ID & dof_id);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// dof representations in the dof manager
   struct DOFData {
     DOFData() = delete;
     explicit DOFData(const ID & dof_id);
     virtual ~DOFData();
 
     /// DOF support type (nodal, general) this is needed to determine how the
     /// dof are shared among processors
     DOFSupportType support_type;
 
     ID group_support;
 
     /// Degree of freedom array
     Array<Real> * dof;
 
     /// Blocked degree of freedoms array
     Array<bool> * blocked_dofs;
 
     /// Degree of freedoms increment
     Array<Real> * increment;
 
     /// Degree of freedoms at previous step
     Array<Real> * previous;
 
     /// Solution associated to the dof
     Array<Real> solution;
 
     /// local numbering equation numbers
     Array<UInt> local_equation_number;
 
     /* ---------------------------------------------------------------------- */
     /* data for dynamic simulations                                           */
     /* ---------------------------------------------------------------------- */
     /// Degree of freedom derivatives arrays
     std::vector<Array<Real> *> dof_derivatives;
   };
 
   /// type to store dofs information
   using DOFStorage = std::map<ID, std::unique_ptr<DOFData>>;
 
   /// type to store all the matrices
   using SparseMatricesMap = std::map<ID, std::unique_ptr<SparseMatrix>>;
 
   /// type to store all the lumped matrices
   using LumpedMatricesMap = std::map<ID, std::unique_ptr<Array<Real>>>;
 
   /// type to store all the non linear solver
   using NonLinearSolversMap = std::map<ID, std::unique_ptr<NonLinearSolver>>;
 
   /// type to store all the time step solver
   using TimeStepSolversMap = std::map<ID, std::unique_ptr<TimeStepSolver>>;
 
   /// store a reference to the dof arrays
   DOFStorage dofs;
 
   /// list of sparse matrices that where created
   SparseMatricesMap matrices;
 
   /// list of lumped matrices
   LumpedMatricesMap lumped_matrices;
 
   /// non linear solvers storage
   NonLinearSolversMap non_linear_solvers;
 
   /// time step solvers storage
   TimeStepSolversMap time_step_solvers;
 
   /// reference to the underlying mesh
   Mesh * mesh{nullptr};
 
   /// Total number of degrees of freedom (size with the ghosts)
   UInt local_system_size{0};
 
   /// Number of purely local dofs (size without the ghosts)
   UInt pure_local_system_size{0};
 
   /// Total number of degrees of freedom
   UInt system_size{0};
 
   /// Communicator used for this manager, should be the same as in the mesh if a
   /// mesh is registered
   Communicator & communicator;
 };
 
 using DefaultDOFManagerFactory = Factory<DOFManager, ID, const ID &, const MemoryID &>;
 using DOFManagerFactory = Factory<DOFManager, ID, Mesh &, const ID &, const MemoryID &>;
 
 } // namespace akantu
 
 #include "dof_manager_inline_impl.cc"
 
 #endif /* __AKANTU_DOF_MANAGER_HH__ */
diff --git a/src/model/model_solver.cc b/src/model/model_solver.cc
index f4ac5415c..78e97c629 100644
--- a/src/model/model_solver.cc
+++ b/src/model/model_solver.cc
@@ -1,366 +1,364 @@
 /**
  * @file   model_solver.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Aug 12 13:31:56 2015
  *
  * @brief  Implementation of ModelSolver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "model_solver.hh"
 #include "dof_manager.hh"
 #include "dof_manager_default.hh"
 #include "mesh.hh"
 #include "non_linear_solver.hh"
 #include "time_step_solver.hh"
 
 #if defined(AKANTU_USE_PETSC)
 #include "dof_manager_petsc.hh"
 #endif
 
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <typename T> static T getOptionToType(const std::string & opt_str) {
   std::stringstream sstr(opt_str);
   T opt;
   sstr >> opt;
 
   return opt;
 }
 
 /* -------------------------------------------------------------------------- */
 ModelSolver::ModelSolver(Mesh & mesh, const ModelType & type, const ID & id,
                          UInt memory_id)
     : Parsable(ParserType::_model, id), SolverCallback(), model_type(type),
       parent_id(id), parent_memory_id(memory_id), mesh(mesh),
       dof_manager(nullptr), default_solver_id("") {}
 
 /* -------------------------------------------------------------------------- */
 ModelSolver::~ModelSolver() = default;
 
 /* -------------------------------------------------------------------------- */
 std::tuple<ParserSection, bool> ModelSolver::getParserSection() {
   auto sub_sections = getStaticParser().getSubSections(ParserType::_model);
 
   auto it = std::find_if(
       sub_sections.begin(), sub_sections.end(), [&](auto && section) {
         ModelType type = getOptionToType<ModelType>(section.getName());
         // default id should be the model type if not defined
         std::string name = section.getParameter("name", this->parent_id);
         return type == model_type and name == this->parent_id;
       });
 
   if (it == sub_sections.end())
     return std::make_tuple(ParserSection(), true);
 
   return std::make_tuple(*it, false);
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::initDOFManager() {
   // default without external solver activated at compilation same as mumps that
   // is the historical solver but with only the lumped solver
   ID solver_type = "default";
 
 #if defined(AKANTU_USE_MUMPS)
   solver_type = "default";
 #elif defined(AKANTU_USE_PETSC)
   solver_type = "petsc";
 #endif
 
   ParserSection section;
   bool is_empty;
   std::tie(section, is_empty) = this->getParserSection();
 
   if (not is_empty) {
     solver_type = section.getOption(solver_type);
     this->initDOFManager(section, solver_type);
   } else {
     this->initDOFManager(solver_type);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::initDOFManager(const ID & solver_type) {
-
   try {
     this->dof_manager = DOFManagerFactory::getInstance().allocate(
         solver_type, mesh, this->parent_id + ":dof_manager" + solver_type,
         this->parent_memory_id);
   } catch (...) {
     AKANTU_EXCEPTION(
         "To use the solver "
         << solver_type
         << " you will have to code it. This is an unknown solver type.");
   }
 
   this->setDOFManager(*this->dof_manager);
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::initDOFManager(const ParserSection & section,
                                  const ID & solver_type) {
   this->initDOFManager(solver_type);
   auto sub_sections = section.getSubSections(ParserType::_time_step_solver);
 
   // parsing the time step solvers
   for (auto && section : sub_sections) {
-
     ID type = section.getName();
     ID solver_id = section.getParameter("name", type);
 
     auto tss_type = getOptionToType<TimeStepSolverType>(type);
     auto tss_options = this->getDefaultSolverOptions(tss_type);
 
     auto sub_solvers_sect =
         section.getSubSections(ParserType::_non_linear_solver);
     auto nb_non_linear_solver_section =
         section.getNbSubSections(ParserType::_non_linear_solver);
 
     auto nls_type = tss_options.non_linear_solver_type;
 
     if (nb_non_linear_solver_section == 1) {
       auto && nls_section = *(sub_solvers_sect.first);
       nls_type = getOptionToType<NonLinearSolverType>(nls_section.getName());
     } else if (nb_non_linear_solver_section > 0) {
       AKANTU_EXCEPTION("More than one non linear solver are provided for the "
                        "time step solver "
                        << solver_id);
     }
 
     this->getNewSolver(solver_id, tss_type, nls_type);
     if (nb_non_linear_solver_section == 1) {
       const auto & nls_section = *(sub_solvers_sect.first);
       this->dof_manager->getNonLinearSolver(solver_id).parseSection(
           nls_section);
     }
 
     auto sub_integrator_sections =
         section.getSubSections(ParserType::_integration_scheme);
 
     for (auto && is_section : sub_integrator_sections) {
       const auto & dof_type_str = is_section.getName();
       ID dof_id;
       try {
         ID tmp = is_section.getParameter("name");
         dof_id = tmp;
       } catch (...) {
         AKANTU_EXCEPTION("No degree of freedom name specified for the "
                          "integration scheme of type "
                          << dof_type_str);
       }
 
       auto it_type = getOptionToType<IntegrationSchemeType>(dof_type_str);
 
       IntegrationScheme::SolutionType s_type = is_section.getParameter(
           "solution_type", tss_options.solution_type[dof_id]);
       this->setIntegrationScheme(solver_id, dof_id, it_type, s_type);
     }
 
     for (auto & is_type : tss_options.integration_scheme_type) {
       if (!this->hasIntegrationScheme(solver_id, is_type.first)) {
         this->setIntegrationScheme(solver_id, is_type.first, is_type.second,
                                    tss_options.solution_type[is_type.first]);
       }
     }
   }
 
   if (section.hasParameter("default_solver")) {
     ID default_solver = section.getParameter("default_solver");
     if (this->hasSolver(default_solver)) {
       this->setDefaultSolver(default_solver);
     } else
       AKANTU_EXCEPTION(
           "The solver \""
           << default_solver
           << "\" was not created, it cannot be set as default solver");
   }
 }
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolver & ModelSolver::getSolver(const ID & solver_id) {
   ID tmp_solver_id = solver_id;
   if (tmp_solver_id == "")
     tmp_solver_id = this->default_solver_id;
 
   TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(tmp_solver_id);
   return tss;
 }
 
 /* -------------------------------------------------------------------------- */
 const TimeStepSolver & ModelSolver::getSolver(const ID & solver_id) const {
   ID tmp_solver_id = solver_id;
   if (solver_id == "")
     tmp_solver_id = this->default_solver_id;
 
   const TimeStepSolver & tss =
       this->dof_manager->getTimeStepSolver(tmp_solver_id);
   return tss;
 }
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolver & ModelSolver::getTimeStepSolver(const ID & solver_id) {
   return this->getSolver(solver_id);
 }
 
 /* -------------------------------------------------------------------------- */
 const TimeStepSolver &
 ModelSolver::getTimeStepSolver(const ID & solver_id) const {
   return this->getSolver(solver_id);
 }
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolver & ModelSolver::getNonLinearSolver(const ID & solver_id) {
   return this->getSolver(solver_id).getNonLinearSolver();
 }
 /* -------------------------------------------------------------------------- */
 const NonLinearSolver &
 ModelSolver::getNonLinearSolver(const ID & solver_id) const {
   return this->getSolver(solver_id).getNonLinearSolver();
 }
 
 /* -------------------------------------------------------------------------- */
 bool ModelSolver::hasSolver(const ID & solver_id) const {
   ID tmp_solver_id = solver_id;
   if (solver_id == "")
     tmp_solver_id = this->default_solver_id;
 
   if (not this->dof_manager) {
     AKANTU_EXCEPTION("No DOF manager was initialized");
   }
   return this->dof_manager->hasTimeStepSolver(tmp_solver_id);
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::setDefaultSolver(const ID & solver_id) {
   AKANTU_DEBUG_ASSERT(
       this->hasSolver(solver_id),
       "Cannot set the default solver to a solver that does not exists");
   this->default_solver_id = solver_id;
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::solveStep(const ID & solver_id) {
   AKANTU_DEBUG_IN();
 
   TimeStepSolver & tss = this->getSolver(solver_id);
   // make one non linear solve
   tss.solveStep(*this);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::getNewSolver(const ID & solver_id,
                                TimeStepSolverType time_step_solver_type,
                                NonLinearSolverType non_linear_solver_type) {
   if (this->default_solver_id == "") {
     this->default_solver_id = solver_id;
   }
 
   if (non_linear_solver_type == _nls_auto) {
     switch (time_step_solver_type) {
     case _tsst_dynamic:
     case _tsst_static:
       non_linear_solver_type = _nls_newton_raphson;
       break;
     case _tsst_dynamic_lumped:
       non_linear_solver_type = _nls_lumped;
       break;
     case _tsst_not_defined:
       AKANTU_EXCEPTION(time_step_solver_type
                        << " is not a valid time step solver type");
       break;
     }
   }
 
   this->initSolver(time_step_solver_type, non_linear_solver_type);
 
   NonLinearSolver & nls = this->dof_manager->getNewNonLinearSolver(
       solver_id, non_linear_solver_type);
 
   this->dof_manager->getNewTimeStepSolver(solver_id, time_step_solver_type,
                                           nls);
 }
 
 /* -------------------------------------------------------------------------- */
 Real ModelSolver::getTimeStep(const ID & solver_id) const {
   const TimeStepSolver & tss = this->getSolver(solver_id);
 
   return tss.getTimeStep();
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::setTimeStep(Real time_step, const ID & solver_id) {
   TimeStepSolver & tss = this->getSolver(solver_id);
 
   return tss.setTimeStep(time_step);
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::setIntegrationScheme(
     const ID & solver_id, const ID & dof_id,
     const IntegrationSchemeType & integration_scheme_type,
     IntegrationScheme::SolutionType solution_type) {
   TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(solver_id);
 
   tss.setIntegrationScheme(dof_id, integration_scheme_type, solution_type);
 }
 
 /* -------------------------------------------------------------------------- */
 bool ModelSolver::hasDefaultSolver() const {
   return (this->default_solver_id != "");
 }
 
 /* -------------------------------------------------------------------------- */
 bool ModelSolver::hasIntegrationScheme(const ID & solver_id,
                                        const ID & dof_id) const {
   TimeStepSolver & tss = this->dof_manager->getTimeStepSolver(solver_id);
   return tss.hasIntegrationScheme(dof_id);
 }
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::predictor() {}
 
 /* -------------------------------------------------------------------------- */
 void ModelSolver::corrector() {}
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolverType ModelSolver::getDefaultSolverType() const {
   return _tsst_dynamic_lumped;
 }
 
 /* -------------------------------------------------------------------------- */
 ModelSolverOptions
 ModelSolver::getDefaultSolverOptions(__attribute__((unused))
                                      const TimeStepSolverType & type) const {
   ModelSolverOptions options;
   options.non_linear_solver_type = _nls_auto;
   return options;
 }
 
 } // namespace akantu
diff --git a/src/model/non_linear_solver.cc b/src/model/non_linear_solver.cc
index 41e34238f..a6333d41e 100644
--- a/src/model/non_linear_solver.cc
+++ b/src/model/non_linear_solver.cc
@@ -1,66 +1,78 @@
 /**
  * @file   non_linear_solver.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Tue Oct 13 15:34:43 2015
  *
  * @brief  Implementation of the base class NonLinearSolver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "non_linear_solver.hh"
+#include "dof_manager.hh"
 #include "solver_callback.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolver::NonLinearSolver(
     DOFManager & dof_manager,
     const NonLinearSolverType & non_linear_solver_type, const ID & id,
     UInt memory_id)
     : Memory(id, memory_id), Parsable(ParserType::_non_linear_solver, id),
       _dof_manager(dof_manager),
       non_linear_solver_type(non_linear_solver_type) {
 
   this->registerParam("type", this->non_linear_solver_type, _pat_parsable,
                       "Non linear solver type");
 }
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolver::~NonLinearSolver() = default;
 
 /* -------------------------------------------------------------------------- */
 void NonLinearSolver::checkIfTypeIsSupported() {
   if (this->supported_type.find(this->non_linear_solver_type) ==
       this->supported_type.end()) {
     AKANTU_EXCEPTION("The resolution method "
                      << this->non_linear_solver_type
                      << " is not implemented in the non linear solver "
                      << this->id << "!");
   }
 }
 
 /* -------------------------------------------------------------------------- */
+void NonLinearSolver::assembleResidual(SolverCallback & solver_callback) {
+  if (solver_callback.canSplitResidual() and
+      non_linear_solver_type == _nls_linear) {
+    this->_dof_manager.clearResidual();
+    solver_callback.assembleResidual("external");
+    this->_dof_manager.assembleMatMulDOFsToResidual("K", -1.);
+    solver_callback.assembleResidual("inertial");
+  } else {
+    solver_callback.assembleResidual();
+  }
+}
 
 } // akantu
diff --git a/src/model/non_linear_solver.hh b/src/model/non_linear_solver.hh
index 56c8691ec..2cea85168 100644
--- a/src/model/non_linear_solver.hh
+++ b/src/model/non_linear_solver.hh
@@ -1,96 +1,98 @@
 /**
  * @file   non_linear_solver.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Mon Aug 24 23:48:41 2015
  *
  * @brief  Non linear solver interface
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "aka_memory.hh"
 #include "parsable.hh"
 /* -------------------------------------------------------------------------- */
 #include <set>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_NON_LINEAR_SOLVER_HH__
 #define __AKANTU_NON_LINEAR_SOLVER_HH__
 
 namespace akantu {
 class DOFManager;
 class SolverCallback;
 }
 
 namespace akantu {
 
 class NonLinearSolver : private Memory, public Parsable {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   NonLinearSolver(DOFManager & dof_manager,
                   const NonLinearSolverType & non_linear_solver_type,
                   const ID & id = "non_linear_solver", UInt memory_id = 0);
   ~NonLinearSolver() override;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// solve the system described by the jacobian matrix, and rhs contained in
   /// the dof manager
   virtual void solve(SolverCallback & callback) = 0;
 
 protected:
   void checkIfTypeIsSupported();
 
+  void assembleResidual(SolverCallback & callback);
+
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   DOFManager & _dof_manager;
 
   /// type of non linear solver
   NonLinearSolverType non_linear_solver_type;
 
   /// list of supported non linear solver types
   std::set<NonLinearSolverType> supported_type;
 };
 
 namespace debug {
   class NLSNotConvergedException : public Exception {
   public:
     NLSNotConvergedException(Real threshold, UInt niter, Real error)
         : Exception("The non linear solver did not converge."),
           threshold(threshold), niter(niter), error(error) {}
     Real threshold;
     UInt niter;
     Real error;
   };
 }
 
 } // akantu
 
 #endif /* __AKANTU_NON_LINEAR_SOLVER_HH__ */
diff --git a/src/model/non_linear_solver_linear.cc b/src/model/non_linear_solver_linear.cc
index 8a8411b6e..4a5704d52 100644
--- a/src/model/non_linear_solver_linear.cc
+++ b/src/model/non_linear_solver_linear.cc
@@ -1,70 +1,73 @@
 /**
  * @file   non_linear_solver_linear.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Tue Aug 25 00:57:00 2015
  *
  * @brief  Implementation of the default NonLinearSolver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "non_linear_solver_linear.hh"
 #include "dof_manager_default.hh"
 #include "solver_callback.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolverLinear::NonLinearSolverLinear(
     DOFManagerDefault & dof_manager,
     const NonLinearSolverType & non_linear_solver_type, const ID & id,
     UInt memory_id)
     : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id),
       dof_manager(dof_manager),
       solver(dof_manager, "J", id + ":sparse_solver", memory_id) {
 
   this->supported_type.insert(_nls_linear);
   this->checkIfTypeIsSupported();
 }
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolverLinear::~NonLinearSolverLinear() = default;
 
 /* ------------------------------------------------------------------------ */
 void NonLinearSolverLinear::solve(SolverCallback & solver_callback) {
   this->dof_manager.updateGlobalBlockedDofs();
 
   solver_callback.predictor();
 
-  solver_callback.assembleResidual();
   solver_callback.assembleMatrix("J");
 
+  // Residual computed after J to allow the model to use K to compute the
+  // residual
+  this->assembleResidual(solver_callback);
+
   this->solver.solve();
 
   solver_callback.corrector();
 }
 
 /* -------------------------------------------------------------------------- */
 
 } // akantu
diff --git a/src/model/non_linear_solver_newton_raphson.cc b/src/model/non_linear_solver_newton_raphson.cc
index 11d5c44e1..540ac8dd0 100644
--- a/src/model/non_linear_solver_newton_raphson.cc
+++ b/src/model/non_linear_solver_newton_raphson.cc
@@ -1,186 +1,191 @@
 /**
  * @file   non_linear_solver_newton_raphson.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Tue Aug 25 00:57:00 2015
  *
  * @brief  Implementation of the default NonLinearSolver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "non_linear_solver_newton_raphson.hh"
 #include "communicator.hh"
 #include "dof_manager_default.hh"
 #include "solver_callback.hh"
 #include "sparse_solver_mumps.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolverNewtonRaphson::NonLinearSolverNewtonRaphson(
     DOFManagerDefault & dof_manager,
     const NonLinearSolverType & non_linear_solver_type, const ID & id,
     UInt memory_id)
     : NonLinearSolver(dof_manager, non_linear_solver_type, id, memory_id),
       dof_manager(dof_manager),
       solver(std::make_unique<SparseSolverMumps>(
           dof_manager, "J", id + ":sparse_solver", memory_id)) {
 
   this->supported_type.insert(_nls_newton_raphson_modified);
   this->supported_type.insert(_nls_newton_raphson);
   this->supported_type.insert(_nls_linear);
 
   this->checkIfTypeIsSupported();
 
   this->registerParam("threshold", convergence_criteria, 1e-10, _pat_parsmod,
                       "Threshold to consider results as converged");
   this->registerParam("convergence_type", convergence_criteria_type,
                       _scc_solution, _pat_parsmod,
                       "Type of convergence criteria");
   this->registerParam("max_iterations", max_iterations, 10, _pat_parsmod,
                       "Max number of iterations");
   this->registerParam("error", error, _pat_readable, "Last reached error");
   this->registerParam("nb_iterations", n_iter, _pat_readable,
                       "Last reached number of iterations");
   this->registerParam("converged", converged, _pat_readable,
                       "Did last solve converged");
   this->registerParam("force_linear_recompute", force_linear_recompute, true,
                       _pat_modifiable,
                       "Force reassembly of the jacobian matrix");
 }
 
 /* -------------------------------------------------------------------------- */
 NonLinearSolverNewtonRaphson::~NonLinearSolverNewtonRaphson() = default;
 
 /* ------------------------------------------------------------------------ */
 void NonLinearSolverNewtonRaphson::solve(SolverCallback & solver_callback) {
   this->dof_manager.updateGlobalBlockedDofs();
 
   solver_callback.predictor();
 
-  solver_callback.assembleResidual();
+  if (non_linear_solver_type == _nls_linear and
+      solver_callback.canSplitResidual())
+    solver_callback.assembleMatrix("K");
+
+  this->assembleResidual(solver_callback);
 
   if (this->non_linear_solver_type == _nls_newton_raphson_modified ||
       (this->non_linear_solver_type == _nls_linear &&
        this->force_linear_recompute)) {
     solver_callback.assembleMatrix("J");
     this->force_linear_recompute = false;
   }
 
   this->n_iter = 0;
   this->converged = false;
 
   if (this->convergence_criteria_type == _scc_residual) {
     this->converged = this->testConvergence(this->dof_manager.getResidual());
 
     if (this->converged)
       return;
   }
 
   do {
     if (this->non_linear_solver_type == _nls_newton_raphson)
       solver_callback.assembleMatrix("J");
 
     this->solver->solve();
 
     solver_callback.corrector();
 
     // EventManager::sendEvent(NonLinearSolver::AfterSparseSolve(method));
 
     if (this->convergence_criteria_type == _scc_residual) {
-      solver_callback.assembleResidual();
+      this->assembleResidual(solver_callback);
       this->converged = this->testConvergence(this->dof_manager.getResidual());
     } else {
       this->converged =
           this->testConvergence(this->dof_manager.getGlobalSolution());
     }
 
-    if (this->convergence_criteria_type == _scc_solution && !this->converged)
-      solver_callback.assembleResidual();
+    if (this->convergence_criteria_type == _scc_solution and
+        not this->converged)
+      this->assembleResidual(solver_callback);
     // this->dump();
 
     this->n_iter++;
     AKANTU_DEBUG_INFO(
         "[" << this->convergence_criteria_type << "] Convergence iteration "
             << std::setw(std::log10(this->max_iterations)) << this->n_iter
             << ": error " << this->error << (this->converged ? " < " : " > ")
             << this->convergence_criteria);
 
-  } while (!this->converged && this->n_iter < this->max_iterations);
+  } while (not this->converged and this->n_iter < this->max_iterations);
 
   // this makes sure that you have correct strains and stresses after the
   // solveStep function (e.g., for dumping)
   if (this->convergence_criteria_type == _scc_solution)
-    solver_callback.assembleResidual();
+    this->assembleResidual(solver_callback);
 
   if (this->converged) {
     // this->sendEvent(NonLinearSolver::ConvergedEvent(method));
   } else if (this->n_iter == this->max_iterations) {
     AKANTU_CUSTOM_EXCEPTION(debug::NLSNotConvergedException(
         this->convergence_criteria, this->n_iter, this->error));
 
     AKANTU_DEBUG_WARNING("[" << this->convergence_criteria_type
                              << "] Convergence not reached after "
                              << std::setw(std::log10(this->max_iterations))
                              << this->n_iter << " iteration"
                              << (this->n_iter == 1 ? "" : "s") << "!");
   }
 
   return;
 }
 
 /* -------------------------------------------------------------------------- */
 bool NonLinearSolverNewtonRaphson::testConvergence(const Array<Real> & array) {
   AKANTU_DEBUG_IN();
 
   const Array<bool> & blocked_dofs = this->dof_manager.getGlobalBlockedDOFs();
 
   UInt nb_degree_of_freedoms = array.size();
 
   auto arr_it = array.begin();
   auto bld_it = blocked_dofs.begin();
 
   Real norm = 0.;
   for (UInt n = 0; n < nb_degree_of_freedoms; ++n, ++arr_it, ++bld_it) {
     bool is_local_node = this->dof_manager.isLocalOrMasterDOF(n);
     if ((!*bld_it) && is_local_node) {
       norm += *arr_it * *arr_it;
     }
   }
 
   dof_manager.getCommunicator().allReduce(norm, SynchronizerOperation::_sum);
 
   norm = std::sqrt(norm);
 
   AKANTU_DEBUG_ASSERT(!Math::isnan(norm),
                       "Something went wrong in the solve phase");
 
   this->error = norm;
 
   return (error < this->convergence_criteria);
 }
 
 /* -------------------------------------------------------------------------- */
 
 } // akantu
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh
index 242d2f561..b4393907c 100644
--- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh
+++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh
@@ -1,818 +1,803 @@
 /**
  * @file   material_reinforcement_tmpl.hh
  *
  * @author Lucas Frerot <lucas.frerot@epfl.ch>
  *
  * @date creation: Thu Feb 1 2018
  *
  * @brief  Reinforcement material
  *
  * @section LICENSE
  *
  * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
  * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 #include "aka_common.hh"
 #include "aka_voigthelper.hh"
 #include "material_reinforcement.hh"
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <class Mat, UInt dim>
 MaterialReinforcement<Mat, dim>::MaterialReinforcement(
     EmbeddedInterfaceModel & model, const ID & id)
     : Mat(model, 1,
           model.getInterfaceMesh(),
           model.getFEEngine("EmbeddedInterfaceFEEngine"), id),
       emodel(model),
       gradu_embedded("gradu_embedded", *this, 1,
                      model.getFEEngine("EmbeddedInterfaceFEEngine"),
                      this->element_filter),
       directing_cosines("directing_cosines", *this, 1,
                         model.getFEEngine("EmbeddedInterfaceFEEngine"),
                         this->element_filter),
       pre_stress("pre_stress", *this, 1,
                  model.getFEEngine("EmbeddedInterfaceFEEngine"),
                  this->element_filter),
       area(1.0), shape_derivatives() {
   AKANTU_DEBUG_IN();
   this->initialize();
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::initialize() {
   AKANTU_DEBUG_IN();
 
   this->registerParam("area", area, _pat_parsable | _pat_modifiable,
                       "Reinforcement cross-sectional area");
   this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable,
                       "Uniform pre-stress");
 
   // this->unregisterInternal(this->stress);
 
   // Fool the AvgHomogenizingFunctor
   // stress.initialize(dim * dim);
 
   // Reallocate the element filter
   this->element_filter.initialize(this->emodel.getInterfaceMesh(),
                                   _spatial_dimension = 1);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 MaterialReinforcement<Mat, dim>::~MaterialReinforcement() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::initMaterial() {
   Mat::initMaterial();
 
   gradu_embedded.initialize(dim * dim);
   pre_stress.initialize(1);
 
   /// We initialise the stuff that is not going to change during the simulation
   this->initFilters();
   this->allocBackgroundShapeDerivatives();
   this->initBackgroundShapeDerivatives();
   this->initDirectingCosines();
 }
 
-/* -------------------------------------------------------------------------- */
-
-namespace detail {
-  class FilterInitializer : public MeshElementTypeMapArrayInializer {
-  public:
-    FilterInitializer(EmbeddedInterfaceModel & emodel,
-                      const GhostType & ghost_type)
-        : MeshElementTypeMapArrayInializer(emodel.getMesh(),
-                                           1, emodel.getSpatialDimension(),
-                                           ghost_type, _ek_regular) {}
-
-    UInt size(const ElementType & /*bgtype*/) const override { return 0; }
-  };
-}
-
 /* -------------------------------------------------------------------------- */
 /// Initialize the filter for background elements
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::initFilters() {
   for (auto gt : ghost_types) {
     for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) {
       std::string shaped_id = "filter";
       if (gt == _ghost)
         shaped_id += ":ghost";
 
       auto & background =
           background_filter(std::make_unique<ElementTypeMapArray<UInt>>(
                                 "bg_" + shaped_id, this->name),
                             type, gt);
       auto & foreground = foreground_filter(
           std::make_unique<ElementTypeMapArray<UInt>>(shaped_id, this->name),
           type, gt);
-      foreground->initialize(detail::FilterInitializer(emodel, gt), 0, true);
-      background->initialize(detail::FilterInitializer(emodel, gt), 0, true);
+      foreground->initialize(emodel.getMesh(), _nb_component = 1,
+                             _ghost_type = gt);
+      background->initialize(emodel.getMesh(), _nb_component = 1,
+                             _ghost_type = gt);
 
       // Computing filters
       for (auto && bg_type : background->elementTypes(dim, gt)) {
         filterInterfaceBackgroundElements(
             (*foreground)(bg_type), (*background)(bg_type), bg_type, type, gt);
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 /// Construct a filter for a (interface_type, background_type) pair
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::filterInterfaceBackgroundElements(
     Array<UInt> & foreground, Array<UInt> & background,
     const ElementType & type, const ElementType & interface_type,
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   foreground.resize(0);
   background.resize(0);
 
   Array<Element> & elements =
       emodel.getInterfaceAssociatedElements(interface_type, ghost_type);
   Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type);
 
   for (auto & elem_id : elem_filter) {
     Element & elem = elements(elem_id);
     if (elem.type == type) {
       background.push_back(elem.element);
       foreground.push_back(elem_id);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 namespace detail {
-  class BackgroundShapeDInitializer : public ElementTypeMapArrayInializer {
+  class BackgroundShapeDInitializer : public ElementTypeMapArrayInitializer {
   public:
-    BackgroundShapeDInitializer(UInt spatial_dimension,
-				FEEngine & engine,
-				const ElementType & foreground_type,
-                                ElementTypeMapArray<UInt> & filter,
+    BackgroundShapeDInitializer(UInt spatial_dimension, FEEngine & engine,
+                                const ElementType & foreground_type,
+                                const ElementTypeMapArray<UInt> & filter,
                                 const GhostType & ghost_type)
-        : ElementTypeMapArrayInializer(spatial_dimension, 0, ghost_type,
-                                       _ek_regular) {
+        : ElementTypeMapArrayInitializer(
+              [](const ElementType & bgtype, const GhostType &) {
+                return ShapeFunctions::getShapeDerivativesSize(bgtype);
+              },
+              spatial_dimension, ghost_type, _ek_regular) {
       auto nb_quad = engine.getNbIntegrationPoints(foreground_type);
       // Counting how many background elements are affected by elements of
       // interface_type
       for (auto type : filter.elementTypes(this->spatial_dimension)) {
         // Inserting size
         array_size_per_bg_type(filter(type).size() * nb_quad, type,
                                this->ghost_type);
       }
     }
 
     auto elementTypes() const -> decltype(auto) {
       return array_size_per_bg_type.elementTypes();
     }
 
     UInt size(const ElementType & bgtype) const {
       return array_size_per_bg_type(bgtype, this->ghost_type);
     }
 
-    UInt nbComponent(const ElementType & bgtype) const {
-      return ShapeFunctions::getShapeDerivativesSize(bgtype);
-    }
-
   protected:
     ElementTypeMap<UInt> array_size_per_bg_type;
   };
 }
 
 /**
  * Background shape derivatives need to be stored per background element
  * types but also per embedded element type, which is why they are stored
  * in an ElementTypeMap<ElementTypeMapArray<Real> *>. The outer ElementTypeMap
  * refers to the embedded types, and the inner refers to the background types.
  */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::allocBackgroundShapeDerivatives() {
   AKANTU_DEBUG_IN();
 
   for (auto gt : ghost_types) {
     for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) {
       std::string shaped_id = "embedded_shape_derivatives";
       if (gt == _ghost)
         shaped_id += ":ghost";
 
       auto & shaped_etma = shape_derivatives(
           std::make_unique<ElementTypeMapArray<Real>>(shaped_id, this->name),
           type, gt);
       shaped_etma->initialize(
           detail::BackgroundShapeDInitializer(
               emodel.getSpatialDimension(),
               emodel.getFEEngine("EmbeddedInterfaceFEEngine"), type,
               *background_filter(type, gt), gt),
           0, true);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::initBackgroundShapeDerivatives() {
   AKANTU_DEBUG_IN();
 
   for (auto interface_type :
        this->element_filter.elementTypes(this->spatial_dimension)) {
     for (auto type : background_filter(interface_type)->elementTypes(dim)) {
       computeBackgroundShapeDerivatives(interface_type, type, _not_ghost,
                                         this->element_filter(interface_type));
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::computeBackgroundShapeDerivatives(
     const ElementType & interface_type, const ElementType & bg_type,
     GhostType ghost_type, const Array<UInt> & filter) {
   auto & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine");
   auto & engine = emodel.getFEEngine();
   auto & interface_mesh = emodel.getInterfaceMesh();
 
   const auto nb_nodes_elem_bg = Mesh::getNbNodesPerElement(bg_type);
   // const auto nb_strss = VoigtHelper<dim>::size;
   const auto nb_quads_per_elem =
       interface_engine.getNbIntegrationPoints(interface_type);
 
   Array<Real> quad_pos(0, dim, "interface_quad_pos");
   interface_engine.interpolateOnIntegrationPoints(interface_mesh.getNodes(),
                                                   quad_pos, dim, interface_type,
                                                   ghost_type, filter);
   auto & background_shapesd =
       (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type);
   auto & background_elements =
       (*background_filter(interface_type, ghost_type))(bg_type, ghost_type);
   auto & foreground_elements =
       (*foreground_filter(interface_type, ghost_type))(bg_type, ghost_type);
 
   auto shapesd_begin =
     background_shapesd.begin(dim, nb_nodes_elem_bg, nb_quads_per_elem);
   auto quad_begin = quad_pos.begin(dim, nb_quads_per_elem);
 
   for (auto && tuple : zip(background_elements, foreground_elements)) {
     UInt bg = std::get<0>(tuple), fg = std::get<1>(tuple);
     for (UInt i = 0; i < nb_quads_per_elem; ++i) {
       Matrix<Real> shapesd = Tensor3<Real>(shapesd_begin[fg])(i);
       Vector<Real> quads = Matrix<Real>(quad_begin[fg])(i);
 
       engine.computeShapeDerivatives(quads, bg, bg_type, shapesd,
                                      ghost_type);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::initDirectingCosines() {
   AKANTU_DEBUG_IN();
 
   Mesh & mesh = emodel.getInterfaceMesh();
 
   Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost);
   Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost);
 
   const UInt voigt_size = VoigtHelper<dim>::size;
   directing_cosines.initialize(voigt_size);
 
   for (; type_it != type_end; ++type_it) {
     computeDirectingCosines(*type_it, _not_ghost);
     // computeDirectingCosines(*type_it, _ghost);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix(
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Mesh & interface_mesh = emodel.getInterfaceMesh();
 
   Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost);
   Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost);
 
   for (; type_it != type_end; ++type_it) {
     assembleStiffnessMatrix(*type_it, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::assembleInternalForces(
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Mesh & interface_mesh = emodel.getInterfaceMesh();
 
   Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost);
   Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost);
 
   for (; type_it != type_end; ++type_it) {
     this->assembleInternalForces(*type_it, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::computeAllStresses(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Mesh::type_iterator it = emodel.getInterfaceMesh().firstType();
   Mesh::type_iterator last_type = emodel.getInterfaceMesh().lastType();
 
   for (; it != last_type; ++it) {
     computeGradU(*it, ghost_type);
     this->computeStress(*it, ghost_type);
     addPrestress(*it, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::addPrestress(const ElementType & type,
                                                    GhostType ghost_type) {
   auto & stress = this->stress(type, ghost_type);
   auto & sigma_p = this->pre_stress(type, ghost_type);
 
   for (auto && tuple : zip(stress, sigma_p)) {
     std::get<0>(tuple) += std::get<1>(tuple);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::assembleInternalForces(
     const ElementType & type, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Mesh & mesh = emodel.getMesh();
 
   Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type);
   Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type);
 
   for (; type_it != type_end; ++type_it) {
     assembleInternalForcesInterface(type, *type_it, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 /**
  * Computes and assemble the residual. Residual in reinforcement is computed as:
  *
  * \f[
  * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s}
  * \f]
  */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::assembleInternalForcesInterface(
     const ElementType & interface_type, const ElementType & background_type,
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   UInt voigt_size = VoigtHelper<dim>::size;
 
   FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine");
 
   Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type);
 
   UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type);
   UInt nb_quadrature_points =
       interface_engine.getNbIntegrationPoints(interface_type, ghost_type);
   UInt nb_element = elem_filter.size();
 
   UInt back_dof = dim * nodes_per_background_e;
 
   Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))(
       background_type, ghost_type);
 
   Array<Real> integrant(nb_quadrature_points * nb_element, back_dof,
                         "integrant");
 
   auto integrant_it = integrant.begin(back_dof);
   auto integrant_end = integrant.end(back_dof);
 
   Array<Real>::matrix_iterator B_it =
       shapesd.begin(dim, nodes_per_background_e);
   auto C_it =
       directing_cosines(interface_type, ghost_type).begin(voigt_size);
 
   auto sigma_it = this->stress(interface_type, ghost_type).begin();
 
   Matrix<Real> Bvoigt(voigt_size, back_dof);
 
   for (; integrant_it != integrant_end;
        ++integrant_it, ++B_it, ++C_it, ++sigma_it) {
     VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt,
                                                        nodes_per_background_e);
     Vector<Real> & C = *C_it;
     Vector<Real> & BtCt_sigma = *integrant_it;
 
     BtCt_sigma.mul<true>(Bvoigt, C);
     BtCt_sigma *= *sigma_it * area;
   }
 
   Array<Real> residual_interface(nb_element, back_dof, "residual_interface");
   interface_engine.integrate(integrant, residual_interface, back_dof,
                              interface_type, ghost_type, elem_filter);
   integrant.resize(0);
 
   Array<UInt> background_filter(nb_element, 1, "background_filter");
 
   auto & filter =
       getBackgroundFilter(interface_type, background_type, ghost_type);
 
   emodel.getDOFManager().assembleElementalArrayLocalArray(
       residual_interface, emodel.getInternalForce(), background_type,
       ghost_type, -1., filter);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::computeDirectingCosines(
     const ElementType & type, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Mesh & interface_mesh = emodel.getInterfaceMesh();
 
   const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   const UInt steel_dof = dim * nb_nodes_per_element;
   const UInt voigt_size = VoigtHelper<dim>::size;
   const UInt nb_quad_points = emodel.getFEEngine("EmbeddedInterfaceFEEngine")
                                   .getNbIntegrationPoints(type, ghost_type);
 
   Array<Real> node_coordinates(this->element_filter(type, ghost_type).size(),
                                steel_dof);
 
   this->emodel.getFEEngine().template extractNodalToElementField<Real>(
       interface_mesh, interface_mesh.getNodes(), node_coordinates, type,
       ghost_type, this->element_filter(type, ghost_type));
 
   Array<Real>::matrix_iterator directing_cosines_it =
     directing_cosines(type, ghost_type).begin(1, voigt_size);
 
   Array<Real>::matrix_iterator node_coordinates_it =
       node_coordinates.begin(dim, nb_nodes_per_element);
   Array<Real>::matrix_iterator node_coordinates_end =
       node_coordinates.end(dim, nb_nodes_per_element);
 
   for (; node_coordinates_it != node_coordinates_end; ++node_coordinates_it) {
     for (UInt i = 0; i < nb_quad_points; i++, ++directing_cosines_it) {
       Matrix<Real> & nodes = *node_coordinates_it;
       Matrix<Real> & cosines = *directing_cosines_it;
 
       computeDirectingCosinesOnQuad(nodes, cosines);
     }
   }
 
   // Mauro: the directing_cosines internal is defined on the quadrature points
   // of each element
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix(
     const ElementType & type, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Mesh & mesh = emodel.getMesh();
 
   Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type);
   Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type);
 
   for (; type_it != type_end; ++type_it) {
     assembleStiffnessMatrixInterface(type, *type_it, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001)
  * \f[
  * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T
  * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}}
  * \f]
  */
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrixInterface(
     const ElementType & interface_type, const ElementType & background_type,
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   UInt voigt_size = VoigtHelper<dim>::size;
 
   FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine");
 
   Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type);
   Array<Real> & grad_u = gradu_embedded(interface_type, ghost_type);
 
   UInt nb_element = elem_filter.size();
   UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type);
   UInt nb_quadrature_points =
       interface_engine.getNbIntegrationPoints(interface_type, ghost_type);
 
   UInt back_dof = dim * nodes_per_background_e;
 
   UInt integrant_size = back_dof;
 
   grad_u.resize(nb_quadrature_points * nb_element);
 
   Array<Real> tangent_moduli(nb_element * nb_quadrature_points, 1,
                              "interface_tangent_moduli");
   this->computeTangentModuli(interface_type, tangent_moduli, ghost_type);
 
   Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))(
       background_type, ghost_type);
 
   Array<Real> integrant(nb_element * nb_quadrature_points,
                         integrant_size * integrant_size, "B^t*C^t*D*C*B");
 
   /// Temporary matrices for integrant product
   Matrix<Real> Bvoigt(voigt_size, back_dof);
   Matrix<Real> DCB(1, back_dof);
   Matrix<Real> CtDCB(voigt_size, back_dof);
 
   Array<Real>::scalar_iterator D_it = tangent_moduli.begin();
   Array<Real>::scalar_iterator D_end = tangent_moduli.end();
 
   Array<Real>::matrix_iterator C_it =
       directing_cosines(interface_type, ghost_type).begin(1, voigt_size);
   Array<Real>::matrix_iterator B_it =
       shapesd.begin(dim, nodes_per_background_e);
   Array<Real>::matrix_iterator integrant_it =
       integrant.begin(integrant_size, integrant_size);
 
   for (; D_it != D_end; ++D_it, ++C_it, ++B_it, ++integrant_it) {
     Real & D = *D_it;
     Matrix<Real> & C = *C_it;
     Matrix<Real> & B = *B_it;
     Matrix<Real> & BtCtDCB = *integrant_it;
 
     VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt,
                                                        nodes_per_background_e);
 
     DCB.mul<false, false>(C, Bvoigt);
     DCB *= D * area;
     CtDCB.mul<true, false>(C, DCB);
     BtCtDCB.mul<true, false>(Bvoigt, CtDCB);
   }
 
   tangent_moduli.resize(0);
 
   Array<Real> K_interface(nb_element, integrant_size * integrant_size,
                           "K_interface");
   interface_engine.integrate(integrant, K_interface,
                              integrant_size * integrant_size, interface_type,
                              ghost_type, elem_filter);
 
   integrant.resize(0);
 
   // Mauro: Here K_interface contains the local stiffness matrices,
   // directing_cosines contains the information about the orientation
   // of the reinforcements, any rotation of the local stiffness matrix
   // can be done here
 
   auto & filter =
       getBackgroundFilter(interface_type, background_type, ghost_type);
 
   emodel.getDOFManager().assembleElementalMatricesToMatrix(
       "K", "displacement", K_interface, background_type, ghost_type, _symmetric,
       filter);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Mat, UInt dim>
 Real MaterialReinforcement<Mat, dim>::getEnergy(const std::string & id) {
   AKANTU_DEBUG_IN();
   if (id == "potential") {
     Real epot = 0.;
 
     this->computePotentialEnergyByElements();
 
     Mesh::type_iterator it = this->element_filter.firstType(
                             this->spatial_dimension),
                         end = this->element_filter.lastType(
                             this->spatial_dimension);
 
     for (; it != end; ++it) {
       FEEngine & interface_engine =
           emodel.getFEEngine("EmbeddedInterfaceFEEngine");
       epot += interface_engine.integrate(
           this->potential_energy(*it, _not_ghost), *it, _not_ghost,
           this->element_filter(*it, _not_ghost));
       epot *= area;
     }
 
     return epot;
   }
 
   AKANTU_DEBUG_OUT();
   return 0;
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 void MaterialReinforcement<Mat, dim>::computeGradU(
     const ElementType & interface_type, GhostType ghost_type) {
   // Looping over background types
   for (auto && bg_type :
        background_filter(interface_type, ghost_type)->elementTypes(dim)) {
 
     const UInt nodes_per_background_e = Mesh::getNbNodesPerElement(bg_type);
     const UInt voigt_size = VoigtHelper<dim>::size;
 
     auto & bg_shapesd =
         (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type);
 
     auto & filter = getBackgroundFilter(interface_type, bg_type, ghost_type);
 
     Array<Real> disp_per_element(0, dim * nodes_per_background_e, "disp_elem");
 
     FEEngine::extractNodalToElementField(
         emodel.getMesh(), emodel.getDisplacement(), disp_per_element, bg_type,
         ghost_type, filter);
 
     Matrix<Real> concrete_du(dim, dim);
     Matrix<Real> epsilon(dim, dim);
     Vector<Real> evoigt(voigt_size);
 
     for (auto && tuple :
          zip(make_view(disp_per_element, dim, nodes_per_background_e),
              make_view(bg_shapesd, dim, nodes_per_background_e),
              this->gradu(interface_type, ghost_type),
              make_view(this->directing_cosines(interface_type, ghost_type),
                        voigt_size))) {
       auto & u = std::get<0>(tuple);
       auto & B = std::get<1>(tuple);
       auto & du = std::get<2>(tuple);
       auto & C = std::get<3>(tuple);
 
       concrete_du.mul<false, true>(u, B);
       auto epsilon = 0.5 * (concrete_du + concrete_du.transpose());
       strainTensorToVoigtVector(epsilon, evoigt);
       du = C.dot(evoigt);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 /**
  * The structure of the directing cosines matrix is :
  * \f{eqnarray*}{
  *  C_{1,\cdot} & = & (l^2, m^2, n^2, mn, ln, lm) \\
  *  C_{i,j} & = & 0
  * \f}
  *
  * with :
  * \f[
  * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot
  * \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}
  * \f]
  */
 template <class Mat, UInt dim>
 inline void MaterialReinforcement<Mat, dim>::computeDirectingCosinesOnQuad(
     const Matrix<Real> & nodes, Matrix<Real> & cosines) {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(nodes.cols() == 2,
                       "Higher order reinforcement elements not implemented");
 
   const Vector<Real> a = nodes(0), b = nodes(1);
   Vector<Real> delta = b - a;
 
   Real sq_length = 0.;
   for (UInt i = 0; i < dim; i++) {
     sq_length += delta(i) * delta(i);
   }
 
   if (dim == 2) {
     cosines(0, 0) = delta(0) * delta(0); // l^2
     cosines(0, 1) = delta(1) * delta(1); // m^2
     cosines(0, 2) = delta(0) * delta(1); // lm
   } else if (dim == 3) {
     cosines(0, 0) = delta(0) * delta(0); // l^2
     cosines(0, 1) = delta(1) * delta(1); // m^2
     cosines(0, 2) = delta(2) * delta(2); // n^2
 
     cosines(0, 3) = delta(1) * delta(2); // mn
     cosines(0, 4) = delta(0) * delta(2); // ln
     cosines(0, 5) = delta(0) * delta(1); // lm
   }
 
   cosines /= sq_length;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 inline void MaterialReinforcement<Mat, dim>::stressTensorToVoigtVector(
     const Matrix<Real> & tensor, Vector<Real> & vector) {
   AKANTU_DEBUG_IN();
 
   for (UInt i = 0; i < dim; i++) {
     vector(i) = tensor(i, i);
   }
 
   if (dim == 2) {
     vector(2) = tensor(0, 1);
   } else if (dim == 3) {
     vector(3) = tensor(1, 2);
     vector(4) = tensor(0, 2);
     vector(5) = tensor(0, 1);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <class Mat, UInt dim>
 inline void MaterialReinforcement<Mat, dim>::strainTensorToVoigtVector(
     const Matrix<Real> & tensor, Vector<Real> & vector) {
   AKANTU_DEBUG_IN();
 
   for (UInt i = 0; i < dim; i++) {
     vector(i) = tensor(i, i);
   }
 
   if (dim == 2) {
     vector(2) = 2 * tensor(0, 1);
   } else if (dim == 3) {
     vector(3) = 2 * tensor(1, 2);
     vector(4) = 2 * tensor(0, 2);
     vector(5) = 2 * tensor(0, 1);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 } // akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc
index e97927adf..e534b46f2 100644
--- a/src/model/solid_mechanics/solid_mechanics_model.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model.cc
@@ -1,1195 +1,1219 @@
 /**
  * @file   solid_mechanics_model.cc
  *
  * @author Ramin Aghababaei <ramin.aghababaei@epfl.ch>
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Clement Roux <clement.roux@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Tue Jul 27 2010
  * @date last modification: Tue Jan 19 2016
  *
  * @brief  Implementation of the SolidMechanicsModel class
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "solid_mechanics_model.hh"
 #include "integrator_gauss.hh"
 #include "shape_lagrange.hh"
 #include "solid_mechanics_model_tmpl.hh"
 
 #include "communicator.hh"
 #include "element_synchronizer.hh"
 #include "sparse_matrix.hh"
 #include "synchronizer_registry.hh"
 
 #include "dumpable_inline_impl.hh"
 #ifdef AKANTU_USE_IOHELPER
 #include "dumper_iohelper_paraview.hh"
 #endif
 
 #include "material_non_local.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /**
  * A solid mechanics model need a mesh  and a dimension to be created. the model
  * by it  self can not  do a lot,  the good init  functions should be  called in
  * order to configure the model depending on what we want to do.
  *
  * @param  mesh mesh  representing  the model  we  want to  simulate
  * @param dim spatial  dimension of the problem, if dim =  0 (default value) the
  * dimension of the problem is assumed to be the on of the mesh
  * @param id an id to identify the model
  */
 SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id,
-                                         const MemoryID & memory_id, const ModelType model_type)
+                                         const MemoryID & memory_id,
+                                         const ModelType model_type)
     : Model(mesh, model_type, dim, id, memory_id),
       BoundaryCondition<SolidMechanicsModel>(), f_m2a(1.0),
       displacement(nullptr), previous_displacement(nullptr),
       displacement_increment(nullptr), mass(nullptr), velocity(nullptr),
       acceleration(nullptr), external_force(nullptr), internal_force(nullptr),
       blocked_dofs(nullptr), current_position(nullptr),
       material_index("material index", id, memory_id),
       material_local_numbering("material local numbering", id, memory_id),
-      increment_flag(false),
-      are_materials_instantiated(false) {
+      increment_flag(false), are_materials_instantiated(false) {
   AKANTU_DEBUG_IN();
 
   this->registerFEEngineObject<MyFEEngineType>("SolidMechanicsFEEngine", mesh,
                                                Model::spatial_dimension);
 
 #if defined(AKANTU_USE_IOHELPER)
   this->mesh.registerDumper<DumperParaview>("paraview_all", id, true);
   this->mesh.addDumpMesh(mesh, Model::spatial_dimension, _not_ghost,
                          _ek_regular);
 #endif
 
   material_selector = std::make_shared<DefaultMaterialSelector>(material_index),
 
   this->initDOFManager();
 
   this->registerDataAccessor(*this);
 
   if (this->mesh.isDistributed()) {
     auto & synchronizer = this->mesh.getElementSynchronizer();
     this->registerSynchronizer(synchronizer, _gst_material_id);
     this->registerSynchronizer(synchronizer, _gst_smm_mass);
     this->registerSynchronizer(synchronizer, _gst_smm_stress);
     this->registerSynchronizer(synchronizer, _gst_smm_boundary);
     this->registerSynchronizer(synchronizer, _gst_for_dump);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModel::~SolidMechanicsModel() {
   AKANTU_DEBUG_IN();
 
   for (auto & internal : this->registered_internals) {
     delete internal.second;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::setTimeStep(Real time_step, const ID & solver_id) {
   Model::setTimeStep(time_step, solver_id);
 
 #if defined(AKANTU_USE_IOHELPER)
   this->mesh.getDumper().setTimeStep(time_step);
 #endif
 }
 
 /* -------------------------------------------------------------------------- */
 /* Initialization                                                             */
 /* -------------------------------------------------------------------------- */
 /**
  * This function groups  many of the initialization in on  function. For most of
  * basics  case the  function should  be  enough. The  functions initialize  the
  * model, the internal  vectors, set them to 0, and  depending on the parameters
  * it also initialize the explicit or implicit solver.
  *
  * @param material_file the  file containing the materials to  use
  * @param method the analysis method wanted.  See the akantu::AnalysisMethod for
  * the different possibilities
  */
 void SolidMechanicsModel::initFullImpl(const ModelOptions & options) {
   material_index.initialize(mesh, _element_kind = _ek_not_defined,
                             _default_value = UInt(-1), _with_nb_element = true);
   material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined,
                                       _with_nb_element = true);
 
   Model::initFullImpl(options);
 
   // initialize pbc
   if (this->pbc_pair.size() != 0)
     this->initPBC();
 
   // initialize the materials
   if (this->parser.getLastParsedFile() != "") {
     this->instantiateMaterials();
   }
 
   this->initMaterials();
 
   this->initBC(*this, *displacement, *displacement_increment, *external_force);
 }
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolverType SolidMechanicsModel::getDefaultSolverType() const {
   return _tsst_dynamic_lumped;
 }
 
 /* -------------------------------------------------------------------------- */
 ModelSolverOptions SolidMechanicsModel::getDefaultSolverOptions(
     const TimeStepSolverType & type) const {
   ModelSolverOptions options;
 
   switch (type) {
   case _tsst_dynamic_lumped: {
     options.non_linear_solver_type = _nls_lumped;
     options.integration_scheme_type["displacement"] = _ist_central_difference;
     options.solution_type["displacement"] = IntegrationScheme::_acceleration;
     break;
   }
   case _tsst_static: {
     options.non_linear_solver_type = _nls_newton_raphson;
     options.integration_scheme_type["displacement"] = _ist_pseudo_time;
     options.solution_type["displacement"] = IntegrationScheme::_not_defined;
     break;
   }
   case _tsst_dynamic: {
     if (this->method == _explicit_consistent_mass) {
       options.non_linear_solver_type = _nls_newton_raphson;
       options.integration_scheme_type["displacement"] = _ist_central_difference;
       options.solution_type["displacement"] = IntegrationScheme::_acceleration;
     } else {
       options.non_linear_solver_type = _nls_newton_raphson;
       options.integration_scheme_type["displacement"] = _ist_trapezoidal_rule_2;
       options.solution_type["displacement"] = IntegrationScheme::_displacement;
     }
     break;
   }
   default:
     AKANTU_EXCEPTION(type << " is not a valid time step solver type");
   }
 
   return options;
 }
 
 /* -------------------------------------------------------------------------- */
 std::tuple<ID, TimeStepSolverType>
 SolidMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) {
   switch (method) {
   case _explicit_lumped_mass: {
     return std::make_tuple("explicit_lumped", _tsst_dynamic_lumped);
   }
   case _explicit_consistent_mass: {
     return std::make_tuple("explicit", _tsst_dynamic);
   }
   case _static: {
     return std::make_tuple("static", _tsst_static);
   }
   case _implicit_dynamic: {
     return std::make_tuple("implicit", _tsst_dynamic);
   }
   default:
     return std::make_tuple("unknown", _tsst_not_defined);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type,
                                      NonLinearSolverType) {
   auto & dof_manager = this->getDOFManager();
 
   /* ------------------------------------------------------------------------ */
   // for alloc type of solvers
   this->allocNodalField(this->displacement, spatial_dimension, "displacement");
   this->allocNodalField(this->previous_displacement, spatial_dimension,
                         "previous_displacement");
   this->allocNodalField(this->displacement_increment, spatial_dimension,
                         "displacement_increment");
   this->allocNodalField(this->internal_force, spatial_dimension,
                         "internal_force");
   this->allocNodalField(this->external_force, spatial_dimension,
                         "external_force");
   this->allocNodalField(this->blocked_dofs, spatial_dimension, "blocked_dofs");
   this->allocNodalField(this->current_position, spatial_dimension,
                         "current_position");
 
   // initialize the current positions
   this->current_position->copy(this->mesh.getNodes());
 
   /* ------------------------------------------------------------------------ */
   if (!dof_manager.hasDOFs("displacement")) {
     dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal);
     dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs);
     dof_manager.registerDOFsIncrement("displacement",
                                       *this->displacement_increment);
     dof_manager.registerDOFsPrevious("displacement",
                                      *this->previous_displacement);
   }
 
   /* ------------------------------------------------------------------------ */
   // for dynamic
   if (time_step_solver_type == _tsst_dynamic ||
       time_step_solver_type == _tsst_dynamic_lumped) {
     this->allocNodalField(this->velocity, spatial_dimension, "velocity");
     this->allocNodalField(this->acceleration, spatial_dimension,
                           "acceleration");
 
     if (!dof_manager.hasDOFsDerivatives("displacement", 1)) {
       dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity);
       dof_manager.registerDOFsDerivative("displacement", 2,
                                          *this->acceleration);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Initialize the model,basically it  pre-compute the shapes, shapes derivatives
  * and jacobian
  */
 void SolidMechanicsModel::initModel() {
   /// \todo add  the current position  as a parameter to  initShapeFunctions for
   /// large deformation
   getFEEngine().initShapeFunctions(_not_ghost);
   getFEEngine().initShapeFunctions(_ghost);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::assembleResidual() {
   AKANTU_DEBUG_IN();
 
   /* ------------------------------------------------------------------------ */
   // computes the internal forces
   this->assembleInternalForces();
 
   /* ------------------------------------------------------------------------ */
   this->getDOFManager().assembleToResidual("displacement",
                                            *this->external_force, 1);
   this->getDOFManager().assembleToResidual("displacement",
                                            *this->internal_force, 1);
 
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModel::assembleResidual(const ID & residual_part) {
+  AKANTU_DEBUG_IN();
+
+  if ("external" == residual_part) {
+    this->getDOFManager().assembleToResidual("displacement",
+                                             *this->external_force, 1);
+    AKANTU_DEBUG_OUT();
+    return;
+  }
+
+  if ("internal" == residual_part) {
+    this->getDOFManager().assembleToResidual("displacement",
+                                             *this->internal_force, 1);
+    AKANTU_DEBUG_OUT();
+    return;
+  }
+
+  AKANTU_CUSTOM_EXCEPTION(
+      debug::SolverCallbackResidualPartUnknown(residual_part));
+
+  AKANTU_DEBUG_OUT();
+}
+
 /* -------------------------------------------------------------------------- */
 MatrixType SolidMechanicsModel::getMatrixType(const ID & matrix_id) {
   // \TODO check the materials to know what is the correct answer
   if (matrix_id == "C")
     return _mt_not_defined;
 
   return _symmetric;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::assembleMatrix(const ID & matrix_id) {
   if (matrix_id == "K") {
     this->assembleStiffnessMatrix();
   } else if (matrix_id == "M") {
     this->assembleMass();
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::assembleLumpedMatrix(const ID & matrix_id) {
   if (matrix_id == "M") {
     this->assembleMassLumped();
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::beforeSolveStep() {
   for (auto & material : materials)
     material->beforeSolveStep();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::afterSolveStep() {
   for (auto & material : materials)
     material->afterSolveStep();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::predictor() { ++displacement_release; }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::corrector() { ++displacement_release; }
 
 /* -------------------------------------------------------------------------- */
 /**
  * This function computes the internal forces as F_{int} = \int_{\Omega} N
  * \sigma d\Omega@f$
  */
 void SolidMechanicsModel::assembleInternalForces() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_INFO("Assemble the internal forces");
 
   this->internal_force->clear();
 
   // compute the stresses of local elements
   AKANTU_DEBUG_INFO("Compute local stresses");
   for (auto & material : materials) {
     material->computeAllStresses(_not_ghost);
   }
 
   /* ------------------------------------------------------------------------ */
   /* Computation of the non local part */
   if (this->non_local_manager)
     this->non_local_manager->computeAllNonLocalStresses();
 
   // communicate the stresses
   AKANTU_DEBUG_INFO("Send data for residual assembly");
   this->asynchronousSynchronize(_gst_smm_stress);
 
   // assemble the forces due to local stresses
   AKANTU_DEBUG_INFO("Assemble residual for local elements");
   for (auto & material : materials) {
     material->assembleInternalForces(_not_ghost);
   }
 
   // finalize communications
   AKANTU_DEBUG_INFO("Wait distant stresses");
   this->waitEndSynchronize(_gst_smm_stress);
 
   // assemble the stresses due to ghost elements
   AKANTU_DEBUG_INFO("Assemble residual for ghost elements");
   for (auto & material : materials) {
     material->assembleInternalForces(_ghost);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::assembleStiffnessMatrix() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_INFO("Assemble the new stiffness matrix.");
 
   // Check if materials need to recompute the matrix
   bool need_to_reassemble = false;
 
   for (auto & material : materials) {
     need_to_reassemble |= material->hasStiffnessMatrixChanged();
   }
 
   if (need_to_reassemble) {
     this->getDOFManager().getMatrix("K").clear();
 
     // call compute stiffness matrix on each local elements
     for (auto & material : materials) {
       material->assembleStiffnessMatrix(_not_ghost);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateCurrentPosition() {
   if (this->current_position_release == this->displacement_release)
     return;
 
   this->current_position->copy(this->mesh.getNodes());
 
   auto cpos_it = this->current_position->begin(Model::spatial_dimension);
   auto cpos_end = this->current_position->end(Model::spatial_dimension);
   auto disp_it = this->displacement->begin(Model::spatial_dimension);
 
   for (; cpos_it != cpos_end; ++cpos_it, ++disp_it) {
     *cpos_it += *disp_it;
   }
 
   this->current_position_release = this->displacement_release;
 }
 
 /* -------------------------------------------------------------------------- */
 const Array<Real> & SolidMechanicsModel::getCurrentPosition() {
   this->updateCurrentPosition();
   return *this->current_position;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateDataForNonLocalCriterion(
     ElementTypeMapReal & criterion) {
   const ID field_name = criterion.getName();
   for (auto & material : materials) {
     if (!material->isInternal<Real>(field_name, _ek_regular))
       continue;
 
     for (auto ghost_type : ghost_types) {
       material->flattenInternal(field_name, criterion, ghost_type, _ek_regular);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 /* Information                                                                */
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getStableTimeStep() {
   AKANTU_DEBUG_IN();
 
   Real min_dt = getStableTimeStep(_not_ghost);
 
   /// reduction min over all processors
   mesh.getCommunicator().allReduce(min_dt, SynchronizerOperation::_min);
 
   AKANTU_DEBUG_OUT();
   return min_dt;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   Real min_dt = std::numeric_limits<Real>::max();
 
   this->updateCurrentPosition();
 
   Element elem;
   elem.ghost_type = ghost_type;
 
   for (auto type :
        mesh.elementTypes(Model::spatial_dimension, ghost_type, _ek_regular)) {
     elem.type = type;
     UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type);
     UInt nb_element = mesh.getNbElement(type);
 
     auto mat_indexes = material_index(type, ghost_type).begin();
     auto mat_loc_num = material_local_numbering(type, ghost_type).begin();
 
     Array<Real> X(0, nb_nodes_per_element * Model::spatial_dimension);
     FEEngine::extractNodalToElementField(mesh, *current_position, X, type,
                                          _not_ghost);
 
     auto X_el = X.begin(Model::spatial_dimension, nb_nodes_per_element);
 
     for (UInt el = 0; el < nb_element;
          ++el, ++X_el, ++mat_indexes, ++mat_loc_num) {
       elem.element = *mat_loc_num;
       Real el_h = getFEEngine().getElementInradius(*X_el, type);
       Real el_c = this->materials[*mat_indexes]->getCelerity(elem);
       Real el_dt = el_h / el_c;
 
       min_dt = std::min(min_dt, el_dt);
     }
   }
 
   AKANTU_DEBUG_OUT();
   return min_dt;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getKineticEnergy() {
   AKANTU_DEBUG_IN();
 
   Real ekin = 0.;
   UInt nb_nodes = mesh.getNbNodes();
 
   if (this->getDOFManager().hasLumpedMatrix("M")) {
     auto m_it = this->mass->begin(Model::spatial_dimension);
     auto m_end = this->mass->end(Model::spatial_dimension);
     auto v_it = this->velocity->begin(Model::spatial_dimension);
 
     for (UInt n = 0; m_it != m_end; ++n, ++m_it, ++v_it) {
       const Vector<Real> & v = *v_it;
       const Vector<Real> & m = *m_it;
 
       Real mv2 = 0;
       bool is_local_node = mesh.isLocalOrMasterNode(n);
       // bool is_not_pbc_slave_node = !isPBCSlaveNode(n);
       bool count_node = is_local_node; // && is_not_pbc_slave_node;
       if (count_node) {
         for (UInt i = 0; i < Model::spatial_dimension; ++i) {
           if (m(i) > std::numeric_limits<Real>::epsilon())
             mv2 += v(i) * v(i) * m(i);
         }
       }
 
       ekin += mv2;
     }
   } else if (this->getDOFManager().hasMatrix("M")) {
     Array<Real> Mv(nb_nodes, Model::spatial_dimension);
     this->getDOFManager().getMatrix("M").matVecMul(*this->velocity, Mv);
 
     auto mv_it = Mv.begin(Model::spatial_dimension);
     auto mv_end = Mv.end(Model::spatial_dimension);
     auto v_it = this->velocity->begin(Model::spatial_dimension);
 
     for (; mv_it != mv_end; ++mv_it, ++v_it) {
       ekin += v_it->dot(*mv_it);
     }
   } else {
     AKANTU_ERROR("No function called to assemble the mass matrix.");
   }
 
   mesh.getCommunicator().allReduce(ekin, SynchronizerOperation::_sum);
 
   AKANTU_DEBUG_OUT();
   return ekin * .5;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getKineticEnergy(const ElementType & type,
                                            UInt index) {
   AKANTU_DEBUG_IN();
 
   UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type);
 
   Array<Real> vel_on_quad(nb_quadrature_points, Model::spatial_dimension);
   Array<UInt> filter_element(1, 1, index);
 
   getFEEngine().interpolateOnIntegrationPoints(*velocity, vel_on_quad,
                                                Model::spatial_dimension, type,
                                                _not_ghost, filter_element);
 
   auto vit =
       vel_on_quad.begin(Model::spatial_dimension);
   auto vend = vel_on_quad.end(Model::spatial_dimension);
 
   Vector<Real> rho_v2(nb_quadrature_points);
 
   Real rho = materials[material_index(type)(index)]->getRho();
 
   for (UInt q = 0; vit != vend; ++vit, ++q) {
     rho_v2(q) = rho * vit->dot(*vit);
   }
 
   AKANTU_DEBUG_OUT();
 
   return .5 * getFEEngine().integrate(rho_v2, type, index);
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getExternalWork() {
   AKANTU_DEBUG_IN();
 
   auto ext_force_it = external_force->begin(Model::spatial_dimension);
   auto int_force_it = internal_force->begin(Model::spatial_dimension);
   auto boun_it = blocked_dofs->begin(Model::spatial_dimension);
 
   decltype(ext_force_it) incr_or_velo_it;
   if (this->method == _static) {
     incr_or_velo_it =
         this->displacement_increment->begin(Model::spatial_dimension);
   } else {
     incr_or_velo_it = this->velocity->begin(Model::spatial_dimension);
   }
 
   Real work = 0.;
 
   UInt nb_nodes = this->mesh.getNbNodes();
 
   for (UInt n = 0; n < nb_nodes;
        ++n, ++ext_force_it, ++int_force_it, ++boun_it, ++incr_or_velo_it) {
     const auto & int_force = *int_force_it;
     const auto & ext_force = *ext_force_it;
     const auto & boun = *boun_it;
     const auto & incr_or_velo = *incr_or_velo_it;
 
     bool is_local_node = this->mesh.isLocalOrMasterNode(n);
     // bool is_not_pbc_slave_node = !this->isPBCSlaveNode(n);
     bool count_node = is_local_node; // && is_not_pbc_slave_node;
 
     if (count_node) {
       for (UInt i = 0; i < Model::spatial_dimension; ++i) {
         if (boun(i))
           work -= int_force(i) * incr_or_velo(i);
         else
           work += ext_force(i) * incr_or_velo(i);
       }
     }
   }
 
   mesh.getCommunicator().allReduce(work, SynchronizerOperation::_sum);
 
   if (this->method != _static)
     work *= this->getTimeStep();
 
   AKANTU_DEBUG_OUT();
   return work;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getEnergy(const std::string & energy_id) {
   AKANTU_DEBUG_IN();
 
   if (energy_id == "kinetic") {
     return getKineticEnergy();
   } else if (energy_id == "external work") {
     return getExternalWork();
   }
 
   Real energy = 0.;
   for (auto & material : materials)
     energy += material->getEnergy(energy_id);
 
   /// reduction sum over all processors
   mesh.getCommunicator().allReduce(energy, SynchronizerOperation::_sum);
 
   AKANTU_DEBUG_OUT();
   return energy;
 }
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getEnergy(const std::string & energy_id,
                                     const ElementType & type, UInt index) {
   AKANTU_DEBUG_IN();
 
   if (energy_id == "kinetic") {
     return getKineticEnergy(type, index);
   }
 
   UInt mat_index = this->material_index(type, _not_ghost)(index);
   UInt mat_loc_num = this->material_local_numbering(type, _not_ghost)(index);
   Real energy =
       this->materials[mat_index]->getEnergy(energy_id, type, mat_loc_num);
 
   AKANTU_DEBUG_OUT();
   return energy;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onElementsAdded(const Array<Element> & element_list,
                                           const NewElementsEvent & event) {
   AKANTU_DEBUG_IN();
 
   this->material_index.initialize(mesh, _element_kind = _ek_not_defined,
                                   _with_nb_element = true,
                                   _default_value = UInt(-1));
   this->material_local_numbering.initialize(
       mesh, _element_kind = _ek_not_defined, _with_nb_element = true,
       _default_value = UInt(-1));
 
   ElementTypeMapArray<UInt> filter("new_element_filter", this->getID(),
                                    this->getMemoryID());
 
   for (auto & elem : element_list) {
     if (!filter.exists(elem.type, elem.ghost_type))
       filter.alloc(0, 1, elem.type, elem.ghost_type);
     filter(elem.type, elem.ghost_type).push_back(elem.element);
   }
 
   this->assignMaterialToElements(&filter);
 
   for (auto & material : materials)
     material->onElementsAdded(element_list, event);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onElementsRemoved(
     const Array<Element> & element_list,
     const ElementTypeMapArray<UInt> & new_numbering,
     const RemovedElementsEvent & event) {
   for (auto & material : materials) {
     material->onElementsRemoved(element_list, new_numbering, event);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onNodesAdded(const Array<UInt> & nodes_list,
                                        const NewNodesEvent & event) {
   AKANTU_DEBUG_IN();
   UInt nb_nodes = mesh.getNbNodes();
 
   if (displacement) {
     displacement->resize(nb_nodes, 0.);
     ++displacement_release;
   }
   if (mass)
     mass->resize(nb_nodes, 0.);
   if (velocity)
     velocity->resize(nb_nodes, 0.);
   if (acceleration)
     acceleration->resize(nb_nodes, 0.);
   if (external_force)
     external_force->resize(nb_nodes, 0.);
   if (internal_force)
     internal_force->resize(nb_nodes, 0.);
   if (blocked_dofs)
     blocked_dofs->resize(nb_nodes, 0.);
   if (current_position)
     current_position->resize(nb_nodes, 0.);
 
   if (previous_displacement)
     previous_displacement->resize(nb_nodes, 0.);
   if (displacement_increment)
     displacement_increment->resize(nb_nodes, 0.);
 
   for (auto & material : materials) {
     material->onNodesAdded(nodes_list, event);
   }
 
   need_to_reassemble_lumped_mass = true;
   need_to_reassemble_mass = true;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onNodesRemoved(const Array<UInt> & /*element_list*/,
                                          const Array<UInt> & new_numbering,
                                          const RemovedNodesEvent & /*event*/) {
   if (displacement) {
     mesh.removeNodesFromArray(*displacement, new_numbering);
     ++displacement_release;
   }
   if (mass)
     mesh.removeNodesFromArray(*mass, new_numbering);
   if (velocity)
     mesh.removeNodesFromArray(*velocity, new_numbering);
   if (acceleration)
     mesh.removeNodesFromArray(*acceleration, new_numbering);
   if (internal_force)
     mesh.removeNodesFromArray(*internal_force, new_numbering);
   if (external_force)
     mesh.removeNodesFromArray(*external_force, new_numbering);
   if (blocked_dofs)
     mesh.removeNodesFromArray(*blocked_dofs, new_numbering);
 
   // if (increment_acceleration)
   //   mesh.removeNodesFromArray(*increment_acceleration, new_numbering);
   if (displacement_increment)
     mesh.removeNodesFromArray(*displacement_increment, new_numbering);
 
   if (previous_displacement)
     mesh.removeNodesFromArray(*previous_displacement, new_numbering);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::printself(std::ostream & stream, int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   stream << space << "Solid Mechanics Model [" << std::endl;
   stream << space << " + id                : " << id << std::endl;
   stream << space << " + spatial dimension : " << Model::spatial_dimension
          << std::endl;
   stream << space << " + fem [" << std::endl;
   getFEEngine().printself(stream, indent + 2);
   stream << space << AKANTU_INDENT << "]" << std::endl;
   stream << space << " + nodals information [" << std::endl;
   displacement->printself(stream, indent + 2);
   if (velocity)
     velocity->printself(stream, indent + 2);
   if (acceleration)
     acceleration->printself(stream, indent + 2);
   if (mass)
     mass->printself(stream, indent + 2);
   external_force->printself(stream, indent + 2);
   internal_force->printself(stream, indent + 2);
   blocked_dofs->printself(stream, indent + 2);
   stream << space << AKANTU_INDENT << "]" << std::endl;
 
   stream << space << " + material information [" << std::endl;
   material_index.printself(stream, indent + 2);
   stream << space << AKANTU_INDENT << "]" << std::endl;
 
   stream << space << " + materials [" << std::endl;
   for (auto & material : materials) {
     material->printself(stream, indent + 1);
   }
   stream << space << AKANTU_INDENT << "]" << std::endl;
 
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initializeNonLocal() {
   this->non_local_manager->synchronize(*this, _gst_material_id);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::insertIntegrationPointsInNeighborhoods(
     const GhostType & ghost_type) {
   for (auto & mat : materials) {
     MaterialNonLocalInterface * mat_non_local;
     if ((mat_non_local =
              dynamic_cast<MaterialNonLocalInterface *>(mat.get())) == nullptr)
       continue;
 
     ElementTypeMapArray<Real> quadrature_points_coordinates(
         "quadrature_points_coordinates_tmp_nl", this->id, this->memory_id);
     quadrature_points_coordinates.initialize(this->getFEEngine(),
                                              _nb_component = spatial_dimension,
                                              _ghost_type = ghost_type);
 
     for (auto & type : quadrature_points_coordinates.elementTypes(
              Model::spatial_dimension, ghost_type)) {
       this->getFEEngine().computeIntegrationPointsCoordinates(
           quadrature_points_coordinates(type, ghost_type), type, ghost_type);
     }
 
     mat_non_local->initMaterialNonLocal();
 
     mat_non_local->insertIntegrationPointsInNeighborhoods(
         ghost_type, quadrature_points_coordinates);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::computeNonLocalStresses(
     const GhostType & ghost_type) {
   for (auto & mat : materials) {
     if (dynamic_cast<MaterialNonLocalInterface *>(mat.get()) == nullptr)
       continue;
 
     auto & mat_non_local = dynamic_cast<MaterialNonLocalInterface &>(*mat);
     mat_non_local.computeNonLocalStresses(ghost_type);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateLocalInternal(
     ElementTypeMapReal & internal_flat, const GhostType & ghost_type,
     const ElementKind & kind) {
   const ID field_name = internal_flat.getName();
   for (auto & material : materials) {
     if (material->isInternal<Real>(field_name, kind))
       material->flattenInternal(field_name, internal_flat, ghost_type, kind);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateNonLocalInternal(
     ElementTypeMapReal & internal_flat, const GhostType & ghost_type,
     const ElementKind & kind) {
 
   const ID field_name = internal_flat.getName();
 
   for (auto & mat : materials) {
     if (dynamic_cast<MaterialNonLocalInterface *>(mat.get()) == nullptr)
       continue;
 
     auto & mat_non_local = dynamic_cast<MaterialNonLocalInterface &>(*mat);
     mat_non_local.updateNonLocalInternals(internal_flat, field_name, ghost_type,
                                           kind);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) {
   return dynamic_cast<FEEngine &>(
       getFEEngineClassBoundary<MyFEEngineType>(name));
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::splitElementByMaterial(
     const Array<Element> & elements,
     std::vector<Array<Element>> & elements_per_mat) const {
   ElementType current_element_type = _not_defined;
   GhostType current_ghost_type = _casper;
   const Array<UInt> * mat_indexes = nullptr;
   const Array<UInt> * mat_loc_num = nullptr;
 
   for (const auto & el : elements) {
     if (el.type != current_element_type ||
         el.ghost_type != current_ghost_type) {
       current_element_type = el.type;
       current_ghost_type = el.ghost_type;
       mat_indexes = &(this->material_index(el.type, el.ghost_type));
       mat_loc_num = &(this->material_local_numbering(el.type, el.ghost_type));
     }
 
     Element mat_el = el;
 
     mat_el.element = (*mat_loc_num)(el.element);
     elements_per_mat[(*mat_indexes)(el.element)].push_back(mat_el);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 UInt SolidMechanicsModel::getNbData(const Array<Element> & elements,
                                     const SynchronizationTag & tag) const {
   AKANTU_DEBUG_IN();
 
   UInt size = 0;
   UInt nb_nodes_per_element = 0;
 
   for (const Element & el : elements) {
     nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type);
   }
 
   switch (tag) {
   case _gst_material_id: {
     size += elements.size() * sizeof(UInt);
     break;
   }
   case _gst_smm_mass: {
     size += nb_nodes_per_element * sizeof(Real) *
             Model::spatial_dimension; // mass vector
     break;
   }
   case _gst_smm_for_gradu: {
     size += nb_nodes_per_element * Model::spatial_dimension *
             sizeof(Real); // displacement
     break;
   }
   case _gst_smm_boundary: {
     // force, displacement, boundary
     size += nb_nodes_per_element * Model::spatial_dimension *
             (2 * sizeof(Real) + sizeof(bool));
     break;
   }
   case _gst_for_dump: {
     // displacement, velocity, acceleration, residual, force
     size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real) * 5;
     break;
   }
   default: {}
   }
 
   if (tag != _gst_material_id) {
     splitByMaterial(elements, [&](auto && mat, auto && elements) {
       size += mat.getNbData(elements, tag);
     });
   }
 
   AKANTU_DEBUG_OUT();
   return size;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::packData(CommunicationBuffer & buffer,
                                    const Array<Element> & elements,
                                    const SynchronizationTag & tag) const {
   AKANTU_DEBUG_IN();
 
   switch (tag) {
   case _gst_material_id: {
     this->packElementalDataHelper(material_index, buffer, elements, false,
                                   getFEEngine());
     break;
   }
   case _gst_smm_mass: {
     packNodalDataHelper(*mass, buffer, elements, mesh);
     break;
   }
   case _gst_smm_for_gradu: {
     packNodalDataHelper(*displacement, buffer, elements, mesh);
     break;
   }
   case _gst_for_dump: {
     packNodalDataHelper(*displacement, buffer, elements, mesh);
     packNodalDataHelper(*velocity, buffer, elements, mesh);
     packNodalDataHelper(*acceleration, buffer, elements, mesh);
     packNodalDataHelper(*internal_force, buffer, elements, mesh);
     packNodalDataHelper(*external_force, buffer, elements, mesh);
     break;
   }
   case _gst_smm_boundary: {
     packNodalDataHelper(*external_force, buffer, elements, mesh);
     packNodalDataHelper(*velocity, buffer, elements, mesh);
     packNodalDataHelper(*blocked_dofs, buffer, elements, mesh);
     break;
   }
   default: {}
   }
 
   if (tag != _gst_material_id) {
     splitByMaterial(elements, [&](auto && mat, auto && elements) {
       mat.packData(buffer, elements, tag);
     });
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer,
                                      const Array<Element> & elements,
                                      const SynchronizationTag & tag) {
   AKANTU_DEBUG_IN();
 
   switch (tag) {
   case _gst_material_id: {
     for (auto && element : elements) {
       UInt recv_mat_index;
       buffer >> recv_mat_index;
       UInt & mat_index = material_index(element);
       if (mat_index != UInt(-1))
         continue;
 
       // add ghosts element to the correct material
       mat_index = recv_mat_index;
       UInt index = materials[mat_index]->addElement(element);
       material_local_numbering(element) = index;
     }
     break;
   }
   case _gst_smm_mass: {
     unpackNodalDataHelper(*mass, buffer, elements, mesh);
     break;
   }
   case _gst_smm_for_gradu: {
     unpackNodalDataHelper(*displacement, buffer, elements, mesh);
     break;
   }
   case _gst_for_dump: {
     unpackNodalDataHelper(*displacement, buffer, elements, mesh);
     unpackNodalDataHelper(*velocity, buffer, elements, mesh);
     unpackNodalDataHelper(*acceleration, buffer, elements, mesh);
     unpackNodalDataHelper(*internal_force, buffer, elements, mesh);
     unpackNodalDataHelper(*external_force, buffer, elements, mesh);
     break;
   }
   case _gst_smm_boundary: {
     unpackNodalDataHelper(*external_force, buffer, elements, mesh);
     unpackNodalDataHelper(*velocity, buffer, elements, mesh);
     unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh);
     break;
   }
   default: {}
   }
 
   if (tag != _gst_material_id) {
     splitByMaterial(elements, [&](auto && mat, auto && elements) {
       mat.unpackData(buffer, elements, tag);
     });
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 UInt SolidMechanicsModel::getNbData(const Array<UInt> & dofs,
                                     const SynchronizationTag & tag) const {
   AKANTU_DEBUG_IN();
 
   UInt size = 0;
   //  UInt nb_nodes = mesh.getNbNodes();
 
   switch (tag) {
   case _gst_smm_uv: {
     size += sizeof(Real) * Model::spatial_dimension * 2;
     break;
   }
   case _gst_smm_res: {
     size += sizeof(Real) * Model::spatial_dimension;
     break;
   }
   case _gst_smm_mass: {
     size += sizeof(Real) * Model::spatial_dimension;
     break;
   }
   case _gst_for_dump: {
     size += sizeof(Real) * Model::spatial_dimension * 5;
     break;
   }
   default: {
     AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
   }
   }
 
   AKANTU_DEBUG_OUT();
   return size * dofs.size();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::packData(CommunicationBuffer & buffer,
                                    const Array<UInt> & dofs,
                                    const SynchronizationTag & tag) const {
   AKANTU_DEBUG_IN();
 
   switch (tag) {
   case _gst_smm_uv: {
     packDOFDataHelper(*displacement, buffer, dofs);
     packDOFDataHelper(*velocity, buffer, dofs);
     break;
   }
   case _gst_smm_res: {
     packDOFDataHelper(*internal_force, buffer, dofs);
     break;
   }
   case _gst_smm_mass: {
     packDOFDataHelper(*mass, buffer, dofs);
     break;
   }
   case _gst_for_dump: {
     packDOFDataHelper(*displacement, buffer, dofs);
     packDOFDataHelper(*velocity, buffer, dofs);
     packDOFDataHelper(*acceleration, buffer, dofs);
     packDOFDataHelper(*internal_force, buffer, dofs);
     packDOFDataHelper(*external_force, buffer, dofs);
     break;
   }
   default: {
     AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
   }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer,
                                      const Array<UInt> & dofs,
                                      const SynchronizationTag & tag) {
   AKANTU_DEBUG_IN();
 
   switch (tag) {
   case _gst_smm_uv: {
     unpackDOFDataHelper(*displacement, buffer, dofs);
     unpackDOFDataHelper(*velocity, buffer, dofs);
     break;
   }
   case _gst_smm_res: {
     unpackDOFDataHelper(*internal_force, buffer, dofs);
     break;
   }
   case _gst_smm_mass: {
     unpackDOFDataHelper(*mass, buffer, dofs);
     break;
   }
   case _gst_for_dump: {
     unpackDOFDataHelper(*displacement, buffer, dofs);
     unpackDOFDataHelper(*velocity, buffer, dofs);
     unpackDOFDataHelper(*acceleration, buffer, dofs);
     unpackDOFDataHelper(*internal_force, buffer, dofs);
     unpackDOFDataHelper(*external_force, buffer, dofs);
     break;
   }
   default: {
     AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
   }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 } // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh
index 368f5fbe1..f42929e96 100644
--- a/src/model/solid_mechanics/solid_mechanics_model.hh
+++ b/src/model/solid_mechanics/solid_mechanics_model.hh
@@ -1,556 +1,560 @@
 /**
  * @file   solid_mechanics_model.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Tue Jul 27 2010
  * @date last modification: Tue Jan 19 2016
  *
  * @brief  Model of Solid Mechanics
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "boundary_condition.hh"
 #include "data_accessor.hh"
 #include "fe_engine.hh"
 #include "model.hh"
 #include "non_local_manager.hh"
 #include "solid_mechanics_model_event_handler.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__
 #define __AKANTU_SOLID_MECHANICS_MODEL_HH__
 
 namespace akantu {
 class Material;
 class MaterialSelector;
 class DumperIOHelper;
 class NonLocalManager;
 template <ElementKind kind, class IntegrationOrderFunctor>
 class IntegratorGauss;
 template <ElementKind kind> class ShapeLagrange;
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 class SolidMechanicsModel
     : public Model,
       public DataAccessor<Element>,
       public DataAccessor<UInt>,
       public BoundaryCondition<SolidMechanicsModel>,
       public NonLocalManagerCallback,
       public EventHandlerManager<SolidMechanicsModelEventHandler> {
 
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   class NewMaterialElementsEvent : public NewElementsEvent {
   public:
     AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array<UInt> &);
     AKANTU_GET_MACRO(MaterialList, material, const Array<UInt> &);
 
   protected:
     Array<UInt> material;
   };
 
   using MyFEEngineType = FEEngineTemplate<IntegratorGauss, ShapeLagrange>;
 
 protected:
   using EventManager = EventHandlerManager<SolidMechanicsModelEventHandler>;
 
 public:
   SolidMechanicsModel(
       Mesh & mesh, UInt spatial_dimension = _all_dimensions,
       const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0,
       const ModelType model_type = ModelType::_solid_mechanics_model);
 
   ~SolidMechanicsModel() override;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 protected:
   /// initialize completely the model
   void initFullImpl(
       const ModelOptions & options = SolidMechanicsModelOptions()) override;
 
   /// initialize all internal arrays for materials
   virtual void initMaterials();
 
   /// initialize the model
   void initModel() override;
 
   /// function to print the containt of the class
   void printself(std::ostream & stream, int indent = 0) const override;
 
   /// get some default values for derived classes
   std::tuple<ID, TimeStepSolverType>
   getDefaultSolverID(const AnalysisMethod & method) override;
 
   /* ------------------------------------------------------------------------ */
   /* Solver interface                                                         */
   /* ------------------------------------------------------------------------ */
 public:
   /// assembles the stiffness matrix,
   virtual void assembleStiffnessMatrix();
   /// assembles the internal forces in the array internal_forces
   virtual void assembleInternalForces();
 
 protected:
   /// callback for the solver, this adds f_{ext} - f_{int} to the residual
   void assembleResidual() override;
 
+  /// callback for the solver, this adds f_{ext} or  f_{int} to the residual
+  void assembleResidual(const ID & residual_part) override;
+  bool canSplitResidual() override { return true; }
+
   /// get the type of matrix needed
   MatrixType getMatrixType(const ID & matrix_id) override;
 
   /// callback for the solver, this assembles different matrices
   void assembleMatrix(const ID & matrix_id) override;
 
   /// callback for the solver, this assembles the stiffness matrix
   void assembleLumpedMatrix(const ID & matrix_id) override;
 
   /// callback for the solver, this is called at beginning of solve
   void predictor() override;
   /// callback for the solver, this is called at end of solve
   void corrector() override;
 
   /// callback for the solver, this is called at beginning of solve
   void beforeSolveStep() override;
   /// callback for the solver, this is called at end of solve
   void afterSolveStep() override;
 
   /// Callback for the model to instantiate the matricees when needed
   void initSolver(TimeStepSolverType time_step_solver_type,
                   NonLinearSolverType non_linear_solver_type) override;
 
 protected:
   /* ------------------------------------------------------------------------ */
   TimeStepSolverType getDefaultSolverType() const override;
   /* ------------------------------------------------------------------------ */
   ModelSolverOptions
   getDefaultSolverOptions(const TimeStepSolverType & type) const override;
 
 public:
   bool isDefaultSolverExplicit() {
     return method == _explicit_lumped_mass ||
            method == _explicit_consistent_mass;
   }
 
 protected:
   /// update the current position vector
   void updateCurrentPosition();
 
   /* ------------------------------------------------------------------------ */
   /* Materials (solid_mechanics_model_material.cc)                            */
   /* ------------------------------------------------------------------------ */
 public:
   /// register an empty material of a given type
   Material & registerNewMaterial(const ID & mat_name, const ID & mat_type,
                                  const ID & opt_param);
 
   /// reassigns materials depending on the material selector
   virtual void reassignMaterial();
 
   /// apply a constant eigen_grad_u on all quadrature points of a given material
   virtual void applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u,
                                const ID & material_name,
                                const GhostType ghost_type = _not_ghost);
 
 protected:
   /// register a material in the dynamic database
   Material & registerNewMaterial(const ParserSection & mat_section);
 
   /// read the material files to instantiate all the materials
   void instantiateMaterials();
 
   /// set the element_id_by_material and add the elements to the good materials
   virtual void
   assignMaterialToElements(const ElementTypeMapArray<UInt> * filter = nullptr);
 
   /* ------------------------------------------------------------------------ */
   /* Mass (solid_mechanics_model_mass.cc)                                     */
   /* ------------------------------------------------------------------------ */
 public:
   /// assemble the lumped mass matrix
   void assembleMassLumped();
 
   /// assemble the mass matrix for consistent mass resolutions
   void assembleMass();
 
 protected:
   /// assemble the lumped mass matrix for local and ghost elements
   void assembleMassLumped(GhostType ghost_type);
 
   /// assemble the mass matrix for either _ghost or _not_ghost elements
   void assembleMass(GhostType ghost_type);
 
   /// fill a vector of rho
   void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type);
 
   /// compute the kinetic energy
   Real getKineticEnergy();
   Real getKineticEnergy(const ElementType & type, UInt index);
 
   /// compute the external work (for impose displacement, the velocity should be
   /// given too)
   Real getExternalWork();
 
   /* ------------------------------------------------------------------------ */
   /* NonLocalManager inherited members                                        */
   /* ------------------------------------------------------------------------ */
 protected:
   void initializeNonLocal() override;
 
   void updateDataForNonLocalCriterion(ElementTypeMapReal & criterion) override;
 
   void computeNonLocalStresses(const GhostType & ghost_type) override;
 
   void
   insertIntegrationPointsInNeighborhoods(const GhostType & ghost_type) override;
 
   /// update the values of the non local internal
   void updateLocalInternal(ElementTypeMapReal & internal_flat,
                            const GhostType & ghost_type,
                            const ElementKind & kind) override;
 
   /// copy the results of the averaging in the materials
   void updateNonLocalInternal(ElementTypeMapReal & internal_flat,
                               const GhostType & ghost_type,
                               const ElementKind & kind) override;
 
   /* ------------------------------------------------------------------------ */
   /* Data Accessor inherited members                                          */
   /* ------------------------------------------------------------------------ */
 public:
   UInt getNbData(const Array<Element> & elements,
                  const SynchronizationTag & tag) const override;
 
   void packData(CommunicationBuffer & buffer, const Array<Element> & elements,
                 const SynchronizationTag & tag) const override;
 
   void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements,
                   const SynchronizationTag & tag) override;
 
   UInt getNbData(const Array<UInt> & dofs,
                  const SynchronizationTag & tag) const override;
 
   void packData(CommunicationBuffer & buffer, const Array<UInt> & dofs,
                 const SynchronizationTag & tag) const override;
 
   void unpackData(CommunicationBuffer & buffer, const Array<UInt> & dofs,
                   const SynchronizationTag & tag) override;
 
 protected:
   void
   splitElementByMaterial(const Array<Element> & elements,
                          std::vector<Array<Element>> & elements_per_mat) const;
 
   template <typename Operation>
   void splitByMaterial(const Array<Element> & elements, Operation && op) const;
 
   /* ------------------------------------------------------------------------ */
   /* Mesh Event Handler inherited members                                     */
   /* ------------------------------------------------------------------------ */
 protected:
   void onNodesAdded(const Array<UInt> & nodes_list,
                     const NewNodesEvent & event) override;
   void onNodesRemoved(const Array<UInt> & element_list,
                       const Array<UInt> & new_numbering,
                       const RemovedNodesEvent & event) override;
   void onElementsAdded(const Array<Element> & nodes_list,
                        const NewElementsEvent & event) override;
   void onElementsRemoved(const Array<Element> & element_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const RemovedElementsEvent & event) override;
   void onElementsChanged(const Array<Element> &, const Array<Element> &,
                          const ElementTypeMapArray<UInt> &,
                          const ChangedElementsEvent &) override{};
 
   /* ------------------------------------------------------------------------ */
   /* Dumpable interface (kept for convenience) and dumper relative functions  */
   /* ------------------------------------------------------------------------ */
 public:
   virtual void onDump();
 
   //! decide wether a field is a material internal or not
   bool isInternal(const std::string & field_name,
                   const ElementKind & element_kind);
 #ifndef SWIG
   //! give the amount of data per element
   virtual ElementTypeMap<UInt>
   getInternalDataPerElem(const std::string & field_name,
                          const ElementKind & kind);
 
   //! flatten a given material internal field
   ElementTypeMapArray<Real> &
   flattenInternal(const std::string & field_name, const ElementKind & kind,
                   const GhostType ghost_type = _not_ghost);
   //! flatten all the registered material internals
   void flattenAllRegisteredInternals(const ElementKind & kind);
 #endif
 
   dumper::Field * createNodalFieldReal(const std::string & field_name,
                                        const std::string & group_name,
                                        bool padding_flag) override;
 
   dumper::Field * createNodalFieldBool(const std::string & field_name,
                                        const std::string & group_name,
                                        bool padding_flag) override;
 
   dumper::Field * createElementalField(const std::string & field_name,
                                        const std::string & group_name,
                                        bool padding_flag,
                                        const UInt & spatial_dimension,
                                        const ElementKind & kind) override;
 
   virtual void dump(const std::string & dumper_name);
 
   virtual void dump(const std::string & dumper_name, UInt step);
 
   virtual void dump(const std::string & dumper_name, Real time, UInt step);
 
   void dump() override;
 
   virtual void dump(UInt step);
 
   virtual void dump(Real time, UInt step);
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// return the dimension of the system space
   AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt);
 
   /// set the value of the time step
   void setTimeStep(Real time_step, const ID & solver_id = "") override;
 
   /// get the value of the conversion from forces/ mass to acceleration
   AKANTU_GET_MACRO(F_M2A, f_m2a, Real);
 
   /// set the value of the conversion from forces/ mass to acceleration
   AKANTU_SET_MACRO(F_M2A, f_m2a, Real);
 
   /// get the SolidMechanicsModel::displacement vector
   AKANTU_GET_MACRO(Displacement, *displacement, Array<Real> &);
 
   /// get the SolidMechanicsModel::previous_displacement vector
   AKANTU_GET_MACRO(PreviousDisplacement, *previous_displacement, Array<Real> &);
 
   /// get the SolidMechanicsModel::current_position vector \warn only consistent
   /// after a call to SolidMechanicsModel::updateCurrentPosition
   const Array<Real> & getCurrentPosition();
 
   /// get  the SolidMechanicsModel::increment  vector \warn  only  consistent if
   /// SolidMechanicsModel::setIncrementFlagOn has been called before
   AKANTU_GET_MACRO(Increment, *displacement_increment, Array<Real> &);
 
   /// get the lumped SolidMechanicsModel::mass vector
   AKANTU_GET_MACRO(Mass, *mass, Array<Real> &);
 
   /// get the SolidMechanicsModel::velocity vector
   AKANTU_GET_MACRO(Velocity, *velocity, Array<Real> &);
 
   /// get    the    SolidMechanicsModel::acceleration    vector,   updated    by
   /// SolidMechanicsModel::updateAcceleration
   AKANTU_GET_MACRO(Acceleration, *acceleration, Array<Real> &);
 
   /// get the SolidMechanicsModel::force vector (external forces)
   AKANTU_GET_MACRO(Force, *external_force, Array<Real> &);
 
   /// get the SolidMechanicsModel::internal_force vector (internal forces)
   AKANTU_GET_MACRO(InternalForce, *internal_force, Array<Real> &);
 
   /// get the SolidMechanicsModel::blocked_dofs vector
   AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &);
 
   /// get the value of the SolidMechanicsModel::increment_flag
   AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool);
 
   /// get a particular material (by material index)
   inline Material & getMaterial(UInt mat_index);
 
   /// get a particular material (by material index)
   inline const Material & getMaterial(UInt mat_index) const;
 
   /// get a particular material (by material name)
   inline Material & getMaterial(const std::string & name);
 
   /// get a particular material (by material name)
   inline const Material & getMaterial(const std::string & name) const;
 
   /// get a particular material id from is name
   inline UInt getMaterialIndex(const std::string & name) const;
 
   /// give the number of materials
   inline UInt getNbMaterials() const { return materials.size(); }
 
   /// give the material internal index from its id
   Int getInternalIndexFromID(const ID & id) const;
 
   /// compute the stable time step
   Real getStableTimeStep();
 
   /// get the energies
   Real getEnergy(const std::string & energy_id);
 
   /// compute the energy for energy
   Real getEnergy(const std::string & energy_id, const ElementType & type,
                  UInt index);
 
   AKANTU_GET_MACRO(MaterialByElement, material_index,
                    const ElementTypeMapArray<UInt> &);
 
   /// vectors containing local material element index for each global element
   /// index
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialByElement, material_index,
                                          UInt);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialByElement, material_index, UInt);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialLocalNumbering,
                                          material_local_numbering, UInt);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialLocalNumbering,
                                    material_local_numbering, UInt);
 
   AKANTU_GET_MACRO_NOT_CONST(MaterialSelector, *material_selector,
                              MaterialSelector &);
   AKANTU_SET_MACRO(MaterialSelector, material_selector,
                    std::shared_ptr<MaterialSelector>);
 
   /// Access the non_local_manager interface
   AKANTU_GET_MACRO(NonLocalManager, *non_local_manager, NonLocalManager &);
 
   /// get the FEEngine object to integrate or interpolate on the boundary
   FEEngine & getFEEngineBoundary(const ID & name = "") override;
 
 protected:
   friend class Material;
 
 protected:
 
   /// compute the stable time step
   Real getStableTimeStep(const GhostType & ghost_type);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// conversion coefficient form force/mass to acceleration
   Real f_m2a;
 
   /// displacements array
   Array<Real> * displacement;
   UInt displacement_release{0};
 
   /// displacements array at the previous time step (used in finite deformation)
   Array<Real> * previous_displacement{nullptr};
 
   /// increment of displacement
   Array<Real> * displacement_increment{nullptr};
 
   /// lumped mass array
   Array<Real> * mass{nullptr};
 
   /// Check if materials need to recompute the mass array
   bool need_to_reassemble_lumped_mass{true};
   /// Check if materials need to recompute the mass matrix
   bool need_to_reassemble_mass{true};
 
   /// velocities array
   Array<Real> * velocity{nullptr};
 
   /// accelerations array
   Array<Real> * acceleration{nullptr};
 
   /// accelerations array
   // Array<Real> * increment_acceleration;
 
   /// external forces array
   Array<Real> * external_force{nullptr};
 
   /// internal forces array
   Array<Real> * internal_force{nullptr};
 
   /// array specifing if a degree of freedom is blocked or not
   Array<bool> * blocked_dofs{nullptr};
 
   /// array of current position used during update residual
   Array<Real> * current_position{nullptr};
   UInt current_position_release{0};
 
   /// Arrays containing the material index for each element
   ElementTypeMapArray<UInt> material_index;
 
   /// Arrays containing the position in the element filter of the material
   /// (material's local numbering)
   ElementTypeMapArray<UInt> material_local_numbering;
 
   /// list of used materials
   std::vector<std::unique_ptr<Material>> materials;
 
   /// mapping between material name and material internal id
   std::map<std::string, UInt> materials_names_to_id;
 
   /// class defining of to choose a material
   std::shared_ptr<MaterialSelector> material_selector;
 
   /// flag defining if the increment must be computed or not
   bool increment_flag;
 
   /// tells if the material are instantiated
   bool are_materials_instantiated;
 
   using flatten_internal_map = std::map<std::pair<std::string, ElementKind>,
                                         ElementTypeMapArray<Real> *>;
 
   /// map a registered internals to be flattened for dump purposes
   flatten_internal_map registered_internals;
 
   /// non local manager
   std::unique_ptr<NonLocalManager> non_local_manager;
 };
 
 /* -------------------------------------------------------------------------- */
 namespace BC {
   namespace Neumann {
     using FromStress = FromHigherDim;
     using FromTraction = FromSameDim;
   } // namespace Neumann
 } // namespace BC
 
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 #include "material.hh"
 #include "parser.hh"
 
 #include "solid_mechanics_model_inline_impl.cc"
 #include "solid_mechanics_model_tmpl.hh"
 /* -------------------------------------------------------------------------- */
 
 #endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */
diff --git a/src/model/solver_callback.hh b/src/model/solver_callback.hh
index 9ab943c99..f986d9908 100644
--- a/src/model/solver_callback.hh
+++ b/src/model/solver_callback.hh
@@ -1,92 +1,108 @@
 /**
  * @file   solver_callback.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Tue Sep 15 22:45:27 2015
  *
  * @brief  Class defining the interface for non_linear_solver callbacks
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SOLVER_CALLBACK_HH__
 #define __AKANTU_SOLVER_CALLBACK_HH__
 
 namespace akantu {
 class DOFManager;
 }
 
 namespace akantu {
 
 class SolverCallback {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   explicit SolverCallback(DOFManager & dof_manager);
   explicit SolverCallback();
   /* ------------------------------------------------------------------------ */
   virtual ~SolverCallback();
 
 protected:
   void setDOFManager(DOFManager & dof_manager);
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the type of matrix needed
   virtual MatrixType getMatrixType(const ID &) = 0;
 
   /// callback to assemble a Matrix
   virtual void assembleMatrix(const ID &) = 0;
 
   /// callback to assemble a lumped Matrix
   virtual void assembleLumpedMatrix(const ID &) = 0;
 
   /// callback to assemble the residual (rhs)
   virtual void assembleResidual() = 0;
 
+  /// callback to assemble the rhs parts, (e.g. internal_forces +
+  /// external_forces)
+  virtual void assembleResidual(const ID & /*residual_part*/) {}
+
   /* ------------------------------------------------------------------------ */
   /* Dynamic simulations part                                                 */
   /* ------------------------------------------------------------------------ */
   /// callback for the predictor (in case of dynamic simulation)
-  virtual void predictor() { }
+  virtual void predictor() {}
 
   /// callback for the corrector (in case of dynamic simulation)
-  virtual void corrector() { }
+  virtual void corrector() {}
+
+  /// tells if the residual can be computed in separated parts
+  virtual bool canSplitResidual() { return false; }
 
   /* ------------------------------------------------------------------------ */
   /* management callbacks                                                     */
   /* ------------------------------------------------------------------------ */
-  virtual void beforeSolveStep() { };
-  virtual void afterSolveStep() { };
+  virtual void beforeSolveStep(){};
+  virtual void afterSolveStep(){};
+
 protected:
   /// DOFManager prefixed to avoid collision in multiple inheritance cases
   DOFManager * sc_dof_manager{nullptr};
 };
 
+namespace debug {
+  class SolverCallbackResidualPartUnknown : public Exception {
+  public:
+    SolverCallbackResidualPartUnknown(const ID & residual_part)
+        : Exception(residual_part + " is not known here.") {}
+  };
+}
+
 } // namespace akantu
 
 #endif /* __AKANTU_SOLVER_CALLBACK_HH__ */
diff --git a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh
index e84fb3017..885a0a1a5 100644
--- a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh
+++ b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh
@@ -1,75 +1,76 @@
 /**
  * @file   structural_element_bernoulli_kirchhoff_shell.hh
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation  Tue Sep 19 2017
  *
  * @brief Specific functions for bernoulli kirchhoff shell
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #ifndef __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__
 #define __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__
 
 #include "structural_mechanics_model.hh"
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 StructuralMechanicsModel::assembleMass<_discrete_kirchhoff_triangle_18>() {
   AKANTU_TO_IMPLEMENT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void StructuralMechanicsModel::computeTangentModuli<
     _discrete_kirchhoff_triangle_18>(Array<Real> & tangent_moduli) {
 
   auto tangent_size =
     ElementClass<_discrete_kirchhoff_triangle_18>::getNbStressComponents();
   auto nb_quad =
       getFEEngine().getNbIntegrationPoints(_discrete_kirchhoff_triangle_18);
 
   auto H_it = tangent_moduli.begin(tangent_size, tangent_size);
 
   for (UInt mat :
        element_material(_discrete_kirchhoff_triangle_18, _not_ghost)) {
     auto & m = materials[mat];
 
     for (UInt q = 0; q < nb_quad; ++q, ++H_it) {
       auto & H = *H_it;
+      H.clear();
       Matrix<Real> D = {{1, m.nu, 0}, {m.nu, 1, 0}, {0, 0, (1 - m.nu) / 2}};
-      D *= m.E / (1 - m.nu * m.nu);
-      H.block(0, 0, 3, 3) = D; // in plane membrane behavior
-      H.block(3, 3, 3, 3) = D * Math::pow<3>(m.t) / 12.; // bending behavior
+      D *= m.E * m.t / (1 - m.nu * m.nu);
+      H.block(D, 0, 0);                           // in plane membrane behavior
+      H.block(D * Math::pow<3>(m.t) / 12., 3, 3); // bending behavior
     }
   }
 }
 
 }  // akantu
 
 #endif /* __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_DISCRETE_KIRCHHOFF_TRIANGLE_18_HH__ */
diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc
index 9a29752cb..d093d45c6 100644
--- a/src/model/structural_mechanics/structural_mechanics_model.cc
+++ b/src/model/structural_mechanics/structural_mechanics_model.cc
@@ -1,442 +1,489 @@
 /**
  * @file   structural_mechanics_model.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Model implementation for StucturalMechanics elements
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "structural_mechanics_model.hh"
 #include "dof_manager.hh"
 #include "integrator_gauss.hh"
 #include "mesh.hh"
 #include "shape_structural.hh"
 #include "sparse_matrix.hh"
+#include "time_step_solver.hh"
 /* -------------------------------------------------------------------------- */
 #ifdef AKANTU_USE_IOHELPER
 #include "dumpable_inline_impl.hh"
 #include "dumper_elemental_field.hh"
 #include "dumper_iohelper_paraview.hh"
 #include "group_manager_inline_impl.cc"
 #endif
 /* -------------------------------------------------------------------------- */
 #include "structural_mechanics_model_inline_impl.cc"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 StructuralMechanicsModel::StructuralMechanicsModel(Mesh & mesh, UInt dim,
                                                    const ID & id,
                                                    const MemoryID & memory_id)
     : Model(mesh, ModelType::_structural_mechanics_model, dim, id, memory_id),
       time_step(NAN), f_m2a(1.0), stress("stress", id, memory_id),
       element_material("element_material", id, memory_id),
       set_ID("beam sets", id, memory_id),
       rotation_matrix("rotation_matices", id, memory_id) {
   AKANTU_DEBUG_IN();
 
   registerFEEngineObject<MyFEEngineType>("StructuralMechanicsFEEngine", mesh,
                                          spatial_dimension);
 
   if (spatial_dimension == 2)
     nb_degree_of_freedom = 3;
   else if (spatial_dimension == 3)
     nb_degree_of_freedom = 6;
   else {
     AKANTU_TO_IMPLEMENT();
   }
 
 #ifdef AKANTU_USE_IOHELPER
   this->mesh.registerDumper<DumperParaview>("paraview_all", id, true);
 #endif
   this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_structural);
 
   this->initDOFManager();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 StructuralMechanicsModel::~StructuralMechanicsModel() = default;
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::initFullImpl(const ModelOptions & options) {
   // <<<< This is the SolidMechanicsModel implementation for future ref >>>>
   // material_index.initialize(mesh, _element_kind = _ek_not_defined,
   //                           _default_value = UInt(-1), _with_nb_element =
   //                           true);
   // material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined,
   //                                     _with_nb_element = true);
 
   // Model::initFullImpl(options);
 
   // // initialize pbc
   // if (this->pbc_pair.size() != 0)
   //   this->initPBC();
 
   // // initialize the materials
   // if (this->parser.getLastParsedFile() != "") {
   //   this->instantiateMaterials();
   // }
 
   // this->initMaterials();
   // this->initBC(*this, *displacement, *displacement_increment,
   // *external_force);
 
   // <<<< END >>>>
 
   Model::initFullImpl(options);
+
+  // Initializing stresses
+  ElementTypeMap<UInt> stress_components;
+
+  /// TODO this is ugly af, maybe add a function to FEEngine
+  for (auto & type : mesh.elementTypes(_spatial_dimension = _all_dimensions,
+				       _element_kind = _ek_structural)) {
+    UInt nb_components = 0;
+
+    // Getting number of components for each element type
+#define GET_(type) nb_components = ElementClass<type>::getNbStressComponents()
+    AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(GET_);
+#undef GET_
+
+    stress_components(nb_components, type);
+  }
+
+  stress.initialize(getFEEngine(), _spatial_dimension = _all_dimensions,
+                    _element_kind = _ek_structural,
+		    _all_ghost_types = true,
+                    _nb_component = [&stress_components](
+                        const ElementType & type, const GhostType &) -> UInt {
+                      return stress_components(type);
+                    });
 }
 
 /* -------------------------------------------------------------------------- */
 
 void StructuralMechanicsModel::initFEEngineBoundary() {
   /// TODO: this function should not be reimplemented
   /// we're just avoiding a call to Model::initFEEngineBoundary()
 }
 
 /* -------------------------------------------------------------------------- */
 // void StructuralMechanicsModel::setTimeStep(Real time_step) {
 //   this->time_step = time_step;
 
 // #if defined(AKANTU_USE_IOHELPER)
 //   this->mesh.getDumper().setTimeStep(time_step);
 // #endif
 // }
 
 /* -------------------------------------------------------------------------- */
 /* Initialisation                                                             */
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::initSolver(
     TimeStepSolverType time_step_solver_type, NonLinearSolverType) {
   AKANTU_DEBUG_IN();
 
   this->allocNodalField(displacement_rotation, nb_degree_of_freedom,
                         "displacement");
-  this->allocNodalField(external_force_momentum, nb_degree_of_freedom,
+  this->allocNodalField(external_force, nb_degree_of_freedom,
                         "external_force");
-  this->allocNodalField(internal_force_momentum, nb_degree_of_freedom,
+  this->allocNodalField(internal_force, nb_degree_of_freedom,
                         "internal_force");
   this->allocNodalField(blocked_dofs, nb_degree_of_freedom, "blocked_dofs");
 
   auto & dof_manager = this->getDOFManager();
 
   if (!dof_manager.hasDOFs("displacement")) {
     dof_manager.registerDOFs("displacement", *displacement_rotation,
                              _dst_nodal);
     dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs);
   }
 
   if (time_step_solver_type == _tsst_dynamic ||
       time_step_solver_type == _tsst_dynamic_lumped) {
     this->allocNodalField(velocity, spatial_dimension, "velocity");
     this->allocNodalField(acceleration, spatial_dimension, "acceleration");
 
     if (!dof_manager.hasDOFsDerivatives("displacement", 1)) {
       dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity);
       dof_manager.registerDOFsDerivative("displacement", 2,
                                          *this->acceleration);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::initModel() {
   for (auto && type : mesh.elementTypes(_element_kind = _ek_structural)) {
     // computeRotationMatrix(type);
     element_material.alloc(mesh.getNbElement(type), 1, type);
   }
 
   getFEEngine().initShapeFunctions(_not_ghost);
   getFEEngine().initShapeFunctions(_ghost);
 }
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::assembleStiffnessMatrix() {
   AKANTU_DEBUG_IN();
 
   getDOFManager().getMatrix("K").clear();
 
   for (auto & type :
        mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) {
 #define ASSEMBLE_STIFFNESS_MATRIX(type) assembleStiffnessMatrix<type>();
 
     AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(ASSEMBLE_STIFFNESS_MATRIX);
 #undef ASSEMBLE_STIFFNESS_MATRIX
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::computeStresses() {
   AKANTU_DEBUG_IN();
 
   for (auto & type :
        mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) {
 #define COMPUTE_STRESS_ON_QUAD(type) computeStressOnQuad<type>();
 
     AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_STRESS_ON_QUAD);
 #undef COMPUTE_STRESS_ON_QUAD
   }
 
   AKANTU_DEBUG_OUT();
 }
 
-/* -------------------------------------------------------------------------- */
-void StructuralMechanicsModel::updateResidual() {
-  AKANTU_DEBUG_IN();
-
-  auto & K = getDOFManager().getMatrix("K");
-
-  internal_force_momentum->clear();
-  K.matVecMul(*displacement_rotation, *internal_force_momentum);
-  *internal_force_momentum *= -1.;
-
-  getDOFManager().assembleToResidual("displacement", *external_force_momentum,
-                                     1.);
-
-  getDOFManager().assembleToResidual("displacement", *internal_force_momentum,
-                                     1.);
-
-  AKANTU_DEBUG_OUT();
-}
-
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::computeRotationMatrix(const ElementType & type) {
   Mesh & mesh = getFEEngine().getMesh();
 
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_element = mesh.getNbElement(type);
 
   if (!rotation_matrix.exists(type)) {
     rotation_matrix.alloc(nb_element,
                           nb_degree_of_freedom * nb_nodes_per_element *
                               nb_degree_of_freedom * nb_nodes_per_element,
                           type);
   } else {
     rotation_matrix(type).resize(nb_element);
   }
   rotation_matrix(type).clear();
 
   Array<Real> rotations(nb_element,
                         nb_degree_of_freedom * nb_degree_of_freedom);
   rotations.clear();
 
 #define COMPUTE_ROTATION_MATRIX(type) computeRotationMatrix<type>(rotations);
 
   AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_ROTATION_MATRIX);
 #undef COMPUTE_ROTATION_MATRIX
 
   auto R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom);
   auto T_it =
       rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element,
                                   nb_degree_of_freedom * nb_nodes_per_element);
 
   for (UInt el = 0; el < nb_element; ++el, ++R_it, ++T_it) {
     auto & T = *T_it;
     auto & R = *R_it;
     for (UInt k = 0; k < nb_nodes_per_element; ++k) {
       for (UInt i = 0; i < nb_degree_of_freedom; ++i)
         for (UInt j = 0; j < nb_degree_of_freedom; ++j)
           T(k * nb_degree_of_freedom + i, k * nb_degree_of_freedom + j) =
               R(i, j);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 dumper::Field * StructuralMechanicsModel::createNodalFieldBool(
     const std::string & field_name, const std::string & group_name,
     __attribute__((unused)) bool padding_flag) {
 
   std::map<std::string, Array<bool> *> uint_nodal_fields;
   uint_nodal_fields["blocked_dofs"] = blocked_dofs;
 
   dumper::Field * field = NULL;
   field = mesh.createNodalField(uint_nodal_fields[field_name], group_name);
   return field;
 }
 
 /* -------------------------------------------------------------------------- */
 dumper::Field *
 StructuralMechanicsModel::createNodalFieldReal(const std::string & field_name,
                                                const std::string & group_name,
                                                bool padding_flag) {
 
   UInt n;
   if (spatial_dimension == 2) {
     n = 2;
   } else {
     n = 3;
   }
 
   if (field_name == "displacement") {
     return mesh.createStridedNodalField(displacement_rotation, group_name, n, 0,
                                         padding_flag);
   }
 
   if (field_name == "rotation") {
     return mesh.createStridedNodalField(displacement_rotation, group_name,
                                         nb_degree_of_freedom - n, n,
                                         padding_flag);
   }
 
   if (field_name == "force") {
-    return mesh.createStridedNodalField(external_force_momentum, group_name, n,
+    return mesh.createStridedNodalField(external_force, group_name, n,
                                         0, padding_flag);
   }
 
   if (field_name == "momentum") {
-    return mesh.createStridedNodalField(external_force_momentum, group_name,
+    return mesh.createStridedNodalField(external_force, group_name,
                                         nb_degree_of_freedom - n, n,
                                         padding_flag);
   }
 
   if (field_name == "internal_force") {
-    return mesh.createStridedNodalField(internal_force_momentum, group_name, n,
+    return mesh.createStridedNodalField(internal_force, group_name, n,
                                         0, padding_flag);
   }
 
   if (field_name == "internal_momentum") {
-    return mesh.createStridedNodalField(internal_force_momentum, group_name,
+    return mesh.createStridedNodalField(internal_force, group_name,
                                         nb_degree_of_freedom - n, n,
                                         padding_flag);
   }
 
   return nullptr;
 }
 
 /* -------------------------------------------------------------------------- */
 dumper::Field * StructuralMechanicsModel::createElementalField(
     const std::string & field_name, const std::string & group_name, bool,
     const ElementKind & kind, const std::string &) {
 
   dumper::Field * field = NULL;
 
   if (field_name == "element_index_by_material")
     field = mesh.createElementalField<UInt, Vector, dumper::ElementalField>(
         field_name, group_name, this->spatial_dimension, kind);
 
   return field;
 }
 
 /* -------------------------------------------------------------------------- */
 /* Virtual methods from SolverCallback */
 /* -------------------------------------------------------------------------- */
 /// get the type of matrix needed
 MatrixType StructuralMechanicsModel::getMatrixType(const ID & /*id*/) {
   return _symmetric;
 }
 
 /// callback to assemble a Matrix
 void StructuralMechanicsModel::assembleMatrix(const ID & id) {
   if (id == "K")
     assembleStiffnessMatrix();
 }
 
 /// callback to assemble a lumped Matrix
 void StructuralMechanicsModel::assembleLumpedMatrix(const ID & /*id*/) {}
 
 /// callback to assemble the residual StructuralMechanicsModel::(rhs)
 void StructuralMechanicsModel::assembleResidual() {
-  this->getDOFManager().assembleToResidual("displacement",
-                                           *this->external_force_momentum, 1);
+  AKANTU_DEBUG_IN();
+
+  auto & dof_manager = getDOFManager();
+
+  internal_force->clear();
+  computeStresses();
+  assembleInternalForce();
+  dof_manager.assembleToResidual("displacement", *internal_force, -1);
+  dof_manager.assembleToResidual("displacement", *external_force, 1);
+
+  AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /* Virtual methods from MeshEventHandler */
 /* -------------------------------------------------------------------------- */
 
 /// function to implement to react on  akantu::NewNodesEvent
 void StructuralMechanicsModel::onNodesAdded(const Array<UInt> & /*nodes_list*/,
                                             const NewNodesEvent & /*event*/) {}
 /// function to implement to react on  akantu::RemovedNodesEvent
 void StructuralMechanicsModel::onNodesRemoved(
     const Array<UInt> & /*nodes_list*/, const Array<UInt> & /*new_numbering*/,
     const RemovedNodesEvent & /*event*/) {}
 /// function to implement to react on  akantu::NewElementsEvent
 void StructuralMechanicsModel::onElementsAdded(
     const Array<Element> & /*elements_list*/,
     const NewElementsEvent & /*event*/) {}
 /// function to implement to react on  akantu::RemovedElementsEvent
 void StructuralMechanicsModel::onElementsRemoved(
     const Array<Element> & /*elements_list*/,
     const ElementTypeMapArray<UInt> & /*new_numbering*/,
     const RemovedElementsEvent & /*event*/) {}
 /// function to implement to react on  akantu::ChangedElementsEvent
 void StructuralMechanicsModel::onElementsChanged(
     const Array<Element> & /*old_elements_list*/,
     const Array<Element> & /*new_elements_list*/,
     const ElementTypeMapArray<UInt> & /*new_numbering*/,
     const ChangedElementsEvent & /*event*/) {}
 
 /* -------------------------------------------------------------------------- */
 /* Virtual methods from Model */
 /* -------------------------------------------------------------------------- */
 /// get some default values for derived classes
 std::tuple<ID, TimeStepSolverType>
 StructuralMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) {
   switch (method) {
   case _static: {
     return std::make_tuple("static", _tsst_static);
   }
   case _implicit_dynamic: {
     return std::make_tuple("implicit", _tsst_dynamic);
   }
   default:
     return std::make_tuple("unknown", _tsst_not_defined);
   }
 }
 
 /* ------------------------------------------------------------------------ */
 ModelSolverOptions StructuralMechanicsModel::getDefaultSolverOptions(
     const TimeStepSolverType & type) const {
   ModelSolverOptions options;
 
   switch (type) {
   case _tsst_static: {
     options.non_linear_solver_type = _nls_linear;
     options.integration_scheme_type["displacement"] = _ist_pseudo_time;
     options.solution_type["displacement"] = IntegrationScheme::_not_defined;
     break;
   }
   default:
     AKANTU_EXCEPTION(type << " is not a valid time step solver type");
   }
 
   return options;
 }
+
+/* -------------------------------------------------------------------------- */
+void StructuralMechanicsModel::assembleInternalForce() {
+  for (auto type : mesh.elementTypes(_spatial_dimension = _all_dimensions,
+				     _element_kind = _ek_structural)) {
+    assembleInternalForce(type, _not_ghost);
+    // assembleInternalForce(type, _ghost);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+void StructuralMechanicsModel::assembleInternalForce(const ElementType & type,
+                                                     GhostType gt) {
+  auto & fem = getFEEngine();
+  auto & sigma = stress(type, gt);
+  auto ndof = getNbDegreeOfFreedom(type);
+  auto nb_nodes = mesh.getNbNodesPerElement(type);
+  auto ndof_per_elem = ndof * nb_nodes;
+
+  Array<Real> BtSigma(fem.getNbIntegrationPoints(type) *
+                          mesh.getNbElement(type),
+                      ndof_per_elem, "BtSigma");
+  fem.computeBtD(sigma, BtSigma, type, gt);
+
+  Array<Real> intBtSigma(0, ndof_per_elem,
+                         "intBtSigma");
+  fem.integrate(BtSigma, intBtSigma, ndof_per_elem, type, gt);
+  BtSigma.resize(0);
+
+  getDOFManager().assembleElementalArrayLocalArray(intBtSigma, *internal_force,
+                                                   type, gt, 1);
+}
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/model/structural_mechanics/structural_mechanics_model.hh b/src/model/structural_mechanics/structural_mechanics_model.hh
index fcb036768..b06e1ea41 100644
--- a/src/model/structural_mechanics/structural_mechanics_model.hh
+++ b/src/model/structural_mechanics/structural_mechanics_model.hh
@@ -1,327 +1,333 @@
 /**
  * @file   structural_mechanics_model.hh
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Thu Jan 21 2016
  *
  * @brief  Particular implementation of the structural elements in the
  * StructuralMechanicsModel
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "aka_named_argument.hh"
 #include "boundary_condition.hh"
 #include "model.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__
 #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 class Material;
 class MaterialSelector;
 class DumperIOHelper;
 class NonLocalManager;
 template <ElementKind kind, class IntegrationOrderFunctor>
 class IntegratorGauss;
 template <ElementKind kind> class ShapeStructural;
 } // namespace akantu
 
 namespace akantu {
 
 struct StructuralMaterial {
   Real E{0};
   Real A{1};
   Real I{0};
   Real Iz{0};
   Real Iy{0};
   Real GJ{0};
   Real rho{0};
   Real t{0};
   Real nu{0};
 };
 
 class StructuralMechanicsModel : public Model {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   using MyFEEngineType =
       FEEngineTemplate<IntegratorGauss, ShapeStructural, _ek_structural>;
 
   StructuralMechanicsModel(Mesh & mesh,
                            UInt spatial_dimension = _all_dimensions,
                            const ID & id = "structural_mechanics_model",
                            const MemoryID & memory_id = 0);
 
   virtual ~StructuralMechanicsModel();
 
   /// Init full model
   void initFullImpl(const ModelOptions & options) override;
 
   /// Init boundary FEEngine
   void initFEEngineBoundary() override;
 
 
   /* ------------------------------------------------------------------------ */
   /* Virtual methods from SolverCallback */
   /* ------------------------------------------------------------------------ */
   /// get the type of matrix needed
   MatrixType getMatrixType(const ID &) override;
 
   /// callback to assemble a Matrix
   void assembleMatrix(const ID &) override;
 
   /// callback to assemble a lumped Matrix
   void assembleLumpedMatrix(const ID &) override;
 
   /// callback to assemble the residual (rhs)
   void assembleResidual() override;
 
   /* ------------------------------------------------------------------------ */
   /* Virtual methods from MeshEventHandler */
   /* ------------------------------------------------------------------------ */
 
   /// function to implement to react on  akantu::NewNodesEvent
   void onNodesAdded(const Array<UInt> & nodes_list,
                     const NewNodesEvent & event) override;
   /// function to implement to react on  akantu::RemovedNodesEvent
   void onNodesRemoved(const Array<UInt> & nodes_list,
                       const Array<UInt> & new_numbering,
                       const RemovedNodesEvent & event) override;
   /// function to implement to react on  akantu::NewElementsEvent
   void onElementsAdded(const Array<Element> & elements_list,
                        const NewElementsEvent & event) override;
   /// function to implement to react on  akantu::RemovedElementsEvent
   void onElementsRemoved(const Array<Element> & elements_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const RemovedElementsEvent & event) override;
   /// function to implement to react on  akantu::ChangedElementsEvent
   void onElementsChanged(const Array<Element> & old_elements_list,
                          const Array<Element> & new_elements_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const ChangedElementsEvent & event) override;
 
   /* ------------------------------------------------------------------------ */
   /* Virtual methods from Model */
   /* ------------------------------------------------------------------------ */
 protected:
   /// get some default values for derived classes
   std::tuple<ID, TimeStepSolverType>
   getDefaultSolverID(const AnalysisMethod & method) override;
 
   ModelSolverOptions
   getDefaultSolverOptions(const TimeStepSolverType & type) const override;
 
+  UInt getNbDegreeOfFreedom(const ElementType & type) const;
+
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
   void initSolver(TimeStepSolverType, NonLinearSolverType) override;
 
   /// initialize the model
   void initModel() override;
 
   /// compute the stresses per elements
   void computeStresses();
 
+  /// compute the nodal forces
+  void assembleInternalForce();
+
+  /// compute the nodal forces for an element type
+  void assembleInternalForce(const ElementType & type, GhostType gt);
+
   /// assemble the stiffness matrix
   void assembleStiffnessMatrix();
 
   /// assemble the mass matrix for consistent mass resolutions
   void assembleMass();
 
-  /// update the residual vector
-  void updateResidual();
-
+  /// TODO remove
   void computeRotationMatrix(const ElementType & type);
 
 protected:
   /// compute Rotation Matrices
   template <const ElementType type>
   void computeRotationMatrix(__attribute__((unused)) Array<Real> & rotations) {}
 
   /* ------------------------------------------------------------------------ */
   /* Mass (structural_mechanics_model_mass.cc) */
   /* ------------------------------------------------------------------------ */
 
   /// assemble the mass matrix for either _ghost or _not_ghost elements
   void assembleMass(GhostType ghost_type);
 
   /// computes rho
   void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type);
 
   /// finish the computation of residual to solve in increment
   void updateResidualInternal();
 
   /* ------------------------------------------------------------------------ */
 private:
   template <ElementType type> void assembleStiffnessMatrix();
   template <ElementType type> void assembleMass();
   template <ElementType type> void computeStressOnQuad();
   template <ElementType type>
   void computeTangentModuli(Array<Real> & tangent_moduli);
 
   /* ------------------------------------------------------------------------ */
   /* Dumpable interface                                                       */
   /* ------------------------------------------------------------------------ */
 public:
   virtual dumper::Field * createNodalFieldReal(const std::string & field_name,
                                                const std::string & group_name,
                                                bool padding_flag);
 
   virtual dumper::Field * createNodalFieldBool(const std::string & field_name,
                                                const std::string & group_name,
                                                bool padding_flag);
 
   virtual dumper::Field *
   createElementalField(const std::string & field_name,
                        const std::string & group_name, bool padding_flag,
                        const ElementKind & kind,
                        const std::string & fe_engine_id = "");
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// set the value of the time step
   // void setTimeStep(Real time_step, const ID & solver_id = "") override;
 
   /// return the dimension of the system space
   AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt);
 
   /// get the StructuralMechanicsModel::displacement vector
   AKANTU_GET_MACRO(Displacement, *displacement_rotation, Array<Real> &);
 
   /// get the StructuralMechanicsModel::velocity vector
   AKANTU_GET_MACRO(Velocity, *velocity, Array<Real> &);
 
   /// get    the    StructuralMechanicsModel::acceleration    vector,   updated
   /// by
   /// StructuralMechanicsModel::updateAcceleration
   AKANTU_GET_MACRO(Acceleration, *acceleration, Array<Real> &);
 
   /// get the StructuralMechanicsModel::external_force vector
-  AKANTU_GET_MACRO(ExternalForce, *external_force_momentum, Array<Real> &);
+  AKANTU_GET_MACRO(ExternalForce, *external_force, Array<Real> &);
 
   /// get the StructuralMechanicsModel::internal_force vector (boundary forces)
-  AKANTU_GET_MACRO(InternalForce, *internal_force_momentum, Array<Real> &);
+  AKANTU_GET_MACRO(InternalForce, *internal_force, Array<Real> &);
 
   /// get the StructuralMechanicsModel::boundary vector
   AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(RotationMatrix, rotation_matrix, Real);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementMaterial, element_material, UInt);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Set_ID, set_ID, UInt);
 
   void addMaterial(StructuralMaterial & material) {
     materials.push_back(material);
   }
 
   const StructuralMaterial & getMaterial(const Element & element) const {
     return materials[element_material(element)];
   }
 
   /* ------------------------------------------------------------------------ */
   /* Boundaries (structural_mechanics_model_boundary.cc)                      */
   /* ------------------------------------------------------------------------ */
 public:
   /// Compute Linear load function set in global axis
   template <ElementType type>
   void computeForcesByGlobalTractionArray(const Array<Real> & tractions);
 
   /// Compute Linear load function set in local axis
   template <ElementType type>
   void computeForcesByLocalTractionArray(const Array<Real> & tractions);
 
   /// compute force vector from a function(x,y,momentum) that describe stresses
   // template <ElementType type>
   // void computeForcesFromFunction(BoundaryFunction in_function,
   //                                BoundaryFunctionType function_type);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
   /// time step
   Real time_step;
 
   /// conversion coefficient form force/mass to acceleration
   Real f_m2a;
 
   /// displacements array
   Array<Real> * displacement_rotation{nullptr};
 
   /// velocities array
   Array<Real> * velocity{nullptr};
 
   /// accelerations array
   Array<Real> * acceleration{nullptr};
 
   /// forces array
-  Array<Real> * internal_force_momentum{nullptr};
+  Array<Real> * internal_force{nullptr};
 
   /// forces array
-  Array<Real> * external_force_momentum{nullptr};
+  Array<Real> * external_force{nullptr};
 
   /// lumped mass array
   Array<Real> * mass{nullptr};
 
   /// boundaries array
   Array<bool> * blocked_dofs{nullptr};
 
   /// stress array
   ElementTypeMapArray<Real> stress;
 
   ElementTypeMapArray<UInt> element_material;
 
   // Define sets of beams
   ElementTypeMapArray<UInt> set_ID;
 
   /// number of degre of freedom
   UInt nb_degree_of_freedom;
 
   // Rotation matrix
   ElementTypeMapArray<Real> rotation_matrix;
 
   // /// analysis method check the list in akantu::AnalysisMethod
   // AnalysisMethod method;
 
   /// flag defining if the increment must be computed or not
   bool increment_flag;
 
   /* ------------------------------------------------------------------------ */
   std::vector<StructuralMaterial> materials;
 };
 
 } // namespace akantu
 
 #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ */
diff --git a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc
index 172a8d000..0a4bd6679 100644
--- a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc
+++ b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc
@@ -1,361 +1,370 @@
 /**
  * @file   structural_mechanics_model_inline_impl.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Implementation of inline functions of StructuralMechanicsModel
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "structural_mechanics_model.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__
 #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__
 
 namespace akantu {
+/* -------------------------------------------------------------------------- */
+inline UInt
+StructuralMechanicsModel::getNbDegreeOfFreedom(const ElementType & type) const {
+  UInt ndof = 0;
+#define GET_(type) ndof = ElementClass<type>::getNbDegreeOfFreedom()
+  AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_, _ek_structural);
+#undef GET_
+
+  return ndof;
+}
+
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeTangentModuli(
     Array<Real> & /*tangent_moduli*/) {
   AKANTU_TO_IMPLEMENT();
 }
 } // namespace akantu
 
 #include "structural_element_bernoulli_beam_2.hh"
 #include "structural_element_bernoulli_beam_3.hh"
 #include "structural_element_kirchhoff_shell.hh"
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::assembleStiffnessMatrix() {
   AKANTU_DEBUG_IN();
 
   auto nb_element = getFEEngine().getMesh().getNbElement(type);
   auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type);
   auto tangent_size = ElementClass<type>::getNbStressComponents();
 
   auto tangent_moduli = std::make_unique<Array<Real>>(
       nb_element * nb_quadrature_points, tangent_size * tangent_size,
       "tangent_stiffness_matrix");
   computeTangentModuli<type>(*tangent_moduli);
 
   /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   UInt bt_d_b_size = nb_degree_of_freedom * nb_nodes_per_element;
 
   auto bt_d_b = std::make_unique<Array<Real>>(
       nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B");
 
   const auto & b = getFEEngine().getShapesDerivatives(type);
 
   Matrix<Real> BtD(bt_d_b_size, tangent_size);
 
   for (auto && tuple :
        zip(make_view(b, tangent_size, bt_d_b_size),
            make_view(*tangent_moduli, tangent_size, tangent_size),
            make_view(*bt_d_b, bt_d_b_size, bt_d_b_size))) {
     auto & B = std::get<0>(tuple);
     auto & D = std::get<1>(tuple);
     auto & BtDB = std::get<2>(tuple);
     BtD.mul<true, false>(B, D);
     BtDB.template mul<false, false>(BtD, B);
   }
 
   /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   auto int_bt_d_b = std::make_unique<Array<Real>>(
       nb_element, bt_d_b_size * bt_d_b_size, "int_B^t*D*B");
 
   getFEEngine().integrate(*bt_d_b, *int_bt_d_b, bt_d_b_size * bt_d_b_size,
                           type);
 
   getDOFManager().assembleElementalMatricesToMatrix(
       "K", "displacement", *int_bt_d_b, type, _not_ghost, _symmetric);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeStressOnQuad() {
   AKANTU_DEBUG_IN();
 
   Array<Real> & sigma = stress(type, _not_ghost);
 
   auto nb_element = mesh.getNbElement(type);
   auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type);
   auto tangent_size = ElementClass<type>::getNbStressComponents();
 
   auto tangent_moduli = std::make_unique<Array<Real>>(
       nb_element * nb_quadrature_points, tangent_size * tangent_size,
       "tangent_stiffness_matrix");
 
   computeTangentModuli<type>(*tangent_moduli);
 
   /// compute DB
   auto d_b_size = nb_degree_of_freedom * nb_nodes_per_element;
 
   auto d_b = std::make_unique<Array<Real>>(nb_element * nb_quadrature_points,
                                            d_b_size * tangent_size, "D*B");
 
   const auto & b = getFEEngine().getShapesDerivatives(type);
 
   auto B = b.begin(tangent_size, d_b_size);
   auto D = tangent_moduli->begin(tangent_size, tangent_size);
   auto D_B = d_b->begin(tangent_size, d_b_size);
 
   for (UInt e = 0; e < nb_element; ++e) {
     for (UInt q = 0; q < nb_quadrature_points; ++q, ++B, ++D, ++D_B) {
       D_B->template mul<false, false>(*D, *B);
     }
   }
 
   /// compute DBu
   D_B = d_b->begin(tangent_size, d_b_size);
   auto DBu = sigma.begin(tangent_size);
-  Vector<Real> ul(d_b_size);
 
   Array<Real> u_el(0, d_b_size);
   FEEngine::extractNodalToElementField(mesh, *displacement_rotation, u_el,
                                        type);
 
   auto ug = u_el.begin(d_b_size);
-  auto T = rotation_matrix(type).begin(d_b_size, d_b_size);
 
-  for (UInt e = 0; e < nb_element; ++e, ++T, ++ug) {
-    ul.mul<false>(*T, *ug);
+  // No need to rotate because B is post-multiplied
+  for (UInt e = 0; e < nb_element; ++e, ++ug) {
     for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_B, ++DBu) {
-      DBu->template mul<false>(*D_B, ul);
+      DBu->template mul<false>(*D_B, *ug);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeForcesByLocalTractionArray(
     const Array<Real> & tractions) {
   AKANTU_DEBUG_IN();
 
 #if 0
   UInt nb_element = getFEEngine().getMesh().getNbElement(type);
   UInt nb_nodes_per_element =
       getFEEngine().getMesh().getNbNodesPerElement(type);
   UInt nb_quad = getFEEngine().getNbIntegrationPoints(type);
 
   // check dimension match
   AKANTU_DEBUG_ASSERT(
       Mesh::getSpatialDimension(type) == getFEEngine().getElementDimension(),
       "element type dimension does not match the dimension of boundaries : "
           << getFEEngine().getElementDimension()
           << " != " << Mesh::getSpatialDimension(type));
 
   // check size of the vector
   AKANTU_DEBUG_ASSERT(
       tractions.size() == nb_quad * nb_element,
       "the size of the vector should be the total number of quadrature points");
 
   // check number of components
   AKANTU_DEBUG_ASSERT(tractions.getNbComponent() == nb_degree_of_freedom,
                       "the number of components should be the spatial "
                       "dimension of the problem");
 
   Array<Real> Nvoigt(nb_element * nb_quad, nb_degree_of_freedom *
                                                nb_degree_of_freedom *
                                                nb_nodes_per_element);
   transferNMatrixToSymVoigtNMatrix<type>(Nvoigt);
 
   Array<Real>::const_matrix_iterator N_it = Nvoigt.begin(
       nb_degree_of_freedom, nb_degree_of_freedom * nb_nodes_per_element);
   Array<Real>::const_matrix_iterator T_it =
       rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element,
                                   nb_degree_of_freedom * nb_nodes_per_element);
   auto te_it =
       tractions.begin(nb_degree_of_freedom);
 
   Array<Real> funct(nb_element * nb_quad,
                     nb_degree_of_freedom * nb_nodes_per_element, 0.);
   Array<Real>::iterator<Vector<Real>> Fe_it =
       funct.begin(nb_degree_of_freedom * nb_nodes_per_element);
 
   Vector<Real> fe(nb_degree_of_freedom * nb_nodes_per_element);
   for (UInt e = 0; e < nb_element; ++e, ++T_it) {
     const Matrix<Real> & T = *T_it;
     for (UInt q = 0; q < nb_quad; ++q, ++N_it, ++te_it, ++Fe_it) {
       const Matrix<Real> & N = *N_it;
       const Vector<Real> & te = *te_it;
       Vector<Real> & Fe = *Fe_it;
 
       // compute N^t tl
       fe.mul<true>(N, te);
       // turn N^t tl back in the global referential
       Fe.mul<true>(T, fe);
     }
   }
 
   // allocate the vector that will contain the integrated values
   std::stringstream name;
   name << id << type << ":integral_boundary";
   Array<Real> int_funct(nb_element, nb_degree_of_freedom * nb_nodes_per_element,
                         name.str());
 
   // do the integration
   getFEEngine().integrate(funct, int_funct,
                           nb_degree_of_freedom * nb_nodes_per_element, type);
 
   // assemble the result into force vector
   getFEEngine().assembleArray(int_funct, *force_momentum,
                               dof_synchronizer->getLocalDOFEquationNumbers(),
                               nb_degree_of_freedom, type);
 #endif
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeForcesByGlobalTractionArray(
     const Array<Real> & traction_global) {
   AKANTU_DEBUG_IN();
 #if 0
   UInt nb_element = mesh.getNbElement(type);
   UInt nb_quad = getFEEngine().getNbIntegrationPoints(type);
   UInt nb_nodes_per_element =
       getFEEngine().getMesh().getNbNodesPerElement(type);
 
   std::stringstream name;
   name << id << ":structuralmechanics:imposed_linear_load";
   Array<Real> traction_local(nb_element * nb_quad, nb_degree_of_freedom,
                              name.str());
 
   Array<Real>::const_matrix_iterator T_it =
       rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element,
                                   nb_degree_of_freedom * nb_nodes_per_element);
 
   Array<Real>::const_iterator<Vector<Real>> Te_it =
       traction_global.begin(nb_degree_of_freedom);
   Array<Real>::iterator<Vector<Real>> te_it =
       traction_local.begin(nb_degree_of_freedom);
 
   Matrix<Real> R(nb_degree_of_freedom, nb_degree_of_freedom);
   for (UInt e = 0; e < nb_element; ++e, ++T_it) {
     const Matrix<Real> & T = *T_it;
     for (UInt i = 0; i < nb_degree_of_freedom; ++i)
       for (UInt j = 0; j < nb_degree_of_freedom; ++j)
         R(i, j) = T(i, j);
 
     for (UInt q = 0; q < nb_quad; ++q, ++Te_it, ++te_it) {
       const Vector<Real> & Te = *Te_it;
       Vector<Real> & te = *te_it;
       // turn the traction in the local referential
       te.mul<false>(R, Te);
     }
   }
 
   computeForcesByLocalTractionArray<type>(traction_local);
 #endif
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * @param myf pointer  to a function that fills a  vector/tensor with respect to
  * passed coordinates
  */
 #if 0
 template <ElementType type>
 inline void StructuralMechanicsModel::computeForcesFromFunction(
     BoundaryFunction myf, BoundaryFunctionType function_type) {
   /** function type is
    ** _bft_forces : linear load is given
    ** _bft_stress : stress function is given -> Not already done for this kind
    *of model
    */
 
   std::stringstream name;
   name << id << ":structuralmechanics:imposed_linear_load";
   Array<Real> lin_load(0, nb_degree_of_freedom, name.str());
   name.clear();
 
   UInt offset = nb_degree_of_freedom;
 
   // prepare the loop over element types
   UInt nb_quad = getFEEngine().getNbIntegrationPoints(type);
   UInt nb_element = getFEEngine().getMesh().getNbElement(type);
 
   name.clear();
   name << id << ":structuralmechanics:quad_coords";
   Array<Real> quad_coords(nb_element * nb_quad, spatial_dimension,
                           "quad_coords");
 
   getFEEngineClass<MyFEEngineType>()
       .getShapeFunctions()
       .interpolateOnIntegrationPoints<type>(getFEEngine().getMesh().getNodes(),
                                             quad_coords, spatial_dimension);
   getFEEngineClass<MyFEEngineType>()
       .getShapeFunctions()
       .interpolateOnIntegrationPoints<type>(
           getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension,
           _not_ghost, empty_filter, true, 0, 1, 1);
   if (spatial_dimension == 3)
     getFEEngineClass<MyFEEngineType>()
         .getShapeFunctions()
         .interpolateOnIntegrationPoints<type>(
             getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension,
             _not_ghost, empty_filter, true, 0, 2, 2);
   lin_load.resize(nb_element * nb_quad);
   Real * imposed_val = lin_load.storage();
 
   /// sigma/load on each quadrature points
   Real * qcoord = quad_coords.storage();
   for (UInt el = 0; el < nb_element; ++el) {
     for (UInt q = 0; q < nb_quad; ++q) {
       myf(qcoord, imposed_val, NULL, 0);
       imposed_val += offset;
       qcoord += spatial_dimension;
     }
   }
 
   switch (function_type) {
   case _bft_traction_local:
     computeForcesByLocalTractionArray<type>(lin_load);
     break;
   case _bft_traction:
     computeForcesByGlobalTractionArray<type>(lin_load);
     break;
   default:
     break;
   }
 }
 #endif
 } // namespace akantu
 
 #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ */
diff --git a/src/model/time_step_solver.hh b/src/model/time_step_solver.hh
index fab8342e3..07fab9115 100644
--- a/src/model/time_step_solver.hh
+++ b/src/model/time_step_solver.hh
@@ -1,132 +1,136 @@
 /**
  * @file   time_step_solver.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Mon Aug 24 12:42:04 2015
  *
  * @brief  This corresponding to the time step evolution solver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_array.hh"
 #include "aka_memory.hh"
 #include "integration_scheme.hh"
 #include "parameter_registry.hh"
 #include "solver_callback.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_TIME_STEP_SOLVER_HH__
 #define __AKANTU_TIME_STEP_SOLVER_HH__
 
 namespace akantu {
 class DOFManager;
 class NonLinearSolver;
 }
 
 namespace akantu {
 
 class TimeStepSolver : public Memory,
                        public ParameterRegistry,
                        public SolverCallback {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   TimeStepSolver(DOFManager & dof_manager, const TimeStepSolverType & type,
                  NonLinearSolver & non_linear_solver, const ID & id,
                  UInt memory_id);
   ~TimeStepSolver() override;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// solves on step
   virtual void solveStep(SolverCallback & solver_callback) = 0;
 
   /// register an integration scheme for a given dof
   virtual void
   setIntegrationScheme(const ID & dof_id, const IntegrationSchemeType & type,
                        IntegrationScheme::SolutionType solution_type =
                        IntegrationScheme::_not_defined) = 0;
 
   /// replies if a integration scheme has been set
   virtual bool hasIntegrationScheme(const ID & dof_id) const = 0;
   /* ------------------------------------------------------------------------ */
   /* Solver Callback interface                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// implementation of the SolverCallback::getMatrixType()
   MatrixType getMatrixType(const ID &) final { return _mt_not_defined; }
   /// implementation of the SolverCallback::predictor()
   void predictor() override;
   /// implementation of the SolverCallback::corrector()
   void corrector() override;
   /// implementation of the SolverCallback::assembleJacobian()
   void assembleMatrix(const ID & matrix_id) override;
   /// implementation of the SolverCallback::assembleJacobian()
   void assembleLumpedMatrix(const ID & matrix_id) final;
   /// implementation of the SolverCallback::assembleResidual()
   void assembleResidual() override;
+  /// implementation of the SolverCallback::assembleResidual()
+  void assembleResidual(const ID & residual_part) override;
 
   void beforeSolveStep() override;
   void afterSolveStep() override;
+
+  bool canSplitResidual() { return solver_callback->canSplitResidual(); }
   /* ------------------------------------------------------------------------ */
   /* Accessor                                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   AKANTU_GET_MACRO(TimeStep, time_step, Real);
   AKANTU_SET_MACRO(TimeStep, time_step, Real);
 
   AKANTU_GET_MACRO(NonLinearSolver, non_linear_solver, const NonLinearSolver &);
   AKANTU_GET_MACRO_NOT_CONST(NonLinearSolver, non_linear_solver,
                              NonLinearSolver &);
 protected:
   MatrixType getCommonMatrixType();
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// Underlying dof manager containing the dof to treat
   DOFManager & _dof_manager;
 
   /// Type of solver
   TimeStepSolverType type;
 
   /// The time step for this solver
   Real time_step;
 
   /// Temporary storage for solver callback
   SolverCallback * solver_callback;
 
   /// NonLinearSolver used by this tome step solver
   NonLinearSolver & non_linear_solver;
 
   /// List of required matrices
   std::map<std::string, MatrixType> needed_matrices;
 };
 
 } // akantu
 
 #endif /* __AKANTU_TIME_STEP_SOLVER_HH__ */
diff --git a/src/model/time_step_solvers/time_step_solver.cc b/src/model/time_step_solvers/time_step_solver.cc
index 43f429c2a..1cb645ef3 100644
--- a/src/model/time_step_solvers/time_step_solver.cc
+++ b/src/model/time_step_solvers/time_step_solver.cc
@@ -1,167 +1,176 @@
 /**
  * @file   time_step_solver.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Mon Oct 12 16:56:43 2015
  *
  * @brief  Implementation of common part of TimeStepSolvers
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "time_step_solver.hh"
 #include "dof_manager.hh"
 #include "non_linear_solver.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolver::TimeStepSolver(DOFManager & dof_manager,
                                const TimeStepSolverType & type,
                                NonLinearSolver & non_linear_solver,
                                const ID & id, UInt memory_id)
     : Memory(id, memory_id), SolverCallback(dof_manager),
       _dof_manager(dof_manager), type(type), time_step(0.),
       solver_callback(nullptr), non_linear_solver(non_linear_solver) {
   this->registerSubRegistry("non_linear_solver", non_linear_solver);
 }
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolver::~TimeStepSolver() = default;
 
 /* -------------------------------------------------------------------------- */
 MatrixType TimeStepSolver::getCommonMatrixType() {
   MatrixType common_type = _mt_not_defined;
   for (auto & pair : needed_matrices) {
     auto & type = pair.second;
     if (type == _mt_not_defined) {
       type = this->solver_callback->getMatrixType(pair.first);
     }
 
     common_type = std::min(common_type, type);
   }
 
   AKANTU_DEBUG_ASSERT(common_type != _mt_not_defined,
                       "No type defined for the matrices");
 
   return common_type;
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolver::predictor() {
   AKANTU_DEBUG_ASSERT(
       this->solver_callback != nullptr,
       "This function cannot be called if the solver_callback is not set");
 
   this->solver_callback->predictor();
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolver::corrector() {
   AKANTU_DEBUG_ASSERT(
       this->solver_callback != nullptr,
       "This function cannot be called if the solver_callback is not set");
 
   this->solver_callback->corrector();
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolver::beforeSolveStep() {
   AKANTU_DEBUG_ASSERT(
       this->solver_callback != nullptr,
       "This function cannot be called if the solver_callback is not set");
 
   this->solver_callback->beforeSolveStep();
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolver::afterSolveStep() {
   AKANTU_DEBUG_ASSERT(
       this->solver_callback != nullptr,
       "This function cannot be called if the solver_callback is not set");
 
   this->solver_callback->afterSolveStep();
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolver::assembleLumpedMatrix(const ID & matrix_id) {
   AKANTU_DEBUG_ASSERT(
       this->solver_callback != nullptr,
       "This function cannot be called if the solver_callback is not set");
 
   if (not _dof_manager.hasLumpedMatrix(matrix_id))
     _dof_manager.getNewLumpedMatrix(matrix_id);
 
   this->solver_callback->assembleLumpedMatrix(matrix_id);
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolver::assembleMatrix(const ID & matrix_id) {
   AKANTU_DEBUG_ASSERT(
       this->solver_callback != nullptr,
       "This function cannot be called if the solver_callback is not set");
 
   auto common_type = this->getCommonMatrixType();
 
   if (matrix_id != "J") {
     auto type = needed_matrices[matrix_id];
     if (type == _mt_not_defined) return;
 
     if (not _dof_manager.hasMatrix(matrix_id)) {
       _dof_manager.getNewMatrix(matrix_id, type);
     }
 
     this->solver_callback->assembleMatrix(matrix_id);
     return;
   }
 
   if (not _dof_manager.hasMatrix("J"))
     _dof_manager.getNewMatrix("J", common_type);
 
   for (auto & pair : needed_matrices) {
     auto type = pair.second;
     if (type == _mt_not_defined)
       continue;
 
     auto name = pair.first;
     if (not _dof_manager.hasMatrix(name))
       _dof_manager.getNewMatrix(name, type);
 
     this->solver_callback->assembleMatrix(name);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolver::assembleResidual() {
   AKANTU_DEBUG_ASSERT(
       this->solver_callback != nullptr,
       "This function cannot be called if the solver_callback is not set");
 
   this->_dof_manager.clearResidual();
   this->solver_callback->assembleResidual();
 }
 
+/* -------------------------------------------------------------------------- */
+void TimeStepSolver::assembleResidual(const ID & residual_part) {
+  AKANTU_DEBUG_ASSERT(
+      this->solver_callback != nullptr,
+      "This function cannot be called if the solver_callback is not set");
+
+  this->solver_callback->assembleResidual(residual_part);
+}
+
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/model/time_step_solvers/time_step_solver_default.cc b/src/model/time_step_solvers/time_step_solver_default.cc
index 95e038d65..41fe9bce9 100644
--- a/src/model/time_step_solvers/time_step_solver_default.cc
+++ b/src/model/time_step_solvers/time_step_solver_default.cc
@@ -1,282 +1,309 @@
 /**
  * @file   time_step_solver_default.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Sep 16 10:20:55 2015
  *
  * @brief  Default implementation of the time step solver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "time_step_solver_default.hh"
 #include "dof_manager_default.hh"
 #include "integration_scheme_1st_order.hh"
 #include "integration_scheme_2nd_order.hh"
 #include "mesh.hh"
 #include "non_linear_solver.hh"
 #include "pseudo_time.hh"
 #include "sparse_matrix_aij.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolverDefault::TimeStepSolverDefault(
     DOFManagerDefault & dof_manager, const TimeStepSolverType & type,
     NonLinearSolver & non_linear_solver, const ID & id, UInt memory_id)
     : TimeStepSolver(dof_manager, type, non_linear_solver, id, memory_id),
       dof_manager(dof_manager), is_mass_lumped(false) {
   switch (type) {
   case _tsst_dynamic:
     break;
   case _tsst_dynamic_lumped:
     this->is_mass_lumped = true;
     break;
   case _tsst_static:
     /// initialize a static time solver for callback dofs
     break;
   default:
     AKANTU_TO_IMPLEMENT();
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolverDefault::setIntegrationScheme(
     const ID & dof_id, const IntegrationSchemeType & type,
     IntegrationScheme::SolutionType solution_type) {
   if (this->integration_schemes.find(dof_id) !=
       this->integration_schemes.end()) {
     AKANTU_EXCEPTION("Their DOFs "
                      << dof_id
                      << "  have already an integration scheme associated");
   }
 
   std::unique_ptr<IntegrationScheme> integration_scheme;
   if (this->is_mass_lumped) {
     switch (type) {
     case _ist_forward_euler: {
       integration_scheme = std::make_unique<ForwardEuler>(dof_manager, dof_id);
       break;
     }
     case _ist_central_difference: {
       integration_scheme =
           std::make_unique<CentralDifference>(dof_manager, dof_id);
       break;
     }
     default:
       AKANTU_EXCEPTION(
           "This integration scheme cannot be used in lumped dynamic");
     }
   } else {
     switch (type) {
     case _ist_pseudo_time: {
       integration_scheme = std::make_unique<PseudoTime>(dof_manager, dof_id);
       break;
     }
     case _ist_forward_euler: {
       integration_scheme = std::make_unique<ForwardEuler>(dof_manager, dof_id);
       break;
     }
     case _ist_trapezoidal_rule_1: {
       integration_scheme =
           std::make_unique<TrapezoidalRule1>(dof_manager, dof_id);
       break;
     }
     case _ist_backward_euler: {
       integration_scheme = std::make_unique<BackwardEuler>(dof_manager, dof_id);
       break;
     }
     case _ist_central_difference: {
       integration_scheme =
           std::make_unique<CentralDifference>(dof_manager, dof_id);
       break;
     }
     case _ist_fox_goodwin: {
       integration_scheme = std::make_unique<FoxGoodwin>(dof_manager, dof_id);
       break;
     }
     case _ist_trapezoidal_rule_2: {
       integration_scheme =
           std::make_unique<TrapezoidalRule2>(dof_manager, dof_id);
       break;
     }
     case _ist_linear_acceleration: {
       integration_scheme =
           std::make_unique<LinearAceleration>(dof_manager, dof_id);
       break;
     }
     case _ist_generalized_trapezoidal: {
       integration_scheme =
           std::make_unique<GeneralizedTrapezoidal>(dof_manager, dof_id);
       break;
     }
     case _ist_newmark_beta:
       integration_scheme = std::make_unique<NewmarkBeta>(dof_manager, dof_id);
       break;
     }
   }
 
   AKANTU_DEBUG_ASSERT(integration_scheme,
                       "No integration scheme was found for the provided types");
 
   auto && matrices_names = integration_scheme->getNeededMatrixList();
   for (auto && name : matrices_names) {
     needed_matrices.insert({name, _mt_not_defined});
   }
 
   this->integration_schemes[dof_id] = std::move(integration_scheme);
   this->solution_types[dof_id] = solution_type;
 
   this->integration_schemes_owner.insert(dof_id);
 }
 
 /* -------------------------------------------------------------------------- */
 bool TimeStepSolverDefault::hasIntegrationScheme(const ID & dof_id) const {
   return this->integration_schemes.find(dof_id) !=
          this->integration_schemes.end();
 }
 
 /* -------------------------------------------------------------------------- */
 TimeStepSolverDefault::~TimeStepSolverDefault() = default;
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolverDefault::solveStep(SolverCallback & solver_callback) {
   this->solver_callback = &solver_callback;
 
   this->solver_callback->beforeSolveStep();
   this->non_linear_solver.solve(*this);
   this->solver_callback->afterSolveStep();
 
   this->solver_callback = nullptr;
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolverDefault::predictor() {
   AKANTU_DEBUG_IN();
 
   TimeStepSolver::predictor();
 
   for (auto & pair : this->integration_schemes) {
     auto & dof_id = pair.first;
     auto & integration_scheme = pair.second;
 
     if (this->dof_manager.hasPreviousDOFs(dof_id)) {
       this->dof_manager.savePreviousDOFs(dof_id);
     }
 
     /// integrator predictor
     integration_scheme->predictor(this->time_step);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolverDefault::corrector() {
   AKANTU_DEBUG_IN();
 
   TimeStepSolver::corrector();
 
   for (auto & pair : this->integration_schemes) {
     auto & dof_id = pair.first;
     auto & integration_scheme = pair.second;
 
     const auto & solution_type = this->solution_types[dof_id];
     integration_scheme->corrector(solution_type, this->time_step);
 
     /// computing the increment of dof if needed
     if (this->dof_manager.hasDOFsIncrement(dof_id)) {
       if (!this->dof_manager.hasPreviousDOFs(dof_id)) {
         AKANTU_DEBUG_WARNING("In order to compute the increment of "
                              << dof_id << " a 'previous' has to be registered");
         continue;
       }
 
       Array<Real> & increment = this->dof_manager.getDOFsIncrement(dof_id);
       Array<Real> & previous = this->dof_manager.getPreviousDOFs(dof_id);
 
       UInt dof_array_comp = this->dof_manager.getDOFs(dof_id).getNbComponent();
 
       auto prev_dof_it = previous.begin(dof_array_comp);
       auto incr_it = increment.begin(dof_array_comp);
       auto incr_end = increment.end(dof_array_comp);
 
       increment.copy(this->dof_manager.getDOFs(dof_id));
       for (; incr_it != incr_end; ++incr_it, ++prev_dof_it) {
         *incr_it -= *prev_dof_it;
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolverDefault::assembleMatrix(const ID & matrix_id) {
   AKANTU_DEBUG_IN();
 
   TimeStepSolver::assembleMatrix(matrix_id);
 
   if (matrix_id != "J")
     return;
 
   for (auto & pair : this->integration_schemes) {
     auto & dof_id = pair.first;
     auto & integration_scheme = pair.second;
 
     const auto & solution_type = this->solution_types[dof_id];
 
     integration_scheme->assembleJacobian(solution_type, this->time_step);
   }
 
   this->dof_manager.applyBoundary("J");
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void TimeStepSolverDefault::assembleResidual() {
   AKANTU_DEBUG_IN();
 
   if (this->needed_matrices.find("M") != needed_matrices.end()) {
     if (this->is_mass_lumped) {
       this->assembleLumpedMatrix("M");
     } else {
       this->assembleMatrix("M");
     }
   }
 
   TimeStepSolver::assembleResidual();
 
   for (auto & pair : this->integration_schemes) {
     auto & integration_scheme = pair.second;
 
     integration_scheme->assembleResidual(this->is_mass_lumped);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+void TimeStepSolverDefault::assembleResidual(const ID & residual_part) {
+  AKANTU_DEBUG_IN();
+
+  if (this->needed_matrices.find("M") != needed_matrices.end()) {
+    if (this->is_mass_lumped) {
+      this->assembleLumpedMatrix("M");
+    } else {
+      this->assembleMatrix("M");
+    }
+  }
+
+  if (residual_part != "inertial") {
+    TimeStepSolver::assembleResidual(residual_part);
+  }
+
+  if(residual_part == "inertial") {
+    for (auto & pair : this->integration_schemes) {
+      auto & integration_scheme = pair.second;
+
+      integration_scheme->assembleResidual(this->is_mass_lumped);
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/model/time_step_solvers/time_step_solver_default.hh b/src/model/time_step_solvers/time_step_solver_default.hh
index 1d5fcff70..7513f2526 100644
--- a/src/model/time_step_solvers/time_step_solver_default.hh
+++ b/src/model/time_step_solvers/time_step_solver_default.hh
@@ -1,109 +1,110 @@
 /**
  * @file   time_step_solver_default.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Mon Aug 24 17:10:29 2015
  *
  * @brief  Default implementation for the time stepper
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "integration_scheme.hh"
 #include "time_step_solver.hh"
 /* -------------------------------------------------------------------------- */
 #include <map>
 #include <set>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_TIME_STEP_SOLVER_DEFAULT_HH__
 #define __AKANTU_TIME_STEP_SOLVER_DEFAULT_HH__
 
 namespace akantu {
 class DOFManagerDefault;
 }
 
 namespace akantu {
 
 class TimeStepSolverDefault : public TimeStepSolver {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   TimeStepSolverDefault(DOFManagerDefault & dof_manager,
                         const TimeStepSolverType & type,
                         NonLinearSolver & non_linear_solver, const ID & id,
                         UInt memory_id);
 
   ~TimeStepSolverDefault() override;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// registers an integration scheme for a given dof
   void setIntegrationScheme(const ID & dof_id,
                             const IntegrationSchemeType & type,
                             IntegrationScheme::SolutionType solution_type =
                                 IntegrationScheme::_not_defined) override;
   bool hasIntegrationScheme(const ID & dof_id) const override;
 
   /// implementation of the TimeStepSolver::predictor()
   void predictor() override;
   /// implementation of the TimeStepSolver::corrector()
   void corrector() override;
   /// implementation of the TimeStepSolver::assembleMatrix()
   void assembleMatrix(const ID & matrix_id) override;
   /// implementation of the TimeStepSolver::assembleResidual()
   void assembleResidual() override;
+  void assembleResidual(const ID & residual_part) override;
 
   /// implementation of the generic TimeStepSolver::solveStep()
   void solveStep(SolverCallback & solver_callback) override;
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
   using DOFsIntegrationSchemes = std::map<ID, std::unique_ptr<IntegrationScheme>>;
   using DOFsIntegrationSchemesSolutionTypes = std::map<ID, IntegrationScheme::SolutionType>;
   using DOFsIntegrationSchemesOwner = std::set<ID>;
 
   /// DOFManager with its real type
   DOFManagerDefault & dof_manager;
 
   /// Underlying integration scheme per dof, \todo check what happens in dynamic
   /// in case of coupled equations
   DOFsIntegrationSchemes integration_schemes;
 
   /// defines if the solver is owner of the memory or not
   DOFsIntegrationSchemesOwner integration_schemes_owner;
 
   /// Type of corrector to use
   DOFsIntegrationSchemesSolutionTypes solution_types;
 
   /// define if the mass matrix is lumped or not
   bool is_mass_lumped;
 };
 
 } // namespace akantu
 
 #endif /* __AKANTU_TIME_STEP_SOLVER_DEFAULT_HH__ */
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc
index cc5a0514b..f7ae14564 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc
@@ -1,48 +1,42 @@
 /* -------------------------------------------------------------------------- */
 #include "material_marigo.hh"
 #include "material_mazars.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types = ::testing::Types<
 
     Traits<MaterialMarigo, 1>, Traits<MaterialMarigo, 2>,
     Traits<MaterialMarigo, 3>,
 
     Traits<MaterialMazars, 1>, Traits<MaterialMazars, 2>,
     Traits<MaterialMazars, 3>>;
 
-
 /*****************************************************************/
 
 namespace {
 
 template <typename T>
 class TestDamageMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestDamageMaterialFixture, types);
 
 TYPED_TEST(TestDamageMaterialFixture, DISABLED_ComputeStress) {
   this->material->testComputeStress();
 }
 TYPED_TEST(TestDamageMaterialFixture, DISABLED_EnergyDensity) {
   this->material->testEnergyDensity();
 }
 TYPED_TEST(TestDamageMaterialFixture, DISABLED_ComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
-
-TYPED_TEST(TestDamageMaterialFixture, DISABLED_ComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
-}
-
-TYPED_TEST(TestDamageMaterialFixture, DISABLED_ComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
+TYPED_TEST(TestDamageMaterialFixture, DISABLED_ComputeCelerity) {
+  this->material->testCelerity();
 }
 }
 /*****************************************************************/
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc
index 16e3330f6..60bb381fa 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc
@@ -1,807 +1,1039 @@
 /* -------------------------------------------------------------------------- */
 #include "material_elastic.hh"
 #include "material_elastic_orthotropic.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types =
     ::testing::Types<Traits<MaterialElastic, 1>, Traits<MaterialElastic, 2>,
                      Traits<MaterialElastic, 3>,
 
-                     Traits<MaterialElasticOrthotropic, 1>,
                      Traits<MaterialElasticOrthotropic, 2>,
                      Traits<MaterialElasticOrthotropic, 3>,
 
-                     Traits<MaterialElasticLinearAnisotropic, 1>,
                      Traits<MaterialElasticLinearAnisotropic, 2>,
                      Traits<MaterialElasticLinearAnisotropic, 3>>;
 
 /* -------------------------------------------------------------------------- */
 template <> void FriendMaterial<MaterialElastic<1>>::testComputeStress() {
   Real E = 3.;
   setParam("E", E);
 
   Matrix<Real> eps = {{2}};
   Matrix<Real> sigma(1, 1);
   Real sigma_th = 2;
   this->computeStressOnQuad(eps, sigma, sigma_th);
 
   auto solution = E * eps(0, 0) + sigma_th;
   ASSERT_NEAR(sigma(0, 0), solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <> void FriendMaterial<MaterialElastic<1>>::testEnergyDensity() {
   Real eps = 2, sigma = 2;
   Real epot = 0;
   this->computePotentialEnergyOnQuad({{eps}}, {{sigma}}, epot);
   Real solution = 2;
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElastic<1>>::testComputeTangentModuli() {
   Real E = 2;
   setParam("E", E);
   Matrix<Real> tangent(1, 1);
   this->computeTangentModuliOnQuad(tangent);
   ASSERT_NEAR(tangent(0, 0), E, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<1>>::testPushWaveSpeed() {
+template <> void FriendMaterial<MaterialElastic<1>>::testCelerity() {
   Real E = 3., rho = 2.;
   setParam("E", E);
   setParam("rho", rho);
 
-  auto wave_speed = this->getPushWaveSpeed(Element());
+  auto wave_speed = this->getCelerity(Element());
   auto solution = std::sqrt(E / rho);
   ASSERT_NEAR(wave_speed, solution, 1e-14);
 }
 
-/* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<1>>::testShearWaveSpeed() {
-  ASSERT_THROW(this->getShearWaveSpeed(Element()), debug::Exception);
-}
-
 /* -------------------------------------------------------------------------- */
 template <> void FriendMaterial<MaterialElastic<2>>::testComputeStress() {
   Real E = 1.;
   Real nu = .3;
   Real sigma_th = 0.3; // thermal stress
   setParam("E", E);
   setParam("nu", nu);
 
+  Real bulk_modulus_K = E / 3. / (1 - 2. * nu);
+  Real shear_modulus_mu = 0.5 * E / (1 + nu);
+
   Matrix<Real> rotation_matrix = getRandomRotation2d();
 
-  auto grad_u = this->getDeviatoricStrain(1.).block(0, 0, 2, 2);
+  auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2);
 
   auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
 
   Matrix<Real> sigma_rot(2, 2);
   this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th);
 
   auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
 
   Matrix<Real> identity(2, 2);
   identity.eye();
 
-  Matrix<Real> sigma_expected =
-      0.5 * E / (1 + nu) * (grad_u + grad_u.transpose()) + sigma_th * identity;
+  Matrix<Real> strain = 0.5 * (grad_u + grad_u.transpose());
+  Matrix<Real> deviatoric_strain = strain - 1. / 3. * strain.trace() * identity;
+
+  Matrix<Real> sigma_expected = 2 * shear_modulus_mu * deviatoric_strain +
+                                (sigma_th + 2. * bulk_modulus_K) * identity;
 
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
   ASSERT_NEAR(stress_error, 0., 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <> void FriendMaterial<MaterialElastic<2>>::testEnergyDensity() {
   Matrix<Real> sigma = {{1, 2}, {2, 4}};
   Matrix<Real> eps = {{1, 0}, {0, 1}};
   Real epot = 0;
   Real solution = 2.5;
   this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElastic<2>>::testComputeTangentModuli() {
   Real E = 1.;
   Real nu = .3;
   setParam("E", E);
   setParam("nu", nu);
   Matrix<Real> tangent(3, 3);
 
   /* Plane Strain */
   // clang-format off
   Matrix<Real> solution = {
     {1 - nu, nu, 0},
     {nu, 1 - nu, 0},
     {0, 0, (1 - 2 * nu) / 2},
   };
   // clang-format on
   solution *= E / ((1 + nu) * (1 - 2 * nu));
 
   this->computeTangentModuliOnQuad(tangent);
   Real tangent_error = (tangent - solution).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 
   /* Plane Stress */
   this->plane_stress = true;
   this->updateInternalParameters();
   // clang-format off
   solution = {
     {1, nu, 0},
     {nu, 1, 0},
     {0, 0, (1 - nu) / 2},
   };
   // clang-format on
   solution *= E / (1 - nu * nu);
 
   this->computeTangentModuliOnQuad(tangent);
   tangent_error = (tangent - solution).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<2>>::testPushWaveSpeed() {
+template <> void FriendMaterial<MaterialElastic<2>>::testCelerity() {
   Real E = 1.;
   Real nu = .3;
   Real rho = 2;
   setParam("E", E);
   setParam("nu", nu);
   setParam("rho", rho);
-  auto wave_speed = this->getPushWaveSpeed(Element());
+  auto push_wave_speed = this->getPushWaveSpeed(Element());
+  auto celerity = this->getCelerity(Element());
 
   Real K = E / (3 * (1 - 2 * nu));
   Real mu = E / (2 * (1 + nu));
   Real sol = std::sqrt((K + 4. / 3 * mu) / rho);
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
-}
+  ASSERT_NEAR(push_wave_speed, sol, 1e-14);
+  ASSERT_NEAR(celerity, sol, 1e-14);
 
-/* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<2>>::testShearWaveSpeed() {
-  Real E = 1.;
-  Real nu = .3;
-  Real rho = 2;
-  setParam("E", E);
-  setParam("nu", nu);
-  setParam("rho", rho);
-  auto wave_speed = this->getShearWaveSpeed(Element());
+  auto shear_wave_speed = this->getShearWaveSpeed(Element());
 
-  Real mu = E / (2 * (1 + nu));
-  Real sol = std::sqrt(mu / rho);
+  sol = std::sqrt(mu / rho);
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
+  ASSERT_NEAR(shear_wave_speed, sol, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
+
 template <> void FriendMaterial<MaterialElastic<3>>::testComputeStress() {
   Real E = 1.;
   Real nu = .3;
   Real sigma_th = 0.3; // thermal stress
   setParam("E", E);
   setParam("nu", nu);
 
+  Real bulk_modulus_K = E / 3. / (1 - 2. * nu);
+  Real shear_modulus_mu = 0.5 * E / (1 + nu);
+
   Matrix<Real> rotation_matrix = getRandomRotation3d();
 
-  auto grad_u = this->getDeviatoricStrain(1.);
+  auto grad_u = this->getComposedStrain(1.);
 
   auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
 
   Matrix<Real> sigma_rot(3, 3);
   this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th);
 
   auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
 
   Matrix<Real> identity(3, 3);
   identity.eye();
 
-  Matrix<Real> sigma_expected =
-      0.5 * E / (1 + nu) * (grad_u + grad_u.transpose()) + sigma_th * identity;
+  Matrix<Real> strain = 0.5 * (grad_u + grad_u.transpose());
+  Matrix<Real> deviatoric_strain = strain - 1. / 3. * strain.trace() * identity;
+
+  Matrix<Real> sigma_expected = 2 * shear_modulus_mu * deviatoric_strain +
+                                (sigma_th + 3. * bulk_modulus_K) * identity;
 
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
   ASSERT_NEAR(stress_error, 0., 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <> void FriendMaterial<MaterialElastic<3>>::testEnergyDensity() {
   Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}};
   Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
   Real epot = 0;
   Real solution = 5.5;
   this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElastic<3>>::testComputeTangentModuli() {
   Real E = 1.;
   Real nu = .3;
   setParam("E", E);
   setParam("nu", nu);
   Matrix<Real> tangent(6, 6);
 
   // clang-format off
   Matrix<Real> solution = {
       {1 - nu, nu, nu, 0, 0, 0},
       {nu, 1 - nu, nu, 0, 0, 0},
       {nu, nu, 1 - nu, 0, 0, 0},
       {0, 0, 0, (1 - 2 * nu) / 2, 0, 0},
       {0, 0, 0, 0, (1 - 2 * nu) / 2, 0},
       {0, 0, 0, 0, 0, (1 - 2 * nu) / 2},
   };
   // clang-format on
   solution *= E / ((1 + nu) * (1 - 2 * nu));
 
   this->computeTangentModuliOnQuad(tangent);
   Real tangent_error = (tangent - solution).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<3>>::testPushWaveSpeed() {
+template <> void FriendMaterial<MaterialElastic<3>>::testCelerity() {
   Real E = 1.;
   Real nu = .3;
   Real rho = 2;
   setParam("E", E);
   setParam("nu", nu);
   setParam("rho", rho);
-  auto wave_speed = this->getPushWaveSpeed(Element());
+
+  auto push_wave_speed = this->getPushWaveSpeed(Element());
+  auto celerity = this->getCelerity(Element());
 
   Real K = E / (3 * (1 - 2 * nu));
   Real mu = E / (2 * (1 + nu));
   Real sol = std::sqrt((K + 4. / 3 * mu) / rho);
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
-}
+  ASSERT_NEAR(push_wave_speed, sol, 1e-14);
+  ASSERT_NEAR(celerity, sol, 1e-14);
 
-/* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<3>>::testShearWaveSpeed() {
-  Real E = 1.;
-  Real nu = .3;
-  Real rho = 2;
-  setParam("E", E);
-  setParam("nu", nu);
-  setParam("rho", rho);
-  auto wave_speed = this->getShearWaveSpeed(Element());
+  auto shear_wave_speed = this->getShearWaveSpeed(Element());
 
-  Real mu = E / (2 * (1 + nu));
-  Real sol = std::sqrt(mu / rho);
+  sol = std::sqrt(mu / rho);
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
+  ASSERT_NEAR(shear_wave_speed, sol, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticOrthotropic<2>>::testComputeStress() {
   UInt Dim = 2;
 
   this->E1 = 1.;
   this->E2 = 2.;
   this->nu12 = 0.1;
   this->G12 = 2.;
 
   // material frame of reference is rotate by rotation_matrix starting from
   // canonical basis
   Matrix<Real> rotation_matrix = getRandomRotation2d();
 
   // canonical basis as expressed in the material frame of reference, as
   // required by MaterialElasticOrthotropic class (it is simply given by the
   // columns of the rotation_matrix; the lines give the material basis expressed
   // in the canonical frame of reference)
   *this->dir_vecs[0] = rotation_matrix(0);
   *this->dir_vecs[1] = rotation_matrix(1);
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   // gradient in material frame of reference
-  auto grad_u = (this->getDeviatoricStrain(2.) + this->getHydrostaticStrain(1.))
-                    .block(0, 0, 2, 2);
+  auto grad_u = this->getComposedStrain(2.).block(0, 0, 2, 2);
 
   // gradient in canonical basis (we need to rotate *back* to the canonical
   // basis)
   auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
 
   // stress in the canonical basis
   Matrix<Real> sigma_rot(2, 2);
   this->computeStressOnQuad(grad_u_rot, sigma_rot);
 
   // stress in the material reference (we need to apply the rotation)
   auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
 
   // construction of Cijkl engineering tensor in the *material* frame of
   // reference
   // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
   Real nu21 = nu12 * E2 / E1;
   Real gamma = 1 / (1 - nu12 * nu21);
 
   Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0);
   C_expected(0, 0) = gamma * E1;
   C_expected(1, 1) = gamma * E2;
   C_expected(2, 2) = G12;
 
   C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21;
 
   // epsilon is computed directly in the *material* frame of reference
   Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
 
   // sigma_expected is computed directly in the *material* frame of reference
   Matrix<Real> sigma_expected(Dim, Dim);
   for (UInt i = 0; i < Dim; ++i) {
     for (UInt j = 0; j < Dim; ++j) {
       sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j);
     }
   }
 
   sigma_expected(0, 1) = sigma_expected(1, 0) =
       C_expected(2, 2) * 2 * epsilon(0, 1);
 
   // sigmas are checked in the *material* frame of reference
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
   ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticOrthotropic<2>>::testEnergyDensity() {
   Matrix<Real> sigma = {{1, 2}, {2, 4}};
   Matrix<Real> eps = {{1, 0}, {0, 1}};
   Real epot = 0;
   Real solution = 2.5;
   this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticOrthotropic<2>>::testComputeTangentModuli() {
 
   // Note: for this test material and canonical basis coincide
   Vector<Real> n1 = {1, 0};
   Vector<Real> n2 = {0, 1};
   Real E1 = 1.;
   Real E2 = 2.;
   Real nu12 = 0.1;
   Real G12 = 2.;
 
   *this->dir_vecs[0] = n1;
   *this->dir_vecs[1] = n2;
 
   this->E1 = E1;
   this->E2 = E2;
   this->nu12 = nu12;
   this->G12 = G12;
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   // construction of Cijkl engineering tensor in the *material* frame of
   // reference
   // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
   Real nu21 = nu12 * E2 / E1;
   Real gamma = 1 / (1 - nu12 * nu21);
 
   Matrix<Real> C_expected(3, 3);
   C_expected(0, 0) = gamma * E1;
   C_expected(1, 1) = gamma * E2;
   C_expected(2, 2) = G12;
 
   C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21;
 
   Matrix<Real> tangent(3, 3);
   this->computeTangentModuliOnQuad(tangent);
 
   Real tangent_error = (tangent - C_expected).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
+/* -------------------------------------------------------------------------- */
+
+template <> void FriendMaterial<MaterialElasticOrthotropic<2>>::testCelerity() {
+
+  // Note: for this test material and canonical basis coincide
+  Vector<Real> n1 = {1, 0};
+  Vector<Real> n2 = {0, 1};
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real nu12 = 0.1;
+  Real G12 = 2.;
+  Real rho = 2.5;
+
+  setParamNoUpdate("n1", n1);
+  setParamNoUpdate("n2", n2);
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("G12", G12);
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real gamma = 1 / (1 - nu12 * nu21);
+
+  Matrix<Real> C_expected(3, 3);
+  C_expected(0, 0) = gamma * E1;
+  C_expected(1, 1) = gamma * E2;
+  C_expected(2, 2) = G12;
+
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21;
+
+  Vector<Real> eig_expected(3);
+  C_expected.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
+}
+
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticOrthotropic<3>>::testComputeStress() {
   UInt Dim = 3;
   Real E1 = 1.;
   Real E2 = 2.;
   Real E3 = 3.;
   Real nu12 = 0.1;
   Real nu13 = 0.2;
   Real nu23 = 0.3;
   Real G12 = 2.;
   Real G13 = 3.;
   Real G23 = 1.;
 
   this->E1 = E1;
   this->E2 = E2;
   this->E3 = E3;
   this->nu12 = nu12;
   this->nu13 = nu13;
   this->nu23 = nu23;
   this->G12 = G12;
   this->G13 = G13;
   this->G23 = G23;
 
   // material frame of reference is rotate by rotation_matrix starting from
   // canonical basis
   Matrix<Real> rotation_matrix = getRandomRotation3d();
 
   // canonical basis as expressed in the material frame of reference, as
   // required by MaterialElasticOrthotropic class (it is simply given by the
   // columns of the rotation_matrix; the lines give the material basis expressed
   // in the canonical frame of reference)
   *this->dir_vecs[0] = rotation_matrix(0);
   *this->dir_vecs[1] = rotation_matrix(1);
   *this->dir_vecs[2] = rotation_matrix(2);
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   // gradient in material frame of reference
-  auto grad_u = this->getDeviatoricStrain(2.) + this->getHydrostaticStrain(1.);
+  auto grad_u = this->getComposedStrain(2.);
 
   // gradient in canonical basis (we need to rotate *back* to the canonical
   // basis)
   auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
 
   // stress in the canonical basis
   Matrix<Real> sigma_rot(3, 3);
   this->computeStressOnQuad(grad_u_rot, sigma_rot);
 
   // stress in the material reference (we need to apply the rotation)
   auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
 
   // construction of Cijkl engineering tensor in the *material* frame of
   // reference
   // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
   Real nu21 = nu12 * E2 / E1;
   Real nu31 = nu13 * E3 / E1;
   Real nu32 = nu23 * E3 / E2;
   Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 -
                     2 * nu21 * nu32 * nu13);
 
   Matrix<Real> C_expected(6, 6);
   C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32);
   C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31);
   C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21);
 
   C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23);
   C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32);
   C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31);
 
   C_expected(3, 3) = G23;
   C_expected(4, 4) = G13;
   C_expected(5, 5) = G12;
 
   // epsilon is computed directly in the *material* frame of reference
   Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
 
   // sigma_expected is computed directly in the *material* frame of reference
   Matrix<Real> sigma_expected(Dim, Dim);
   for (UInt i = 0; i < Dim; ++i) {
     for (UInt j = 0; j < Dim; ++j) {
       sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j);
     }
   }
 
   sigma_expected(0, 1) = C_expected(5, 5) * 2 * epsilon(0, 1);
   sigma_expected(0, 2) = C_expected(4, 4) * 2 * epsilon(0, 2);
   sigma_expected(1, 2) = C_expected(3, 3) * 2 * epsilon(1, 2);
   sigma_expected(1, 0) = sigma_expected(0, 1);
   sigma_expected(2, 0) = sigma_expected(0, 2);
   sigma_expected(2, 1) = sigma_expected(1, 2);
 
   // sigmas are checked in the *material* frame of reference
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
   ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticOrthotropic<3>>::testEnergyDensity() {
   Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}};
   Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
   Real epot = 0;
   Real solution = 5.5;
   this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticOrthotropic<3>>::testComputeTangentModuli() {
 
   // Note: for this test material and canonical basis coincide
   UInt Dim = 3;
   Vector<Real> n1 = {1, 0, 0};
   Vector<Real> n2 = {0, 1, 0};
   Vector<Real> n3 = {0, 0, 1};
   Real E1 = 1.;
   Real E2 = 2.;
   Real E3 = 3.;
   Real nu12 = 0.1;
   Real nu13 = 0.2;
   Real nu23 = 0.3;
   Real G12 = 2.;
   Real G13 = 3.;
   Real G23 = 1.;
 
   *this->dir_vecs[0] = n1;
   *this->dir_vecs[1] = n2;
   *this->dir_vecs[2] = n3;
   this->E1 = E1;
   this->E2 = E2;
   this->E3 = E3;
   this->nu12 = nu12;
   this->nu13 = nu13;
   this->nu23 = nu23;
   this->G12 = G12;
   this->G13 = G13;
   this->G23 = G23;
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   // construction of Cijkl engineering tensor in the *material* frame of
   // reference
   // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
   Real nu21 = nu12 * E2 / E1;
   Real nu31 = nu13 * E3 / E1;
   Real nu32 = nu23 * E3 / E2;
   Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 -
                     2 * nu21 * nu32 * nu13);
 
   Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0);
   C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32);
   C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31);
   C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21);
 
   C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23);
   C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32);
   C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31);
 
   C_expected(3, 3) = G23;
   C_expected(4, 4) = G13;
   C_expected(5, 5) = G12;
 
   Matrix<Real> tangent(6, 6);
   this->computeTangentModuliOnQuad(tangent);
 
   Real tangent_error = (tangent - C_expected).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
+/* -------------------------------------------------------------------------- */
+template <> void FriendMaterial<MaterialElasticOrthotropic<3>>::testCelerity() {
+
+  // Note: for this test material and canonical basis coincide
+  UInt Dim = 3;
+  Vector<Real> n1 = {1, 0, 0};
+  Vector<Real> n2 = {0, 1, 0};
+  Vector<Real> n3 = {0, 0, 1};
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real E3 = 3.;
+  Real nu12 = 0.1;
+  Real nu13 = 0.2;
+  Real nu23 = 0.3;
+  Real G12 = 2.;
+  Real G13 = 3.;
+  Real G23 = 1.;
+  Real rho = 2.3;
+
+  setParamNoUpdate("n1", n1);
+  setParamNoUpdate("n2", n2);
+  setParamNoUpdate("n3", n3);
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("E3", E3);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("nu13", nu13);
+  setParamNoUpdate("nu23", nu23);
+  setParamNoUpdate("G12", G12);
+  setParamNoUpdate("G13", G13);
+  setParamNoUpdate("G23", G23);
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real nu31 = nu13 * E3 / E1;
+  Real nu32 = nu23 * E3 / E2;
+  Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 -
+                    2 * nu21 * nu32 * nu13);
+
+  Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0);
+  C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32);
+  C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31);
+  C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21);
+
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23);
+  C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32);
+  C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31);
+
+  C_expected(3, 3) = G23;
+  C_expected(4, 4) = G13;
+  C_expected(5, 5) = G12;
+
+  Vector<Real> eig_expected(6);
+  C_expected.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
+}
+
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testComputeStress() {
   UInt Dim = 2;
   Matrix<Real> C = {
       {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5},
   };
 
-  this->Cprime = C;
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C33", C(2, 2));
 
   // material frame of reference is rotate by rotation_matrix starting from
   // canonical basis
   Matrix<Real> rotation_matrix = getRandomRotation2d();
 
   // canonical basis as expressed in the material frame of reference, as
   // required by MaterialElasticLinearAnisotropic class (it is simply given by
   // the columns of the rotation_matrix; the lines give the material basis
   // expressed in the canonical frame of reference)
   *this->dir_vecs[0] = rotation_matrix(0);
   *this->dir_vecs[1] = rotation_matrix(1);
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   // gradient in material frame of reference
-  auto grad_u = (this->getDeviatoricStrain(2.) + this->getHydrostaticStrain(1.))
-                    .block(0, 0, 2, 2);
+  auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2);
 
   // gradient in canonical basis (we need to rotate *back* to the canonical
   // basis)
   auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
 
   // stress in the canonical basis
   Matrix<Real> sigma_rot(2, 2);
   this->computeStressOnQuad(grad_u_rot, sigma_rot);
 
   // stress in the material reference (we need to apply the rotation)
   auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
 
   // epsilon is computed directly in the *material* frame of reference
   Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
   Vector<Real> epsilon_voigt(3);
   epsilon_voigt(0) = epsilon(0, 0);
   epsilon_voigt(1) = epsilon(1, 1);
   epsilon_voigt(2) = 2 * epsilon(0, 1);
 
   // sigma_expected is computed directly in the *material* frame of reference
   Vector<Real> sigma_voigt = C * epsilon_voigt;
   Matrix<Real> sigma_expected(Dim, Dim);
   sigma_expected(0, 0) = sigma_voigt(0);
   sigma_expected(1, 1) = sigma_voigt(1);
   sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(2);
 
   // sigmas are checked in the *material* frame of reference
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
   ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testEnergyDensity() {
   Matrix<Real> sigma = {{1, 2}, {2, 4}};
   Matrix<Real> eps = {{1, 0}, {0, 1}};
   Real epot = 0;
   Real solution = 2.5;
   this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<
     MaterialElasticLinearAnisotropic<2>>::testComputeTangentModuli() {
 
   // Note: for this test material and canonical basis coincide
   Matrix<Real> C = {
       {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5},
   };
 
-  this->Cprime = C;
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C33", C(2, 2));
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   Matrix<Real> tangent(3, 3);
   this->computeTangentModuliOnQuad(tangent);
 
   Real tangent_error = (tangent - C).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testCelerity() {
+
+  // Note: for this test material and canonical basis coincide
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5},
+  };
+
+  Real rho = 2.7;
+
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  Vector<Real> eig_expected(3);
+  C.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
+}
+
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testComputeStress() {
   UInt Dim = 3;
   Matrix<Real> C = {
       {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2},
       {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4},
       {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2},
   };
 
-  this->Cprime = C;
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C14", C(0, 3));
+  setParamNoUpdate("C15", C(0, 4));
+  setParamNoUpdate("C16", C(0, 5));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C24", C(1, 3));
+  setParamNoUpdate("C25", C(1, 4));
+  setParamNoUpdate("C26", C(1, 5));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("C34", C(2, 3));
+  setParamNoUpdate("C35", C(2, 4));
+  setParamNoUpdate("C36", C(2, 5));
+  setParamNoUpdate("C44", C(3, 3));
+  setParamNoUpdate("C45", C(3, 4));
+  setParamNoUpdate("C46", C(3, 5));
+  setParamNoUpdate("C55", C(4, 4));
+  setParamNoUpdate("C56", C(4, 5));
+  setParamNoUpdate("C66", C(5, 5));
 
   // material frame of reference is rotate by rotation_matrix starting from
   // canonical basis
   Matrix<Real> rotation_matrix = getRandomRotation3d();
 
   // canonical basis as expressed in the material frame of reference, as
   // required by MaterialElasticLinearAnisotropic class (it is simply given by
   // the columns of the rotation_matrix; the lines give the material basis
   // expressed in the canonical frame of reference)
   *this->dir_vecs[0] = rotation_matrix(0);
   *this->dir_vecs[1] = rotation_matrix(1);
   *this->dir_vecs[2] = rotation_matrix(2);
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   // gradient in material frame of reference
-  auto grad_u = this->getDeviatoricStrain(2.) + this->getHydrostaticStrain(1.);
+  auto grad_u = this->getComposedStrain(2.);
 
   // gradient in canonical basis (we need to rotate *back* to the canonical
   // basis)
   auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
 
   // stress in the canonical basis
   Matrix<Real> sigma_rot(3, 3);
   this->computeStressOnQuad(grad_u_rot, sigma_rot);
 
   // stress in the material reference (we need to apply the rotation)
   auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
 
   // epsilon is computed directly in the *material* frame of reference
   Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
   Vector<Real> epsilon_voigt(6);
   epsilon_voigt(0) = epsilon(0, 0);
   epsilon_voigt(1) = epsilon(1, 1);
   epsilon_voigt(2) = epsilon(2, 2);
   epsilon_voigt(3) = 2 * epsilon(1, 2);
   epsilon_voigt(4) = 2 * epsilon(0, 2);
   epsilon_voigt(5) = 2 * epsilon(0, 1);
 
   // sigma_expected is computed directly in the *material* frame of reference
   Vector<Real> sigma_voigt = C * epsilon_voigt;
   Matrix<Real> sigma_expected(Dim, Dim);
   sigma_expected(0, 0) = sigma_voigt(0);
   sigma_expected(1, 1) = sigma_voigt(1);
   sigma_expected(2, 2) = sigma_voigt(2);
   sigma_expected(1, 2) = sigma_expected(2, 1) = sigma_voigt(3);
   sigma_expected(0, 2) = sigma_expected(2, 0) = sigma_voigt(4);
   sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(5);
 
   // sigmas are checked in the *material* frame of reference
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
   ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testEnergyDensity() {
   Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}};
   Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
   Real epot = 0;
   Real solution = 5.5;
   this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<
     MaterialElasticLinearAnisotropic<3>>::testComputeTangentModuli() {
 
   // Note: for this test material and canonical basis coincide
   Matrix<Real> C = {
       {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2},
       {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4},
       {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2},
   };
 
-  this->Cprime = C;
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C14", C(0, 3));
+  setParamNoUpdate("C15", C(0, 4));
+  setParamNoUpdate("C16", C(0, 5));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C24", C(1, 3));
+  setParamNoUpdate("C25", C(1, 4));
+  setParamNoUpdate("C26", C(1, 5));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("C34", C(2, 3));
+  setParamNoUpdate("C35", C(2, 4));
+  setParamNoUpdate("C36", C(2, 5));
+  setParamNoUpdate("C44", C(3, 3));
+  setParamNoUpdate("C45", C(3, 4));
+  setParamNoUpdate("C46", C(3, 5));
+  setParamNoUpdate("C55", C(4, 4));
+  setParamNoUpdate("C56", C(4, 5));
+  setParamNoUpdate("C66", C(5, 5));
 
   // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
 
   Matrix<Real> tangent(6, 6);
   this->computeTangentModuliOnQuad(tangent);
 
   Real tangent_error = (tangent - C).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testCelerity() {
+
+  // Note: for this test material and canonical basis coincide
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2},
+      {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4},
+      {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2},
+  };
+  Real rho = 2.9;
+
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C14", C(0, 3));
+  setParamNoUpdate("C15", C(0, 4));
+  setParamNoUpdate("C16", C(0, 5));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C24", C(1, 3));
+  setParamNoUpdate("C25", C(1, 4));
+  setParamNoUpdate("C26", C(1, 5));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("C34", C(2, 3));
+  setParamNoUpdate("C35", C(2, 4));
+  setParamNoUpdate("C36", C(2, 5));
+  setParamNoUpdate("C44", C(3, 3));
+  setParamNoUpdate("C45", C(3, 4));
+  setParamNoUpdate("C46", C(3, 5));
+  setParamNoUpdate("C55", C(4, 4));
+  setParamNoUpdate("C56", C(4, 5));
+  setParamNoUpdate("C66", C(5, 5));
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  Vector<Real> eig_expected(6);
+  C.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+
 namespace {
 
 template <typename T>
 class TestElasticMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestElasticMaterialFixture, types);
 
 TYPED_TEST(TestElasticMaterialFixture, ComputeStress) {
   this->material->testComputeStress();
 }
 
 TYPED_TEST(TestElasticMaterialFixture, EnergyDensity) {
   this->material->testEnergyDensity();
 }
 
 TYPED_TEST(TestElasticMaterialFixture, ComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
 
-TYPED_TEST(TestElasticMaterialFixture, ComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
+TYPED_TEST(TestElasticMaterialFixture, ElasticComputeCelerity) {
+  this->material->testCelerity();
 }
 
-TYPED_TEST(TestElasticMaterialFixture, ComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
-}
 } // namespace
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc
index e00b46133..4a509f9f4 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc
@@ -1,59 +1,56 @@
 /* -------------------------------------------------------------------------- */
 #include "material_neohookean.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types = ::testing::Types<
 
     Traits<MaterialNeohookean, 1>, Traits<MaterialNeohookean, 2>,
     Traits<MaterialNeohookean, 3>>;
 
 /*****************************************************************/
 
 template <> void FriendMaterial<MaterialNeohookean<3>>::testComputeStress() {
   AKANTU_TO_IMPLEMENT();
 }
 
 /*****************************************************************/
 template <>
 void FriendMaterial<MaterialNeohookean<3>>::testComputeTangentModuli() {
   AKANTU_TO_IMPLEMENT();
 }
 
 /*****************************************************************/
 
 template <> void FriendMaterial<MaterialNeohookean<3>>::testEnergyDensity() {
   AKANTU_TO_IMPLEMENT();
 }
 
 /*****************************************************************/
 
 namespace {
 
 template <typename T>
 class TestFiniteDefMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestFiniteDefMaterialFixture, types);
 
 TYPED_TEST(TestFiniteDefMaterialFixture, DISABLED_ComputeStress) {
   this->material->testComputeStress();
 }
 TYPED_TEST(TestFiniteDefMaterialFixture, DISABLED_EnergyDensity) {
   this->material->testEnergyDensity();
 }
 TYPED_TEST(TestFiniteDefMaterialFixture, DISABLED_ComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
-TYPED_TEST(TestFiniteDefMaterialFixture, DISABLED_ComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
-}
-TYPED_TEST(TestFiniteDefMaterialFixture, DISABLED_ComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
+TYPED_TEST(TestFiniteDefMaterialFixture, DISABLED_DefComputeCelerity) {
+  this->material->testCelerity();
 }
 }
 /*****************************************************************/
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh
index 9eed7866b..bc2aa097a 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh
@@ -1,170 +1,183 @@
 /* -------------------------------------------------------------------------- */
 #include "material_elastic.hh"
 #include "solid_mechanics_model.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <random>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 /* -------------------------------------------------------------------------- */
 template <typename T> class FriendMaterial : public T {
 public:
   ~FriendMaterial() = default;
 
   virtual void testComputeStress() { AKANTU_TO_IMPLEMENT(); };
   virtual void testComputeTangentModuli() { AKANTU_TO_IMPLEMENT(); };
   virtual void testEnergyDensity() { AKANTU_TO_IMPLEMENT(); };
-  virtual void testPushWaveSpeed() { AKANTU_TO_IMPLEMENT(); }
-  virtual void testShearWaveSpeed() { AKANTU_TO_IMPLEMENT(); }
+  virtual void testCelerity() { AKANTU_TO_IMPLEMENT(); }
 
   static inline Matrix<Real> getDeviatoricStrain(Real intensity);
-
   static inline Matrix<Real> getHydrostaticStrain(Real intensity);
+  static inline Matrix<Real> getComposedStrain(Real intensity);
 
   static inline const Matrix<Real>
   reverseRotation(Matrix<Real> mat, Matrix<Real> rotation_matrix) {
     Matrix<Real> R = rotation_matrix;
     Matrix<Real> m2 = mat * R;
     Matrix<Real> m1 = R.transpose();
     return m1 * m2;
   };
 
   static inline const Matrix<Real>
   applyRotation(Matrix<Real> mat, const Matrix<Real> rotation_matrix) {
     Matrix<Real> R = rotation_matrix;
     Matrix<Real> m2 = mat * R.transpose();
     Matrix<Real> m1 = R;
     return m1 * m2;
   };
 
   static inline Matrix<Real> getRandomRotation3d();
   static inline Matrix<Real> getRandomRotation2d();
 
   using T::T;
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Matrix<Real> FriendMaterial<T>::getDeviatoricStrain(Real intensity) {
   Matrix<Real> dev = {{0., 1., 2.}, {1., 0., 3.}, {2., 3., 0.}};
   dev *= intensity;
   return dev;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Matrix<Real> FriendMaterial<T>::getHydrostaticStrain(Real intensity) {
+<<<<<<< HEAD
   Matrix<Real> dev = {{1., 0., 0.}, {0., 2., 0.}, {0., 0., 3.}};
+=======
+  Matrix<Real> dev = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+>>>>>>> f7fbe61127f3a7c649f5b24e7682f50eb13c10f9
   dev *= intensity;
   return dev;
 }
 
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+Matrix<Real> FriendMaterial<T>::getComposedStrain(Real intensity) {
+  Matrix<Real> s = FriendMaterial<T>::getHydrostaticStrain(intensity) +
+                   FriendMaterial<T>::getDeviatoricStrain(intensity);
+  s *= intensity;
+  return s;
+}
+
 /* -------------------------------------------------------------------------- */
 template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation3d() {
   constexpr UInt Dim = 3;
   // Seed with a real random value, if available
   std::random_device rd;
   std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
   std::uniform_real_distribution<Real> dis;
 
   Vector<Real> v1(Dim);
   Vector<Real> v2(Dim);
   Vector<Real> v3(Dim);
 
   for (UInt i = 0; i < Dim; ++i) {
     v1(i) = dis(gen);
     v2(i) = dis(gen);
   }
 
   v1.normalize();
 
   auto d = v1.dot(v2);
   v2 -= v1 * d;
   v2.normalize();
 
   v3.crossProduct(v1, v2);
 
   Matrix<Real> mat(Dim, Dim);
   for (UInt i = 0; i < Dim; ++i) {
     mat(0, i) = v1[i];
     mat(1, i) = v2[i];
     mat(2, i) = v3[i];
   }
 
   return mat;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation2d() {
   constexpr UInt Dim = 2;
   // Seed with a real random value, if available
   std::random_device rd;
   std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
   std::uniform_real_distribution<> dis;
 
   // v1 and v2 are such that they form a right-hand basis with prescribed v3,
   // it's need (at least) for 2d linear elastic anisotropic and (orthotropic)
   // materials to rotate the tangent stiffness
 
   Vector<Real> v1(3);
   Vector<Real> v2(3);
   Vector<Real> v3 = {0, 0, 1};
 
   for (UInt i = 0; i < Dim; ++i) {
     v1(i) = dis(gen);
     // v2(i) = dis(gen);
   }
 
   v1.normalize();
   v2.crossProduct(v3, v1);
 
   Matrix<Real> mat(Dim, Dim);
   for (UInt i = 0; i < Dim; ++i) {
     mat(0, i) = v1[i];
     mat(1, i) = v2[i];
   }
 
   return mat;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, class Model>
 class TestMaterialBaseFixture : public ::testing::Test {
 public:
   using mat_class = typename T::mat_class;
 
   void SetUp() override {
     constexpr auto spatial_dimension = T::Dim;
     mesh = std::make_unique<Mesh>(spatial_dimension);
     model = std::make_unique<Model>(*mesh);
     material = std::make_unique<friend_class>(*model);
   }
 
   void TearDown() override {
     material.reset(nullptr);
     model.reset(nullptr);
     mesh.reset(nullptr);
   }
 
   using friend_class = FriendMaterial<mat_class>;
 
 protected:
   std::unique_ptr<Mesh> mesh;
   std::unique_ptr<Model> model;
   std::unique_ptr<friend_class> material;
 };
 
 /* -------------------------------------------------------------------------- */
 template <template <UInt> class T, UInt _Dim> struct Traits {
   using mat_class = T<_Dim>;
   static constexpr UInt Dim = _Dim;
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 using TestMaterialFixture = TestMaterialBaseFixture<T, SolidMechanicsModel>;
 
 /* -------------------------------------------------------------------------- */
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc
index 024270f8c..d6543e139 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc
@@ -1,41 +1,161 @@
 /* -------------------------------------------------------------------------- */
 #include "material_linear_isotropic_hardening.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types = ::testing::Types<Traits<MaterialLinearIsotropicHardening, 1>,
                                Traits<MaterialLinearIsotropicHardening, 2>,
                                Traits<MaterialLinearIsotropicHardening, 3>>;
 
-/*****************************************************************/
+/* -------------------------------------------------------------------------- */
+
+template <>
+void FriendMaterial<MaterialLinearIsotropicHardening<3>>::testComputeStress() {
+
+  Real E = 1.;
+  // Real nu = .3;
+  Real nu = 0.;
+  Real rho = 1.;
+  Real sigma_0 = 1.;
+  Real h = 0.;
+  Real bulk_modulus_K = E / 3. / (1 - 2. * nu);
+  Real shear_modulus_mu = 0.5 * E / (1 + nu);
+
+  setParam("E", E);
+  setParam("nu", nu);
+  setParam("rho", rho);
+  setParam("sigma_y", sigma_0);
+  setParam("h", h);
+
+  Matrix<Real> rotation_matrix = getRandomRotation3d();
+
+  Real max_strain = 10.;
+  Real strain_steps = 100;
+  Real dt = max_strain / strain_steps;
+  std::vector<double> steps(strain_steps);
+  std::iota(steps.begin(), steps.end(), 0.);
+
+  Matrix<Real> previous_grad_u_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_sigma = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_sigma_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> inelastic_strain_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> inelastic_strain = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_inelastic_strain = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_inelastic_strain_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> sigma_rot(3, 3, 0.);
+  Real iso_hardening = 0.;
+  Real previous_iso_hardening = 0.;
+
+  // hydrostatic loading (should not plastify)
+  for (auto && i : steps) {
+    auto t = i * dt;
+
+    auto grad_u = this->getHydrostaticStrain(t);
+    auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
+
+    this->computeStressOnQuad(grad_u_rot, previous_grad_u_rot, sigma_rot,
+                              previous_sigma_rot, inelastic_strain_rot,
+                              previous_inelastic_strain_rot, iso_hardening,
+                              previous_iso_hardening, 0., 0.);
+
+    auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
+
+    Matrix<Real> sigma_expected =
+        t * 3. * bulk_modulus_K * Matrix<Real>::eye(3, 1.);
+
+    Real stress_error = (sigma - sigma_expected).norm<L_inf>();
+
+    ASSERT_NEAR(stress_error, 0., 1e-13);
+    ASSERT_NEAR(inelastic_strain_rot.norm<L_inf>(), 0., 1e-13);
+
+    previous_grad_u_rot = grad_u_rot;
+    previous_sigma_rot = sigma_rot;
+    previous_inelastic_strain_rot = inelastic_strain_rot;
+    previous_iso_hardening = iso_hardening;
+  }
+
+  // deviatoric loading (should plastify)
+  // stress at onset of plastication
+  Real beta = sqrt(42);
+  Real t_P = sigma_0 / 2. / shear_modulus_mu / beta;
+  Matrix<Real> sigma_P = sigma_0 / beta * this->getDeviatoricStrain(1.);
+
+  for (auto && i : steps) {
+
+    auto t = i * dt;
+    auto grad_u = this->getDeviatoricStrain(t);
+    auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
+    Real iso_hardening, previous_iso_hardening;
+
+    this->computeStressOnQuad(grad_u_rot, previous_grad_u_rot, sigma_rot,
+                              previous_sigma_rot, inelastic_strain_rot,
+                              previous_inelastic_strain_rot, iso_hardening,
+                              previous_iso_hardening, 0., 0.);
+
+    auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
+    auto inelastic_strain =
+        this->reverseRotation(inelastic_strain_rot, rotation_matrix);
+
+    if (t < t_P) {
+
+      Matrix<Real> sigma_expected =
+          shear_modulus_mu * (grad_u + grad_u.transpose());
+
+      Real stress_error = (sigma - sigma_expected).norm<L_inf>();
+      ASSERT_NEAR(stress_error, 0., 1e-13);
+      ASSERT_NEAR(inelastic_strain_rot.norm<L_inf>(), 0., 1e-13);
+    } else if (t > t_P + dt) {
+      // skip the transition from non plastic to plastic
+
+      auto delta_lambda_expected =
+          dt / t * previous_sigma.doubleDot(grad_u + grad_u.transpose()) / 2.;
+      auto delta_inelastic_strain_expected =
+          delta_lambda_expected * 3. / 2. / sigma_0 * previous_sigma;
+      auto inelastic_strain_expected =
+          delta_inelastic_strain_expected + previous_inelastic_strain;
+      ASSERT_NEAR((inelastic_strain - inelastic_strain_expected).norm<L_inf>(),
+                  0., 1e-13);
+      auto delta_sigma_expected =
+          2. * shear_modulus_mu *
+          (0.5 * dt / t * (grad_u + grad_u.transpose()) -
+           delta_inelastic_strain_expected);
+
+      auto delta_sigma = sigma - previous_sigma;
+      ASSERT_NEAR((delta_sigma_expected - delta_sigma).norm<L_inf>(), 0.,
+                  1e-13);
+    }
+    previous_sigma = sigma;
+    previous_sigma_rot = sigma_rot;
+    previous_grad_u_rot = grad_u_rot;
+    previous_inelastic_strain = inelastic_strain;
+    previous_inelastic_strain_rot = inelastic_strain_rot;
+  }
+}
 
 namespace {
 
 template <typename T>
 class TestPlasticMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestPlasticMaterialFixture, types);
 
 TYPED_TEST(TestPlasticMaterialFixture, DISABLED_ComputeStress) {
   this->material->testComputeStress();
 }
 TYPED_TEST(TestPlasticMaterialFixture, DISABLED_EnergyDensity) {
   this->material->testEnergyDensity();
 }
 TYPED_TEST(TestPlasticMaterialFixture, DISABLED_ComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
-TYPED_TEST(TestPlasticMaterialFixture, DISABLED_ComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
-}
-TYPED_TEST(TestPlasticMaterialFixture, DISABLED_ComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
+TYPED_TEST(TestPlasticMaterialFixture, DISABLED_ComputeCelerity) {
+  this->material->testCelerity();
 }
 }
 
 /*****************************************************************/
diff --git a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc
index 2be5f8e32..fb0bfad88 100644
--- a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc
+++ b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc
@@ -1,314 +1,314 @@
 /**
  * @file   test_solid_mechanics_model_cube3d.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  *
  * @date creation: Wed Aug 04 2010
  * @date last modification: Thu Aug 06 2015
  *
  * @brief  test of the class SolidMechanicsModel on the 3d cube
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "boundary_condition_functor.hh"
 #include "test_solid_mechanics_model_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 namespace {
 
 const Real A = 1e-1;
 const Real E = 1.;
 const Real poisson = 3. / 10;
 const Real lambda = E * poisson / (1 + poisson) / (1 - 2 * poisson);
 const Real mu = E / 2 / (1. + poisson);
 const Real rho = 1.;
 const Real cp = std::sqrt((lambda + 2 * mu) / rho);
 const Real cs = std::sqrt(mu / rho);
 const Real c = std::sqrt(E / rho);
 
 const Vector<Real> k = {.5, 0., 0.};
 const Vector<Real> psi1 = {0., 0., 1.};
 const Vector<Real> psi2 = {0., 1., 0.};
 const Real knorm = k.norm();
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim> struct Verification {};
 
 /* -------------------------------------------------------------------------- */
 template <> struct Verification<1> {
   void displacement(Vector<Real> & disp, const Vector<Real> & coord,
                     Real current_time) {
     const auto & x = coord(_x);
     const Real omega = c * k[0];
     disp(_x) = A * cos(k[0] * x - omega * current_time);
   }
 
   void velocity(Vector<Real> & vel, const Vector<Real> & coord,
                 Real current_time) {
     const auto & x = coord(_x);
     const Real omega = c * k[0];
     vel(_x) = omega * A * sin(k[0] * x - omega * current_time);
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct Verification<2> {
   void displacement(Vector<Real> & disp, const Vector<Real> & X,
                     Real current_time) {
     Vector<Real> kshear = {k[1], k[0]};
     Vector<Real> kpush = {k[0], k[1]};
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     disp = A * (kpush * cos(phase_p) + kshear * cos(phase_s));
   }
 
   void velocity(Vector<Real> & vel, const Vector<Real> & X, Real current_time) {
     Vector<Real> kshear = {k[1], k[0]};
     Vector<Real> kpush = {k[0], k[1]};
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     vel =
         A * (kpush * omega_p * cos(phase_p) + kshear * omega_s * cos(phase_s));
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct Verification<3> {
   void displacement(Vector<Real> & disp, const Vector<Real> & coord,
                     Real current_time) {
     const auto & X = coord;
     Vector<Real> kpush = k;
     Vector<Real> kshear1(3);
     Vector<Real> kshear2(3);
     kshear1.crossProduct(k, psi1);
     kshear2.crossProduct(k, psi2);
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     disp = A * (kpush * cos(phase_p) + kshear1 * cos(phase_s) +
                 kshear2 * cos(phase_s));
   }
 
   void velocity(Vector<Real> & vel, const Vector<Real> & coord,
                 Real current_time) {
     const auto & X = coord;
     Vector<Real> kpush = k;
     Vector<Real> kshear1(3);
     Vector<Real> kshear2(3);
     kshear1.crossProduct(k, psi1);
     kshear2.crossProduct(k, psi2);
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     vel =
         A * (kpush * omega_p * cos(phase_p) + kshear1 * omega_s * cos(phase_s) +
              kshear2 * omega_s * cos(phase_s));
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <ElementType _type>
 class SolutionFunctor : public BC::Dirichlet::DirichletFunctor {
 public:
   SolutionFunctor(Real current_time, SolidMechanicsModel & model)
       : current_time(current_time), model(model) {}
 
 public:
   static constexpr UInt dim = ElementClass<_type>::getSpatialDimension();
 
   inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal,
                          const Vector<Real> & coord) const {
     flags(0) = true;
     auto & vel = model.getVelocity();
     auto it = vel.begin(model.getSpatialDimension());
     Vector<Real> v = it[node];
 
     Verification<dim> verif;
     verif.displacement(primal, coord, current_time);
     verif.velocity(v, coord, current_time);
   }
 
 private:
   Real current_time;
   SolidMechanicsModel & model;
 };
 
 /* -------------------------------------------------------------------------- */
 // This fixture uses somewhat finer meshes representing bars.
 template <typename type_>
 class TestSMMFixtureBar
     : public TestSMMFixture<std::tuple_element_t<0, type_>> {
   using parent = TestSMMFixture<std::tuple_element_t<0, type_>>;
 
 public:
   void SetUp() override {
     this->mesh_file = "../patch_tests/data/bar" + aka::to_string(this->type) + ".msh";
     parent::SetUp();
 
     getStaticParser().parse("test_solid_mechanics_model_"
                             "dynamics_material.dat");
 
     auto analysis_method = std::tuple_element_t<1, type_>::value;
     this->model->initFull(_analysis_method = analysis_method);
 
     if (this->dump_paraview) {
       std::stringstream base_name;
       base_name << "bar" << analysis_method << this->type;
       this->model->setBaseName(base_name.str());
       this->model->addDumpFieldVector("displacement");
       this->model->addDumpField("mass");
       this->model->addDumpField("velocity");
       this->model->addDumpField("acceleration");
       this->model->addDumpFieldVector("external_force");
       this->model->addDumpFieldVector("internal_force");
       this->model->addDumpField("stress");
       this->model->addDumpField("strain");
     }
 
     time_step = this->model->getStableTimeStep() / 10.;
     this->model->setTimeStep(time_step);
     // std::cout << "timestep: " << time_step << std::endl;
 
     const auto & position = this->mesh->getNodes();
     auto & displacement = this->model->getDisplacement();
     auto & velocity = this->model->getVelocity();
 
     constexpr auto dim = parent::spatial_dimension;
 
     Verification<dim> verif;
 
     for (auto && tuple :
          zip(make_view(position, dim), make_view(displacement, dim),
              make_view(velocity, dim))) {
       verif.displacement(std::get<1>(tuple), std::get<0>(tuple), 0.);
       verif.velocity(std::get<2>(tuple), std::get<0>(tuple), 0.);
     }
 
     if (dump_paraview)
       this->model->dump();
 
     /// boundary conditions
     this->model->applyBC(SolutionFunctor<parent::type>(0., *this->model), "BC");
 
     wave_velocity = 1.; // sqrt(E/rho) = sqrt(1/1) = 1
     simulation_time = 5 / wave_velocity;
 
     max_steps = simulation_time / time_step; // 100
     auto ndump = 50;
     dump_freq = max_steps / ndump;
   }
 
 protected:
   Real time_step;
   Real wave_velocity;
   Real simulation_time;
   UInt max_steps;
   UInt dump_freq;
   bool dump_paraview{false};
 };
 
 template <AnalysisMethod t>
 using analysis_method_t = std::integral_constant<AnalysisMethod, t>;
 
 #ifdef AKANTU_IMPLICIT
 using TestAnalysisTypes =
     std::tuple<analysis_method_t<_implicit_dynamic>, analysis_method_t<_explicit_lumped_mass>>;
 #else
 using TestAnalysisTypes = std::tuple<analysis_method_t<_explicit_lumped_mass>>;
 #endif
 
 using TestTypes =
     gtest_list_t<cross_product_t<TestElementTypes, TestAnalysisTypes>>;
 
 TYPED_TEST_CASE(TestSMMFixtureBar, TestTypes);
 
 /* -------------------------------------------------------------------------- */
 
 TYPED_TEST(TestSMMFixtureBar, DynamicsExplicit) {
   constexpr auto dim = TestFixture::spatial_dimension;
   Real current_time = 0.;
   const auto & position = this->mesh->getNodes();
   const auto & displacement = this->model->getDisplacement();
   UInt nb_nodes = this->mesh->getNbNodes();
   UInt nb_global_nodes = this->mesh->getNbGlobalNodes();
   Real max_error{0.};
 
   Array<Real> displacement_solution(nb_nodes, dim);
 
   Verification<dim> verif;
 
   for (UInt s = 0; s < this->max_steps; ++s, current_time += this->time_step) {
     if (s % this->dump_freq == 0 && this->dump_paraview)
       this->model->dump();
 
     /// boundary conditions
     this->model->applyBC(
         SolutionFunctor<TestFixture::type>(current_time, *this->model), "BC");
 
     // compute the disp solution
     for (auto && tuple :
          zip(make_view(position, dim), make_view(displacement_solution, dim))) {
       verif.displacement(std::get<1>(tuple), std::get<0>(tuple), current_time);
     }
 
     // compute the error solution
     Real disp_error = 0.;
     for (auto && tuple : zip(make_view(displacement, dim),
                              make_view(displacement_solution, dim))) {
       auto diff = std::get<1>(tuple) - std::get<0>(tuple);
       disp_error += diff.dot(diff);
     }
 
     this->mesh->getCommunicator().allReduce(disp_error,
                                             SynchronizerOperation::_sum);
 
     disp_error = sqrt(disp_error) / nb_global_nodes;
     max_error = std::max(disp_error, max_error);
 
-    ASSERT_NEAR(disp_error, 0., 1e-3);
+    ASSERT_NEAR(disp_error, 0., 2e-3);
 
     this->model->solveStep();
   }
   // std::cout << "max error: " << max_error << std::endl;
 }
 }
diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc
index b2d1070d9..21864217a 100644
--- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc
+++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc
@@ -1,99 +1,112 @@
 /**
  * @file   test_structural_mechanics_model_bernoulli_beam_2.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Computation of the analytical exemple 1.1 in the TGC vol 6
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "test_structural_mechanics_model_fixture.hh"
+#include "sparse_matrix.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 
 using namespace akantu;
 
 /* -------------------------------------------------------------------------- */
 class TestStructDKT18
     : public TestStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>> {
   using parent = TestStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>>;
 
 public:
   void addMaterials() override {
     mat.E = 1;
     mat.t = 1;
     mat.nu = 0.3;
 
     this->model->addMaterial(mat);
   }
 
   void assignMaterials() override {
     auto & materials = this->model->getElementMaterial(parent::type);
     std::fill(materials.begin(), materials.end(), 0);
   }
 
   void setDirichlets() override {
     this->model->getBlockedDOFs().set(true);
     auto center_node = this->model->getBlockedDOFs().end(parent::ndof) - 1;
     *center_node = {false, false, false, false, false, true};
 
     this->model->getDisplacement().clear();
     auto disp = ++this->model->getDisplacement().begin(parent::ndof);
 
     // Displacement field from Batoz Vol. 2 p. 392
     // with theta to beta correction from discrete Kirchhoff condition
+    // see also the master thesis of Michael Lozano
+
     // clang-format off
+
+    // This displacement field tests membrane and bending modes
     *disp = {40, 20, -800 , -20, 40, 0}; ++disp;
     *disp = {50, 40, -1400, -40, 50, 0}; ++disp;
     *disp = {10, 20, -200 , -20, 10, 0}; ++disp;
+
+    // This displacement tests the bending mode
+    // *disp = {0, 0, -800 , -20, 40, 0}; ++disp;
+    // *disp = {0, 0, -1400, -40, 50, 0}; ++disp;
+    // *disp = {0, 0, -200 , -20, 10, 0}; ++disp;
+
+    // This displacement tests the membrane mode
+    // *disp = {40, 20, 0, 0, 0, 0}; ++disp;
+    // *disp = {50, 40, 0, 0, 0, 0}; ++disp;
+    // *disp = {10, 20, 0, 0, 0, 0}; ++disp;
+
     // clang-format on
   }
 
   void setNeumanns() override {}
 
 protected:
   StructuralMaterial mat;
 };
 
 /* -------------------------------------------------------------------------- */
 
 // Batoz Vol 2. patch test, ISBN 2-86601-259-3
 TEST_F(TestStructDKT18, TestDisplacements) {
   model->solveStep();
   Vector<Real> solution = {22.5, 22.5, -337.5, -22.5, 22.5, 0};
   auto nb_nodes = this->model->getDisplacement().size();
 
   Vector<Real> center_node_disp =
       model->getDisplacement().begin(solution.size())[nb_nodes - 1];
 
   auto error = solution - center_node_disp;
-  std::cout << center_node_disp << std::endl;
-
-  Real tol = Math::getTolerance();
 
-  EXPECT_NEAR(error.norm<L_2>(), 0., tol);
+  EXPECT_NEAR(error.norm<L_2>(), 0., 1e-12);
 }