diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1e61617367ab0bf20663ce8d6510ae1386700d31
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/CMakeLists.txt
@@ -0,0 +1,6 @@
+project(my_first_test)
+cmake_minimum_required(VERSION 3.0.0)
+
+find_package(Akantu REQUIRED)
+
+add_akantu_simulation(clip_compute_damage clip_compute_damage.cc material.dat square.msh)
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/clip_compute_damage.cc b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/clip_compute_damage.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8995d5966a72962e1a1bb942ca8990557c26ff92
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/clip_compute_damage.cc
@@ -0,0 +1,112 @@
+/**
+ * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 <chrono>
+#include <iostream>
+#include "data_accessor.hh"
+#include "mesh.hh"
+#include "mesh_accessor.hh"
+//#include "mesh_partition_scotch.hh"
+#include "periodic_node_synchronizer.hh"
+/* -------------------------------------------------------------------------- */
+#include "dumpable_inline_impl.hh"
+//#include "dumper_element_partition.hh"
+#include "dumper_iohelper_paraview.hh"
+/* -------------------------------------------------------------------------- */
+#include "solid_mechanics_model_clip.hh"
+
+
+using namespace akantu;
+
+class init 
+{
+  public:
+  init(Real lc_, Real xmid_):lc(lc_),xmid(xmid_) {}
+  
+  Real operator()(const Vector<Real> & coords)
+  {
+    Real d = std::max(0.,1.-std::abs(coords[0])/lc);
+    return d;
+  }
+  private:
+  Real lc;
+  Real xmid;
+};
+
+int main(int argc, char ** argv) {
+  initialize("material.dat", argc, argv);
+  
+  Real lc = 1.;
+  Real xmid = 0.;
+  init initializer(lc,xmid);
+
+  constexpr Int dim = 2;
+
+  Mesh mesh(dim);
+  mesh.read("square_fine.msh");
+  std::cout << "Initiate SolidMechanicsModelCLIP ... " << std::endl ;
+  SolidMechanicsModelCLIP model(mesh,dim);
+  model.getElementInserter().setLimit(_x, -1., 1.);
+  model.getElementInserter().setLimit(_y, -1., 1.);
+  // model.getMaterial(1).setReal("lc", lc);
+  auto start = std::chrono::high_resolution_clock::now();
+  std::cout << "done initiate SolidMechanicsModelCLIP ! " << std::endl ;
+
+  /// model initialization
+  model.initFull(_analysis_method = _explicit_lumped_mass
+                 ,_is_extrinsic = false);
+
+  model.setBaseName("cohesive");
+  model.addDumpFieldVector("displacement");
+  model.addDumpField("damage");
+  model.setBaseNameToDumper("cohesive elements", "cohesive_elements");
+  model.addDumpFieldToDumper("cohesive elements", "czm_damage");
+
+  model.setBaseNameToDumper("clip", "clip");
+  model.addDumpFieldToDumper("clip", "clip_bulk_damage");
+  model.addDumpFieldToDumper("clip", "clip_czm_damage");
+
+  
+  model.initializeCZMDamage(initializer);
+  model.dump();
+  model.dump("cohesive elements");
+
+  std::cout << "test computeBulkDamage ... " << std::endl ;
+   // Start timing
+  
+  model.initialize();
+  model.computeBulkDamage();
+  // model.solveStep();
+  // model.computeDamage();
+  auto end = std::chrono::high_resolution_clock::now();
+  std::chrono::duration<double> elapsed = end - start;
+  std::cout << "Elapsed time: " << elapsed.count() << " seconds" << std::endl;
+  
+  std::cout << "done computeBulkDamage ! " << std::endl ;
+
+  model.dump();
+  model.dump("cohesive elements");
+  model.dump("clip");
+
+  finalize();
+  return EXIT_SUCCESS;
+  
+}
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/material.dat b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/material.dat
new file mode 100644
index 0000000000000000000000000000000000000000..70ca9ae3dba48f97d414ca1142bb8a07d3f07b6b
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/material.dat
@@ -0,0 +1,20 @@
+material bulk_damage [
+	 name = bulk
+	 rho = 275   # density
+	 E   = 3e9   # young's modulus
+	 nu  = 0.001 # poisson's ratio
+	 sigma_c = 3e6
+	 G_c = 120
+	 lc = 0.0125
+     Dm = 0.1
+]
+
+material cohesive_damage_extrinsic [
+	 name = cohesive
+         sigma_c = 3e6
+		 E = 3e9
+         k = 75000000000.0
+         G_c = 120
+		 lc = 0.0125
+		 Dm = 0.1
+]
\ No newline at end of file
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.geo b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.geo
new file mode 100644
index 0000000000000000000000000000000000000000..7aa44974a3d67e104832ed16d6bf826d9b4c27f6
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.geo
@@ -0,0 +1,27 @@
+h = 0.01;
+L = 1;
+
+Point(1) = { L, 0.1*L, 0, h};
+Point(2) = {0., 0.1*L, 0, h};
+Point(3) = {0.,0., 0, h};
+Point(4) = {L,0., 0, h};
+
+Line(1) = {1, 2};
+Line(2) = {2, 3};
+Line(3) = {3, 4};
+Line(4) = {4, 1};
+
+Line Loop(5) = {1, 2, 3, 4};
+
+Plane Surface(6) = {5};
+Physical Surface(7) = {6};
+
+Transfinite Line {2, 4} = 2;
+Transfinite Line {1, 3} = 51;
+Transfinite Surface "*";
+Physical Curve("left", 8) = {2};
+Physical Curve("right", 9) = {4};
+Physical Point("point", 10) = {3};
+Physical Curve("bottom", 11) = {3};
+Physical Curve("top", 12) = {1};
+
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.msh b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.msh
new file mode 100644
index 0000000000000000000000000000000000000000..05c846b87358d88e45407c688ec12f514c9112c7
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.msh
@@ -0,0 +1,34 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$PhysicalNames
+3
+0 10 "point"
+1 8 "left"
+1 9 "right"
+$EndPhysicalNames
+$Nodes
+8
+1 1 1 0
+2 -1 1 0
+3 -1 -1 0
+4 1 -1 0
+5 2.750244476601438e-12 1 0
+6 -2.750244476601438e-12 -1 0
+7 -0.2845299461618773 0 0
+8 0.3430940107676245 -2.220446049250313e-17 0
+$EndNodes
+$Elements
+11
+1 15 2 10 3 3
+2 1 2 8 2 2 3
+3 1 2 9 4 4 1
+4 2 2 7 6 3 6 7
+5 2 2 7 6 7 6 8
+6 2 2 7 6 6 4 8
+7 2 2 7 6 5 7 8
+8 2 2 7 6 1 5 8
+9 2 2 7 6 5 2 7
+10 2 2 7 6 4 1 8
+11 2 2 7 6 2 3 7
+$EndElements
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..38f887790a8b9c057ad085ecbf535c8ac60de19e
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/CMakeLists.txt
@@ -0,0 +1,28 @@
+#===============================================================================
+# Copyright (©) 2018-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+#
+# This file is part of Akantu
+# 
+# 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/>.
+#
+#===============================================================================
+
+add_mesh(square square.geo DIM 2 ORDER 1)
+
+register_test(clip_mesh
+  SOURCES clip_mesh.cc
+  DEPENDS square 
+  PACKAGE core
+  UNSTABLE)
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/clip_mesh.cc b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/clip_mesh.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8e7753da8d4554f52bdafbdbc76c0a51eeb20027
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/clip_mesh.cc
@@ -0,0 +1,129 @@
+/**
+ * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "data_accessor.hh"
+#include "mesh.hh"
+#include "mesh_accessor.hh"
+//#include "mesh_partition_scotch.hh"
+#include "periodic_node_synchronizer.hh"
+/* -------------------------------------------------------------------------- */
+#include "dumpable_inline_impl.hh"
+//#include "dumper_element_partition.hh"
+#include "dumper_iohelper_paraview.hh"
+/* -------------------------------------------------------------------------- */
+#include "gmsh.h"
+
+
+using namespace akantu;
+
+int main(int argc, char ** argv) {
+  initialize(argc, argv);
+
+  constexpr Int dim = 2;
+
+  Mesh mesh(dim);
+  mesh.read("square.msh");
+  Mesh clip_mesh(dim);
+
+  MeshAccessor mesh_accessor(mesh);
+  MeshAccessor mesh_accessor_clip(clip_mesh);
+
+  auto & clip_nodes = mesh_accessor_clip.getNodes();
+  auto & clip_connectivities = mesh_accessor_clip.getConnectivities();
+
+  Mesh & mesh_facets = mesh.initMeshFacets();
+  MeshAccessor mesh_accessor_facets(mesh_facets);
+  // auto & facet_connectivities = mesh_accessor_facets.getConnectivities();
+
+  ElementTypeMapArray<Real> barycenters;
+  Int nb_clip_nodes(0);
+  barycenters.initialize(mesh_facets, _nb_component = dim,
+                         _spatial_dimension = dim-1,
+                         _with_nb_element = true);
+
+  for (auto && ghost_type : ghost_types) {
+    for (auto && type :
+         barycenters.elementTypes(dim-1,ghost_type)) {
+      mesh_facets.getBarycenters(barycenters(type, ghost_type),type,
+                                  ghost_type);
+      nb_clip_nodes+=mesh_facets.getNbElement(type, ghost_type);
+    }
+  }
+
+  mesh_accessor_clip.resizeNodes(nb_clip_nodes);
+
+  auto && view_clip_nodes = make_view(clip_nodes,dim);
+  auto clip_nodes_it = view_clip_nodes.begin();
+
+  std::vector<double> coord;
+  for (auto && ghost_type : ghost_types) {
+   for (auto && type :
+        barycenters.elementTypes(dim-1,ghost_type)) {
+     auto & barycenter = barycenters(type,ghost_type);
+     auto && view_bar =
+         make_view(barycenter, barycenter.getNbComponent());
+     for(auto && bar : view_bar) {
+     *clip_nodes_it=bar;
+     ++clip_nodes_it;
+     for(Int i=0; i<dim;++i)
+     {
+      coord.push_back(bar[i]);
+     }
+     }
+   }
+  }
+  // for(auto it=view_clip_nodes.begin();it!=view_clip_nodes.end();++it)
+  // {
+  //   std::cout << "node = " << *it << std::endl;
+  // } 
+  std::cout << "n_nodes = " << coord.size() << std::endl;
+
+  std::vector<std::size_t> tri;
+  gmsh::initialize();
+  gmsh::model::mesh::triangulate(coord,tri);
+  int n_tri = tri.size()/3;
+  std::cout << "n_tri = " << n_tri << std::endl ;
+  
+  for (auto && ghost_type : ghost_types) {
+    clip_mesh.addConnectivityType(_triangle_3, ghost_type);
+    mesh_accessor_clip.resizeConnectivity(n_tri,_triangle_3, ghost_type);
+    auto & clip_conn = clip_connectivities(_triangle_3, ghost_type);
+    auto && view_conn_it = make_view(clip_conn, clip_conn.getNbComponent()).begin();
+    for(int i = 0 ; i<n_tri; ++i, ++view_conn_it)
+    {
+      for(int j = 0; j<3;++j) {
+        (*view_conn_it)[j]=tri[3*i+j]-1;
+        // std::cout << tri[i+3*j] << " " << std::endl;
+      }
+      // std::cout << std::endl;
+    }
+  }
+
+  
+  // auto * dumper = new DumperParaview("clip_mesh", "./paraview");
+  // mesh.registerExternalDumper(*dumper, "clip_mesh", true);
+  // mesh.addDumpMesh(clip_mesh);
+  // mesh.dump();
+
+  mesh_accessor_clip.makeReady();
+  clip_mesh.write("clip_mesh.msh");
+  
+}
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.geo b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.geo
new file mode 100644
index 0000000000000000000000000000000000000000..3f21d3ffc8c9abbabd401ecc62d05ba8f6cb6b17
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.geo
@@ -0,0 +1,21 @@
+h = .1;
+
+Point(1) = { 1, 1, 0, h};
+Point(2) = {-1, 1, 0, h};
+Point(3) = {-1,-1, 0, h};
+Point(4) = { 1,-1, 0, h};
+Line(1) = {1, 2};
+Line(2) = {2, 3};
+Line(3) = {3, 4};
+Line(4) = {4, 1};
+Line Loop(5) = {1, 2, 3, 4};
+Plane Surface(6) = {5};
+// Transfinite Surface {7} = 6;
+Physical Surface(7) = {6};
+
+Transfinite Line {2, 4} = 1;
+Transfinite Line {1, 3} = 3;
+
+Physical Curve("left", 8) = {2};
+Physical Curve("right", 9) = {4};
+Physical Point("point", 10) = {3};
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.msh b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.msh
new file mode 100644
index 0000000000000000000000000000000000000000..05c846b87358d88e45407c688ec12f514c9112c7
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.msh
@@ -0,0 +1,34 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$PhysicalNames
+3
+0 10 "point"
+1 8 "left"
+1 9 "right"
+$EndPhysicalNames
+$Nodes
+8
+1 1 1 0
+2 -1 1 0
+3 -1 -1 0
+4 1 -1 0
+5 2.750244476601438e-12 1 0
+6 -2.750244476601438e-12 -1 0
+7 -0.2845299461618773 0 0
+8 0.3430940107676245 -2.220446049250313e-17 0
+$EndNodes
+$Elements
+11
+1 15 2 10 3 3
+2 1 2 8 2 2 3
+3 1 2 9 4 4 1
+4 2 2 7 6 3 6 7
+5 2 2 7 6 7 6 8
+6 2 2 7 6 6 4 8
+7 2 2 7 6 5 7 8
+8 2 2 7 6 1 5 8
+9 2 2 7 6 5 2 7
+10 2 2 7 6 4 1 8
+11 2 2 7 6 2 3 7
+$EndElements
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6cb8ab9312bde21bfd8538d1bb27fa2ad03f7107
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/CMakeLists.txt
@@ -0,0 +1,28 @@
+#===============================================================================
+# Copyright (©) 2018-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+#
+# This file is part of Akantu
+# 
+# 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/>.
+#
+#===============================================================================
+
+add_mesh(square square.geo DIM 2 ORDER 1)
+
+register_test(clip_compute_damage
+  SOURCES clip_compute_damage.cc
+  DEPENDS square 
+  PACKAGE core
+  UNSTABLE)
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/clip_non_local.cc b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/clip_non_local.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6a4c31a18b8126b6164b53790963e0f1becc58f6
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/clip_non_local.cc
@@ -0,0 +1,97 @@
+/**
+ * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "data_accessor.hh"
+#include "mesh.hh"
+#include "mesh_accessor.hh"
+/* -------------------------------------------------------------------------- */
+#include "solid_mechanics_model_clip.hh"
+
+
+using namespace akantu;
+
+class init 
+{
+  public:
+  init(Real lc_, Real xmid_):lc(lc_),xmid(xmid_) {}
+  Real operator()(const Vector<Real> & coords)
+  {
+    if(std::abs(coords[0]) < 0.1*lc) 
+    {
+      return 1.;
+    }
+    else
+    {
+      return 0.;
+    }
+  }
+  private:
+  Real lc;
+  Real xmid;
+};
+
+int main(int argc, char ** argv) {
+  initialize("material.dat", argc, argv);
+  
+  Real lc = 1.;
+  Real xmid = 0.;
+  init initializer(lc,xmid);
+
+  constexpr Int dim = 2;
+
+  Mesh mesh(dim);
+  mesh.read("square.msh");
+  std::cout << "Initiate SolidMechanicsModelCLIP ... " << std::endl ;
+  SolidMechanicsModelCLIP model(mesh,dim);
+  model.getElementInserter().setLimit(_x, -1., 1.);
+  model.getElementInserter().setLimit(_y, -1., 1.);
+
+  std::cout << "done initiate SolidMechanicsModelCLIP ! " << std::endl ;
+
+  /// model initialization
+  model.initFull(_analysis_method = _explicit_lumped_mass
+                 ,_is_extrinsic = false);
+
+  model.setBaseName("cohesive");
+  model.addDumpFieldVector("displacement");
+  model.addDumpField("damage");
+  model.setBaseNameToDumper("cohesive elements", "cohesive_elements");
+  model.addDumpFieldToDumper("cohesive elements", "czm_damage");
+
+  model.setBaseNameToDumper("clip", "clip");
+  model.addDumpFieldToDumper("clip", "clip_bulk_damage");
+  model.addDumpFieldToDumper("clip", "clip_czm_damage");
+
+  model.initializeCZMDamage(initializer);
+
+  model.assembleInternalForces();
+
+  // model.dump();
+  // model.dump("cohesive elements");
+
+  // model.dump();
+  // model.dump("cohesive elements");
+  // model.dump("clip");
+
+  finalize();
+  return EXIT_SUCCESS;
+  
+}
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/material.dat b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/material.dat
new file mode 100644
index 0000000000000000000000000000000000000000..2eb2461b92e451dca4e841460a2656e819bae72a
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/material.dat
@@ -0,0 +1,20 @@
+material bulk_damage_non_local [
+	 name = bulk
+	 rho = 1e3   # density
+	 E   = 1e3   # young's modulus
+	 nu  = 0.001 # poisson's ratio
+]
+
+material cohesive_damage_non_local [
+	 name = cohesive
+         sigma_c = 3e6
+         k = 75e9
+         G_c = 120
+]
+
+non_local clip base_dist [
+	  radius       = 0.01
+	  Dm = 0.8
+	  distance_function distance_parameter []	  
+]
+
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.geo b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.geo
new file mode 100644
index 0000000000000000000000000000000000000000..6a9251b7df87bc9d93906feb857764da79b69b1e
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.geo
@@ -0,0 +1,21 @@
+h = .2;
+
+Point(1) = { 1, 1, 0, h};
+Point(2) = {-1, 1, 0, h};
+Point(3) = {-1,-1, 0, h};
+Point(4) = { 1,-1, 0, h};
+Line(1) = {1, 2};
+Line(2) = {2, 3};
+Line(3) = {3, 4};
+Line(4) = {4, 1};
+Line Loop(5) = {1, 2, 3, 4};
+Plane Surface(6) = {5};
+// Transfinite Surface {7} = 6;
+Physical Surface(7) = {6};
+
+//Transfinite Line {2, 4} = 1;
+//Transfinite Line {1, 3} = 3;
+
+Physical Curve("left", 8) = {2};
+Physical Curve("right", 9) = {4};
+Physical Point("point", 10) = {3};
diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.msh b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.msh
new file mode 100644
index 0000000000000000000000000000000000000000..d608af215b65228be190ac0cab469aa0778432df
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.msh
@@ -0,0 +1,426 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$PhysicalNames
+3
+0 10 "point"
+1 8 "left"
+1 9 "right"
+$EndPhysicalNames
+$Nodes
+144
+1 1 1 0
+2 -1 1 0
+3 -1 -1 0
+4 1 -1 0
+5 0.8000000000005548 1 0
+6 0.6000000000011096 1 0
+7 0.4000000000016644 1 0
+8 0.2000000000022192 1 0
+9 2.752242878045763e-12 1 0
+10 -0.1999999999977808 1 0
+11 -0.3999999999983355 1 0
+12 -0.5999999999988903 1 0
+13 -0.7999999999994454 1 0
+14 -1 0.8000000000005548 0
+15 -1 0.6000000000011096 0
+16 -1 0.4000000000016644 0
+17 -1 0.2000000000022192 0
+18 -1 2.752242878045763e-12 0
+19 -1 -0.1999999999977808 0
+20 -1 -0.3999999999983355 0
+21 -1 -0.5999999999988903 0
+22 -1 -0.7999999999994454 0
+23 -0.8000000000005548 -1 0
+24 -0.6000000000011096 -1 0
+25 -0.4000000000016644 -1 0
+26 -0.2000000000022192 -1 0
+27 -2.752242878045763e-12 -1 0
+28 0.1999999999977808 -1 0
+29 0.3999999999983355 -1 0
+30 0.5999999999988903 -1 0
+31 0.7999999999994454 -1 0
+32 1 -0.8000000000005548 0
+33 1 -0.6000000000011096 0
+34 1 -0.4000000000016644 0
+35 1 -0.2000000000022192 0
+36 1 -2.752242878045763e-12 0
+37 1 0.1999999999977808 0
+38 1 0.3999999999983355 0
+39 1 0.5999999999988903 0
+40 1 0.7999999999994454 0
+41 0.09999999999751429 -0.8267949192431123 0
+42 -0.0999999999975143 0.8267949192431123 0
+43 -0.8152641451785186 -0.07885143852468808 0
+44 0.8304434373555855 0.09368058125465918 0
+45 0.3000000000017492 0.8267949192434423 0
+46 -0.8222913958556177 0.301840399804423 0
+47 -0.3000000000019418 -0.8267949192435928 0
+48 0.8267949192435928 -0.3000000000019418 0
+49 -0.4983653964756185 0.8277386580263953 0
+50 -0.8474033730928048 -0.4965246177615327 0
+51 0.4919576064632172 -0.840815486206938 0
+52 0.820740775008972 0.5173451309406248 0
+53 0.6991525261446221 0.8306455909891675 0
+54 -0.6891118908206922 -0.8090094343789862 0
+55 -0.81886055051106 0.6816348761887513 0
+56 0.8341005191704839 -0.698813536602138 0
+57 -0.2997275660773219 0.8269522090402291 0
+58 -0.1999545943440471 0.6536160534525139 0
+59 7.567611085503948e-06 0.6535942076475989 0
+60 -0.09999117112044205 0.4803898550844917 0
+61 0.1000027327496564 0.4803863354826932 0
+62 1.926939795782179e-06 0.3071807894914093 0
+63 -0.2006679354644429 0.3079248201300853 0
+64 -0.1014219475707913 0.1348264734253454 0
+65 0.09976332989618426 0.1341167611715012 0
+66 -0.0002764362773821823 -0.03906481084559155 0
+67 0.1999144822710444 -0.03917917809790765 0
+68 -0.201594010124382 -0.03833339145989768 0
+69 -0.1003117410650043 -0.2122584375003307 0
+70 -0.2983971709787789 -0.211147753724287 0
+71 0.2999463020288573 0.1340068414498632 0
+72 0.4089084371318499 -0.03267814517071942 0
+73 0.3014704865684335 -0.2113349576607175 0
+74 -0.4021165753759368 -0.03843604351766587 0
+75 -0.1997848186717709 -0.3853964894912181 0
+76 -0.3947386321509533 -0.3860304825270545 0
+77 -1.609328773086172e-05 -0.3855704319928288 0
+78 -0.09999999999686258 -0.558845726808855 0
+79 0.5032249595933229 0.1402606472768321 0
+80 0.4005285436045737 0.308232726355823 0
+81 0.5070716218789619 -0.2025490658234078 0
+82 0.4000000000016977 -0.3856406460521801 0
+83 0.6000000000009191 0.3071796769738866 0
+84 0.4942868204123083 0.4772109010552537 0
+85 0.1000000000026652 -0.5588457268086711 0
+86 0.62196210851684 -0.3904927803711393 0
+87 0.4975474734247751 -0.5568744827875467 0
+88 -0.3996745928146653 0.6537777124103196 0
+89 -0.6011821531096809 0.6593963523377666 0
+90 -0.5001427909848405 0.482115766704055 0
+91 -0.7010121778846208 0.4863202964944682 0
+92 -0.6065140164046823 0.3069727224290131 0
+93 -0.7049870583211724 0.1193783134563418 0
+94 -0.5077207049162372 0.1295170451519014 0
+95 -0.598774899089267 -0.0522329575172658 0
+96 -0.6740836360500956 -0.2392227049285593 0
+97 -0.302253528907891 0.1345117077962618 0
+98 0.2999999999981645 -0.8267949192426931 0
+99 0.7988367911987242 0.3057967778574708 0
+100 0.20000171672785 0.6535908296389998 0
+101 -0.1000000000021191 -0.8267949192431698 0
+102 0.8315481940282681 -0.1010532364594917 0
+103 0.6335912237475191 -0.02003653305503406 0
+104 0.100001547391357 0.8267958126288588 0
+105 -0.2999999999963751 -0.5588457268090072 0
+106 -0.4999999999960433 -0.5588457268092286 0
+107 0.4998587543585607 0.8274366978677389 0
+108 -0.491800230084482 -0.8369074999460275 0
+109 0.8264939634898354 -0.4982177194965171 0
+110 0.6302412295336577 0.6366727295001388 0
+111 0.1001301163685956 -0.2121747436915847 0
+112 0.2000404725367574 0.3073847019469172 0
+113 0.299143381005376 0.480065888827752 0
+114 0.4039219836732503 0.6502953276888875 0
+115 0.2002640849426297 -0.3854020388357766 0
+116 0.3000000000021172 -0.5588457268086774 0
+117 -0.300071847453999 0.4815659251382113 0
+118 -0.4028951373553488 0.3071013312249213 0
+119 -0.6938642437921219 0.8357449249653118 0
+120 -0.8443586096716835 -0.6931320786098996 0
+121 0.6881867797212334 -0.8122913120462014 0
+122 0.8335264302193998 0.7017517856175469 0
+123 -0.4900946041198567 -0.2133115496794405 0
+124 -0.8467162638363354 -0.2999999999980582 0
+125 -0.5773605825153454 -0.3977276319424348 0
+126 0.6761062340080962 -0.6000000000011095 0
+127 -0.6784462875602467 -0.5767637941719381 0
+128 0.6813857876547964 -0.2014420016043129 0
+129 -0.8684328248502595 0.4939591144980833 0
+130 0.1999999999975585 -0.6928203230278142 0
+131 0.3999999999983475 -0.6928203230271605 0
+132 -2.340797873689592e-12 -0.692820323027974 0
+133 -0.200000000001768 -0.6928203230279757 0
+134 -0.4000000000016648 -0.6928203230284052 0
+135 0.665192378864661 0.4602885682977754 0
+136 -0.8694874729372553 0.1000000000024857 0
+137 0.6732192823792142 0.1653762300615629 0
+138 0.8535898384868191 0.8535898384865219 0
+139 -0.8535898384865219 0.8535898384868191 0
+140 -0.8535898384868191 -0.8535898384865219 0
+141 0.8535898384865219 -0.8535898384868191 0
+142 -0.7292000671453386 -0.389286746676304 0
+143 -0.5518716816926258 -0.6948693556669171 0
+144 0.5507596187231338 -0.7005603208137912 0
+$EndNodes
+$Elements
+267
+1 15 2 10 3 3
+2 1 2 8 2 2 14
+3 1 2 8 2 14 15
+4 1 2 8 2 15 16
+5 1 2 8 2 16 17
+6 1 2 8 2 17 18
+7 1 2 8 2 18 19
+8 1 2 8 2 19 20
+9 1 2 8 2 20 21
+10 1 2 8 2 21 22
+11 1 2 8 2 22 3
+12 1 2 9 4 4 32
+13 1 2 9 4 32 33
+14 1 2 9 4 33 34
+15 1 2 9 4 34 35
+16 1 2 9 4 35 36
+17 1 2 9 4 36 37
+18 1 2 9 4 37 38
+19 1 2 9 4 38 39
+20 1 2 9 4 39 40
+21 1 2 9 4 40 1
+22 2 2 7 6 72 81 103
+23 2 2 7 6 110 52 122
+24 2 2 7 6 52 110 135
+25 2 2 7 6 48 86 109
+26 2 2 7 6 93 43 95
+27 2 2 7 6 89 55 91
+28 2 2 7 6 103 81 128
+29 2 2 7 6 109 86 126
+30 2 2 7 6 79 72 103
+31 2 2 7 6 43 93 136
+32 2 2 7 6 91 55 129
+33 2 2 7 6 91 46 92
+34 2 2 7 6 92 46 93
+35 2 2 7 6 86 48 128
+36 2 2 7 6 95 43 96
+37 2 2 7 6 53 110 122
+38 2 2 7 6 83 99 135
+39 2 2 7 6 55 89 119
+40 2 2 7 6 121 56 126
+41 2 2 7 6 86 87 126
+42 2 2 7 6 68 64 97
+43 2 2 7 6 92 94 118
+44 2 2 7 6 120 54 127
+45 2 2 7 6 99 83 137
+46 2 2 7 6 74 94 95
+47 2 2 7 6 99 52 135
+48 2 2 7 6 127 125 142
+49 2 2 7 6 94 97 118
+50 2 2 7 6 64 63 97
+51 2 2 7 6 74 68 97
+52 2 2 7 6 92 93 94
+53 2 2 7 6 121 126 144
+54 2 2 7 6 46 91 129
+55 2 2 7 6 74 95 123
+56 2 2 7 6 94 93 95
+57 2 2 7 6 94 74 97
+58 2 2 7 6 42 57 58
+59 2 2 7 6 44 37 99
+60 2 2 7 6 41 28 98
+61 2 2 7 6 42 10 57
+62 2 2 7 6 88 49 89
+63 2 2 7 6 9 10 42
+64 2 2 7 6 18 19 43
+65 2 2 7 6 27 28 41
+66 2 2 7 6 36 37 44
+67 2 2 7 6 100 45 104
+68 2 2 7 6 27 41 101
+69 2 2 7 6 36 44 102
+70 2 2 7 6 45 8 104
+71 2 2 7 6 47 26 101
+72 2 2 7 6 48 35 102
+73 2 2 7 6 57 49 88
+74 2 2 7 6 88 89 90
+75 2 2 7 6 9 42 104
+76 2 2 7 6 11 49 57
+77 2 2 7 6 38 52 99
+78 2 2 7 6 29 51 98
+79 2 2 7 6 110 107 114
+80 2 2 7 6 26 27 101
+81 2 2 7 6 35 36 102
+82 2 2 7 6 42 58 59
+83 2 2 7 6 10 11 57
+84 2 2 7 6 28 29 98
+85 2 2 7 6 37 38 99
+86 2 2 7 6 45 100 114
+87 2 2 7 6 8 9 104
+88 2 2 7 6 42 59 104
+89 2 2 7 6 90 89 91
+90 2 2 7 6 59 100 104
+91 2 2 7 6 90 91 92
+92 2 2 7 6 107 45 114
+93 2 2 7 6 20 21 50
+94 2 2 7 6 38 39 52
+95 2 2 7 6 11 12 49
+96 2 2 7 6 29 30 51
+97 2 2 7 6 102 44 103
+98 2 2 7 6 84 110 114
+99 2 2 7 6 59 58 60
+100 2 2 7 6 62 60 63
+101 2 2 7 6 65 64 66
+102 2 2 7 6 69 75 77
+103 2 2 7 6 65 66 67
+104 2 2 7 6 66 68 69
+105 2 2 7 6 58 57 88
+106 2 2 7 6 66 64 68
+107 2 2 7 6 62 64 65
+108 2 2 7 6 77 75 78
+109 2 2 7 6 71 67 72
+110 2 2 7 6 65 67 71
+111 2 2 7 6 7 8 45
+112 2 2 7 6 16 17 46
+113 2 2 7 6 25 26 47
+114 2 2 7 6 34 35 48
+115 2 2 7 6 62 63 64
+116 2 2 7 6 71 72 79
+117 2 2 7 6 66 69 111
+118 2 2 7 6 67 66 111
+119 2 2 7 6 77 78 85
+120 2 2 7 6 70 68 74
+121 2 2 7 6 69 77 111
+122 2 2 7 6 78 75 105
+123 2 2 7 6 69 70 75
+124 2 2 7 6 65 71 112
+125 2 2 7 6 61 60 62
+126 2 2 7 6 62 65 112
+127 2 2 7 6 59 61 100
+128 2 2 7 6 72 73 81
+129 2 2 7 6 81 82 86
+130 2 2 7 6 59 60 61
+131 2 2 7 6 61 62 112
+132 2 2 7 6 100 113 114
+133 2 2 7 6 6 7 107
+134 2 2 7 6 24 25 108
+135 2 2 7 6 33 34 109
+136 2 2 7 6 105 76 106
+137 2 2 7 6 7 45 107
+138 2 2 7 6 25 47 108
+139 2 2 7 6 72 67 73
+140 2 2 7 6 34 48 109
+141 2 2 7 6 69 68 70
+142 2 2 7 6 80 84 113
+143 2 2 7 6 71 79 80
+144 2 2 7 6 75 76 105
+145 2 2 7 6 61 112 113
+146 2 2 7 6 73 67 111
+147 2 2 7 6 100 61 113
+148 2 2 7 6 80 83 84
+149 2 2 7 6 75 70 76
+150 2 2 7 6 71 80 112
+151 2 2 7 6 77 85 115
+152 2 2 7 6 111 77 115
+153 2 2 7 6 112 80 113
+154 2 2 7 6 81 73 82
+155 2 2 7 6 5 6 53
+156 2 2 7 6 14 15 55
+157 2 2 7 6 23 24 54
+158 2 2 7 6 32 33 56
+159 2 2 7 6 88 90 117
+160 2 2 7 6 113 84 114
+161 2 2 7 6 86 82 87
+162 2 2 7 6 115 85 116
+163 2 2 7 6 80 79 83
+164 2 2 7 6 73 111 115
+165 2 2 7 6 53 107 110
+166 2 2 7 6 53 6 107
+167 2 2 7 6 54 24 108
+168 2 2 7 6 56 33 109
+169 2 2 7 6 60 58 117
+170 2 2 7 6 82 73 115
+171 2 2 7 6 82 115 116
+172 2 2 7 6 63 60 117
+173 2 2 7 6 58 88 117
+174 2 2 7 6 87 82 116
+175 2 2 7 6 106 125 127
+176 2 2 7 6 95 96 123
+177 2 2 7 6 76 123 125
+178 2 2 7 6 127 54 143
+179 2 2 7 6 97 63 118
+180 2 2 7 6 90 92 118
+181 2 2 7 6 63 117 118
+182 2 2 7 6 96 43 124
+183 2 2 7 6 117 90 118
+184 2 2 7 6 89 49 119
+185 2 2 7 6 12 13 119
+186 2 2 7 6 21 22 120
+187 2 2 7 6 30 31 121
+188 2 2 7 6 39 40 122
+189 2 2 7 6 76 70 123
+190 2 2 7 6 123 96 125
+191 2 2 7 6 43 19 124
+192 2 2 7 6 20 50 124
+193 2 2 7 6 93 46 136
+194 2 2 7 6 102 103 128
+195 2 2 7 6 81 86 128
+196 2 2 7 6 50 21 120
+197 2 2 7 6 52 39 122
+198 2 2 7 6 49 12 119
+199 2 2 7 6 51 30 121
+200 2 2 7 6 70 74 123
+201 2 2 7 6 16 46 129
+202 2 2 7 6 55 15 129
+203 2 2 7 6 110 84 135
+204 2 2 7 6 18 43 136
+205 2 2 7 6 46 17 136
+206 2 2 7 6 44 99 137
+207 2 2 7 6 40 1 138
+208 2 2 7 6 13 2 139
+209 2 2 7 6 22 3 140
+210 2 2 7 6 31 4 141
+211 2 2 7 6 1 5 138
+212 2 2 7 6 2 14 139
+213 2 2 7 6 3 23 140
+214 2 2 7 6 4 32 141
+215 2 2 7 6 50 127 142
+216 2 2 7 6 19 20 124
+217 2 2 7 6 106 76 125
+218 2 2 7 6 56 109 126
+219 2 2 7 6 48 102 128
+220 2 2 7 6 79 103 137
+221 2 2 7 6 50 120 127
+222 2 2 7 6 54 108 143
+223 2 2 7 6 83 79 137
+224 2 2 7 6 116 130 131
+225 2 2 7 6 132 78 133
+226 2 2 7 6 130 85 132
+227 2 2 7 6 78 105 133
+228 2 2 7 6 85 78 132
+229 2 2 7 6 105 106 134
+230 2 2 7 6 133 105 134
+231 2 2 7 6 116 85 130
+232 2 2 7 6 15 16 129
+233 2 2 7 6 87 116 131
+234 2 2 7 6 41 98 130
+235 2 2 7 6 130 98 131
+236 2 2 7 6 101 132 133
+237 2 2 7 6 98 51 131
+238 2 2 7 6 41 130 132
+239 2 2 7 6 47 101 133
+240 2 2 7 6 101 41 132
+241 2 2 7 6 108 47 134
+242 2 2 7 6 47 133 134
+243 2 2 7 6 84 83 135
+244 2 2 7 6 17 18 136
+245 2 2 7 6 103 44 137
+246 2 2 7 6 51 121 144
+247 2 2 7 6 119 13 139
+248 2 2 7 6 120 22 140
+249 2 2 7 6 121 31 141
+250 2 2 7 6 122 40 138
+251 2 2 7 6 5 53 138
+252 2 2 7 6 14 55 139
+253 2 2 7 6 23 54 140
+254 2 2 7 6 32 56 141
+255 2 2 7 6 124 50 142
+256 2 2 7 6 53 122 138
+257 2 2 7 6 54 120 140
+258 2 2 7 6 55 119 139
+259 2 2 7 6 56 121 141
+260 2 2 7 6 96 124 142
+261 2 2 7 6 125 96 142
+262 2 2 7 6 126 87 144
+263 2 2 7 6 106 127 143
+264 2 2 7 6 108 134 143
+265 2 2 7 6 134 106 143
+266 2 2 7 6 87 131 144
+267 2 2 7 6 131 51 144
+$EndElements
diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..37b7ff0b39a468d3931930869479d38f1aa28b7f
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/CMakeLists.txt
@@ -0,0 +1,6 @@
+project(cohesive_damage_extrinsic)
+cmake_minimum_required(VERSION 3.0.0)
+
+find_package(Akantu REQUIRED)
+
+add_akantu_simulation(cohesive_damage_extrinsic cohesive_damage_extrinsic.cc material.dat triangle.msh)
diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.cc b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4dfaa7ae2f61321835a35639cd628c31b1c8ecfc
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.cc
@@ -0,0 +1,113 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_group.hh"
+#include "mesh_iterators.hh"
+#include "non_linear_solver.hh"
+#include "solid_mechanics_model_cohesive_damage.hh"
+/* -------------------------------------------------------------------------- */
+#include <iostream>
+/* -------------------------------------------------------------------------- */
+
+using namespace akantu;
+
+/* -------------------------------------------------------------------------- */
+int main(int argc, char * argv[]) {
+  initialize("material.dat", argc, argv);
+
+  const Int spatial_dimension = 2;
+  const Int max_steps = 1;
+
+  Real L = 0.4;
+  Real eps0 = 1e-1;
+
+  Mesh mesh(spatial_dimension);
+  mesh.read("triangle.msh");
+
+  SolidMechanicsModelCohesiveDamage model(mesh);
+
+  /// model initialization
+  model.initFull(_analysis_method = _explicit_lumped_mass
+                 ,_is_extrinsic = true);
+
+  Real time_step = model.getStableTimeStep() * 0.05;
+  model.setTimeStep(time_step);
+  std::cout << "Time step: " << time_step << std::endl;
+
+  model.getElementInserter().setLimit(_x, 0.5*L-0.1, 0.5*L+0.1);
+  model.updateAutomaticInsertion();
+
+
+
+  model.applyBC(BC::Dirichlet::FixedValue(0., _x), "left");
+  model.applyBC(BC::Dirichlet::FixedValue(0., _y), "point");
+
+  Int nb_nodes = mesh.getNbNodes();
+
+  Array<Real> & position = mesh.getNodes();
+  Array<Real> & velocity = model.getVelocity();
+
+  for (Int n = 0; n < nb_nodes; ++n) {
+    velocity(n,0) = eps0*position(n,0);
+  }
+
+  model.setBaseName("cohesive");
+  model.addDumpFieldVector("displacement");
+//  model.addDumpField("velocity");
+//  model.addDumpField("acceleration");
+  model.addDumpField("stress");
+  model.addDumpField("grad_u");
+  model.addDumpField("external_force");
+  model.addDumpField("internal_force");
+  model.dump();
+
+  /// Main loop
+  for (Int s = 1; s <= max_steps; ++s) {
+    model.applyBC(BC::Dirichlet::IncrementValue(time_step*eps0*L, _x), "right");
+    // debug::setDebugLevel(dblDump);
+    debug::setDebugLevel(dblInfo);
+    model.checkCohesiveInsertion(); /// TODO : replace by a function which does not interpolate stress
+    model.solveStep();
+    model.computeLagrangeMultiplier();
+    model.computeDamage();
+    model.checkCohesiveStress();
+    debug::setDebugLevel(dblWarning);
+
+    if (s % 1 == 0) {
+      model.dump();
+      std::cout << "passing step " << s << "/" << max_steps << std::endl;
+    }
+  }
+
+  Real E = model.getEnergy("potential");
+
+  std::cout << "Elastic energy : " << E << std::endl;
+
+//  if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) {
+//    std::cout << "The dissipated energy is incorrect" << std::endl;
+//    return EXIT_FAILURE;
+//  }
+
+  finalize();
+
+  return EXIT_SUCCESS;
+}
+
diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.py b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.py
new file mode 100644
index 0000000000000000000000000000000000000000..4ef34df3d915e445f55e60163fef2993c15c5f8e
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+__copyright__ = (
+    "Copyright (©) 2019-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)"
+    "Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)"
+)
+__license__ = "LGPLv3"
+
+
+import sys
+sys.path.insert(0,"/home/ble/developpement/akantu/build/buildCZMDamageDebug/python")
+print(sys.path)
+
+import akantu as aka
+import numpy as np
+import matplotlib.pyplot as plt
+
+from czm_damage import *
+					
+def set_dumpers(model):
+    model.setBaseName("cohesive")
+    model.addDumpFieldVector("displacement")
+    model.addDumpFieldVector("external_force")
+    model.addDumpField("strain")
+    model.addDumpField("stress")
+    model.addDumpField("blocked_dofs")
+
+    model.setBaseNameToDumper("cohesive elements", "cohesive")
+    model.addDumpFieldVectorToDumper("cohesive elements", "displacement")
+    model.addDumpFieldToDumper("cohesive elements", "damage")
+    model.addDumpFieldVectorToDumper("cohesive elements", "tractions")
+    model.addDumpFieldVectorToDumper("cohesive elements", "opening")
+
+
+class FixedDisplacement (aka.DirichletFunctor):
+    '''
+        Fix the displacement at its current value
+    '''
+
+    def __init__(self, axis, vel):
+        super().__init__(axis)
+        self.axis = axis
+        self.time = 0
+        self.vel = vel
+
+    def set_time(self, t):
+        self.time = t
+
+    def get_imposed_disp(self):
+        return self.vel*self.time
+        
+    def __call__(self, node, flags, disp, coord):
+        # sets the blocked dofs vector to true in the desired axis
+        flags[int(self.axis)] = True
+        disp[int(self.axis)] = self.get_imposed_disp()
+        
+def solve(material_file, mesh_file):
+    aka.parseInput(material_file)
+    spatial_dimension = 2
+    L = 0.4
+    
+    # -------------------------------------------------------------------------
+    # Initialization
+    # -------------------------------------------------------------------------
+    mesh = aka.Mesh(spatial_dimension)
+    mesh.read(mesh_file)
+
+    model = aka.SolidMechanicsModelCohesiveDamage(mesh)
+    model.getElementInserter().setLimit(aka._x, 0.5*L-0.1, 0.5*L+0.1);
+
+    model.initFull(_analysis_method=aka._static, _is_extrinsic=True)
+    
+    # Initilize a new solver (explicit Newmark with lumped mass)
+    model.initNewSolver(aka._explicit_lumped_mass)
+    # Dynamic insertion of cohesive elements
+    model.updateAutomaticInsertion()
+                       
+    set_dumpers(model)
+
+
+    E = model.getMaterial("steel").getReal("E")
+    Gc = model.getMaterial("cohesive").getReal("G_c")
+    sigc = model.getMaterial("cohesive").getReal("sigma_c")
+    wc = 2.*Gc/sigc
+    w0 = (sigc/E)*L
+    k = model.getMaterial("cohesive").getReal("k")
+    g = degradation_function_linear_czm()
+    h = softening_function_linear_czm(k,sigc,Gc)
+    updater = damage_updater(Gc,sigc,k,g,h)
+
+    imposed_disp = [0.]
+    reaction_force = [0.]
+    E_pot = []
+    E_kin = []
+    E_dis = []
+    E_rev = []
+    E_con = []
+
+    U = 0.
+    F = 0.
+        
+    # -------------------------------------------------------------------------
+    # Initial and boundary conditions
+    # -------------------------------------------------------------------------
+    eps0dot = 5e-1
+    tc = w0/(eps0dot*L)
+    functor_r = FixedDisplacement(aka._x, L*eps0dot)
+    functor_r.set_time(tc)
+    model.applyBC(functor_r, 'right')
+
+    model.applyBC(aka.FixedValue(0.0, aka._x), "left")
+    model.applyBC(aka.FixedValue(0.0, aka._y), "point")
+    
+    nodes = model.getMesh().getNodes()
+    disp_field = np.zeros(nodes.shape)
+    disp_field[:, 0] = nodes[:, 0]*(w0/L)
+    model.getDisplacement()[:] = disp_field
+    vel_field = np.zeros(nodes.shape)
+    vel_field[:, 0] = nodes[:, 0]*eps0dot
+    model.getVelocity()[:] = vel_field
+    
+    model.getExternalForce()[:] = 0
+    model.assembleInternalForces()                           
+                                                  
+    d = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._segment_2)
+    lda = model.getMaterial("cohesive").getInternalReal("lambda")(aka._segment_2)
+    Fint = model.getInternalForce() 
+
+    nodes_right = mesh.getElementGroup("right").getNodeGroup().getNodes()    
+    
+    U = functor_r.get_imposed_disp()
+    imposed_disp.append(U)    
+    F = -np.sum(Fint[nodes_right,0])
+    reaction_force.append(F)
+    
+    Ep = model.getEnergy("potential")
+    Ek = model.getEnergy("kinetic")
+    Ed = model.getEnergy("dissipated")
+    Er = model.getEnergy("reversible")
+    
+    E_pot.append(Ep)
+    E_kin.append(Ek)
+    E_dis.append(Ed)
+    E_rev.append(Er)
+    
+    model.dump()
+    #model.dump("cohesive elements")
+            
+    maxsteps = 1
+    dt = model.getStableTimeStep()*0.1
+    # choose the timestep
+    model.setTimeStep(dt)
+
+    time = tc
+    for i in range(0, maxsteps):
+        print("---- step {0}/{1}".format(i, maxsteps))
+        time+=dt
+        functor_r.set_time(time)
+        # fix displacements of the right boundary
+        model.applyBC(functor_r, 'right')
+        d_previous = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._segment_2).copy()        
+        #print("lda = ",lda)
+        model.solveStep('explicit_lumped')
+        model.computeLagrangeMultiplier()
+        #d[:] = updater.update_d(d_previous,lda)
+        model.computeDamage()
+        # print("d = ",d)
+
+        model.checkCohesiveInsertion()
+        
+        U = functor_r.get_imposed_disp()
+        imposed_disp.append(U)    
+        F = -np.sum(Fint[nodes_right,0])
+        reaction_force.append(F)
+
+        Ep = model.getEnergy("potential")
+        Ek = model.getEnergy("kinetic")
+        Ed = model.getEnergy("dissipated")
+        Er = model.getEnergy("reversible")
+    
+        E_pot.append(Ep)
+        E_kin.append(Ek)
+        E_dis.append(Ed)
+        E_rev.append(Er)
+        
+        model.dump()
+        #model.dump("cohesive elements")
+
+    plt.plot(imposed_disp,reaction_force,'-o')
+    plt.plot([0., w0, wc], [0., sigc*L, 0.], 'k-o')
+    plt.show()
+
+
+# -----------------------------------------------------------------------------
+# main
+# -----------------------------------------------------------------------------
+def main():
+    mesh_file = "triangle.msh"
+    material_file = "material.dat"
+    solve(material_file, mesh_file)
+
+
+# -----------------------------------------------------------------------------
+if __name__ == "__main__":
+    main()
diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/czm_damage.py b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/czm_damage.py
new file mode 100644
index 0000000000000000000000000000000000000000..3bce7d71269530f57b68ab4992efa8a84af27d1f
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/czm_damage.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+
+import numpy as np
+import scipy.optimize
+
+import matplotlib.pyplot as plt
+
+class degradation_function:
+	# g(d)
+	def val(self,d):
+		return
+	# dg_dd(d)
+	def deriv(self,d):
+		return
+	# 1+g(d)
+	def augmented_stiffness(self,d):
+		return
+	def augmented_compliance(self,d):
+	# 1/(1+g(d))
+		return
+	def augmented_compliance_deriv(self,d):
+	# d()1/(1+g(d))_dd
+		return
+				
+class degradation_function_linear_czm(degradation_function):
+	def val(self,d):
+		return 1./d-1.
+	def deriv(self,d):
+		return -1./d**2
+	def augmented_stiffness(self,d):
+		return 1./d
+	def augmented_compliance(self,d):
+		return d
+	def augmented_compliance_deriv(self,d):
+		return 1.
+		
+class softening_function:
+	def val(self,d):
+		return
+	def deriv(self,d):
+		return
+		
+class softening_function_linear_czm:
+	def __init__(self,k,tc,Gc):
+		wc = 2.*Gc/tc
+		self.a = k*wc/tc
+	def val(self,d):
+		return d/(d+self.a*(1.-d))
+	def deriv(self,d):
+		return self.a/(d+self.a*(1.-d))**2
+		
+class damage_updater:
+    def __init__(self,Gc, sigc, k, g, h):
+        self.Gc = Gc
+        self.sigc = sigc
+        self.k = k
+        self.g = g
+        self.h = h
+    def update_d(self,d_previous,lda):
+        dz = d_previous.flatten()
+        shape_d = d_previous.shape
+        lda_lda_on_k = (lda[:,0]**2 + lda[:,1]**2)/self.k        
+        
+        def F(d):		
+            return -0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(d))+self.Gc*np.sum(self.h.val(d))
+        def dF(d):
+            return -0.5*self.g.augmented_compliance_deriv(d)*lda_lda_on_k+self.Gc*self.h.deriv(d)
+
+        #dd = np.linspace(0.,1.,100)
+        #D = dz.copy()
+        #FF = []
+        #for i in range(len(dd)):
+        #    D[0] = dd[i]
+        #    FF.append(F(D))
+        #plt.plot(dd,FF)
+        #plt.show()
+        #print("dz = ",dz)
+        #print("lda_lda_on_k = ",lda_lda_on_k)
+        #print("F1  = ",-0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(dz)))
+        #print("F2 = ",self.Gc*np.sum(self.h.val(dz)))
+        #print("F(dz) = ",F(dz))
+        #print("self.k = ",self.k)
+        
+        boundd = scipy.optimize.Bounds(dz, np.ones(len(dz))) 
+        options = {'verbose':1}
+        resd = scipy.optimize.minimize(F, dz, bounds=boundd
+		                              , jac =dF
+                                      #, method = 'trust-constr'
+                                      #, options = options
+                                      #, tol = 1e-10
+                                      )
+        if not resd.success:
+            print("resd.message = ",resd.message)
+        #print("niterd = ",resd.nit)
+        return np.resize(resd.x,shape_d)
+	
+def energy(model):
+    return model.getEnergy("potential") + model.getEnergy("dissipated")
diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/material.dat b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/material.dat
new file mode 100644
index 0000000000000000000000000000000000000000..58628a0714ca1e1d788e5f367e6ed3f92511ea78
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/material.dat
@@ -0,0 +1,13 @@
+material elastic [
+	 name = steel
+	 rho = 3800   # density
+	 E   = 3e10   # young's modulus
+         nu  = 0. # poisson's ratio
+]
+
+material cohesive_damage_extrinsic [
+	 name = cohesive
+         sigma_c = 3e6
+         k = 75e9
+         G_c = 120
+]
diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.geo b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.geo
new file mode 100644
index 0000000000000000000000000000000000000000..e3d5073b5fdcb78a4f83d1dcce9e9dd63428b8f4
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.geo
@@ -0,0 +1,23 @@
+h = .1;
+L = 0.4;
+
+Point(1) = { L, L, 0, h};
+Point(2) = {0., L, 0, h};
+Point(3) = {0.,0., 0, h};
+Point(4) = {L,0., 0, h};
+Line(1) = {1, 2};
+Line(2) = {2, 3};
+Line(3) = {3, 4};
+Line(4) = {4, 1};
+Line Loop(5) = {1, 2, 3, 4};
+Plane Surface(6) = {5};
+Physical Surface(7) = {6};
+
+Transfinite Line {2, 4} = 2;
+Transfinite Line {1, 3} = 3;
+Transfinite Surface {6} = {1, 2, 3, 4};
+
+
+Physical Curve("left", 8) = {2};
+Physical Curve("right", 9) = {4};
+Physical Point("point", 10) = {3};
diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.msh b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.msh
new file mode 100644
index 0000000000000000000000000000000000000000..4bb857aa493be251ed6cdb4a8da93c071d9858f2
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.msh
@@ -0,0 +1,28 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$PhysicalNames
+3
+0 10 "point"
+1 8 "left"
+1 9 "right"
+$EndPhysicalNames
+$Nodes
+6
+1 0.4 0.4 0
+2 0 0.4 0
+3 0 0 0
+4 0.4 0 0
+5 0.2000000000005479 0.4 0
+6 0.1999999999994742 0 0
+$EndNodes
+$Elements
+7
+1 15 2 10 3 3
+2 1 2 8 2 2 3
+3 1 2 9 4 4 1
+4 2 2 7 6 1 5 4
+5 2 2 7 6 4 5 6
+6 2 2 7 6 5 2 6
+7 2 2 7 6 6 2 3
+$EndElements
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/my_first_test/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..67ef4310bc692c719f839a4c1b6632c2f53b7ccb
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/CMakeLists.txt
@@ -0,0 +1,6 @@
+project(my_first_test)
+cmake_minimum_required(VERSION 3.0.0)
+
+find_package(Akantu REQUIRED)
+
+add_akantu_simulation(my_first_test my_first_test.cc material.dat triangle.msh)
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/czm_damage.py b/examples/c++/solid_mechanics_cohesive_model/my_first_test/czm_damage.py
new file mode 100644
index 0000000000000000000000000000000000000000..3bce7d71269530f57b68ab4992efa8a84af27d1f
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/czm_damage.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+
+import numpy as np
+import scipy.optimize
+
+import matplotlib.pyplot as plt
+
+class degradation_function:
+	# g(d)
+	def val(self,d):
+		return
+	# dg_dd(d)
+	def deriv(self,d):
+		return
+	# 1+g(d)
+	def augmented_stiffness(self,d):
+		return
+	def augmented_compliance(self,d):
+	# 1/(1+g(d))
+		return
+	def augmented_compliance_deriv(self,d):
+	# d()1/(1+g(d))_dd
+		return
+				
+class degradation_function_linear_czm(degradation_function):
+	def val(self,d):
+		return 1./d-1.
+	def deriv(self,d):
+		return -1./d**2
+	def augmented_stiffness(self,d):
+		return 1./d
+	def augmented_compliance(self,d):
+		return d
+	def augmented_compliance_deriv(self,d):
+		return 1.
+		
+class softening_function:
+	def val(self,d):
+		return
+	def deriv(self,d):
+		return
+		
+class softening_function_linear_czm:
+	def __init__(self,k,tc,Gc):
+		wc = 2.*Gc/tc
+		self.a = k*wc/tc
+	def val(self,d):
+		return d/(d+self.a*(1.-d))
+	def deriv(self,d):
+		return self.a/(d+self.a*(1.-d))**2
+		
+class damage_updater:
+    def __init__(self,Gc, sigc, k, g, h):
+        self.Gc = Gc
+        self.sigc = sigc
+        self.k = k
+        self.g = g
+        self.h = h
+    def update_d(self,d_previous,lda):
+        dz = d_previous.flatten()
+        shape_d = d_previous.shape
+        lda_lda_on_k = (lda[:,0]**2 + lda[:,1]**2)/self.k        
+        
+        def F(d):		
+            return -0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(d))+self.Gc*np.sum(self.h.val(d))
+        def dF(d):
+            return -0.5*self.g.augmented_compliance_deriv(d)*lda_lda_on_k+self.Gc*self.h.deriv(d)
+
+        #dd = np.linspace(0.,1.,100)
+        #D = dz.copy()
+        #FF = []
+        #for i in range(len(dd)):
+        #    D[0] = dd[i]
+        #    FF.append(F(D))
+        #plt.plot(dd,FF)
+        #plt.show()
+        #print("dz = ",dz)
+        #print("lda_lda_on_k = ",lda_lda_on_k)
+        #print("F1  = ",-0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(dz)))
+        #print("F2 = ",self.Gc*np.sum(self.h.val(dz)))
+        #print("F(dz) = ",F(dz))
+        #print("self.k = ",self.k)
+        
+        boundd = scipy.optimize.Bounds(dz, np.ones(len(dz))) 
+        options = {'verbose':1}
+        resd = scipy.optimize.minimize(F, dz, bounds=boundd
+		                              , jac =dF
+                                      #, method = 'trust-constr'
+                                      #, options = options
+                                      #, tol = 1e-10
+                                      )
+        if not resd.success:
+            print("resd.message = ",resd.message)
+        #print("niterd = ",resd.nit)
+        return np.resize(resd.x,shape_d)
+	
+def energy(model):
+    return model.getEnergy("potential") + model.getEnergy("dissipated")
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/material.dat b/examples/c++/solid_mechanics_cohesive_model/my_first_test/material.dat
new file mode 100644
index 0000000000000000000000000000000000000000..2f627470cac6f3b6dbebe6833d42b4fac47c8182
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/material.dat
@@ -0,0 +1,13 @@
+material elastic [
+	 name = steel
+	 rho = 1   # density
+	 E   = 3e10   # young's modulus
+         nu  = 0. # poisson's ratio
+]
+
+material cohesive_damage_intrinsic [
+	 name = cohesive
+         sigma_c = 3e6
+         k = 75e9
+         G_c = 120
+]
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.cc b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ae3bf49d97ab8bf7ba1e7dcd0c7955c3e3fe3738
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.cc
@@ -0,0 +1,98 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_group.hh"
+#include "mesh_iterators.hh"
+#include "non_linear_solver.hh"
+#include "solid_mechanics_model_cohesive.hh"
+/* -------------------------------------------------------------------------- */
+#include <iostream>
+/* -------------------------------------------------------------------------- */
+
+using namespace akantu;
+
+/* -------------------------------------------------------------------------- */
+int main(int argc, char * argv[]) {
+  initialize("material.dat", argc, argv);
+
+  const Int spatial_dimension = 2;
+  const Int max_steps = 1;
+
+  Mesh mesh(spatial_dimension);
+  mesh.read("triangle.msh");
+
+  SolidMechanicsModelCohesive model(mesh);
+  model.getElementInserter().setLimit(_x, -0.05, 0.05);
+
+  /// model initialization
+  model.initFull(_analysis_method = _static
+                 ,_is_extrinsic = false
+                 );
+
+  auto & solver = model.getNonLinearSolver();
+//  solver.set("convergence_type", SolveConvergenceCriteria::_residual);
+  solver.set("convergence_type", SolveConvergenceCriteria::_solution);
+  solver.set("max_iterations", 2);
+
+  model.applyBC(BC::Dirichlet::FixedValue(0., _x), "left");
+  model.applyBC(BC::Dirichlet::FixedValue(0., _y), "point");
+
+  model.setBaseName("cohesive");
+  model.addDumpFieldVector("displacement");
+//  model.addDumpField("velocity");
+//  model.addDumpField("acceleration");
+  model.addDumpField("stress");
+  model.addDumpField("grad_u");
+  model.addDumpField("external_force");
+  model.addDumpField("internal_force");
+  model.dump();
+
+
+  Real increment = 0.01;
+
+  /// Main loop
+  for (Int s = 1; s <= max_steps; ++s) {
+    model.applyBC(BC::Dirichlet::IncrementValue(increment, _x), "right");
+    // debug::setDebugLevel(dblDump);
+    debug::setDebugLevel(dblInfo);
+    model.solveStep();
+    debug::setDebugLevel(dblWarning);
+
+    if (s % 1 == 0) {
+      model.dump();
+      std::cout << "passing step " << s << "/" << max_steps << std::endl;
+    }
+  }
+
+  Real E = model.getEnergy("potential");
+
+  std::cout << "Elastic energy : " << E << std::endl;
+
+//  if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) {
+//    std::cout << "The dissipated energy is incorrect" << std::endl;
+//    return EXIT_FAILURE;
+//  }
+
+  finalize();
+
+  return EXIT_SUCCESS;
+}
+
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.py b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..a0244473dcfeb64c0274a2d6d242a57cc7788237
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+__copyright__ = (
+    "Copyright (©) 2019-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)"
+    "Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)"
+)
+__license__ = "LGPLv3"
+
+
+import sys
+sys.path.insert(0,"/home/ble/buildAkantu/buildDebug/python")
+print(sys.path)
+
+import akantu as aka
+import numpy as np
+import matplotlib.pyplot as plt
+
+from czm_damage import *
+					
+def set_dumpers(model):
+    model.setBaseName("cohesive")
+    model.addDumpFieldVector("displacement")
+    model.addDumpFieldVector("external_force")
+    model.addDumpField("strain")
+    model.addDumpField("stress")
+    model.addDumpField("blocked_dofs")
+
+    model.setBaseNameToDumper("cohesive elements", "cohesive")
+    model.addDumpFieldVectorToDumper("cohesive elements", "displacement")
+    model.addDumpFieldToDumper("cohesive elements", "damage")
+    model.addDumpFieldVectorToDumper("cohesive elements", "tractions")
+    model.addDumpFieldVectorToDumper("cohesive elements", "opening")
+
+
+def solve(material_file, mesh_file, increment):
+    aka.parseInput(material_file)
+    spatial_dimension = 2
+
+    # -------------------------------------------------------------------------
+    # Initialization
+    # -------------------------------------------------------------------------
+    mesh = aka.Mesh(spatial_dimension)
+    mesh.read(mesh_file)
+
+    model = aka.SolidMechanicsModelCohesive(mesh)
+    model.getElementInserter().setLimit(aka._x, -0.1, 0.1);
+
+    model.initFull(_analysis_method=aka._static, _is_extrinsic=False)
+                           
+    set_dumpers(model)
+
+    L = 0.4
+    E = model.getMaterial("steel").getReal("E")
+    Gc = model.getMaterial("cohesive").getReal("G_c")
+    tc = model.getMaterial("cohesive").getReal("sigma_c")
+    wc = 2.*Gc/tc
+    k = model.getMaterial("cohesive").getReal("k")
+    g = degradation_function_linear_czm()
+    h = softening_function_linear_czm(k,tc,Gc)
+    updater = damage_updater(Gc,tc,k,g,h)
+
+    imposed_disp = [0.]
+    reaction_force = [0.]
+    U = 0.
+    F = 0.
+        
+    # -------------------------------------------------------------------------
+    # Boundary conditions
+    # -------------------------------------------------------------------------
+    model.applyBC(aka.FixedValue(0.0, aka._x), "left")
+    model.applyBC(aka.FixedValue(0.0, aka._y), "point")
+    model.applyBC(aka.IncrementValue(increment, aka._x), "right")  
+    U+=increment
+    imposed_disp.append(U)
+    
+    model.getExternalForce()[:] = 0
+
+    solver = model.getNonLinearSolver("static")
+    solver.set("max_iterations", 2)
+    solver.set("threshold", 1e-10)
+    solver.set("convergence_type", aka.SolveConvergenceCriteria.residual)
+
+    model.getNewSolver("linear_static", aka.TimeStepSolverType.static,
+                       aka.NonLinearSolverType.linear)
+    model.setIntegrationScheme("linear_static", "displacement",
+                       aka.IntegrationSchemeType.pseudo_time)
+    model.setIntegrationScheme("linear_static", "lambda",
+                       aka.IntegrationSchemeType.pseudo_time)
+                                                  
+    d = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._cohesive_2d_4)
+    lda = model.getMaterial("cohesive").getInternalReal("lambda")(aka._cohesive_2d_4)
+    Fint = model.getInternalForce() 
+    
+    nodes_right = mesh.getElementGroup("right").getNodeGroup().getNodes()
+    model.solveStep("linear_static")
+    F = -np.sum(Fint[nodes_right,0])
+    reaction_force.append(F)
+    
+    model.dump()
+    #model.dump("cohesive elements")
+            
+    maxsteps = 8
+    maxiter = 10
+    tol = 1e-6
+    
+    for i in range(0, maxsteps):
+        print("---- step {0}/{1}".format(i, maxsteps))
+        model.applyBC(aka.IncrementValue(increment, aka._x), "right")
+        U+=increment
+        imposed_disp.append(U)    
+        it = 0
+        d_previous = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._cohesive_2d_4).copy()
+        W0 = energy(model)
+        while it < maxiter:
+            #aka.debug.setDebugLevel(aka.dblInfo);
+            model.solveStep("linear_static")
+            d[:] = updater.update_d(d_previous,lda)
+            W = energy(model)
+            err = abs(W-W0)/W
+            print("iter ",it,", err = ",err)          
+            if err < tol:
+                break
+            else:
+                W0 = W
+                it+=1
+        F = -np.sum(Fint[nodes_right,0])
+        reaction_force.append(F)
+    
+        model.dump()
+        #model.dump("cohesive elements")
+
+    plt.plot(imposed_disp,reaction_force,'-o')
+    plt.plot([0., (tc/E)*L, wc], [0., tc*L, 0.], 'k-o')
+    plt.show()
+    W = model.getEnergy("potential");
+    D = model.getEnergy("dissipated");
+    print("Elastic energy = ",W)
+    print("Dissipated energy = ",D)
+
+# -----------------------------------------------------------------------------
+# main
+# -----------------------------------------------------------------------------
+def main():
+    mesh_file = "triangle.msh"
+    material_file = "material.dat"
+    increment = 0.01e-3
+    solve(material_file, mesh_file, increment)
+
+
+# -----------------------------------------------------------------------------
+if __name__ == "__main__":
+    main()
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.geo b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.geo
new file mode 100644
index 0000000000000000000000000000000000000000..43289bc469f191c43f77f0850c645fc9d9d54626
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.geo
@@ -0,0 +1,20 @@
+h = .1;
+
+Point(1) = { 1, 1, 0, h};
+Point(2) = {-1, 1, 0, h};
+Point(3) = {-1,-1, 0, h};
+Point(4) = { 1,-1, 0, h};
+Line(1) = {1, 2};
+Line(2) = {2, 3};
+Line(3) = {3, 4};
+Line(4) = {4, 1};
+Line Loop(5) = {1, 2, 3, 4};
+Plane Surface(6) = {5};
+Physical Surface(7) = {6};
+
+Transfinite Line {1, 2, 3, 4} = 3;
+
+
+Physical Curve("left", 8) = {2};
+Physical Curve("right", 9) = {4};
+Physical Point("point", 10) = {3};
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.msh b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.msh
new file mode 100644
index 0000000000000000000000000000000000000000..8cff65b22fa2618249c9950a99588549901f74ab
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.msh
@@ -0,0 +1,37 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$PhysicalNames
+3
+0 10 "point"
+1 8 "left"
+1 9 "right"
+$EndPhysicalNames
+$Nodes
+9
+1 1 1 0
+2 -1 1 0
+3 -1 -1 0
+4 1 -1 0
+5 2.750244476601438e-12 1 0
+6 -1 2.750244476601438e-12 0
+7 -2.750244476601438e-12 -1 0
+8 1 -2.750244476601438e-12 0
+9 7.564178960885304e-24 0 0
+$EndNodes
+$Elements
+13
+1 15 2 10 3 3
+2 1 2 8 2 2 6
+3 1 2 8 2 6 3
+4 1 2 9 4 4 8
+5 1 2 9 4 8 1
+6 2 2 7 6 1 5 8
+7 2 2 7 6 8 5 9
+8 2 2 7 6 8 9 4
+9 2 2 7 6 4 9 7
+10 2 2 7 6 5 2 9
+11 2 2 7 6 9 2 6
+12 2 2 7 6 9 6 7
+13 2 2 7 6 7 6 3
+$EndElements
diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle_small.msh b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle_small.msh
new file mode 100644
index 0000000000000000000000000000000000000000..abf034048728dd554f1db12e8e476bb55088ebf6
--- /dev/null
+++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle_small.msh
@@ -0,0 +1,28 @@
+$MeshFormat
+2.2 0 8
+$EndMeshFormat
+$PhysicalNames
+3
+0 10 "point"
+1 8 "left"
+1 9 "right"
+$EndPhysicalNames
+$Nodes
+6
+1 1 1 0
+2 -1 1 0
+3 -1 -1 0
+4 1 -1 0
+5 2.750244476601438e-12 1 0
+6 -2.750244476601438e-12 -1 0
+$EndNodes
+$Elements
+7
+1 15 2 10 3 3
+2 1 2 8 2 2 3
+3 1 2 9 4 4 1
+4 2 2 7 6 1 5 4
+5 2 2 7 6 4 5 6
+6 2 2 7 6 5 2 6
+7 2 2 7 6 6 2 3
+$EndElements
diff --git a/packages/cohesive_element.cmake b/packages/cohesive_element.cmake
index 86c8a49d8004095732ede94b63299190c001b14e..cc93d32a121398587bf29e362a46a0d6601c3fab 100644
--- a/packages/cohesive_element.cmake
+++ b/packages/cohesive_element.cmake
@@ -1,4 +1,4 @@
-#===============================================================================
+	#===============================================================================
 # Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
 # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
 #
@@ -62,9 +62,36 @@ package_declare_sources(cohesive_element
   model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh
   model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.hh
 
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh
+
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh 
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh
+  
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh  
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh
+  model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh
+  
+          
   model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc
   model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh
   model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_inline_impl.hh
   model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc
+  
+  model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc
+  model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh
+  
+  model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc
+  model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh
+  model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh
+  
   )
 
diff --git a/packages/core.cmake b/packages/core.cmake
index e70c826c8af828f40dd8ffc5f3d54e5897627f90..90b948f1c758748baa44380905bbd6d30cbf8082 100644
--- a/packages/core.cmake
+++ b/packages/core.cmake
@@ -237,6 +237,14 @@ package_declare_sources(core
   model/common/non_local_toolbox/base_weight_function.hh
   model/common/non_local_toolbox/base_weight_function.cc
   model/common/non_local_toolbox/base_weight_function_inline_impl.hh
+  
+  model/common/non_local_toolbox/clip_neighborhood.hh
+  model/common/non_local_toolbox/clip_neighborhood_tmpl.hh
+  model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh
+  model/common/non_local_toolbox/base_distance_function.hh
+  model/common/non_local_toolbox/base_distance_function.cc
+  model/common/non_local_toolbox/base_distance_function_inline_impl.hh
+  
 
   model/common/model_solver.cc
   model/common/model_solver.hh
@@ -247,7 +255,6 @@ package_declare_sources(core
   model/common/dof_manager/dof_manager.hh
   model/common/dof_manager/dof_manager_default.cc
   model/common/dof_manager/dof_manager_default.hh
-  model/common/dof_manager/dof_manager_default_inline_impl.hh
   model/common/dof_manager/dof_manager_inline_impl.hh
 
   model/common/non_linear_solver/non_linear_solver.cc
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 603658d7a1b0da8b488bc7d389725be9ef8bfa0e..e32b27a2b3133a77d106bd8ff15b4fb8b0662b2d 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -62,6 +62,7 @@ package_is_activated(cohesive_element _is_activated)
 if (_is_activated)
   list(APPEND PYAKANTU_SRCS
     py_solid_mechanics_model_cohesive.cc
+    py_solid_mechanics_model_cohesive_damage.cc
     py_fragment_manager.cc
     )
 endif()
diff --git a/python/py_akantu.cc b/python/py_akantu.cc
index fc231c1b22a2f648b892b609445ebb66fd635222..6ffa5e4078dbd72d386e15c611e916cf6afcdd97 100644
--- a/python/py_akantu.cc
+++ b/python/py_akantu.cc
@@ -50,6 +50,7 @@
 #if defined(AKANTU_COHESIVE_ELEMENT)
 #include "py_fragment_manager.hh"
 #include "py_solid_mechanics_model_cohesive.hh"
+#include "py_solid_mechanics_model_cohesive_damage.hh"
 #endif
 
 #if defined(AKANTU_CONTACT_MECHANICS)
@@ -109,6 +110,7 @@ void register_all(pybind11::module & mod) {
 
 #if defined(AKANTU_COHESIVE_ELEMENT)
   register_solid_mechanics_model_cohesive(mod);
+  register_solid_mechanics_model_cohesive_damage(mod);
   register_fragment_manager(mod);
 #endif
 
diff --git a/python/py_material.cc b/python/py_material.cc
index 2b56be2d44c26834c822be5f9b607c67570e07db..49e4946ddd92a6b9bb03c79cc42fd34f1dc01eab 100644
--- a/python/py_material.cc
+++ b/python/py_material.cc
@@ -217,6 +217,12 @@ void register_material(py::module & mod) {
           [](MaterialCohesive & self, ElementType type, GhostType ghost_type)
               -> decltype(auto) { return self.getTraction(type, ghost_type); },
           py::arg("type"), py::arg("ghost_type") = _not_ghost,
+          py::return_value_policy::reference)
+      .def(
+          "getDamage",
+          [](MaterialCohesive & self, ElementType type, GhostType ghost_type)
+              -> decltype(auto) { return self.getDamage(type, ghost_type); },
+          py::arg("type"), py::arg("ghost_type") = _not_ghost,
           py::return_value_policy::reference);
 
   register_material_cohesive_classes<MaterialCohesiveLinear<2>>(
diff --git a/python/py_solid_mechanics_model_cohesive.cc b/python/py_solid_mechanics_model_cohesive.cc
index d4d8c8db966557d0cb3dd47b4b37ca5a3c7f1958..68293f04258d3727d842e510b965275b78a35c3c 100644
--- a/python/py_solid_mechanics_model_cohesive.cc
+++ b/python/py_solid_mechanics_model_cohesive.cc
@@ -35,13 +35,13 @@ namespace akantu {
 #define def_function_nocopy(func_name)                                         \
   def(                                                                         \
       #func_name,                                                              \
-      [](SolidMechanicsModel & self) -> decltype(auto) {                       \
+      [](SolidMechanicsModelCohesive & self) -> decltype(auto) {                       \
         return self.func_name();                                               \
       },                                                                       \
       py::return_value_policy::reference)
 
 #define def_function(func_name)                                                \
-  def(#func_name, [](SolidMechanicsModel & self) -> decltype(auto) {           \
+  def(#func_name, [](SolidMechanicsModelCohesive & self) -> decltype(auto) {           \
     return self.func_name();                                                   \
   })
 
diff --git a/python/py_solid_mechanics_model_cohesive_damage.cc b/python/py_solid_mechanics_model_cohesive_damage.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8fab3c850743399f5d7982eb024cccf4447c58c7
--- /dev/null
+++ b/python/py_solid_mechanics_model_cohesive_damage.cc
@@ -0,0 +1,87 @@
+/**
+ * Copyright (©) 2020-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "py_aka_array.hh"
+/* -------------------------------------------------------------------------- */
+#include <element_synchronizer.hh>
+#include <non_linear_solver.hh>
+#include <solid_mechanics_model_cohesive_damage.hh>
+/* -------------------------------------------------------------------------- */
+#include <pybind11/pybind11.h>
+/* -------------------------------------------------------------------------- */
+namespace py = pybind11;
+/* -------------------------------------------------------------------------- */
+
+namespace akantu {
+
+#define def_function_nocopy(func_name)                                         \
+  def(                                                                         \
+      #func_name,                                                              \
+      [](SolidMechanicsModelCohesiveDamage & self) -> decltype(auto) {                       \
+        return self.func_name();                                               \
+      },                                                                       \
+      py::return_value_policy::reference)
+
+#define def_function(func_name)                                                \
+  def(#func_name, [](SolidMechanicsModelCohesiveDamage & self) -> decltype(auto) {           \
+    return self.func_name();                                                   \
+  })
+
+void register_solid_mechanics_model_cohesive_damage(py::module & mod) {
+     
+  py::class_<SolidMechanicsModelCohesiveDamage, SolidMechanicsModel>(
+      mod, "SolidMechanicsModelCohesiveDamage")
+      .def(py::init<Mesh &, Int, const ID &>(), py::arg("mesh"),
+           py::arg("spatial_dimension") = _all_dimensions,
+           py::arg("id") = "solid_mechanics_model")
+      .def(
+          "initFull",
+          [](SolidMechanicsModel & self, const AnalysisMethod & analysis_method,
+             bool is_extrinsic) {
+            self.initFull(_analysis_method = analysis_method,
+                          _is_extrinsic = is_extrinsic);
+          },
+          py::arg("_analysis_method") = _explicit_lumped_mass,
+          py::arg("_is_extrinsic") = false)
+
+      .def("checkCohesiveStress",
+           &SolidMechanicsModelCohesiveDamage::checkCohesiveStress)
+      .def("checkCohesiveInsertion",
+           &SolidMechanicsModelCohesiveDamage::checkCohesiveInsertion)
+      .def("computeLagrangeMultiplier",
+           &SolidMechanicsModelCohesiveDamage::computeLagrangeMultiplier)
+      .def("computeDamage",
+           &SolidMechanicsModelCohesiveDamage::computeDamage)
+      .def("getElementInserter",
+           &SolidMechanicsModelCohesiveDamage::getElementInserter,
+           py::return_value_policy::reference)
+      .def("getStressOnFacets", &SolidMechanicsModelCohesiveDamage::getStressOnFacets,
+           py::arg("type"), py::arg("ghost_type") = _not_ghost,
+           py::return_value_policy::reference)
+      .def("getTangents", &SolidMechanicsModelCohesiveDamage::getTangents,
+           py::arg("type"), py::arg("ghost_type") = _not_ghost,
+           py::return_value_policy::reference)
+      .def_function_nocopy(getLambda)
+      .def("updateAutomaticInsertion",
+           &SolidMechanicsModelCohesiveDamage::updateAutomaticInsertion);
+}
+
+} // namespace akantu
diff --git a/src/model/common/dof_manager/dof_manager_default_inline_impl.hh b/python/py_solid_mechanics_model_cohesive_damage.hh
similarity index 68%
rename from src/model/common/dof_manager/dof_manager_default_inline_impl.hh
rename to python/py_solid_mechanics_model_cohesive_damage.hh
index 2092bebf4c21a20a38c350d0339a6c3bae0b7331..83436997f20860cf6f181821de78daf197493cee 100644
--- a/src/model/common/dof_manager/dof_manager_default_inline_impl.hh
+++ b/python/py_solid_mechanics_model_cohesive_damage.hh
@@ -1,5 +1,5 @@
 /**
- * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Copyright (©) 2020-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * This file is part of Akantu
@@ -19,12 +19,15 @@
  */
 
 /* -------------------------------------------------------------------------- */
-#include "dof_manager_default.hh"
-/* -------------------------------------------------------------------------- */
+#include <pybind11/pybind11.h>
+
+#ifndef AKANTU_PY_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_
+#define AKANTU_PY_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_
+
+namespace akantu {
 
-#ifndef AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_HH_
-#define AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_HH_
+void register_solid_mechanics_model_cohesive_damage(pybind11::module & mod);
 
-namespace akantu {} // namespace akantu
+} // namespace akantu
 
-#endif /* AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_HH */
+#endif // AKANTU_PY_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 69763527d64e6c6965fe437ba627f84275ef531c..fde7470d4b08d0ce04b9bdec3cdac12f9a913a7e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -53,6 +53,7 @@ set(AKANTU_INCLUDE_DIRS
   ${CMAKE_CURRENT_BINARY_DIR} ${AKANTU_LIBRARY_INCLUDE_DIRS}
   CACHE INTERNAL "Internal include directories to link with Akantu as a subproject")
 
+
 #===========================================================================
 # configurations
 #===========================================================================
@@ -118,6 +119,16 @@ endif()
 #===============================================================================
 add_library(akantu ${AKANTU_LIBRARY_SRCS})
 
+
+#===============================================================================
+# Gmsh Management
+#===============================================================================
+if(GMSH_INSTALL_DIR)
+  target_include_directories(akantu PUBLIC "${GMSH_INSTALL_DIR}/include/")
+  target_link_libraries(akantu PRIVATE ${GMSH_INSTALL_DIR}/lib/libgmsh.so)
+  add_definitions(-DWITH_GMSH)
+endif()
+
 target_include_directories(akantu
   PRIVATE   $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}>
   INTERFACE $<INSTALL_INTERFACE:include/akantu>
diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh
index 4433dfc1b1e7e36f70487cff3a3304005485389b..9bc405d5f12a664d7b5de5999d78863dde292f15 100644
--- a/src/common/aka_common.hh
+++ b/src/common/aka_common.hh
@@ -103,7 +103,8 @@ enum EventHandlerPriority {
   _ehp_mesh = 5,
   _ehp_fe_engine = 9,
   _ehp_synchronizer = 10,
-  _ehp_dof_manager = 20,
+  _ehp_dof_data = 21,
+  _ehp_dof_manager = 21,
   _ehp_model = 94,
   _ehp_non_local_manager = 100,
   _ehp_lowest = 100
@@ -516,7 +517,7 @@ namespace {
   inline void set##name(type variable) { this->variable = variable; }
 
 #define AKANTU_GET_MACRO(name, variable, type)                                 \
-  [[nodiscard]] inline auto get##name() const -> type { return variable; }
+  [[nodiscard]] inline auto get##name() const->type { return variable; }
 
 #define AKANTU_GET_MACRO_AUTO(name, variable)                                  \
   [[nodiscard]] inline decltype(auto) get##name() const { return (variable); }
@@ -525,7 +526,7 @@ namespace {
   inline decltype(auto) get##name() { return (variable); }
 
 #define AKANTU_GET_MACRO_NOT_CONST(name, variable, type)                       \
-  [[nodiscard]] inline auto get##name() -> type { return variable; }
+  [[nodiscard]] inline auto get##name()->type { return variable; }
 
 #define AKANTU_GET_MACRO_DEREF_PTR(name, ptr)                                  \
   [[nodiscard]] inline const auto & get##name() const {                        \
diff --git a/src/fe_engine/cohesive_element.hh b/src/fe_engine/cohesive_element.hh
index c4e597394b7ad8f76f4a03e19eee7cdfabbc7223..a6efe6a09cfdf17451af9e92f863b9b392bf4cdf 100644
--- a/src/fe_engine/cohesive_element.hh
+++ b/src/fe_engine/cohesive_element.hh
@@ -33,7 +33,7 @@ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_1d_2, _gt_cohesive_1d_2,
 
 AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_2d_4, _gt_cohesive_2d_4,
                                      _itp_lagrange_segment_2, _ek_cohesive, 2,
-                                     _git_segment, 2);
+                                     _git_segment, 1);
 
 AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_2d_6, _gt_cohesive_2d_6,
                                      _itp_lagrange_segment_3, _ek_cohesive, 2,
diff --git a/src/io/parser/parser.hh b/src/io/parser/parser.hh
index db8584720cdc1b133fad95ab5f5e368bfadf0eac..05681e510cb08e953f9e6343d0ef59ac73d1a6e6 100644
--- a/src/io/parser/parser.hh
+++ b/src/io/parser/parser.hh
@@ -50,11 +50,13 @@ namespace akantu {
   (neighborhoods)                                                       \
   (non_linear_solver)                                                   \
   (non_local)                                                           \
+  (clip)                                                                \
   (rules)                                                               \
   (solver)                                                              \
   (time_step_solver)                                                    \
   (user)                                                                \
   (weight_function)                                                     \
+  (distance_function)                                                   \
   (contact_detector)                                                    \
   (contact_resolution)                                                  \
   (not_defined)
@@ -82,11 +84,13 @@ enum class ParserType {
   neighborhoods,
   non_linear_solver,
   non_local,
+  clip,
   rules,
   solver,
   time_step_solver,
   user,
   weight_function,
+  distance_function,
   not_defined
 };
 #endif
diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc
index 5b8cc6bcec69ec8465f8f42022401752661eb992..267f5ab032ef53731b3845583b41990177c7f0d3 100644
--- a/src/mesh/mesh.cc
+++ b/src/mesh/mesh.cc
@@ -563,7 +563,7 @@ void Mesh::distributeImpl(
 
   this->computeBoundingBox();
 
-  MeshIsDistributedEvent event(AKANTU_CURRENT_FUNCTION);
+  MeshIsDistributedEvent event(mesh, AKANTU_CURRENT_FUNCTION);
   this->sendEvent(event);
 }
 
@@ -621,6 +621,24 @@ void Mesh::fillNodesToElements(Int dimension) {
   }
 }
 
+/* -------------------------------------------------------------------------- */
+void Mesh::copyNodes(const Mesh & mesh, std::vector<Idx> nodes) {
+
+  auto && it = make_view(mesh.getNodes(), spatial_dimension).begin();
+
+  Idx new_node = this->nodes->size() - 1;
+
+  for (auto node : nodes) {
+    auto && pos = it[node];
+    this->nodes->push_back(pos);
+    this->nodes_flags->push_back(mesh.getNodeFlag(node));
+    this->nodes_prank[new_node] = mesh.getNodePrank(node);
+    ++new_node;
+  }
+
+  // TODO: need to regenerate global nodes ids and node synchronizer
+}
+
 /* -------------------------------------------------------------------------- */
 std::tuple<Idx, Idx> Mesh::updateGlobalData(NewNodesEvent & nodes_event,
                                             NewElementsEvent & elements_event) {
diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh
index 462081826296b92d5f7a35a3bc479b789b816820..8c03c7c17efdde6938562bff380e68e12f25df83 100644
--- a/src/mesh/mesh.hh
+++ b/src/mesh/mesh.hh
@@ -258,6 +258,9 @@ public:
   /// fills the nodes_to_elements for given dimension elements
   void fillNodesToElements(Int dimension = _all_dimensions);
 
+  /// copy the nodes `nodes` from `mesh` to *this
+  void copyNodes(const Mesh & mesh, std::vector<Idx> nodes);
+
 private:
   /// update the global ids, nodes type, ...
   std::tuple<Int, Int> updateGlobalData(NewNodesEvent & nodes_event,
@@ -265,6 +268,7 @@ private:
 
   void registerGlobalDataUpdater(
       std::unique_ptr<MeshGlobalDataUpdater> && global_data_updater);
+
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
diff --git a/src/mesh/mesh_events.hh b/src/mesh/mesh_events.hh
index 4158ff7ebcef6f1b14ff94091bd82341ea67ba9a..67827c74a2019dbdab3e0fd5ed3e5c08b562f37b 100644
--- a/src/mesh/mesh_events.hh
+++ b/src/mesh/mesh_events.hh
@@ -34,19 +34,24 @@ namespace akantu {
 /// akantu::MeshEvent is the base event for meshes
 template <class Entity> class MeshEvent {
 public:
-  MeshEvent(const std::string & origin = "") : origin_(origin) {}
+  MeshEvent(const Mesh & mesh, const std::string & origin = "")
+      : mesh(mesh), origin_(origin) {}
 
   virtual ~MeshEvent() = default;
   /// Get the list of entity modified by the event nodes or elements
-  const Array<Entity> & getList() const { return list; }
+  [[nodiscard]] const Array<Entity> & getList() const { return list; }
   /// Get the list of entity modified by the event nodes or elements
   Array<Entity> & getList() { return list; }
 
-  std::string origin() const { return origin_; }
+  [[nodiscard]] const ID & origin() const { return origin_; }
+
+  AKANTU_GET_MACRO_AUTO(Mesh, mesh);
 
 protected:
   Array<Entity> list;
 
+  const Mesh & mesh;
+
 private:
   std::string origin_;
 };
@@ -56,20 +61,19 @@ class Mesh;
 /// akantu::MeshEvent related to new nodes in the mesh
 class NewNodesEvent : public MeshEvent<Idx> {
 public:
-  NewNodesEvent(const std::string & origin = "") : MeshEvent(origin) {}
-  ~NewNodesEvent() override = default;
+  NewNodesEvent(const Mesh & mesh, const std::string & origin = "")
+      : MeshEvent(mesh, origin) {}
 };
 
 /// akantu::MeshEvent related to nodes removed from the mesh
 class RemovedNodesEvent : public MeshEvent<Idx> {
 public:
-  inline RemovedNodesEvent(const Mesh & mesh, const std::string & origin = "");
+  RemovedNodesEvent(const Mesh & mesh, const std::string & origin = "");
 
-  ~RemovedNodesEvent() override = default;
   /// Get the new numbering following suppression of nodes from nodes arrays
-  AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, auto &);
+  AKANTU_GET_MACRO_AUTO_NOT_CONST(NewNumbering, new_numbering);
   /// Get the new numbering following suppression of nodes from nodes arrays
-  AKANTU_GET_MACRO(NewNumbering, new_numbering, const auto &);
+  AKANTU_GET_MACRO_AUTO(NewNumbering, new_numbering);
 
 private:
   Array<Idx> new_numbering;
@@ -78,35 +82,31 @@ private:
 /// akantu::MeshEvent related to new elements in the mesh
 class NewElementsEvent : public MeshEvent<Element> {
 public:
-  NewElementsEvent(const std::string & origin = "")
-      : MeshEvent<Element>(origin) {}
-  ~NewElementsEvent() override = default;
+  NewElementsEvent(const Mesh & mesh, const std::string & origin = "")
+      : MeshEvent<Element>(mesh, origin) {}
 };
 
 /// akantu::MeshEvent related to the case the mesh is made distributed.
 ///  Note that the `list` has no meaning for this event.
-class MeshIsDistributedEvent : public MeshEvent<UInt> {
+class MeshIsDistributedEvent : public MeshEvent<Idx> {
 public:
-  MeshIsDistributedEvent(const std::string & origin = "")
-      : MeshEvent<UInt>(origin) {}
-  ~MeshIsDistributedEvent() override = default;
+  MeshIsDistributedEvent(const Mesh & mesh, const std::string & origin = "")
+      : MeshEvent<Idx>(mesh, origin) {}
 };
 
 /// akantu::MeshEvent related to elements removed from the mesh
 class RemovedElementsEvent : public MeshEvent<Element> {
 public:
-  inline RemovedElementsEvent(const Mesh & mesh,
-                              const ID & new_numbering_id = "new_numbering",
-                              const std::string & origin = "");
-
-  ~RemovedElementsEvent() override = default;
+  RemovedElementsEvent(const Mesh & mesh,
+                       const ID & new_numbering_id = "new_numbering",
+                       const std::string & origin = "");
 
   /// Get the new numbering following suppression of elements from elements
   /// arrays
-  AKANTU_GET_MACRO(NewNumbering, new_numbering, const auto &);
+  AKANTU_GET_MACRO_AUTO(NewNumbering, new_numbering);
   /// Get the new numbering following suppression of elements from elements
   /// arrays
-  AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, auto &);
+  AKANTU_GET_MACRO_AUTO_NOT_CONST(NewNumbering, new_numbering);
   /// Get the new numbering following suppression of elements from elements
   /// arrays
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(NewNumbering, new_numbering, Idx);
@@ -128,11 +128,11 @@ public:
       const std::string & origin = "")
       : RemovedElementsEvent(mesh, new_numbering_id, origin) {}
 
-  ~ChangedElementsEvent() override = default;
-  AKANTU_GET_MACRO(ListOld, list, const Array<Element> &);
-  AKANTU_GET_MACRO_NOT_CONST(ListOld, list, Array<Element> &);
-  AKANTU_GET_MACRO(ListNew, new_list, const Array<Element> &);
-  AKANTU_GET_MACRO_NOT_CONST(ListNew, new_list, Array<Element> &);
+  AKANTU_GET_MACRO_AUTO(ListOld, list);
+  AKANTU_GET_MACRO_AUTO(ListNew, new_list);
+
+  AKANTU_GET_MACRO_AUTO_NOT_CONST(ListOld, list);
+  AKANTU_GET_MACRO_AUTO_NOT_CONST(ListNew, new_list);
 
 protected:
   Array<Element> new_list;
diff --git a/src/mesh/mesh_inline_impl.hh b/src/mesh/mesh_inline_impl.hh
index 2ea6d6fbedfddd6c6b46f69456b512c4ac0ef8c7..e12b743ddcb7415effeb9dd946b30ef3e23f1045 100644
--- a/src/mesh/mesh_inline_impl.hh
+++ b/src/mesh/mesh_inline_impl.hh
@@ -59,14 +59,14 @@ inline decltype(auto) Mesh::getConnectivity(const Element & element) const {
 /* -------------------------------------------------------------------------- */
 inline RemovedNodesEvent::RemovedNodesEvent(const Mesh & mesh,
                                             const std::string & origin)
-    : MeshEvent<Idx>(origin),
+    : MeshEvent<Idx>(mesh, origin),
       new_numbering(mesh.getNbNodes(), 1, "new_numbering") {}
 
 /* -------------------------------------------------------------------------- */
 inline RemovedElementsEvent::RemovedElementsEvent(const Mesh & mesh,
                                                   const ID & new_numbering_id,
                                                   const std::string & origin)
-    : MeshEvent<Element>(origin),
+    : MeshEvent<Element>(mesh, origin),
       new_numbering(new_numbering_id, mesh.getID()) {}
 
 /* -------------------------------------------------------------------------- */
diff --git a/src/mesh/mesh_periodic.cc b/src/mesh/mesh_periodic.cc
index 16cecb26488a737a1cf7a7c494851a6311c8dae2..1429e66f3b23c89acbd3ccfdbc17bcdc51878b33 100644
--- a/src/mesh/mesh_periodic.cc
+++ b/src/mesh/mesh_periodic.cc
@@ -136,7 +136,7 @@ void Mesh::makePeriodic(const SpatialDirection & direction,
 
   std::vector<Idx> new_nodes;
   if (is_distributed) {
-    NewNodesEvent event(AKANTU_CURRENT_FUNCTION);
+    NewNodesEvent event(mesh, AKANTU_CURRENT_FUNCTION);
 
     /* ---------------------------------------------------------------------- */
     // function to send nodes in bboxes intersections
@@ -203,8 +203,8 @@ void Mesh::makePeriodic(const SpatialDirection & direction,
 
       while (not buffer.empty()) {
         Vector<Real> pos(spatial_dimension);
-        Idx global_node;
-        NodeFlag flag;
+        Idx global_node{};
+        NodeFlag flag{};
         buffer >> global_node;
         buffer >> pos;
         buffer >> flag;
@@ -214,7 +214,7 @@ void Mesh::makePeriodic(const SpatialDirection & direction,
 
         // get the master info of is slave
         if (flag == NodeFlag::_periodic_slave) {
-          Idx master_node;
+          Idx master_node{};
           buffer >> master_node;
           // std::cout << " slave of " << master_node << std::endl;
           // auto local_master_node = getNodeLocalId(master_node);
@@ -224,11 +224,11 @@ void Mesh::makePeriodic(const SpatialDirection & direction,
 
         // get the list of slaves if is master
         if ((flag & NodeFlag::_periodic_mask) == NodeFlag::_periodic_master) {
-          Int nb_slaves;
+          Int nb_slaves{};
           buffer >> nb_slaves;
           // std::cout << " master of " << nb_slaves << " nodes : [";
           for (auto ns [[gnu::unused]] : arange(nb_slaves)) {
-            Idx gslave_node;
+            Idx gslave_node{};
             buffer >> gslave_node;
             // std::cout << (ns == 0 ? "" : ", ") << gslave_node;
             // auto lslave_node = getNodeLocalId(gslave_node);
diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc
index 36ad226cb802cd638a6304319919d62d2d2fdc6d..8c687334e9993ebe485d9b2b6167233e732ec36f 100644
--- a/src/mesh_utils/cohesive_element_inserter.cc
+++ b/src/mesh_utils/cohesive_element_inserter.cc
@@ -226,8 +226,8 @@ void CohesiveElementInserter::limitCheckFacets(
 
 /* -------------------------------------------------------------------------- */
 UInt CohesiveElementInserter::insertElements(bool only_double_facets) {
-  CohesiveNewNodesEvent node_event(AKANTU_CURRENT_FUNCTION);
-  NewElementsEvent element_event(AKANTU_CURRENT_FUNCTION);
+  CohesiveNewNodesEvent node_event(mesh, AKANTU_CURRENT_FUNCTION);
+  NewElementsEvent element_event(mesh, AKANTU_CURRENT_FUNCTION);
 
   if (mesh_facets.isDistributed()) {
     mesh_facets.getElementSynchronizer().synchronizeOnce(
diff --git a/src/mesh_utils/cohesive_element_inserter.hh b/src/mesh_utils/cohesive_element_inserter.hh
index ce0cb29b4a26836f09a3f6ed19a81fdedaa64a76..03de522945227ddedcfa42a818255937cf1e6a5b 100644
--- a/src/mesh_utils/cohesive_element_inserter.hh
+++ b/src/mesh_utils/cohesive_element_inserter.hh
@@ -82,7 +82,7 @@ protected:
 
   /// functions for parallel communications
   inline Int getNbData(const Array<Element> & elements,
-                        const SynchronizationTag & tag) const override;
+                       const SynchronizationTag & tag) const override;
 
   inline void packData(CommunicationBuffer & buffer,
                        const Array<Element> & elements,
@@ -151,8 +151,8 @@ private:
 
 class CohesiveNewNodesEvent : public NewNodesEvent {
 public:
-  CohesiveNewNodesEvent(const std::string & origin) : NewNodesEvent(origin) {}
-  ~CohesiveNewNodesEvent() override = default;
+  CohesiveNewNodesEvent(const Mesh & mesh, const std::string & origin)
+      : NewNodesEvent(mesh, origin) {}
 
   AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array<Idx> &);
   AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array<Idx> &);
diff --git a/src/mesh_utils/cohesive_element_inserter_helper.cc b/src/mesh_utils/cohesive_element_inserter_helper.cc
index 43a3bdd75576a4de7380e2e31104614d2c5898b7..ccb87d3d1191c52039ae21eb7d8f71641cabd6ff 100644
--- a/src/mesh_utils/cohesive_element_inserter_helper.cc
+++ b/src/mesh_utils/cohesive_element_inserter_helper.cc
@@ -431,7 +431,7 @@ Int CohesiveElementInserterHelper::insertFacetsOnly() {
 /* -------------------------------------------------------------------------- */
 template <Int dim> void CohesiveElementInserterHelper::doubleFacets() {
   AKANTU_DEBUG_IN();
-  NewElementsEvent new_facets;
+  NewElementsEvent new_facets(mesh);
   auto spatial_dimension = mesh_facets.getSpatialDimension();
 
   auto & facets_to_double = *facets_to_double_by_dim[dim];
@@ -798,7 +798,7 @@ void CohesiveElementInserterHelper::doublePointFacet() {
     return;
   }
 
-  NewElementsEvent new_facets_event;
+  NewElementsEvent new_facets_event(mesh);
 
   auto & facets_to_double = *facets_to_double_by_dim[spatial_dimension - 1];
   const auto & element_to_facet = mesh_facets.getElementToSubelement();
@@ -852,7 +852,7 @@ void CohesiveElementInserterHelper::doubleSubfacet() {
     return;
   }
 
-  NewElementsEvent new_facets_event;
+  NewElementsEvent new_facets_event(mesh);
 
   std::vector<Idx> nodes_to_double;
   MeshAccessor mesh_accessor(mesh_facets);
diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc
index 0d7ccaa563e00d2949cfddfe3d52114bc71b3882..2c1b4ed58667899a68059ff4ef53b5d7a8988c5c 100644
--- a/src/mesh_utils/mesh_utils.cc
+++ b/src/mesh_utils/mesh_utils.cc
@@ -206,7 +206,7 @@ void MeshUtils::buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets,
   Array<Int> counter;
   std::vector<Element> connected_elements;
 
-  NewElementsEvent event(AKANTU_CURRENT_FUNCTION);
+  NewElementsEvent event(mesh, AKANTU_CURRENT_FUNCTION);
 
   // init the SubelementToElement data to improve performance
   for (auto && ghost_type : ghost_types) {
diff --git a/src/model/common/boundary_condition/boundary_condition.hh b/src/model/common/boundary_condition/boundary_condition.hh
index 69205decd8cb3c12b0929bdbb42d0ec852538d1a..3229150184f6300e04b1823a8c33585a2eef9b26 100644
--- a/src/model/common/boundary_condition/boundary_condition.hh
+++ b/src/model/common/boundary_condition/boundary_condition.hh
@@ -40,7 +40,7 @@ private:
   /* Constructors / Destructors / Initializers                                */
   /* ------------------------------------------------------------------------ */
 public:
-  BoundaryCondition() : model(nullptr) {}
+  BoundaryCondition(const ID & dof_name) : model(nullptr), dof_name(dof_name) {}
   /// Initialize the boundary conditions
   void initBC(ModelType & model, Array<Real> & primal, Array<Real> & dual);
   void initBC(ModelType & model, Array<Real> & primal,
@@ -73,6 +73,8 @@ public:
 
 private:
   ModelType * model;
+  ID dof_name;
+
   Array<Real> * primal{nullptr};
   Array<Real> * dual{nullptr};
   Array<Real> * primal_increment{nullptr};
diff --git a/src/model/common/boundary_condition/boundary_condition_tmpl.hh b/src/model/common/boundary_condition/boundary_condition_tmpl.hh
index 3fd02e64a8e7a0de2593c8a14c20dff8925ba43b..070191b10ab0c2353a5bef8668785225cd7fb339 100644
--- a/src/model/common/boundary_condition/boundary_condition_tmpl.hh
+++ b/src/model/common/boundary_condition/boundary_condition_tmpl.hh
@@ -166,7 +166,8 @@ struct BoundaryCondition<ModelType>::TemplateFunctionWrapper<
 
       // assemble the result into force vector
       model.getDOFManager().assembleElementalArrayLocalArray(
-          dual_by_shapes_integ, dual, type, ghost_type, 1., element_ids);
+          bc_instance.dof_name, dual_by_shapes_integ, dual, type, ghost_type,
+          1., element_ids);
     }
   }
 };
diff --git a/src/model/common/dof_manager/dof_manager.cc b/src/model/common/dof_manager/dof_manager.cc
index d5a47ba38b6ef0e1f27eb3caa56ad5db74122375..e956111094a6c0b97815c63d4112e06865dbfb78 100644
--- a/src/model/common/dof_manager/dof_manager.cc
+++ b/src/model/common/dof_manager/dof_manager.cc
@@ -40,17 +40,6 @@ DOFManager::DOFManager(const ID & id)
       global_equation_number(0, 1, "global_equation_number"),
       communicator(Communicator::getStaticCommunicator()) {}
 
-/* -------------------------------------------------------------------------- */
-DOFManager::DOFManager(Mesh & mesh, const ID & id)
-    : id(id), mesh(&mesh), dofs_flag(0, 1, std::string(id + ":dofs_type")),
-      global_equation_number(0, 1, "global_equation_number"),
-      communicator(mesh.getCommunicator()) {
-  this->mesh->registerEventHandler(*this, _ehp_dof_manager);
-}
-
-/* -------------------------------------------------------------------------- */
-DOFManager::~DOFManager() = default;
-
 /* -------------------------------------------------------------------------- */
 std::vector<ID> DOFManager::getDOFIDs() const {
   std::vector<ID> keys;
@@ -63,57 +52,50 @@ std::vector<ID> DOFManager::getDOFIDs() const {
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::assembleElementalArrayLocalArray(
-    const Array<Real> & elementary_vect, Array<Real> & array_assembeled,
-    ElementType type, GhostType ghost_type, Real scale_factor,
-    const Array<Int> & filter_elements) {
+    const ID & dof_id, const Array<Real> & elementary_vect,
+    Array<Real> & array_assembeled, ElementType type, GhostType ghost_type,
+    Real scale_factor, const Array<Int> & filter_elements) {
   AKANTU_DEBUG_IN();
+  auto & dof_data = this->getDOFData(dof_id);
 
-  Int nb_element;
-  auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+  auto && connectivity = dof_data.mesh->getConnectivity(type, ghost_type);
+
+  auto nb_nodes_per_element = connectivity.getNbComponent();
   auto nb_degree_of_freedom =
       elementary_vect.getNbComponent() / nb_nodes_per_element;
 
-  const Idx * filter_it = nullptr;
-  if (filter_elements != empty_filter) {
-    nb_element = filter_elements.size();
-    filter_it = filter_elements.data();
-  } else {
-    nb_element = this->mesh->getNbElement(type, ghost_type);
-  }
-
-  AKANTU_DEBUG_ASSERT(elementary_vect.size() == nb_element,
+  AKANTU_DEBUG_ASSERT((filter_elements != empty_filter and
+                       elementary_vect.size() == filter_elements.size()) or
+                          (elementary_vect.size() == connectivity.size()),
                       "The vector elementary_vect("
                           << elementary_vect.getID()
                           << ") has not the good size.");
 
-  const auto & connectivity = this->mesh->getConnectivity(type, ghost_type);
-
-  auto elem_it =
-      make_view(elementary_vect, nb_degree_of_freedom, nb_nodes_per_element)
-          .begin();
   auto assemble_it = make_view(array_assembeled, nb_degree_of_freedom).begin();
 
-  for (Int el = 0; el < nb_element; ++el, ++elem_it) {
-    auto element = el;
-    if (filter_it != nullptr) {
-
-      element = *filter_it;
-    }
-
-    // const Vector<UInt> & conn = *conn_it;
-    const auto & elemental_val = *elem_it;
-    for (Int n = 0; n < nb_nodes_per_element; ++n) {
-      auto node = connectivity(element, n);
-
+  auto per_element_assemble = [&assemble_it, scale_factor](auto & conn,
+                                                           auto & vals) {
+    for (auto && [node, val] : zip(conn, vals)) {
       auto && assemble = assemble_it[node];
-      assemble += scale_factor * elemental_val(n);
+      assemble += scale_factor * val;
     }
+  };
 
-    if (filter_it != nullptr) {
-      ++filter_it;
+  if (filter_elements != empty_filter) {
+    for (auto && [conn, vals] :
+         zip(filter(filter_elements,
+                    make_view(connectivity, nb_nodes_per_element)),
+             make_view(elementary_vect, nb_degree_of_freedom,
+                       nb_nodes_per_element))) {
+      per_element_assemble(conn, vals);
+    }
+  } else {
+    for (auto && [conn, vals] :
+         zip(make_view(connectivity, nb_nodes_per_element),
+             make_view(elementary_vect, nb_degree_of_freedom,
+                       nb_nodes_per_element))) {
+      per_element_assemble(conn, vals);
     }
-    //    else
-    //      ++conn_it;
   }
 
   AKANTU_DEBUG_OUT();
@@ -125,18 +107,22 @@ void DOFManager::assembleElementalArrayToResidual(
     GhostType ghost_type, Real scale_factor,
     const Array<Int> & filter_elements) {
   AKANTU_DEBUG_IN();
+  auto & dof_data = this->getDOFData(dof_id);
+
+  auto && connectivity = dof_data.mesh->getConnectivity(type, ghost_type);
 
-  auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+  //  auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+  auto nb_nodes_per_element = connectivity.getNbComponent();
   auto nb_degree_of_freedom =
       elementary_vect.getNbComponent() / nb_nodes_per_element;
-  Array<Real> array_localy_assembeled(this->mesh->getNbNodes(),
-                                      nb_degree_of_freedom);
 
+  Array<Real> array_localy_assembeled(dof_data.dof->size(),
+                                      nb_degree_of_freedom);
   array_localy_assembeled.zero();
 
   this->assembleElementalArrayLocalArray(
-      elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor,
-      filter_elements);
+      dof_id, elementary_vect, array_localy_assembeled, type, ghost_type,
+      scale_factor, filter_elements);
 
   this->assembleToResidual(dof_id, array_localy_assembeled, 1);
 
@@ -149,24 +135,39 @@ void DOFManager::assembleElementalArrayToLumpedMatrix(
     const ID & lumped_mtx, ElementType type, GhostType ghost_type,
     Real scale_factor, const Array<Int> & filter_elements) {
   AKANTU_DEBUG_IN();
+  auto & dof_data = this->getDOFData(dof_id);
 
-  auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+  auto && connectivity = dof_data.mesh->getConnectivity(type, ghost_type);
+
+  auto nb_nodes_per_element = connectivity.getNbComponent();
   auto nb_degree_of_freedom =
       elementary_vect.getNbComponent() / nb_nodes_per_element;
-  Array<Real> array_localy_assembeled(this->mesh->getNbNodes(),
+
+  Array<Real> array_localy_assembeled(dof_data.dof->size(),
                                       nb_degree_of_freedom);
 
   array_localy_assembeled.zero();
 
   this->assembleElementalArrayLocalArray(
-      elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor,
-      filter_elements);
+      dof_id, 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::assembleElementalMatricesToMatrix(
+    const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat,
+    ElementType type, GhostType ghost_type,
+    const MatrixType & elemental_matrix_type,
+    const Array<Int> & filter_elements) {
+  assembleElementalMatricesToMatrix(matrix_id, dof_id, elementary_mat, type,
+                                    ghost_type, elemental_matrix_type,
+                                    filter_elements);
+}
+
 /* -------------------------------------------------------------------------- */
 void DOFManager::assembleMatMulDOFsToResidual(const ID & A_id,
                                               Real scale_factor) {
@@ -241,29 +242,50 @@ DOFManager::DOFData::DOFData(const ID & dof_id)
       associated_nodes(0, 1, dof_id + "associated_nodes") {}
 
 /* -------------------------------------------------------------------------- */
-DOFManager::DOFData::~DOFData() = default;
+void DOFManager::DOFData::onNodesAdded(const Array<Idx> & nodes_list,
+                                       const NewNodesEvent & event) {
+  if (this->mesh != nullptr and this->mesh != &(event.getMesh())) {
+    return;
+  }
+
+  const auto & group = group_support;
+
+  if (group == "__mesh__") {
+    dof_manager->updateNodalDOFs(dof_id, nodes_list);
+  } else {
+    const auto & node_group = this->mesh->getElementGroup(group).getNodeGroup();
+    Array<Idx> new_nodes_list;
+    for (const auto & node : nodes_list) {
+      if (node_group.find(node) != Int(-1)) {
+        new_nodes_list.push_back(node);
+      }
+    }
+
+    dof_manager->updateNodalDOFs(dof_id, new_nodes_list);
+  }
+}
 
 /* -------------------------------------------------------------------------- */
 template <typename Func>
-auto DOFManager::countDOFsForNodes(const DOFData & dof_data, Int nb_nodes,
-                                   Func && getNode) {
+auto DOFManager::DOFData::countDOFsForNodes(Int nb_nodes,
+                                            Func && get_node) const {
   auto nb_local_dofs = nb_nodes;
   decltype(nb_local_dofs) nb_pure_local = 0;
   for (auto n : arange(nb_nodes)) {
-    UInt node = getNode(n);
+    auto node = get_node(n);
 
     // http://www.open-std.org/jtc1/sc22/open/n2356/conv.html
     // bool are by convention casted to 0 and 1 when promoted to int
-    nb_pure_local += this->mesh->isLocalOrMasterNode(node);
-    nb_local_dofs -= this->mesh->isPeriodicSlave(node);
+    nb_pure_local += mesh->isLocalOrMasterNode(node);
+    nb_local_dofs -= mesh->isPeriodicSlave(node);
   }
 
-  const auto & dofs_array = *dof_data.dof;
-  nb_pure_local *= dofs_array.getNbComponent();
-  nb_local_dofs *= dofs_array.getNbComponent();
+  nb_pure_local *= dof->getNbComponent();
+  nb_local_dofs *= dof->getNbComponent();
   return std::make_pair(nb_local_dofs, nb_pure_local);
 }
 
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 auto DOFManager::getNewDOFDataInternal(const ID & dof_id) -> DOFData & {
   auto it = this->dofs.find(dof_id);
@@ -275,15 +297,21 @@ auto DOFManager::getNewDOFDataInternal(const ID & dof_id) -> DOFData & {
   DOFData & dof_data = *dof_data_ptr;
 
   this->dofs[dof_id] = std::move(dof_data_ptr);
+
+  dof_data.dof_manager = this;
+  dof_data.dof_id = dof_id;
+
   return dof_data;
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array,
                               DOFSupportType support_type) {
+  AKANTU_DEBUG_ASSERT(support_type != _dst_nodal,
+                      "Nodal DOFs need to be registered with a mesh");
+
   auto & dofs_storage = this->getNewDOFDataInternal(dof_id);
   dofs_storage.support_type = support_type;
-
   this->registerDOFsInternal(dof_id, dofs_array);
 
   resizeGlobalArrays();
@@ -291,10 +319,17 @@ void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array,
 
 /* -------------------------------------------------------------------------- */
 void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array,
-                              const ID & support_group) {
+                              Mesh & mesh, const ID & support_group) {
   auto & dofs_storage = this->getNewDOFDataInternal(dof_id);
   dofs_storage.support_type = _dst_nodal;
   dofs_storage.group_support = support_group;
+  dofs_storage.mesh = &mesh;
+
+  if (registered_meshes.find(&mesh) == registered_meshes.end()) {
+    mesh.registerEventHandler(*this, _ehp_dof_manager);
+    registered_meshes.insert(&mesh);
+  }
+  mesh.registerEventHandler(dofs_storage, _ehp_dof_data);
 
   this->registerDOFsInternal(dof_id, dofs_array);
 
@@ -319,22 +354,22 @@ DOFManager::registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) {
     std::function<Idx(Idx)> getNode;
     if (group == "__mesh__") {
       AKANTU_DEBUG_ASSERT(
-          dofs_array.size() == this->mesh->getNbNodes(),
+          dofs_array.size() == dof_data.mesh->getNbNodes(),
           "The array of dof is too short to be associated to nodes.");
 
-      std::tie(nb_local_dofs, nb_pure_local) = countDOFsForNodes(
-          dof_data, this->mesh->getNbNodes(), [](auto && n) { return n; });
+      std::tie(nb_local_dofs, nb_pure_local) = dof_data.countDOFsForNodes(
+          dof_data.mesh->getNbNodes(), [](auto && n) { return n; });
     } else {
       const auto & node_group =
-          this->mesh->getElementGroup(group).getNodeGroup().getNodes();
+          dof_data.mesh->getElementGroup(group).getNodeGroup().getNodes();
 
       AKANTU_DEBUG_ASSERT(
           dofs_array.size() == node_group.size(),
-          "The array of dof is too shot to be associated to nodes.");
+          "The array of dof is too short to be associated to nodes.");
 
-      std::tie(nb_local_dofs, nb_pure_local) =
-          countDOFsForNodes(dof_data, node_group.size(),
-                            [&node_group](auto && n) { return node_group(n); });
+      std::tie(nb_local_dofs, nb_pure_local) = dof_data.countDOFsForNodes(
+          node_group.size(),
+          [&node_group](auto && n) { return node_group(n); });
     }
 
     break;
@@ -367,13 +402,13 @@ DOFManager::registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) {
     const auto & group = dof_data.group_support;
     if (group != "__mesh__") {
       auto & support_nodes =
-          this->mesh->getElementGroup(group).getNodeGroup().getNodes();
+          dof_data.mesh->getElementGroup(group).getNodeGroup().getNodes();
       this->updateDOFsData(
           dof_data, nb_local_dofs, nb_pure_local, support_nodes.size(),
           [&support_nodes](Idx node) -> Idx { return support_nodes[node]; });
     } else {
       this->updateDOFsData(dof_data, nb_local_dofs, nb_pure_local,
-                           mesh->getNbNodes(),
+                           dof_data.mesh->getNbNodes(),
                            [](Idx node) -> Idx { return node; });
     }
     break;
@@ -624,11 +659,9 @@ void DOFManager::zeroLumpedMatrix(const ID & mtx) {
 std::pair<Int, Int> DOFManager::updateNodalDOFs(const ID & dof_id,
                                                 const Array<Idx> & nodes_list) {
   auto & dof_data = this->getDOFData(dof_id);
-  Int nb_new_local_dofs, nb_new_pure_local;
 
-  std::tie(nb_new_local_dofs, nb_new_pure_local) =
-      countDOFsForNodes(dof_data, nodes_list.size(),
-                        [&nodes_list](auto && n) { return nodes_list(n); });
+  auto && [nb_new_local_dofs, nb_new_pure_local] = dof_data.countDOFsForNodes(
+      nodes_list.size(), [&nodes_list](auto && n) { return nodes_list(n); });
 
   this->pure_local_system_size += nb_new_pure_local;
   this->local_system_size += nb_new_local_dofs;
@@ -664,42 +697,21 @@ void DOFManager::resizeGlobalArrays() {
 }
 
 /* -------------------------------------------------------------------------- */
-void DOFManager::onNodesAdded(const Array<Idx> & 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<Idx> new_nodes_list;
-      for (const auto & node : nodes_list) {
-        if (node_group.find(node) != Int(-1)) {
-          new_nodes_list.push_back(node);
-        }
-      }
-
-      this->updateNodalDOFs(dof_id, new_nodes_list);
-    }
-  }
-
+void DOFManager::onNodesAdded(const Array<Idx> & /*nodes_list*/,
+                              const NewNodesEvent & /*event*/) {
   this->resizeGlobalArrays();
 }
 
 /* -------------------------------------------------------------------------- */
-void DOFManager::onMeshIsDistributed(const MeshIsDistributedEvent & /*event*/) {
-  AKANTU_DEBUG_ASSERT(this->mesh != nullptr, "The `Mesh` pointer is not set.");
+void DOFManager::onMeshIsDistributed(const MeshIsDistributedEvent & event) {
+  const Mesh * mesh = &event.getMesh();
+
+  AKANTU_DEBUG_ASSERT(this->registered_meshes.find(mesh) !=
+                          this->registered_meshes.end(),
+                      "The `Mesh` pointer is not set.");
 
   // check if the distributed state of the residual and the mesh are the same.
-  if (this->mesh->isDistributed() != this->residual->isDistributed()) {
+  if (mesh->isDistributed() != this->residual->isDistributed()) {
     // TODO: Allow to reallocate the internals, in that case one could actually
     // react on that event.
     auto is_or_is_not = [](bool q) {
@@ -708,7 +720,7 @@ void DOFManager::onMeshIsDistributed(const MeshIsDistributedEvent & /*event*/) {
     AKANTU_EXCEPTION("There is an inconsistency about the distribution state "
                      "of the `DOFManager`."
                      " It seams that the `Mesh` "
-                     << is_or_is_not(this->mesh->isDistributed())
+                     << is_or_is_not(mesh->isDistributed())
                      << " distributed, but the `DOFManager`'s residual "
                      << is_or_is_not(this->residual->isDistributed())
                      << ", which is of type "
@@ -723,11 +735,8 @@ public:
   GlobalDOFInfoDataAccessor(DOFManager::DOFData & dof_data,
                             DOFManager & dof_manager)
       : dof_data(dof_data), dof_manager(dof_manager) {
-    for (auto && pair :
+    for (auto && [dof, node] :
          zip(dof_data.local_equation_number, dof_data.associated_nodes)) {
-      Idx node;
-      Idx dof;
-      std::tie(dof, node) = pair;
 
       dofs_per_node[node].push_back(dof);
     }
@@ -806,7 +815,7 @@ auto DOFManager::computeFirstDOFIDs(Int nb_new_local_dofs,
 /* -------------------------------------------------------------------------- */
 void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
                                 Int nb_new_pure_local, Int nb_node,
-                                const std::function<Idx(Idx)> & getNode) {
+                                const std::function<Idx(Idx)> & get_node) {
   auto nb_local_dofs_added = nb_node * dof_data.dof->getNbComponent();
 
   auto first_dof_pos = dof_data.local_equation_number.size();
@@ -821,17 +830,17 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
   std::unordered_map<std::pair<Idx, Idx>, Idx> masters_dofs;
 
   // update per dof info
-  Int local_eq_num, first_global_dof_id;
-  std::tie(local_eq_num, first_global_dof_id) =
+  auto && [local_eq_num, first_global_dof_id] =
       computeFirstDOFIDs(nb_new_local_dofs, nb_new_pure_local);
+
   for (auto d : arange(nb_local_dofs_added)) {
-    auto node = getNode(d / dof_data.dof->getNbComponent());
-    auto dof_flag = this->mesh->getNodeFlag(node);
+    auto node = get_node(d / dof_data.dof->getNbComponent());
+    auto dof_flag = dof_data.mesh->getNodeFlag(node);
 
     dof_data.associated_nodes.push_back(node);
-    auto is_local_dof = this->mesh->isLocalOrMasterNode(node);
-    auto is_periodic_slave = this->mesh->isPeriodicSlave(node);
-    auto is_periodic_master = this->mesh->isPeriodicMaster(node);
+    auto is_local_dof = dof_data.mesh->isLocalOrMasterNode(node);
+    auto is_periodic_slave = dof_data.mesh->isPeriodicSlave(node);
+    auto is_periodic_master = dof_data.mesh->isPeriodicMaster(node);
 
     if (is_periodic_slave) {
       dof_data.local_equation_number.push_back(-1);
@@ -851,7 +860,7 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
     }
 
     if (is_periodic_master) {
-      auto node = getNode(d / dof_data.dof->getNbComponent());
+      auto node = get_node(d / dof_data.dof->getNbComponent());
       auto dof = d % dof_data.dof->getNbComponent();
       masters_dofs.insert(
           std::make_pair(std::make_pair(node, dof), local_eq_num));
@@ -861,15 +870,15 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
   }
 
   // correct periodic slave equation numbers
-  if (this->mesh->isPeriodic()) {
+  if (dof_data.mesh->isPeriodic()) {
     auto assoc_begin = dof_data.associated_nodes.begin();
     for (auto d : arange(nb_local_dofs_added)) {
       auto node = dof_data.associated_nodes(first_dof_pos + d);
-      if (not this->mesh->isPeriodicSlave(node)) {
+      if (not dof_data.mesh->isPeriodicSlave(node)) {
         continue;
       }
 
-      auto master_node = this->mesh->getPeriodicMaster(node);
+      auto master_node = dof_data.mesh->getPeriodicMaster(node);
       auto dof = d % dof_data.dof->getNbComponent();
       dof_data.local_equation_number(first_dof_pos + d) =
           masters_dofs[std::make_pair(master_node, dof)];
@@ -877,15 +886,15 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
   }
 
   // synchronize the global numbering for slaves nodes
-  if (this->mesh->isDistributed()) {
+  if (dof_data.mesh->isDistributed()) {
     GlobalDOFInfoDataAccessor data_accessor(dof_data, *this);
 
-    if (this->mesh->isPeriodic()) {
-      mesh->getPeriodicNodeSynchronizer().synchronizeOnce(
+    if (dof_data.mesh->isPeriodic()) {
+      dof_data.mesh->getPeriodicNodeSynchronizer().synchronizeOnce(
           data_accessor, SynchronizationTag::_giu_global_conn);
     }
 
-    auto & node_synchronizer = this->mesh->getNodeSynchronizer();
+    auto & node_synchronizer = dof_data.mesh->getNodeSynchronizer();
     node_synchronizer.synchronizeOnce(data_accessor,
                                       SynchronizationTag::_ask_nodes);
   }
@@ -897,8 +906,7 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
   dof_data.local_equation_number.reserve(dof_data.local_equation_number.size() +
                                          nb_new_local_dofs);
 
-  Int first_local_dof_id, first_global_dof_id;
-  std::tie(first_local_dof_id, first_global_dof_id) =
+  auto [first_local_dof_id, first_global_dof_id] =
       computeFirstDOFIDs(nb_new_local_dofs, nb_new_pure_local);
 
   this->dofs_flag.resize(this->local_system_size, NodeFlag::_normal);
@@ -919,25 +927,6 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
   }
 }
 
-/* -------------------------------------------------------------------------- */
-void DOFManager::onNodesRemoved(const Array<Idx> &, const Array<Idx> &,
-                                const RemovedNodesEvent &) {}
-
-/* -------------------------------------------------------------------------- */
-void DOFManager::onElementsAdded(const Array<Element> & /*unused*/,
-                                 const NewElementsEvent & /*unused*/) {}
-
-/* -------------------------------------------------------------------------- */
-void DOFManager::onElementsRemoved(const Array<Element> &,
-                                   const ElementTypeMapArray<Idx> &,
-                                   const RemovedElementsEvent &) {}
-
-/* -------------------------------------------------------------------------- */
-void DOFManager::onElementsChanged(const Array<Element> &,
-                                   const Array<Element> &,
-                                   const ElementTypeMapArray<Idx> &,
-                                   const ChangedElementsEvent &) {}
-
 /* -------------------------------------------------------------------------- */
 void DOFManager::updateGlobalBlockedDofs() {
   this->previous_global_blocked_dofs.copy(this->global_blocked_dofs);
diff --git a/src/model/common/dof_manager/dof_manager.hh b/src/model/common/dof_manager/dof_manager.hh
index 8b14df5cc45bfacd43181bdc50e83b1398702478..a715dba6a95c7a75bbba15b05a3f27c9a575aa3d 100644
--- a/src/model/common/dof_manager/dof_manager.hh
+++ b/src/model/common/dof_manager/dof_manager.hh
@@ -21,6 +21,8 @@
 /* -------------------------------------------------------------------------- */
 #include "aka_factory.hh"
 #include "mesh.hh"
+#include "non_linear_solver.hh"
+#include "time_step_solver.hh"
 /* -------------------------------------------------------------------------- */
 #include <map>
 #include <set>
@@ -49,8 +51,7 @@ protected:
 
 public:
   DOFManager(const ID & id = "dof_manager");
-  DOFManager(Mesh & mesh, const ID & id = "dof_manager");
-  ~DOFManager() override;
+  ~DOFManager() = default;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
@@ -63,7 +64,7 @@ public:
   /// 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 & support_group);
+                            Mesh & mesh, const ID & support_group = "__mesh__");
 
   /// register an array of previous values of the degree of freedom
   virtual void registerDOFsPrevious(const ID & dof_id,
@@ -99,8 +100,9 @@ public:
    * 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,
-      ElementType type, GhostType ghost_type, Real scale_factor = 1.,
+      const ID & dof_id, const Array<Real> & elementary_vect,
+      Array<Real> & array_assembeled, ElementType type, GhostType ghost_type,
+      Real scale_factor = 1.,
       const Array<Int> & filter_elements = empty_filter);
 
   /**
@@ -133,7 +135,7 @@ public:
       const Array<Real> & elementary_mat, ElementType type,
       GhostType ghost_type = _not_ghost,
       const MatrixType & elemental_matrix_type = _symmetric,
-      const Array<Int> & filter_elements = empty_filter) = 0;
+      const Array<Int> & filter_elements = empty_filter);
 
   /// multiply a vector by a matrix and assemble the result to the residual
   virtual void assembleMatMulVectToArray(const ID & dof_id, const ID & A_id,
@@ -469,12 +471,7 @@ public:
   bool hasTimeStepSolver(const ID & solver_id) const;
 
   /* ------------------------------------------------------------------------ */
-  const Mesh & getMesh() {
-    if (mesh != nullptr) {
-      return *mesh;
-    }
-    AKANTU_EXCEPTION("No mesh registered in this dof manager");
-  }
+  const Mesh & getMesh(const ID & dof_id) const;
 
   /* ------------------------------------------------------------------------ */
   AKANTU_GET_MACRO_AUTO(Communicator, communicator);
@@ -496,10 +493,6 @@ protected:
   virtual std::pair<Int, Int> updateNodalDOFs(const ID & dof_id,
                                               const Array<Idx> & nodes_list);
 
-  template <typename Func>
-  auto countDOFsForNodes(const DOFData & dof_data, Int nb_nodes,
-                         Func && getNode);
-
   void updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs,
                       Int nb_new_pure_local, Int nb_nodes,
                       const std::function<Idx(Idx)> & getNode);
@@ -513,30 +506,6 @@ protected:
   /// cleaning matrices profiles
   virtual void resizeGlobalArrays();
 
-public:
-  /// function to implement to react on  akantu::NewNodesEvent
-  void onNodesAdded(const Array<Idx> & nodes_list,
-                    const NewNodesEvent & event) override;
-  /// function to implement to react on  akantu::RemovedNodesEvent
-  void onNodesRemoved(const Array<Idx> & nodes_list,
-                      const Array<Idx> & 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<Idx> & 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<Idx> & new_numbering,
-                         const ChangedElementsEvent & event) override;
-
-  /// function to implement to react on  akantu::MeshIsDistributedEvent
-  void onMeshIsDistributed(const MeshIsDistributedEvent & event) override;
-
 protected:
   inline DOFData & getDOFData(const ID & dof_id);
   inline const DOFData & getDOFData(const ID & dof_id) const;
@@ -547,16 +516,36 @@ protected:
 
   virtual std::unique_ptr<DOFData> getNewDOFData(const ID & dof_id) = 0;
 
+public:
+  /// function to implement to react on  akantu::NewNodesEvent
+  void onNodesAdded(const Array<Idx> & nodes_list,
+                    const NewNodesEvent & event) override;
+
+  /// function to implement to react on  akantu::MeshIsDistributedEvent
+  void onMeshIsDistributed(const MeshIsDistributedEvent & event) override;
+
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// dof representations in the dof manager
-  struct DOFData {
+  struct DOFData : public MeshEventHandler {
     DOFData() = delete;
     explicit DOFData(const ID & dof_id);
-    virtual ~DOFData();
 
+    template <typename Func>
+    [[nodiscard]] auto countDOFsForNodes(Int nb_nodes, Func && get_node) const;
+
+    virtual Array<Idx> & getLocalEquationsNumbers() {
+      return local_equation_number;
+    }
+
+    /// function to implement to react on  akantu::NewNodesEvent
+    void onNodesAdded(const Array<Idx> & nodes_list,
+                      const NewNodesEvent & event) override;
+
+  public:
+    ID dof_id;
     /// DOF support type (nodal, general) this is needed to determine how the
     /// dof are shared among processors
     DOFSupportType support_type;
@@ -597,12 +586,13 @@ protected:
     /// local numbering equation numbers
     Array<Idx> local_equation_number;
 
+    /// reference to the underlying mesh
+    const Mesh * mesh{nullptr};
+
+    DOFManager * dof_manager{nullptr};
+
     /// associated node for _dst_nodal dofs only
     Array<Idx> associated_nodes;
-
-    virtual Array<Idx> & getLocalEquationsNumbers() {
-      return local_equation_number;
-    }
   };
 
   /// type to store dofs information
@@ -637,9 +627,6 @@ protected:
   /// 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)
   Int local_system_size{0};
 
@@ -695,10 +682,12 @@ protected:
 private:
   /// This is for unit testing
   friend class DOFManagerTester;
+
+  std::set<const Mesh *> registered_meshes;
 };
 
 using DefaultDOFManagerFactory = Factory<DOFManager, ID, const ID &>;
-using DOFManagerFactory = Factory<DOFManager, ID, Mesh &, const ID &>;
+using DOFManagerFactory = Factory<DOFManager, ID, const ID &>;
 
 } // namespace akantu
 
diff --git a/src/model/common/dof_manager/dof_manager_default.cc b/src/model/common/dof_manager/dof_manager_default.cc
index 361cc8c867605a95b7fe262d64d22297b8dbf239..eac4ab08cfb3dbda4643bc839a6db8a935da90fa 100644
--- a/src/model/common/dof_manager/dof_manager_default.cc
+++ b/src/model/common/dof_manager/dof_manager_default.cc
@@ -41,40 +41,31 @@ namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 DOFManagerDefault::DOFManagerDefault(const ID & id)
-    : DOFManager(id), synchronizer(nullptr) {
-  residual = std::make_unique<SolverVectorDefault>(
-      *this, std::string(id + ":residual"));
-  solution = std::make_unique<SolverVectorDefault>(
-      *this, std::string(id + ":solution"));
-  data_cache = std::make_unique<SolverVectorDefault>(
-      *this, std::string(id + ":data_cache"));
-}
-
-/* -------------------------------------------------------------------------- */
-DOFManagerDefault::DOFManagerDefault(Mesh & mesh, const ID & id)
-    : DOFManager(mesh, id), synchronizer(nullptr) {
-  if (this->mesh->isDistributed()) {
-    this->synchronizer = std::make_unique<DOFSynchronizer>(
-        *this, this->id + ":dof_synchronizer");
-    residual = std::make_unique<SolverVectorDistributed>(
-        *this, std::string(id + ":residual"));
-    solution = std::make_unique<SolverVectorDistributed>(
-        *this, std::string(id + ":solution"));
-    data_cache = std::make_unique<SolverVectorDistributed>(
-        *this, std::string(id + ":data_cache"));
-
-  } else {
-    residual = std::make_unique<SolverVectorDefault>(
-        *this, std::string(id + ":residual"));
-    solution = std::make_unique<SolverVectorDefault>(
-        *this, std::string(id + ":solution"));
-    data_cache = std::make_unique<SolverVectorDefault>(
-        *this, std::string(id + ":data_cache"));
-  }
-}
+    : DOFManager(id), synchronizer(nullptr) {}
 
-/* -------------------------------------------------------------------------- */
 DOFManagerDefault::~DOFManagerDefault() = default;
+/* -------------------------------------------------------------------------- */
+// DOFManagerDefault::DOFManagerDefault(Mesh & mesh, const ID & id)
+//     : DOFManager(mesh, id), synchronizer(nullptr) {
+//   if (this->mesh->isDistributed()) {
+//     this->synchronizer = std::make_unique<DOFSynchronizer>(
+//         *this, this->id + ":dof_synchronizer");
+//     residual = std::make_unique<SolverVectorDistributed>(
+//         *this, std::string(id + ":residual"));
+//     solution = std::make_unique<SolverVectorDistributed>(
+//         *this, std::string(id + ":solution"));
+//     data_cache = std::make_unique<SolverVectorDistributed>(
+//         *this, std::string(id + ":data_cache"));
+
+//   } else {
+//     residual = std::make_unique<SolverVectorDefault>(
+//         *this, std::string(id + ":residual"));
+//     solution = std::make_unique<SolverVectorDefault>(
+//         *this, std::string(id + ":solution"));
+//     data_cache = std::make_unique<SolverVectorDefault>(
+//         *this, std::string(id + ":data_cache"));
+//   }
+// }
 
 /* -------------------------------------------------------------------------- */
 void DOFManagerDefault::makeConsistentForPeriodicity(const ID & dof_id,
@@ -84,11 +75,11 @@ void DOFManagerDefault::makeConsistentForPeriodicity(const ID & dof_id,
     return;
   }
 
-  if (not mesh->isPeriodic()) {
+  if (not dof_data.mesh->isPeriodic()) {
     return;
   }
 
-  this->mesh->getPeriodicNodeSynchronizer()
+  dof_data.mesh->getPeriodicNodeSynchronizer()
       .reduceSynchronizeWithPBCSlaves<AddOperation>(
           aka::as_type<SolverVectorDefault>(array).getVector());
 }
@@ -107,7 +98,7 @@ void DOFManagerDefault::assembleToGlobalArray(
                       "The array to assemble does not have a correct size."
                           << " (" << array_to_assemble.getID() << ")");
 
-  if (dof_data.support_type == _dst_nodal and mesh->isPeriodic()) {
+  if (dof_data.support_type == _dst_nodal and dof_data.mesh->isPeriodic()) {
     for (auto && data :
          zip(dof_data.local_equation_number, dof_data.associated_nodes,
              make_view(array_to_assemble))) {
@@ -162,11 +153,37 @@ DOFManagerDefault::registerDOFsInternal(const ID & dof_id,
                                         Array<Real> & dofs_array) {
   auto ret = DOFManager::registerDOFsInternal(dof_id, dofs_array);
 
-  // update the synchronizer if needed
-  if (this->synchronizer) {
-    this->synchronizer->registerDOFs(dof_id);
+  auto & dof_data = aka::as_type<DOFDataDefault>(this->getDOFData(dof_id));
+
+  if (residual == nullptr) {
+    if (dof_data.mesh != nullptr and dof_data.mesh->isDistributed()) {
+      residual = std::make_unique<SolverVectorDistributed>(
+          *this, std::string(id + ":residual"));
+      solution = std::make_unique<SolverVectorDistributed>(
+          *this, std::string(id + ":solution"));
+      data_cache = std::make_unique<SolverVectorDistributed>(
+          *this, std::string(id + ":data_cache"));
+    } else {
+      residual = std::make_unique<SolverVectorDefault>(
+          *this, std::string(id + ":residual"));
+      solution = std::make_unique<SolverVectorDefault>(
+          *this, std::string(id + ":solution"));
+      data_cache = std::make_unique<SolverVectorDefault>(
+          *this, std::string(id + ":data_cache"));
+    }
+  }
+
+  if (dof_data.mesh == nullptr) {
+    return ret;
   }
 
+  if (not hasSynchronizer()) {
+    synchronizer = std::make_unique<DOFSynchronizer>(
+        *this, this->id + ":dof_synchronizer");
+  }
+
+  synchronizer->registerDOFs(dof_id);
+
   return ret;
 }
 
@@ -302,7 +319,8 @@ void DOFManagerDefault::assembleMatMulVectToArray(const ID & dof_id,
                                                   const Array<Real> & x,
                                                   Array<Real> & array,
                                                   Real scale_factor) {
-  if (mesh->isDistributed()) {
+  auto & dof_data = this->getDOFData(dof_id);
+  if (dof_data.mesh->isDistributed()) {
     DOFManager::assembleMatMulVectToArray_<SolverVectorDistributed>(
         dof_id, A_id, x, array, scale_factor);
   } else {
@@ -326,7 +344,7 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id,
   auto type_pair = std::make_pair(type, ghost_type);
 
   auto prof_it = this->matrix_profiled_dofs.find(mat_dof);
-  if (prof_it != this->matrix_profiled_dofs.end() &&
+  if (prof_it != this->matrix_profiled_dofs.end() and
       std::find(prof_it->second.begin(), prof_it->second.end(), type_pair) !=
           prof_it->second.end()) {
     return;
@@ -342,7 +360,7 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id,
 
   auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 
-  const auto & connectivity = this->mesh->getConnectivity(type, ghost_type);
+  const auto & connectivity = dof_data.mesh->getConnectivity(type, ghost_type);
   auto cbegin = connectivity.begin(nb_nodes_per_element);
   auto cit = cbegin;
 
@@ -350,7 +368,7 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id,
   const Int * ge_it = nullptr;
   if (dof_data.group_support != "__mesh__") {
     const auto & group_elements =
-        this->mesh->getElementGroup(dof_data.group_support)
+        dof_data.mesh->getElementGroup(dof_data.group_support)
             .getElements(type, ghost_type);
     ge_it = group_elements.data();
     nb_elements = group_elements.size();
@@ -376,15 +394,15 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id,
       ++cit;
     }
 
-    for (Int i = 0; i < size_mat; ++i) {
-      auto c_irn = element_eq_nb(i);
-      if (c_irn < size) {
-        for (Int j = 0; j < size_mat; ++j) {
-          auto c_jcn = element_eq_nb(j);
-          if (c_jcn < size) {
-            A.add(c_irn, c_jcn);
-          }
+    for (auto c_irn : element_eq_nb) {
+      if (c_irn >= size) {
+        continue;
+      }
+      for (auto c_jcn : element_eq_nb) {
+        if (c_jcn >= size) {
+          continue;
         }
+        A.add(c_irn, c_jcn);
       }
     }
   }
@@ -414,8 +432,8 @@ void DOFManagerDefault::onNodesAdded(const Array<Idx> & nodes_list,
                                      const NewNodesEvent & event) {
   DOFManager::onNodesAdded(nodes_list, event);
 
-  if (this->synchronizer) {
-    this->synchronizer->onNodesAdded(nodes_list);
+  if (synchronizer) {
+    synchronizer->onNodesAdded(nodes_list);
   }
 }
 
@@ -456,17 +474,16 @@ const Array<bool> & DOFManagerDefault::getBlockedDOFs() const {
 }
 
 /* -------------------------------------------------------------------------- */
-static bool dof_manager_is_registered =
+static const bool dof_manager_is_registered =
     DOFManagerFactory::getInstance().registerAllocator(
-        "default",
-        [](Mesh & mesh, const ID & id) -> std::unique_ptr<DOFManager> {
-          return std::make_unique<DOFManagerDefault>(mesh, id);
+        "default", [](const ID & id) -> std::unique_ptr<DOFManager> {
+          return std::make_unique<DOFManagerDefault>(id);
         });
 
-static bool dof_manager_is_registered_mumps =
+static const bool dof_manager_is_registered_mumps =
     DOFManagerFactory::getInstance().registerAllocator(
-        "mumps", [](Mesh & mesh, const ID & id) -> std::unique_ptr<DOFManager> {
-          return std::make_unique<DOFManagerDefault>(mesh, id);
+        "mumps", [](const ID & id) -> std::unique_ptr<DOFManager> {
+          return std::make_unique<DOFManagerDefault>(id);
         });
 
 } // namespace akantu
diff --git a/src/model/common/dof_manager/dof_manager_default.hh b/src/model/common/dof_manager/dof_manager_default.hh
index fa26f3845ced19fade05cc7c73dee301f986ea1e..4e8cd9453e94950e85c7fffdd19afe4041ffd988 100644
--- a/src/model/common/dof_manager/dof_manager_default.hh
+++ b/src/model/common/dof_manager/dof_manager_default.hh
@@ -43,12 +43,15 @@ class DOFManagerDefault : public DOFManager {
   /* ------------------------------------------------------------------------ */
 public:
   DOFManagerDefault(const ID & id = "dof_manager_default");
-  DOFManagerDefault(Mesh & mesh, const ID & id = "dof_manager_default");
   ~DOFManagerDefault() override;
 
 protected:
   struct DOFDataDefault : public DOFData {
     explicit DOFDataDefault(const ID & dof_id);
+
+  public:
+    /// synchronizer to maintain coherency in dof fields
+    std::shared_ptr<DOFSynchronizer> synchronizer;
   };
 
   /* ------------------------------------------------------------------------ */
@@ -114,9 +117,6 @@ public:
   /// update the global dofs vector
   void updateGlobalBlockedDofs() override;
 
-  //   /// apply boundary conditions to jacobian matrix
-  //   void applyBoundary(const ID & matrix_id = "J") override;
-
 private:
   /// Add a symmetric matrices to a symmetric sparse matrix
   void addSymmetricElementalMatrixToSymmetric(
@@ -139,23 +139,14 @@ private:
                     GhostType ghost_type);
 
   /* ------------------------------------------------------------------------ */
-  /* MeshEventHandler interface                                               */
+  /* MeOAshEventHandler interface */
   /* ------------------------------------------------------------------------ */
 protected:
   std::tuple<Int, Int, Int>
   registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) override;
 
-  // std::pair<UInt, UInt>
-  // updateNodalDOFs(const ID & dof_id, const Array<UInt> & nodes_list)
-  // override;
-
   void resizeGlobalArrays() override;
 
-public:
-  /// function to implement to react on  akantu::NewNodesEvent
-  void onNodesAdded(const Array<Idx> & nodes_list,
-                    const NewNodesEvent & event) override;
-
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
@@ -192,6 +183,9 @@ public:
                        NonLinearSolver & non_linear_solver,
                        SolverCallback & solver_callback) override;
 
+  /* ------------------------------------------------------------------------ */
+  void onNodesAdded(const Array<Idx> & nodes_list, const NewNodesEvent & event);
+
   /* ------------------------------------------------------------------------ */
 private:
   /// Get the solution array
@@ -205,10 +199,15 @@ private:
 
 public:
   /// access the internal dof_synchronizer
-  AKANTU_GET_MACRO_NOT_CONST(Synchronizer, *synchronizer, DOFSynchronizer &);
+  DOFSynchronizer & getSynchronizer() {
+    AKANTU_DEBUG_ASSERT(synchronizer != nullptr, "DOFSynchronizer is not set");
+    return *synchronizer;
+  }
 
   /// access the internal dof_synchronizer
-  bool hasSynchronizer() const { return synchronizer != nullptr; }
+  [[nodiscard]] bool hasSynchronizer() const {
+    return (synchronizer != nullptr);
+  }
 
   Array<bool> & getBlockedDOFs();
   const Array<bool> & getBlockedDOFs() const;
@@ -227,17 +226,14 @@ protected:
   /// contains the the dofs that where added to the profile of a given matrix.
   DOFToMatrixProfile matrix_profiled_dofs;
 
-  /// synchronizer to maintain coherency in dof fields
-  std::unique_ptr<DOFSynchronizer> synchronizer;
-
   friend class DOFSynchronizer;
 
   /// Array containing the true or false if the node is in global_blocked_dofs
   Array<bool> global_blocked_dofs_uint;
+
+  std::unique_ptr<DOFSynchronizer> synchronizer;
 };
 
 } // namespace akantu
 
-#include "dof_manager_default_inline_impl.hh"
-
 #endif /* AKANTU_DOF_MANAGER_DEFAULT_HH_ */
diff --git a/src/model/common/dof_manager/dof_manager_inline_impl.hh b/src/model/common/dof_manager/dof_manager_inline_impl.hh
index 7aeedf31ecdfe335ae4b4f3ab2b72c96989794d0..1492a61f4427d4d1ab85cd977b0fc6624e952193 100644
--- a/src/model/common/dof_manager/dof_manager_inline_impl.hh
+++ b/src/model/common/dof_manager/dof_manager_inline_impl.hh
@@ -57,6 +57,14 @@ const DOFManager::DOFData & DOFManager::getDOFData(const ID & dof_id) const {
   return *it->second;
 }
 
+/* -------------------------------------------------------------------------- */
+inline const Mesh & DOFManager::getMesh(const ID & dof_id) const {
+  auto && dof_data = getDOFData(dof_id);
+  if (not dof_data.mesh) {
+    AKANTU_EXCEPTION("No mesh was associated to the dof " << dof_id);
+  }
+  return *(dof_data.mesh);
+}
 /* -------------------------------------------------------------------------- */
 inline void DOFManager::extractElementEquationNumber(
     const Array<Idx> & equation_numbers, const Vector<Idx> & connectivity,
@@ -244,20 +252,23 @@ void DOFManager::assembleElementalMatricesToMatrix_(
 
   const auto & equation_number = this->getLocalEquationsNumbers(dof_id);
 
-  Int nb_element;
+  Int nb_element{};
   const Idx * filter_it = nullptr;
+
+  const auto & connectivity = dof_data.mesh->getConnectivity(type, ghost_type);
+
   if (filter_elements != empty_filter) {
     nb_element = filter_elements.size();
     filter_it = filter_elements.data();
   } else {
     if (dof_data.group_support != "__mesh__") {
       const auto & group_elements =
-          this->mesh->getElementGroup(dof_data.group_support)
+          dof_data.mesh->getElementGroup(dof_data.group_support)
               .getElements(type, ghost_type);
       nb_element = group_elements.size();
       filter_it = group_elements.data();
     } else {
-      nb_element = this->mesh->getNbElement(type, ghost_type);
+      nb_element = connectivity.size();
     }
   }
 
@@ -266,11 +277,10 @@ void DOFManager::assembleElementalMatricesToMatrix_(
                           << elementary_mat.getID()
                           << ") has not the good size.");
 
-  auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+  auto nb_nodes_per_element = connectivity.getNbComponent();
 
   auto nb_degree_of_freedom = dof_data.dof->getNbComponent();
 
-  const auto & connectivity = this->mesh->getConnectivity(type, ghost_type);
   auto conn_begin = connectivity.begin(nb_nodes_per_element);
   auto conn_it = conn_begin;
   auto size_mat = nb_nodes_per_element * nb_degree_of_freedom;
@@ -323,4 +333,4 @@ void DOFManager::assemblePreassembledMatrix_(Mat & A,
 
 } // namespace akantu
 
-//#endif /* __AKANTU_DOF_MANAGER_INLINE_IMPL_CC__ */
+// #endif /* __AKANTU_DOF_MANAGER_INLINE_IMPL_CC__ */
diff --git a/src/model/common/dof_manager/dof_manager_petsc.cc b/src/model/common/dof_manager/dof_manager_petsc.cc
index e2bdd3addd4c9721943adeba609b164bf2787e4d..d7f3ccd6d32a4392431a30663a51a7d7ff2d32d0 100644
--- a/src/model/common/dof_manager/dof_manager_petsc.cc
+++ b/src/model/common/dof_manager/dof_manager_petsc.cc
@@ -190,13 +190,13 @@ void DOFManagerPETSc::getArrayPerDOFs(const ID & dof_id,
 /* -------------------------------------------------------------------------- */
 void DOFManagerPETSc::assembleElementalMatricesToMatrix(
     const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat,
-    ElementType type, GhostType ghost_type,
+    const Array<Idx> & connectivity, ElementType type, GhostType ghost_type,
     const MatrixType & elemental_matrix_type,
     const Array<Int> & filter_elements) {
   auto & A = getMatrix(matrix_id);
   DOFManager::assembleElementalMatricesToMatrix_(
-      A, dof_id, elementary_mat, type, ghost_type, elemental_matrix_type,
-      filter_elements);
+      A, dof_id, elementary_mat, connectivity, type, ghost_type,
+      elemental_matrix_type, filter_elements);
 
   A.applyModifications();
 }
diff --git a/src/model/common/dof_manager/dof_manager_petsc.hh b/src/model/common/dof_manager/dof_manager_petsc.hh
index 88370ea029542ff4d5a430fe6bbe0eb7972d578a..4411cefb1229ff617e8d94e1bbb1f4bd255c7558 100644
--- a/src/model/common/dof_manager/dof_manager_petsc.hh
+++ b/src/model/common/dof_manager/dof_manager_petsc.hh
@@ -82,29 +82,27 @@ protected:
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
-  void assembleToLumpedMatrix(const ID & /*dof_id*/,
-                              Array<Real> & /*array_to_assemble*/,
-                              const ID & /*lumped_mtx*/,
-                              Real /*scale_factor*/ = 1.) override {
+  void assembleToLumpedMatrix(const ID & dof_id,
+                              Array<Real> & array_to_assemble,
+                              const ID & lumped_mtx,
+                              Real scale_factor = 1.) override {
     AKANTU_TO_IMPLEMENT();
   }
 
   void assembleElementalMatricesToMatrix(
-      const ID & /*matrix_id*/, const ID & /*dof_id*/,
-      const Array<Real> & /*elementary_mat*/, ElementType /*type*/,
-      GhostType /*ghost_type*/,
-      const MatrixType & /*elemental_matrix_type*/,
-      const Array<Idx> & /*filter_elements*/) override;
-
-  void assembleMatMulVectToArray(const ID & /*dof_id*/, const ID & /*A_id*/,
-                                 const Array<Real> & /*x*/,
-                                 Array<Real> & /*array*/,
-                                 Real /*scale_factor*/ = 1.) override;
-
-  void assembleLumpedMatMulVectToResidual(const ID & /*dof_id*/,
-                                          const ID & /*A_id*/,
-                                          const Array<Real> & /*x*/,
-                                          Real /*scale_factor*/ = 1) override {
+      const ID & matrix_id, const ID & dof_id,
+      const Array<Real> & elementary_mat, const Array<Idx> & connectivity,
+      ElementType type, GhostType ghost_type,
+      const MatrixType & elemental_matrix_type,
+      const Array<Idx> & filter_elements) override;
+
+  void assembleMatMulVectToArray(const ID & dof_id, const ID & A_id,
+                                 const Array<Real> & x, Array<Real> & array,
+                                 Real scale_factor = 1.) override;
+
+  void assembleLumpedMatMulVectToResidual(const ID & dof_id, const ID & A_id,
+                                          const Array<Real> & x,
+                                          Real scale_factor = 1) override {
     AKANTU_TO_IMPLEMENT();
   }
 
diff --git a/src/model/common/model_solver.cc b/src/model/common/model_solver.cc
index 8d1b7258dc8aebca5205a97a0b2511eb2e779f30..92f4a9f556bc542a84b68e5595a27cfb7d0b7e78 100644
--- a/src/model/common/model_solver.cc
+++ b/src/model/common/model_solver.cc
@@ -80,7 +80,7 @@ ModelSolver::initDOFManager(const std::shared_ptr<DOFManager> & dof_manager) {
   ID solver_type = "default";
 
 #if defined(AKANTU_USE_MUMPS)
-  solver_type = "default";
+  solver_type = "mumps";
 #elif defined(AKANTU_USE_PETSC)
   solver_type = "petsc";
 #endif
@@ -103,7 +103,7 @@ ModelSolver::initDOFManager(const ID & solver_type) {
 
   try {
     this->dof_manager = DOFManagerFactory::getInstance().allocate(
-        solver_type, mesh, this->id + ":dof_manager_" + solver_type);
+        solver_type, this->id + ":dof_manager_" + solver_type);
   } catch (...) {
     AKANTU_EXCEPTION(
         "To use the solver "
diff --git a/src/model/common/non_local_toolbox/base_distance_function.cc b/src/model/common/non_local_toolbox/base_distance_function.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a96c5c1ea14b11d2dc5fa19ff35ff6c066abc51e
--- /dev/null
+++ b/src/model/common/non_local_toolbox/base_distance_function.cc
@@ -0,0 +1,28 @@
+/**
+ * Copyright (©) 2022-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "base_distance_function.hh"
+
+namespace akantu {
+
+// TODO : MODIFY THIS ???
+INSTANTIATE_CLIP_NEIGHBORHOOD(base_dist, BaseDistanceFunction);
+
+} // namespace akantu
diff --git a/src/model/common/non_local_toolbox/base_distance_function.hh b/src/model/common/non_local_toolbox/base_distance_function.hh
new file mode 100644
index 0000000000000000000000000000000000000000..15bacdf36616bb3787634c9814900b293db11f08
--- /dev/null
+++ b/src/model/common/non_local_toolbox/base_distance_function.hh
@@ -0,0 +1,170 @@
+/**
+ * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_factory.hh"
+#include "data_accessor.hh"
+#include "model.hh"
+#include "non_local_manager.hh"
+#include "clip_neighborhood.hh"
+#include "parsable.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_BASE_DISTANCE_FUNCTION_HH_
+#define AKANTU_BASE_DISTANCE_FUNCTION_HH_
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+/*  Normal weight function                                                    */
+/* -------------------------------------------------------------------------- */
+class BaseDistanceFunction : public Parsable, public DataAccessor<Element> {
+public:
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+  BaseDistanceFunction(NonLocalManager & manager,
+                     const std::string & type = "base")
+      : Parsable(ParserType::_distance_function, "distance_function:" + type),
+        manager(manager), type(type),
+        spatial_dimension(manager.getModel().getMesh().getSpatialDimension()) {
+    this->registerParam("update_rate", update_rate, Int(1), _pat_parsmod,
+                        "Update frequency");
+  }
+
+  ~BaseDistanceFunction() override = default;
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+  /// initialize the weight function
+  virtual inline void init();
+
+  /// update the internal parameters
+  virtual void updateInternals(){};
+
+  /* ------------------------------------------------------------------------ */
+  /// set the non-local radius
+  inline void setRadius(Real radius);
+
+  /* ------------------------------------------------------------------------ */
+  /// compute the weight for a given distance between two quadrature points
+  inline Real operator()(Real r, const IntegrationPoint & q1,
+                         const IntegrationPoint & q2) const;
+
+  /// print function
+  void printself(std::ostream & stream, int indent = 0) const override {
+    std::string space;
+    for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) {
+      ;
+    }
+    stream << space << "WeightFunction " << type << " [" << std::endl;
+    Parsable::printself(stream, indent);
+    stream << space << "]" << std::endl;
+  }
+
+  /* --------------------------------------------------------------------------
+   */
+  /* Accessors */
+  /* --------------------------------------------------------------------------
+   */
+
+public:
+  /// get the radius
+  Real getRadius() const { return R; }
+  /// get the update rate
+  Int getUpdateRate() const { return update_rate; }
+
+public:
+  /* ------------------------------------------------------------------------ */
+  /* Data Accessor inherited members                                          */
+  /* ------------------------------------------------------------------------ */
+
+  Int getNbData(const Array<Element> &,
+                const SynchronizationTag &) const override {
+    return 0;
+  }
+
+  inline void packData(CommunicationBuffer & /*buffer*/,
+                       const Array<Element> & /*element*/,
+                       const SynchronizationTag & /*tag*/) const override {}
+
+  inline void unpackData(CommunicationBuffer & /*buffer*/,
+                         const Array<Element> & /*element*/,
+                         const SynchronizationTag & /*tag*/) override {}
+
+  /* ------------------------------------------------------------------------ */
+  /* Accessors */
+  /* ------------------------------------------------------------------------ */
+public:
+  AKANTU_GET_MACRO(Type, type, const ID &);
+
+protected:
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+  /// reference to the non-local manager
+  NonLocalManager & manager;
+
+  /// the non-local radius
+  Real R;
+
+  /// the non-local radius squared
+  Real R2;
+
+  /// the update rate
+  Int update_rate;
+
+  /// name of the type of weight function
+  const std::string type;
+
+  /// the spatial dimension
+  Int spatial_dimension;
+};
+
+inline std::ostream & operator<<(std::ostream & stream,
+                                 const BaseDistanceFunction & _this) {
+  _this.printself(stream);
+  return stream;
+}
+
+#define INSTANTIATE_CLIP_NEIGHBORHOOD(id, distance_fun_name)                       \
+  static bool distance_is_alocated_##id [[gnu::unused]] =                        \
+      NonLocalNeighborhoodFactory::getInstance().registerAllocator(            \
+          #id,                                                                 \
+          [](const ID & /*name*/, NonLocalManager & non_local_manager,         \
+             const ElementTypeMapReal & quad_point_positions, const ID & id) { \
+            return std::make_unique<CLIPNeighborhood<distance_fun_name>>(    \
+                non_local_manager, quad_point_positions, id);                  \
+          })
+
+} // namespace akantu
+
+#include "base_distance_function_inline_impl.hh"
+
+/* -------------------------------------------------------------------------- */
+/* Include all other distance function types                                    */
+/* -------------------------------------------------------------------------- */
+#if defined(AKANTU_DAMAGE_NON_LOCAL)
+// in case other distance functions are defined
+#endif
+/* -------------------------------------------------------------------------- */
+
+#endif /* AKANTU_BASE_DISTANCE_FUNCTION_HH_ */
diff --git a/src/model/common/non_local_toolbox/base_distance_function_inline_impl.hh b/src/model/common/non_local_toolbox/base_distance_function_inline_impl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..144a7efb25cf1a3848b42db9438adcdd3b9fa28e
--- /dev/null
+++ b/src/model/common/non_local_toolbox/base_distance_function_inline_impl.hh
@@ -0,0 +1,53 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "base_distance_function.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_BASE_DISTANCE_FUNCTION_INLINE_IMPL_HH_
+#define AKANTU_BASE_DISTANCE_FUNCTION_INLINE_IMPL_HH_
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+inline void BaseDistanceFunction::init() {
+  /// compute R^2 for a given non-local radius
+  this->R2 = this->R * this->R;
+}
+
+/* -------------------------------------------------------------------------- */
+inline void BaseDistanceFunction::setRadius(Real radius) {
+  /// set the non-local radius and update R^2 accordingly
+  this->R = radius;
+  this->R2 = this->R * this->R;
+}
+
+/* -------------------------------------------------------------------------- */
+inline Real
+BaseDistanceFunction::operator()(Real r, const IntegrationPoint & /* q1 */,
+                               const IntegrationPoint & /* q2 */) const {
+
+  return r;
+}
+
+} // namespace akantu
+
+#endif /* AKANTU_BASE_DISTANCE_FUNCTION_INLINE_IMPL_HH_ */
diff --git a/src/model/common/non_local_toolbox/base_weight_function.hh b/src/model/common/non_local_toolbox/base_weight_function.hh
index 9a77266dbfaeeff84c5fe56fbc3a0f0a50cb9b6a..0ca6376b4d26fd58bb14c282e0585dc0a96c03da 100644
--- a/src/model/common/non_local_toolbox/base_weight_function.hh
+++ b/src/model/common/non_local_toolbox/base_weight_function.hh
@@ -145,10 +145,6 @@ inline std::ostream & operator<<(std::ostream & stream,
   return stream;
 }
 
-using NonLocalNeighborhoodFactory =
-    Factory<NonLocalNeighborhoodBase, ID, ID, NonLocalManager &,
-            const ElementTypeMapReal &, const ID &>;
-
 #define INSTANTIATE_NL_NEIGHBORHOOD(id, weight_fun_name)                       \
   static bool weigth_is_alocated_##id [[gnu::unused]] =                        \
       NonLocalNeighborhoodFactory::getInstance().registerAllocator(            \
diff --git a/src/model/common/non_local_toolbox/clip_neighborhood.hh b/src/model/common/non_local_toolbox/clip_neighborhood.hh
new file mode 100644
index 0000000000000000000000000000000000000000..a2e2e6ba5349d8b2e41dfbb701e6619ce2552954
--- /dev/null
+++ b/src/model/common/non_local_toolbox/clip_neighborhood.hh
@@ -0,0 +1,138 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_local_neighborhood_base.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_CLIPNEIGHBORHOOD_HH_
+#define AKANTU_CLIPNEIGHBORHOOD_HH_
+
+namespace akantu {
+class BaseDistanceFunction;
+class NonLocalManager;
+} // namespace akantu
+
+namespace akantu {
+
+template <class DistanceFunction = BaseDistanceFunction>
+class CLIPNeighborhood : public NonLocalNeighborhoodBase {
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  CLIPNeighborhood(NonLocalManager & manager,
+                       const ElementTypeMapReal & quad_coordinates,
+                       const ID & id = "neighborhood");
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+public:
+
+  /// create the pairs of quadrature points
+  void updatePairList() override;
+  
+  /// compute the weights for non-local averaging
+  void computeWeights() override;
+
+  /// compute the weights for non-local averaging of function derivative
+  void computeDerivativeWeights();
+
+  /// save the pair of weights in a file
+  void saveWeights(const std::string & filename) const override;
+
+  /// compute the non-local counter part for a given element type map
+  void weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate,
+                                   ElementTypeMapReal & accumulated,
+                                   Int nb_degree_of_freedom,
+                                   GhostType ghost_type2) const override;
+
+  /// compute the non-local part of clip functional derivative for a given element type map
+  void weightedDerivativeAverageOnNeighbours(const ElementTypeMapReal & to_accumulate,
+                                            ElementTypeMapReal & accumulated,
+                                            Int nb_degree_of_freedom,
+                                            GhostType ghost_type2) const;
+
+  /// update the weights based on the weight function
+  void updateWeights() override;
+
+  /// register a new non-local variable in the neighborhood
+  // void registerNonLocalVariable(const ID & id);
+protected:
+  template <class Func>
+  inline void foreach_distance(GhostType ghost_type, Func && func);
+
+  template <class Func>
+  inline void foreach_distance(GhostType ghost_type, Func && func) const;
+
+  template <class Func>
+  inline void foreach_derivative_weight(GhostType ghost_type, Func && func);
+
+  template <class Func>
+  inline void foreach_derivative_weight(GhostType ghost_type, Func && func) const;
+
+  [[nodiscard]] inline Int
+  getNbData(const Array<Element> & elements,
+            const SynchronizationTag & tag) const override;
+
+  inline void packData(CommunicationBuffer & buffer,
+                       const Array<Element> & elements,
+                       const SynchronizationTag & tag) const override;
+
+  inline void unpackData(CommunicationBuffer & buffer,
+                         const Array<Element> & elements,
+                         const SynchronizationTag & tag) override;
+
+  /* ------------------------------------------------------------------------ */
+  /* Accessor                                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  AKANTU_GET_MACRO_AUTO(NonLocalManager, non_local_manager);
+  AKANTU_GET_MACRO_AUTO_NOT_CONST(NonLocalManager, non_local_manager);
+
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+private:
+
+  /// Damage limiter value
+  Real Dm{0.};
+
+  /// Pointer to non-local manager class
+  NonLocalManager & non_local_manager;
+
+  /// the distances associated to the pairs
+  std::map<GhostType, std::unique_ptr<Array<Real>>> pair_distance;
+
+  /// the derivative weights associated to the pairs
+  std::map<GhostType, std::unique_ptr<Array<Real>>> pair_derivative_weights;
+
+  /// weight function
+  std::shared_ptr<DistanceFunction> distance_function;
+  
+};
+
+} // namespace akantu
+
+#include "clip_neighborhood_inline_impl.hh"
+#include "clip_neighborhood_tmpl.hh"
+
+#endif /* AKANTU_CLIPNEIGHBORHOOD_HH_ */
diff --git a/src/model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh b/src/model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..cadf551a697973797153ade6062f5a17e104df2c
--- /dev/null
+++ b/src/model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh
@@ -0,0 +1,77 @@
+/**
+ * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_local_neighborhood.hh"
+#include "non_local_manager.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_CLIP_NEIGHBORHOOD_INLINE_IMPL_HH_
+#define AKANTU_CLIP_NEIGHBORHOOD_INLINE_IMPL_HH_
+
+namespace akantu {
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+inline Int CLIPNeighborhood<DistanceFunction>::getNbData(
+    const Array<Element> & elements, const SynchronizationTag & tag) const {
+  Int size = 0;
+
+  if (tag == SynchronizationTag::_mnl_for_average) {
+    for (auto && variable_id : non_local_variables) {
+      size += this->non_local_manager.getNbData(elements, variable_id);
+    }
+  }
+
+  size += this->distance_function->getNbData(elements, tag);
+
+  return size;
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+inline void CLIPNeighborhood<DistanceFunction>::packData(
+    CommunicationBuffer & buffer, const Array<Element> & elements,
+    const SynchronizationTag & tag) const {
+  if (tag == SynchronizationTag::_mnl_for_average) {
+    for (auto && variable_id : non_local_variables) {
+      this->non_local_manager.packData(buffer, elements, variable_id);
+    }
+  }
+
+  this->distance_function->packData(buffer, elements, tag);
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+inline void CLIPNeighborhood<DistanceFunction>::unpackData(
+    CommunicationBuffer & buffer, const Array<Element> & elements,
+    const SynchronizationTag & tag) {
+  if (tag == SynchronizationTag::_mnl_for_average) {
+    for (auto & variable_id : non_local_variables) {
+      this->non_local_manager.unpackData(buffer, elements, variable_id);
+    }
+  }
+
+  this->distance_function->unpackData(buffer, elements, tag);
+}
+
+} // namespace akantu
+
+#endif /* AKANTU_CLIP_NEIGHBORHOOD_INLINE_IMPL_HH_ */
diff --git a/src/model/common/non_local_toolbox/clip_neighborhood_tmpl.hh b/src/model/common/non_local_toolbox/clip_neighborhood_tmpl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..8372fe64a969a4e80a9374a0919a189e5cd51b26
--- /dev/null
+++ b/src/model/common/non_local_toolbox/clip_neighborhood_tmpl.hh
@@ -0,0 +1,351 @@
+/**
+ * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "communicator.hh"
+#include "model.hh"
+#include "non_local_manager.hh"
+#include "clip_neighborhood.hh"
+/* -------------------------------------------------------------------------- */
+#include <fstream>
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_CLIP_NEIGHBORHOOD_TMPL_HH_
+#define AKANTU_CLIP_NEIGHBORHOOD_TMPL_HH_
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+template <class Func>
+inline void
+CLIPNeighborhood<DistanceFunction>::foreach_distance(GhostType ghost_type,
+                                                     Func && func) {
+  auto && weight_vect = *pair_distance[ghost_type];
+
+  for (auto && [pair, weight] :
+       zip(pair_list[ghost_type],
+           make_view(weight_vect, weight_vect.getNbComponent()))) {
+    auto && [q1, q2] = pair;
+    std::forward<decltype(func)>(func)(q1, q2, weight);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+template <class Func>
+inline void
+CLIPNeighborhood<DistanceFunction>::foreach_distance(GhostType ghost_type,
+                                                     Func && func) const {
+  auto && weight_vect = *pair_distance.at(ghost_type);
+
+  for (auto && [pair, weight] :
+       zip(pair_list.at(ghost_type),
+           make_view(weight_vect, weight_vect.getNbComponent()))) {
+    auto && [q1, q2] = pair;
+    std::forward<decltype(func)>(func)(q1, q2, weight);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+template <class Func>
+inline void
+CLIPNeighborhood<DistanceFunction>::foreach_derivative_weight(GhostType ghost_type,
+                                                     Func && func) {
+  auto && weight_vect = *pair_derivative_weights[ghost_type];
+
+  for (auto && [pair, weight] :
+       zip(pair_list[ghost_type],
+           make_view(weight_vect, weight_vect.getNbComponent()))) {
+    auto && [q1, q2] = pair;
+    std::forward<decltype(func)>(func)(q1, q2, weight);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+template <class Func>
+inline void
+CLIPNeighborhood<DistanceFunction>::foreach_derivative_weight(GhostType ghost_type,
+                                                     Func && func) const {
+  auto && weight_vect = *pair_derivative_weights.at(ghost_type);
+
+  for (auto && [pair, weight] :
+       zip(pair_list.at(ghost_type),
+           make_view(weight_vect, weight_vect.getNbComponent()))) {
+    auto && [q1, q2] = pair;
+    std::forward<decltype(func)>(func)(q1, q2, weight);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+CLIPNeighborhood<DistanceFunction>::CLIPNeighborhood(
+    NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates,
+    const ID & id)
+    : NonLocalNeighborhoodBase(manager.getModel(), quad_coordinates, id),
+      non_local_manager(manager) {
+  AKANTU_DEBUG_IN();
+
+  this->distance_function = std::make_unique<DistanceFunction>(manager);
+
+  this->registerSubSection(ParserType::_distance_function, "distance_parameter",
+                           *distance_function);
+  this->registerParam("Dm", Dm, 0.,
+                      _pat_parsable | _pat_readable, "Dm");
+
+  for (auto ghost_type : ghost_types) {
+    if (pair_distance.find(ghost_type) == pair_distance.end()) {
+      pair_distance[ghost_type] = std::make_unique<Array<Real>>(0, 1);
+      pair_list[ghost_type].resize(0);
+    }
+    if (pair_derivative_weights.find(ghost_type) == pair_derivative_weights.end()) {
+      pair_derivative_weights[ghost_type] = std::make_unique<Array<Real>>(0, 1);
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+void CLIPNeighborhood<DistanceFunction>::updatePairList() {
+  AKANTU_DEBUG_IN();
+
+  //// loop over all quads -> all cells
+  for (auto && cell_id : *spatial_grid) {
+    AKANTU_DEBUG_INFO("Looping on next cell");
+
+    for (auto && q1 : spatial_grid->getCell(cell_id)) {
+      if (q1.ghost_type == _ghost || q1.kind() == _ek_regular) {
+        break;
+      }
+      auto q1_coords = this->quad_coordinates.get(q1);
+
+      AKANTU_DEBUG_INFO("Current quadrature point in this cell: " << q1);
+      auto cell_id = spatial_grid->getCellID(q1_coords);
+
+      /// loop over all the neighboring cells of the current quad
+      for (auto && neighbor_cell : cell_id.neighbors()) {
+        // loop over the quadrature point in the current neighboring cell
+        for (auto && q2 : spatial_grid->getCell(neighbor_cell)) {
+          auto q2_coords = this->quad_coordinates.get(q2);
+
+          Real distance = q1_coords.distance(q2_coords);
+
+          if (distance <= this->neighborhood_radius + Math::getTolerance() &&
+              q2.kind() == _ek_regular) {
+              // Not sure if we still need these conditions
+              // (q2.ghost_type == _ghost ||
+              //  (q2.ghost_type == _not_ghost &&
+              //   q1.global_num <= q2.global_num))) { // storing only half lists
+            pair_list[q1.ghost_type].emplace_back(q1, q2);
+          }
+        }
+      }
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+void CLIPNeighborhood<DistanceFunction>::computeWeights() {
+  AKANTU_DEBUG_IN();
+
+  std::cout << "CLIPNeighborhood::In computeWeights " << std::endl;
+  this->distance_function->setRadius(this->neighborhood_radius);
+
+  /// update the internals of the weight function if applicable (not
+  /// all the weight functions have internals and do noting in that
+  /// case)
+  distance_function->updateInternals();
+
+  for (auto ghost_type : ghost_types) {
+    /// allocate the array to store the weight, if it doesn't exist already
+    if (not pair_distance[ghost_type]) {
+      pair_distance[ghost_type] =
+          std::make_unique<Array<Real>>(0, 1);
+    }
+
+    auto && pair_lists = pair_list[ghost_type];
+    auto && pair_distances = *pair_distance[ghost_type];
+
+    pair_distances.resize(pair_lists.size());
+    pair_distances.zero(); 
+
+    /// loop over all pairs in the current pair list array and their
+    /// corresponding weights
+    // Compute the distances
+    for (auto && [dist, pairs] :
+         zip(make_view(pair_distances, 1), pair_lists)) {
+      const auto & [q1, q2] = pairs;
+
+      /// get the coordinates for the given pair of quads
+      auto && q1_coord = this->quad_coordinates.get(q1);
+      auto && q2_coord = this->quad_coordinates.get(q2);
+
+      /// compute distance between the two quadrature points
+      auto r = q1_coord.distance(q2_coord);
+
+      /// compute the weight for averaging on q1 based on the distance
+      dist(0) = (*this->distance_function)(r, q1, q2);
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+void CLIPNeighborhood<DistanceFunction>::computeDerivativeWeights() {
+  AKANTU_DEBUG_IN();
+
+  for (auto ghost_type : ghost_types) {
+    /// allocate the array to store the weight, if it doesn't exist already
+    if (not pair_derivative_weights[ghost_type]) {
+      pair_derivative_weights[ghost_type] =
+          std::make_unique<Array<Real>>(0, 1);
+    }
+
+    auto && pair_lists = pair_list[ghost_type];
+    auto && pair_derivative_weights = *pair_derivative_weights[ghost_type];
+
+    pair_derivative_weights.resize(pair_lists.size());
+    pair_derivative_weights.zero(); 
+
+    /// loop over all pairs in the current pair list array and their
+    /// corresponding weights
+    // Compute the distances
+    for (auto && [weight, pairs] :
+         zip(make_view(pair_derivative_weights, 1), pair_lists)) {
+      const auto & [q1, q2] = pairs;
+
+      /// get the coordinates for the given pair of quads
+      auto && q1_coord = this->quad_coordinates.get(q1);
+      auto && q2_coord = this->quad_coordinates.get(q2);
+
+      /// TODO : compute the weight for averaging on q1 
+      weight(0) = 0.;
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+void CLIPNeighborhood<DistanceFunction>::saveWeights(
+    const std::string & filename) const {
+  std::ofstream pout;
+
+  std::stringstream sstr;
+
+  const Communicator & comm = model.getMesh().getCommunicator();
+
+  auto prank = comm.whoAmI();
+  sstr << filename << "." << prank;
+
+  pout.open(sstr.str().c_str());
+
+  for (auto ghost_type : ghost_types) {
+    AKANTU_DEBUG_ASSERT((pair_distance.at(ghost_type)),
+                        "the weights have not been computed yet");
+
+    const auto & weights = *pair_distance.at(ghost_type);
+    for (auto && weight : make_view(weights, 2)) {
+      pout << "w1: " << weight(0) << " w2: " << weight(1) << "\n";
+    }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+void CLIPNeighborhood<DistanceFunction>::weightedAverageOnNeighbours(
+    const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated,
+    Int /*nb_degree_of_freedom*/, GhostType ghost_type2) const {
+
+  std::cout << "CLIPNeighborhood::In weightedAverageOnNeighbours " << std::endl;
+
+  auto it = non_local_variables.find(accumulated.getName());
+  // do averaging only for variables registered in the neighborhood
+  if (it == non_local_variables.end()) {
+    return;
+  }
+
+  std::cout << "to_accumulate.getName() " << to_accumulate.getName() << std::endl;
+  std::cout << "accumulated.getName() " << accumulated.getName() << std::endl;
+
+  foreach_distance(
+      ghost_type2,
+      [this,ghost_type2, &to_accumulate,
+       &accumulated](const auto & q1, const auto & q2, auto & weight) {
+        auto && to_acc_1 = to_accumulate.get(q1);
+        auto && acc_2 = accumulated.get(q2);
+        acc_2(0) =std::max(acc_2(0),this->Dm*(to_acc_1(0)-weight(0)/this->neighborhood_radius));
+        // acc_1 =this->Dm*(to_acc_2+weight(0)/this->neighborhood_radius);
+      });
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+void CLIPNeighborhood<DistanceFunction>::weightedDerivativeAverageOnNeighbours(
+    const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated,
+    Int /*nb_degree_of_freedom*/, GhostType ghost_type2) const {
+
+  std::cout << "CLIPNeighborhood::In weightedDerivativeAverageOnNeighbours " << std::endl;
+
+  // auto it = non_local_variables.find(accumulated.getName());
+  // // do averaging only for variables registered in the neighborhood
+  // if (it == non_local_variables.end()) {
+  //   return;
+  // }
+
+  std::cout << "to_accumulate.getName() " << to_accumulate.getName() << std::endl;
+  std::cout << "accumulated.getName() " << accumulated.getName() << std::endl;
+
+  foreach_derivative_weight(
+      ghost_type2,
+      [this,ghost_type2, &to_accumulate,
+       &accumulated](const auto & q1, const auto & q2, auto & weight) {
+        auto && acc_1 = accumulated.get(q1);
+        auto && to_acc_2 = to_accumulate.get(q2);
+        acc_1 += weight(0) * to_acc_2;
+      });
+}
+
+/* -------------------------------------------------------------------------- */
+template <class DistanceFunction>
+void CLIPNeighborhood<DistanceFunction>::updateWeights() {
+  // Update the weights for the non local variable averaging
+  if (this->distance_function->getUpdateRate() and
+      (this->non_local_manager.getNbStressCalls() %
+           this->distance_function->getUpdateRate() ==
+       0)) {
+    SynchronizerRegistry::synchronize(SynchronizationTag::_mnl_weight);
+    this->computeWeights();
+  }
+}
+
+} // namespace akantu
+
+#endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL__ */
diff --git a/src/model/common/non_local_toolbox/neighborhood_base.hh b/src/model/common/non_local_toolbox/neighborhood_base.hh
index 061c2fdfd22513923fcdfb0bc294ac538fa691cc..4a74b9f19eabdf490f3f918154b23e3278f6bc66 100644
--- a/src/model/common/non_local_toolbox/neighborhood_base.hh
+++ b/src/model/common/non_local_toolbox/neighborhood_base.hh
@@ -61,7 +61,7 @@ public:
                                      const VectorProxy<const Real> & coords);
 
   /// create the pairs of quadrature points
-  void updatePairList();
+  virtual void updatePairList();
 
   /// save the pairs of quadrature points in a file
   void savePairs(const std::string & filename) const;
diff --git a/src/model/common/non_local_toolbox/non_local_manager.cc b/src/model/common/non_local_toolbox/non_local_manager.cc
index acfa9b7e033a987311c586c8f67d34d471825683..c0df1ca0b47faca73f714d469284c4a667e0edb4 100644
--- a/src/model/common/non_local_toolbox/non_local_manager.cc
+++ b/src/model/common/non_local_toolbox/non_local_manager.cc
@@ -21,10 +21,12 @@
 /* -------------------------------------------------------------------------- */
 #include "non_local_manager.hh"
 #include "base_weight_function.hh"
+#include "base_distance_function.hh"
 #include "grid_synchronizer.hh"
 #include "integrator.hh"
 #include "model.hh"
 #include "non_local_neighborhood.hh"
+#include "clip_neighborhood.hh"
 /* -------------------------------------------------------------------------- */
 #include <numeric>
 /* -------------------------------------------------------------------------- */
@@ -102,6 +104,7 @@ void NonLocalManager::setJacobians(const FEEngine & fe_engine,
 /* -------------------------------------------------------------------------- */
 void NonLocalManager::createNeighborhood(const ID & weight_func,
                                          const ID & neighborhood_id) {
+
   auto weight_func_it = this->weight_function_types.find(weight_func);
   AKANTU_DEBUG_ASSERT(weight_func_it != weight_function_types.end(),
                       "No info found in the input file for the weight_function "
@@ -111,7 +114,6 @@ void NonLocalManager::createNeighborhood(const ID & weight_func,
   const ParserSection & section = weight_func_it->second;
   const ID weight_func_type = section.getOption();
 
-  /// create new neighborhood for given ID
   neighborhoods[neighborhood_id] =
       NonLocalNeighborhoodFactory::getInstance().allocate(
           weight_func_type, neighborhood_id, *this,
diff --git a/src/model/common/non_local_toolbox/non_local_manager.hh b/src/model/common/non_local_toolbox/non_local_manager.hh
index 065010de7dfcd2a9262d69ccc0a6f4430d58a517..f434b62472c050a3ac50fdda95e20721c7d922b4 100644
--- a/src/model/common/non_local_toolbox/non_local_manager.hh
+++ b/src/model/common/non_local_toolbox/non_local_manager.hh
@@ -180,6 +180,7 @@ private:
   ID id;
 
 protected:
+  
   /// the non-local neighborhoods present
   NeighborhoodMap neighborhoods;
 
diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh
index 178e0c29f45fc5d934b2d0b4e68ae17c26c79059..4458a6b1ba42cc8311ab661ea2a90a37fa856344 100644
--- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh
+++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh
@@ -20,6 +20,7 @@
 
 /* -------------------------------------------------------------------------- */
 #include "neighborhood_base.hh"
+#include "non_local_manager.hh"
 #include "parsable.hh"
 /* -------------------------------------------------------------------------- */
 
@@ -118,6 +119,10 @@ protected:
   std::set<ID> non_local_variables;
 };
 
+using NonLocalNeighborhoodFactory =
+    Factory<NonLocalNeighborhoodBase, ID, ID, NonLocalManager &,
+            const ElementTypeMapReal &, const ID &>;
+
 } // namespace akantu
 
 #endif /* AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH_ */
diff --git a/src/model/contact_mechanics/contact_mechanics_model.cc b/src/model/contact_mechanics/contact_mechanics_model.cc
index e260c669384e4a0e8d16d66f5cbef07814ca28a6..f12f2f9de52208efce57f032a4932adb6446c591 100644
--- a/src/model/contact_mechanics/contact_mechanics_model.cc
+++ b/src/model/contact_mechanics/contact_mechanics_model.cc
@@ -37,7 +37,8 @@ namespace akantu {
 ContactMechanicsModel::ContactMechanicsModel(
     Mesh & mesh, Int dim, const ID & id,
     std::shared_ptr<DOFManager> dof_manager, const ModelType model_type)
-    : Model(mesh, model_type, dim, id) {
+    : Model(mesh, model_type, dim, id),
+      BoundaryCondition<ContactMechanicsModel>("displacement") {
 
   AKANTU_DEBUG_IN();
 
@@ -484,8 +485,8 @@ void ContactMechanicsModel::computeNodalAreas(GhostType ghost_type) {
                            ghost_type, element_ids);
 
     this->getDOFManager().assembleElementalArrayLocalArray(
-        dual_by_shapes_integ, *external_force, type, ghost_type, 1.,
-        element_ids);
+        "displacement", dual_by_shapes_integ, *external_force, type, ghost_type,
+        1., element_ids);
   }
 
   for (auto && tuple :
diff --git a/src/model/diffusion_model/diffusion_law.cc b/src/model/diffusion_model/diffusion_law.cc
index 7b5ad1a4de74922400f2515e9adb99cba4cee352..ebe76e7c56caa1cfae09b358b31e9407231e62f7 100644
--- a/src/model/diffusion_model/diffusion_law.cc
+++ b/src/model/diffusion_model/diffusion_law.cc
@@ -66,8 +66,8 @@ void DiffusionLaw::assembleInternalFlow(GhostType ghost_type) {
                   elem_filter);
 
     model.getDOFManager().assembleElementalArrayLocalArray(
-        int_bt_d_gu, model.getInternalFlow(), type, ghost_type, -1,
-        elem_filter);
+        model.getDOFName(), int_bt_d_gu, model.getInternalFlow(), type,
+        ghost_type, -1, elem_filter);
   }
 }
 
diff --git a/src/model/diffusion_model/diffusion_model.cc b/src/model/diffusion_model/diffusion_model.cc
index 27338c55fba863459d0a5c25429e99c802d3d72c..6e308c33db6d8d1424be7a27c6fe06f0a4d33590 100644
--- a/src/model/diffusion_model/diffusion_model.cc
+++ b/src/model/diffusion_model/diffusion_model.cc
@@ -135,7 +135,7 @@ void DiffusionModel::initSolver(TimeStepSolverType time_step_solver_type,
   this->allocNodalField(this->blocked_dofs, 1, "blocked_dofs");
 
   if (not dof_manager.hasDOFs(dof_name)) {
-    dof_manager.registerDOFs(dof_name, *this->diffusion, _dst_nodal);
+    dof_manager.registerDOFs(dof_name, *this->diffusion, this->mesh);
     dof_manager.registerBlockedDOFs(dof_name, *this->blocked_dofs);
   }
 
diff --git a/src/model/model_couplers/coupler_solid_phasefield.cc b/src/model/model_couplers/coupler_solid_phasefield.cc
index 6a259cfd8593d23d64b0e90dbe9d4242743abb8b..7a626ffa95eb135da8891204eaaa6f396724810e 100644
--- a/src/model/model_couplers/coupler_solid_phasefield.cc
+++ b/src/model/model_couplers/coupler_solid_phasefield.cc
@@ -33,7 +33,8 @@ namespace akantu {
 CouplerSolidPhaseField::CouplerSolidPhaseField(Mesh & mesh, Int dim,
                                                const ID & id,
                                                const ModelType model_type)
-    : Model(mesh, model_type, dim, id) {
+    : Model(mesh, model_type, dim, id),
+      BoundaryCondition<CouplerSolidPhaseField>("displacement") {
   this->registerFEEngineObject<MyFEEngineType>("CouplerSolidPhaseField", mesh,
                                                Model::spatial_dimension);
 
diff --git a/src/model/phase_field/phase_field_model.cc b/src/model/phase_field/phase_field_model.cc
index b3f3618a9fcf217b8c74c20b54e9c09f052e5115..6f3fefbf5e49aa6a44824aa3f09aac03e9b131e4 100644
--- a/src/model/phase_field/phase_field_model.cc
+++ b/src/model/phase_field/phase_field_model.cc
@@ -39,7 +39,8 @@ namespace akantu {
 PhaseFieldModel::PhaseFieldModel(Mesh & mesh, Int dim, const ID & id,
                                  std::shared_ptr<DOFManager> dof_manager,
                                  ModelType model_type)
-    : Parent(mesh, model_type, dim, id) {
+    : Parent(mesh, model_type, dim, id), BoundaryCondition<PhaseFieldModel>(
+                                             "damage") {
   AKANTU_DEBUG_IN();
 
   this->initDOFManager(std::move(dof_manager));
@@ -109,7 +110,7 @@ void PhaseFieldModel::initSolver(TimeStepSolverType time_step_solver_type,
   this->allocNodalField(this->previous_damage, 1, "previous_damage");
 
   if (!dof_manager.hasDOFs("damage")) {
-    dof_manager.registerDOFs("damage", *this->damage, _dst_nodal);
+    dof_manager.registerDOFs("damage", *this->damage, mesh);
     dof_manager.registerBlockedDOFs("damage", *this->blocked_dofs);
     dof_manager.registerDOFsPrevious("damage", *this->previous_damage);
   }
diff --git a/src/model/phase_field/phasefield.cc b/src/model/phase_field/phasefield.cc
index cbce39571501dc48aecafd394d8778f5dc009f8e..0025044ca59687067198ae889b9b698b83b007e1 100644
--- a/src/model/phase_field/phasefield.cc
+++ b/src/model/phase_field/phasefield.cc
@@ -121,7 +121,7 @@ void PhaseField::assembleInternalForces(GhostType ghost_type) {
                   type, ghost_type, elem_filter);
 
     handler.getDOFManager().assembleElementalArrayLocalArray(
-        int_nt_driving_force, internal_force, type, ghost_type, -1,
+        "damage", int_nt_driving_force, internal_force, type, ghost_type, -1,
         elem_filter);
 
     // damage_energy_on_qpoints = gc*l0 = scalar
@@ -136,7 +136,7 @@ void PhaseField::assembleInternalForces(GhostType ghost_type) {
                   nb_nodes_per_element, type, ghost_type, elem_filter);
 
     handler.getDOFManager().assembleElementalArrayLocalArray(
-        int_bt_driving_energy, internal_force, type, ghost_type, -1,
+        "damage", int_bt_driving_energy, internal_force, type, ghost_type, -1,
         elem_filter);
   }
 }
diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc
index 5fd5737aafdae3dee6f78a344cec628910870e15..54d87409641a7c34567451e00571946b8a2b214a 100644
--- a/src/model/solid_mechanics/material.cc
+++ b/src/model/solid_mechanics/material.cc
@@ -127,7 +127,6 @@ void Material::assembleInternalForces(GhostType ghost_type) {
  */
 void Material::computeAllStresses(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
-
   auto spatial_dimension = getModel().getSpatialDimension();
   auto & fem = getFEEngine();
   for (const auto & type :
@@ -506,7 +505,8 @@ void Material::assembleInternalForces(GhostType ghost_type) {
 
   /// assemble
   getModel().getDOFManager().assembleElementalArrayLocalArray(
-      *int_sigma_dphi_dx, internal_force, type, ghost_type, -1, elem_filter);
+      "displacement", *int_sigma_dphi_dx, internal_force, type, ghost_type, -1,
+      elem_filter);
 }
 /* -------------------------------------------------------------------------- */
 template <Int dim>
@@ -578,7 +578,7 @@ void Material::assembleInternalForcesFiniteDeformation(GhostType ghost_type) {
   fem.integrate(*bt_s, *r_e, bt_s_size, type, ghost_type, elem_filter);
 
   getModel().getDOFManager().assembleElementalArrayLocalArray(
-      *r_e, internal_force, type, ghost_type, -1., elem_filter);
+      "displacement", *r_e, internal_force, type, ghost_type, -1., elem_filter);
 
   AKANTU_DEBUG_OUT();
 }
diff --git a/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh b/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh
index 5a6f6191a43a13dae8c778449608e1b45f863bf5..5a0423c83edeebe77898e3a6157d578271ad365b 100644
--- a/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh
+++ b/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh
@@ -113,6 +113,8 @@ template <class Args>
 inline void MaterialElastic<dim>::computePotentialEnergyOnQuad(Args && args,
                                                                Real & epot) {
   epot = .5 * args["sigma"_n].doubleDot(args["grad_u"_n]);
+  // std::cout << "epot "<< epot << std::endl ;
+
 }
 
 } // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc
index 21737ca8dbd46d38d3c20ec9b00f9611267ca984..c58504f17e9ad219cf56382adb8bea12746aa13b 100644
--- a/src/model/solid_mechanics/solid_mechanics_model.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model.cc
@@ -52,7 +52,8 @@ namespace akantu {
 SolidMechanicsModel::SolidMechanicsModel(
     Mesh & mesh, Int dim, const ID & id,
     const std::shared_ptr<DOFManager> & dof_manager, const ModelType model_type)
-    : CLHParent(mesh, model_type, dim, id) {
+    : CLHParent(mesh, model_type, dim, id),
+      BoundaryCondition<SolidMechanicsModel>("displacement") {
   AKANTU_DEBUG_IN();
 
   this->initDOFManager(dof_manager);
@@ -207,7 +208,7 @@ void SolidMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type,
 
   /* ------------------------------------------------------------------------ */
   if (!dof_manager.hasDOFs("displacement")) {
-    dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal);
+    dof_manager.registerDOFs("displacement", *this->displacement, this->mesh);
     dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs);
     dof_manager.registerDOFsIncrement("displacement",
                                       *this->displacement_increment);
@@ -336,7 +337,7 @@ void SolidMechanicsModel::assembleInternalForces() {
   AKANTU_DEBUG_INFO("Assemble the internal forces");
 
   this->internal_force->zero();
-
+  
   // compute the stresses of local elements
   AKANTU_DEBUG_INFO("Compute local stresses");
   for_each_constitutive_law(
@@ -521,9 +522,11 @@ Real SolidMechanicsModel::getKineticEnergy() {
   }
 
   mesh.getCommunicator().allReduce(ekin, SynchronizerOperation::_sum);
+  Real kinetic_energy = ekin / 2.;
+  
 
   AKANTU_DEBUG_OUT();
-  return ekin / 2.;
+  return kinetic_energy;
 }
 
 /* -------------------------------------------------------------------------- */
@@ -661,38 +664,22 @@ void SolidMechanicsModel::onNodesAdded(const Array<Idx> & nodes_list,
   AKANTU_DEBUG_IN();
   auto nb_nodes = mesh.getNbNodes();
 
+  for (auto && ptr :
+       {displacement.get(), velocity.get(), acceleration.get(), mass.get(),
+        external_force.get(), internal_force.get(), current_position.get(),
+        previous_displacement.get(), displacement_increment.get()}) {
+    if (ptr != nullptr) {
+      ptr->resize(nb_nodes, 0.);
+    }
+  }
+
   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, false);
   }
-  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_each_constitutive_law(
       [&](auto && material) { material.onNodesAdded(nodes_list, event); });
@@ -707,35 +694,21 @@ void SolidMechanicsModel::onNodesAdded(const Array<Idx> & nodes_list,
 void SolidMechanicsModel::onNodesRemoved(const Array<Idx> & /*element_list*/,
                                          const Array<Idx> & 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);
+  for (auto && ptr :
+       {displacement.get(), velocity.get(), acceleration.get(), mass.get(),
+        external_force.get(), internal_force.get(), previous_displacement.get(),
+        displacement_increment.get()}) {
+    if (ptr != nullptr) {
+      mesh.removeNodesFromArray(*ptr, new_numbering);
+    }
   }
+
   if (blocked_dofs) {
     mesh.removeNodesFromArray(*blocked_dofs, new_numbering);
   }
 
-  if (displacement_increment) {
-    mesh.removeNodesFromArray(*displacement_increment, new_numbering);
-  }
-
-  if (previous_displacement) {
-    mesh.removeNodesFromArray(*previous_displacement, new_numbering);
+  if (displacement) {
+    ++displacement_release;
   }
 }
 
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7fdac579533135b81e1697564e9a191477f4992c
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc
@@ -0,0 +1,127 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_bulk_damage.hh"
+#include "aka_common.hh"
+#include "solid_mechanics_model.hh"
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+MaterialBulkDamage<dim>::MaterialBulkDamage(SolidMechanicsModel & model,
+                                            const ID & id)
+    : Parent(model, id),
+      objective_functional(this->registerInternal("objective_functional", 1)) {
+  AKANTU_DEBUG_IN();          
+  this->registerParam("Dm", Dm, _pat_parsable | _pat_readable,
+                      "Clip Parameter");
+  
+  this->registerParam("sigma_c", sigc, _pat_parsable | _pat_readable,
+                      "Critical stress");
+
+  this->registerParam("G_c", G_c, _pat_parsable | _pat_readable,
+                      "Fracture energy");
+
+  this->registerParam("lc", lc, _pat_parsable | _pat_readable,
+                      "Regularising length");
+
+  AKANTU_DEBUG_OUT();
+}
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialBulkDamage<dim>::initMaterial() {
+  AKANTU_DEBUG_IN();
+
+  Parent::initMaterial();
+
+  // This is a quick fix : sigc and wc should be CohesiveInternalField<Real>/FacetInternalField<Real>
+
+  lch = (this->E * G_c)/(pow(sigc, 2));
+  gamma = lc/lch;  
+  Yc  = (sigc*sigc)/(2*this->E);
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialBulkDamage<dim>::computeStress(ElementType el_type,
+                                            GhostType ghost_type) {
+  for (auto && args : getArguments(el_type, ghost_type)) {
+    computeStressOnQuad(args);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialBulkDamage<dim>::computeTangentModuli(ElementType el_type,
+                                                   Array<Real> & tangent_matrix,
+                                                   GhostType ghost_type) {
+  for (auto && args :
+       getArgumentsTangent(tangent_matrix, el_type, ghost_type)) {
+    computeTangentModuliOnQuad(args);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+Real MaterialBulkDamage<dim>::computeObjectiveFunctional() {
+  Real val(0.);
+  for (auto && type : this->getElementFilter().elementTypes(dim, _not_ghost)) {
+    for (auto && args : getArgumentsObjective(type)) {
+      computeObjectiveFunctionalOnQuad(args);
+    }
+    val += this->getFEEngine().integrate(
+        this->objective_functional(type, _not_ghost), type, _not_ghost,
+        this->getElementFilter(type, _not_ghost));
+  }
+  return val;
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+Real MaterialBulkDamage<dim>::GD_clip_function(const Real D)
+{
+    Real num = gamma*pow((pow(D,2) - 1),2);
+    Real den = (2*D*Dm + gamma*pow((pow(D,2) - 1), 2));
+
+    return num/den;
+}
+
+template <Int dim>
+Real MaterialBulkDamage<dim>::HD_clip_function(const Real D)
+{
+    Real num = 2*D*Dm ;
+    Real den = (gamma*pow((pow(D,2) * Dm - pow(D,2) + 1),2));
+
+    return num/den;
+}
+
+/* -------------------------------------------------------------------------- */
+template class MaterialBulkDamage<1>;
+template class MaterialBulkDamage<2>;
+template class MaterialBulkDamage<3>;
+
+const bool material_is_allocated_bulk [[maybe_unused]] =
+    instantiateMaterial<MaterialBulkDamage>("bulk_damage");
+
+} // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh
new file mode 100644
index 0000000000000000000000000000000000000000..c19485adbc52cddff49166b9cc7560c5d766fd79
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh
@@ -0,0 +1,114 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material.hh"
+#include "material_damage.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_MATERIAL_BULK_DAMAGE_HH_
+#define AKANTU_MATERIAL_BULK_DAMAGE_HH_
+
+namespace akantu {
+
+template <Int dim> class MaterialBulkDamage : public MaterialDamage<dim> {
+  using Parent = MaterialDamage<dim>;
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  MaterialBulkDamage(SolidMechanicsModel & model, const ID & id = "");
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+public:
+
+  /// initialize the material parameters
+  void initMaterial() override;
+
+  /// constitutive law for all element of a type
+  void computeStress(ElementType el_type,
+                     GhostType ghost_type = _not_ghost) override;
+
+  /// compute the tangent stiffness matrix for an element type
+  void computeTangentModuli(ElementType el_type, Array<Real> & tangent_matrix,
+                            GhostType ghost_type = _not_ghost) override;
+
+  /// objective function for all element of a type
+  Real computeObjectiveFunctional();
+
+  /* ------------------------------------------------------------------------ */
+  decltype(auto) getArguments(ElementType el_type,
+                              GhostType ghost_type = _not_ghost) {
+    return zip_append(Parent::getArguments(el_type, ghost_type),
+                      "damage"_n = make_view(this->damage(el_type, ghost_type)));
+  }
+
+  decltype(auto) getArgumentsTangent(Array<Real> & tangent_matrix,
+                                     ElementType el_type,
+                                     GhostType ghost_type) {
+    return zip_append(
+        Parent::getArgumentsTangent(tangent_matrix, el_type, ghost_type),
+        "damage"_n = make_view(this->damage(el_type, ghost_type)));
+  }
+
+    decltype(auto) getArgumentsObjective(ElementType el_type) {
+    return zip_append(Parent::getArguments(el_type, _not_ghost),
+                      "damage"_n = make_view(this->damage(el_type, _not_ghost)),
+                      "objective"_n = make_view(this->objective_functional(el_type, _not_ghost)));
+  }
+
+protected:
+  /// constitutive law for a given quadrature point
+  template <class Args> inline void computeStressOnQuad(Args && args);
+
+  /// compute the tangent stiffness matrix for a given quadrature point
+  template <class Args> inline void computeTangentModuliOnQuad(Args && args);
+
+  /// compute the objective function for a given quadrature point
+  template <class Args> inline void computeObjectiveFunctionalOnQuad(Args && args);
+
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+protected:
+
+  Real GD_clip_function(const Real D);
+  // Real GD_clip_function_first_derivative(const Real D, const Real gamma);
+
+  Real HD_clip_function(const Real D);
+  // Real HD_clip_function_first_derivative(const Real D, const Real gamma);
+
+  Real lc, Dm, lch, gamma, sigc, G_c, Yc;
+  /// objective functional at quadrature points
+  InternalField<Real> & objective_functional;
+};
+
+} // namespace akantu
+
+/* -------------------------------------------------------------------------- */
+/* inline functions                                                           */
+/* -------------------------------------------------------------------------- */
+
+#include "material_bulk_damage_inline_impl.hh"
+
+#endif /* AKANTU_MATERIAL_BULK_DAMAGE_HH_ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..ba25535265ced738f93283946f2c6ee4e2d1ac8c
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh
@@ -0,0 +1,58 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_bulk_damage.hh"
+
+#ifndef AKANTU_MATERIAL_BULK_DAMAGE_INLINE_IMPL_HH_
+#define AKANTU_MATERIAL_BULK_DAMAGE_INLINE_IMPL_HH_
+/* -------------------------------------------------------------------------- */
+namespace akantu {
+template <Int dim>
+template <class Args>
+inline void MaterialBulkDamage<dim>::computeStressOnQuad(Args && args) {
+  MaterialElastic<dim>::computeStressOnQuad(args);    
+  auto && dam = args["damage"_n];  
+  args["sigma"_n] *= GD_clip_function(dam);
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+template <class Args>
+void MaterialBulkDamage<dim>::computeTangentModuliOnQuad(Args && args) {
+  MaterialElastic<dim>::computeTangentModuliOnQuad(args);
+
+  auto dam = args["damage"_n];
+  /// TODO : replace (1 - dam) by G(D)
+  args["tangent_moduli"_n] *= (1 - dam);
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+template <class Args>
+void MaterialBulkDamage<dim>::computeObjectiveFunctionalOnQuad(Args && args) {
+  auto && obj = args["objective"_n];
+  auto && sigma = args["sigma"_n];
+  auto && eps = Material::gradUToEpsilon<dim>(args["grad_u"_n]);
+  auto && dam = args["damage"_n];
+  obj = 0.5*sigma.doubleDot(eps)*GD_clip_function(dam) + Yc*HD_clip_function(dam);
+}
+
+} // namespace akantu
+#endif
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc
new file mode 100644
index 0000000000000000000000000000000000000000..223291a7ac8ba2b778cb92a2f924876a13c33db8
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc
@@ -0,0 +1,35 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_bulk_damage_non_local.hh"
+
+namespace akantu {
+
+template class MaterialBulkDamageNonLocal<1>;
+template class MaterialBulkDamageNonLocal<2>;
+template class MaterialBulkDamageNonLocal<3>;
+
+template <Int dim> using MaterialBulkDamageNonLocal_ = MaterialBulkDamageNonLocal<dim>;
+
+static bool material_is_alocated_bulk_damage_non_local =
+    instantiateMaterial<MaterialBulkDamageNonLocal_>("bulk_damage_non_local");
+
+} // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh
new file mode 100644
index 0000000000000000000000000000000000000000..e9740e0d8a081374b9b41b12d5ce2ec96c2dadba
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh
@@ -0,0 +1,79 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_damage_non_local.hh"
+#include "material_bulk_damage.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_HH_
+#define AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_HH_
+
+namespace akantu {
+
+/**
+ * Material bulk damage Non local
+ *
+ * parameters in the material files :
+ */
+template <Int dim>
+class MaterialBulkDamageNonLocal
+    : public MaterialDamageNonLocal<dim, MaterialBulkDamage<dim>> {
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  using parent = MaterialDamageNonLocal<dim, MaterialBulkDamage<dim>>;
+
+  MaterialBulkDamageNonLocal(SolidMechanicsModel & model, const ID & id = "");
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+protected:
+  /// constitutive law for all element of a type
+  void computeStress(ElementType el_type,
+                     GhostType ghost_type = _not_ghost) override;
+
+  void computeNonLocalStress(ElementType el_type,
+                             GhostType ghost_type = _not_ghost) override;
+
+  void registerNonLocalVariables() override;
+
+  ID getNeighborhoodName() override {return "clip"; };
+
+  /* ------------------------------------------------------------------------ */
+  /* Accessors                                                                */
+  /* ------------------------------------------------------------------------ */
+public:
+
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+private:
+
+};
+
+} // namespace akantu
+
+#include "material_bulk_damage_non_local_tmpl.hh"
+
+#endif /* AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_HH_ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..a0d836a6e5bdfa4397d9fdad9ceb3c77a944af84
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh
@@ -0,0 +1,67 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_
+#define AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+MaterialBulkDamageNonLocal<dim>::MaterialBulkDamageNonLocal(
+    SolidMechanicsModel & model, const ID & id):parent(model,id)
+    {
+  AKANTU_DEBUG_IN();
+
+  this->is_non_local = true;
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialBulkDamageNonLocal<dim>::registerNonLocalVariables() {
+  this->getModel()
+      .getNonLocalManager()
+      .getNeighborhood(this->getNeighborhoodName())
+      .registerNonLocalVariable(this->damage.getName());
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialBulkDamageNonLocal<dim>::computeStress(ElementType el_type,
+                                                        GhostType ghost_type) {
+  parent::MaterialParent::computeStress(el_type,ghost_type);
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialBulkDamageNonLocal<dim>::computeNonLocalStress(
+    ElementType /*el_type*/, GhostType /*ghost_type*/) {
+/// TODO
+}
+
+} // namespace akantu
+
+#endif // AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc
index 7e8776ea854a5912fd3bbb79022307fc04799957..8b5a58f4ff463d6ad8120ffee23affc355117829 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc
@@ -165,7 +165,8 @@ void MaterialCohesive::assembleInternalForces(GhostType ghost_type) {
 
     /// assemble
     model->getDOFManager().assembleElementalArrayLocalArray(
-        *int_t_N, internal_force, type, ghost_type, 1, elem_filter);
+        "displacement", *int_t_N, internal_force, type, ghost_type, 1,
+        elem_filter);
   }
 
   AKANTU_DEBUG_OUT();
@@ -283,11 +284,13 @@ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) {
  */
 void MaterialCohesive::computeTraction(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
-
+  
   for (const auto & type : getElementFilter().elementTypes(
            spatial_dimension, ghost_type, _ek_cohesive)) {
+            
     auto & elem_filter = getElementFilter(type, ghost_type);
     auto nb_element = elem_filter.size();
+    
     if (nb_element == 0) {
       continue;
     }
@@ -299,7 +302,7 @@ void MaterialCohesive::computeTraction(GhostType ghost_type) {
     /// compute openings @f$\mathbf{\delta}@f$
     computeOpening(model->getDisplacement(), opening(type, ghost_type), type,
                    ghost_type);
-
+    
     /// compute traction @f$\mathbf{t}@f$
     computeTraction(type, ghost_type);
   }
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh
index a7bc0bec294b08a5249d06e27282dbbaeb85ac17..05eff0e60a111b099a11ec435b00f9be45dab5d3 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh
@@ -40,8 +40,8 @@ class MaterialCohesive : public Material {
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
-  using MyFEEngineCohesiveType =
-      FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>;
+    using MyFEEngineCohesiveType =
+        FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>;
 
 public:
   MaterialCohesive(SolidMechanicsModel & model, const ID & id = "");
@@ -62,6 +62,15 @@ public:
     AKANTU_TO_IMPLEMENT();
   }
 
+  /// compute Lagrange multiplier
+  virtual void computeLambda(GhostType /*ghost_type*/ = _not_ghost) {
+    AKANTU_TO_IMPLEMENT();
+  }
+
+  virtual void computeDamage(GhostType /*ghost_type*/ = _not_ghost){
+    AKANTU_TO_IMPLEMENT();
+  }
+
   /// interpolate   stress  on   given   positions  for   each  element   (empty
   /// implemantation to avoid the generic call to be done on cohesive elements)
   virtual void interpolateStress(const ElementType /*type*/,
@@ -121,6 +130,8 @@ protected:
     AKANTU_TO_IMPLEMENT();
   }
 
+
+
   /// parallelism functions
   [[nodiscard]] inline Int
   getNbData(const Array<Element> & elements,
@@ -176,6 +187,8 @@ public:
   //   return Material::getEnergy(energy_id, element);
   // }
 
+  [[nodiscard]] virtual bool needLambda() const { return false; }
+
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc
new file mode 100644
index 0000000000000000000000000000000000000000..444c3e6422a483f0ab7121298000449c08b00a9b
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc
@@ -0,0 +1,188 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_cohesive_damage.hh"
+//#include "solid_mechanics_model_cohesive.hh"
+/* -------------------------------------------------------------------------- */
+#include <algorithm>
+#include <numeric>
+/* -------------------------------------------------------------------------- */
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+MaterialCohesiveDamage::MaterialCohesiveDamage(SolidMechanicsModel & model,
+                                                    const ID & id)
+    : MaterialCohesive(model, id)
+{
+  AKANTU_DEBUG_IN();
+
+  this->registerParam("k", k, _pat_parsable | _pat_readable,
+                      "Cohesive stiffness parameter");
+
+  this->registerParam("G_c", G_c, _pat_parsable | _pat_readable,
+                      "Mode I fracture energy");
+
+  this->registerParam("E", E_coh, _pat_parsable | _pat_readable,
+                      "Youngs Modulus Cohesive");
+
+  this->registerParam("lc", lc, _pat_parsable | _pat_readable |_pat_modifiable, 
+                      "Regularising length");
+
+  this->registerParam("Dm", Dm, _pat_parsable | _pat_readable,
+                      "Clip Parameter");
+  
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void MaterialCohesiveDamage::initMaterial() {
+  AKANTU_DEBUG_IN();
+
+  MaterialCohesive::initMaterial();
+
+  // This is a quick fix : sigc and wc should be CohesiveInternalField<Real>/FacetInternalField<Real>
+  sigc = sigma_c;
+  wc = 2.*G_c/sigc;
+  a = k*wc/sigc;
+
+  lch = (E_coh * G_c)/(pow(sigc, 2));
+  gamma = lc/lch;
+  
+  yc  = (sigc*sigc)/(2*k);
+  Yc  = (sigc*sigc)/(2*E_coh);
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+Real MaterialCohesiveDamage::stiffness(const Real d)
+{
+    return k*(1./d-1.);
+}
+
+Real MaterialCohesiveDamage::augmented_stiffness(const Real d)
+{
+    return k*1./d;
+}
+
+Real MaterialCohesiveDamage::augmented_compliance(const Real d)
+{
+    return d/k;
+}
+
+Real MaterialCohesiveDamage::augmented_compliance_first_derivative(const Real /*d*/)
+{
+    return 1./k;
+}
+
+Real MaterialCohesiveDamage::augmented_compliance_second_derivative(const Real /*d*/)
+{
+    return 0.;
+}
+
+Real MaterialCohesiveDamage::softening(const Real d)
+{
+    return d/(d+a*(1.-d));
+}
+
+Real MaterialCohesiveDamage::softening_first_derivative(const Real d)
+{
+    return a/pow(d+a*(1.-d),2);
+}
+
+Real MaterialCohesiveDamage::softening_second_derivative(const Real d)
+{
+    return -2.*(1.-a)*a/pow(d+a*(1.-d),3);
+}
+
+Real MaterialCohesiveDamage::gd_clip_function(const Real d)
+{
+    return (1-d)/((1 - Dm)*d);
+}
+
+Real MaterialCohesiveDamage::gd_clip_function_first_derivative(const Real d)
+{
+    return 1./(pow(d,2)*(Dm -1));
+}
+
+Real MaterialCohesiveDamage::hd_clip_function(const Real d)
+{
+    Real num = 2 * d * (pow(Dm, 6) * pow(d, 4)
+        - 5 * pow(Dm, 5) * pow(d, 4)
+        + 2 * pow(Dm, 5) * pow(d, 3)
+        + 4 * pow(Dm, 4) * pow(d, 4)
+        - 2 * pow(Dm, 4) *pow(d, 3)
+        - pow(Dm, 4) * pow(d, 2)
+        + 4 * pow(Dm, 3) * pow(d, 2)
+        - 3 * pow(Dm, 2) * pow(d, 2)
+        - Dm + 1
+    );
+
+    Real den = (
+        std::pow(Dm, 6) * std::pow(d, 5)
+        - 2 * std::pow(Dm, 5) * std::pow(d, 5)
+        + std::pow(Dm, 4) * std::pow(d, 5)
+        - std::pow(Dm, 4) * std::pow(d, 3)
+        + std::pow(Dm, 3) * std::pow(d, 3)
+        + 2 * std::pow(Dm, 3) * std::pow(d, 2)
+        - 2 * std::pow(Dm, 2) * std::pow(d, 2)
+        - Dm * d - d + 2
+    );
+
+    if (den == 0){
+        throw std::runtime_error("Divison by zero in h(d) function");
+    }
+    return num/den;
+}
+
+Real MaterialCohesiveDamage::hd_clip_function_first_derivative(const Real d)
+{
+
+    
+    Real numerator = 2*((8*pow(Dm,4)*pow(d,3)*(pow(Dm,2) - 2*Dm + 1) + 9*pow(Dm,2)*pow(d,2)*(1 - Dm) - 4*pow(Dm,2)*d*(pow(Dm,2) - 5*Dm + 4) - Dm - 5)*pow((pow(Dm,4)*pow(d,5)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) - pow(Dm,3)*pow(d,3)*(pow(Dm,2) - 2*Dm + 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2) - 2*Dm + 1) + 2*Dm - d*(pow(Dm,2) - 1) - 2),2) + (5*pow(Dm,4)*pow(d,4)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) + 3*pow(Dm,3)*pow(d,2)*(-pow(Dm,2) + 2*Dm - 1) + 4*pow(Dm,2)*d*(pow(Dm,2) - 2*Dm + 1) - pow(Dm,2) + 1)*(2*pow(Dm,4)*pow(d,4)*(-pow(Dm,2) + 2*Dm - 1) + 3*pow(Dm,2)*pow(d,3)*(Dm - 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2)- 5*Dm + 4) + 2*Dm + d*(Dm + 5) - 8)*(pow(Dm,4)*pow(d,5)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) + pow(Dm,3)*pow(d,3)*(-pow(Dm,2) + 2*Dm - 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2) - 2*Dm + 1) + 2*Dm - d*(pow(Dm,2) - 1) - 2));
+
+    Real denominator = pow((pow(Dm,4)*pow(d,5)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) - pow(Dm,3)*pow(d,3)*(pow(Dm,2) - 2*Dm + 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2) - 2*Dm + 1) + 2*Dm - d*(pow(Dm,2) - 1) - 2),3);
+
+    if (denominator == 0) {
+        throw std::runtime_error("Division by zero in h'(d) function");
+    }
+
+    return numerator / denominator;
+}
+
+Real MaterialCohesiveDamage::GD_clip_function(const Real D)
+{
+    Real num = gamma*pow((pow(D,2) - 1),2);
+    Real den = (2*D*Dm + gamma*pow((pow(D,2) - 1), 2));
+
+    return num/den;
+}
+
+Real MaterialCohesiveDamage::HD_clip_function(const Real D)
+{
+    Real num = 2*D*Dm ;
+    Real den = (gamma*pow((pow(D,2) * Dm - pow(D,2) + 1),2));
+
+    return num/den;
+}
+
+}
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh
new file mode 100644
index 0000000000000000000000000000000000000000..419205a8fa6c0240a9ec9f90476453ce677732f1
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh
@@ -0,0 +1,148 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_cohesive.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_HH_
+#define AKANTU_MATERIAL_COHESIVE_DAMAGE_HH_
+
+namespace akantu {
+
+/**
+ * Cohesive material linear damage
+ *
+ * parameters in the material files :
+ *   - sigma_c   : critical stress sigma_c  (default: 0)
+ *   - G_c       : fracture energy for mode I (default: 0)
+ *   - k         : cohesive stiffness
+ */
+class MaterialCohesiveDamage : public MaterialCohesive {
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  MaterialCohesiveDamage(SolidMechanicsModel & model, const ID & id = "");
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+public:
+  /// initialize the material parameters
+  void initMaterial() override;
+
+  virtual void computeDamage(GhostType /*ghost_type*/ = _not_ghost)
+  {
+    AKANTU_TO_IMPLEMENT();
+  }
+
+  virtual void readDamage(const Array<Element> &, const Array<Real> &)
+  {
+    AKANTU_TO_IMPLEMENT();
+  }
+
+  virtual void writeDamage(const Array<Element> &,  Array<Real> &) const
+  {
+    AKANTU_TO_IMPLEMENT();
+  }
+
+  /// compute the objective function
+  virtual Real computeObjectiveFunctional() = 0;
+
+  /// accessors
+  AKANTU_GET_MACRO(Lc, lc, Real);
+  AKANTU_GET_MACRO(Dm, Dm, Real);
+
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+protected:
+
+  virtual void getArgumentsDamage(ElementType /*el_type*/,
+                               GhostType /*ghost_type*/ = _not_ghost) {
+    AKANTU_TO_IMPLEMENT();
+  }
+  /// compute the damage for a given quadrature point
+  template <typename Args> inline void computeDamageOnQuad(Args && args);
+
+  inline Real computeResidual(Real d, Real target_omega2);
+  inline Real solveForDamageUsingLeastSquares(Real target_omega2, Real lower_bound, Real upper_bound, 
+                                                                    Real tol, int max_iter);
+  /// these functions should be put in a separate class
+  Real stiffness(const Real d);
+  Real augmented_stiffness(const Real d);
+
+  Real augmented_compliance(const Real d);
+  Real augmented_compliance_first_derivative(const Real d);
+  Real augmented_compliance_second_derivative(const Real d);
+
+  Real softening(const Real d);
+  Real softening_first_derivative(const Real d);
+  Real softening_second_derivative(const Real d);
+
+  Real gd_clip_function(const Real d);
+  Real gd_clip_function_first_derivative(const Real d);
+  
+  Real hd_clip_function(const Real d);
+  Real hd_clip_function_first_derivative(const Real d);
+
+  /// WARNING : These functions should be in MaterialBulkDamage
+  ///           They are necessary in MaterialCohesiveDamage only because
+  ///           cohesive damage is computed using 1D stress/opening curve.
+  ///           Once computation of d by (TAO) optimisation is implemented, 
+  ///           these functions should be removed from MaterialCohesiveDamage
+  Real GD_clip_function(const Real D);
+  // Real GD_clip_function_first_derivative(const Real D, const Real gamma);
+
+  Real HD_clip_function(const Real D);
+  // Real HD_clip_function_first_derivative(const Real D, const Real gamma);
+ 
+  /// cohesive stiffness
+  Real k;
+
+  /// mode I fracture energy
+  Real G_c;
+
+  /// CLIP regularization parameters
+  Real lc, Dm;
+
+  /// critical stress and opening
+  Real sigc, wc;
+
+  Real E_coh;
+
+  /// parameter for softening function
+  Real a;
+
+  Real lch, gamma;
+
+  Real yc,Yc ;
+};
+
+/* -------------------------------------------------------------------------- */
+/* inline functions                                                           */
+/* -------------------------------------------------------------------------- */
+
+} // namespace akantu
+
+#include "material_cohesive_damage_inline_impl.hh"
+
+#endif /* AKANTU_MATERIAL_COHESIVE_DAMAGE_HH_ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc
new file mode 100644
index 0000000000000000000000000000000000000000..602303cbd3c560dd3b51e48d23c889a6ad929c01
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc
@@ -0,0 +1,392 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_cohesive_damage_extrinsic.hh"
+#include "dof_synchronizer.hh"
+#include "fe_engine_template.hh"
+#include "integrator_gauss.hh"
+#include "shape_cohesive.hh"
+#include "solid_mechanics_model_cohesive_damage.hh"
+#include "sparse_matrix.hh"
+/* -------------------------------------------------------------------------- */
+#include <algorithm>
+#include <numeric>
+/* -------------------------------------------------------------------------- */
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+MaterialCohesiveDamageExtrinsic<dim>::MaterialCohesiveDamageExtrinsic(SolidMechanicsModel & model,
+                                                    const ID & id)
+    : MaterialCohesiveDamage(model, id),
+      lambda(registerInternal<Real, CohesiveInternalField>("lambda",
+                                                           spatial_dimension)),
+      czm_damage(
+          registerInternal<Real, CohesiveInternalField>("czm_damage", 1)),
+      insertion_stress(registerInternal<Real, CohesiveInternalField>(
+          "insertion_stress", dim)),
+      sigma_c_eff(registerInternal<Real, CohesiveRandomInternalField>(
+          "sigma_c_eff", 1)),
+      delta_c_eff(
+          registerInternal<Real, CohesiveInternalField>("delta_c_eff", 1)),
+      is_new_crack(registerInternal<Real, CohesiveInternalField>(
+          "is_new_crack", 1)),
+      objective_functional(registerInternal<Real, CohesiveInternalField>(
+          "objective_functional", 1))
+{
+
+    this->registerParam("max_quad_stress_insertion", max_quad_stress_insertion,
+                      false, _pat_parsable | _pat_readable,
+                      "Insertion of cohesive element when stress is high "
+                      "enough just on one quadrature point");
+
+//    czm_damage.setDefaultValue(0.1);
+    is_new_crack.setDefaultValue(0.);
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim> // NOLINTNEXTLINE(readability-function-cognitive-complexity)
+void MaterialCohesiveDamageExtrinsic<dim>::checkInsertion(bool check_only) {
+  AKANTU_DEBUG_IN();
+
+  const auto & mesh_facets = model->getMeshFacets();
+  auto & inserter = model->getElementInserter();
+
+  for (const auto & type_facet : mesh_facets.elementTypes(dim - 1)) {
+    auto type_cohesive = FEEngine::getCohesiveElementType(type_facet);
+
+    const auto & facets_check = inserter.getCheckFacets(type_facet);
+    auto & f_insertion = inserter.getInsertionFacets(type_facet);
+    auto & sig_c_eff = sigma_c_eff(type_cohesive);
+    auto & del_c = delta_c_eff(type_cohesive);
+    auto & ins_stress = insertion_stress(type_cohesive);
+    auto & trac_old = tractions.previous(type_cohesive);
+    const auto & f_stress = model->getStressOnFacets(type_facet);
+
+    const auto & facet_filter_array = getFacetFilter(type_facet);
+    const auto & sigma_limit_array = sigma_c(type_facet);
+
+    auto nb_quad_facet =
+        model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet);
+
+#ifndef AKANTU_NDEBUG
+    auto nb_quad_cohesive = model->getFEEngine("CohesiveFEEngine")
+                                .getNbIntegrationPoints(type_cohesive);
+
+    AKANTU_DEBUG_ASSERT(nb_quad_cohesive == nb_quad_facet,
+                        "The cohesive element and the corresponding facet do "
+                        "not have the same numbers of integration points");
+#endif
+
+    Matrix<Real, dim, dim> stress_tmp;
+    Matrix<Real> normal_traction(dim, nb_quad_facet);
+    Vector<Real> stress_check(nb_quad_facet);
+
+    const auto & tangents = model->getTangents(type_facet);
+    const auto & normals = model->getFEEngine("FacetsFEEngine")
+                               .getNormalsOnIntegrationPoints(type_facet);
+    auto normal_begin = make_view<dim>(normals).begin();
+    auto tangent_begin = make_view<dim, (dim == 3 ? 2 : 1)>(tangents).begin();
+    auto facet_stress_begin = make_view(f_stress, dim, dim, 2).begin();
+
+    std::vector<Real> new_sigmas;
+    std::vector<Vector<Real>> new_normal_traction;
+    std::vector<Real> new_delta_c;
+
+    // loop over each facet belonging to this material
+    for (auto && [facet, sigma_limit] :
+         zip(facet_filter_array, sigma_limit_array)) {
+      // skip facets where check shouldn't be realized
+      if (!facets_check(facet)) {
+        continue;
+      }
+
+      // compute the effective norm on each quadrature point of the facet
+      for (Int q = 0; q < nb_quad_facet; ++q) {
+        auto current_quad = facet * nb_quad_facet + q;
+        auto && normal = normal_begin[current_quad];
+        auto && tangent = tangent_begin[current_quad];
+        auto && facet_stress = facet_stress_begin[current_quad];
+
+        // compute average stress on the current quadrature point
+        auto && stress_1 = facet_stress(0);
+        auto && stress_2 = facet_stress(1);
+
+        auto && stress_avg = (stress_1 + stress_2) / 2.;
+     
+        // compute normal and effective stress
+        stress_check(q) = computeEffectiveNorm(stress_avg, normal, tangent,
+                                               normal_traction(q));
+      }
+
+      // verify if the effective stress overcomes the threshold
+      auto final_stress = stress_check.mean();
+      if (max_quad_stress_insertion) {
+        final_stress =
+            *std::max_element(stress_check.begin(), stress_check.end());
+      }
+
+      if (final_stress > sigma_limit) {
+        f_insertion(facet) = true;
+
+        if (check_only) {
+          continue;
+        }
+
+        // store the new cohesive material parameters for each quadrature
+        // point
+        for (Int q = 0; q < nb_quad_facet; ++q) {
+          auto new_sigma = stress_check(q);
+          auto && normal_traction_vec = normal_traction(q);
+
+          if (dim != 3) {
+            normal_traction_vec *= -1.;
+          }
+
+          new_sigmas.push_back(new_sigma);
+          new_normal_traction.emplace_back(normal_traction_vec);
+
+          Real new_delta{};
+
+          // set delta_c in function of G_c or a given delta_c value
+          if (Math::are_float_equal(delta_c, 0.)) {
+            new_delta = 2 * G_c / new_sigma;
+          } else {
+            new_delta = sigma_limit / new_sigma * delta_c;
+          }
+
+          new_delta_c.push_back(new_delta);
+        }
+      }
+    }
+
+    // update material data for the new elements
+    auto old_nb_quad_points = sig_c_eff.size();
+    Int new_nb_quad_points = Int(new_sigmas.size());
+    sig_c_eff.resize(old_nb_quad_points + new_nb_quad_points);
+    ins_stress.resize(old_nb_quad_points + new_nb_quad_points);
+    trac_old.resize(old_nb_quad_points + new_nb_quad_points);
+    del_c.resize(old_nb_quad_points + new_nb_quad_points);
+
+    for (Int q = 0; q < new_nb_quad_points; ++q) {
+      sig_c_eff(old_nb_quad_points + q) = new_sigmas[q];
+      del_c(old_nb_quad_points + q) = new_delta_c[q];
+      for (Int d = 0; d < dim; ++d) {
+        ins_stress(old_nb_quad_points + q, d) = new_normal_traction[q](d);
+        trac_old(old_nb_quad_points + q, d) = new_normal_traction[q](d);
+      }
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialCohesiveDamageExtrinsic<dim>::computeLambdaOnQuad(ElementType type,
+                                                      GhostType ghost_type) {
+  SolidMechanicsModelCohesiveDamage * model_lambda = &aka::as_type<SolidMechanicsModelCohesiveDamage>(*model);
+  auto & fem_lambda = model->getFEEngine("LambdaFEEngine");
+  const auto & lambda = model_lambda->getLambda();
+  auto & lambda_on_quad = this->lambda(type, ghost_type);
+
+  auto underlying_type = Mesh::getFacetType(type);
+  fem_lambda.interpolateOnIntegrationPoints(
+      lambda, lambda_on_quad, dim, underlying_type, ghost_type,
+      this->getElementFilter(type, ghost_type));
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialCohesiveDamageExtrinsic<dim>::computeTraction(ElementType el_type,
+                                                  GhostType ghost_type) {
+
+// std::cout << "In MaterialCohesiveDamageExtrinsic<dim>::computeTraction " << std::endl ;
+
+  auto & elem_filter = getElementFilter(el_type, ghost_type);
+  auto nb_element = elem_filter.size();
+  if (nb_element > 0) {
+    // computeLambdaOnQuad(el_type, ghost_type);   // not used 
+    // it iterates over the elements of type _ek_cohesive to computeTraction
+    for (auto && args : getArguments(el_type, ghost_type)) {
+     
+      computeTractionOnQuad(args);
+    }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+Real MaterialCohesiveDamageExtrinsic<dim>::computeObjectiveFunctional() {
+
+  Real val(0.);
+
+  /// integrate the dissipated energy for each type of elements
+  for (auto && type : this->getElementFilter().elementTypes(dim, _not_ghost)) {
+    auto & elem_filter = getElementFilter(type, _not_ghost);
+    auto nb_element = elem_filter.size();
+    if (nb_element > 0) {
+      for (auto && args : getArgumentsObjective(type)) {
+        computeObjectiveFunctionalOnQuad(args);
+      }
+      val += this->getFEEngine().integrate(
+        this->objective_functional(type, _not_ghost), type, _not_ghost,
+        this->getElementFilter(type, _not_ghost));
+    }
+  }
+  return val;
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialCohesiveDamageExtrinsic<dim>::computeLambda(GhostType ghost_type)
+{
+  std::cout << " In MaterialCohesiveDamageExtrinsic<dim>::computeLambda " << std::endl ;
+  const auto & mesh_facets = model->getMeshFacets();
+  for (const auto & type_facet : mesh_facets.elementTypes(dim - 1)) {
+    auto type_cohesive = FEEngine::getCohesiveElementType(type_facet);
+    auto nb_quad_facet =
+        model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet);
+
+    #ifndef AKANTU_NDEBUG
+    auto nb_quad_cohesive = model->getFEEngine("CohesiveFEEngine")
+                                .getNbIntegrationPoints(type_cohesive);
+
+    AKANTU_DEBUG_ASSERT(nb_quad_cohesive == nb_quad_facet,
+                        "The cohesive element and the corresponding facet do "
+                        "not have the same numbers of integration points");
+    #endif
+
+    const auto & element_to_subelement =
+            mesh_facets.getElementToSubelement(type_facet, ghost_type);
+
+    const auto & normals = model->getFEEngine("FacetsFEEngine")
+                               .getNormalsOnIntegrationPoints(type_facet);
+    const auto & f_stress = model->getStressOnFacets(type_facet);
+
+    auto facet_stress_begin = make_view(f_stress, dim, dim, 2).begin();
+    auto normal_begin = make_view<dim>(normals).begin();
+
+    auto damage_begin = czm_damage(type_facet,ghost_type).begin();
+    auto opening_begin = make_view<dim>(opening(type_cohesive,ghost_type)).begin();
+
+    for (auto data :
+         enumerate(make_view(lambda(type_facet), dim,nb_quad_facet))) {
+      auto && f = std::get<0>(data);
+      auto && lda = std::get<1>(data);
+      auto && elem = element_to_subelement(f);
+
+      auto && e = -1;
+      for(auto ec : elem)
+      {
+        if(ec!=ElementNull)
+        {
+          if(ec.kind() == _ek_cohesive)
+          {
+              e = ec.element;
+              continue;
+          }
+        }
+      }
+
+      if(e < 0)
+      {
+        for (Int q = 0; q < nb_quad_facet; ++q) {
+          auto current_quad = f * nb_quad_facet + q;
+          auto && normal = normal_begin[current_quad];
+          auto && facet_stress = facet_stress_begin[current_quad];
+
+          auto && stress_1 = facet_stress(0);
+          auto && stress_2 = facet_stress(1);
+
+          auto && stress_avg = (stress_1 + stress_2) / 2.;
+          lda(q) = stress_avg*normal;
+        }
+      }
+      else
+      {
+        for (Int q = 0; q < nb_quad_facet; ++q) {
+          auto current_quad = f * nb_quad_facet + q;
+          auto current_elem_quad = e * nb_quad_facet + q;
+          auto && w = opening_begin[current_elem_quad];
+          auto && d = damage_begin[current_quad];
+          lda(q) = k*augmented_stiffness(d)*w;
+          std::cout << "f = " << f << std::endl ;
+          std::cout << " w = " << w << std::endl ;
+          std::cout << " d = " << d << std::endl ;
+          std::cout << " lda = " << lda(q) << std::endl ;
+        }
+      }
+    }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialCohesiveDamageExtrinsic<dim>::computeDamage(GhostType ghost_type)
+{
+
+  for (const auto & type : getElementFilter().elementTypes(
+           spatial_dimension, ghost_type, _ek_cohesive)) {
+    
+    auto & elem_filter = getElementFilter(type, ghost_type);
+    // retrives the a filter that selects elments based on their type, more specifically like triangle, quad etc
+    auto nb_element = elem_filter.size();
+    
+    if (nb_element == 0) {
+      continue;
+    }
+    
+    // iterating over the elements of type _ek_cohesive
+    for (auto && args : getArguments(type, ghost_type)) {
+      computeDamageOnQuad(args);
+    }
+  }
+
+}
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialCohesiveDamageExtrinsic<dim>::readDamage(const Array<Element> &, const Array<Real> &)
+{
+  /// TODO
+}
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialCohesiveDamageExtrinsic<dim>::writeDamage(const Array<Element> & clip_to_mesh,  Array<Real> & to) const
+{
+  Int n_nodes = to.size();
+  auto clip_nodes_it = clip_to_mesh.begin();
+  for(int i = 0 ; i<n_nodes; ++i, ++clip_nodes_it) {
+    Element elem=*clip_nodes_it;
+    if(elem!=ElementNull) {
+      to[i]=czm_damage(elem);      
+    }
+  }
+}
+/* -------------------------------------------------------------------------- */
+template class MaterialCohesiveDamageExtrinsic<1>;
+template class MaterialCohesiveDamageExtrinsic<2>;
+template class MaterialCohesiveDamageExtrinsic<3>;
+const bool material_is_alocated_cohesive_damage [[maybe_unused]] =
+    instantiateMaterial<MaterialCohesiveDamageExtrinsic>("cohesive_damage_extrinsic");
+
+} // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f6c78d2097bb4d228c90401bb8723c770ff647eb
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh
@@ -0,0 +1,142 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_cohesive_damage.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_HH_
+#define AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_HH_
+
+namespace akantu {
+
+/**
+ * Cohesive material linear damage for extrinsinc case
+ *
+ * parameters in the material files :
+ *   - sigma_c   : critical stress sigma_c  (default: 0)
+ *   - G_c       : fracture energy for mode I (default: 0)
+ *   - k         : cohesive stiffness
+ */
+template <Int dim> class MaterialCohesiveDamageExtrinsic : public MaterialCohesiveDamage {
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  MaterialCohesiveDamageExtrinsic(SolidMechanicsModel & model, const ID & id = "");
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+
+  /// check stress for cohesive elements' insertion
+  void checkInsertion(bool check_only = false) override;
+
+  void computeLambda(GhostType ghost_type = _not_ghost) override;
+
+  void computeDamage(GhostType /*ghost_type*/ = _not_ghost) override;
+
+  void readDamage(const Array<Element> &, const Array<Real> &) override;
+  void writeDamage(const Array<Element> &,  Array<Real> &) const override;
+
+  template <class D1, class D2, class D3, class D4>
+  Real
+  computeEffectiveNorm(const Eigen::MatrixBase<D1> & stress,
+                       const Eigen::MatrixBase<D2> & normal,
+                       const Eigen::MatrixBase<D3> & tangent,
+                       const Eigen::MatrixBase<D4> & normal_traction_) const;
+
+  /// compute the value of the objective function 
+  Real computeObjectiveFunctional();
+
+protected:
+  void computeLambdaOnQuad(ElementType type, GhostType ghost_type);
+
+  inline decltype(auto) getArguments(ElementType element_type,
+                                     GhostType ghost_type) {
+    using namespace tuple;
+    return zip_append(
+        MaterialCohesive::getArguments<dim>(element_type, ghost_type),
+        "lambda"_n = make_view<dim>(this->lambda(element_type, ghost_type)),
+        "czm_damage"_n = this->czm_damage(element_type, ghost_type));
+  }
+
+  /// constitutive law
+  void computeTraction(ElementType el_type,
+                       GhostType ghost_type = _not_ghost) override;
+
+  template <typename Args> inline void computeTractionOnQuad(Args && args);
+  
+  /// compute the objective function for a given quadrature point
+  template <typename Args> inline void computeObjectiveFunctionalOnQuad(Args && args);
+
+  inline decltype(auto) getArgumentsObjective(ElementType element_type) {
+    using namespace tuple;
+    return zip_append(
+        MaterialCohesive::getArguments<dim>(element_type, _not_ghost),
+        "lambda"_n = make_view<dim>(this->lambda(element_type, _not_ghost)),
+        "czm_damage"_n = this->czm_damage(element_type, _not_ghost),
+        "objective"_n = this->czm_damage(element_type, _not_ghost));
+  }
+
+  [[nodiscard]] bool needLambda() const override { return false; }
+
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+protected:
+
+  /// augmented lagrange multiplier
+  CohesiveInternalField<Real> & lambda;
+
+  /// cohesive damage
+  CohesiveInternalField<Real> & czm_damage;
+
+  /// stress at insertion
+  CohesiveInternalField<Real> & insertion_stress;
+
+  CohesiveRandomInternalField<Real> & sigma_c_eff;
+
+  /// effective critical displacement (each element can have a
+  /// different value)
+  CohesiveInternalField<Real> & delta_c_eff;
+
+  /// stress at insertion
+  CohesiveInternalField<Real> & is_new_crack;
+
+  /// objective_function
+  CohesiveInternalField<Real> & objective_functional;
+
+  bool max_quad_stress_insertion{};
+  
+  Real beta2_inv{};
+  
+
+};
+
+/* -------------------------------------------------------------------------- */
+/* inline functions                                                           */
+/* -------------------------------------------------------------------------- */
+
+} // namespace akantu
+
+#include "material_cohesive_damage_extrinsic_inline_impl.hh"
+
+#endif /* AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_HH_ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..09cc2f4d5489a1cfa977413454b9e95b92b62969
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh
@@ -0,0 +1,96 @@
+/**
+ * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_cohesive_damage_extrinsic.hh"
+
+/* -------------------------------------------------------------------------- */
+#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_INLINE_IMPL_HH_
+#define AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_INLINE_IMPL_HH_
+
+/* -------------------------------------------------------------------------- */
+
+namespace akantu {
+
+///* -------------------------------------------------------------------------- */
+
+template <Int dim>
+template <typename Args>
+inline void MaterialCohesiveDamageExtrinsic<dim>::computeTractionOnQuad(Args && args) {
+  
+  auto && d = args["czm_damage"_n];
+  auto && opening = args["opening"_n];
+  auto && traction = args["traction"_n];
+  // auto && normal = args["normal"_n];
+  if (d == 0.0) {
+    traction.setZero();
+    
+    return;
+  }
+
+  traction = k * opening * this->gd_clip_function(d);
+
+}
+/* -------------------------------------------------------------------------------------- */
+template <Int dim>
+template <class D1, class D2, class D3, class D4>
+Real MaterialCohesiveDamageExtrinsic<dim>::computeEffectiveNorm(
+    const Eigen::MatrixBase<D1> & stress, const Eigen::MatrixBase<D2> & normal,
+    const Eigen::MatrixBase<D3> & tangent,
+    const Eigen::MatrixBase<D4> & normal_traction_) const {
+  Eigen::MatrixBase<D4> & normal_traction =
+      const_cast<Eigen::MatrixBase<D4> &>(normal_traction_);
+  normal_traction = stress * normal;
+
+  Real normal_contrib = normal_traction.dot(normal);
+
+  /// in 3D tangential components must be summed
+  Real tangent_contrib = 0;
+
+  if constexpr (dim == 2) {
+    Real tangent_contrib_tmp = normal_traction.dot(tangent);
+    tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp;
+  } else if constexpr (dim == 3) {
+    for (auto && tangent_v : tangent) {
+      Real tangent_contrib_tmp = normal_traction.dot(tangent_v);
+      tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp;
+    }
+  }
+
+  tangent_contrib = std::sqrt(tangent_contrib);
+  normal_contrib = std::max(Real(0.), normal_contrib);
+
+  return std::sqrt(normal_contrib * normal_contrib +
+                   tangent_contrib * tangent_contrib * beta2_inv);
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+template <typename Args>
+inline void MaterialCohesiveDamageExtrinsic<dim>::computeObjectiveFunctionalOnQuad(Args && args) {
+  auto && d = args["czm_damage"_n];
+  auto && opening = args["opening"_n];
+  args["objective"_n] = 0.5*k*opening.dot(opening)*this->gd_clip_function(d) + yc*hd_clip_function(d);
+}
+
+} // namespace akantu
+
+/* -------------------------------------------------------------------------- */
+#endif // AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_INLINE_IMPL_HH_
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..df7b0d230fbeeb0ccf1ed58623ff41267aef42a6
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh
@@ -0,0 +1,208 @@
+/**
+ * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_cohesive_damage.hh"
+
+/* -------------------------------------------------------------------------- */
+#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_INLINE_IMPL_HH_
+#define AKANTU_MATERIAL_COHESIVE_DAMAGE_INLINE_IMPL_HH_
+
+/* -------------------------------------------------------------------------- */
+
+namespace akantu {
+///* -------------------------------------------------------------------------- */
+template <typename Args>
+inline void MaterialCohesiveDamage::computeDamageOnQuad(Args && args) {
+ auto && d = args["czm_damage"_n]; 
+ auto && open = args["opening"_n];
+ auto && normal = args["normal"_n];
+
+ auto normal_opening = open.dot(normal);
+ auto normal_opening_squared = normal_opening * normal_opening;
+
+ Real lower_bound = 1e-10; // Define lower bound of the damage
+ Real upper_bound = 1.; // Define upper bound of the damage
+  
+ if(normal_opening_squared == 0) {
+    d = 0.0;
+    return;
+ }
+ 
+try {
+        // Define the residual function for Brent's Method
+        auto residual = [&](Real d_val) { return computeResidual(d_val, normal_opening_squared); };
+
+        // Solve for d using Brent's Method
+        Real d_solution = brentsMethod(residual, lower_bound, upper_bound);
+
+        d = d_solution;
+        // std::cout << "Solution for d found using Brent's Method: d = " << d_solution << std::endl;
+    } catch (const std::exception &e) {
+        std::cerr << "Error in Brent's method: " << e.what() << std::endl;
+        // Handle error (e.g., fallback to another method or log failure)
+    }
+
+// try {
+//         // Solve for d using Least Squares
+//         Real d_solution = solveForDamageUsingLeastSquares(normal_opening_squared, lower_bound, upper_bound, 1e-12, 1000);
+
+//         d = d_solution;
+//         std::cout << "Solution for d found using Least Squares: d = " << d_solution << std::endl;
+//     } catch (const std::exception &e) {
+//         std::cerr << "Error in Least Squares method: " << e.what() << std::endl;
+//         // Handle error (e.g., fallback to another method or log failure)
+//     }
+
+} 
+
+///* -------------------------------------------------------------------------- */
+/// Function to Define Residual for Brent's Method
+inline Real MaterialCohesiveDamage::computeResidual(Real d, Real normal_opening_squared) {
+
+    auto numerator = (yc * hd_clip_function_first_derivative(d) / 2.0) + 
+                     (Yc * lc * HD_clip_function(Dm * d));
+    
+    auto denominator = ((k * k * gd_clip_function(d) * gd_clip_function(d) * lc) / (2.0 * E_coh)) *
+                       (1.0 / GD_clip_function(Dm * d) - 1.0) -
+                       (k * gd_clip_function_first_derivative(d) / 4.0);
+
+
+    auto f_d = numerator / denominator;
+    return f_d - normal_opening_squared;
+}
+
+
+///* -------------------------------------------------------------------------- */
+template <typename Func>
+Real brentsMethod(Func func, Real lower, Real upper, Real tol = 1e-15, int max_iter = 1000) {
+    Real a = lower, b = upper, c = upper;
+    Real fa = func(a), fb = func(b), fc = fb;
+
+    if (std::abs(fa) < tol) return a;
+    if (std::abs(fb) < tol) return b;
+
+    Real s = b, fs = fb; // Approximation and function value
+    bool mflag = true;     // Flag to indicate if bisection is used
+    Real d = 0;          // Step size for the interval
+
+    for (int iter = 0; iter < max_iter; ++iter) {
+        // Convergence check
+        if (std::abs(b - a) < tol || std::abs(fb) < tol) {
+            return b;
+        }
+
+        if (fa != fc && fb != fc) {
+            // Inverse quadratic interpolation
+            s = a * fb * fc / ((fa - fb) * (fa - fc)) +
+                b * fa * fc / ((fb - fa) * (fb - fc)) +
+                c * fa * fb / ((fc - fa) * (fc - fb));
+        } else {
+            // Secant method
+            s = b - fb * (b - a) / (fb - fa);
+        }
+
+        // Condition for bisection fallback
+        if ((s < (3 * a + b) / 4 || s > b) ||
+            (mflag && std::abs(s - b) >= std::abs(b - c) / 2) ||
+            (!mflag && std::abs(s - b) >= std::abs(c - d) / 2) ||
+            (mflag && std::abs(b - c) < tol) ||
+            (!mflag && std::abs(c - d) < tol)) {
+            s = (a + b) / 2; // Bisection
+            mflag = true;
+        } else {
+            mflag = false;
+        }
+
+        fs = func(s);
+        d = c; // Update previous step
+        c = b; // Update c to the current b
+
+        if (fa * fs < 0) {
+            b = s;
+            fb = fs;
+        } else {
+            a = s;
+            fa = fs;
+        }
+
+        // Ensure a and b are ordered with |f(a)| < |f(b)|
+        if (std::abs(fa) < std::abs(fb)) {
+            std::swap(a, b);
+            std::swap(fa, fb);
+        }
+    }
+
+    throw std::runtime_error("Brent's method failed to converge.");
+}
+
+/* -------------------------------------------------------------------------- */
+/// Least Squares Solver for the Problem
+inline Real MaterialCohesiveDamage::solveForDamageUsingLeastSquares(Real normal_opening_squared, Real lower_bound, Real upper_bound, 
+                                                                    Real tol, int max_iter) {
+    Real a = lower_bound, b = upper_bound;
+    Real best_d = a, best_residual = std::numeric_limits<Real>::max();
+    
+    // Number of points for the grid search phase
+    const int num_points = 1000;
+    std::vector<Real> d_values(num_points);
+
+    // Grid search to find a rough minimum
+    for (int i = 0; i < num_points; ++i) {
+        Real d = a + i * (b - a) / (num_points - 1);
+        Real residual = std::pow(computeResidual(d, normal_opening_squared), 2);
+        if (residual < best_residual) {
+            best_d = d;
+            best_residual = residual;
+        }
+    }
+
+    // Refine solution using a gradient-descent-like approach
+    Real d = best_d;
+    for (int iter = 0; iter < max_iter; ++iter) {
+        Real f_d = computeResidual(d, normal_opening_squared);
+        Real f_d_prime = (computeResidual(d + tol, normal_opening_squared) - f_d) / tol; // Approximate derivative
+
+        if (std::abs(f_d_prime) < tol) {
+            break; // Convergence achieved
+        }
+
+        // Gradient descent update
+        Real step = -2.0 * f_d * f_d_prime;
+        d += step;
+
+        // Keep d within bounds
+        if (d < a || d > b) {
+            throw std::runtime_error("Solution moved out of bounds.");
+        }
+
+        // Check for convergence
+        if (std::abs(f_d) < tol) {
+            return d;
+        }
+    }
+
+    return d;
+}
+
+} 
+
+/* -------------------------------------------------------------------------- */
+#endif // AKANTU_MATERIAL_COHESIVE_DAMAGE_INLINE_IMPL_HH_
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc
new file mode 100644
index 0000000000000000000000000000000000000000..01abc4a34246c32821e145c1c8e42a1b66b45093
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc
@@ -0,0 +1,35 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_cohesive_damage_non_local.hh"
+
+namespace akantu {
+
+template class MaterialCohesiveDamageNonLocal<1>;
+template class MaterialCohesiveDamageNonLocal<2>;
+template class MaterialCohesiveDamageNonLocal<3>;
+
+template <Int dim> using MaterialCohesiveDamageNonLocal_ = MaterialCohesiveDamageNonLocal<dim>;
+
+static bool material_is_alocated_cohesive_damage_non_local =
+    instantiateMaterial<MaterialCohesiveDamageNonLocal_>("cohesive_damage_non_local");
+
+} // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh
new file mode 100644
index 0000000000000000000000000000000000000000..6ca13aa375ba010e8bd45ca8599a1004cff2e662
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh
@@ -0,0 +1,80 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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 "material_damage_non_local.hh"
+#include "material_cohesive_damage_extrinsic.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_NON_LOCAL_HH_
+#define AKANTU_MATERIAL_COHESIVE_DAMAGE_NON_LOCAL_HH_
+
+namespace akantu {
+
+/**
+ * Material bulk damage Non local
+ *
+ * parameters in the material files :
+ */
+template <Int dim>
+class MaterialCohesiveDamageNonLocal
+    : public MaterialDamageNonLocal<dim, MaterialCohesiveDamageExtrinsic<dim>> {
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  using parent = MaterialDamageNonLocal<dim, MaterialCohesiveDamageExtrinsic<dim>>;
+
+  MaterialCohesiveDamageNonLocal(SolidMechanicsModel & model, const ID & id = "");
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+
+  void computeNonLocalStress(ElementType /*el_type*/,
+                             GhostType /*ghost_type = _not_ghost*/) override {}
+
+protected:
+
+  void registerNeighborhood() override {};
+
+  void registerNonLocalVariables() override;
+
+  /* ------------------------------------------------------------------------ */
+  /* Accessors                                                                */
+  /* ------------------------------------------------------------------------ */
+
+  ID getNeighborhoodName() override {return "clip"; };
+
+public:
+
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+private:
+
+};
+
+} // namespace akantu
+
+#include "material_cohesive_damage_non_local_tmpl.hh"
+
+#endif /* AKANTU_MATERIAL_COHESIVE_DAMAGE_NON_LOCAL_HH_ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..604ada62dfb2ed243f81d884c03b96f931bb10c2
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh
@@ -0,0 +1,54 @@
+/**
+ * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_
+#define AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+MaterialCohesiveDamageNonLocal<dim>::MaterialCohesiveDamageNonLocal(
+    SolidMechanicsModel & model, const ID & id):parent(model,id)
+    {
+  AKANTU_DEBUG_IN();
+
+  //// MUST THIS REALLY BE SET TO TRUE ???
+  this->is_non_local = true;
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <Int dim>
+void MaterialCohesiveDamageNonLocal<dim>::registerNonLocalVariables() {
+  // this->getModel()
+  //     .getNonLocalManager()
+  //     .getNeighborhood(this->name)
+  //     .registerNonLocalVariable(this->czm_damage.getName());
+}
+
+} // namespace akantu
+
+#endif // AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc
new file mode 100644
index 0000000000000000000000000000000000000000..786b00fa40a7386df732d58b5a3d36ff5de4b09a
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc
@@ -0,0 +1,446 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_clip.hh"
+#include "aka_iterators.hh"
+#include "fe_engine_template.hh"
+#include "shape_lagrange.hh"
+#include "integrator_gauss.hh"
+#include "mesh_accessor.hh"
+/* -------------------------------------------------------------------------- */
+#include "dumper_iohelper_paraview.hh"
+/* -------------------------------------------------------------------------- */
+#include <algorithm>
+/* -------------------------------------------------------------------------- */
+#if defined(WITH_GMSH)
+#include "gmsh.h"
+#endif
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+SolidMechanicsModelCLIP::SolidMechanicsModelCLIP(
+    Mesh & mesh, Int dim, const ID & id,
+    const std::shared_ptr<DOFManager> & dof_manager)
+    : SolidMechanicsModelCohesiveDamage(mesh, dim, id, dof_manager)
+    ,czm_material(nullptr)
+    ,bulk_material(nullptr)
+{
+    czm_damage =
+        std::make_unique<Array<Real>>(0, 1, "cohesive damage");
+
+    bulk_damage =
+        std::make_unique<Array<Real>>(0, 1, "bulk damage");
+
+    clip_mesh = std::make_unique<Mesh>(spatial_dimension,
+                                         mesh.getCommunicator(), "clip_mesh");
+
+    this->mesh.registerDumper<DumperParaview>("clip", id);
+    this->mesh.addDumpMeshToDumper("clip", *clip_mesh,
+                                 Model::spatial_dimension, _not_ghost,
+                                 _ek_regular);
+
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCLIP::initialize() {
+    // Precompute distances once before the time-stepping loop
+    precomputeDistances();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCLIP::initConstitutiveLaws() {
+  AKANTU_DEBUG_IN();
+  #if defined(WITH_GMSH)
+  createCLIPMesh();
+  #endif
+  this->for_each_constitutive_law([&](auto && material) {
+  try {
+      auto & mat = aka::as_type<MaterialCohesiveDamage>(material);
+      czm_material = &mat;
+    } catch (std::bad_cast & bce) {
+        Material * mat = &material;
+        if(mat->isInternal<Real>("damage",_ek_regular)) {
+        bulk_material = &material;
+      }
+    }
+  });
+  SolidMechanicsModelCohesiveDamage::initConstitutiveLaws();
+  if (this->isNonLocal()) {
+    this->getNonLocalManager().registerNonLocalVariable("czm_damage", "damage", 1);
+  }
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCLIP::createCLIPMesh()
+{
+  MeshAccessor mesh_accessor(mesh);
+  MeshAccessor mesh_accessor_clip(*clip_mesh);
+
+  auto & clip_nodes = mesh_accessor_clip.getNodes();
+  auto & clip_connectivities = mesh_accessor_clip.getConnectivities();
+
+  Mesh & mesh_facets = mesh.initMeshFacets();
+  MeshAccessor mesh_accessor_facets(mesh_facets);
+
+  // get facets barycenters
+  ElementTypeMapArray<Real> barycenters;
+  Int nb_clip_nodes(0);
+  barycenters.initialize(mesh_facets, _nb_component = spatial_dimension,
+                         _spatial_dimension = spatial_dimension-1,
+                         _with_nb_element = true);
+
+  for (auto && ghost_type : ghost_types) {
+    for (auto && type :
+         barycenters.elementTypes(spatial_dimension-1,ghost_type)) {
+      mesh_facets.getBarycenters(barycenters(type, ghost_type),type,
+                                  ghost_type);
+      nb_clip_nodes+=mesh_facets.getNbElement(type, ghost_type);
+    }
+  }
+
+  mesh_accessor_clip.resizeNodes(nb_clip_nodes);
+
+  // create clip mesh nodes array and facets_to_clip element map
+  auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh");
+  clip_to_mesh.resize(clip_mesh->getNbNodes(),ElementNull);
+  
+  auto && view_clip_nodes = make_view(clip_nodes,spatial_dimension);
+  auto clip_nodes_begin = view_clip_nodes.begin();
+  facets_to_clip.initialize(mesh_facets, _nb_component = 1,_spatial_dimension = spatial_dimension-1);
+  std::vector<double> coord;
+  Int i_node = 0;
+
+  for (auto && ghost_type : ghost_types) {
+   for (auto && type :
+        barycenters.elementTypes(spatial_dimension-1,ghost_type)) {
+     auto & barycenter = barycenters(type,ghost_type);
+     auto && view_bar =
+         make_view(barycenter, barycenter.getNbComponent());
+     facets_to_clip(type,ghost_type).resize(mesh_facets.getNbElement(type,ghost_type),-1);
+     for (auto && data : zip(view_bar,view_clip_nodes,facets_to_clip(type,ghost_type))) {
+      std::get<1>(data)=std::get<0>(data);
+      std::get<2>(data)=i_node;
+      for(Int i=0; i<spatial_dimension;++i)
+      {
+        coord.push_back(std::get<0>(data)[i]);
+      }
+      ++i_node;
+     }
+   }
+  }
+
+  // call gmsh to create clip mesh
+  std::vector<std::size_t> tri;
+  #if defined(WITH_GMSH)
+  gmsh::initialize();
+  gmsh::model::mesh::triangulate(coord,tri);
+  #else
+  std::cout << "WARNING : SolidMechanicsModelCLIP::createCLIPMesh requires to compile with WITH_GMSH=ON " << std::endl;
+  #endif
+  int n_tri = tri.size()/3;
+  
+  // create mesh connectivities + fix triangles orientations
+  for (auto && ghost_type : ghost_types) {
+    clip_mesh->addConnectivityType(_triangle_3, ghost_type);
+    mesh_accessor_clip.resizeConnectivity(n_tri,_triangle_3, ghost_type);
+    auto & clip_conn = clip_connectivities(_triangle_3, ghost_type);
+    auto && view_conn_it = make_view(clip_conn, clip_conn.getNbComponent()).begin();
+    for(int i = 0 ; i<n_tri; ++i, ++view_conn_it)
+    { 
+      int i1 = tri[3*i]-1;
+      int i2 = tri[3*i+1]-1;
+      int i3 = tri[3*i+2]-1;
+      auto x1 = clip_nodes_begin[i1];
+      auto x2 = clip_nodes_begin[i2];
+      auto x3 = clip_nodes_begin[i3];
+      auto v12 = x2-x1;
+      auto v13 = x3-x1;
+      Real t = v12[1]*v13[0]-v12[0]*v13[1];
+      (*view_conn_it)[0]=i1;
+      if(t < 0.)
+      {
+        (*view_conn_it)[1]=i2;
+        (*view_conn_it)[2]=i3;
+      }
+      else
+      {
+        (*view_conn_it)[1]=i3;
+        (*view_conn_it)[2]=i2;
+      }
+    }
+  }
+
+  mesh_accessor_clip.makeReady();
+  clip_mesh->write("clip_mesh.msh");
+
+  czm_damage->resize(clip_mesh->getNbNodes(),0.);
+  bulk_damage->resize(clip_mesh->getNbNodes(),0.);
+
+  registerFEEngineObject<MyFEEngineType>("CLIPFEEngine", *clip_mesh,
+                                          Model::spatial_dimension);
+  // precompute clip shape functions at computation mesh integration points
+  computeShapeFunctionsOnIntegrationPoints();
+
+}
+
+
+/*----------------------------------------------------------------------------*/
+void SolidMechanicsModelCLIP::precomputeDistances() {
+   auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh");
+    Int n_nodes = clip_to_mesh.size();
+    MeshAccessor mesh_accessor_clip(*clip_mesh);
+    auto & clip_nodes = mesh_accessor_clip.getNodes();
+    auto && view_clip_nodes = make_view(clip_nodes, spatial_dimension);
+    auto clip_nodes_begin = view_clip_nodes.begin();
+
+    distances.resize(n_nodes, std::vector<Real>(n_nodes, 0.0));
+    std::cout << "Distances are pre computed" << std::endl ;
+    for (Int i = 0; i < n_nodes; ++i) {
+        const auto& current_node = clip_nodes_begin[i];
+        for (Int j = 0; j < n_nodes; ++j) {
+            const auto& other_node = clip_nodes_begin[j];
+            Real dist = 0.0;
+            for (Int k = 0; k < spatial_dimension; ++k) {
+                Real diff = current_node[k] - other_node[k];
+                dist += diff * diff;
+            }
+            distances[i][j] = std::sqrt(dist);
+        }
+    }
+}
+
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCLIP::computeBulkDamage() {
+    auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh");
+  
+    // Write czm damage from MaterialCohesiveDamage inside model czm damage
+    czm_material->writeDamage(clip_to_mesh, *czm_damage);
+
+    Real lc = czm_material->getLc();
+    Real Dm = czm_material->getDm();
+
+    // Get the number of nodes in the clip_to_mesh
+    Int n_nodes = clip_to_mesh.size();
+    // std::cout << "Number of nodes of Clip mesh = " << n_nodes << std::endl ;
+  
+    // Initialize vectors to store damage values
+    std::vector<std::vector<Real>> all_Di(n_nodes, std::vector<Real>(n_nodes, 0.0));
+    std::vector<Real> max_Di(n_nodes, 0.0);
+
+    // Iterate over each node in the clip_to_mesh
+    for(Int i = 0; i < n_nodes; ++i) {
+        auto& di = (*czm_damage)[i];
+        // Iterate over all other nodes to compute damage using precomputed distances
+        for (Int j = 0; j < n_nodes; ++j) {
+            Real dist = distances[i][j];
+            Real Computed_Di = (di - (dist)/(lc))*Dm;
+            all_Di[i][j] = Computed_Di;
+        }
+    }
+    // Compute and print the maximum value of each column in all_Di
+  std::vector<Real> max_col_values(n_nodes, 0.0);
+  for (Int j = 0; j < n_nodes; ++j) {
+  Real max_col_value = all_Di[0][j];
+  for (Int i = 1; i < n_nodes; ++i) {
+      if (all_Di[i][j] > max_col_value) {
+          max_col_value = all_Di[i][j];
+      }
+  }
+  max_col_values[j] = max_col_value;
+  }
+
+    for (Int i = 0; i < n_nodes; ++i) {
+        (*bulk_damage)[i] = max_col_values[i];
+    }
+
+    // czm_material->readDamage(clip_to_mesh, *czm_damage);
+    interpolateBulkDamageOnIntegrationPoints();
+}
+/* -------------------------------------------------------------------------- */
+Real SolidMechanicsModelCLIP::computeObjectiveFunction() {
+  Real val_czm = czm_material->computeObjectiveFunctional();
+  Real val_bulk;
+  // very dirty but no other choice for now
+  switch(spatial_dimension) {
+    case 1 : 
+      val_bulk =  aka::as_type<MaterialBulkDamage<1>>(*bulk_material).computeObjectiveFunctional();
+      break;
+    case 2 : 
+      val_bulk =  aka::as_type<MaterialBulkDamage<2>>(*bulk_material).computeObjectiveFunctional();
+      break;
+    case 3 : 
+      val_bulk =  aka::as_type<MaterialBulkDamage<3>>(*bulk_material).computeObjectiveFunctional();
+      break;
+    default:
+      break;
+  }
+  return val_czm + val_bulk;
+}
+
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCLIP::computeShapeFunctionsOnIntegrationPoints() {
+  auto & fem_clip = this->getFEEngine("CLIPFEEngine");
+  auto & fem = this->getFEEngine("SolidMechanicsFEEngine");
+
+  clip_shapes.initialize(mesh,_spatial_dimension = spatial_dimension);
+  gp_to_clip_elem.initialize(mesh,_spatial_dimension = spatial_dimension);
+
+  for (auto && ghost_type : ghost_types) {
+    for (auto && type : mesh.elementTypes(spatial_dimension,ghost_type,_ek_regular)) {
+      Array<Real> quadrature_points(mesh.getNbElement(type,ghost_type),spatial_dimension*fem.getNbIntegrationPoints(type,ghost_type));
+      fem.computeIntegrationPointsCoordinates(quadrature_points,type,ghost_type);
+
+      auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
+      auto size_of_shapes = fem_clip.getShapes(type, ghost_type).getNbComponent();
+      clip_shapes(type,ghost_type).resize(mesh.getNbElement(type,ghost_type)*size_of_shapes*nb_quadrature_points);
+      gp_to_clip_elem(type,ghost_type).resize(mesh.getNbElement(type,ghost_type)*nb_quadrature_points);
+      auto quadrature_points_begin = make_view(quadrature_points,spatial_dimension).begin();
+      auto shapes_begin = make_view(clip_shapes(type,ghost_type),size_of_shapes).begin();
+      auto gp_to_clip_elem_begin = make_view(gp_to_clip_elem(type,ghost_type),nb_quadrature_points).begin();
+      for(int e =0; e<mesh.getNbElement(type,ghost_type);++e) {
+        auto && gp_to_clip_elem_e = gp_to_clip_elem_begin[e];
+        for(int i = 0; i < nb_quadrature_points; ++i)
+        {
+          const auto & xgi = quadrature_points_begin[e*nb_quadrature_points+i];
+          auto && Ngi = shapes_begin[e*nb_quadrature_points+i];
+          // WARNING : very CPU inefficient, try to find something else !!!
+          for (auto && ghost_typei : ghost_types) {
+            for (auto && typei : clip_mesh->elementTypes(spatial_dimension,ghost_type,_ek_regular)) {
+              Int j=0;
+              for(; j<clip_mesh->getNbElement(typei,ghost_typei);++j) {
+                if(aka::as_type<MyFEEngineType>(fem_clip).contains(xgi,j,typei,ghost_typei)) {
+                  /// NOTE : THIS WORKS ONLY IF CLIP MESH IS MADE ONLY OF TRI/TET (WHICH IS THE CASE AT THE MOMENT)
+                  ///        (normally should also store type and chost_type)
+                  gp_to_clip_elem_e[i]=j;
+                  break;
+                }
+              }
+              fem_clip.computeShapes(xgi,j,typei,Ngi,ghost_typei);
+            }
+          }
+        }
+      }
+    }    
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCLIP::interpolateBulkDamageOnIntegrationPoints()
+{
+  InternalField<Real> &  bulk_damage_internal = bulk_material->getInternal<Real>("damage");
+    
+  auto & connectivities = clip_mesh->getConnectivities();
+  auto & fem_clip = this->getFEEngine("CLIPFEEngine");
+  auto & fem = this->getFEEngine("SolidMechanicsFEEngine");
+
+  for (auto && ghost_type : ghost_types) {
+    for (auto && type : mesh.elementTypes(spatial_dimension,ghost_type,_ek_regular)) {
+      auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+      auto nb_quadrature_points_per_element = fem.getNbIntegrationPoints(type, ghost_type);
+      auto size_of_shapes = fem_clip.getShapes(type, ghost_type).getNbComponent();
+
+      auto connectivities_begin = make_view(connectivities(type,ghost_type),nb_nodes_per_element).begin();
+      auto shapes_begin = make_view(clip_shapes(type,ghost_type),size_of_shapes*nb_quadrature_points_per_element).begin();
+      auto bulk_damage_begin = make_view(bulk_damage_internal(type,ghost_type),nb_quadrature_points_per_element).begin();
+      auto gp_to_clip_elem_begin = make_view(gp_to_clip_elem(type,ghost_type),nb_quadrature_points_per_element).begin();
+      for(int e =0; e<mesh.getNbElement(type,ghost_type);++e) {
+        auto && gp_to_clip_elem_e = gp_to_clip_elem_begin[e];
+        auto && dam = bulk_damage_begin[e];
+        for(int i = 0; i < nb_quadrature_points_per_element; ++i)
+        {
+          auto e_clip = gp_to_clip_elem_e[i];
+          const auto & shape = shapes_begin[e];
+          const auto & conn = connectivities_begin[e_clip];
+          auto && Di = dam[i];
+          Di=0.;
+          for(int j=0;j<size_of_shapes;++j)
+          {
+            Di+=(*this->bulk_damage)[conn[j]]*shape[i*nb_quadrature_points_per_element+j];
+          }
+        }
+      }
+    } 
+  } 
+}
+
+/* -------------------------------------------------------------------------- */
+std::shared_ptr<dumpers::Field>
+SolidMechanicsModelCLIP::createNodalFieldReal(const std::string & field_name,
+                     const std::string & group_name,
+                     bool padding_flag)
+{
+  if(field_name == "clip_bulk_damage" || field_name == "clip_czm_damage")
+  {
+
+    std::map<std::string, Array<Real> *> real_nodal_fields;
+    real_nodal_fields["clip_bulk_damage"] = this->bulk_damage.get();
+    real_nodal_fields["clip_czm_damage"] = this->czm_damage.get();
+
+    std::shared_ptr<dumpers::Field> field;
+    if (padding_flag) {
+      field = clip_mesh->createNodalField(real_nodal_fields[field_name],
+                                        group_name, 3);
+    } else {
+      field =
+          clip_mesh->createNodalField(real_nodal_fields[field_name], group_name);
+    }
+  return field;
+  }
+  else
+  {
+    return SolidMechanicsModel::createNodalFieldReal(field_name,group_name,padding_flag);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+std::shared_ptr<dumpers::Field>
+SolidMechanicsModelCLIP::createElementalField(const std::string & field_name,
+                     const std::string & group_name, bool padding_flag,
+                      Int spatial_dimension, ElementKind kind)
+{
+  return SolidMechanicsModel::createElementalField(field_name,group_name,padding_flag,spatial_dimension,kind);
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCLIP::onElementsAdded(const Array<Element> & element_list,
+                                              const NewElementsEvent & event)
+
+{
+  auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh");
+  const auto & mesh_facets = this->getMeshFacets();
+  for(auto & element : element_list)
+  {
+    auto type = element.type;
+    auto ghost_type = element.ghost_type;
+    const auto & element_to_facet = mesh_facets.getSubelementToElement(type,ghost_type);
+    auto && facet_1 = element_to_facet(element.element,0);
+    auto && facet_2 = element_to_facet(element.element,1);
+    auto && facet = facet_1<facet_2?facet_1:facet_2;
+    clip_to_mesh[facets_to_clip(facet)]=element;
+  }
+  SolidMechanicsModelCohesiveDamage::onElementsAdded(element_list,event);
+}
+
+} // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh
new file mode 100644
index 0000000000000000000000000000000000000000..3eefb0422e62fe3dd54b9a6e0416e09ac2516afc
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh
@@ -0,0 +1,114 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_cohesive_damage.hh"
+#include "material_cohesive_damage.hh"
+#include "material_bulk_damage.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_SOLID_MECHANICS_MODEL_CLIP_HH_
+#define AKANTU_SOLID_MECHANICS_MODEL_CLIP_HH_
+
+/* -------------------------------------------------------------------------- */
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+/* Solid Mechanics Model for CLIP formulation                               */
+/* -------------------------------------------------------------------------- */
+class SolidMechanicsModelCLIP : public SolidMechanicsModelCohesiveDamage {
+
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  SolidMechanicsModelCLIP(
+      Mesh & mesh, Int dim = _all_dimensions,
+      const ID & id = "solid_mechanics_model_cohesive_clip",
+      const std::shared_ptr<DOFManager> & dof_manager = nullptr);
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+
+public:
+  void initialize();
+  void createCLIPMesh();
+
+  template<class func>
+  void initializeCZMDamage(func);
+
+  void precomputeDistances();
+  void computeBulkDamage() override;
+  
+  Real computeObjectiveFunction();
+
+  std::shared_ptr<dumpers::Field>
+  createNodalFieldReal(const std::string & field_name,
+                       const std::string & group_name,
+                       bool padding_flag) override;
+
+  std::shared_ptr<dumpers::Field>
+  createElementalField(const std::string & field_name,
+                       const std::string & group_name, bool padding_flag,
+                       Int spatial_dimension, ElementKind kind) override;
+
+
+protected:
+
+  /// initialize cohesive material and clip mesh
+  void initConstitutiveLaws() override;
+
+  void onElementsAdded(const Array<Element> & element_list,
+                       const NewElementsEvent & event) override;
+
+  void computeShapeFunctionsOnIntegrationPoints();
+
+  void interpolateBulkDamageOnIntegrationPoints();
+
+private:
+
+  MaterialCohesiveDamage * czm_material;
+
+  Material * bulk_material;
+
+  std::unique_ptr<Mesh> clip_mesh;
+
+  ElementTypeMapInt facets_to_clip;
+
+  ElementTypeMapReal clip_shapes;
+
+  ElementTypeMapInt gp_to_clip_elem;
+
+
+  /// cohesive damage
+  std::unique_ptr<Array<Real>> czm_damage;
+
+  /// bulk damage
+  std::unique_ptr<Array<Real>> bulk_damage;
+
+  std::vector<std::vector<Real>> distances;
+};
+
+} // namespace akantu
+
+#include "solid_mechanics_model_clip_inline_impl.hh"
+
+#endif /* AKANTU_SOLID_MECHANICS_MODEL_CLIP_HH_ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh
new file mode 100644
index 0000000000000000000000000000000000000000..e2b7bfbb70d3c006e68c0f59fef473e5e8fdde53
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh
@@ -0,0 +1,51 @@
+/**
+ * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_clip.hh"
+
+#ifndef AKANTU_SOLID_MECHANICS_MODEL_CLIP_INLINE_IMPL_HH_
+#define AKANTU_SOLID_MECHANICS_MODEL_CLIP_INLINE_IMPL_HH_
+
+namespace akantu {
+
+template<class func>
+void SolidMechanicsModelCLIP::initializeCZMDamage(func init){
+  InternalField<Real> &  czm_damage_internal = czm_material->getInternal<Real>("czm_damage");
+  auto & fem = this->getFEEngine("CohesiveFEEngine");
+  ElementTypeMapReal integration_points_positions("integration_points_positions", id);
+  integration_points_positions.initialize(fem, _nb_component = spatial_dimension,
+                                           _spatial_dimension = spatial_dimension);
+  fem.computeIntegrationPointsCoordinates(integration_points_positions);
+
+  for (auto ghost_type : ghost_types) {
+    for (auto type : mesh.elementTypes(_element_kind = _ek_cohesive,
+                       _ghost_type = ghost_type)) {
+      for (auto && data :
+       zip((czm_damage_internal)(type,ghost_type)
+       ,make_view(integration_points_positions(type,ghost_type),spatial_dimension))) {
+       std::get<0>(data) = init(std::get<1>(data));
+      }
+    }
+  }
+}
+
+} // namespace akantu
+
+#endif /* AKANTU_SOLID_MECHANICS_MODEL_CLIP_INLINE_IMPL_HH_ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc
index 0d0b906907eefaa59e3d2112a7b6e470940d9cff..38d31c135d2f11cb1d59bd707859650959975ab3 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc
@@ -397,20 +397,28 @@ void SolidMechanicsModelCohesive::initStressInterpolation() {
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::assembleInternalForces() {
   AKANTU_DEBUG_IN();
-
+  // std::cout << "Assemble Internal forces" << std::endl;
   // f_int += f_int_cohe
+  // iterates over each constiute law defined in the solidMEchanicsModel
+  
   this->for_each_constitutive_law([&](auto && material) {
     try {
+      //it tries to cast the generic material to the type MaterialCohesive.If its a different type
+      // it throws a std::bad_cast
+      
       auto & mat = aka::as_type<MaterialCohesive>(material);
+      mat.computeDamage(_not_ghost);
+      
       mat.computeTraction(_not_ghost);
     } catch (std::bad_cast & bce) {
     }
   });
-
+  computeBulkDamage();
+  // need to compute Bulk G(D)
   SolidMechanicsModel::assembleInternalForces();
 
   AKANTU_DEBUG_OUT();
-}
+ }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::computeNormals() {
@@ -490,7 +498,6 @@ UInt SolidMechanicsModelCohesive::checkCohesiveStress() {
 void SolidMechanicsModelCohesive::onElementsAdded(
     const Array<Element> & element_list, const NewElementsEvent & event) {
   AKANTU_DEBUG_IN();
-
   SolidMechanicsModel::onElementsAdded(element_list, event);
 
   if (is_extrinsic) {
@@ -500,6 +507,7 @@ void SolidMechanicsModelCohesive::onElementsAdded(
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::onNodesAdded(const Array<Idx> & new_nodes,
                                                const NewNodesEvent & event) {
@@ -552,8 +560,6 @@ void SolidMechanicsModelCohesive::onNodesAdded(const Array<Idx> & new_nodes,
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::afterSolveStep(bool converged) {
-  AKANTU_DEBUG_IN();
-
   /*
    * This is required because the Cauchy stress is the stress measure that
    * is used to check the insertion of cohesive elements
@@ -567,8 +573,6 @@ void SolidMechanicsModelCohesive::afterSolveStep(bool converged) {
   }
 
   SolidMechanicsModel::afterSolveStep(converged);
-
-  AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh
index c4c96d4d9d257b204674d1da9b73f0e790d6002b..08806b6a31ba21053f3694d26c33be6f5dfdfe8c 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh
@@ -44,14 +44,15 @@ struct FacetsCohesiveIntegrationOrderFunctor {
                                   CohesiveFacetProperty<type>::cohesive_type>
   struct _helper {
     static constexpr int get() {
-      return ElementClassProperty<cohesive_type>::polynomial_degree;
+//      return 1;
+        return ElementClassProperty<cohesive_type>::polynomial_degree;
     }
   };
 
   template <ElementType type> struct _helper<type, _not_defined> {
     static constexpr int get() {
-      return ElementClassProperty<type>::polynomial_degree;
-    }
+        //      return 1;
+        return ElementClassProperty<type>::polynomial_degree;    }
   };
 
   template <ElementType type> static inline constexpr int getOrder() {
@@ -115,7 +116,6 @@ public:
 
   /// insert intrinsic cohesive elements
   void insertIntrinsicElements();
-
   // template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria
   // criteria> bool solveStepCohesive(Real tolerance, Real & error, UInt
   // max_iteration = 100,
@@ -139,7 +139,7 @@ protected:
   /// function to print the contain of the class
   void printself(std::ostream & stream, int indent = 0) const override;
 
-private:
+protected:
   /// insert cohesive elements along a given physical surface of the mesh
   void insertElementsFromMeshData(const std::string & physical_name);
 
@@ -155,6 +155,9 @@ private:
   /// init facets_check array
   void initFacetsCheck();
 
+  virtual void computeBulkDamage(){
+    // TODO: Implement bulk damage computation
+  }
   /* ------------------------------------------------------------------------ */
   /* Mesh Event Handler inherited members                                     */
   /* ------------------------------------------------------------------------ */
@@ -183,13 +186,6 @@ public:
                                  ElementKind element_kind,
                                  bool padding_flag) override;
 
-public:
-  /// register the tags associated with the parallel synchronizer for
-  /// cohesive elements
-  // void initParallel(MeshPartition * partition,
-  //                DataAccessor * data_accessor = NULL,
-  //                bool extrinsic = false);
-
 protected:
   // void synchronizeGhostFacetsConnectivity();
 
@@ -267,7 +263,7 @@ public:
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
-private:
+protected:
   friend class CohesiveMeshGlobalDataUpdater;
 
   /// @todo store tangents when normals are computed:
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc
new file mode 100644
index 0000000000000000000000000000000000000000..648a1552f49c1e161204babe4fd9930380283bb1
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc
@@ -0,0 +1,502 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_cohesive_damage.hh"
+#include "aka_iterators.hh"
+#include "cohesive_element_inserter.hh"
+#include "fe_engine_template.hh"
+#include "integrator_gauss.hh"
+#include "material_cohesive_damage.hh"
+#include "mesh_accessor.hh"
+#include "parser.hh"
+#include "shape_cohesive.hh"
+/* -------------------------------------------------------------------------- */
+#include "dumper_iohelper_paraview.hh"
+/* -------------------------------------------------------------------------- */
+#include <algorithm>
+/* -------------------------------------------------------------------------- */
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+SolidMechanicsModelCohesiveDamage::SolidMechanicsModelCohesiveDamage(
+    Mesh & mesh, Int dim, const ID & id,
+    const std::shared_ptr<DOFManager> & dof_manager)
+    : SolidMechanicsModelCohesive(mesh, dim, id, dof_manager)
+{}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesiveDamage::initConstitutiveLaws() {
+  AKANTU_DEBUG_IN();
+
+  // make sure the material are instantiated
+  instantiateMaterials();
+
+  auto & material_selector = this->getConstitutiveLawSelector();
+
+  // set the facet information in the material in case of dynamic insertion
+  // to know what material to call for stress checks
+  const Mesh & mesh_facets = inserter->getMeshFacets();
+  facet_material.initialize(
+      mesh_facets, _spatial_dimension = spatial_dimension - 1,
+      _with_nb_element = true,
+      _default_value =
+          DefaultMaterialCohesiveSelector::getDefaultCohesiveMaterial(*this));
+
+  for_each_element(
+      mesh_facets,
+      [&](auto && element) {
+        auto mat_index = material_selector(element);
+        if (not mat_index) {
+          return;
+        }
+        auto & mat =
+            aka::as_type<MaterialCohesive>(this->getConstitutiveLaw(mat_index));
+
+        facet_material(element) = mat_index;
+        if (is_extrinsic) {
+          mat.addFacet(element);
+        }
+      },
+      _spatial_dimension = spatial_dimension - 1, _ghost_type = _not_ghost);
+
+  SolidMechanicsModel::initConstitutiveLaws();
+
+  auto & initial_nodes = mesh.getNodalData<Idx>("initial_nodes_match");
+  initial_nodes.resize(mesh.getNbNodes());
+  for (auto && [node, init_node] : enumerate(initial_nodes)) {
+    init_node = node;
+  }
+
+  auto need_lambda = false;
+
+  this->for_each_constitutive_law([&need_lambda](auto && material) {
+    if (aka::is_of_type<MaterialCohesive>(material)) {
+      need_lambda |= aka::as_type<MaterialCohesive>(material).needLambda();
+    }
+  });
+
+  if (need_lambda) {
+    lambda =
+        std::make_unique<Array<Real>>(0, spatial_dimension, "cohesive lambda");
+    previous_lambda =
+        std::make_unique<Array<Real>>(0, spatial_dimension, "previous lambda");
+    lambda_increment =
+        std::make_unique<Array<Real>>(0, spatial_dimension, "lambda increment");
+    lambda_blocked_dofs = std::make_unique<Array<bool>>(0, spatial_dimension,
+                                                        "lambda_blocked_dofs");
+
+    lambda_mesh = std::make_unique<Mesh>(spatial_dimension,
+                                         mesh.getCommunicator(), "lambda_mesh");
+    registerFEEngineObject<MyFEEngineLambdaType>("LambdaFEEngine", *lambda_mesh,
+                                                 Model::spatial_dimension - 1);
+
+    auto & nodes_to_lambda = mesh.getNodalData<Idx>("nodes_to_lambda");
+    nodes_to_lambda.resize(mesh.getNbNodes(), -1);
+  }
+
+  if (is_extrinsic) {
+    this->initAutomaticInsertion();
+  } else {
+    this->insertIntrinsicElements();
+  }
+
+  if (lambda) {
+    auto & dof_manager = this->getDOFManager();
+    if (!dof_manager.hasDOFs("lambda")) {
+      dof_manager.registerDOFs("lambda", *this->lambda, *lambda_mesh);
+      dof_manager.registerDOFsIncrement("lambda", *this->lambda_increment);
+      dof_manager.registerDOFsPrevious("lambda", *this->previous_lambda);
+      dof_manager.registerBlockedDOFs("lambda", *this->lambda_blocked_dofs);
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+} // namespace akantu
+
+/* -------------------------------------------------------------------------- */
+UInt SolidMechanicsModelCohesiveDamage::checkCohesiveInsertion() {
+  AKANTU_DEBUG_IN();
+
+  if (not is_extrinsic) {
+    AKANTU_EXCEPTION(
+        "This function can only be used for extrinsic cohesive elements");
+  }
+
+  this->for_each_constitutive_law([&](auto && material) {
+    std::cout << "check insertion " << std::endl ;
+    if (aka::is_of_type<MaterialCohesive>(material)) {
+      /// check which not ghost cohesive elements are to be created
+      auto & mat_cohesive = aka::as_type<MaterialCohesive>(material);
+      mat_cohesive.checkInsertion();
+    }
+  });
+
+  /// insert cohesive elements
+  auto nb_new_elements = inserter->insertElements();
+
+  AKANTU_DEBUG_OUT();
+
+  return nb_new_elements;
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesiveDamage::computeLagrangeMultiplier() {
+  AKANTU_DEBUG_IN();
+
+  if (not is_extrinsic) {
+    AKANTU_EXCEPTION(
+        "This function can only be used for extrinsic cohesive elements");
+  }
+
+  interpolateStress();
+
+  this->for_each_constitutive_law([&](auto && material) {
+    if (aka::is_of_type<MaterialCohesive>(material)) {
+      /// check which not ghost cohesive elements are to be created
+      auto & mat_cohesive = aka::as_type<MaterialCohesive>(material);
+      mat_cohesive.computeLambda();
+    }
+  });
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesiveDamage::computeDamage() {
+  AKANTU_DEBUG_IN();
+  
+  this->for_each_constitutive_law([&](auto && material) {
+    if (aka::is_of_type<MaterialCohesiveDamage>(material)) {
+      /// check which not ghost cohesive elements are to be created
+      auto & mat_cohesive = aka::as_type<MaterialCohesiveDamage>(material);
+      mat_cohesive.computeDamage();
+    }
+  });
+  
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesiveDamage::updateLambdaMesh() {
+//    std::cout << " SolidMechanicsModelCohesiveDamage::updateLambdaMesh " << std::endl;
+
+  const auto & connectivities = mesh.getConnectivities();
+  const auto & initial_nodes = mesh.getNodalData<Idx>("initial_nodes_match");
+  auto & nodes_to_lambda = mesh.getNodalData<Idx>("nodes_to_lambda");
+  nodes_to_lambda.resize(mesh.getNbNodes(), -1);
+
+  auto & lambda_connectivities = MeshAccessor(*lambda_mesh).getConnectivities();
+
+  auto lambda_id = lambda->size();
+
+  std::vector<Idx> new_nodes;
+
+  NewNodesEvent node_event(*lambda_mesh, AKANTU_CURRENT_FUNCTION);
+  auto & node_list = node_event.getList();
+//  std::cout << "node_list before = " << std::endl ;
+//  ArrayPrintHelper<true>::print_content(node_list,std::cout,0);
+
+  NewElementsEvent element_event(*lambda_mesh, AKANTU_CURRENT_FUNCTION);
+  auto & element_list = element_event.getList();
+//  std::cout << "element_list before = " << std::endl ;
+//  ArrayPrintHelper<true>::print_content(element_list,std::cout,0);
+
+  for (auto ghost_type : ghost_types) {
+    for (auto type : connectivities.elementTypes(_element_kind = _ek_cohesive,
+                     _ghost_type = ghost_type)) {
+      auto underlying_type = Mesh::getFacetType(type);
+
+      auto & connectivity = connectivities(type, ghost_type);
+      auto & lambda_connectivity =
+          lambda_connectivities(underlying_type, ghost_type);
+
+//      std::cout << "connectivity = " << std::endl ;
+//      ArrayPrintHelper<true>::print_content(connectivity,std::cout,0);
+
+//      std::cout << "lambda_connectivity = " << std::endl ;
+//      ArrayPrintHelper<true>::print_content(lambda_connectivity,std::cout,0);
+
+
+      auto nb_new_elements = connectivity.size() - lambda_connectivity.size();
+      auto nb_old_elements = lambda_connectivity.size();
+
+      lambda_connectivity.resize(connectivity.size());
+
+      auto && view_iconn =
+          make_view(connectivity, connectivity.getNbComponent());
+      auto && view_conn =
+          make_view(lambda_connectivity, lambda_connectivity.getNbComponent());
+
+//      std::cout << " connectivity.getNbComponent() " << connectivity.getNbComponent() << std::endl  ;
+//      std::cout << " lambda_connectivity.getNbComponent() " << lambda_connectivity.getNbComponent() << std::endl  ;
+
+//      for (auto && [conn, lambda_conn] :
+//           zip(range(view_iconn.begin() + nb_old_elements, view_iconn.end()),
+//               range(view_conn.begin() + nb_old_elements, view_conn.end()))) {
+//          std::cout << "conn = " << conn << std::endl ;
+//          std::cout << "lambda_conn = " << lambda_conn << std::endl ;
+
+//        for (auto && [n, lambda_node] : enumerate(lambda_conn)) {
+//            std::cout << "n = " << n << std::endl ;
+//          auto node = conn[n];
+//          std::cout << "node conn= " << node << std::endl ;
+
+//          node = initial_nodes(node);
+//          std::cout << "node initial_nodes = " << node << std::endl ;
+
+//          auto & ntl = nodes_to_lambda(node);
+//          std::cout << "ntl = " << ntl << std::endl ;
+
+//          if (ntl == -1) {
+//            ntl = lambda_id;
+//            new_nodes.push_back(node);
+//            node_list.push_back(lambda_id);
+//            ++lambda_id;
+//          }
+
+//          lambda_node = ntl;
+//        }
+//      }
+
+      for (auto && [conn, lambda_conn] :
+           zip(range(view_iconn.begin() + nb_old_elements, view_iconn.end()),
+               range(view_conn.begin() + nb_old_elements, view_conn.end()))) {
+//          std::cout << "conn = " << conn << std::endl ;
+//          std::cout << "lambda_conn = " << lambda_conn << std::endl ;
+
+        for (auto && [n, lambda_node] : enumerate(lambda_conn)) {
+//            std::cout << "n = " << n << std::endl ;
+          auto node = conn[n];
+//          std::cout << "node conn= " << node << std::endl ;
+
+          node = initial_nodes(node);
+//          std::cout << "node initial_nodes = " << node << std::endl ;
+
+          auto & ntl = nodes_to_lambda(node);
+//          std::cout << "ntl = " << ntl << std::endl ;
+
+         if (ntl == -1) {
+            ntl = lambda_id;
+            new_nodes.push_back(node);
+            node_list.push_back(lambda_id);
+            ++lambda_id;
+         }
+
+          lambda_node = ntl;
+        }
+      }
+
+      for (auto && el : arange(nb_old_elements, nb_new_elements)) {
+//          std::cout << "el = " << el << std::endl ;
+        element_list.push_back({underlying_type, el, ghost_type});
+      }
+    }
+  }
+
+//  std::cout << "node_list after = " << std::endl ;
+//  ArrayPrintHelper<true>::print_content(node_list,std::cout,0);
+
+//  std::cout << "element_list after = " << std::endl ;
+//  ArrayPrintHelper<true>::print_content(element_list,std::cout,0);
+
+  lambda_mesh->copyNodes(mesh, new_nodes);
+
+  lambda->resize(lambda_id, 0.);
+  lambda_increment->resize(lambda_id, 0.);
+  previous_lambda->resize(lambda_id, 0.);
+
+  lambda_mesh->sendEvent(element_event);
+  lambda_mesh->sendEvent(node_event);
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesiveDamage::onElementsAdded(
+    const Array<Element> & element_list, const NewElementsEvent & event) {
+  AKANTU_DEBUG_IN();
+
+//  std::cout << " SolidMechanicsModelCohesiveDamage::onElementsAdded " << std::endl;
+
+  SolidMechanicsModel::onElementsAdded(element_list, event);
+
+  if (lambda) {
+    auto & lambda_connectivities =
+        MeshAccessor(*lambda_mesh).getConnectivities();
+
+    for (auto ghost_type : ghost_types) {
+      for (auto type : mesh.elementTypes(_element_kind = _ek_cohesive,
+                       _ghost_type = ghost_type)) {
+        auto underlying_type = Mesh::getFacetType(type);
+        if (not lambda_connectivities.exists(underlying_type, ghost_type)) {
+          auto nb_nodes_per_element =
+              Mesh::getNbNodesPerElement(underlying_type);
+          lambda_connectivities.alloc(0, nb_nodes_per_element, underlying_type,
+                                      ghost_type, -1);
+        }
+      }
+    }
+  }
+
+  if (is_extrinsic) {
+    resizeFacetStress();
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesiveDamage::onNodesAdded(const Array<Idx> & new_nodes,
+                                               const NewNodesEvent & event) {
+  SolidMechanicsModel::onNodesAdded(new_nodes, event);
+
+  auto & initial_nodes = mesh.getNodalData<Idx>("initial_nodes_match");
+
+  auto old_max_nodes = initial_nodes.size();
+  initial_nodes.resize(mesh.getNbNodes(), -1);
+
+  const auto * cohesive_event =
+      dynamic_cast<const CohesiveNewNodesEvent *>(&event);
+  if (cohesive_event == nullptr) {
+    for (auto && node : new_nodes) {
+      initial_nodes(node) = node;
+    }
+    return;
+  }
+
+  auto old_nodes = cohesive_event->getOldNodesList();
+
+  // getting a corrected old_nodes for multiple doubling
+  for (auto & onode : old_nodes) {
+    while (onode >= old_max_nodes) {
+      auto nnode = new_nodes.find(onode);
+      AKANTU_DEBUG_ASSERT(nnode != -1,
+                          "If the old node is bigger than old_max_nodes it "
+                          "should also be a new node");
+      onode = nnode;
+    }
+  }
+
+  auto copy = [&new_nodes, &old_nodes](auto & arr) {
+    auto it = make_view(arr, arr.getNbComponent()).begin();
+    for (auto [new_node, old_node] : zip(new_nodes, old_nodes)) {
+      it[new_node] = it[old_node];
+    }
+  };
+
+  for (auto && ptr : {displacement.get(), velocity.get(), acceleration.get(),
+                      current_position.get(), previous_displacement.get(),
+                      displacement_increment.get()}) {
+    if (ptr != nullptr) {
+      copy(*ptr);
+    }
+  }
+
+  copy(*displacement);
+  copy(*blocked_dofs);
+
+  if (velocity) {
+    copy(*velocity);
+  }
+
+  if (acceleration) {
+    copy(*acceleration);
+  }
+
+  if (current_position) {
+    copy(*current_position);
+  }
+
+  if (previous_displacement) {
+    copy(*previous_displacement);
+  }
+
+  if (displacement_increment) {
+    copy(*displacement_increment);
+  }
+
+  copy(getDOFManager().getSolution("displacement"));
+
+  // correct connectivities
+  if (lambda) {
+    lambda_blocked_dofs->resize(mesh.getNbNodes(), false);
+    copy(*lambda_blocked_dofs);
+    updateLambdaMesh();
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+ModelSolverOptions SolidMechanicsModelCohesiveDamage::getDefaultSolverOptions(
+    const TimeStepSolverType & type) const {
+  ModelSolverOptions options =
+      SolidMechanicsModel::getDefaultSolverOptions(type);
+
+    if (lambda) {
+//  if (true) {
+    switch (type) {
+    case TimeStepSolverType::_dynamic_lumped: {
+      options.non_linear_solver_type = NonLinearSolverType::_lumped;
+      options.integration_scheme_type["lambda"] =
+          IntegrationSchemeType::_central_difference;
+      options.solution_type["lambda"] = IntegrationScheme::_acceleration;
+      break;
+    }
+    case TimeStepSolverType::_static: {
+      options.non_linear_solver_type = NonLinearSolverType::_newton_raphson;
+      options.integration_scheme_type["lambda"] =
+          IntegrationSchemeType::_pseudo_time;
+      options.solution_type["lambda"] = IntegrationScheme::_not_defined;
+      break;
+    }
+    case TimeStepSolverType::_dynamic: {
+      if (this->method == _explicit_consistent_mass) {
+        options.non_linear_solver_type = NonLinearSolverType::_newton_raphson;
+        options.integration_scheme_type["lambda"] =
+            IntegrationSchemeType::_central_difference;
+        options.solution_type["lambda"] = IntegrationScheme::_acceleration;
+      } else {
+        options.non_linear_solver_type = NonLinearSolverType::_newton_raphson;
+        options.integration_scheme_type["lambda"] =
+            IntegrationSchemeType::_trapezoidal_rule_2;
+        options.solution_type["lambda"] = IntegrationScheme::_displacement;
+      }
+      break;
+    }
+    default:
+      AKANTU_EXCEPTION(type << " is not a valid time step solver type");
+    }
+  }
+  return options;
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesiveDamage::printself(std::ostream & stream,
+                                            int indent) const {
+  std::string space(indent, AKANTU_INDENT);
+
+  stream << space << "SolidMechanicsModelCohesiveDamage ["
+         << "\n";
+  SolidMechanicsModelCohesive::printself(stream, indent + 2);
+  stream << space << "]\n";
+}
+
+/* -------------------------------------------------------------------------- */
+
+} // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh
new file mode 100644
index 0000000000000000000000000000000000000000..5ccf6b678f4c06187b9cb3e96a0c9bb66547d2fc
--- /dev/null
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh
@@ -0,0 +1,151 @@
+/**
+ * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * This file is part of Akantu
+ *
+ * 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_cohesive.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_
+#define AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_
+
+/* -------------------------------------------------------------------------- */
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+struct CohesiveIntegrationOrderFunctor {
+  template <ElementType type, ElementType cohesive_type =
+                                  CohesiveFacetProperty<type>::cohesive_type>
+  struct _helper {
+    static constexpr int get() {
+        //      return 1;
+        return ElementClassProperty<cohesive_type>::polynomial_degree;    }
+  };
+
+  template <ElementType type> struct _helper<type, _not_defined> {
+    static constexpr int get() {
+        //      return 1;
+        return ElementClassProperty<type>::polynomial_degree;    }
+  };
+
+  template <ElementType type> static inline constexpr int getOrder() {
+    return _helper<type>::get();
+  }
+};
+
+/* -------------------------------------------------------------------------- */
+/* Solid Mechanics Model for Cohesive damage elements                                */
+/* -------------------------------------------------------------------------- */
+class SolidMechanicsModelCohesiveDamage : public SolidMechanicsModelCohesive {
+    
+    using MyFEEngineLambdaType =
+      FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_regular,
+                       FacetsCohesiveIntegrationOrderFunctor>;
+  
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  SolidMechanicsModelCohesiveDamage(
+      Mesh & mesh, Int dim = _all_dimensions,
+      const ID & id = "solid_mechanics_model_cohesive_damage",
+      const std::shared_ptr<DOFManager> & dof_manager = nullptr);
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+
+public:
+
+  /// function to perform an insertion check on each facet and insert
+  /// cohesive elements if needed (returns the number of new cohesive
+  /// elements)
+  UInt checkCohesiveInsertion();
+
+  /// compute Lagrange multiplier
+  void computeLagrangeMultiplier();
+
+  /// compute damage variable
+  void computeDamage();
+
+protected:
+
+  /// initialize cohesive material
+  void initConstitutiveLaws() override;
+
+  /// function to print the contain of the class
+  void printself(std::ostream & stream, int indent = 0) const override;
+
+  /* ------------------------------------------------------------------------ */
+  /* SolidMechanicsModelEventHandler inherited members                        */
+  /* ------------------------------------------------------------------------ */
+public:
+
+  [[nodiscard]] ModelSolverOptions
+  getDefaultSolverOptions(const TimeStepSolverType & type) const override;
+
+  void updateLambdaMesh();
+
+  /* ------------------------------------------------------------------------ */
+  /* Accessors                                                                */
+  /* ------------------------------------------------------------------------ */
+public:
+
+  /// get the SolidMechanicsModel::lambda array
+  AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(Lambda, lambda);
+  /// get the SolidMechanicsModel::displacement array
+  AKANTU_GET_MACRO_DEREF_PTR(Lambda, lambda);
+
+  /// get lambda mesh
+  const Mesh & getLambdaMesh() {
+    if (not lambda_mesh) {
+      AKANTU_EXCEPTION("This model does not have a lambda mesh");
+    }
+    return *lambda_mesh;
+  }
+
+protected:
+  void onNodesAdded(const Array<Idx> & new_nodes,
+                    const NewNodesEvent & event) override;
+  void onElementsAdded(const Array<Element> & element_list,
+                       const NewElementsEvent & event) override;
+                       
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+private:
+
+  /// lambda array
+  std::unique_ptr<Array<Real>> lambda;
+
+  /// lambda array at the previous time step
+  std::unique_ptr<Array<Real>> previous_lambda;
+
+  /// increment of lambda
+  std::unique_ptr<Array<Real>> lambda_increment;
+
+  /// array specifing if a lambda degree of freedom is blocked or not
+  std::unique_ptr<Array<bool>> lambda_blocked_dofs;
+
+  std::unique_ptr<Mesh> lambda_mesh;
+};
+
+} // namespace akantu
+
+#endif /* AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_ */
diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc
index 49a48cfdcd4ec4b6de5f36e1a9fb31303a992ad1..92eba2052a3a677748f3b283e6b3123e1defcf52 100644
--- a/src/model/structural_mechanics/structural_mechanics_model.cc
+++ b/src/model/structural_mechanics/structural_mechanics_model.cc
@@ -149,8 +149,7 @@ void StructuralMechanicsModel::initSolver(
   auto & dof_manager = this->getDOFManager();
 
   if (not dof_manager.hasDOFs("displacement")) {
-    dof_manager.registerDOFs("displacement", *displacement_rotation,
-                             _dst_nodal);
+    dof_manager.registerDOFs("displacement", *displacement_rotation, mesh);
     dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs);
   }
 
@@ -525,8 +524,8 @@ void StructuralMechanicsModel::assembleInternalForce(ElementType type,
   Array<Real> intBtSigma(0, ndof_per_elem, "intBtSigma");
   fem.integrate(BtSigma, intBtSigma, ndof_per_elem, type, gt);
 
-  getDOFManager().assembleElementalArrayLocalArray(intBtSigma, *internal_force,
-                                                   type, gt, -1.);
+  getDOFManager().assembleElementalArrayLocalArray(
+      "displacement", intBtSigma, *internal_force, type, gt, -1.);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -687,8 +686,8 @@ void StructuralMechanicsModel::computeForcesByLocalTractionArray(
                           nb_degree_of_freedom * nb_nodes_per_element, type);
 
   // assemble the result into force vector
-  getDOFManager().assembleElementalArrayLocalArray(int_funct, *external_force,
-                                                   type, _not_ghost, 1);
+  getDOFManager().assembleElementalArrayLocalArray(
+      "displacement", int_funct, *external_force, type, _not_ghost, 1);
 
   AKANTU_DEBUG_OUT();
 }
diff --git a/src/synchronizer/dof_synchronizer.cc b/src/synchronizer/dof_synchronizer.cc
index 4cdf8f55b5f5c51c78d8e54530800d848a57898f..d6497c76531d6528a2900025f7dee5e7781a7f17 100644
--- a/src/synchronizer/dof_synchronizer.cc
+++ b/src/synchronizer/dof_synchronizer.cc
@@ -56,9 +56,6 @@ DOFSynchronizer::DOFSynchronizer(DOFManagerDefault & dof_manager, const ID & id)
   }
 }
 
-/* -------------------------------------------------------------------------- */
-DOFSynchronizer::~DOFSynchronizer() = default;
-
 /* -------------------------------------------------------------------------- */
 void DOFSynchronizer::registerDOFs(const ID & dof_id) {
   if (this->nb_proc == 1) {
@@ -71,7 +68,8 @@ void DOFSynchronizer::registerDOFs(const ID & dof_id) {
 
   const auto & equation_numbers = dof_manager.getLocalEquationsNumbers(dof_id);
   const auto & associated_nodes = dof_manager.getDOFsAssociatedNodes(dof_id);
-  const auto & node_synchronizer = dof_manager.getMesh().getNodeSynchronizer();
+  const auto & node_synchronizer =
+      dof_manager.getMesh(dof_id).getNodeSynchronizer();
   const auto & node_communications = node_synchronizer.getCommunications();
 
   auto transcode_node_to_global_dof_scheme =
@@ -99,8 +97,7 @@ void DOFSynchronizer::registerDOFs(const ID & dof_id) {
         std::sort(global_dofs_per_node.begin(), global_dofs_per_node.end());
         std::transform(global_dofs_per_node.begin(), global_dofs_per_node.end(),
                        global_dofs_per_node.begin(), [this](Idx g) -> Idx {
-                         auto l = dof_manager.globalToLocalEquationNumber(g);
-                         return l;
+                         return dof_manager.globalToLocalEquationNumber(g);
                        });
         for (auto & leqnum : global_dofs_per_node) {
           scheme.push_back(leqnum);
@@ -145,8 +142,7 @@ void DOFSynchronizer::onNodesAdded(const Array<Idx> & /*nodes_list*/) {
   auto dof_ids = dof_manager.getDOFIDs();
 
   for (auto sr : iterate_send_recv) {
-    for (auto && data : communications.iterateSchemes(sr)) {
-      auto & scheme = data.second;
+    for (auto && [_, scheme] : communications.iterateSchemes(sr)) {
       scheme.resize(0);
     }
   }
diff --git a/src/synchronizer/dof_synchronizer.hh b/src/synchronizer/dof_synchronizer.hh
index 93179dcaf8852e0b6bbebf3535313ea9f2a4685a..f3ea171aaf857c28b382b578182d5e98f55732d6 100644
--- a/src/synchronizer/dof_synchronizer.hh
+++ b/src/synchronizer/dof_synchronizer.hh
@@ -41,7 +41,6 @@ class DOFSynchronizer : public SynchronizerImpl<Idx> {
 public:
   DOFSynchronizer(DOFManagerDefault & dof_manager,
                   const ID & id = "dof_synchronizer");
-  ~DOFSynchronizer() override;
 
   virtual void registerDOFs(const ID & dof_id);
   /* ------------------------------------------------------------------------ */
diff --git a/src/synchronizer/grid_synchronizer.cc b/src/synchronizer/grid_synchronizer.cc
index 25f00d184b9d971d6cf73d34fbafc986f69f14ca..19117fc3622d8c8ae9d2a9054cfe979fcc0baabc 100644
--- a/src/synchronizer/grid_synchronizer.cc
+++ b/src/synchronizer/grid_synchronizer.cc
@@ -27,7 +27,6 @@
 #include "mesh.hh"
 #include "mesh_io.hh"
 #include <iostream>
-
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
@@ -232,8 +231,8 @@ void GridSynchronizer::createGridSynchronizer(const SpatialGrid<E> & grid) {
   Int nb_total_nodes_to_recv = 0;
   Int nb_current_nodes = global_nodes_ids.size();
 
-  NewNodesEvent new_nodes;
-  NewElementsEvent new_elements;
+  NewNodesEvent new_nodes(mesh);
+  NewElementsEvent new_elements(mesh);
 
   std::map<Int, std::vector<Int>> ask_nodes_per_proc;
 
diff --git a/test/test_model/test_common/test_dof_manager.cc b/test/test_model/test_common/test_dof_manager.cc
index acde4ea0669bdd02fb7151bab5082ebb21855ca1..64251a74eeddda4a96a9955929c08672e2692f3e 100644
--- a/test/test_model/test_common/test_dof_manager.cc
+++ b/test/test_model/test_common/test_dof_manager.cc
@@ -121,7 +121,7 @@ public:
         {_dmt_default, "default"}, {_dmt_petsc, "petsc"}};
 
     return DOFManagerTester(DOFManagerFactory::getInstance().allocate(
-        types[T::value], *mesh, "dof_manager"));
+        types[T::value], "dof_manager"));
   }
 
   decltype(auto) registerDOFs(DOFSupportType dst1, DOFSupportType dst2) {
@@ -130,14 +130,22 @@ public:
     auto n1 = dst1 == _dst_nodal ? nb_nodes : nb_pure_local;
     this->dof1 = std::make_unique<Array<Real>>(n1, 3);
 
-    dof_manager->registerDOFs("dofs1", *this->dof1, dst1);
+    if (dst1 == _dst_nodal) {
+      dof_manager->registerDOFs("dofs1", *this->dof1, *mesh);
+    } else {
+      dof_manager->registerDOFs("dofs1", *this->dof1, dst1);
+    }
 
     EXPECT_EQ(dof_manager.residual().size(), nb_total_nodes * 3);
 
     auto n2 = dst2 == _dst_nodal ? nb_nodes : nb_pure_local;
     this->dof2 = std::make_unique<Array<Real>>(n2, 5);
 
-    dof_manager->registerDOFs("dofs2", *this->dof2, dst2);
+    if (dst2 == _dst_nodal) {
+      dof_manager->registerDOFs("dofs2", *this->dof2, *mesh);
+    } else {
+      dof_manager->registerDOFs("dofs2", *this->dof2, dst2);
+    }
 
     EXPECT_EQ(dof_manager.residual().size(), nb_total_nodes * 8);
     return dof_manager;
@@ -176,23 +184,32 @@ TYPED_TEST(DOFManagerFixture, RegisterGenericDOF1) {
   EXPECT_GE(dof_manager.residual().size(), this->nb_total_nodes * 3);
 }
 
+/* -------------------------------------------------------------------------- */
+TYPED_TEST(DOFManagerFixture, RegisterGenericDOF2) {
+  this->registerDOFs(_dst_generic, _dst_generic);
+}
+
 /* -------------------------------------------------------------------------- */
 TYPED_TEST(DOFManagerFixture, RegisterNodalDOF1) {
   auto dof_manager = this->alloc();
 
   Array<Real> dofs(this->nb_nodes, 3);
-  dof_manager->registerDOFs("dofs1", dofs, _dst_nodal);
+  dof_manager->registerDOFs("dofs1", dofs, *this->mesh);
   EXPECT_GE(dof_manager.residual().size(), this->nb_total_nodes * 3);
 }
 
 /* -------------------------------------------------------------------------- */
-TYPED_TEST(DOFManagerFixture, RegisterGenericDOF2) {
-  this->registerDOFs(_dst_generic, _dst_generic);
+TYPED_TEST(DOFManagerFixture, RegisterNodalDOF2) {
+  this->registerDOFs(_dst_nodal, _dst_nodal);
 }
 
 /* -------------------------------------------------------------------------- */
-TYPED_TEST(DOFManagerFixture, RegisterNodalDOF2) {
-  this->registerDOFs(_dst_nodal, _dst_nodal);
+TYPED_TEST(DOFManagerFixture, RegisterNodalDOF3) {
+  auto dof_manager = this->alloc();
+
+  Array<Real> dofs(this->nb_nodes, 3);
+  EXPECT_THROW(dof_manager->registerDOFs("dofs1", dofs, _dst_nodal),
+               debug::Exception);
 }
 
 /* -------------------------------------------------------------------------- */
diff --git a/test/test_model/test_common/test_dof_mesh_distribute.cc b/test/test_model/test_common/test_dof_mesh_distribute.cc
index 1514cb254698d43951080a653814e9663b127331..ea2b89db6c51cc3971a00cbc1ea8c1bcb7356237 100644
--- a/test/test_model/test_common/test_dof_mesh_distribute.cc
+++ b/test/test_model/test_common/test_dof_mesh_distribute.cc
@@ -53,16 +53,19 @@ TEST(TestMesh, TestMeshDistribute) {
     mesh2.read("mesh.msh");
   }
 
+  Array<Real> dofs(mesh1.getNbNodes(), 1);
+
   /* This should fail since the mesh is distributed after the
    *  DOFManager is created. */
-  DOFManagerDefault dof_manager(mesh1, "test_dof_manager_1__failing");
+  DOFManagerDefault dof_manager("test_dof_manager_1__failing");
+  dof_manager.registerDOFs("u", dofs, mesh1);
   EXPECT_THROW(mesh1.distribute(), debug::Exception);
 
   /* This will succeed since the mesh is distributed before the manager is
    * created. */
   mesh2.distribute();
-  EXPECT_NO_THROW(
-      DOFManagerDefault dof_manager2(mesh2, "test_dof_manager_2__succeeding"));
+  DOFManagerDefault dof_manager2("test_dof_manager_2__succeeding");
+  EXPECT_NO_THROW(dof_manager2.registerDOFs("u", dofs, mesh2));
 
   finalize();
 }
diff --git a/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh b/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh
index b8ce549a4c5293ada414f9b1083143935dc0e5b1..9d25bd39f997eaa3bca280270b797337e387aa6e 100644
--- a/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh
+++ b/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh
@@ -50,11 +50,11 @@ public:
   MyModel(Real F, Mesh & mesh, bool lumped,
           const ID & dof_manager_type = "default")
       : ModelSolver(mesh, ModelType::_model, "model_solver"),
-        nb_dofs(mesh.getNbNodes()), nb_elements(mesh.getNbElement(_segment_2)),
-        lumped(lumped), E(1.), A(1.), rho(1.), mesh(mesh),
-        displacement(nb_dofs, 1, "disp"), velocity(nb_dofs, 1, "velo"),
-        acceleration(nb_dofs, 1, "accel"), blocked(nb_dofs, 1, "blocked"),
-        forces(nb_dofs, 1, "force_ext"),
+        BoundaryCondition<MyModel>("disp"), nb_dofs(mesh.getNbNodes()),
+        nb_elements(mesh.getNbElement(_segment_2)), lumped(lumped), E(1.),
+        A(1.), rho(1.), mesh(mesh), displacement(nb_dofs, 1, "disp"),
+        velocity(nb_dofs, 1, "velo"), acceleration(nb_dofs, 1, "accel"),
+        blocked(nb_dofs, 1, "blocked"), forces(nb_dofs, 1, "force_ext"),
         internal_forces(nb_dofs, 1, "force_int"),
         stresses(nb_elements, 1, "stress"), strains(nb_elements, 1, "strain"),
         initial_lengths(nb_elements, 1, "L0") {
@@ -63,7 +63,7 @@ public:
 
     this->initBC(*this, displacement, forces);
 
-    this->getDOFManager().registerDOFs("disp", displacement, _dst_nodal);
+    this->getDOFManager().registerDOFs("disp", displacement, mesh);
     this->getDOFManager().registerDOFsDerivative("disp", 1, velocity);
     this->getDOFManager().registerDOFsDerivative("disp", 2, acceleration);
     this->getDOFManager().registerBlockedDOFs("disp", blocked);
@@ -140,7 +140,7 @@ public:
     }
 
     this->getDOFManager().assembleElementalArrayLocalArray(
-        m_all_el, M, _segment_2, ghost_type);
+        "disp", m_all_el, M, _segment_2, ghost_type);
 
     this->getDOFManager().assembleToLumpedMatrix("disp", M, "M");
   }
@@ -295,7 +295,7 @@ public:
     }
 
     this->getDOFManager().assembleElementalArrayLocalArray(
-        forces_internal_el, internal_forces, _segment_2, ghost_type);
+        "disp", forces_internal_el, internal_forces, _segment_2, ghost_type);
   }
 
   Real getPotentialEnergy() {
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo
index 9cae112da0a2518e00a7ee8fdb48f0acfc0b23cd..8656cdfcfa044acfd52ba723498f36d9c5faa058 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo
@@ -10,23 +10,39 @@ Point(4) = { x/2.,-y/2, 0, h};
 Point(5) = {-x/2.,   0, 0, h};
 Point(6) = { x/2.,   0, 0, h};
 
-Line(1) = {1, 2};
+Point(7) = {    0,   0, 0, h};
+Point(8) = {    0, y/2, 0, h};
+Point(9) = {    0,-y/2, 0, h};
+
+
+Line(11) = {1, 8};
+Line(12) = {8, 2};
 Line(2) = {2, 5};
-Line(3) = {5, 6};
+Line(31) = {5, 7};
+Line(32) = {7, 6};
 Line(4) = {6, 1};
 
 Line(5) = {5, 3};
-Line(6) = {3, 4};
+Line(61) = {3, 9};
+Line(62) = {9, 4};
 Line(7) = {4, 6};
 
-Line Loop(1) = {1, 2, 3, 4};
-Line Loop(2) = {-3, 5, 6, 7};
-Plane Surface(1) = {1};
-Plane Surface(2) = {2};
+Line(8) = {7, 8};
+Line(9) = {7, 9};
+
+Line Loop(11) = {11, -8, 32, 4};
+Line Loop(12) = {12, 2, 31, 8};
+Line Loop(21) = {-32, 9, 62, 7};
+Line Loop(22) = {-31, 5, 61, -9};
+Plane Surface(11) = {11};
+Plane Surface(12) = {12};
+Plane Surface(21) = {21};
+Plane Surface(22) = {22};
 
-Physical Line("fixed") = {6};
-Physical Line("loading") = {1};
-Physical Line("insertion") = {3};
+Physical Line("fixed") = {61, 62};
+Physical Line("loading") = {11, 12};
+Physical Line("insertion") = {31, 32};
 Physical Line("sides") = {2, 5, 7, 4};
+Physical Line("middle") = {8, 9};
 
-Physical Surface("body") = {1, 2};
+Physical Surface("body") = {11, 12, 21, 22};
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh
index f9a6e5773bdc6681f4e2e194cbfef15d42c8b481..dbe5b77db2ee982a15298b492fd2621a6cfa034e 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh
@@ -1,51 +1,205 @@
 $MeshFormat
-2.2 0 8
+4.1 0 8
 $EndMeshFormat
 $PhysicalNames
-4
+6
 1 1 "fixed"
 1 2 "loading"
 1 3 "insertion"
-2 4 "body"
+1 4 "sides"
+1 5 "middle"
+2 6 "body"
 $EndPhysicalNames
+$Entities
+9 12 2 0
+1 1 0.5 0 0 
+2 -1 0.5 0 0 
+3 -1 -0.5 0 0 
+4 1 -0.5 0 0 
+5 -1 0 0 0 
+6 1 0 0 0 
+7 0 0 0 0 
+8 0 0.5 0 0 
+9 0 -0.5 0 0 
+2 -1 0 0 -1 0.5 0 1 4 2 2 -5 
+4 1 0 0 1 0.5 0 1 4 2 6 -1 
+5 -1 -0.5 0 -1 0 0 1 4 2 5 -3 
+7 1 -0.5 0 1 0 0 1 4 2 4 -6 
+8 0 0 0 0 0.5 0 1 5 2 7 -8 
+9 0 -0.5 0 0 0 0 1 5 2 7 -9 
+11 0 0.5 0 1 0.5 0 1 2 2 1 -8 
+12 -1 0.5 0 0 0.5 0 1 2 2 8 -2 
+31 -1 0 0 0 0 0 1 3 2 5 -7 
+32 0 0 0 1 0 0 1 3 2 7 -6 
+61 -1 -0.5 0 0 -0.5 0 1 1 2 3 -9 
+62 0 -0.5 0 1 -0.5 0 1 1 2 9 -4 
+1 -1 0 0 1 0.5 0 1 6 8 12 2 31 8 -4 -32 8 -11 
+2 -1 -0.5 0 1 0 0 1 6 8 -32 9 62 7 -31 5 61 -9 
+$EndEntities
 $Nodes
+23 33 1 33
+0 1 0 1
+1
+1 0.5 0
+0 2 0 1
+2
+-1 0.5 0
+0 3 0 1
+3
+-1 -0.5 0
+0 4 0 1
+4
+1 -0.5 0
+0 5 0 1
+5
+-1 0 0
+0 6 0 1
+6
+1 0 0
+0 7 0 1
+7
+0 0 0
+0 8 0 1
+8
+0 0.5 0
+0 9 0 1
+9
+0 -0.5 0
+1 2 0 1
+10
+-1 0.2500000000010293 0
+1 4 0 1
+11
+1 0.2499999999993471 0
+1 5 0 1
+12
+-1 -0.2499999999993471 0
+1 7 0 1
 13
-1 1 1 0
-2 -1 1 0
-3 -1 -1 0
-4 1 -1 0
-5 -1 0 0
-6 1 0 0
-7 2.752797989558076e-12 1 0
-8 -2.752797989558076e-12 0 0
-9 -2.752797989558076e-12 -1 0
-10 -0.4999999999986235 0.5000000000027528 0
-11 0.5000000000013765 0.5 0
-12 0.4999999999986235 -0.5 0
-13 -0.5000000000013765 -0.5 0
+1 -0.2500000000010293 0
+1 8 0 1
+14
+0 0.2499999999993471 0
+1 9 0 1
+15
+0 -0.2499999999993471 0
+1 11 0 2
+16
+17
+0.6666666666675911 0.5 0
+0.3333333333347203 0.5 0
+1 12 0 2
+18
+19
+-0.3333333333325025 0.5 0
+-0.6666666666657889 0.5 0
+1 31 0 2
+20
+21
+-0.6666666666675911 0 0
+-0.3333333333347203 0 0
+1 32 0 2
+22
+23
+0.3333333333325025 0 0
+0.6666666666657889 0 0
+1 61 0 2
+24
+25
+-0.6666666666675911 -0.5 0
+-0.3333333333347203 -0.5 0
+1 62 0 2
+26
+27
+0.3333333333325025 -0.5 0
+0.6666666666657889 -0.5 0
+2 1 0 3
+28
+29
+30
+-0.5000000000003003 0.2499999999997421 0
+-0.2500000000005764 0.263888888887807 0
+-0.7500000000006232 0.2361111111106458 0
+2 2 0 3
+31
+32
+33
+-0.5000000000011557 -0.25 0
+-0.2500000000005597 -0.2638888888885687 0
+-0.7500000000005961 -0.2638888888893391 0
 $EndNodes
 $Elements
-22
-1 1 4 2 1 1 1 1 7
-2 1 4 2 1 1 1 7 2
-3 1 2 3 3 5 8
-4 1 2 3 3 8 6
-5 1 4 1 6 1 3 3 9
-6 1 4 1 6 1 3 9 4
-7 2 5 4 1 2 1 -2 11 7 10
-8 2 5 4 1 2 2 -1 8 11 10
-9 2 5 4 1 2 1 -2 2 10 7
-10 2 6 4 1 3 2 -1 -3 6 11 8
-11 2 6 4 1 3 1 -2 -3 1 11 6
-12 2 6 4 1 3 1 -2 -3 2 5 10
-13 2 6 4 1 3 2 -1 -3 5 8 10
-14 2 5 4 1 2 1 -2 1 7 11
-15 2 5 4 2 2 2 -3 12 8 13
-16 2 5 4 2 2 3 -2 9 12 13
-17 2 5 4 2 2 3 -2 4 12 9
-18 2 6 4 2 3 2 -1 -3 6 8 12
-19 2 6 4 2 3 3 -1 -2 3 13 5
-20 2 6 4 2 3 3 -1 -2 4 6 12
-21 2 5 4 2 2 3 -2 3 9 13
-22 2 6 4 2 3 2 -1 -3 5 13 8
+14 58 1 58
+1 2 1 2
+1 2 10 
+2 10 5 
+1 4 1 2
+3 6 11 
+4 11 1 
+1 5 1 2
+5 5 12 
+6 12 3 
+1 7 1 2
+7 4 13 
+8 13 6 
+1 8 1 2
+9 7 14 
+10 14 8 
+1 9 1 2
+11 7 15 
+12 15 9 
+1 11 1 3
+13 1 16 
+14 16 17 
+15 17 8 
+1 12 1 3
+16 8 18 
+17 18 19 
+18 19 2 
+1 31 1 3
+19 5 20 
+20 20 21 
+21 21 7 
+1 32 1 3
+22 7 22 
+23 22 23 
+24 23 6 
+1 61 1 3
+25 3 24 
+26 24 25 
+27 25 9 
+1 62 1 3
+28 9 26 
+29 26 27 
+30 27 4 
+2 1 2 14
+31 2 10 30 
+32 7 14 29 
+33 19 2 30 
+34 21 7 29 
+35 14 8 29 
+36 10 5 30 
+37 8 18 29 
+38 5 20 30 
+39 18 19 28 
+40 20 21 28 
+41 28 19 30 
+42 28 21 29 
+43 18 28 29 
+44 20 28 30 
+2 2 2 14
+45 7 32 15 
+46 12 33 5 
+47 21 32 7 
+48 5 33 20 
+49 15 32 9 
+50 3 33 12 
+51 9 32 25 
+52 24 33 3 
+53 25 31 24 
+54 20 31 21 
+55 31 32 21 
+56 20 33 31 
+57 25 32 31 
+58 31 33 24 
 $EndElements
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo
index 5d78488e4400f78609adfa30e4a2b6b317d51721..4d3fec0ea0707460156ebf9b21b9100886c7e049 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo
@@ -1,4 +1,4 @@
-h = 0.5;
+h = 0.4;
 
 y = 1;
 x = 2;
@@ -10,27 +10,43 @@ Point(4) = { x/2.,-y/2, 0, h};
 Point(5) = {-x/2.,   0, 0, h};
 Point(6) = { x/2.,   0, 0, h};
 
-Line(1) = {1, 2};
+Point(7) = {    0,   0, 0, h};
+Point(8) = {    0, y/2, 0, h};
+Point(9) = {    0,-y/2, 0, h};
+
+
+Line(11) = {1, 8};
+Line(12) = {8, 2};
 Line(2) = {2, 5};
-Line(3) = {5, 6};
+Line(31) = {5, 7};
+Line(32) = {7, 6};
 Line(4) = {6, 1};
 
 Line(5) = {5, 3};
-Line(6) = {3, 4};
+Line(61) = {3, 9};
+Line(62) = {9, 4};
 Line(7) = {4, 6};
 
-Line Loop(1) = {1, 2, 3, 4};
-Line Loop(2) = {-3, 5, 6, 7};
-Plane Surface(1) = {1};
-Plane Surface(2) = {2};
-
-Physical Line("fixed") = {6};
-Physical Line("loading") = {1};
-Physical Line("insertion") = {3};
+Line(8) = {7, 8};
+Line(9) = {7, 9};
+
+Line Loop(11) = {11, -8, 32, 4};
+Line Loop(12) = {12, 2, 31, 8};
+Line Loop(21) = {-32, 9, 62, 7};
+Line Loop(22) = {-31, 5, 61, -9};
+Plane Surface(11) = {11};
+Plane Surface(12) = {12};
+Plane Surface(21) = {21};
+Plane Surface(22) = {22};
+
+Physical Line("fixed") = {61, 62};
+Physical Line("loading") = {11, 12};
+Physical Line("insertion") = {31, 32};
 Physical Line("sides") = {2, 5, 7, 4};
+Physical Line("middle") = {8, 9};
 
-Physical Surface("body") = {1, 2};
+Physical Surface("body") = {11, 12, 21, 22};
 
-Recombine Surface {2};
-Transfinite Surface {2};
+Recombine Surface {21, 22};
+Transfinite Surface {21, 22};
 Mesh.SecondOrderIncomplete = 1;
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo
index 07eadacae310dd5f164b6aed0ab4104f2c6e241f..2fbd9855413fb4dba06a69797ca96760537709c1 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo
@@ -1,4 +1,4 @@
-h = 0.2;
+h = 0.4;
 
 y = 1;
 x = 2;
@@ -10,26 +10,42 @@ Point(4) = { x/2.,-y/2, 0, h};
 Point(5) = {-x/2.,   0, 0, h};
 Point(6) = { x/2.,   0, 0, h};
 
-Line(1) = {1, 2};
+Point(7) = {    0,   0, 0, h};
+Point(8) = {    0, y/2, 0, h};
+Point(9) = {    0,-y/2, 0, h};
+
+
+Line(11) = {1, 8};
+Line(12) = {8, 2};
 Line(2) = {2, 5};
-Line(3) = {5, 6};
+Line(31) = {5, 7};
+Line(32) = {7, 6};
 Line(4) = {6, 1};
 
 Line(5) = {5, 3};
-Line(6) = {3, 4};
+Line(61) = {3, 9};
+Line(62) = {9, 4};
 Line(7) = {4, 6};
 
-Line Loop(1) = {1, 2, 3, 4};
-Line Loop(2) = {-3, 5, 6, 7};
-Plane Surface(1) = {1};
-Plane Surface(2) = {2};
-
-Physical Line("fixed") = {6};
-Physical Line("loading") = {1};
-Physical Line("insertion") = {3};
+Line(8) = {7, 8};
+Line(9) = {7, 9};
+
+Line Loop(11) = {11, -8, 32, 4};
+Line Loop(12) = {12, 2, 31, 8};
+Line Loop(21) = {-32, 9, 62, 7};
+Line Loop(22) = {-31, 5, 61, -9};
+Plane Surface(11) = {11};
+Plane Surface(12) = {12};
+Plane Surface(21) = {21};
+Plane Surface(22) = {22};
+
+Physical Line("fixed") = {61, 62};
+Physical Line("loading") = {11, 12};
+Physical Line("insertion") = {31, 32};
 Physical Line("sides") = {2, 5, 7, 4};
+Physical Line("middle") = {8, 9};
 
-Physical Surface("body") = {1, 2};
+Physical Surface("body") = {11, 12, 21, 22};
 
 Recombine Surface "*";
 Transfinite Surface "*";
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo
index 3242a10d2e9e2dbc5a86a1e41bee981edef703e4..1831c5086e40528bcbb85f155376cd3b0eac0615 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo
@@ -1,4 +1,4 @@
-h = 0.7;
+h = 0.4;
 
 z = 1;
 y = 2;
@@ -12,26 +12,43 @@ Point(4) = { x/2,-y/2, -z/2, h};
 Point(5) = {-x/2, 0,  -z/2, h};
 Point(6) = { x/2, 0,  -z/2, h};
 
-Line(1) = {1, 2};
-Line(2) = {2, 5};
-Line(3) = {5, 6};
-Line(4) = {6, 1};
+Point(7) = {    0,   0, -z/2, h};
+Point(8) = {    0, y/2, -z/2, h};
+Point(9) = {    0,-y/2, -z/2, h};
 
-Line(5) = {5, 3};
-Line(6) = {3, 4};
-Line(7) = {4, 6};
 
-Line Loop(1) = {1, 2, 3, 4};
-Line Loop(2) = {-3, 5, 6, 7};
-Plane Surface(1) = {1};
-Plane Surface(2) = {2};
+Line(11) = {1, 8};
+Line(12) = {8, 2};
+Line(2)  = {2, 5};
+Line(31) = {5, 7};
+Line(32) = {7, 6};
+Line(4)  = {6, 1};
+
+Line(5)  = {5, 3};
+Line(61) = {3, 9};
+Line(62) = {9, 4};
+Line(7)  = {4, 6};
+
+Line(8) = {7, 8};
+Line(9) = {7, 9};
+
+Line Loop(11) = {11, -8, 32, 4};
+Line Loop(12) = {12, 2, 31, 8};
+Line Loop(21) = {-32, 9, 62, 7};
+Line Loop(22) = {-31, 5, 61, -9};
+Plane Surface(11) = {11};
+Plane Surface(12) = {12};
+Plane Surface(21) = {21};
+Plane Surface(22) = {22};
+
 Extrude {0, 0, z} {
-  Surface{1}; Surface{2};
+  Surface{11}; Surface{12}; Surface{21}; Surface{22};
 }
 
-Physical Surface("fixed") = {46};
-Physical Surface("insertion") = {24};
-Physical Surface("loading") = {16};
-Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42};
+Physical Surface("fixed") = {145, 123};
+Physical Surface("loading") = {93, 71};
+Physical Surface("insertion") = {101, 79};
+Physical Surface("sides") = {97, 141, 83, 127};
+Physical Surface("middle") = {75, 119};
 
-Physical Volume("body") = {1, 2};
+Physical Volume("body") = {1, 2, 3, 4};
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo
index c54ed87057536e0dd07ae5439520908a191ef64e..a3224b5e6c98b6d0de84a91f61ec39d54be8cccf 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo
@@ -1,36 +1,57 @@
-h = 0.5;
-
-Point(1) = { 1, 1, -.5, h};
-Point(2) = {-1, 1, -.5, h};
-Point(3) = {-1,-1, -.5, h};
-Point(4) = { 1,-1, -.5, h};
-
-Point(5) = {-1, 0, -.5, h};
-Point(6) = { 1, 0, -.5, h};
-
-Line(1) = {1, 2};
-Line(2) = {2, 5};
-Line(3) = {5, 6};
-Line(4) = {6, 1};
-
-Line(5) = {5, 3};
-Line(6) = {3, 4};
-Line(7) = {4, 6};
-
-Line Loop(1) = {1, 2, 3, 4};
-Line Loop(2) = {-3, 5, 6, 7};
-Plane Surface(1) = {1};
-Plane Surface(2) = {2};
-Extrude {0, 0, 1} {
-  Surface{1}; Surface{2};
+h = 0.4;
+
+z = 1;
+y = 2;
+x = 2;
+
+Point(1) = { x/2, y/2, -z/2, h};
+Point(2) = {-x/2, y/2, -z/2, h};
+Point(3) = {-x/2,-y/2, -z/2, h};
+Point(4) = { x/2,-y/2, -z/2, h};
+
+Point(5) = {-x/2, 0,  -z/2, h};
+Point(6) = { x/2, 0,  -z/2, h};
+
+Point(7) = {    0,   0, -z/2, h};
+Point(8) = {    0, y/2, -z/2, h};
+Point(9) = {    0,-y/2, -z/2, h};
+
+
+Line(11) = {1, 8};
+Line(12) = {8, 2};
+Line(2)  = {2, 5};
+Line(31) = {5, 7};
+Line(32) = {7, 6};
+Line(4)  = {6, 1};
+
+Line(5)  = {5, 3};
+Line(61) = {3, 9};
+Line(62) = {9, 4};
+Line(7)  = {4, 6};
+
+Line(8) = {7, 8};
+Line(9) = {7, 9};
+
+Line Loop(11) = {11, -8, 32, 4};
+Line Loop(12) = {12, 2, 31, 8};
+Line Loop(21) = {-32, 9, 62, 7};
+Line Loop(22) = {-31, 5, 61, -9};
+Plane Surface(11) = {11};
+Plane Surface(12) = {12};
+Plane Surface(21) = {21};
+Plane Surface(22) = {22};
+
+Extrude {0, 0, z} {
+  Surface{11}; Surface{12}; Surface{21}; Surface{22};
 }
 
-Physical Surface("fixed") = {46};
-Physical Surface("insertion") = {24};
-Physical Surface("loading") = {16};
-Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42};
+Physical Line("fixed") = {145, 123};
+Physical Line("loading") = {93, 71};
+Physical Line("insertion") = {101, 79};
+Physical Line("sides") = {97, 141, 83, 127};
+Physical Line("middle") = {75, 119};
 
-Physical Volume("body") = {1, 2};
+Physical Surface("body") = {1, 2, 3, 4};
 
 Transfinite Surface "*";
 Transfinite Volume "*";
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc
index aa532806ccc2d0e296aee73bcd9fa87702770b1c..bf75e5c6c77e765d133db2a7a16e3bd704e9fac1 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc
@@ -121,3 +121,23 @@ TYPED_TEST(TestSMMCFixture, IntrinsicModeII) {
   // if (this->dim != 3)
   this->checkDissipated(G_c);
 }
+
+TYPED_TEST(TestSMMCFixture, IntrinsicImplicitModeI) {
+  if (this->mesh->getCommunicator().getNbProc() > 1 and this->dim == 1) {
+    SUCCEED();
+    return;
+  }
+  getStaticParser().parse("material_1.dat");
+  this->is_extrinsic = false;
+  this->analysis_method = _implicit_dynamic;
+
+  this->testModeI();
+
+  this->checkInsertion();
+
+  auto & mat_co = this->model->getMaterial("insertion");
+  Real G_c = mat_co.get("G_c");
+
+  // if (this->dim != 3)
+  this->checkDissipated(G_c);
+}
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh
index 199a2cc28d9d171e1d91441592b2d0625af25fc9..6dfc991774b8e5ce2a7cdf9cce65de729c233921 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh
@@ -19,7 +19,7 @@
  */
 
 /* -------------------------------------------------------------------------- */
-#include "communicator.hh"
+#include "non_linear_solver.hh"
 #include "solid_mechanics_model_cohesive.hh"
 #include "test_gtest_utils.hh"
 /* -------------------------------------------------------------------------- */
@@ -86,6 +86,13 @@ public:
     model->initFull(_analysis_method = this->analysis_method,
                     _is_extrinsic = this->is_extrinsic);
 
+    if (this->analysis_method == _implicit_dynamic) {
+      auto & solver = model->getNonLinearSolver();
+      solver.set("max_iterations", 100);
+      solver.set("threshold", 1e-7);
+      solver.set("convergence_type", SolveConvergenceCriteria::_residual);
+    }
+
     auto time_step = this->model->getStableTimeStep() * 0.01;
     this->model->setTimeStep(time_step);
 
@@ -109,7 +116,7 @@ public:
 
     mesh->getCommunicator().allReduce(group_size, SynchronizerOperation::_sum);
 
-#define debug_ 0
+#define debug_ 1
 
 #if debug_
     auto size = mesh->getCommunicator().getNbProc();
@@ -137,11 +144,9 @@ public:
   }
 
   void setInitialCondition(const Matrix<Real> & strain) {
-    for (auto && data :
+    for (auto && [pos, disp] :
          zip(make_view(this->mesh->getNodes(), this->dim),
              make_view(this->model->getDisplacement(), this->dim))) {
-      const auto & pos = std::get<0>(data);
-      auto & disp = std::get<1>(data);
       disp = strain * pos;
     }
   }
@@ -165,16 +170,20 @@ public:
     for (auto _ [[gnu::unused]] : arange(nb_steps)) {
       this->model->applyBC(functor, "loading");
       this->model->applyBC(functor, "fixed");
+#if debug_
+      this->model->dump();
+      this->model->dump("cohesive elements");
+#endif
       if (this->is_extrinsic) {
         this->model->checkCohesiveStress();
       }
 
       this->model->solveStep();
+    }
 #if debug_
-      this->model->dump();
-      this->model->dump("cohesive elements");
+    this->model->dump();
+    this->model->dump("cohesive elements");
 #endif
-    }
   }
 
   void checkInsertion() {
@@ -201,10 +210,18 @@ public:
     if (dim == 1) {
       direction = _x;
     }
+
     auto length =
         mesh->getUpperBounds()(direction) - mesh->getLowerBounds()(direction);
     nb_steps = length / speed / model->getTimeStep();
 
+    if (this->dim > 1) {
+      this->model->applyBC(BC::Dirichlet::FlagOnly(_x), "middle");
+    }
+    if (this->dim > 2) {
+      this->model->applyBC(BC::Dirichlet::FlagOnly(_z), "middle");
+    }
+
     SCOPED_TRACE(std::to_string(this->dim) + "D - " + std::to_string(type_1) +
                  ":" + std::to_string(type_2));
 
@@ -227,6 +244,12 @@ public:
     strain *= sigma_c / E;
 
     this->setInitialCondition((1 - 1e-5) * strain);
+
+#if debug_
+    this->model->dump();
+    this->model->dump("cohesive elements");
+#endif
+
     this->steps(2e-2 * strain);
   }
 
@@ -251,10 +274,12 @@ public:
     SCOPED_TRACE(std::to_string(this->dim) + "D - " + std::to_string(type_1) +
                  ":" + std::to_string(type_2));
 
-    if (this->dim > 1)
+    if (this->dim > 1) {
       this->model->applyBC(BC::Dirichlet::FlagOnly(_y), "sides");
-    if (this->dim > 2)
+    }
+    if (this->dim > 2) {
       this->model->applyBC(BC::Dirichlet::FlagOnly(_z), "sides");
+    }
 
     auto & mat_co = this->model->getMaterial("insertion");
     Real sigma_c = mat_co.get("sigma_c");
@@ -279,6 +304,12 @@ public:
     // nb_steps *= 5;
 
     this->setInitialCondition((1. - 1e-5) * strain);
+
+#if debug_
+    this->model->dump();
+    this->model->dump("cohesive elements");
+#endif
+
     this->steps(0.005 * strain);
   }
 
diff --git a/test/test_solver/test_sparse_matrix_assemble.cc b/test/test_solver/test_sparse_matrix_assemble.cc
index 0ed5de244b6b734bddd30db5ef2c37b093e68eff..a9582d324d6ce55e8d0dd498747faab30439cded 100644
--- a/test/test_solver/test_sparse_matrix_assemble.cc
+++ b/test/test_solver/test_sparse_matrix_assemble.cc
@@ -38,35 +38,15 @@ int main(int argc, char * argv[]) {
   Mesh mesh(spatial_dimension);
   mesh.read("triangle.msh");
 
-  UInt nb_nodes = mesh.getNbNodes();
+  auto nb_nodes = mesh.getNbNodes();
 
-  DOFManagerDefault dof_manager(mesh, "test_dof_manager");
+  DOFManagerDefault dof_manager("test_dof_manager");
 
   Array<Real> test_synchronize(nb_nodes, spatial_dimension, "Test vector");
-  dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal);
+  dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh);
 
   auto & A = dof_manager.getNewMatrix("A", _symmetric);
 
-  // const akantu::Mesh::ConnectivityTypeList & type_list =
-  // mesh.getConnectivityTypeList();
-  // akantu::Mesh::ConnectivityTypeList::const_iterator it;
-
-  // for(it = type_list.begin(); it != type_list.end(); ++it) {
-  //   if(mesh.getSpatialDimension(*it) != spatial_dimension) continue;
-  //   akantu::UInt nb_element           = mesh.getNbElement(*it);
-  //   akantu::UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it);
-  //   akantu::Element element(*it);
-
-  //   akantu::UInt m = nb_nodes_per_element * spatial_dimension;
-  //   akantu::Array<akantu::Real> local_mat(m, m, 1, "local_mat");
-
-  //   for(akantu::UInt e = 0; e < nb_element; ++e) {
-  //     element.element = e;
-  //     sparse_matrix.addToMatrix(local_mat.data(), element,
-  //     nb_nodes_per_element);
-  //   }
-  // }
-
   A.saveMatrix("matrix.mtx");
 
   finalize();
diff --git a/test/test_solver/test_sparse_matrix_product.cc b/test/test_solver/test_sparse_matrix_product.cc
index 4c2f53fa6e2e5aacef0321382f94568f146eea8b..5c03ba24110dce81023159d0aa07721fb42d4eeb 100644
--- a/test/test_solver/test_sparse_matrix_product.cc
+++ b/test/test_solver/test_sparse_matrix_product.cc
@@ -46,10 +46,10 @@ int main(int argc, char * argv[]) {
   mesh.distribute();
 
   Int nb_nodes = mesh.getNbNodes();
-  DOFManagerDefault dof_manager(mesh, "test_dof_manager");
+  DOFManagerDefault dof_manager("test_dof_manager");
 
   Array<Real> test_synchronize(nb_nodes, nb_dof, "Test vector");
-  dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal);
+  dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh);
 
   if (prank == 0)
     std::cout << "Creating a SparseMatrix" << std::endl;
diff --git a/test/test_solver/test_sparse_matrix_profile.cc b/test/test_solver/test_sparse_matrix_profile.cc
index 4d45b25ddb653d89d5d2805c34b37deeb20bbad8..4d69e35447a7087d42230b1d63c0fab5799bcd27 100644
--- a/test/test_solver/test_sparse_matrix_profile.cc
+++ b/test/test_solver/test_sparse_matrix_profile.cc
@@ -38,9 +38,9 @@ int main(int argc, char * argv[]) {
 
   Int nb_nodes = mesh.getNbNodes();
 
-  DOFManagerDefault dof_manager(mesh, "test_dof_manager");
+  DOFManagerDefault dof_manager("test_dof_manager");
   Array<Real> test_synchronize(nb_nodes, spatial_dimension, "Test vector");
-  dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal);
+  dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh);
 
   auto & A = dof_manager.getNewMatrix("A", _symmetric);
 
diff --git a/test/test_solver/test_sparse_solver_mumps.cc b/test/test_solver/test_sparse_solver_mumps.cc
index b4ef93d8e0b0b6cd2cecb6898c274060e763372a..d45b443b8ce0cfd400e1e8c9527e59056f17c3ca 100644
--- a/test/test_solver/test_sparse_solver_mumps.cc
+++ b/test/test_solver/test_sparse_solver_mumps.cc
@@ -66,10 +66,10 @@ int main(int argc, char * argv[]) {
   }
   Int nb_nodes = mesh.getNbNodes();
 
-  DOFManagerDefault dof_manager(mesh, "test_dof_manager");
+  DOFManagerDefault dof_manager("test_dof_manager");
 
   Array<Real> x(nb_nodes);
-  dof_manager.registerDOFs("x", x, _dst_nodal);
+  dof_manager.registerDOFs("x", x, mesh);
 
   const auto & local_equation_number =
       dof_manager.getLocalEquationsNumbers("x");
diff --git a/test/test_synchronizer/test_dof_synchronizer.cc b/test/test_synchronizer/test_dof_synchronizer.cc
index 896f1c1bb7d0e6a64d0f4d7ad7156c97410eb122..c30b9bb7fd1ff549decfb89964c7f2e33d9d0bbd 100644
--- a/test/test_synchronizer/test_dof_synchronizer.cc
+++ b/test/test_synchronizer/test_dof_synchronizer.cc
@@ -45,7 +45,7 @@ int main(int argc, char * argv[]) {
     mesh.read("bar.msh");
   mesh.distribute();
 
-  DOFManagerDefault dof_manager(mesh, "test_dof_manager");
+  DOFManagerDefault dof_manager("test_dof_manager");
 
   UInt nb_nodes = mesh.getNbNodes();
 
@@ -53,7 +53,7 @@ int main(int argc, char * argv[]) {
   /* test the synchronization                                                 */
   /* ------------------------------------------------------------------------ */
   Array<Real> test_synchronize(nb_nodes, spatial_dimension, "Test vector");
-  dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal);
+  dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh);
 
   const auto & equation_number =
       dof_manager.getLocalEquationsNumbers("test_synchronize");