diff --git a/.gitignore b/.gitignore
index a3fea6cfd..be850e87b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,17 @@
 build*
 .dir-locals.el
 TAGS
 third-party/blackdynamite/
 third-party/pybind11
 third-party/google-test
 third-party/cpp-array/
 *~
 release
 .*.swp
 *.tar.gz
 *.tgz
 *.tbz
 *.tar.bz2
 .idea
-__pycache__
\ No newline at end of file
+__pycache__
+.mailmap
diff --git a/cmake/AkantuTestsMacros.cmake b/cmake/AkantuTestsMacros.cmake
index 5bb3036fd..98d765e38 100644
--- a/cmake/AkantuTestsMacros.cmake
+++ b/cmake/AkantuTestsMacros.cmake
@@ -1,624 +1,624 @@
 #===============================================================================
 # @file   AkantuTestsMacros.cmake
 #
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Fri Sep 03 2010
 # @date last modification: Fri Jan 22 2016
 #
 # @brief  macros for tests
 #
 # @section LICENSE
 #
 # Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
 # Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
 # Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 #===============================================================================
 
 #[=======================================================================[.rst:
 AkantuTestsMacros
 -----------------
 
 This modules provides the functions to helper to declare tests and folders
 containing tests in akantu
 
 .. command:: add_test_tree
 
 add_test_tree(<test_direcotry>)
 
 ``<test_directory>`` is the entry direcroty of the full structure of
 subfolders containing tests
 
 .. command:: add_akantu_test
 
 add_akantu_test(<dir> <desc>)
 
 This function add a subdirectory ``<dir>`` of tests that will be conditionnaly
 activable and will be visible only if the parent folder as been activated An
 option ``AKANTU_BUILD_TEST_<dir>`` will appear in ccmake with the description
 ``<desc>``. The compilation of all tests can be forced with the option
 ``AKANTU_BUILD_ALL_TESTS``
 
 .. command:: register_test
 
 register_test(<test_name>
   SOURCES <sources>...
   PACKAGE <akantu_packages>...
   SCRIPT <scirpt>
   [FILES_TO_COPY <filenames>...]
   [DEPENDS <targets>...]
   [DIRECTORIES_TO_CREATE <directories>...]
   [COMPILE_OPTIONS <flags>...]
   [EXTRA_FILES <filnames>...]
   [LINK_LIBRARIES <libraries>...]
   [INCLUDE_DIRECTORIES <include>...]
   [UNSABLE]
   [PARALLEL]
   [PARALLEL_LEVEL <procs>...]
   )
 
 This function defines a test ``<test_name>_run`` this test could be of
 different nature depending on the context. If Just sources are provided the
 test consist of running the executable generated. If a file ``<test_name>.sh``
 is present the test will execute the script. And if a ``<test_name>.verified``
 exists the output of the test will be compared to this reference file
 
 The options are:
 
 ``SOURCES <sources>...``
 The list of source files to compile to generate the executable of the test
 
 ``PACKAGE <akantu_packages>...``
 The list of package to which this test belongs. The test will be activable
 only of all the packages listed are activated
 
 ``SCRIPT <script>``
 The script to execute instead of the executable
 
 ``FILES_TO_COPY <filenames>...``
 List of files to copy from the source directory to the build directory
 
 ``DEPENDS <targets>...``
 List of targets the test depends on, for example if a mesh as to be generated
 
 ``DIRECTORIES_TO_CREATE <directories>...``
 Obsolete. This specifies a list of directories that have to be created in
 the build folder
 
 ``COMPILE_OPTIONS <flags>...``
 List of extra compilations options to pass to the compiler
 
 ``EXTRA_FILES <filnames>...``
 Files to consider when generating a package_source
 
 ``UNSABLE``
 If this option is specified the test can be unacitivated by the glocal option
 ``AKANTU_BUILD_UNSTABLE_TESTS``, this is mainly intendeed to remove test
 under developement from the continious integration
 
 ``PARALLEL``
 This specifies that this test should be run in parallel. It will generate a
 series of test for different number of processors. This automaticaly adds a
 dependency to the package ``AKANTU_PARALLEL``
 
 ``PARALLEL_LEVEL``
 This defines the different processor numbers to use, if not defined the
 macro tries to determine it in a "clever" way
 
 ]=======================================================================]
 
 set(AKANTU_DRIVER_SCRIPT ${AKANTU_CMAKE_DIR}/akantu_test_driver.sh)
 
 # ==============================================================================
 macro(add_test_tree dir)
   if(AKANTU_TESTS)
     enable_testing()
     include(CTest)
     mark_as_advanced(BUILD_TESTING)
 
     set(_akantu_current_parent_test ${dir} CACHE INTERNAL "Current test folder" FORCE)
     set(_akantu_${dir}_tests_count 0 CACHE INTERNAL "" FORCE)
 
     string(TOUPPER ${dir} _u_dir)
     set(AKANTU_BUILD_${_u_dir} ON CACHE INTERNAL "${desc}" FORCE)
 
     package_get_all_test_folders(_test_dirs)
 
     foreach(_dir ${_test_dirs})
       add_subdirectory(${_dir})
     endforeach()
   endif()
 endmacro()
 
 
 set(_test_flags
   UNSTABLE
   PARALLEL
   PYTHON
   HEADER_ONLY
   )
 
 set(_test_one_variables
   POSTPROCESS
   SCRIPT
   )
 
 set(_test_multi_variables
   SOURCES
   FILES_TO_COPY
   DEPENDS
   DIRECTORIES_TO_CREATE
   COMPILE_OPTIONS
   EXTRA_FILES
   LINK_LIBRARIES
   INCLUDE_DIRECTORIES
   PACKAGE
   PARALLEL_LEVEL
   )
 
 
 # ==============================================================================
 function(add_akantu_test dir desc)
   if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dir})
     return()
   endif()
 
   set(_my_parent_dir ${_akantu_current_parent_test})
 
   # initialize variables
   set(_akantu_current_parent_test ${dir} CACHE INTERNAL "Current test folder" FORCE)
   set(_akantu_${dir}_tests_count 0 CACHE INTERNAL "" FORCE)
 
   # set the option for this directory
   string(TOUPPER ${dir} _u_dir)
   option(AKANTU_BUILD_${_u_dir} "${desc}")
   mark_as_advanced(AKANTU_BUILD_${_u_dir})
 
   # add the sub-directory
   add_subdirectory(${dir})
 
   # if no test can be activated make the option disappear
   set(_force_deactivate_count FALSE)
   if(${_akantu_${dir}_tests_count} EQUAL 0)
     set(_force_deactivate_count TRUE)
   endif()
 
   # if parent off make the option disappear
   set(_force_deactivate_parent FALSE)
   string(TOUPPER ${_my_parent_dir} _u_parent_dir)
   if(NOT AKANTU_BUILD_${_u_parent_dir})
     set(_force_deactivate_parent TRUE)
   endif()
 
   if(_force_deactivate_parent OR _force_deactivate_count OR AKANTU_BUILD_ALL_TESTS)
     if(NOT DEFINED _AKANTU_BUILD_${_u_dir}_SAVE)
       set(_AKANTU_BUILD_${_u_dir}_SAVE ${AKANTU_BUILD_${_u_dir}} CACHE INTERNAL "" FORCE)
     endif()
     unset(AKANTU_BUILD_${_u_dir} CACHE)
     if(AKANTU_BUILD_ALL_TESTS AND NOT _force_deactivate_count)
       set(AKANTU_BUILD_${_u_dir} ON CACHE INTERNAL "${desc}" FORCE)
     else()
       set(AKANTU_BUILD_${_u_dir} OFF CACHE INTERNAL "${desc}" FORCE)
     endif()
   else()
     if(DEFINED _AKANTU_BUILD_${_u_dir}_SAVE)
       unset(AKANTU_BUILD_${_u_dir} CACHE)
       set(AKANTU_BUILD_${_u_dir} ${_AKANTU_BUILD_${_u_dir}_SAVE} CACHE BOOL "${desc}")
       unset(_AKANTU_BUILD_${_u_dir}_SAVE CACHE)
     endif()
   endif()
 
   # adding up to the parent count
   math(EXPR _tmp_parent_count "${_akantu_${dir}_tests_count} + ${_akantu_${_my_parent_dir}_tests_count}")
   set(_akantu_${_my_parent_dir}_tests_count ${_tmp_parent_count} CACHE INTERNAL "" FORCE)
 
   # restoring the parent current dir
   set(_akantu_current_parent_test ${_my_parent_dir} CACHE INTERNAL "Current test folder" FORCE)
 endfunction()
 
 function(is_test_active is_active)
   cmake_parse_arguments(_register_test
     "${_test_flags}"
     "${_test_one_variables}"
     "${_test_multi_variables}"
     ${ARGN}
     )
 
   if(NOT _register_test_PACKAGE)
     message(FATAL_ERROR "No reference package was defined for the test"
       " ${test_name} in folder ${CMAKE_CURRENT_SOURCE_DIR}")
   endif()
 
   set(_test_act TRUE)
   # Activate the test anly if all packages associated to the test are activated
   foreach(_package ${_register_test_PACKAGE})
     package_is_activated(${_package} _act)
     if(NOT _act)
       set(_test_act FALSE)
     endif()
   endforeach()
 
   # check if the test is marked unstable and if the unstable test should be run
   if(_register_test_UNSTABLE AND NOT AKANTU_BUILD_UNSTABLE_TESTS)
     set(_test_act FALSE)
   endif()
 
   if(_test_act)
     # todo this should be checked for the build package_sources since the file will not be listed.
     math(EXPR _tmp_parent_count "${_akantu_${_akantu_current_parent_test}_tests_count} + 1")
     set(_akantu_${_akantu_current_parent_test}_tests_count ${_tmp_parent_count} CACHE INTERNAL "" FORCE)
   endif()
 
   string(TOUPPER ${_akantu_current_parent_test} _u_parent)
   if(NOT (AKANTU_BUILD_${_u_parent} OR AKANTU_BUILD_ALL_TESTS))
     set(_test_act FALSE)
   endif()
 
   set(${is_active} ${_test_act} PARENT_SCOPE)
 endfunction()
 
 # ------------------------------------------------------------------------------
 function(register_gtest_sources)
   cmake_parse_arguments(_register_test
     "${_test_flags}"
     "${_test_one_variables}"
     "${_test_multi_variables}"
     ${ARGN}
     )
 
   is_test_active(_is_active ${ARGN})
   register_test_files_to_package(${ARGN})
 
   if(NOT _is_active)
     return()
   endif()
 
   if(_register_test_PACKAGE)
     set(_list ${_gtest_PACKAGE})
     list(APPEND _list ${_register_test_PACKAGE})
     list(REMOVE_DUPLICATES _list)
     set(_gtest_PACKAGE ${_list} PARENT_SCOPE)
   endif()
 
   foreach (_var ${_test_flags})
     if(_var STREQUAL "HEADER_ONLY")
       if(NOT DEFINED_register_test_${_var})
         set(_gtest_${_var} OFF PARENT_SCOPE)
       elseif(NOT DEFINED _gtest_${_var})
         set(_gtest_${_var} ON PARENT_SCOPE)
       endif()
       continue()
     endif()
 
     if(_register_test_${_var})
       set(_gtest_${_var} ON PARENT_SCOPE)
     else()
       if(_gtest_${_var})
         message("Another gtest file required ${_var} to be ON it will be globally set for this folder...")
       endif()
     endif()
   endforeach()
 
   if(_register_test_UNPARSED_ARGUMENTS)
     list(APPEND _register_test_SOURCES ${_register_test_UNPARSED_ARGUMENTS})
   endif()
 
   foreach (_var ${_test_multi_variables})
     if(_register_test_${_var})
       set(_list ${_gtest_${_var}})
       list(APPEND _list ${_register_test_${_var}})
       list(REMOVE_DUPLICATES _list)
       set(_gtest_${_var} ${_list} PARENT_SCOPE)
     endif()
   endforeach()
 endfunction()
 
 # ==============================================================================
 function(akantu_pybind11_add_module target)
   package_is_activated(pybind11 _pybind11_act)
   if(_pybind11_act)
     package_get_all_external_informations(
       INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR
       )
 
     pybind11_add_module(${target} ${ARGN})
     target_include_directories(${target} SYSTEM PRIVATE ${PYBIND11_INCLUDE_DIR}
       ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR})
     set_property(TARGET ${target} PROPERTY DEBUG_POSTFIX "")
   endif()
 endfunction()
 
 # ==============================================================================
 function(register_gtest_test test_name)
   if(NOT _gtest_PACKAGE)
     return()
   endif()
 
   set(_argn ${test_name}_gtest)
 
   set(_link_libraries GTest::GTest GTest::Main)
 
   list(FIND _gtest_PACKAGE pybind11 _pos)
   package_is_activated(pybind11 _pybind11_act)
 
   if(_pybind11_act AND (NOT _pos EQUAL -1))
     list(APPEND _link_libraries pybind11::embed)
     set(_compile_flags COMPILE_OPTIONS "AKANTU_TEST_USE_PYBIND11")
   endif()
 
   is_test_active(_is_active ${ARGN} PACKAGE ${_gtest_PACKAGE})
   if(NOT _is_active)
     return()
   endif()
 
   register_gtest_sources(${ARGN}
     SOURCES ${PROJECT_SOURCE_DIR}/test/test_gtest_main.cc
     LINK_LIBRARIES ${_link_libraries}
     PACKAGE ${_gtest_PACKAGE}
     ${_compile_flags}
     )
 
   foreach (_var ${_test_flags})
     if(_gtest_${_var})
       list(APPEND _argn ${_var})
       unset(_gtest_${_var})
     endif()
   endforeach()
 
   foreach (_var ${_test_multi_variables})
     if(_gtest_${_var})
       list(APPEND _argn ${_var} ${_gtest_${_var}})
       unset(_gtest_${_var})
     endif()
   endforeach()
 
   register_test(${_argn})
   target_include_directories(${test_name}_gtest PRIVATE ${PROJECT_SOURCE_DIR}/test)
 endfunction()
 
 # ==============================================================================
 function(register_test test_name)
   cmake_parse_arguments(_register_test
     "${_test_flags}"
     "${_test_one_variables}"
     "${_test_multi_variables}"
     ${ARGN}
     )
 
   register_test_files_to_package(${ARGN})
   is_test_active(_test_act ${ARGN})
   if(NOT _test_act)
     return()
   endif()
 
   set(_extra_args)
 
   # check that the sources are files that need to be compiled
   if(_register_test_SOURCES} OR _register_test_UNPARSED_ARGUMENTS)
     set(_need_to_compile TRUE)
   else()
     set(_need_to_compile FALSE)
   endif()
 
   set(_compile_source)
   foreach(_file ${_register_test_SOURCES} ${_register_test_UNPARSED_ARGUMENTS})
     if(_file MATCHES "\\.cc$" OR _file MATCHES "\\.hh$")
       list(APPEND _compile_source ${_file})
     endif()
   endforeach()
 
   if(_compile_source)
     # get the include directories for sources in activated directories
     package_get_all_include_directories(
       AKANTU_LIBRARY_INCLUDE_DIRS
       )
 
     # get the external packages compilation and linking informations
     package_get_all_external_informations(
       INTERFACE_INCLUDE AKANTU_EXTERNAL_INCLUDE_DIR
       )
 
     foreach(_pkg ${_register_test_PACKAGE})
       package_get_nature(${_pkg} _nature)
       if(_nature MATCHES "^external.*")
         package_get_include_dir(${_pkg} _incl)
         package_get_libraries(${_pkg} _libs)
 
         list(APPEND _register_test_INCLUDE_DIRECTORIES ${_incl})
         list(APPEND _register_test_LINK_LIBRARIES ${_libs})
       endif()
     endforeach()
 
     # Register the executable to compile
     add_executable(${test_name} ${_compile_source})
 
     # set the proper includes to build most of the tests
     target_include_directories(${test_name}
       PRIVATE ${AKANTU_LIBRARY_INCLUDE_DIRS}
               ${AKANTU_EXTERNAL_INCLUDE_DIR}
               ${PROJECT_BINARY_DIR}/src
               ${_register_test_INCLUDE_DIRECTORIES})
 
     if(NOT _register_test_HEADER_ONLY)
       target_link_libraries(${test_name} PRIVATE akantu ${_register_test_LINK_LIBRARIES})
     else()
       get_target_property(_features akantu INTERFACE_COMPILE_FEATURES)
       target_link_libraries(${test_name} ${_register_test_LINK_LIBRARIES})
       target_compile_features(${test_name} PRIVATE ${_features})
     endif()
 
     # add the extra compilation options
     if(_register_test_COMPILE_OPTIONS)
       set_target_properties(${test_name}
         PROPERTIES COMPILE_DEFINITIONS "${_register_test_COMPILE_OPTIONS}")
     endif()
 
     if(AKANTU_EXTRA_CXX_FLAGS)
       set_target_properties(${test_name}
         PROPERTIES COMPILE_FLAGS "${AKANTU_EXTRA_CXX_FLAGS}")
     endif()
   else()
     add_custom_target(${test_name} ALL)
     if(_register_test_UNPARSED_ARGUMENTS AND NOT _register_test_SCRIPT)
       set(_register_test_SCRIPT ${_register_test_UNPARSED_ARGUMENTS})
     endif()
   endif()
 
   if(_register_test_DEPENDS)
     add_dependencies(${test_name} ${_register_test_DEPENDS})
   endif()
 
   # copy the needed files to the build folder
   if(_register_test_FILES_TO_COPY)
     foreach(_file ${_register_test_FILES_TO_COPY})
       file(COPY "${_file}" DESTINATION .)
     endforeach()
   endif()
 
   # create the needed folders in the build folder
   if(_register_test_DIRECTORIES_TO_CREATE)
     foreach(_dir ${_register_test_DIRECTORIES_TO_CREATE})
       if(IS_ABSOLUTE ${dir})
         file(MAKE_DIRECTORY "${_dir}")
       else()
         file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_dir}")
       endif()
     endforeach()
   endif()
 
   # register the test for ctest
   set(_arguments -n "${test_name}")
   if(_register_test_SCRIPT)
     file(COPY ${_register_test_SCRIPT}
       FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
                        GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
       DESTINATION .
       )
  
     if(_register_test_PYTHON)
       if(NOT PYTHONINTERP_FOUND)
         find_package(PythonInterp ${AKANTU_PREFERRED_PYTHON_VERSION} REQUIRED)
       endif()
       list(APPEND _arguments -e "${PYTHON_EXECUTABLE}")
       list(APPEND _extra_args "${_register_test_SCRIPT}")
     else()
-      list(APPEND _arguments -e "${_register_test_SCRIPT}")
+      list(APPEND _arguments -e "./${_register_test_SCRIPT}")
     endif()
   elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.sh")
     file(COPY ${test_name}.sh DESTINATION .)
-    list(APPEND _arguments -e "${test_name}.sh")
+    list(APPEND _arguments -e "./${test_name}.sh")
   else()
-    list(APPEND _arguments -e "${test_name}")
+    list(APPEND _arguments -e "./${test_name}")
   endif()
 
   list(APPEND _arguments -E "${PROJECT_BINARY_DIR}/akantu_environement.sh")
 
   package_is_activated(parallel _is_parallel)
   if(_is_parallel AND AKANTU_TESTS_ALWAYS_USE_MPI AND NOT _register_test_PARALLEL)
     set(_register_test_PARALLEL TRUE)
     set(_register_test_PARALLEL_LEVEL 1)
   endif()
 
   if(_register_test_PARALLEL)
     list(APPEND _arguments -p "${MPIEXEC} ${MPIEXEC_PREFLAGS} ${MPIEXEC_NUMPROC_FLAG}")
     if(_register_test_PARALLEL_LEVEL)
       set(_procs "${_register_test_PARALLEL_LEVEL}")
     elseif(CMAKE_VERSION VERSION_GREATER "3.0")
       set(_procs)
       include(ProcessorCount)
       ProcessorCount(N)
       while(N GREATER 1)
         list(APPEND _procs ${N})
         math(EXPR N "${N} / 2")
       endwhile()
     endif()
 
     if(NOT _procs)
       set(_procs 2)
     endif()
   endif()
 
   if(_register_test_POSTPROCESS)
     list(APPEND _arguments -s "${_register_test_POSTPROCESS}")
     file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${_register_test_POSTPROCESS}
       FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
       DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
   endif()
 
   list(APPEND _arguments -w "${CMAKE_CURRENT_BINARY_DIR}")
 
   if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified")
     list(APPEND _arguments -r "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified")
   endif()
 
   string(REPLACE ";" " " _command "${_arguments}")
 
   # register them test
   if(_procs)
     foreach(p ${_procs})
       add_test(NAME ${test_name}_${p} COMMAND ${AKANTU_DRIVER_SCRIPT} ${_arguments} -N ${p} ${_extra_args})
     endforeach()
   else()
     add_test(NAME ${test_name} COMMAND ${AKANTU_DRIVER_SCRIPT} ${_arguments} ${_extra_args})
   endif()
 endfunction()
 
 
 function(register_test_files_to_package)
   set(_test_all_files)
   # add the source files in the list of all files
   foreach(_file ${_register_test_SOURCES} ${_register_test_UNPARSED_ARGUMENTS}
       ${_register_test_EXTRA_FILES} ${_register_test_SOURCES} ${_register_test_SCRIPT}
       ${_register_test_POSTPROCESS} ${_register_test_FILES_TO_COPY})
     if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_file} OR EXISTS ${_file})
       list(APPEND _test_all_files "${_file}")
     else()
       message("The file \"${_file}\" registred by the test \"${test_name}\" does not exists")
     endif()
   endforeach()
 
   # add the different dependencies files (meshes, local libraries, ...)
   foreach(_dep ${_register_test_DEPENDS})
     get_target_list_of_associated_files(${_dep} _dep_ressources)
     if(_dep_ressources)
       list(APPEND _test_all_files "${_dep_ressources}")
     endif()
   endforeach()
 
   # add extra files to the list of files referenced by a given test
   if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.sh")
     list(APPEND _test_all_files "${test_name}.sh")
   endif()
   if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.verified")
     list(APPEND _test_all_files "${test_name}.verified")
   endif()
   if(_register_test_SCRIPT)
     list(APPEND _test_all_files "${_register_test_SCRIPT}")
   endif()
 
   # clean the list of all files for this test and add them in the total list
   foreach(_file ${_test_all_files})
     get_filename_component(_full ${_file} ABSOLUTE)
     file(RELATIVE_PATH __file ${PROJECT_SOURCE_DIR} ${_full})
     list(APPEND _tmp "${__file}")
   endforeach()
 
   foreach(_pkg ${_register_test_PACKAGE})
     package_get_name(${_pkg} _pkg_name)
     _package_add_to_variable(TESTS_FILES ${_pkg_name} ${_tmp})
   endforeach()
 endfunction()
diff --git a/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake b/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake
index f7910d299..2d8c1a484 100644
--- a/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake
+++ b/cmake/Modules/CMakePackagesSystemGlobalFunctions.cmake
@@ -1,138 +1,132 @@
 #===============================================================================
 # @file   CMakePackagesSystemGlobalFunctions.cmake
 #
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Sat Jul 18 2015
 # @date last modification: Mon Jan 18 2016
 #
 # @brief  Set of macros used by the package system to set internal variables
 #
 # @section LICENSE
 #
 # Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
 # (LSMS - Laboratoire de Simulation en Mécanique des Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 #===============================================================================
 
 # ==============================================================================
 # Package system meta functions
 # ==============================================================================
 function(package_set_project_variable variable)
   string(TOUPPER ${PROJECT_NAME} _u_project)
   set(${_u_project}_${variable} "${ARGN}" CACHE INTERNAL "" FORCE)
 endfunction()
 
 function(package_get_project_variable variable value_out)
   string(TOUPPER ${PROJECT_NAME} _u_project)
   set(${value_out} ${${_u_project}_${variable}} PARENT_SCOPE)
 endfunction()
 
 function(package_add_to_project_variable variable)
   package_get_project_variable(${variable} _tmp_list)
   list(APPEND _tmp_list ${ARGN})
   if(_tmp_list)
     list(REMOVE_DUPLICATES _tmp_list)
   endif()
   package_set_project_variable(${variable} ${_tmp_list})
 endfunction()
 
 # ==============================================================================
 function(_package_set_variable variable pkg_name)
   set(${pkg_name}_${variable} ${ARGN} CACHE INTERNAL "" FORCE)
 endfunction()
 
 function(_package_get_variable variable pkg_name value)
   #unset(${value} PARENT_SCOPE)
   if(DEFINED ${pkg_name}_${variable})
     set(${value} ${${pkg_name}_${variable}} PARENT_SCOPE)
   elseif(DEFINED ARGN)
     set(${value} ${ARGN} PARENT_SCOPE)
   else()
     set(${value} PARENT_SCOPE)
   endif()
 endfunction()
 
 # ==============================================================================
 function(_package_variable_unset variable pkg_name)
   unset(${pkg_name}_${variable} CACHE)
 endfunction()
 
 # ==============================================================================
 function(_package_add_to_variable variable pkg_name)
   _package_get_variable(${variable} ${pkg_name} _tmp_list)
   list(APPEND _tmp_list ${ARGN})
   if(_tmp_list)
     list(REMOVE_DUPLICATES _tmp_list)
   endif()
   _package_set_variable(${variable} ${pkg_name} ${_tmp_list})
 endfunction()
 
 function(_package_remove_from_variable variable pkg_name value)
   _package_get_variable(${variable} ${pkg_name} _tmp_list)
   list(LENGTH _tmp_list _length)
   if(_length GREATER 0)
     list(REMOVE_ITEM _tmp_list ${value})
     _package_set_variable(${variable} ${pkg_name} ${_tmp_list})
   endif()
 endfunction()
 
 # ==============================================================================
 function(_package_get_variable_for_packages variable values)
   set(_list_values)
   foreach(_pkg_name ${ARGN})
     _package_get_variable(${variable} ${_pkg_name} _value)
     list(APPEND _list_values ${_value})
   endforeach()
 
   if (_list_values)
     list(REMOVE_DUPLICATES _list_values)
   endif()
 
   set(${values} ${_list_values} PARENT_SCOPE)
 endfunction()
 
 # ==============================================================================
 function(_package_get_variable_for_activated variable values)
   package_get_all_activated_packages(_activated_list)
   _package_get_variable_for_packages(${variable} _list_values ${_activated_list})
   set(${values} ${_list_values} PARENT_SCOPE)
 endfunction()
 
 # ==============================================================================
 function(_package_get_variable_for_external_dependencies variable type values)
   set(_list_packages)
   package_get_all_activated_packages(_activated_list)
   foreach(_pkg_name ${_activated_list})
     _package_get_nature(${_pkg_name} _nature)
-    if(NOT _nature MATCHES "^external.*")
-      _package_get_dependencies(${_pkg_name} ${type} _deps)
-      foreach(_dep ${_deps})
-        _package_get_nature(${_dep} _nature)
-        if(_nature MATCHES "^external.*")
-          list(APPEND _list_packages ${_dep})
-        endif()
-      endforeach()
+    if(_nature MATCHES "^external.*")
+      list(APPEND _list_packages ${_pkg_name})
     endif()
   endforeach()
 
   if (_list_packages)
     list(REMOVE_DUPLICATES _list_packages)
     _package_get_variable_for_packages(${variable} _list_values_deps ${_list_packages})
     set(${values} ${_list_values_deps} PARENT_SCOPE)
   endif()
 endfunction()
 # ==============================================================================
diff --git a/examples/python/CMakeLists.txt b/examples/python/CMakeLists.txt
index e7439f6f2..9bea05474 100644
--- a/examples/python/CMakeLists.txt
+++ b/examples/python/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_subdirectory(plate-hole)
-add_subdirectory(custom-material-dynamics)
+add_subdirectory(custom-material)
 
 package_add_files_to_package(
   examples/python/README.rst
   )
diff --git a/examples/python/custom-material/CMakeLists.txt b/examples/python/custom-material/CMakeLists.txt
index b9e6e0952..abaacb68f 100644
--- a/examples/python/custom-material/CMakeLists.txt
+++ b/examples/python/custom-material/CMakeLists.txt
@@ -1,3 +1,7 @@
-register_example(newmark
-  SCRIPT newmark.py
+register_example(bi-material
+  SCRIPT bi-material.py
+  FILES_TO_COPY material.dat square.geo)
+
+register_example(custom-material
+  SCRIPT custom-material.py
   FILES_TO_COPY material.dat bar.geo)
diff --git a/examples/python/custom-material/bi-material.py b/examples/python/custom-material/bi-material.py
index b2be031d3..017acc202 100644
--- a/examples/python/custom-material/bi-material.py
+++ b/examples/python/custom-material/bi-material.py
@@ -1,192 +1,192 @@
 from __future__ import print_function
 # ------------------------------------------------------------- #
 import akantu
 import subprocess
 import numpy as np
 import time
 # ------------------------------------------------------------- #
 
 
 class LocalElastic:
 
     # declares all the internals
     def initMaterial(self, internals, params):
         self.E = params['E']
         self.nu = params['nu']
         self.rho = params['rho']
         # print(self.__dict__)
         # First Lame coefficient
         self.lame_lambda = self.nu * self.E / (
             (1. + self.nu) * (1. - 2. * self.nu))
         # Second Lame coefficient (shear modulus)
         self.lame_mu = self.E / (2. * (1. + self.nu))
 
         all_factor = internals['factor']
         all_quad_coords = internals['quad_coordinates']
 
         for elem_type in all_factor.keys():
             factor = all_factor[elem_type]
             quad_coords = all_quad_coords[elem_type]
 
             factor[:] = 1.
             factor[quad_coords[:, 1] < 0.5] = .5
 
     # declares all the internals
     @staticmethod
     def registerInternals():
         return ['potential', 'factor']
 
     # declares all the internals
     @staticmethod
     def registerInternalSizes():
         return [1, 1]
 
     # declares all the parameters that could be parsed
     @staticmethod
     def registerParam():
         return ['E', 'nu']
 
     # declares all the parameters that are needed
     def getPushWaveSpeed(self, params):
         return np.sqrt((self.lame_lambda + 2 * self.lame_mu) / self.rho)
 
     # compute small deformation tensor
     @staticmethod
     def computeEpsilon(grad_u):
         return 0.5 * (grad_u + np.einsum('aij->aji', grad_u))
 
     # constitutive law
     def computeStress(self, grad_u, sigma, internals, params):
         n_quads = grad_u.shape[0]
         grad_u = grad_u.reshape((n_quads, 2, 2))
         factor = internals['factor'].reshape(n_quads)
         epsilon = self.computeEpsilon(grad_u)
         sigma = sigma.reshape((n_quads, 2, 2))
         trace = np.einsum('aii->a', grad_u)
 
         sigma[:, :, :] = (
             np.einsum('a,ij->aij', trace,
                       self.lame_lambda * np.eye(2))
             + 2. * self.lame_mu * epsilon)
 
         # print(sigma.reshape((n_quads, 4)))
         # print(grad_u.reshape((n_quads, 4)))
         sigma[:, :, :] = np.einsum('aij, a->aij', sigma, factor)
 
     # constitutive law tangent modulii
     def computeTangentModuli(self, grad_u, tangent, internals, params):
         n_quads = tangent.shape[0]
         tangent = tangent.reshape(n_quads, 3, 3)
         factor = internals['factor'].reshape(n_quads)
 
         Miiii = self.lame_lambda + 2 * self.lame_mu
         Miijj = self.lame_lambda
         Mijij = self.lame_mu
 
         tangent[:, 0, 0] = Miiii
         tangent[:, 1, 1] = Miiii
         tangent[:, 0, 1] = Miijj
         tangent[:, 1, 0] = Miijj
         tangent[:, 2, 2] = Mijij
         tangent[:, :, :] = np.einsum('aij, a->aij', tangent, factor)
 
     # computes the energy density
     def getEnergyDensity(self, energy_type, energy_density,
                          grad_u, stress, internals, params):
 
         nquads = stress.shape[0]
         stress = stress.reshape(nquads, 2, 2)
         grad_u = grad_u.reshape((nquads, 2, 2))
 
         if energy_type != 'potential':
             raise RuntimeError('not known energy')
 
         epsilon = self.computeEpsilon(grad_u)
 
         energy_density[:, 0] = (
             0.5 * np.einsum('aij,aij->a', stress, epsilon))
 
 
 # applies manually the boundary conditions
 def applyBC(model):
 
     nbNodes = model.getMesh().getNbNodes()
     position = model.getMesh().getNodes()
     displacement = model.getDisplacement()
     blocked_dofs = model.getBlockedDOFs()
 
     width = 1.
     height = 1.
     epsilon = 1e-8
     for node in range(0, nbNodes):
         if((np.abs(position[node, 0]) < epsilon) or  # left side
            (np.abs(position[node, 0] - width) < epsilon)):  # right side
             blocked_dofs[node, 0] = True
             displacement[node, 0] = 0 * position[node, 0] + 0.
 
         if(np.abs(position[node, 1]) < epsilon):  # lower side
             blocked_dofs[node, 1] = True
             displacement[node, 1] = - 1.
         if(np.abs(position[node, 1] - height) < epsilon):  # upper side
             blocked_dofs[node, 1] = True
             displacement[node, 1] = 1.
 
 
 ################################################################
 # main
 ################################################################
 
 # main paraeters
 spatial_dimension = 2
 mesh_file = 'square.msh'
 
 # call gmsh to generate the mesh
 ret = subprocess.call(['gmsh', '-2', 'square.geo', '-optimize', 'square.msh'])
 if ret != 0:
     raise Exception(
         'execution of GMSH failed: do you have it installed ?')
 
 time.sleep(1)
 
 # read mesh
 mesh = akantu.Mesh(spatial_dimension)
 mesh.read(mesh_file)
 
 # create the custom material
 mat = LocalElastic()
 akantu.registerNewPythonMaterial(mat, "local_elastic")
 
 # init akantu
 akantu.initialize('material.dat')
 
 # init the SolidMechanicsModel
 model = akantu.SolidMechanicsModel(mesh)
-model.initFull(akantu.SolidMechanicsModelOptions(akantu._static))
+model.initFull(_analysis_method=akantu._static)
 
 # configure the solver
 solver = model.getNonLinearSolver()
 solver.set("max_iterations", 2)
 solver.set("threshold", 1e-3)
 solver.set("convergence_type", akantu._scc_solution)
 
 # prepare the dumper
 model.setBaseName("bimaterial")
 model.addDumpFieldVector("displacement")
 model.addDumpFieldVector("internal_force")
 model.addDumpFieldVector("external_force")
 model.addDumpField("strain")
 model.addDumpField("stress")
 model.addDumpField("factor")
 model.addDumpField("blocked_dofs")
 
 # Boundary conditions
 applyBC(model)
 
 # solve the problem
 model.solveStep()
 
 # dump paraview files
 model.dump()
 
 # shutdown akantu
 akantu.finalize()
diff --git a/examples/python/custom-material/custom-material.py b/examples/python/custom-material/custom-material.py
index 398804f49..199d51dbe 100644
--- a/examples/python/custom-material/custom-material.py
+++ b/examples/python/custom-material/custom-material.py
@@ -1,213 +1,210 @@
 #!/usr/bin/env python3
 
 from __future__ import print_function
 ################################################################
 import os
 import subprocess
 import numpy as np
 import akantu
 ################################################################
 
 
 class FixedValue:
 
     def __init__(self, value, axis):
         self.value = value
         self.axis = axis
 
     def operator(self, node, flags, disp, coord):
         # sets the displacement to the desired value in the desired axis
         disp[self.axis] = self.value
         # sets the blocked dofs vector to true in the desired axis
         flags[self.axis] = True
 
 ################################################################
 
 
 class LocalElastic:
 
     # declares all the internals
     def initMaterial(self, internals, params):
         self.E = params['E']
         self.nu = params['nu']
         self.rho = params['rho']
         # First Lame coefficient
         self.lame_lambda = self.nu * self.E / (
             (1 + self.nu) * (1 - 2 * self.nu))
         # Second Lame coefficient (shear modulus)
         self.lame_mu = self.E / (2 * (1 + self.nu))
 
     # declares all the internals
     @staticmethod
     def registerInternals():
         return ['potential']
 
     # declares all the internals
     @staticmethod
     def registerInternalSizes():
         return [1]
 
     # declares all the parameters that could be parsed
     @staticmethod
     def registerParam():
         return ['E', 'nu']
 
     # declares all the parameters that are needed
     def getPushWaveSpeed(self, params):
         return np.sqrt((self.lame_lambda + 2 * self.lame_mu) / self.rho)
 
     # compute small deformation tensor
     @staticmethod
     def computeEpsilon(grad_u):
         return 0.5 * (grad_u + np.einsum('aij->aji', grad_u))
 
     # constitutive law
     def computeStress(self, grad_u, sigma, internals, params):
         nquads = grad_u.shape[0]
         grad_u = grad_u.reshape((nquads, 2, 2))
         epsilon = self.computeEpsilon(grad_u)
         sigma = sigma.reshape((nquads, 2, 2))
         trace = np.trace(grad_u, axis1=1, axis2=2)
         sigma[:, :, :] = (
             np.einsum('a,ij->aij', trace,
                       self.lame_lambda * np.eye(2))
             + 2.*self.lame_mu * epsilon)
 
     # constitutive law tangent modulii
     def computeTangentModuli(self, grad_u, tangent, internals, params):
         n_quads = tangent.shape[0]
         tangent = tangent.reshape(n_quads, 3, 3)
 
         Miiii = self.lame_lambda + 2 * self.lame_mu
         Miijj = self.lame_lambda
         Mijij = self.lame_mu
 
         tangent[:, 0, 0] = Miiii
         tangent[:, 1, 1] = Miiii
         tangent[:, 0, 1] = Miijj
         tangent[:, 1, 0] = Miijj
         tangent[:, 2, 2] = Mijij
 
     # computes the energy density
     def getEnergyDensity(self, energy_type, energy_density,
                          grad_u, stress, internals, params):
 
         nquads = stress.shape[0]
         stress = stress.reshape(nquads, 2, 2)
         grad_u = grad_u.reshape((nquads, 2, 2))
 
         if energy_type != 'potential':
             raise RuntimeError('not known energy')
 
         epsilon = self.computeEpsilon(grad_u)
 
         energy_density[:, 0] = (
             0.5 * np.einsum('aij,aij->a', stress, epsilon))
 
 
 ################################################################
 # main
 ################################################################
 
 spatial_dimension = 2
 akantu.initialize('material.dat')
 
 mesh_file = 'bar.msh'
 max_steps = 250
 time_step = 1e-3
 
 # if mesh was not created the calls gmsh to generate it
 if not os.path.isfile(mesh_file):
     ret = subprocess.call('gmsh -2 bar.geo bar.msh', shell=True)
     if ret != 0:
         raise Exception(
             'execution of GMSH failed: do you have it installed ?')
 
 ################################################################
 # Initialization
 ################################################################
 mesh = akantu.Mesh(spatial_dimension)
 mesh.read(mesh_file)
 
 mat = LocalElastic()
 akantu.registerNewPythonMaterial(mat, "local_elastic")
 
 model = akantu.SolidMechanicsModel(mesh)
 
-model.initFull(akantu.SolidMechanicsModelOptions(
-    akantu._explicit_lumped_mass))
-
-# model.initFull(akantu.SolidMechanicsModelOptions(
-#     akantu._implicit_dynamic))
+model.initFull(_analysis_method=akantu._explicit_lumped_mass)
+# model.initFull(_analysis_method=akantu._implicit_dynamic)
 
 model.setBaseName("waves")
 model.addDumpFieldVector("displacement")
 model.addDumpFieldVector("acceleration")
 model.addDumpFieldVector("velocity")
 model.addDumpFieldVector("internal_force")
 model.addDumpFieldVector("external_force")
 model.addDumpField("strain")
 model.addDumpField("stress")
 model.addDumpField("blocked_dofs")
 
 ################################################################
 # boundary conditions
 ################################################################
 
 model.applyDirichletBC(FixedValue(0, akantu._x), "XBlocked")
 model.applyDirichletBC(FixedValue(0, akantu._y), "YBlocked")
 
 ################################################################
 # initial conditions
 ################################################################
 
 displacement = model.getDisplacement()
 nb_nodes = mesh.getNbNodes()
 position = mesh.getNodes()
 
 pulse_width = 1
 A = 0.01
 for i in range(0, nb_nodes):
     # Sinus * Gaussian
     x = position[i, 0] - 5.
     L = pulse_width
     k = 0.1 * 2 * np.pi * 3 / L
     displacement[i, 0] = A * \
         np.sin(k * x) * np.exp(-(k * x) * (k * x) / (L * L))
 
 ################################################################
 # timestep value computation
 ################################################################
 time_factor = 0.8
 stable_time_step = model.getStableTimeStep() * time_factor
 
 print("Stable Time Step = {0}".format(stable_time_step))
 print("Required Time Step = {0}".format(time_step))
 
 time_step = stable_time_step * time_factor
 
 model.setTimeStep(time_step)
 
 ################################################################
 # loop for evolution of motion dynamics
 ################################################################
 model.assembleInternalForces()
 
 print("step,step * time_step,epot,ekin,epot + ekin")
 for step in range(0, max_steps + 1):
 
     model.solveStep()
 
     if step % 10 == 0:
         model.dump()
 
     epot = model.getEnergy('potential')
     ekin = model.getEnergy('kinetic')
 
     # output energy calculation to screen
     print("{0},{1},{2},{3},{4}".format(step, step * time_step,
                                        epot, ekin,
                                        (epot + ekin)))
 
 akantu.finalize()
 
diff --git a/examples/python/dynamics/dynamics.py b/examples/python/dynamics/dynamics.py
index bb92576e7..23d34898e 100644
--- a/examples/python/dynamics/dynamics.py
+++ b/examples/python/dynamics/dynamics.py
@@ -1,133 +1,130 @@
 #!/usr/bin/env python3
 
 from __future__ import print_function
 ################################################################
 import os
 import subprocess
 import numpy as np
 import akantu
 ################################################################
 
 
 class FixedValue:
 
     def __init__(self, value, axis):
         self.value = value
         self.axis = axis
 
     def operator(self, node, flags, disp, coord):
         # sets the displacement to the desired value in the desired axis
         disp[self.axis] = self.value
         # sets the blocked dofs vector to true in the desired axis
         flags[self.axis] = True
 
 ################################################################
 
 
 def main():
 
     spatial_dimension = 2
 
     akantu.initialize('material.dat')
 
     mesh_file = 'bar.msh'
     max_steps = 250
     time_step = 1e-3
 
     # if mesh was not created the calls gmsh to generate it
     if not os.path.isfile(mesh_file):
         ret = subprocess.call('gmsh -2 bar.geo bar.msh', shell=True)
         if ret != 0:
             raise Exception(
                 'execution of GMSH failed: do you have it installed ?')
 
     ################################################################
     # Initialization
     ################################################################
     mesh = akantu.Mesh(spatial_dimension)
     mesh.read(mesh_file)
 
     model = akantu.SolidMechanicsModel(mesh)
 
-    model.initFull(akantu.SolidMechanicsModelOptions(
-        akantu._explicit_lumped_mass))
-
-    # model.initFull(akantu.SolidMechanicsModelOptions(
-    #     akantu._implicit_dynamic))
+    model.initFull(_analysis_method=akantu._explicit_lumped_mass)
+    # model.initFull(_analysis_method=akantu._implicit_dynamic)
 
     model.setBaseName("waves")
     model.addDumpFieldVector("displacement")
     model.addDumpFieldVector("acceleration")
     model.addDumpFieldVector("velocity")
     model.addDumpFieldVector("internal_force")
     model.addDumpFieldVector("external_force")
     model.addDumpField("strain")
     model.addDumpField("stress")
     model.addDumpField("blocked_dofs")
 
     ################################################################
     # boundary conditions
     ################################################################
 
     model.applyDirichletBC(FixedValue(0, akantu._x), "XBlocked")
     model.applyDirichletBC(FixedValue(0, akantu._y), "YBlocked")
 
     ################################################################
     # initial conditions
     ################################################################
 
     displacement = model.getDisplacement()
     nb_nodes = mesh.getNbNodes()
     position = mesh.getNodes()
 
     pulse_width = 1
     A = 0.01
     for i in range(0, nb_nodes):
         # Sinus * Gaussian
         x = position[i, 0] - 5.
         L = pulse_width
         k = 0.1 * 2 * np.pi * 3 / L
         displacement[i, 0] = A * \
             np.sin(k * x) * np.exp(-(k * x) * (k * x) / (L * L))
 
     ################################################################
     # timestep value computation
     ################################################################
     time_factor = 0.8
     stable_time_step = model.getStableTimeStep() * time_factor
 
     print("Stable Time Step = {0}".format(stable_time_step))
     print("Required Time Step = {0}".format(time_step))
 
     time_step = stable_time_step * time_factor
 
     model.setTimeStep(time_step)
 
     ################################################################
     # loop for evolution of motion dynamics
     ################################################################
     model.assembleInternalForces()
 
     print("step,step * time_step,epot,ekin,epot + ekin")
     for step in range(0, max_steps + 1):
 
         model.solveStep()
 
         if step % 10 == 0:
             model.dump()
 
         epot = model.getEnergy('potential')
         ekin = model.getEnergy('kinetic')
 
         # output energy calculation to screen
         print("{0},{1},{2},{3},{4}".format(step, step * time_step,
                                            epot, ekin,
                                            (epot + ekin)))
 
     akantu.finalize()
     return
 
 
 ################################################################
 if __name__ == "__main__":
     main()
diff --git a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
index fbf0ccf69..2dcdbaab9 100644
--- a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
+++ b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
@@ -1,196 +1,196 @@
 /**
  * @file   material_FE2.cc
  *
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @brief Material for multi-scale simulations. It stores an
  * underlying RVE on each integration point of the material.
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "material_FE2.hh"
 #include "communicator.hh"
 #include "solid_mechanics_model_RVE.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 MaterialFE2<spatial_dimension>::MaterialFE2(SolidMechanicsModel & model,
                                             const ID & id)
     : Parent(model, id), C("material_stiffness", *this) {
   AKANTU_DEBUG_IN();
 
   this->C.initialize(voigt_h::size * voigt_h::size);
   this->initialize();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 MaterialFE2<spatial_dimension>::~MaterialFE2() = default;
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim> void MaterialFE2<dim>::initialize() {
   this->registerParam("element_type", el_type, _triangle_3,
                       _pat_parsable | _pat_modifiable,
                       "element type in RVE mesh");
   this->registerParam("mesh_file", mesh_file, _pat_parsable | _pat_modifiable,
                       "the mesh file for the RVE");
   this->registerParam("nb_gel_pockets", nb_gel_pockets,
                       _pat_parsable | _pat_modifiable,
                       "the number of gel pockets in each RVE");
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::initMaterial() {
   AKANTU_DEBUG_IN();
   Parent::initMaterial();
 
   /// create a Mesh and SolidMechanicsModel on each integration point of the
   /// material
   const auto & comm = this->model.getMesh().getCommunicator();
   UInt prank = comm.whoAmI();
   auto C_it = this->C(this->el_type).begin(voigt_h::size, voigt_h::size);
 
   for (auto && data :
        enumerate(make_view(C(this->el_type), voigt_h::size, voigt_h::size))) {
     auto q = std::get<0>(data);
     auto & C = std::get<1>(data);
 
     meshes.emplace_back(std::make_unique<Mesh>(
         spatial_dimension, "RVE_mesh_" + std::to_string(prank), q + 1));
 
     auto & mesh = *meshes.back();
     mesh.read(mesh_file);
 
     RVEs.emplace_back(std::make_unique<SolidMechanicsModelRVE>(
         mesh, true, this->nb_gel_pockets, _all_dimensions,
         "SMM_RVE_" + std::to_string(prank), q + 1));
 
     auto & RVE = *RVEs.back();
-    RVE.initFull();
+    RVE.initFull(_analysis_method = _static);
 
     /// compute intial stiffness of the RVE
     RVE.homogenizeStiffness(C);
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::computeStress(ElementType el_type,
                                                    GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   // Compute thermal stresses first
 
   Parent::computeStress(el_type, ghost_type);
   Array<Real>::const_scalar_iterator sigma_th_it =
       this->sigma_th(el_type, ghost_type).begin();
 
   // Wikipedia convention:
   // 2*eps_ij (i!=j) = voigt_eps_I
   // http://en.wikipedia.org/wiki/Voigt_notation
 
   Array<Real>::const_matrix_iterator C_it =
       this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size);
 
   // create vectors to store stress and strain in Voigt notation
   // for efficient computation of stress
   Vector<Real> voigt_strain(voigt_h::size);
   Vector<Real> voigt_stress(voigt_h::size);
 
   MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type);
 
   const Matrix<Real> & C_mat = *C_it;
   const Real & sigma_th = *sigma_th_it;
 
   /// copy strains in Voigt notation
   for (UInt I = 0; I < voigt_h::size; ++I) {
     /// copy stress in
     Real voigt_factor = voigt_h::factors[I];
     UInt i = voigt_h::vec[I][0];
     UInt j = voigt_h::vec[I][1];
 
     voigt_strain(I) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.;
   }
 
   // compute stresses in Voigt notation
   voigt_stress.mul<false>(C_mat, voigt_strain);
 
   /// copy stresses back in full vectorised notation
   for (UInt I = 0; I < voigt_h::size; ++I) {
     UInt i = voigt_h::vec[I][0];
     UInt j = voigt_h::vec[I][1];
     sigma(i, j) = sigma(j, i) = voigt_stress(I) + (i == j) * sigma_th;
   }
 
   ++C_it;
   ++sigma_th_it;
 
   MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END;
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::computeTangentModuli(
     const ElementType & el_type, Array<Real> & tangent_matrix,
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Array<Real>::const_matrix_iterator C_it =
       this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size);
 
   MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix);
   tangent.copy(*C_it);
   ++C_it;
   MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::advanceASR(
     const Matrix<Real> & prestrain) {
   AKANTU_DEBUG_IN();
 
   for (auto && data :
        zip(RVEs, make_view(this->gradu(this->el_type), spatial_dimension,
                            spatial_dimension),
            make_view(this->eigengradu(this->el_type), spatial_dimension,
                      spatial_dimension),
            make_view(this->C(this->el_type), voigt_h::size, voigt_h::size))) {
     auto & RVE = *(std::get<0>(data));
 
     /// apply boundary conditions based on the current macroscopic displ.
     /// gradient
     RVE.applyBoundaryConditions(std::get<1>(data));
 
     /// advance the ASR in every RVE
     RVE.advanceASR(prestrain);
 
     /// compute the average eigen_grad_u
     RVE.homogenizeEigenGradU(std::get<2>(data));
 
     /// compute the new effective stiffness of the RVE
     RVE.homogenizeStiffness(std::get<3>(data));
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 INSTANTIATE_MATERIAL(material_FE2, MaterialFE2);
 
 } // namespace akantu
diff --git a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc
index 4eb79aec2..27306a2ed 100644
--- a/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc
+++ b/extra_packages/extra-materials/src/material_FE2/solid_mechanics_model_RVE.cc
@@ -1,552 +1,553 @@
 /**
  * @file   solid_mechanics_model_RVE.cc
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @date   Wed Jan 13 15:32:35 2016
  *
  * @brief  Implementation of SolidMechanicsModelRVE
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "solid_mechanics_model_RVE.hh"
 #include "element_group.hh"
 #include "material_damage_iterative.hh"
 #include "node_group.hh"
 #include "non_linear_solver.hh"
 #include "parser.hh"
+#include "sparse_matrix.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModelRVE::SolidMechanicsModelRVE(Mesh & mesh,
                                                bool use_RVE_mat_selector,
                                                UInt nb_gel_pockets, UInt dim,
                                                const ID & id,
                                                const MemoryID & memory_id)
     : SolidMechanicsModel(mesh, dim, id, memory_id), volume(0.),
       use_RVE_mat_selector(use_RVE_mat_selector),
       nb_gel_pockets(nb_gel_pockets), nb_dumps(0) {
   AKANTU_DEBUG_IN();
-  /// create node groups for PBCs
-  mesh.createGroupsFromMeshData<std::string>("physical_names");
   /// find the four corner nodes of the RVE
   findCornerNodes();
 
   /// remove the corner nodes from the surface node groups:
   /// This most be done because corner nodes a not periodic
   mesh.getElementGroup("top").removeNode(corner_nodes(2));
   mesh.getElementGroup("top").removeNode(corner_nodes(3));
   mesh.getElementGroup("left").removeNode(corner_nodes(3));
   mesh.getElementGroup("left").removeNode(corner_nodes(0));
   mesh.getElementGroup("bottom").removeNode(corner_nodes(1));
   mesh.getElementGroup("bottom").removeNode(corner_nodes(0));
   mesh.getElementGroup("right").removeNode(corner_nodes(2));
   mesh.getElementGroup("right").removeNode(corner_nodes(1));
 
   const auto & bottom = mesh.getElementGroup("bottom").getNodeGroup();
   bottom_nodes.insert(bottom.begin(), bottom.end());
 
   const auto & left = mesh.getElementGroup("left").getNodeGroup();
   left_nodes.insert(left.begin(), left.end());
 
   // /// enforce periodicity on the displacement fluctuations
   // auto surface_pair_1 = std::make_pair("top", "bottom");
   // auto surface_pair_2 = std::make_pair("right", "left");
   // SurfacePairList surface_pairs_list;
   // surface_pairs_list.push_back(surface_pair_1);
   // surface_pairs_list.push_back(surface_pair_2);
   // TODO: To Nicolas correct the PBCs
   // this->setPBC(surface_pairs_list);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModelRVE::~SolidMechanicsModelRVE() = default;
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::initFullImpl(const ModelOptions & options) {
   AKANTU_DEBUG_IN();
 
   auto options_cp(options);
   options_cp.analysis_method = AnalysisMethod::_static;
 
-  SolidMechanicsModel::initFullImpl(options);
+  SolidMechanicsModel::initFullImpl(options_cp);
 
   this->initMaterials();
 
   auto & fem = this->getFEEngine("SolidMechanicsFEEngine");
 
   /// compute the volume of the RVE
-  for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) {
+  GhostType gt = _not_ghost;
+  for (auto element_type : this->mesh.elementTypes(spatial_dimension, gt, _ek_not_defined)) {
     Array<Real> Volume(this->mesh.getNbElement(element_type) *
                            fem.getNbIntegrationPoints(element_type),
                        1, 1.);
     this->volume = fem.integrate(Volume, element_type);
   }
 
   std::cout << "The volume of the RVE is " << this->volume << std::endl;
 
   /// dumping
   std::stringstream base_name;
   base_name << this->id; // << this->memory_id - 1;
   this->setBaseName(base_name.str());
   this->addDumpFieldVector("displacement");
   this->addDumpField("stress");
   this->addDumpField("grad_u");
   this->addDumpField("eigen_grad_u");
   this->addDumpField("blocked_dofs");
   this->addDumpField("material_index");
   this->addDumpField("damage");
   this->addDumpField("Sc");
-  this->addDumpField("force");
+  this->addDumpField("external_force");
   this->addDumpField("equivalent_stress");
-  this->addDumpField("internal_forces");
+  this->addDumpField("internal_force");
 
   this->dump();
   this->nb_dumps += 1;
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::applyBoundaryConditions(
     const Matrix<Real> & displacement_gradient) {
   AKANTU_DEBUG_IN();
   /// get the position of the nodes
   const Array<Real> & pos = mesh.getNodes();
   /// storage for the coordinates of a given node and the displacement that will
   /// be applied
   Vector<Real> x(spatial_dimension);
   Vector<Real> appl_disp(spatial_dimension);
 
   /// fix top right node
   UInt node = this->corner_nodes(2);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
   // (*this->blocked_dofs)(node,0) = true; (*this->displacement)(node,0) = 0.;
   // (*this->blocked_dofs)(node,1) = true; (*this->displacement)(node,1) = 0.;
 
   /// apply Hx at all the other corner nodes; H: displ. gradient
   node = this->corner_nodes(0);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
 
   node = this->corner_nodes(1);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
 
   node = this->corner_nodes(3);
   x(0) = pos(node, 0);
   x(1) = pos(node, 1);
   appl_disp.mul<false>(displacement_gradient, x);
   (*this->blocked_dofs)(node, 0) = true;
   (*this->displacement)(node, 0) = appl_disp(0);
   (*this->blocked_dofs)(node, 1) = true;
   (*this->displacement)(node, 1) = appl_disp(1);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::findCornerNodes() {
   AKANTU_DEBUG_IN();
 
   // find corner nodes
   const auto & position = mesh.getNodes();
   const auto & lower_bounds = mesh.getLowerBounds();
   const auto & upper_bounds = mesh.getUpperBounds();
 
   AKANTU_DEBUG_ASSERT(spatial_dimension == 2, "This is 2D only!");
   corner_nodes.resize(4);
   corner_nodes.set(UInt(-1));
 
   for (auto && data : enumerate(make_view(position, spatial_dimension))) {
     auto node = std::get<0>(data);
     const auto & X = std::get<1>(data);
 
     auto distance = X.distance(lower_bounds);
     // node 1
     if (Math::are_float_equal(distance, 0)) {
       corner_nodes(0) = node;
     }
     // node 2
     else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
              Math::are_float_equal(X(_y), lower_bounds(_y))) {
       corner_nodes(1) = node;
     }
     // node 3
     else if (Math::are_float_equal(X(_x), upper_bounds(_x)) &&
              Math::are_float_equal(X(_y), upper_bounds(_y))) {
       corner_nodes(2) = node;
     }
     // node 4
     else if (Math::are_float_equal(X(_x), lower_bounds(_x)) &&
              Math::are_float_equal(X(_y), upper_bounds(_y))) {
       corner_nodes(3) = node;
     }
   }
 
   for (UInt i = 0; i < corner_nodes.size(); ++i) {
     if (corner_nodes(i) == UInt(-1))
       AKANTU_DEBUG_ERROR("The corner node " << i + 1 << " wasn't found");
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::advanceASR(const Matrix<Real> & prestrain) {
   AKANTU_DEBUG_IN();
   AKANTU_DEBUG_ASSERT(spatial_dimension == 2, "This is 2D only!");
 
   /// apply the new eigenstrain
   for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) {
     Array<Real> & prestrain_vect =
         const_cast<Array<Real> &>(this->getMaterial("gel").getInternal<Real>(
             "eigen_grad_u")(element_type));
     auto prestrain_it =
         prestrain_vect.begin(spatial_dimension, spatial_dimension);
     auto prestrain_end =
         prestrain_vect.end(spatial_dimension, spatial_dimension);
 
     for (; prestrain_it != prestrain_end; ++prestrain_it)
       (*prestrain_it) = prestrain;
   }
 
   /// advance the damage
   MaterialDamageIterative<2> & mat_paste =
       dynamic_cast<MaterialDamageIterative<2> &>(*this->materials[1]);
   MaterialDamageIterative<2> & mat_aggregate =
       dynamic_cast<MaterialDamageIterative<2> &>(*this->materials[0]);
   UInt nb_damaged_elements = 0;
   Real max_eq_stress_aggregate = 0;
   Real max_eq_stress_paste = 0;
 
   auto & solver = this->getNonLinearSolver();
   solver.set("max_iterations", 2);
   solver.set("threshold", 1e-6);
   solver.set("convergence_type", _scc_solution);
 
   do {
     this->solveStep();
 
     /// compute damage
     max_eq_stress_aggregate = mat_aggregate.getNormMaxEquivalentStress();
     max_eq_stress_paste = mat_paste.getNormMaxEquivalentStress();
 
     nb_damaged_elements = 0;
     if (max_eq_stress_aggregate > max_eq_stress_paste)
       nb_damaged_elements = mat_aggregate.updateDamage();
     else if (max_eq_stress_aggregate < max_eq_stress_paste)
       nb_damaged_elements = mat_paste.updateDamage();
     else
       nb_damaged_elements =
           (mat_paste.updateDamage() + mat_aggregate.updateDamage());
 
     std::cout << "the number of damaged elements is " << nb_damaged_elements
               << std::endl;
   } while (nb_damaged_elements);
 
   if (this->nb_dumps % 10 == 0) {
     this->dump();
   }
   this->nb_dumps += 1;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModelRVE::averageTensorField(UInt row_index, UInt col_index,
                                                 const ID & field_type) {
   AKANTU_DEBUG_IN();
   auto & fem = this->getFEEngine("SolidMechanicsFEEngine");
   Real average = 0;
 
   for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) {
     if (field_type == "stress") {
       for (UInt m = 0; m < this->materials.size(); ++m) {
         const auto & stress_vec = this->materials[m]->getStress(element_type);
         const auto & elem_filter =
             this->materials[m]->getElementFilter(element_type);
         Array<Real> int_stress_vec(elem_filter.size(),
                                    spatial_dimension * spatial_dimension,
                                    "int_of_stress");
 
         fem.integrate(stress_vec, int_stress_vec,
                       spatial_dimension * spatial_dimension, element_type,
                       _not_ghost, elem_filter);
 
         for (UInt k = 0; k < elem_filter.size(); ++k)
           average += int_stress_vec(
               k, row_index * spatial_dimension + col_index); // 3 is the value
                                                              // for the yy (in
                                                              // 3D, the value is
                                                              // 4)
       }
     } else if (field_type == "strain") {
       for (UInt m = 0; m < this->materials.size(); ++m) {
         const auto & gradu_vec = this->materials[m]->getGradU(element_type);
         const auto & elem_filter =
             this->materials[m]->getElementFilter(element_type);
         Array<Real> int_gradu_vec(elem_filter.size(),
                                   spatial_dimension * spatial_dimension,
                                   "int_of_gradu");
 
         fem.integrate(gradu_vec, int_gradu_vec,
                       spatial_dimension * spatial_dimension, element_type,
                       _not_ghost, elem_filter);
 
         for (UInt k = 0; k < elem_filter.size(); ++k)
           /// averaging is done only for normal components, so stress and strain
           /// are equal
           average +=
               0.5 *
               (int_gradu_vec(k, row_index * spatial_dimension + col_index) +
                int_gradu_vec(k, col_index * spatial_dimension + row_index));
       }
     } else if (field_type == "eigen_grad_u") {
       for (UInt m = 0; m < this->materials.size(); ++m) {
         const auto & eigen_gradu_vec =
             this->materials[m]->getInternal<Real>("eigen_grad_u")(element_type);
         const auto & elem_filter =
             this->materials[m]->getElementFilter(element_type);
         Array<Real> int_eigen_gradu_vec(elem_filter.size(),
                                         spatial_dimension * spatial_dimension,
                                         "int_of_gradu");
 
         fem.integrate(eigen_gradu_vec, int_eigen_gradu_vec,
                       spatial_dimension * spatial_dimension, element_type,
                       _not_ghost, elem_filter);
 
         for (UInt k = 0; k < elem_filter.size(); ++k)
           /// averaging is done only for normal components, so stress and strain
           /// are equal
           average +=
               int_eigen_gradu_vec(k, row_index * spatial_dimension + col_index);
       }
     } else {
       AKANTU_DEBUG_ERROR("Averaging not implemented for this field!!!");
     }
   }
 
   return average / this->volume;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::homogenizeStiffness(Matrix<Real> & C_macro) {
   AKANTU_DEBUG_IN();
   const UInt dim = 2;
   AKANTU_DEBUG_ASSERT(this->spatial_dimension == dim,
                       "Is only implemented for 2D!!!");
 
   /// apply three independent loading states to determine C
   /// 1. eps_el = (1;0;0) 2. eps_el = (0,1,0) 3. eps_el = (0,0,0.5)
 
   /// clear the eigenstrain
   Matrix<Real> zero_eigengradu(dim, dim, 0.);
-  for (auto element_type : mesh.elementTypes(_element_kind = _ek_not_defined)) {
+  GhostType gt = _not_ghost;
+  for (auto element_type : mesh.elementTypes(dim, gt, _ek_not_defined)) {
     auto & prestrain_vect =
         const_cast<Array<Real> &>(this->getMaterial("gel").getInternal<Real>(
             "eigen_grad_u")(element_type));
     auto prestrain_it =
         prestrain_vect.begin(spatial_dimension, spatial_dimension);
     auto prestrain_end =
         prestrain_vect.end(spatial_dimension, spatial_dimension);
 
     for (; prestrain_it != prestrain_end; ++prestrain_it)
       (*prestrain_it) = zero_eigengradu;
   }
 
   /// storage for results of 3 different loading states
   UInt voigt_size = VoigtHelper<dim>::size;
   Matrix<Real> stresses(voigt_size, voigt_size, 0.);
   Matrix<Real> strains(voigt_size, voigt_size, 0.);
   Matrix<Real> H(dim, dim, 0.);
 
   /// save the damage state before filling up cracks
   // ElementTypeMapReal saved_damage("saved_damage");
   // saved_damage.initialize(getFEEngine(), _nb_component = 1, _default_value =
   // 0);
   // this->fillCracks(saved_damage);
 
   /// virtual test 1:
   H(0, 0) = 0.01;
   this->performVirtualTesting(H, stresses, strains, 0);
 
   /// virtual test 2:
   H.clear();
   H(1, 1) = 0.01;
   this->performVirtualTesting(H, stresses, strains, 1);
 
   /// virtual test 3:
   H.clear();
   H(0, 1) = 0.01;
   this->performVirtualTesting(H, stresses, strains, 2);
 
   /// drain cracks
   // this->drainCracks(saved_damage);
   /// compute effective stiffness
   Matrix<Real> eps_inverse(voigt_size, voigt_size);
   eps_inverse.inverse(strains);
   C_macro.mul<false, false>(stresses, eps_inverse);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::performVirtualTesting(const Matrix<Real> & H,
                                                    Matrix<Real> & eff_stresses,
                                                    Matrix<Real> & eff_strains,
                                                    const UInt test_no) {
   AKANTU_DEBUG_IN();
   this->applyBoundaryConditions(H);
 
-  auto & solver = this->getNonLinearSolver("static");
+  auto & solver = this->getNonLinearSolver();
   solver.set("max_iterations", 2);
   solver.set("threshold", 1e-6);
   solver.set("convergence_type", _scc_solution);
-  this->solveStep("static");
+  this->solveStep();
 
   /// get average stress and strain
   eff_stresses(0, test_no) = this->averageTensorField(0, 0, "stress");
   eff_strains(0, test_no) = this->averageTensorField(0, 0, "strain");
   eff_stresses(1, test_no) = this->averageTensorField(1, 1, "stress");
   eff_strains(1, test_no) = this->averageTensorField(1, 1, "strain");
   eff_stresses(2, test_no) = this->averageTensorField(1, 0, "stress");
   eff_strains(2, test_no) = 2. * this->averageTensorField(1, 0, "strain");
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::homogenizeEigenGradU(
     Matrix<Real> & eigen_gradu_macro) {
   AKANTU_DEBUG_IN();
   eigen_gradu_macro(0, 0) = this->averageTensorField(0, 0, "eigen_grad_u");
   eigen_gradu_macro(1, 1) = this->averageTensorField(1, 1, "eigen_grad_u");
   eigen_gradu_macro(0, 1) = this->averageTensorField(0, 1, "eigen_grad_u");
   eigen_gradu_macro(1, 0) = this->averageTensorField(1, 0, "eigen_grad_u");
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::initMaterials() {
   AKANTU_DEBUG_IN();
 
   // make sure the material are instantiated
   if (!are_materials_instantiated)
     instantiateMaterials();
 
   if (use_RVE_mat_selector) {
     const Vector<Real> & lowerBounds = mesh.getLowerBounds();
     const Vector<Real> & upperBounds = mesh.getUpperBounds();
     Real bottom = lowerBounds(1);
     Real top = upperBounds(1);
     Real box_size = std::abs(top - bottom);
     Real eps = box_size * 1e-6;
 
     auto tmp = std::make_shared<GelMaterialSelector>(*this, box_size, "gel",
                                                      this->nb_gel_pockets, eps);
     tmp->setFallback(material_selector);
     material_selector = tmp;
   }
 
   SolidMechanicsModel::initMaterials();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::fillCracks(ElementTypeMapReal & saved_damage) {
   const auto & mat_gel = this->getMaterial("gel");
   Real E_gel = mat_gel.get("E");
   Real E_homogenized = 0.;
 
   for (auto && mat : materials) {
     if (mat->getName() == "gel" || mat->getName() == "FE2_mat")
       continue;
 
     Real E = mat->get("E");
     auto & damage = mat->getInternal<Real>("damage");
 
     for (auto && type : damage.elementTypes()) {
       const auto & elem_filter = mat->getElementFilter(type);
       auto nb_integration_point = getFEEngine().getNbIntegrationPoints(type);
 
       auto sav_dam_it =
           make_view(saved_damage(type), nb_integration_point).begin();
       for (auto && data :
            zip(elem_filter, make_view(damage(type), nb_integration_point))) {
         auto el = std::get<0>(data);
         auto & dam = std::get<1>(data);
         Vector<Real> sav_dam = sav_dam_it[el];
 
         sav_dam = dam;
 
         for (auto q : arange(dam.size())) {
           E_homogenized = (E_gel - E) * dam(q) + E;
           dam(q) = 1. - (E_homogenized / E);
         }
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelRVE::drainCracks(
     const ElementTypeMapReal & saved_damage) {
   for (auto && mat : materials) {
     if (mat->getName() == "gel" || mat->getName() == "FE2_mat")
       continue;
     auto & damage = mat->getInternal<Real>("damage");
 
     for (auto && type : damage.elementTypes()) {
       const auto & elem_filter = mat->getElementFilter(type);
       auto nb_integration_point = getFEEngine().getNbIntegrationPoints(type);
 
       auto sav_dam_it = make_view(saved_damage(type), nb_integration_point).begin();
       for (auto && data :
            zip(elem_filter, make_view(damage(type), nb_integration_point))) {
         auto el = std::get<0>(data);
         auto & dam = std::get<1>(data);
         Vector<Real> sav_dam = sav_dam_it[el];
 
         dam = sav_dam;
       }
     }
   }
 }
 
 } // namespace akantu
diff --git a/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc b/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc
index 5c0102369..485abb338 100644
--- a/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc
+++ b/extra_packages/extra-materials/src/material_damage/material_damage_iterative_non_local.cc
@@ -1,40 +1,40 @@
 /**
  * @file   material_damage_iterative.cc
  *
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  *
  * @brief  Implementation of MaterialDamageIterativeNonLocal 
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "material_damage_iterative_non_local.hh"
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template<UInt spatial_dimension>
 void MaterialDamageIterativeNonLocal<spatial_dimension>::computeNonLocalStresses(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
   /// reset normalized maximum equivalent stress
   if(ghost_type==_not_ghost)
     this->norm_max_equivalent_stress = 0;
  
   MaterialDamageIterativeNonLocalParent::computeNonLocalStresses(ghost_type);
 
   /// find global Gauss point with highest stress
-  StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator();
-  comm.allReduce(&(this->norm_max_equivalent_stress), 1, _so_max);
+  const auto & comm = this->model.getMesh().getCommunicator();
+  comm.allReduce(this->norm_max_equivalent_stress, SynchronizerOperation::_max);
 
   AKANTU_DEBUG_OUT();
 }
 /* -------------------------------------------------------------------------- */
-INSTANTIATE_MATERIAL(MaterialDamageIterativeNonLocal);
+INSTANTIATE_MATERIAL(damage_iterative_non_local, MaterialDamageIterativeNonLocal);
 
 } // namespace akantu
diff --git a/packages/embedded.cmake b/packages/embedded.cmake
index b223dfbb5..75c2a1243 100644
--- a/packages/embedded.cmake
+++ b/packages/embedded.cmake
@@ -1,60 +1,57 @@
 #===============================================================================
 # @file   embedded.cmake
 #
 # @author Lucas Frerot <lucas.frerot@epfl.ch>
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Tue Oct 16 2012
 # @date last modification: Mon Dec 14 2015
 #
 # @brief  package descrition for embedded model use
 #
 # @section LICENSE
 #
 # Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
 # Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
 # Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 #===============================================================================
 
 package_declare(embedded 
   DESCRIPTION "Add support for the embedded solid mechanics model"
   DEPENDS CGAL)
 
 package_declare_sources(embedded
   model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.cc
   model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_intersector.hh
   model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc
   model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.hh
-  model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh
+
   model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh
-  model/solid_mechanics/materials/material_embedded/material_reinforcement.cc
   model/solid_mechanics/materials/material_embedded/material_reinforcement.hh
-  model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc
-  model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh
-  model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh
+  model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh
   )
 
 package_declare_material_infos(embedded
   LIST AKANTU_EMBEDDED_MATERIAL_LIST
   INCLUDE material_embedded_includes.hh
   )
 
 package_declare_documentation(embedded
 "This package allows the use of the embedded model in solid mechanics. This package depends on the CGAL package."
 )
 
 #add_example(embedded             "Example on how to run embedded model simulation"     PACKAGE embedded)
diff --git a/packages/solid_mechanics.cmake b/packages/solid_mechanics.cmake
index c64a05a82..27a98df70 100644
--- a/packages/solid_mechanics.cmake
+++ b/packages/solid_mechanics.cmake
@@ -1,128 +1,129 @@
 #===============================================================================
 # @file   solid_mechanics.cmake
 #
 # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Mon Nov 21 2011
 # @date last modification: Mon Jan 18 2016
 #
 # @brief  package description for core
 #
 # @section LICENSE
 #
 # Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
 # Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
 # Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 #===============================================================================
 package_declare(solid_mechanics DEFAULT ON
   DESCRIPTION "Solid mechanics model"
   DEPENDS core
   )
 
 package_declare_sources(solid_mechanics
   model/solid_mechanics/material.cc
   model/solid_mechanics/material.hh
   model/solid_mechanics/material_inline_impl.cc
   model/solid_mechanics/material_selector.hh
   model/solid_mechanics/material_selector_tmpl.hh
   model/solid_mechanics/materials/internal_field.hh
   model/solid_mechanics/materials/internal_field_tmpl.hh
   model/solid_mechanics/materials/random_internal_field.hh
   model/solid_mechanics/materials/random_internal_field_tmpl.hh
   model/solid_mechanics/solid_mechanics_model.cc
   model/solid_mechanics/solid_mechanics_model.hh
   model/solid_mechanics/solid_mechanics_model_inline_impl.cc
   model/solid_mechanics/solid_mechanics_model_io.cc
   model/solid_mechanics/solid_mechanics_model_mass.cc
   model/solid_mechanics/solid_mechanics_model_material.cc
   model/solid_mechanics/solid_mechanics_model_tmpl.hh
   model/solid_mechanics/solid_mechanics_model_event_handler.hh
   model/solid_mechanics/materials/plane_stress_toolbox.hh
   model/solid_mechanics/materials/plane_stress_toolbox_tmpl.hh
 
   model/solid_mechanics/materials/material_core_includes.hh
   model/solid_mechanics/materials/material_elastic.cc
   model/solid_mechanics/materials/material_elastic.hh
   model/solid_mechanics/materials/material_elastic_inline_impl.cc
   model/solid_mechanics/materials/material_thermal.cc
   model/solid_mechanics/materials/material_thermal.hh
   model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc
   model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh
+  model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc
   model/solid_mechanics/materials/material_elastic_orthotropic.cc
   model/solid_mechanics/materials/material_elastic_orthotropic.hh
   model/solid_mechanics/materials/material_damage/material_damage.hh
   model/solid_mechanics/materials/material_damage/material_damage_tmpl.hh
   model/solid_mechanics/materials/material_damage/material_marigo.cc
   model/solid_mechanics/materials/material_damage/material_marigo.hh
   model/solid_mechanics/materials/material_damage/material_marigo_inline_impl.cc
   model/solid_mechanics/materials/material_damage/material_mazars.cc
   model/solid_mechanics/materials/material_damage/material_mazars.hh
   model/solid_mechanics/materials/material_damage/material_mazars_inline_impl.cc
   model/solid_mechanics/materials/material_finite_deformation/material_neohookean.cc
   model/solid_mechanics/materials/material_finite_deformation/material_neohookean.hh
   model/solid_mechanics/materials/material_finite_deformation/material_neohookean_inline_impl.cc
   model/solid_mechanics/materials/material_plastic/material_plastic.cc
   model/solid_mechanics/materials/material_plastic/material_plastic.hh
   model/solid_mechanics/materials/material_plastic/material_plastic_inline_impl.cc
   model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.cc
   model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening.hh
   model/solid_mechanics/materials/material_plastic/material_linear_isotropic_hardening_inline_impl.cc
   model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.cc
   model/solid_mechanics/materials/material_viscoelastic/material_standard_linear_solid_deviatoric.hh
 
   model/solid_mechanics/materials/material_non_local.hh
   model/solid_mechanics/materials/material_non_local_tmpl.hh
   model/solid_mechanics/materials/material_non_local_includes.hh
   )
 
 package_declare_material_infos(solid_mechanics
   LIST AKANTU_CORE_MATERIAL_LIST
   INCLUDE material_core_includes.hh
   )
 
 package_declare_documentation_files(solid_mechanics
   manual-solidmechanicsmodel.tex
   manual-constitutive-laws.tex
   manual-lumping.tex
   manual-appendix-materials.tex
 
   figures/dynamic_analysis.png
   figures/explicit_dynamic.pdf
   figures/explicit_dynamic.svg
   figures/static.pdf
   figures/static.svg
   figures/hooke_law.pdf
   figures/implicit_dynamic.pdf
   figures/implicit_dynamic.svg
   figures/problemDomain.pdf_tex
   figures/problemDomain.pdf
   figures/static_analysis.png
   figures/stress_strain_el.pdf
   figures/tangent.pdf
   figures/tangent.svg
 
   figures/stress_strain_neo.pdf
   figures/visco_elastic_law.pdf
   figures/isotropic_hardening_plasticity.pdf
   figures/stress_strain_visco.pdf
   )
 
 package_declare_extra_files_to_package(solid_mechanics
   SOURCES
     model/solid_mechanics/material_list.hh.in
   )
diff --git a/python/swig/model.i b/python/swig/model.i
index 321fac529..365a13d2b 100644
--- a/python/swig/model.i
+++ b/python/swig/model.i
@@ -1,132 +1,131 @@
 /**
  * @file   model.i
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Dec 12 2014
  * @date last modification: Wed Nov 11 2015
  *
  * @brief  model wrapper
  *
  * @section LICENSE
  *
  * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
  * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 %{
   #include "boundary_condition_python_functor.hh"
   #include "model_solver.hh"
   #include "non_linear_solver.hh"
   %}
 
 
 namespace akantu {
   %ignore Model::createSynchronizerRegistry;
   %ignore Model::getSynchronizerRegistry;
   %ignore Model::createParallelSynch;
   %ignore Model::getDOFSynchronizer;
   %ignore Model::registerFEEngineObject;
   %ignore Model::unregisterFEEngineObject;
   %ignore Model::getFEEngineBoundary;
   //  %ignore Model::getFEEngine;
   %ignore Model::getFEEngineClass;
   %ignore Model::getFEEngineClassBoundary;
   %ignore Model::setParser;
   %ignore Model::updateDataForNonLocalCriterion;
   %ignore IntegrationPoint::operator=;
 
   %ignore FEEngine::getNbIntegrationPoints;
   %ignore FEEngine::getShapes;
   %ignore FEEngine::getShapesDerivatives;
   %ignore FEEngine::getIntegrationPoints;
   %ignore FEEngine::getIGFEMElementTypes;
   %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,ElementTypeMapArray<Real> &,const ElementTypeMapArray<UInt> *) const;
   %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,ElementTypeMapArray<Real> &) const;
   %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,Array<Real> &,UInt,const ElementType&,const GhostType &,const Array< UInt > &) const;
   %ignore FEEngine::interpolateOnIntegrationPoints(const Array<Real> &,Array<Real> &,UInt,const ElementType&,const GhostType &) const;
   %ignore FEEngine::onNodesAdded;
   %ignore FEEngine::onNodesRemoved;
   %ignore FEEngine::onElementsAdded;
   %ignore FEEngine::onElementsChanged;
   %ignore FEEngine::onElementsRemoved;
   %ignore FEEngine::elementTypes;
 }
 
 %include "sparse_matrix.i"
 %include "fe_engine.hh"
 
 %rename(FreeBoundaryDirichlet) akantu::BC::Dirichlet::FreeBoundary;
 %rename(FreeBoundaryNeumann) akantu::BC::Neumann::FreeBoundary;
 %rename(PythonBoundary) akantu::BC::Dirichlet::PythonFunctor;
 
 %include "boundary_condition_functor.hh"
 %include "boundary_condition.hh"
 %include "boundary_condition_python_functor.hh"
 %include "communication_buffer.hh"
 %include "data_accessor.hh"
 //%include "synchronizer.hh"
 //%include "synchronizer_registry.hh"
 %include "model.hh"
 %include "non_linear_solver.hh"
 
 %extend akantu::Model {
   void initFullImpl(
        const akantu::ModelOptions & options = akantu::ModelOptions()){
      $self->initFull(options);
   };
 
   %insert("python") %{
     def initFull(self, *args, **kwargs):
         if len(args) == 0:
             import importlib as __aka_importlib
             _module =  __aka_importlib.import_module(self.__module__)
             _cls = getattr(_module, "{0}Options".format(self.__class__.__name__))
             options = _cls()
             if len(kwargs) > 0:
                 for key, val in kwargs.items():
                     if key[0] == '_':
                         key = key[1:]
-                    _attr = getattr(options, key)
-                    _attr = val
+                    setattr(options, key, val)
         else:
             options = args[0]
 
         self.initFullImpl(options)
   %}
 
 
   void solveStep(){
     $self->solveStep();
   }
 
   akantu::NonLinearSolver & getNonLinearSolver(){
    return $self->getNonLinearSolver();
   }
  }
 
 %extend akantu::NonLinearSolver {
   void set(const std::string & id, akantu::Real val){
     if (id == "max_iterations")
       $self->set(id, int(val));
     else if (id == "convergence_type")
       $self->set(id, akantu::SolveConvergenceCriteria(UInt(val)));
     else $self->set(id, val);
   }
  }
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c753e1594..c3ec182d4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,217 +1,216 @@
 #===============================================================================
 # @file   CMakeLists.txt
 #
 # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Mon Jun 14 2010
 # @date last modification: Wed Jan 20 2016
 #
 # @brief  CMake file for the library
 #
 # @section LICENSE
 #
 # Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
 # Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
 # Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 #===============================================================================
 
 #===============================================================================
 # Package Management
 #===============================================================================
 package_get_all_source_files(
   AKANTU_LIBRARY_SRCS
   AKANTU_LIBRARY_PUBLIC_HDRS
   AKANTU_LIBRARY_PRIVATE_HDRS
   )
 
 package_get_all_include_directories(
   AKANTU_LIBRARY_INCLUDE_DIRS
   )
 
 package_get_all_external_informations(
   PRIVATE_INCLUDE AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR
   INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR
   LIBRARIES AKANTU_EXTERNAL_LIBRARIES
   )
 
 package_get_all_compilation_flags(CXX _cxx_flags)
 set(AKANTU_EXTRA_CXX_FLAGS
   "${_cxx_flags}" CACHE STRING "Extra flags defined by loaded packages" FORCE)
 mark_as_advanced(AKANTU_EXTRA_CXX_FLAGS)
 
 foreach(src_ ${AKANTU_SPIRIT_SOURCES})
   set_property(SOURCE ${src_} PROPERTY COMPILE_FLAGS "-g0 -Werror")
 endforeach()
 
 #===========================================================================
 # header for blas/lapack (any other fortran libraries)
 #===========================================================================
 package_is_activated(BLAS _blas_activated)
 package_is_activated(LAPACK _lapack_activated)
 
 if(_blas_activated OR _lapack_activated)
   if(CMAKE_Fortran_COMPILER)
     # ugly hack
     set(CMAKE_Fortran_COMPILER_LOADED TRUE)
   endif()
 
   include(FortranCInterface)
   FortranCInterface_HEADER(
     "${CMAKE_CURRENT_BINARY_DIR}/aka_fortran_mangling.hh"
     MACRO_NAMESPACE "AKA_FC_")
   mark_as_advanced(CDEFS)
 endif()
 
 list(APPEND AKANTU_LIBRARY_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}")
 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
 #===========================================================================
 package_get_all_material_includes(AKANTU_MATERIAL_INCLUDES)
 package_get_all_material_lists(AKANTU_MATERIAL_LISTS)
 configure_file(model/solid_mechanics/material_list.hh.in
   "${CMAKE_CURRENT_BINARY_DIR}/material_list.hh" @ONLY)
 
 package_get_element_lists()
 configure_file(common/aka_element_classes_info.hh.in
   "${CMAKE_CURRENT_BINARY_DIR}/aka_element_classes_info.hh" @ONLY)
 
 configure_file(common/aka_config.hh.in
   "${CMAKE_CURRENT_BINARY_DIR}/aka_config.hh" @ONLY)
 
 #===============================================================================
 # Debug infos
 #===============================================================================
 set(AKANTU_GDB_DIR ${PROJECT_SOURCE_DIR}/cmake)
 if(UNIX)
   string(TOUPPER "${CMAKE_BUILD_TYPE}" _u_build_type)
   if(_u_build_type STREQUAL "DEBUG" OR _u_build_type STREQUAL "RELWITHDEBINFO")
     configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in
       "${PROJECT_BINARY_DIR}/libakantu-gdb.py"
       @ONLY)
     configure_file(${PROJECT_SOURCE_DIR}/cmake/akantu-debug.cc.in
       "${PROJECT_BINARY_DIR}/akantu-debug.cc" @ONLY)
 
     list(APPEND AKANTU_LIBRARY_SRCS ${PROJECT_BINARY_DIR}/akantu-debug.cc)
   endif()
 else()
   find_program(GDB_EXECUTABLE gdb)
 
   if(GDB_EXECUTABLE)
     execute_process(COMMAND
       ${GDB_EXECUTABLE} --batch -x "${PROJECT_SOURCE_DIR}/cmake/gdb_python_path"
       OUTPUT_VARIABLE AKANTU_PYTHON_GDB_DIR
       ERROR_QUIET
       RESULT_VARIABLE _res)
 
     if(_res EQUAL 0 AND UNIX)
       set(GDB_USER_CONFIG $ENV{HOME}/.gdb/auto-load)
       file(MAKE_DIRECTORY ${GDB_USER_CONFIG})
 
       configure_file(${PROJECT_SOURCE_DIR}/cmake/libakantu-gdb.py.in
         "${GDB_USER_CONFIG}/${CMAKE_SHARED_LIBRARY_PREFIX}akantu${CMAKE_SHARED_LIBRARY_SUFFIX}.${AKANTU_VERSION}-gdb.py"
         @ONLY)
     endif()
   endif()
 endif()
 
 #===============================================================================
 # Library generation
 #===============================================================================
 add_library(akantu ${AKANTU_LIBRARY_SRCS})
 
 target_include_directories(akantu
   PRIVATE   $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}>
   INTERFACE $<INSTALL_INTERFACE:include/akantu>
   )
 
 # small trick for build includes in public
 set_property(TARGET akantu APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
   $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}>)
 
 target_include_directories(akantu SYSTEM
-  PUBLIC $<BUILD_INTERFACE:${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR}>
-         $<INSTALL_INTERFACE:${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR}>
+  PUBLIC ${AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR}
   )
 
 target_include_directories(akantu SYSTEM
   PRIVATE ${AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR}
   )
 
 target_link_libraries(akantu ${AKANTU_EXTERNAL_LIBRARIES})
 
 set_target_properties(akantu
   PROPERTIES
     ${AKANTU_LIBRARY_PROPERTIES} # this contains the version
     COMPILE_FLAGS "${_cxx_flags}"
 
     )
 
 if(NOT CMAKE_VERSION VERSION_LESS 3.1)
   package_get_all_features_public(_PUBLIC_features)
   package_get_all_features_private(_PRIVATE_features)
   foreach(_type PRIVATE PUBLIC)
     if(_${_type}_features)
       target_compile_features(akantu ${_type} ${_${_type}_features})
     endif()
   endforeach()
 else()
   set_target_properties(akantu
     PROPERTIES
     CXX_STANDARD 14
     )
 endif()
 
 package_get_all_extra_dependencies(_extra_target_dependencies)
 if(_extra_target_dependencies)
   # This only adding todo: find a solution for when a dependency was add the is removed...
   add_dependencies(akantu ${_extra_target_dependencies})
 endif()
 
 package_get_all_export_list(AKANTU_EXPORT_LIST)
 list(APPEND AKANTU_EXPORT_LIST akantu)
 
 # TODO separate public from private headers
 install(TARGETS akantu
   EXPORT ${AKANTU_TARGETS_EXPORT}
   LIBRARY DESTINATION lib COMPONENT lib
   ARCHIVE DESTINATION lib COMPONENT lib
   RUNTIME DESTINATION bin COMPONENT bin
   PUBLIC_HEADER DESTINATION include/akantu/ COMPONENT dev
   )
 
 if("${AKANTU_TARGETS_EXPORT}" STREQUAL "AkantuTargets")
   install(EXPORT AkantuTargets DESTINATION share/cmake/${PROJECT_NAME}
     COMPONENT dev)
 
   #Export for build tree
   export(EXPORT AkantuTargets
     FILE "${CMAKE_BINARY_DIR}/AkantuTargets.cmake")
   export(PACKAGE Akantu)
 endif()
 
 
 
 
 # print out the list of materials
 generate_material_list()
 
 register_target_to_tidy(akantu)
diff --git a/src/common/aka_extern.cc b/src/common/aka_extern.cc
index ca6b5a5e7..78ae76cfa 100644
--- a/src/common/aka_extern.cc
+++ b/src/common/aka_extern.cc
@@ -1,109 +1,109 @@
 /**
  * @file   aka_extern.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Jun 14 2010
  * @date last modification: Thu Nov 19 2015
  *
  * @brief  initialisation of all global variables
  * to insure the order of creation
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_array.hh"
 #include "aka_common.hh"
 #include "aka_math.hh"
 #include "aka_named_argument.hh"
 #include "aka_random_generator.hh"
 #include "communication_tag.hh"
 #include "cppargparse.hh"
 #include "parser.hh"
 #include "solid_mechanics_model.hh"
 #if defined(AKANTU_COHESIVE_ELEMENT)
 #include "solid_mechanics_model_cohesive.hh"
 #endif
 /* -------------------------------------------------------------------------- */
 #include <iostream>
 #include <limits>
 /* -------------------------------------------------------------------------- */
 #if defined(AKANTU_DEBUG_TOOLS)
 #include "aka_debug_tools.hh"
 #endif
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /* error.hpp variables                                                        */
 /* -------------------------------------------------------------------------- */
 namespace debug {
   /** \todo write function to get this
    *   values from the environment or a config file
    */
   /// standard output for debug messages
   std::ostream * _akantu_debug_cout = &std::cerr;
 
   /// standard output for normal messages
   std::ostream & _akantu_cout = std::cout;
 
   /// parallel context used in debug messages
   std::string _parallel_context = "";
 
   Debugger debugger;
 
 #if defined(AKANTU_DEBUG_TOOLS)
   DebugElementManager element_manager;
 #endif
 } // namespace debug
 
 /* -------------------------------------------------------------------------- */
 /// list of ghost iterable types
 ghost_type_t ghost_types(_casper);
 
 /* -------------------------------------------------------------------------- */
 /// Paser for commandline arguments
 ::cppargparse::ArgumentParser static_argparser;
 
 /// Parser containing the information parsed by the input file given to initFull
 Parser static_parser;
 
 bool Parser::permissive_parser = false;
 
 /* -------------------------------------------------------------------------- */
-Real Math::tolerance = std::numeric_limits<Real>::epsilon();
+Real Math::tolerance = 1e2 * std::numeric_limits<Real>::epsilon();
 
 /* -------------------------------------------------------------------------- */
 const UInt _all_dimensions = UInt(-1);
 
 /* -------------------------------------------------------------------------- */
 const Array<UInt> empty_filter(0, 1, "empty_filter");
 
 /* -------------------------------------------------------------------------- */
 template <> long int RandomGenerator<UInt>::_seed = 5489u;
 template <> std::default_random_engine RandomGenerator<UInt>::generator(5489u);
 /* -------------------------------------------------------------------------- */
 int Tag::max_tag = 0;
 
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/common/aka_types.hh b/src/common/aka_types.hh
index 62d998fde..203d4d318 100644
--- a/src/common/aka_types.hh
+++ b/src/common/aka_types.hh
@@ -1,1302 +1,1302 @@
 /**
  * @file   aka_types.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Thu Feb 17 2011
  * @date last modification: Fri Jan 22 2016
  *
  * @brief  description of the "simple" types
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_error.hh"
 #include "aka_fwd.hh"
 #include "aka_math.hh"
 /* -------------------------------------------------------------------------- */
 #include <initializer_list>
 #include <iomanip>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_AKA_TYPES_HH__
 #define __AKANTU_AKA_TYPES_HH__
 
 namespace akantu {
 
 enum NormType { L_1 = 1, L_2 = 2, L_inf = UInt(-1) };
 
 /**
  * DimHelper is a class to generalize the setup of a dim array from 3
  * values. This gives a common interface in the TensorStorage class
  * independently of its derived inheritance (Vector, Matrix, Tensor3)
  * @tparam dim
  */
 template <UInt dim> struct DimHelper {
   static inline void setDims(UInt m, UInt n, UInt p, UInt dims[dim]);
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct DimHelper<1> {
   static inline void setDims(UInt m, __attribute__((unused)) UInt n,
                              __attribute__((unused)) UInt p, UInt dims[1]) {
     dims[0] = m;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct DimHelper<2> {
   static inline void setDims(UInt m, UInt n, __attribute__((unused)) UInt p,
                              UInt dims[2]) {
     dims[0] = m;
     dims[1] = n;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct DimHelper<3> {
   static inline void setDims(UInt m, UInt n, UInt p, UInt dims[3]) {
     dims[0] = m;
     dims[1] = n;
     dims[2] = p;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T, UInt ndim, class RetType> class TensorStorage;
 
 /* -------------------------------------------------------------------------- */
 /* Proxy classes                                                              */
 /* -------------------------------------------------------------------------- */
 namespace tensors {
   template <class A, class B> struct is_copyable {
     enum : bool { value = false };
   };
 
   template <class A> struct is_copyable<A, A> {
     enum : bool { value = true };
   };
 
   template <class A> struct is_copyable<A, typename A::RetType> {
     enum : bool { value = true };
   };
 
   template <class A> struct is_copyable<A, typename A::RetType::proxy> {
     enum : bool { value = true };
   };
 
 } // namespace tensors
 
 /**
  * @class TensorProxy aka_types.hh
  * @desc The TensorProxy class is a proxy class to the TensorStorage it handles
  * the
  * wrapped case. That is to say if an accessor should give access to a Tensor
  * wrapped on some data, like the Array<T>::iterator they can return a
  * TensorProxy that will be automatically transformed as a TensorStorage wrapped
  * on the same data
  * @tparam T stored type
  * @tparam ndim order of the tensor
  * @tparam RetType real derived type
  */
 template <typename T, UInt ndim, class _RetType> class TensorProxy {
 protected:
   using RetTypeProxy = typename _RetType::proxy;
 
   constexpr TensorProxy(T * data, UInt m, UInt n, UInt p) {
     DimHelper<ndim>::setDims(m, n, p, this->n);
     this->values = data;
   }
 
 #ifndef SWIG
   template <class Other,
             typename = std::enable_if_t<
                 tensors::is_copyable<TensorProxy, Other>::value>>
   explicit TensorProxy(const Other & other) {
     this->values = other.storage();
     for (UInt i = 0; i < ndim; ++i)
       this->n[i] = other.size(i);
   }
 #endif
 public:
   using RetType = _RetType;
 
   UInt size(UInt i) const {
     AKANTU_DEBUG_ASSERT(i < ndim,
                         "This tensor has only " << ndim << " dimensions, not "
                                                 << (i + 1));
     return n[i];
   }
 
   inline UInt size() const {
     UInt _size = 1;
     for (UInt d = 0; d < ndim; ++d)
       _size *= this->n[d];
     return _size;
   }
 
   T * storage() const { return values; }
 
 #ifndef SWIG
   template <class Other,
             typename = std::enable_if_t<
                 tensors::is_copyable<TensorProxy, Other>::value>>
   inline TensorProxy & operator=(const Other & other) {
     AKANTU_DEBUG_ASSERT(
         other.size() == this->size(),
         "You are trying to copy two tensors with different sizes");
     memcpy(this->values, other.storage(), this->size() * sizeof(T));
     return *this;
   }
 #endif
   // template <class Other, typename = std::enable_if_t<
   //                          tensors::is_copyable<TensorProxy, Other>::value>>
   // inline TensorProxy & operator=(const Other && other) {
   //   AKANTU_DEBUG_ASSERT(
   //       other.size() == this->size(),
   //       "You are trying to copy two tensors with different sizes");
   //   memcpy(this->values, other.storage(), this->size() * sizeof(T));
   //   return *this;
   // }
 
   template <typename O> inline RetTypeProxy & operator*=(const O & o) {
     RetType(*this) *= o;
     return static_cast<RetTypeProxy &>(*this);
   }
 
   template <typename O> inline RetTypeProxy & operator/=(const O & o) {
     RetType(*this) /= o;
     return static_cast<RetTypeProxy &>(*this);
   }
 
 protected:
   T * values;
   UInt n[ndim];
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T> class VectorProxy : public TensorProxy<T, 1, Vector<T>> {
   using parent = TensorProxy<T, 1, Vector<T>>;
   using type = Vector<T>;
 
 public:
   constexpr VectorProxy(T * data, UInt n) : parent(data, n, 0, 0) {}
   template <class Other> explicit VectorProxy(Other & src) : parent(src) {}
 
   /* ---------------------------------------------------------------------- */
   template <class Other>
   inline VectorProxy<T> & operator=(const Other & other) {
     parent::operator=(other);
     return *this;
   }
 
   // inline VectorProxy<T> & operator=(const VectorProxy && other) {
   //   parent::operator=(other);
   //   return *this;
   // }
 
   /* ------------------------------------------------------------------------ */
   T & operator()(UInt index) { return this->values[index]; };
   const T & operator()(UInt index) const { return this->values[index]; };
 };
 
 template <typename T> class MatrixProxy : public TensorProxy<T, 2, Matrix<T>> {
   using parent = TensorProxy<T, 2, Matrix<T>>;
   using type = Matrix<T>;
 
 public:
   MatrixProxy(T * data, UInt m, UInt n) : parent(data, m, n, 0) {}
   template <class Other> explicit MatrixProxy(Other & src) : parent(src) {}
 
   /* ---------------------------------------------------------------------- */
   template <class Other>
   inline MatrixProxy<T> & operator=(const Other & other) {
     parent::operator=(other);
     return *this;
   }
 };
 
 template <typename T>
 class Tensor3Proxy : public TensorProxy<T, 3, Tensor3<T>> {
   using parent = TensorProxy<T, 3, Tensor3<T>>;
   using type = Tensor3<T>;
 
 public:
   Tensor3Proxy(const T * data, UInt m, UInt n, UInt k)
       : parent(data, m, n, k) {}
   Tensor3Proxy(const Tensor3Proxy & src) : parent(src) {}
   Tensor3Proxy(const Tensor3<T> & src) : parent(src) {}
 
   /* ---------------------------------------------------------------------- */
   template <class Other>
   inline Tensor3Proxy<T> & operator=(const Other & other) {
     parent::operator=(other);
     return *this;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 /* Tensor base class                                                          */
 /* -------------------------------------------------------------------------- */
 template <typename T, UInt ndim, class RetType>
 class TensorStorage : public TensorTrait {
 public:
   using value_type = T;
 
   friend class Array<T>;
 
 protected:
   template <class TensorType> void copySize(const TensorType & src) {
     for (UInt d = 0; d < ndim; ++d)
       this->n[d] = src.size(d);
     this->_size = src.size();
   }
 
   TensorStorage() : values(nullptr) {
     for (UInt d = 0; d < ndim; ++d)
       this->n[d] = 0;
     _size = 0;
   }
 
   TensorStorage(const TensorProxy<T, ndim, RetType> & proxy) {
     this->copySize(proxy);
     this->values = proxy.storage();
     this->wrapped = true;
   }
 
 public:
   TensorStorage(const TensorStorage & src) = delete;
 
   TensorStorage(const TensorStorage & src, bool deep_copy) : values(nullptr) {
     if (deep_copy)
       this->deepCopy(src);
     else
       this->shallowCopy(src);
   }
 
 protected:
   TensorStorage(UInt m, UInt n, UInt p, const T & def) {
     static_assert(std::is_trivially_constructible<T>{},
                   "Cannot create a tensor on non trivial types");
     DimHelper<ndim>::setDims(m, n, p, this->n);
 
     this->computeSize();
     this->values = new T[this->_size];
     this->set(def);
     this->wrapped = false;
   }
 
   TensorStorage(T * data, UInt m, UInt n, UInt p) {
     DimHelper<ndim>::setDims(m, n, p, this->n);
 
     this->computeSize();
     this->values = data;
     this->wrapped = true;
   }
 
 public:
   /* ------------------------------------------------------------------------ */
   template <class TensorType> inline void shallowCopy(const TensorType & src) {
     this->copySize(src);
     if (!this->wrapped)
       delete[] this->values;
     this->values = src.storage();
     this->wrapped = true;
   }
 
   /* ------------------------------------------------------------------------ */
   template <class TensorType> inline void deepCopy(const TensorType & src) {
     this->copySize(src);
 
     if (!this->wrapped)
       delete[] this->values;
 
     static_assert(std::is_trivially_constructible<T>{},
                   "Cannot create a tensor on non trivial types");
     this->values = new T[this->_size];
 
     static_assert(std::is_trivially_copyable<T>{},
                   "Cannot copy a tensor on non trivial types");
     memcpy((void *)this->values, (void *)src.storage(),
            this->_size * sizeof(T));
 
     this->wrapped = false;
   }
 
   virtual ~TensorStorage() {
     if (!this->wrapped)
       delete[] this->values;
   }
 
   /* ------------------------------------------------------------------------ */
   inline TensorStorage & operator=(const TensorStorage & src) {
     return this->operator=(dynamic_cast<RetType &>(src));
   }
 
   /* ------------------------------------------------------------------------ */
   inline TensorStorage & operator=(const RetType & src) {
     if (this != &src) {
       if (this->wrapped) {
         static_assert(std::is_trivially_copyable<T>{},
                       "Cannot copy a tensor on non trivial types");
         // this test is not sufficient for Tensor of order higher than 1
         AKANTU_DEBUG_ASSERT(this->_size == src.size(),
                             "Tensors of different size");
         memcpy((void *)this->values, (void *)src.storage(),
                this->_size * sizeof(T));
       } else {
         deepCopy(src);
       }
     }
     return *this;
   }
 
   /* ------------------------------------------------------------------------ */
   template <class R>
   inline RetType & operator+=(const TensorStorage<T, ndim, R> & other) {
     T * a = this->storage();
     T * b = other.storage();
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be subtracted");
     for (UInt i = 0; i < _size; ++i)
       *(a++) += *(b++);
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   template <class R>
   inline RetType & operator-=(const TensorStorage<T, ndim, R> & other) {
     T * a = this->storage();
     T * b = other.storage();
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be subtracted");
     for (UInt i = 0; i < _size; ++i)
       *(a++) -= *(b++);
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   inline RetType & operator+=(const T & x) {
     T * a = this->values;
     for (UInt i = 0; i < _size; ++i)
       *(a++) += x;
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   inline RetType & operator-=(const T & x) {
     T * a = this->values;
     for (UInt i = 0; i < _size; ++i)
       *(a++) -= x;
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   inline RetType & operator*=(const T & x) {
     T * a = this->storage();
     for (UInt i = 0; i < _size; ++i)
       *(a++) *= x;
     return *(static_cast<RetType *>(this));
   }
 
   /* ---------------------------------------------------------------------- */
   inline RetType & operator/=(const T & x) {
     T * a = this->values;
     for (UInt i = 0; i < _size; ++i)
       *(a++) /= x;
     return *(static_cast<RetType *>(this));
   }
 
   /// Y = \alpha X + Y
   inline RetType & aXplusY(const TensorStorage & other, const T & alpha = 1.) {
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be subtracted");
 
     Math::aXplusY(this->_size, alpha, other.storage(), this->storage());
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   T * storage() const { return values; }
   UInt size() const { return _size; }
   UInt size(UInt i) const {
     AKANTU_DEBUG_ASSERT(i < ndim,
                         "This tensor has only " << ndim << " dimensions, not "
                                                 << (i + 1));
     return n[i];
   };
   /* ------------------------------------------------------------------------ */
   inline void clear() { memset(values, 0, _size * sizeof(T)); };
   inline void set(const T & t) { std::fill_n(values, _size, t); };
 
   template <class TensorType> inline void copy(const TensorType & other) {
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be copied");
     memcpy(values, other.storage(), _size * sizeof(T));
   }
 
   bool isWrapped() const { return this->wrapped; }
 
 protected:
   inline void computeSize() {
     _size = 1;
     for (UInt d = 0; d < ndim; ++d)
       _size *= this->n[d];
   }
 
 protected:
   template <typename R, NormType norm_type> struct NormHelper {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it)
         _norm += std::pow(std::abs(*it), norm_type);
       return std::pow(_norm, 1. / norm_type);
     }
   };
 
   template <typename R> struct NormHelper<R, L_1> {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it)
         _norm += std::abs(*it);
       return _norm;
     }
   };
 
   template <typename R> struct NormHelper<R, L_2> {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it)
         _norm += *it * *it;
       return sqrt(_norm);
     }
   };
 
   template <typename R> struct NormHelper<R, L_inf> {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it)
         _norm = std::max(std::abs(*it), _norm);
       return _norm;
     }
   };
 
 public:
   /*----------------------------------------------------------------------- */
   /// "Entrywise" norm norm<L_p> @f[ \|\boldsymbol{T}\|_p = \left(
   /// \sum_i^{n[0]}\sum_j^{n[1]}\sum_k^{n[2]} |T_{ijk}|^p \right)^{\frac{1}{p}}
   /// @f]
   template <NormType norm_type> inline T norm() const {
     return NormHelper<T, norm_type>::norm(*this);
   }
 
 protected:
   UInt n[ndim];
   UInt _size;
   T * values;
   bool wrapped{false};
 };
 
 /* -------------------------------------------------------------------------- */
 /* Vector                                                                     */
 /* -------------------------------------------------------------------------- */
 template <typename T> class Vector : public TensorStorage<T, 1, Vector<T>> {
   using parent = TensorStorage<T, 1, Vector<T>>;
 
 public:
   using value_type = typename parent::value_type;
   using proxy = VectorProxy<T>;
 
 public:
   Vector() : parent() {}
   explicit Vector(UInt n, const T & def = T()) : parent(n, 0, 0, def) {}
   Vector(T * data, UInt n) : parent(data, n, 0, 0) {}
   Vector(const Vector & src, bool deep_copy = true) : parent(src, deep_copy) {}
   Vector(const TensorProxy<T, 1, Vector> & src) : parent(src) {}
 
   Vector(std::initializer_list<T> list) : parent(list.size(), 0, 0, T()) {
     UInt i = 0;
     for (auto val : list) {
       operator()(i++) = val;
     }
   }
 
 public:
   ~Vector() override = default;
 
   /* ------------------------------------------------------------------------ */
   inline Vector & operator=(const Vector & src) {
     parent::operator=(src);
     return *this;
   }
 
   /* ------------------------------------------------------------------------ */
   inline T & operator()(UInt i) {
     AKANTU_DEBUG_ASSERT((i < this->n[0]),
                         "Access out of the vector! "
                             << "Index (" << i
                             << ") is out of the vector of size (" << this->n[0]
                             << ")");
     return *(this->values + i);
   }
 
   inline const T & operator()(UInt i) const {
     AKANTU_DEBUG_ASSERT((i < this->n[0]),
                         "Access out of the vector! "
                             << "Index (" << i
                             << ") is out of the vector of size (" << this->n[0]
                             << ")");
     return *(this->values + i);
   }
 
   inline T & operator[](UInt i) { return this->operator()(i); }
   inline const T & operator[](UInt i) const { return this->operator()(i); }
 
   /* ------------------------------------------------------------------------ */
   inline Vector<T> & operator*=(Real x) { return parent::operator*=(x); }
   inline Vector<T> & operator/=(Real x) { return parent::operator/=(x); }
   /* ------------------------------------------------------------------------ */
   inline Vector<T> & operator*=(const Vector<T> & vect) {
     T * a = this->storage();
     T * b = vect.storage();
     for (UInt i = 0; i < this->_size; ++i)
       *(a++) *= *(b++);
     return *this;
   }
 
   /* ------------------------------------------------------------------------ */
   inline Real dot(const Vector<T> & vect) const {
     return Math::vectorDot(this->values, vect.storage(), this->_size);
   }
 
   /* ------------------------------------------------------------------------ */
   inline Real mean() const {
     Real mean = 0;
     T * a = this->storage();
     for (UInt i = 0; i < this->_size; ++i)
       mean += *(a++);
     return mean / this->_size;
   }
 
   /* ------------------------------------------------------------------------ */
   inline Vector & crossProduct(const Vector<T> & v1, const Vector<T> & v2) {
     AKANTU_DEBUG_ASSERT(this->size() == 3,
                         "crossProduct is only defined in 3D (n=" << this->size()
                                                                  << ")");
     AKANTU_DEBUG_ASSERT(
         this->size() == v1.size() && this->size() == v2.size(),
         "crossProduct is not a valid operation non matching size vectors");
     Math::vectorProduct3(v1.storage(), v2.storage(), this->values);
     return *this;
   }
 
   inline Vector crossProduct(const Vector<T> & v) {
     Vector<T> tmp(this->size());
     tmp.crossProduct(*this, v);
     return tmp;
   }
 
   /* ------------------------------------------------------------------------ */
   inline void solve(const Matrix<T> & A, const Vector<T> & b) {
     AKANTU_DEBUG_ASSERT(
         this->size() == A.rows() && this->_size == A.cols(),
         "The size of the solution vector mismatches the size of the matrix");
     AKANTU_DEBUG_ASSERT(
         this->_size == b._size,
         "The rhs vector has a mismatch in size with the matrix");
     Math::solve(this->_size, A.storage(), this->values, b.storage());
   }
 
   /* ------------------------------------------------------------------------ */
   template <bool tr_A>
   inline void mul(const Matrix<T> & A, const Vector<T> & x, Real alpha = 1.0);
   /* ------------------------------------------------------------------------ */
   inline Real norm() const { return parent::template norm<L_2>(); }
 
   template <NormType nt> inline Real norm() const {
     return parent::template norm<nt>();
   }
 
   /* ------------------------------------------------------------------------ */
   inline Vector<Real> & normalize() {
     Real n = norm();
     operator/=(n);
     return *this;
   }
 
   /* ------------------------------------------------------------------------ */
   /// norm of (*this - x)
   inline Real distance(const Vector<T> & y) const {
     Real * vx = this->values;
     Real * vy = y.storage();
     Real sum_2 = 0;
     for (UInt i = 0; i < this->_size; ++i, ++vx, ++vy)
       sum_2 += (*vx - *vy) * (*vx - *vy);
     return sqrt(sum_2);
   }
 
   /* ------------------------------------------------------------------------ */
   inline bool equal(const Vector<T> & v,
                     Real tolerance = Math::getTolerance()) const {
     T * a = this->storage();
     T * b = v.storage();
     UInt i = 0;
     while (i < this->_size && (std::abs(*(a++) - *(b++)) < tolerance))
       ++i;
     return i == this->_size;
   }
 
   /* ------------------------------------------------------------------------ */
   inline short compare(const Vector<T> & v,
                        Real tolerance = Math::getTolerance()) const {
     T * a = this->storage();
     T * b = v.storage();
     for (UInt i(0); i < this->_size; ++i, ++a, ++b) {
       if (std::abs(*a - *b) > tolerance)
         return (((*a - *b) > tolerance) ? 1 : -1);
     }
     return 0;
   }
 
   /* ------------------------------------------------------------------------ */
   inline bool operator==(const Vector<T> & v) const { return equal(v); }
   inline bool operator!=(const Vector<T> & v) const { return !operator==(v); }
   inline bool operator<(const Vector<T> & v) const { return compare(v) == -1; }
   inline bool operator>(const Vector<T> & v) const { return compare(v) == 1; }
 
   /* ------------------------------------------------------------------------ */
   /// function to print the containt of the class
   virtual void printself(std::ostream & stream, int indent = 0) const {
     std::string space;
     for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
       ;
 
     stream << "[";
     for (UInt i = 0; i < this->_size; ++i) {
       if (i != 0)
         stream << ", ";
       stream << this->values[i];
     }
     stream << "]";
   }
 
   //  friend class ::akantu::Array<T>;
 };
 
 using RVector = Vector<Real>;
 
 /* ------------------------------------------------------------------------ */
 template <>
 inline bool Vector<UInt>::equal(const Vector<UInt> & v,
                                 __attribute__((unused)) Real tolerance) const {
   UInt * a = this->storage();
   UInt * b = v.storage();
   UInt i = 0;
   while (i < this->_size && (*(a++) == *(b++)))
     ++i;
   return i == this->_size;
 }
 
 /* ------------------------------------------------------------------------ */
 /* Matrix                                                                   */
 /* ------------------------------------------------------------------------ */
 template <typename T> class Matrix : public TensorStorage<T, 2, Matrix<T>> {
   using parent = TensorStorage<T, 2, Matrix<T>>;
 
 public:
   using value_type = typename parent::value_type;
   using proxy = MatrixProxy<T>;
 
 public:
   Matrix() : parent() {}
   Matrix(UInt m, UInt n, const T & def = T()) : parent(m, n, 0, def) {}
   Matrix(T * data, UInt m, UInt n) : parent(data, m, n, 0) {}
   Matrix(const Matrix & src, bool deep_copy = true) : parent(src, deep_copy) {}
   Matrix(const MatrixProxy<T> & src) : parent(src) {}
   Matrix(std::initializer_list<std::initializer_list<T>> list) {
     static_assert(std::is_trivially_copyable<T>{},
                   "Cannot create a tensor on non trivial types");
     std::size_t n = 0;
     std::size_t m = list.size();
     for (auto row : list) {
       n = std::max(n, row.size());
     }
 
     DimHelper<2>::setDims(m, n, 0, this->n);
     this->computeSize();
     this->values = new T[this->_size];
     this->set(0);
 
     UInt i = 0, j = 0;
     for (auto & row : list) {
       for (auto & val : row) {
         at(i, j++) = val;
       }
       ++i;
       j = 0;
     }
   }
 
   ~Matrix() override = default;
   /* ------------------------------------------------------------------------ */
   inline Matrix & operator=(const Matrix & src) {
     parent::operator=(src);
     return *this;
   }
 
 public:
   /* ---------------------------------------------------------------------- */
   UInt rows() const { return this->n[0]; }
   UInt cols() const { return this->n[1]; }
 
   /* ---------------------------------------------------------------------- */
   inline T & at(UInt i, UInt j) {
     AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])),
                         "Access out of the matrix! "
                             << "Index (" << i << ", " << j
                             << ") is out of the matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return *(this->values + i + j * this->n[0]);
   }
 
   inline const T & at(UInt i, UInt j) const {
     AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])),
                         "Access out of the matrix! "
                             << "Index (" << i << ", " << j
                             << ") is out of the matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return *(this->values + i + j * this->n[0]);
   }
 
   /* ------------------------------------------------------------------------ */
   inline T & operator()(UInt i, UInt j) { return this->at(i, j); }
   inline const T & operator()(UInt i, UInt j) const { return this->at(i, j); }
 
   /// give a line vector wrapped on the column i
   inline VectorProxy<T> operator()(UInt j) {
     AKANTU_DEBUG_ASSERT(j < this->n[1],
                         "Access out of the matrix! "
                             << "You are trying to access the column vector "
                             << j << " in a matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return VectorProxy<T>(this->values + j * this->n[0], this->n[0]);
   }
 
   inline const VectorProxy<T> operator()(UInt j) const {
     AKANTU_DEBUG_ASSERT(j < this->n[1],
                         "Access out of the matrix! "
                             << "You are trying to access the column vector "
                             << j << " in a matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return VectorProxy<T>(this->values + j * this->n[0], this->n[0]);
   }
 
-  inline void block(Matrix & block, UInt pos_i, UInt pos_j) {
+  inline void block(const Matrix & block, UInt pos_i, UInt pos_j) {
     AKANTU_DEBUG_ASSERT(pos_i + block.rows() <= rows(),
                         "The block size or position are not correct");
     AKANTU_DEBUG_ASSERT(pos_i + block.cols() <= cols(),
                         "The block size or position are not correct");
     for (UInt i = 0; i < block.rows(); ++i)
       for (UInt j = 0; j < block.cols(); ++j)
         this->at(i + pos_i, j + pos_j) = block(i, j);
   }
 
   inline Matrix block(UInt pos_i, UInt pos_j, UInt block_rows,
                       UInt block_cols) const {
     AKANTU_DEBUG_ASSERT(pos_i + block_rows <= rows(),
                         "The block size or position are not correct");
     AKANTU_DEBUG_ASSERT(pos_i + block_cols <= cols(),
                         "The block size or position are not correct");
     Matrix block(block_rows, block_cols);
     for (UInt i = 0; i < block_rows; ++i)
       for (UInt j = 0; j < block_cols; ++j)
         block(i, j) = this->at(i + pos_i, j + pos_j);
     return block;
   }
 
   inline T & operator[](UInt idx) { return *(this->values + idx); };
   inline const T & operator[](UInt idx) const { return *(this->values + idx); };
 
   /* ---------------------------------------------------------------------- */
   inline Matrix operator*(const Matrix & B) {
     Matrix C(this->rows(), B.cols());
     C.mul<false, false>(*this, B);
     return C;
   }
 
   /* ----------------------------------------------------------------------- */
   inline Matrix & operator*=(const T & x) { return parent::operator*=(x); }
 
   inline Matrix & operator*=(const Matrix & B) {
     Matrix C(*this);
     this->mul<false, false>(C, B);
     return *this;
   }
 
   /* ---------------------------------------------------------------------- */
   template <bool tr_A, bool tr_B>
   inline void mul(const Matrix & A, const Matrix & B, T alpha = 1.0) {
     UInt k = A.cols();
     if (tr_A)
       k = A.rows();
 
 #ifndef AKANTU_NDEBUG
     if (tr_B) {
       AKANTU_DEBUG_ASSERT(k == B.cols(),
                           "matrices to multiply have no fit dimensions");
       AKANTU_DEBUG_ASSERT(this->cols() == B.rows(),
                           "matrices to multiply have no fit dimensions");
     } else {
       AKANTU_DEBUG_ASSERT(k == B.rows(),
                           "matrices to multiply have no fit dimensions");
       AKANTU_DEBUG_ASSERT(this->cols() == B.cols(),
                           "matrices to multiply have no fit dimensions");
     }
     if (tr_A) {
       AKANTU_DEBUG_ASSERT(this->rows() == A.cols(),
                           "matrices to multiply have no fit dimensions");
     } else {
       AKANTU_DEBUG_ASSERT(this->rows() == A.rows(),
                           "matrices to multiply have no fit dimensions");
     }
 #endif // AKANTU_NDEBUG
 
     Math::matMul<tr_A, tr_B>(this->rows(), this->cols(), k, alpha, A.storage(),
                              B.storage(), 0., this->storage());
   }
 
   /* ---------------------------------------------------------------------- */
   inline void outerProduct(const Vector<T> & A, const Vector<T> & B) {
     AKANTU_DEBUG_ASSERT(
         A.size() == this->rows() && B.size() == this->cols(),
         "A and B are not compatible with the size of the matrix");
     for (UInt i = 0; i < this->rows(); ++i) {
       for (UInt j = 0; j < this->cols(); ++j) {
         this->values[i + j * this->rows()] += A[i] * B[j];
       }
     }
   }
 
 private:
   class EigenSorter {
   public:
     EigenSorter(const Vector<T> & eigs) : eigs(eigs) {}
 
     bool operator()(const UInt & a, const UInt & b) const {
       return (eigs(a) > eigs(b));
     }
 
   private:
     const Vector<T> & eigs;
   };
 
 public:
   /* ---------------------------------------------------------------------- */
   inline void eig(Vector<T> & eigenvalues, Matrix<T> & eigenvectors) const {
     AKANTU_DEBUG_ASSERT(this->cols() == this->rows(),
                         "eig is not a valid operation on a rectangular matrix");
     AKANTU_DEBUG_ASSERT(eigenvalues.size() == this->cols(),
                         "eigenvalues should be of size " << this->cols()
                                                          << ".");
 #ifndef AKANTU_NDEBUG
     if (eigenvectors.storage() != nullptr)
       AKANTU_DEBUG_ASSERT((eigenvectors.rows() == eigenvectors.cols()) &&
                               (eigenvectors.rows() == this->cols()),
                           "Eigenvectors needs to be a square matrix of size "
                               << this->cols() << " x " << this->cols() << ".");
 #endif
 
     Matrix<T> tmp = *this;
     Vector<T> tmp_eigs(eigenvalues.size());
     Matrix<T> tmp_eig_vects(eigenvectors.rows(), eigenvectors.cols());
 
     if (tmp_eig_vects.rows() == 0 || tmp_eig_vects.cols() == 0)
       Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage());
     else
       Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage(),
                       tmp_eig_vects.storage());
 
     Vector<UInt> perm(eigenvalues.size());
     for (UInt i = 0; i < perm.size(); ++i)
       perm(i) = i;
 
     std::sort(perm.storage(), perm.storage() + perm.size(),
               EigenSorter(tmp_eigs));
 
     for (UInt i = 0; i < perm.size(); ++i)
       eigenvalues(i) = tmp_eigs(perm(i));
 
     if (tmp_eig_vects.rows() != 0 && tmp_eig_vects.cols() != 0)
       for (UInt i = 0; i < perm.size(); ++i) {
         for (UInt j = 0; j < eigenvectors.rows(); ++j) {
           eigenvectors(j, i) = tmp_eig_vects(j, perm(i));
         }
       }
   }
 
   /* ---------------------------------------------------------------------- */
   inline void eig(Vector<T> & eigenvalues) const {
     Matrix<T> empty;
     eig(eigenvalues, empty);
   }
 
   /* ---------------------------------------------------------------------- */
   inline void eye(T alpha = 1.) {
     AKANTU_DEBUG_ASSERT(this->cols() == this->rows(),
                         "eye is not a valid operation on a rectangular matrix");
     this->clear();
     for (UInt i = 0; i < this->cols(); ++i) {
       this->values[i + i * this->rows()] = alpha;
     }
   }
 
   /* ---------------------------------------------------------------------- */
   static inline Matrix<T> eye(UInt m, T alpha = 1.) {
     Matrix<T> tmp(m, m);
     tmp.eye(alpha);
     return tmp;
   }
 
   /* ---------------------------------------------------------------------- */
   inline T trace() const {
     AKANTU_DEBUG_ASSERT(
         this->cols() == this->rows(),
         "trace is not a valid operation on a rectangular matrix");
     T trace = 0.;
     for (UInt i = 0; i < this->rows(); ++i) {
       trace += this->values[i + i * this->rows()];
     }
     return trace;
   }
 
   /* ---------------------------------------------------------------------- */
   inline Matrix transpose() const {
     Matrix tmp(this->cols(), this->rows());
     for (UInt i = 0; i < this->rows(); ++i) {
       for (UInt j = 0; j < this->cols(); ++j) {
         tmp(j, i) = operator()(i, j);
       }
     }
     return tmp;
   }
 
   /* ---------------------------------------------------------------------- */
   inline void inverse(const Matrix & A) {
     AKANTU_DEBUG_ASSERT(A.cols() == A.rows(),
                         "inv is not a valid operation on a rectangular matrix");
     AKANTU_DEBUG_ASSERT(this->cols() == A.cols(),
                         "the matrix should have the same size as its inverse");
 
     if (this->cols() == 1)
       *this->values = 1. / *A.storage();
     else if (this->cols() == 2)
       Math::inv2(A.storage(), this->values);
     else if (this->cols() == 3)
       Math::inv3(A.storage(), this->values);
     else
       Math::inv(this->cols(), A.storage(), this->values);
   }
 
   inline Matrix inverse() {
     Matrix inv(this->rows(), this->cols());
     inv.inverse(*this);
     return inv;
   }
 
   /* --------------------------------------------------------------------- */
   inline T det() const {
     AKANTU_DEBUG_ASSERT(this->cols() == this->rows(),
                         "inv is not a valid operation on a rectangular matrix");
     if (this->cols() == 1)
       return *(this->values);
     else if (this->cols() == 2)
       return Math::det2(this->values);
     else if (this->cols() == 3)
       return Math::det3(this->values);
     else
       return Math::det(this->cols(), this->values);
   }
 
   /* --------------------------------------------------------------------- */
   inline T doubleDot(const Matrix<T> & other) const {
     AKANTU_DEBUG_ASSERT(
         this->cols() == this->rows(),
         "doubleDot is not a valid operation on a rectangular matrix");
     if (this->cols() == 1)
       return *(this->values) * *(other.storage());
     else if (this->cols() == 2)
       return Math::matrixDoubleDot22(this->values, other.storage());
     else if (this->cols() == 3)
       return Math::matrixDoubleDot33(this->values, other.storage());
     else
       AKANTU_DEBUG_ERROR("doubleDot is not defined for other spatial dimensions"
                          << " than 1, 2 or 3.");
     return T();
   }
 
   /* ---------------------------------------------------------------------- */
   /// function to print the containt of the class
   virtual void printself(std::ostream & stream, int indent = 0) const {
     std::string space;
     for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
       ;
 
     stream << "[";
     for (UInt i = 0; i < this->n[0]; ++i) {
       if (i != 0)
         stream << ", ";
       stream << "[";
       for (UInt j = 0; j < this->n[1]; ++j) {
         if (j != 0)
           stream << ", ";
         stream << operator()(i, j);
       }
       stream << "]";
     }
     stream << "]";
   };
 };
 
 /* ------------------------------------------------------------------------ */
 template <typename T>
 template <bool tr_A>
 inline void Vector<T>::mul(const Matrix<T> & A, const Vector<T> & x,
                            Real alpha) {
 #ifndef AKANTU_NDEBUG
   UInt n = x.size();
   if (tr_A) {
     AKANTU_DEBUG_ASSERT(n == A.rows(),
                         "matrix and vector to multiply have no fit dimensions");
     AKANTU_DEBUG_ASSERT(this->size() == A.cols(),
                         "matrix and vector to multiply have no fit dimensions");
   } else {
     AKANTU_DEBUG_ASSERT(n == A.cols(),
                         "matrix and vector to multiply have no fit dimensions");
     AKANTU_DEBUG_ASSERT(this->size() == A.rows(),
                         "matrix and vector to multiply have no fit dimensions");
   }
 #endif
   Math::matVectMul<tr_A>(A.rows(), A.cols(), alpha, A.storage(), x.storage(),
                          0., this->storage());
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline std::ostream & operator<<(std::ostream & stream,
                                  const Matrix<T> & _this) {
   _this.printself(stream);
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline std::ostream & operator<<(std::ostream & stream,
                                  const Vector<T> & _this) {
   _this.printself(stream);
   return stream;
 }
 
 /* ------------------------------------------------------------------------ */
 /* Tensor3                                                                  */
 /* ------------------------------------------------------------------------ */
 template <typename T> class Tensor3 : public TensorStorage<T, 3, Tensor3<T>> {
   using parent = TensorStorage<T, 3, Tensor3<T>>;
 
 public:
   using value_type = typename parent::value_type;
   using proxy = Tensor3Proxy<T>;
 
 public:
   Tensor3() : parent(){};
 
   Tensor3(UInt m, UInt n, UInt p, const T & def = T()) : parent(m, n, p, def) {}
 
   Tensor3(T * data, UInt m, UInt n, UInt p) : parent(data, m, n, p) {}
 
   Tensor3(const Tensor3 & src, bool deep_copy = true)
       : parent(src, deep_copy) {}
 
   Tensor3(const proxy & src) : parent(src) {}
 
 public:
   /* ------------------------------------------------------------------------ */
   inline Tensor3 & operator=(const Tensor3 & src) {
     parent::operator=(src);
     return *this;
   }
 
   /* ---------------------------------------------------------------------- */
   inline T & operator()(UInt i, UInt j, UInt k) {
     AKANTU_DEBUG_ASSERT(
         (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]),
         "Access out of the tensor3! "
             << "You are trying to access the element "
             << "(" << i << ", " << j << ", " << k << ") in a tensor of size ("
             << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")");
     return *(this->values + (k * this->n[0] + i) * this->n[1] + j);
   }
 
   inline const T & operator()(UInt i, UInt j, UInt k) const {
     AKANTU_DEBUG_ASSERT(
         (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]),
         "Access out of the tensor3! "
             << "You are trying to access the element "
             << "(" << i << ", " << j << ", " << k << ") in a tensor of size ("
             << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")");
     return *(this->values + (k * this->n[0] + i) * this->n[1] + j);
   }
 
   inline MatrixProxy<T> operator()(UInt k) {
     AKANTU_DEBUG_ASSERT((k < this->n[2]),
                         "Access out of the tensor3! "
                             << "You are trying to access the slice " << k
                             << " in a tensor3 of size (" << this->n[0] << ", "
                             << this->n[1] << ", " << this->n[2] << ")");
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 
   inline const MatrixProxy<T> operator()(UInt k) const {
     AKANTU_DEBUG_ASSERT((k < this->n[2]),
                         "Access out of the tensor3! "
                             << "You are trying to access the slice " << k
                             << " in a tensor3 of size (" << this->n[0] << ", "
                             << this->n[1] << ", " << this->n[2] << ")");
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 
   inline MatrixProxy<T> operator[](UInt k) {
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 
   inline const MatrixProxy<T> operator[](UInt k) const {
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 };
 
 /* -------------------------------------------------------------------------- */
 // support operations for the creation of other vectors
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Vector<T> operator*(const T & scalar, const Vector<T> & a) {
   Vector<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Vector<T> operator*(const Vector<T> & a, const T & scalar) {
   Vector<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Vector<T> operator/(const Vector<T> & a, const T & scalar) {
   Vector<T> r(a);
   r /= scalar;
   return r;
 }
 
 template <typename T>
 Vector<T> operator*(const Vector<T> & a, const Vector<T> & b) {
   Vector<T> r(a);
   r *= b;
   return r;
 }
 
 template <typename T>
 Vector<T> operator+(const Vector<T> & a, const Vector<T> & b) {
   Vector<T> r(a);
   r += b;
   return r;
 }
 
 template <typename T>
 Vector<T> operator-(const Vector<T> & a, const Vector<T> & b) {
   Vector<T> r(a);
   r -= b;
   return r;
 }
 
 template <typename T>
 Vector<T> operator*(const Matrix<T> & A, const Vector<T> & b) {
   Vector<T> r(b.size());
   r.template mul<false>(A, b);
   return r;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Matrix<T> operator*(const T & scalar, const Matrix<T> & a) {
   Matrix<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator*(const Matrix<T> & a, const T & scalar) {
   Matrix<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator/(const Matrix<T> & a, const T & scalar) {
   Matrix<T> r(a);
   r /= scalar;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator+(const Matrix<T> & a, const Matrix<T> & b) {
   Matrix<T> r(a);
   r += b;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator-(const Matrix<T> & a, const Matrix<T> & b) {
   Matrix<T> r(a);
   r -= b;
   return r;
 }
 
 } // namespace akantu
 
 #endif /* __AKANTU_AKA_TYPES_HH__ */
diff --git a/src/fe_engine/element_class_structural.hh b/src/fe_engine/element_class_structural.hh
index 1e3a79b47..3dbefe93d 100644
--- a/src/fe_engine/element_class_structural.hh
+++ b/src/fe_engine/element_class_structural.hh
@@ -1,277 +1,250 @@
 /**
  * @file   element_class_structural.hh
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Thu Feb 21 2013
  * @date last modification: Thu Oct 22 2015
  *
  * @brief  Specialization of the element classes for structural elements
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "element_class.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__
 #define __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__
 
 namespace akantu {
 
 /// Macro to generate the InterpolationProperty structures for different
 /// interpolation types
 #define AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(                  \
-    itp_type, itp_geom_type, ndof, nb_stress)                                  \
+    itp_type, itp_geom_type, ndof, nb_stress, nb_dnds_cols)                    \
   template <> struct InterpolationProperty<itp_type> {                         \
     static const InterpolationKind kind{_itk_structural};                      \
     static const UInt nb_nodes_per_element{                                    \
         InterpolationProperty<itp_geom_type>::nb_nodes_per_element};           \
     static const InterpolationType itp_geometry_type{itp_geom_type};           \
     static const UInt natural_space_dimension{                                 \
         InterpolationProperty<itp_geom_type>::natural_space_dimension};        \
     static const UInt nb_degree_of_freedom{ndof};                              \
     static const UInt nb_stress_components{nb_stress};                         \
+    static const UInt dnds_columns{nb_dnds_cols};                              \
   }
 
 /* -------------------------------------------------------------------------- */
 template <InterpolationType interpolation_type>
 class InterpolationElement<interpolation_type, _itk_structural> {
 public:
   using interpolation_property = InterpolationProperty<interpolation_type>;
 
   /// compute the shape values for a given set of points in natural coordinates
   static inline void computeShapes(const Matrix<Real> & natural_coord,
 				   const Matrix<Real> & real_coord,
                                    Tensor3<Real> & N) {
     for (UInt i = 0; i < natural_coord.cols(); ++i) {
       Matrix<Real> n_t = N(i);
       computeShapes(natural_coord(i), real_coord, n_t);
     }
   }
 
   /// compute the shape values for a given point in natural coordinates
   static inline void computeShapes(const Vector<Real> & natural_coord,
 				   const Matrix<Real> & real_coord,
                                    Matrix<Real> & N);
 
   /// compute shape derivatives (input is dxds) for a set of points
   static inline void computeShapeDerivatives(const Tensor3<Real> & Js,
                                              const Tensor3<Real> & DNDSs,
 					     const Matrix<Real> & R,
                                              Tensor3<Real> & Bs) {
     for (UInt i = 0; i < Js.size(2); ++i) {
       Matrix<Real> J = Js(i);
       Matrix<Real> DNDS = DNDSs(i);
-      Matrix<Real> DNDS_R(DNDS.rows(), DNDS.cols());
-      DNDS_R.mul<false, false>(DNDS, R);
-      Matrix<Real> B = Bs(i);
+      Matrix<Real> DNDX(DNDS.rows(), DNDS.cols());
       auto inv_J = J.inverse();
-      Matrix<Real> inv_J_full(DNDS.rows(), DNDS.rows());
-
-      // Gotta repeat J^-1 for each stress component
-      for (UInt k = 0, pos = 0; k < getNbStressComponents();
-           k++, pos += inv_J.rows()) {
-        inv_J_full.block(inv_J, pos, pos);
-      }
-
-      B.mul<false, false>(inv_J_full, DNDS_R);
+      DNDX.mul<false, false>(inv_J, DNDS);
+      Matrix<Real> B_R = Bs(i);
+      Matrix<Real> B(B_R.rows(), B_R.cols());
+      arrangeInVoigt(DNDX, B);
+      B_R.mul<false, false>(B, R);
     }
   }
 
   /**
    * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of
    * shape functions along with variation of natural coordinates on a given set
    * of points in natural coordinates
    */
   static inline void computeDNDS(const Matrix<Real> & natural_coord,
 				 const Matrix<Real> & real_coord,
                                  Tensor3<Real> & dnds) {
     for (UInt i = 0; i < natural_coord.cols(); ++i) {
       Matrix<Real> dnds_t = dnds(i);
       computeDNDS(natural_coord(i), real_coord, dnds_t);
     }
   }
 
   /**
    * compute @f$ B_{ij} = \frac{\partial N_j}{\partial S_i} @f$ the variation of
    * shape functions along with
    * variation of natural coordinates on a given point in natural
    * coordinates
    */
   static inline void computeDNDS(const Vector<Real> & natural_coord,
 				 const Matrix<Real> & real_coord,
                                  Matrix<Real> & dnds);
 
+  /**
+   * arrange B in Voigt notation from DNDS
+   */
+  static inline void arrangeInVoigt(const Matrix<Real> & dnds,
+				    Matrix<Real> & B) {
+    // Default implementation assumes dnds is already in Voigt notation
+    B.deepCopy(dnds);
+  }
+
 public:
   static AKANTU_GET_MACRO_NOT_CONST(
       NbNodesPerInterpolationElement,
       interpolation_property::nb_nodes_per_element, UInt);
 
   static AKANTU_GET_MACRO_NOT_CONST(
       ShapeSize, (interpolation_property::nb_nodes_per_element *
                   interpolation_property::nb_degree_of_freedom *
                   interpolation_property::nb_degree_of_freedom),
       UInt);
   static AKANTU_GET_MACRO_NOT_CONST(
       ShapeDerivativesSize, (interpolation_property::nb_nodes_per_element *
                              interpolation_property::nb_degree_of_freedom *
                              interpolation_property::nb_stress_components),
       UInt);
   static AKANTU_GET_MACRO_NOT_CONST(
       NaturalSpaceDimension, interpolation_property::natural_space_dimension,
       UInt);
   static AKANTU_GET_MACRO_NOT_CONST(
       NbDegreeOfFreedom, interpolation_property::nb_degree_of_freedom, UInt);
   static AKANTU_GET_MACRO_NOT_CONST(
       NbStressComponents, interpolation_property::nb_stress_components, UInt);
 };
 
 /// Macro to generate the element class structures for different structural
 /// element types
 /* -------------------------------------------------------------------------- */
 #define AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(                       \
     elem_type, geom_type, interp_type, parent_el_type, elem_kind, sp,          \
     gauss_int_type, min_int_order)                                             \
   template <> struct ElementClassProperty<elem_type> {                         \
     static const GeometricalType geometrical_type{geom_type};                  \
     static const InterpolationType interpolation_type{interp_type};            \
     static const ElementType parent_element_type{parent_el_type};              \
     static const ElementKind element_kind{elem_kind};                          \
     static const UInt spatial_dimension{sp};                                   \
     static const GaussIntegrationType gauss_integration_type{gauss_int_type};  \
     static const UInt polynomial_degree{min_int_order};                        \
   }
 
 /* -------------------------------------------------------------------------- */
 /* ElementClass for structural elements                                       */
 /* -------------------------------------------------------------------------- */
 template <ElementType element_type>
 class ElementClass<element_type, _ek_structural>
     : public GeometricalElement<
           ElementClassProperty<element_type>::geometrical_type>,
       public InterpolationElement<
           ElementClassProperty<element_type>::interpolation_type> {
 protected:
   using geometrical_element =
       GeometricalElement<ElementClassProperty<element_type>::geometrical_type>;
   using interpolation_element = InterpolationElement<
       ElementClassProperty<element_type>::interpolation_type>;
   using parent_element =
       ElementClass<ElementClassProperty<element_type>::parent_element_type>;
 
 public:
   static inline void
   computeRotationMatrix(Matrix<Real> & /*R*/, const Matrix<Real> & /*X*/,
                         const Vector<Real> & /*extra_normal*/) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// compute jacobian (or integration variable change factor) for a given point
-  static inline void computeJMat(const Matrix<Real> & DNDS,
+  static inline void computeJMat(const Vector<Real> & natural_coords,
                                  const Matrix<Real> & Xs, Matrix<Real> & J) {
-    auto nb_nodes = Xs.cols();
-    auto dim = Xs.rows();
-    auto nb_dof =
-        interpolation_element::interpolation_property::nb_degree_of_freedom;
-    Matrix<Real> B(dim, nb_nodes);
-    for (UInt s = 0; s < dim; ++s) {
-      for (UInt n = 0; n < nb_nodes; ++n) {
-        B(s, n) = DNDS(s, n * nb_dof + s);
-      }
-    }
-
-    J.mul<false, true>(B, Xs);
+    Matrix<Real> dnds(Xs.rows(), Xs.cols());
+    parent_element::computeDNDS(natural_coords, dnds);
+    J.mul<false, true>(dnds, Xs);
   }
 
-  static inline void computeJMat(const Tensor3<Real> & DNDSs,
+  static inline void computeJMat(const Matrix<Real> & natural_coords,
                                  const Matrix<Real> & Xs, Tensor3<Real> & Js) {
-    using itp = typename interpolation_element::interpolation_property;
-    auto nb_nodes = Xs.cols();
-    auto dim = Xs.rows();
-    auto nb_dof = itp::nb_degree_of_freedom;
-    Matrix<Real> B(dim, nb_nodes);
-
-    for (UInt i = 0; i < Xs.cols(); ++i) {
-      Matrix<Real> DNDS = DNDSs(i);
+    for (UInt i = 0 ; i < natural_coords.cols(); ++i) {
+      // because non-const l-value reference does not bind to r-value
       Matrix<Real> J = Js(i);
-
-      B.clear();
-      for (UInt s = 0; s < dim; ++s) {
-        for (UInt n = 0; n < nb_nodes; ++n) {
-          B(s, n) = DNDS(s, n * nb_dof + s);
-        }
-      }
-
-      parent_element::computeJMat(B, Xs, J);
-      // computeJMat(DNDS, Xs, J);
+      computeJMat(Vector<Real>(natural_coords(i)), Xs, J);
     }
   }
 
   static inline void computeJacobian(const Matrix<Real> & natural_coords,
                                      const Matrix<Real> & node_coords,
                                      Vector<Real> & jacobians) {
     using itp = typename interpolation_element::interpolation_property;
-    UInt nb_points = natural_coords.cols();
-    Matrix<Real> dnds(itp::natural_space_dimension, itp::nb_nodes_per_element);
-    Matrix<Real> J(natural_coords.rows(), itp::natural_space_dimension);
-
-    // Extract relevant first lines
-    auto x = node_coords.block(0, 0, itp::natural_space_dimension,
-                               itp::nb_nodes_per_element);
-
-    for (UInt p = 0; p < nb_points; ++p) {
-      Vector<Real> ncoord_p(natural_coords(p));
-      parent_element::computeDNDS(ncoord_p, dnds);
-      parent_element::computeJMat(dnds, x, J);
-      jacobians(p) = J.det();
+    Tensor3<Real> Js(itp::natural_space_dimension, itp::natural_space_dimension,
+                     natural_coords.cols());
+    computeJMat(natural_coords, node_coords, Js);
+    for (UInt i = 0; i < natural_coords.cols(); ++i) {
+      Matrix<Real> J = Js(i);
+      jacobians(i) = J.det();
     }
   }
 
   static inline void computeRotation(const Matrix<Real> & node_coords,
                                      Matrix<Real> & rotation);
 
 public:
   static AKANTU_GET_MACRO_NOT_CONST(Kind, _ek_structural, ElementKind);
   static AKANTU_GET_MACRO_NOT_CONST(P1ElementType, _not_defined, ElementType);
   static AKANTU_GET_MACRO_NOT_CONST(FacetType, _not_defined, ElementType);
   static constexpr auto getFacetType(__attribute__((unused)) UInt t = 0) {
     return _not_defined;
   }
   static constexpr AKANTU_GET_MACRO_NOT_CONST(
       SpatialDimension, ElementClassProperty<element_type>::spatial_dimension,
       UInt);
   static constexpr auto getFacetTypes() {
     return ElementClass<_not_defined>::getFacetTypes();
   }
 };
 
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 #include "element_classes/element_class_hermite_inline_impl.cc"
 /* keep order */
 #include "element_classes/element_class_bernoulli_beam_inline_impl.cc"
 #include "element_classes/element_class_kirchhoff_shell_inline_impl.cc"
 /* -------------------------------------------------------------------------- */
 
 #endif /* __AKANTU_ELEMENT_CLASS_STRUCTURAL_HH__ */
diff --git a/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc b/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc
index f7ca15021..407cb0af0 100644
--- a/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc
+++ b/src/fe_engine/element_classes/element_class_bernoulli_beam_inline_impl.cc
@@ -1,202 +1,222 @@
 /**
  * @file   element_class_bernoulli_beam_inline_impl.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Specialization of the element_class class for the type
  _bernoulli_beam_2
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  * @section DESCRIPTION
  *
  * @verbatim
    --x-----q1----|----q2-----x---> x
     -1          0            1
  @endverbatim
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "aka_static_if.hh"
 #include "element_class_structural.hh"
 //#include "aka_element_classes_info.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__
 #define __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__
 
 namespace akantu {
 /* -------------------------------------------------------------------------- */
 AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_bernoulli_beam_2,
                                                      _itp_lagrange_segment_2, 3,
-                                                     2);
+                                                     2, 6);
 
 AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_bernoulli_beam_3,
                                                      _itp_lagrange_segment_2, 6,
-                                                     4);
+                                                     4, 6);
 
 AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_bernoulli_beam_2,
                                                 _gt_segment_2,
                                                 _itp_bernoulli_beam_2,
                                                 _segment_2, _ek_structural, 2,
                                                 _git_segment, 3);
 
 AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_bernoulli_beam_3,
                                                 _gt_segment_2,
                                                 _itp_bernoulli_beam_3,
                                                 _segment_2, _ek_structural, 3,
                                                 _git_segment, 3);
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeShapes(
     const Vector<Real> & natural_coords, const Matrix<Real> & real_coord,
     Matrix<Real> & N) {
   Vector<Real> L(2);
   InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeShapes(
       natural_coords, L);
   Matrix<Real> H(2, 4);
   InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes(
       natural_coords, real_coord, H);
 
   // clang-format off
   //    u1   v1      t1      u2   v2      t2
   N = {{L(0), 0      , 0      , L(1), 0      , 0      },  // u
        {0   , H(0, 0), H(0, 1), 0   , H(0, 2), H(0, 3)},  // v
        {0   , H(1, 0), H(1, 1), 0   , H(1, 2), H(1, 3)}}; // theta
   // clang-format on
 }
 
 template <>
 inline void
 InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::computeShapes(
     const Vector<Real> & natural_coords, const Matrix<Real> & real_coord,
     Matrix<Real> & N) {
   Vector<Real> L(2);
   InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeShapes(
       natural_coords, L);
   Matrix<Real> H(2, 4);
   InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes(
       natural_coords, real_coord, H);
 
   // clang-format off
   //   u1    v1      w1      x1   y1      z1      u2   v2      w2      x2   y2      z2
   N = {{L(0), 0      , 0      , 0   , 0      , 0      , L(1), 0      , 0      , 0   , 0      , 0      },  // u
        {0   , H(0, 0), 0      , 0   , H(0, 1), 0      , 0   , H(0, 2), 0      , 0   , H(0, 3), 0      },  // v
        {0   , 0      , H(0, 0), 0   , 0      , H(0, 1), 0   , 0      , H(0, 2), 0   , 0      , H(0, 3)},  // w
        {0   , 0      , 0      , L(0), 0      , 0      , 0   , 0      , 0      , L(1), 0      , 0      },  // thetax
        {0   , H(1, 0), 0      , 0   , H(1, 1), 0      , 0   , H(1, 2), 0      , 0   , H(1, 3), 0      },  // thetay
        {0   , 0      , H(1, 0), 0   , 0      , H(1, 1), 0   , 0      , H(1, 2), 0   , 0      , H(1, 3)}}; // thetaz
   // clang-format on
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeDNDS(
     const Vector<Real> & natural_coords, const Matrix<Real> & real_coord,
-    Matrix<Real> & B) {
+    Matrix<Real> & dnds) {
   Matrix<Real> L(1, 2);
   InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeDNDS(
       natural_coords, L);
   Matrix<Real> H(1, 4);
   InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS(
       natural_coords, real_coord, H);
 
+  // Storing the derivatives in dnds
+  dnds.block(L, 0, 0);
+  dnds.block(H, 0, 2);
+}
+
+/* -------------------------------------------------------------------------- */
+template <>
+inline void
+InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::arrangeInVoigt(
+    const Matrix<Real> & dnds, Matrix<Real> & B) {
+  auto L = dnds.block(0, 0, 1, 2); // Lagrange shape derivatives
+  auto H = dnds.block(0, 2, 1, 4); // Hermite shape derivatives
   // clang-format off
-  //    u1      v1      t1      u2      v2      t2
-  B = {{L(0, 0), 0      , 0      , L(0, 1), 0      , 0      },   // epsilon
-       {0      , H(0, 0), H(0, 1), 0      , H(0, 2), H(0, 3)}};  // chi (curv.)
+  //    u1       v1       t1       u2       v2       t2
+  B = {{L(0, 0), 0,       0,       L(0, 1), 0,       0      },
+       {0,       H(0, 0), H(0, 1), 0,       H(0, 2), H(0, 3)}};
   // clang-format on
 }
 
+/* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::computeDNDS(
-									  const Vector<Real> & natural_coords, const Matrix<Real> & real_coord, Matrix<Real> & B) {
-  Matrix<Real> L(1, 2);
-  InterpolationElement<_itp_lagrange_segment_2, _itk_lagrangian>::computeDNDS(
-      natural_coords, L);
-  Matrix<Real> H(1, 4);
-  InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS(
-      natural_coords, real_coord, H);
+    const Vector<Real> & natural_coords, const Matrix<Real> & real_coord,
+    Matrix<Real> & dnds) {
+  InterpolationElement<_itp_bernoulli_beam_2, _itk_structural>::computeDNDS(
+      natural_coords, real_coord, dnds);
+}
+
+/* -------------------------------------------------------------------------- */
+template <>
+inline void
+InterpolationElement<_itp_bernoulli_beam_3, _itk_structural>::arrangeInVoigt(
+    const Matrix<Real> & dnds, Matrix<Real> & B) {
+  auto L = dnds.block(0, 0, 1, 2); // Lagrange shape derivatives
+  auto H = dnds.block(0, 2, 1, 4); // Hermite shape derivatives
+
   // clang-format off
   //    u1       v1       w1       x1       y1       z1       u2       v2       w2       x2       y2       z2
   B = {{L(0, 0), 0      , 0      , 0      , 0      , 0      , L(0, 1), 0      , 0      , 0      , 0      , 0      },  // eps
        {0      , H(0, 0), 0      , 0      , 0      , H(0, 1), 0      , H(0, 2), 0      , 0      , 0      , H(0, 3)},  // chi strong axis
        {0      , 0      ,-H(0, 0), 0      , H(0, 1), 0      , 0      , 0      ,-H(0, 2), 0      , H(0, 3), 0      },  // chi weak axis
        {0      , 0      , 0      , L(0, 0), 0      , 0      , 0      , 0      , 0      , L(0, 1), 0      , 0      }}; // chi torsion
   // clang-format on
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void ElementClass<_bernoulli_beam_2>::computeRotationMatrix(
     Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> &) {
   Vector<Real> x2 = X(1); // X2
   Vector<Real> x1 = X(0); // X1
 
   auto cs = (x2 - x1);
   cs.normalize();
 
   auto c = cs(0);
   auto s = cs(1);
 
   // clang-format off
   /// Definition of the rotation matrix
   R = {{ c,  s,  0.},
        {-s,  c,  0.},
        { 0., 0., 1.}};
   // clang-format on
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void ElementClass<_bernoulli_beam_3>::computeRotationMatrix(
     Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> & n) {
   Vector<Real> x2 = X(1); // X2
   Vector<Real> x1 = X(0); // X1
   auto dim = X.rows();
   auto x = (x2 - x1);
   x.normalize();
   auto x_n = x.crossProduct(n);
 
   Matrix<Real> Pe = {{1., 0., 0.}, {0., -1., 0.}, {0., 0., 1.}};
 
   Matrix<Real> Pg(dim, dim);
   Pg(0) = x;
   Pg(1) = x_n;
   Pg(2) = n;
 
   Pe *= Pg.inverse();
 
   R.clear();
   /// Definition of the rotation matrix
   for (UInt i = 0; i < dim; ++i)
     for (UInt j = 0; j < dim; ++j)
       R(i + dim, j + dim) = R(i, j) = Pe(i, j);
 }
 
 } // namespace akantu
 #endif /* __AKANTU_ELEMENT_CLASS_BERNOULLI_BEAM_INLINE_IMPL_CC__ */
diff --git a/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc b/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc
index ba268905d..8d79e01c5 100644
--- a/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc
+++ b/src/fe_engine/element_classes/element_class_hermite_inline_impl.cc
@@ -1,180 +1,180 @@
 /**
  * @file   element_class_hermite_inline_impl.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Specialization of the element_class class for the type
  _hermite
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  * @section DESCRIPTION
  *
  * @verbatim
    --x-----q1----|----q2-----x---> x
     -1          0            1
  @endverbatim
  *
  * @subsection shapes Shape functions
  * @f[
  *   \begin{array}{ll}
  *     M_1(\xi) &= 1/4(\xi^{3}/-3\xi+2)\\
  *     M_2(\xi) &= -1/4(\xi^{3}-3\xi-2)
  *   \end{array}
  *
  *   \begin{array}{ll}
  *     L_1(\xi) &= 1/4(\xi^{3}-\xi^{2}-\xi+1)\\
  *     L_2(\xi) &= 1/4(\xi^{3}+\xi^{2}-\xi-1)
  *   \end{array}
  *
  *   \begin{array}{ll}
  *     M'_1(\xi) &= 3/4(\xi^{2}-1)\\
  *     M'_2(\xi) &= -3/4(\xi^{2}-1)
  *   \end{array}
  *
  *   \begin{array}{ll}
  *     L'_1(\xi) &= 1/4(3\xi^{2}-2\xi-1)\\
  *     L'_2(\xi) &= 1/4(3\xi^{2}+2\xi-1)
  *   \end{array}
  *@f]
  *
  * @subsection dnds Shape derivatives
  *
  *@f[
  * \begin{array}{ll}
  *   N'_1(\xi) &= -1/2\\
  *   N'_2(\xi) &= 1/2
  * \end{array}]
  *
  * \begin{array}{ll}
  *   -M''_1(\xi) &= -3\xi/2\\
  *   -M''_2(\xi) &= 3\xi/2\\
  * \end{array}
  *
  * \begin{array}{ll}
  *   -L''_1(\xi) &= -1/2a(3\xi/a-1)\\
  *   -L''_2(\xi) &= -1/2a(3\xi/a+1)
  * \end{array}
  *@f]
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "aka_static_if.hh"
 #include "element_class_structural.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__
 #define __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__
 
 namespace akantu {
 /* -------------------------------------------------------------------------- */
 
 AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_hermite_2,
                                                      _itp_lagrange_segment_2, 2,
-                                                     1);
+                                                     1, 4);
 
 /* -------------------------------------------------------------------------- */
 
 namespace {
   namespace details {
     inline Real computeLength(const Matrix<Real> & real_coord) {
       Vector<Real> x1 = real_coord(0);
       Vector<Real> x2 = real_coord(1);
       return x1.distance(x2);
     }
 
     inline void computeShapes(const Vector<Real> & natural_coords, Real a, Matrix<Real> & N) {
       /// natural coordinate
       Real xi = natural_coords(0);
 
       // Cubic Hermite splines interpolating displacement
       auto M1 = 1. / 4. * Math::pow<2>(xi - 1) * (xi + 2);
       auto M2 = 1. / 4. * Math::pow<2>(xi + 1) * (2 - xi);
       auto L1 = a / 4. * Math::pow<2>(xi - 1) * (xi + 1);
       auto L2 = a / 4. * Math::pow<2>(xi + 1) * (xi - 1);
 
 #if 1 // Version where we also interpolate the rotations
       // Derivatives (with respect to x) of previous functions interpolating
       // rotations
       auto M1_ = 3. / (4. * a) * (xi * xi - 1);
       auto M2_ = 3. / (4. * a) * (1 - xi * xi);
       auto L1_ = 1 / 4. *
                  (3 * xi * xi - 2 * xi - 1);
       auto L2_ = 1 / 4. *
                  (3 * xi * xi + 2 * xi - 1);
 
       // clang-format off
       //    v1   t1   v2   t2
       N = {{M1 , L1 , M2 , L2},   // displacement interpolation
 	   {M1_, L1_, M2_, L2_}}; // rotation interpolation
       // clang-format on
 
 #else // Version where we only interpolate displacements
       // clang-format off
       //    v1  t1  v2  t2
       N = {{M1, L1, M2, L2}};
       // clang-format on
 #endif
     }
 
     /* ---------------------------------------------------------------------- */
 
     inline void computeDNDS(const Vector<Real> & natural_coords, Real a,
                      Matrix<Real> & B) {
       // natural coordinate
       Real xi = natural_coords(0);
       // Derivatives with respect to xi for rotations
       auto M1__ = 3. / 2. * xi;
       auto M2__ = 3. / 2. * (-xi);
       auto L1__ = a / 2. * (3 * xi - 1);
       auto L2__ = a / 2. * (3 * xi + 1);
 
       //    v1    t1    v2    t2
       B = {{M1__, L1__, M2__, L2__}}; // computing curvature : {chi} = [B]{d}
       B /= a; // to account for first order deriv w/r to x
     }
   } // namespace details
 } // namespace
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_hermite_2, _itk_structural>::computeShapes(
     const Vector<Real> & natural_coords, const Matrix<Real> & real_coord,
     Matrix<Real> & N) {
   auto L = details::computeLength(real_coord);
   details::computeShapes(natural_coords, L / 2, N);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void InterpolationElement<_itp_hermite_2, _itk_structural>::computeDNDS(
     const Vector<Real> & natural_coords, const Matrix<Real> & real_coord,
     Matrix<Real> & B) {
   auto L = details::computeLength(real_coord);
   details::computeDNDS(natural_coords, L / 2, B);
 }
 
 } // namespace akantu
 #endif /* __AKANTU_ELEMENT_CLASS_HERMITE_INLINE_IMPL_CC__ */
diff --git a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc
index 29f1760f7..4769bf237 100644
--- a/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc
+++ b/src/fe_engine/element_classes/element_class_kirchhoff_shell_inline_impl.cc
@@ -1,288 +1,211 @@
 /**
  * @file   element_class_kirchhoff_shell_inline_impl.cc
  *
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 04 2014
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Element class Kirchhoff Shell
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "element_class_structural.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__
 #define __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
-AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(_itp_discrete_kirchhoff_triangle_18,
-                                                     _itp_lagrange_triangle_3,
-                                                     6, 6);
-AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(_discrete_kirchhoff_triangle_18,
-                                                _gt_triangle_3,
-                                                _itp_discrete_kirchhoff_triangle_18,
-                                                _triangle_3, _ek_structural, 3,
-                                                _git_triangle, 2);
+AKANTU_DEFINE_STRUCTURAL_INTERPOLATION_TYPE_PROPERTY(
+    _itp_discrete_kirchhoff_triangle_18, _itp_lagrange_triangle_3, 6, 6, 21);
+AKANTU_DEFINE_STRUCTURAL_ELEMENT_CLASS_PROPERTY(
+    _discrete_kirchhoff_triangle_18, _gt_triangle_3,
+    _itp_discrete_kirchhoff_triangle_18, _triangle_3, _ek_structural, 3,
+    _git_triangle, 2);
+
+/* -------------------------------------------------------------------------- */
+namespace detail {
+  inline void computeBasisChangeMatrix(Matrix<Real> & P,
+                                       const Matrix<Real> & X) {
+    Vector<Real> X1 = X(0);
+    Vector<Real> X2 = X(1);
+    Vector<Real> X3 = X(2);
+
+    Vector<Real> a1 = X2 - X1;
+    Vector<Real> a2 = X3 - X1;
+
+    a1.normalize();
+    Vector<Real> e3 = a1.crossProduct(a2);
+    e3.normalize();
+    Vector<Real> e2 = e3.crossProduct(a1);
+
+    P(0) = a1;
+    P(1) = e2;
+    P(2) = e3;
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <>
+inline void
+ElementClass<_discrete_kirchhoff_triangle_18>::computeRotationMatrix(
+    Matrix<Real> & R, const Matrix<Real> & X, const Vector<Real> &) {
+  auto dim = X.rows();
+  Matrix<Real> P(dim, dim);
+  detail::computeBasisChangeMatrix(P, X);
+
+  R.clear();
+  for (UInt i = 0; i < dim; ++i)
+    for (UInt j = 0; j < dim; ++j)
+      R(i + dim, j + dim) = R(i, j) = P(j, i);
+}
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
 InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeShapes(
     const Vector<Real> & /*natural_coords*/,
-    const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*N*/) {
-//   // projected_coord (x1 x2 x3) (y1 y2 y3)
+    const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*N*/) {}
 
-#if 0
-  // natural coordinate
+/* -------------------------------------------------------------------------- */
+template <>
+inline void
+InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeDNDS(
+    const Vector<Real> & natural_coords, const Matrix<Real> & real_coordinates,
+    Matrix<Real> & B) {
+
+  auto dim = real_coordinates.cols();
+  Matrix<Real> P(dim, dim);
+  detail::computeBasisChangeMatrix(P, real_coordinates);
+  auto X = P * real_coordinates;
+  Vector<Real> X1 = X(0);
+  Vector<Real> X2 = X(1);
+  Vector<Real> X3 = X(2);
+
+  std::array<Vector<Real>, 3> A = {X2 - X1, X3 - X2, X1 - X3};
+  std::array<Real, 3> L, C, S;
+
+  // Setting all last coordinates to 0
+  std::for_each(A.begin(), A.end(), [](auto & a) { a(2) = 0; });
+  // Computing lengths
+  std::transform(A.begin(), A.end(), L.begin(),
+                 [](Vector<Real> & a) { return a.norm<L_2>(); });
+  // Computing cosines
+  std::transform(A.begin(), A.end(), L.begin(), C.begin(),
+                 [](Vector<Real> & a, Real & l) { return a(0) / l; });
+  // Computing sines
+  std::transform(A.begin(), A.end(), L.begin(), S.begin(),
+                 [](Vector<Real> & a, Real & l) { return a(1) / l; });
+
+  // Natural coordinates
   Real xi = natural_coords(0);
   Real eta = natural_coords(1);
 
-  Real x21 = projected_coord(0, 0) - projected_coord(0, 1); // x1-x2
-  Real x32 = projected_coord(0, 1) - projected_coord(0, 2);
-  Real x13 = projected_coord(0, 2) - projected_coord(0, 0);
-
-  Real y21 = projected_coord(1, 0) - projected_coord(1, 1); // y1-y2
-  Real y32 = projected_coord(1, 1) - projected_coord(1, 2);
-  Real y13 = projected_coord(1, 2) - projected_coord(1, 0);
-
-  /* Real x21=projected_coord(0,1)-projected_coord(0,0);
-  Real x32=projected_coord(0,2)-projected_coord(0,1);
-  Real x13=projected_coord(0,0)-projected_coord(0,2);
-
-  Real y21=projected_coord(1,1)-projected_coord(1,0);
-  Real y32=projected_coord(1,2)-projected_coord(1,1);
-  Real y13=projected_coord(1,0)-projected_coord(1,2);*/
-
-  // natural triangle side length
-  Real L4 = std::sqrt(x21 * x21 + y21 * y21);
-  Real L5 = std::sqrt(x32 * x32 + y32 * y32);
-  Real L6 = std::sqrt(x13 * x13 + y13 * y13);
-
-  // sinus and cosinus
-  Real C4 = x21 / L4; // 1.
-  Real C5 = x32 / L5; //-1./std::sqrt(2);
-  Real C6 = x13 / L6; // 0.
-  Real S4 = y21 / L4; // 0.;
-  Real S5 = y32 / L5; // 1./std::sqrt(2);
-  Real S6 = y13 / L6; //-1.;
-
-  Real N1 = 1. - xi - eta;
-  Real N2 = xi;
-  Real N3 = eta;
-
-  Real P4 = 4. * xi * (1. - xi - eta);
-  Real P5 = 4. * xi * eta;
-  Real P6 = 4. * eta * (1. - xi - eta);
-
-  Vector<Real> N0{N1, N2, N3};
-  Vector<Real> Nw2{-(1. / 8.) * P4 * L4 * C4 + (1. / 8.) * P6 * L6 * C6,
-                   -(1. / 8.) * P5 * L5 * C5 + (1. / 8.) * P4 * L4 * C4,
-                   -(1. / 8.) * P6 * L6 * C6 + (1. / 8.) * P5 * L5 * C5};
-  Vector<Real> Nw3{-(1. / 8.) * P4 * L4 * S4 + (1. / 8.) * P6 * L6 * S6,
-                   -(1. / 8.) * P5 * L5 * S5 + (1. / 8.) * P4 * L4 * S4,
-                   -(1. / 8.) * P6 * L6 * S6 + (1. / 8.) * P5 * L5 * S5};
-  Vector<Real> Nx1{3. / (2. * L4) * P4 * C4 - 3. / (2. * L6) * P6 * C6,
-                   3. / (2. * L5) * P5 * C5 - 3. / (2. * L4) * P4 * C4,
-                   3. / (2. * L6) * P6 * C6 - 3. / (2. * L5) * P5 * C5};
-  Vector<Real> Nx2{N1 - (3. / 4.) * P4 * C4 * C4 - (3. / 4.) * P6 * C6 * C6,
-                   N2 - (3. / 4.) * P5 * C5 * C5 - (3. / 4.) * P4 * C4 * C4,
-                   N3 - (3. / 4.) * P6 * C6 * C6 - (3. / 4.) * P5 * C5 * C5};
-  Vector<Real> Nx3{-(3. / 4.) * P4 * C4 * S4 - (3. / 4.) * P6 * C6 * S6,
-                   -(3. / 4.) * P5 * C5 * S5 - (3. / 4.) * P4 * C4 * S4,
-                   -(3. / 4.) * P6 * C6 * S6 - (3. / 4.) * P5 * C5 * S5};
-  Vector<Real> Ny1{3. / (2. * L4) * P4 * S4 - 3. / (2. * L6) * P6 * S6,
-                   3. / (2. * L5) * P5 * S5 - 3. / (2. * L4) * P4 * S4,
-                   3. / (2. * L6) * P6 * S6 - 3. / (2. * L5) * P5 * S5};
-  Vector<Real> Ny2{-(3. / 4.) * P4 * C4 * S4 - (3. / 4.) * P6 * C6 * S6,
-                   -(3. / 4.) * P5 * C5 * S5 - (3. / 4.) * P4 * C4 * S4,
-                   -(3. / 4.) * P6 * C6 * S6 - (3. / 4.) * P5 * C5 * S5};
-  Vector<Real> Ny3{N1 - (3. / 4.) * P4 * S4 * S4 - (3. / 4.) * P6 * S6 * S6,
-                   N2 - (3. / 4.) * P5 * S5 * S5 - (3. / 4.) * P4 * S4 * S4,
-                   N3 - (3. / 4.) * P6 * S6 * S6 - (3. / 4.) * P5 * S5 * S5};
-
-  // clang-format off
-  N = Matrix<Real> {
-  //      0    1       2       3       4      5      6       7       8       9     10     11      12      13      14
-    {N0(0),    0.,     0.,     0.,     0., N0(1),    0.,     0.,     0.,     0., N0(2),    0.,     0.,     0.,     0.},  // 0
-    {   0., N0(0),     0.,     0.,     0.,    0., N0(1),     0.,     0.,     0.,    0., N0(2),     0.,     0.,     0.},  // 1
-    {   0.,    0.,  N0(0), Nw2(0), Nw3(0),    0.,    0.,  N0(1), Nw2(1), Nw3(1),    0.,    0.,  N0(2), Nw2(2), Nw3(2)},  // 2
-    {   0.,    0., Nx1(0), Nx2(0), Nx3(0),    0.,    0., Nx1(1), Nx2(1), Nx3(1),    0.,    0., Nx1(2), Nx2(2), Nx3(2)},  // 3
-    {   0.,    0., Ny1(0), Ny2(0), Ny3(0),    0.,    0., Ny1(1), Ny2(1), Ny3(1),    0.,    0., Ny1(2), Ny2(2), Ny3(2)},  // 4
-    {   0,     0.,     0.,     0.,     0.,    0.,    0.,     0.,     0.,     0.,    0.,    0.,     0.,     0.,     0.}}; // 5 ???
+  // Derivative of quadratic interpolation functions
+  Matrix<Real> dP = {{4 * (1 - 2 * xi - eta), 4 * eta, -4 * eta},
+                     {-4 * xi, 4 * xi, 4 * (1 - xi - 2 * eta)}};
+
+  Matrix<Real> dNx1 = {
+      {3. / 2 * (dP(0, 0) * C[0] / L[0] - dP(0, 2) * C[2] / L[2]),
+       3. / 2 * (dP(0, 1) * C[1] / L[1] - dP(0, 0) * C[0] / L[0]),
+       3. / 2 * (dP(0, 2) * C[2] / L[2] - dP(0, 1) * C[1] / L[1])},
+      {3. / 2 * (dP(1, 0) * C[0] / L[0] - dP(1, 2) * C[2] / L[2]),
+       3. / 2 * (dP(1, 1) * C[1] / L[1] - dP(1, 0) * C[0] / L[0]),
+       3. / 2 * (dP(1, 2) * C[2] / L[2] - dP(1, 1) * C[1] / L[1])}};
+  Matrix<Real> dNx2 = {
+      // clang-format off
+      {-1 - 3. / 4 * (dP(0, 0) * C[0] * C[0] + dP(0, 2) * C[2] * C[2]),
+	1 - 3. / 4 * (dP(0, 1) * C[1] * C[1] + dP(0, 0) * C[0] * C[0]),
+	   -3. / 4 * (dP(0, 2) * C[2] * C[2] + dP(0, 1) * C[1] * C[1])},
+      {-1 - 3. / 4 * (dP(1, 0) * C[0] * C[0] + dP(1, 2) * C[2] * C[2]),
+	   -3. / 4 * (dP(1, 1) * C[1] * C[1] + dP(1, 0) * C[0] * C[0]),
+	1 - 3. / 4 * (dP(1, 2) * C[2] * C[2] + dP(1, 1) * C[1] * C[1])}};
+  // clang-format on
+  Matrix<Real> dNx3 = {
+      {-3. / 4 * (dP(0, 0) * C[0] * S[0] + dP(0, 2) * C[2] * S[2]),
+       -3. / 4 * (dP(0, 1) * C[1] * S[1] + dP(0, 0) * C[0] * S[0]),
+       -3. / 4 * (dP(0, 2) * C[2] * S[2] + dP(0, 1) * C[1] * S[1])},
+      {-3. / 4 * (dP(1, 0) * C[0] * S[0] + dP(1, 2) * C[2] * S[2]),
+       -3. / 4 * (dP(1, 1) * C[1] * S[1] + dP(1, 0) * C[0] * S[0]),
+       -3. / 4 * (dP(1, 2) * C[2] * S[2] + dP(1, 1) * C[1] * S[1])}};
+  Matrix<Real> dNy1 = {
+      {3. / 2 * (dP(0, 0) * S[0] / L[0] - dP(0, 2) * S[2] / L[2]),
+       3. / 2 * (dP(0, 1) * S[1] / L[1] - dP(0, 0) * S[0] / L[0]),
+       3. / 2 * (dP(0, 2) * S[2] / L[2] - dP(0, 1) * S[1] / L[1])},
+      {3. / 2 * (dP(1, 0) * S[0] / L[0] - dP(1, 2) * S[2] / L[2]),
+       3. / 2 * (dP(1, 1) * S[1] / L[1] - dP(1, 0) * S[0] / L[0]),
+       3. / 2 * (dP(1, 2) * S[2] / L[2] - dP(1, 1) * S[1] / L[1])}};
+  Matrix<Real> dNy2 = dNx3;
+  Matrix<Real> dNy3 = {
+      // clang-format off
+      {-1 - 3. / 4 * (dP(0, 0) * S[0] * S[0] + dP(0, 2) * S[2] * S[2]),
+	1 - 3. / 4 * (dP(0, 1) * S[1] * S[1] + dP(0, 0) * S[0] * S[0]),
+	   -3. / 4 * (dP(0, 2) * S[2] * S[2] + dP(0, 1) * S[1] * S[1])},
+      {-1 - 3. / 4 * (dP(1, 0) * S[0] * S[0] + dP(1, 2) * S[2] * S[2]),
+	   -3. / 4 * (dP(1, 1) * S[1] * S[1] + dP(1, 0) * S[0] * S[0]),
+	1 - 3. / 4 * (dP(1, 2) * S[2] * S[2] + dP(1, 1) * S[1] * S[1])}};
   // clang-format on
 
-#endif
+  // Derivative of linear (membrane mode) functions
+  Matrix<Real> dNm(2, 3);
+  InterpolationElement<_itp_lagrange_triangle_3, _itk_lagrangian>::computeDNDS(
+      natural_coords, dNm);
+  
+  UInt i = 0;
+  for (const Matrix<Real> & mat : {dNm, dNx1, dNx2, dNx3, dNy1, dNy2, dNy3}) {
+    B.block(mat, 0, i);
+    i += mat.cols();
+  }
 }
-
 /* -------------------------------------------------------------------------- */
 template <>
 inline void
-InterpolationElement<_itp_discrete_kirchhoff_triangle_18>::computeDNDS(
-    const Vector<Real> & /*natural_coords*/,
-    const Matrix<Real> & /*real_coord*/, Matrix<Real> & /*B*/) {
-
-#if 0
-  // natural coordinate
-  Real xi = natural_coords(0);
-  Real eta = natural_coords(1);
-
-  // projected_coord (x1 x2 x3) (y1 y2 y3)
-
-  // donne juste pour pour le patch test 4_5_5 mais donne quelque changement
-  // de signe dans la matrice de rotation
-
-  Real x21 = projected_coord(0, 0) - projected_coord(0, 1); // x1-x2
-  Real x32 = projected_coord(0, 1) - projected_coord(0, 2);
-  Real x13 = projected_coord(0, 2) - projected_coord(0, 0);
-
-  Real y21 = projected_coord(1, 0) - projected_coord(1, 1); // y1-y2
-  Real y32 = projected_coord(1, 1) - projected_coord(1, 2);
-  Real y13 = projected_coord(1, 2) - projected_coord(1, 0);
-
-  // donne juste pour la matrice de rigidité... mais pas pour le patch test
-  // 4_5_5
-
-  /* Real x21=projected_coord(0,1)-projected_coord(0,0);
-    Real x32=projected_coord(0,2)-projected_coord(0,1);
-    Real x13=projected_coord(0,0)-projected_coord(0,2);
-
-    Real y21=projected_coord(1,1)-projected_coord(1,0);
-    Real y32=projected_coord(1,2)-projected_coord(1,1);
-    Real y13=projected_coord(1,0)-projected_coord(1,2);*/
-
-  // natural triangle side length
-  Real L4 = std::sqrt(x21 * x21 + y21 * y21);
-  Real L5 = std::sqrt(x32 * x32 + y32 * y32);
-  Real L6 = std::sqrt(x13 * x13 + y13 * y13);
-
-  // sinus and cosinus
-  Real C4 = x21 / L4;
-  Real C5 = x32 / L5;
-  Real C6 = x13 / L6;
-  Real S4 = y21 / L4;
-  Real S5 = y32 / L5;
-  Real S6 = y13 / L6;
-
-  Real dN1xi = -1;
-  Real dN2xi = 1;
-  Real dN3xi = 0;
-
-  Real dN1eta = -1;
-  Real dN2eta = 0;
-  Real dN3eta = 1;
-
-  Real dP4xi = 4 - 8. * xi - 4 * eta;
-  Real dP5xi = 4 * eta;
-  Real dP6xi = -4 * eta;
-
-  Real dP4eta = -4 * xi;
-  Real dP5eta = 4 * xi;
-  Real dP6eta = 4 - 4 * xi - 8. * eta;
-
-  // N'xi
-  auto Np00 = dN1xi;
-  auto Np01 = dN2xi;
-  auto Np02 = dN3xi;
-  //   N'eta
-  auto Np10 = dN1eta;
-  auto Np11 = dN2eta;
-  auto Np12 = dN3eta;
-
-  // Nxi1'xi
-  auto Nx1p00 = 3. / (2 * L4) * dP4xi * C4 - 3. / (2. * L6) * dP6xi * C6;
-  auto Nx1p01 = 3. / (2 * L5) * dP5xi * C5 - 3. / (2. * L4) * dP4xi * C4;
-  auto Nx1p02 = 3. / (2 * L6) * dP6xi * C6 - 3. / (2. * L5) * dP5xi * C5;
-  //    Nxi1'eta
-  auto Nx1p10 = 3. / (2 * L4) * dP4eta * C4 - 3. / (2. * L6) * dP6eta * C6;
-  auto Nx1p11 = 3. / (2 * L5) * dP5eta * C5 - 3. / (2. * L4) * dP4eta * C4;
-  auto Nx1p12 = 3. / (2 * L6) * dP6eta * C6 - 3. / (2. * L5) * dP5eta * C5;
-
-  // Nxi2'xi
-  auto Nx2p00 = -1 - (3. / 4.) * dP4xi * C4 * C4 - (3. / 4.) * dP6xi * C6 * C6;
-  auto Nx2p01 = 1 - (3. / 4.) * dP5xi * C5 * C5 - (3. / 4.) * dP4xi * C4 * C4;
-  auto Nx2p02 = -(3. / 4.) * dP6xi * C6 * C6 - (3. / 4.) * dP5xi * C5 * C5;
-  //    Nxi2'eta
-  auto Nx2p10 =
-      -1 - (3. / 4.) * dP4eta * C4 * C4 - (3. / 4.) * dP6eta * C6 * C6;
-  auto Nx2p11 = -(3. / 4.) * dP5eta * C5 * C5 - (3. / 4.) * dP4eta * C4 * C4;
-  auto Nx2p12 = 1 - (3. / 4.) * dP6eta * C6 * C6 - (3. / 4.) * dP5eta * C5 * C5;
-
-  // Nxi3'xi
-  auto Nx3p00 = -(3. / 4.) * dP4xi * C4 * S4 - (3. / 4.) * dP6xi * C6 * S6;
-  auto Nx3p01 = -(3. / 4.) * dP5xi * C5 * S5 - (3. / 4.) * dP4xi * C4 * S4;
-  auto Nx3p02 = -(3. / 4.) * dP6xi * C6 * S6 - (3. / 4.) * dP5xi * C5 * S5;
-  //  Nxi3'eta
-  auto Nx3p10 = -(3. / 4.) * dP4eta * C4 * S4 - (3. / 4.) * dP6eta * C6 * S6;
-  auto Nx3p11 = -(3. / 4.) * dP5eta * C5 * S5 - (3. / 4.) * dP4eta * C4 * S4;
-  auto Nx3p12 = -(3. / 4.) * dP6eta * C6 * S6 - (3. / 4.) * dP5eta * C5 * S5;
-
-  // Nyi1'xi
-  auto Ny1p00 = 3 / (2 * L4) * dP4xi * S4 - 3 / (2 * L6) * dP6xi * S6;
-  auto Ny1p01 = 3 / (2 * L5) * dP5xi * S5 - 3 / (2 * L4) * dP4xi * S4;
-  auto Ny1p02 = 3 / (2 * L6) * dP6xi * S6 - 3 / (2 * L5) * dP5xi * S5;
-  //    Nyi1'eta
-  auto Ny1p10 = 3 / (2 * L4) * dP4eta * S4 - 3 / (2 * L6) * dP6eta * S6;
-  auto Ny1p11 = 3 / (2 * L5) * dP5eta * S5 - 3 / (2 * L4) * dP4eta * S4;
-  auto Ny1p12 = 3 / (2 * L6) * dP6eta * S6 - 3 / (2 * L5) * dP5eta * S5;
-
-  // Nyi2'xi
-  auto Ny2p00 = -(3. / 4.) * dP4xi * C4 * S4 - (3. / 4.) * dP6xi * C6 * S6;
-  auto Ny2p01 = -(3. / 4.) * dP5xi * C5 * S5 - (3. / 4.) * dP4xi * C4 * S4;
-  auto Ny2p02 = -(3. / 4.) * dP6xi * C6 * S6 - (3. / 4.) * dP5xi * C5 * S5;
-  //  Nyi2'eta
-  auto Ny2p10 = -(3. / 4.) * dP4eta * C4 * S4 - (3. / 4.) * dP6eta * C6 * S6;
-  auto Ny2p11 = -(3. / 4.) * dP5eta * C5 * S5 - (3. / 4.) * dP4eta * C4 * S4;
-  auto Ny2p12 = -(3. / 4.) * dP6eta * C6 * S6 - (3. / 4.) * dP5eta * C5 * S5;
-
-  // Nyi3'xi
-  auto Ny3p00 =
-      dN1xi - (3. / 4.) * dP4xi * S4 * S4 - (3. / 4.) * dP6xi * S6 * S6;
-  auto Ny3p01 =
-      dN2xi - (3. / 4.) * dP5xi * S5 * S5 - (3. / 4.) * dP4xi * S4 * S4;
-  auto Ny3p02 =
-      dN3xi - (3. / 4.) * dP6xi * S6 * S6 - (3. / 4.) * dP5xi * S5 * S5;
-  //      Nyi3'eta
-  auto Ny3p10 =
-      dN1eta - (3. / 4.) * dP4eta * S4 * S4 - (3. / 4.) * dP6eta * S6 * S6;
-  auto Ny3p11 =
-      dN2eta - (3. / 4.) * dP5eta * S5 * S5 - (3. / 4.) * dP4eta * S4 * S4;
-  auto Ny3p12 =
-      dN3eta - (3. / 4.) * dP6eta * S6 * S6 - (3. / 4.) * dP5eta * S5 * S5;
+InterpolationElement<_itp_discrete_kirchhoff_triangle_18,
+                     _itk_structural>::arrangeInVoigt(const Matrix<Real> & dnds,
+                                                      Matrix<Real> & B) {
+  Matrix<Real> dNm(2, 3), dNx1(2, 3), dNx2(2, 3), dNx3(2, 3), dNy1(2, 3),
+      dNy2(2, 3), dNy3(2, 3);
+  UInt i = 0;
+  for (Matrix<Real> * mat : {&dNm, &dNx1, &dNx2, &dNx3, &dNy1, &dNy2, &dNy3}) {
+    *mat = dnds.block(0, i, 2, 3);
+    i += mat->cols();
+  }
 
   // clang-format off
-  //       0    1                2                3                4       5     6                7                8                9    10    11               12               13               14
-  B = {{Np00,   0.,              0.,              0.,              0.,   Np01,   0.,              0.,              0.,              0., Np02,   0.,              0.,              0.,              0.},  // 0
-       {  0., Np10,              0.,              0.,              0.,     0., Np11,              0.,              0.,              0.,   0., Np12,              0.,              0.,              0.},  // 1
-       {Np10, Np00,              0.,              0.,              0.,   Np11, Np01,              0.,              0.,              0., Np12, Np02,              0.,              0.,              0.},  // 2
-       {  0.,   0.,          Nx1p00,          Nx2p00,          Nx3p00,     0.,   0.,          Nx1p01,          Nx2p01,          Nx3p01,   0.,   0.,          Nx1p02,          Nx2p02,          Nx3p02},  // 3
-       {  0.,   0.,          Ny1p10,          Ny2p10,          Ny3p10,     0.,   0.,          Ny1p11,          Ny2p11,          Ny3p11,   0.,   0.,          Ny1p12,          Ny2p12,          Ny3p12},  // 4
-       {  0.,   0., Nx1p10 + Ny1p00, Nx2p10 + Ny2p00, Nx3p10 + Ny3p00,     0.,   0., Nx1p11 + Ny1p01, Nx2p11 + Ny2p01, Nx3p11 + Ny3p01,   0.,   0., Nx1p12 + Ny1p02, Nx2p12 + Ny2p02, Nx3p12 + Ny3p02}}; // 5
+  B = {
+    // Membrane shape functions; TODO use the triangle_3 shapes
+    {dNm(0, 0), 0,         0, 0, 0, 0, dNm(0, 1), 0,         0, 0, 0, 0, dNm(0, 2), 0,         0, 0, 0, 0},
+    {0,         dNm(1, 0), 0, 0, 0, 0, 0,         dNm(1, 1), 0, 0, 0, 0, 0,         dNm(1, 2), 0, 0, 0, 0},
+    {dNm(1, 0), dNm(0, 0), 0, 0, 0, 0, dNm(1, 1), dNm(0, 1), 0, 0, 0, 0, dNm(1, 2), dNm(0, 2), 0, 0, 0, 0},
+
+    // Bending shape functions
+    {0, 0, dNx1(0, 0),              -dNx3(0, 0),              dNx2(0, 0),              0, 0, 0, dNx1(0, 1),              -dNx3(0, 1),              dNx2(0, 1),              0, 0, 0, dNx1(0, 2),              -dNx3(0, 2),              dNx2(0, 2),              0},
+    {0, 0, dNy1(1, 0),              -dNy3(1, 0),              dNy2(1, 0),              0, 0, 0, dNy1(1, 1),              -dNy3(1, 1),              dNy2(1, 1),              0, 0, 0, dNy1(1, 2),              -dNy3(1, 2),              dNy2(1, 2),              0},
+    {0, 0, dNx1(1, 0) + dNy1(0, 0), -dNx3(1, 0) - dNy3(0, 0), dNx2(1, 0) + dNy2(1, 0), 0, 0, 0, dNx1(1, 1) + dNy1(0, 1), -dNx3(1, 1) - dNy3(0, 0), dNx2(1, 1) + dNy2(1, 1), 0, 0, 0, dNx1(1, 2) + dNy1(0, 2), -dNx3(1, 2) - dNy3(0, 2), dNx2(1, 2) + dNy2(1, 2), 0}};
   // clang-format on
-#endif
 }
 
 } // namespace akantu
 
 #endif /* __AKANTU_ELEMENT_CLASS_KIRCHHOFF_SHELL_INLINE_IMPL_CC__ */
diff --git a/src/fe_engine/fe_engine_template_cohesive.cc b/src/fe_engine/fe_engine_template_cohesive.cc
index b9475e0e1..d247ac9d5 100644
--- a/src/fe_engine/fe_engine_template_cohesive.cc
+++ b/src/fe_engine/fe_engine_template_cohesive.cc
@@ -1,177 +1,133 @@
 /**
  * @file   fe_engine_template_cohesive.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Wed Oct 31 2012
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Specialization of the FEEngineTemplate for cohesive element
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "fe_engine_template.hh"
 #include "shape_cohesive.hh"
 #include "integrator_gauss.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /* compatibility functions */
 /* -------------------------------------------------------------------------- */
 template <>
 Real FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive,
                       DefaultIntegrationOrderFunctor>::
     integrate(const Array<Real> & f, const ElementType & type,
               const GhostType & ghost_type,
               const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
 #ifndef AKANTU_NDEBUG
   UInt nb_element = mesh.getNbElement(type, ghost_type);
   if (filter_elements != empty_filter)
     nb_element = filter_elements.size();
 
   UInt nb_quadrature_points = getNbIntegrationPoints(type);
 
   AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points,
                       "The vector f(" << f.getID()
                                       << ") has not the good size.");
   AKANTU_DEBUG_ASSERT(f.getNbComponent() == 1,
                       "The vector f("
                           << f.getID()
                           << ") has not the good number of component.");
 #endif
 
   Real integral = 0.;
 
 #define INTEGRATE(type)                                                        \
   integral = integrator.integrate<type>(f, ghost_type, filter_elements);
 
   AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE);
 #undef INTEGRATE
 
   AKANTU_DEBUG_OUT();
   return integral;
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive,
                       DefaultIntegrationOrderFunctor>::
     integrate(const Array<Real> & f, Array<Real> & intf,
               UInt nb_degree_of_freedom, const ElementType & type,
               const GhostType & ghost_type,
               const Array<UInt> & filter_elements) const {
 
 #ifndef AKANTU_NDEBUG
   UInt nb_element = mesh.getNbElement(type, ghost_type);
   if (filter_elements == filter_elements)
     nb_element = filter_elements.size();
 
   UInt nb_quadrature_points = getNbIntegrationPoints(type);
 
   AKANTU_DEBUG_ASSERT(f.size() == nb_element * nb_quadrature_points,
                       "The vector f(" << f.getID() << " size " << f.size()
                                       << ") has not the good size ("
                                       << nb_element << ").");
   AKANTU_DEBUG_ASSERT(f.getNbComponent() == nb_degree_of_freedom,
                       "The vector f("
                           << f.getID()
                           << ") has not the good number of component.");
   AKANTU_DEBUG_ASSERT(intf.getNbComponent() == nb_degree_of_freedom,
                       "The vector intf("
                           << intf.getID()
                           << ") has not the good number of component.");
   AKANTU_DEBUG_ASSERT(intf.size() == nb_element,
                       "The vector intf(" << intf.getID()
                                          << ") has not the good size.");
 #endif
 
 #define INTEGRATE(type)                                                        \
   integrator.integrate<type>(f, intf, nb_degree_of_freedom, ghost_type,        \
                              filter_elements);
 
   AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INTEGRATE);
 #undef INTEGRATE
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive,
                       DefaultIntegrationOrderFunctor>::
     gradientOnIntegrationPoints(const Array<Real> &, Array<Real> &, const UInt,
                                 const ElementType &, const GhostType &,
                                 const Array<UInt> &) const {
   AKANTU_DEBUG_TO_IMPLEMENT();
 }
 
 /* -------------------------------------------------------------------------- */
-template <>
-template <>
-void FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive,
-                      DefaultIntegrationOrderFunctor>::
-    computeNormalsOnIntegrationPoints<_cohesive_1d_2>(
-        const Array<Real> &, Array<Real> & normal,
-        const GhostType & ghost_type) const {
-  AKANTU_DEBUG_IN();
-
-  AKANTU_DEBUG_ASSERT(
-      mesh.getSpatialDimension() == 1,
-      "Mesh dimension must be 1 to compute normals on 1D cohesive elements!");
-  const ElementType type = _cohesive_1d_2;
-  const ElementType facet_type = Mesh::getFacetType(type);
-
-  UInt nb_element = mesh.getConnectivity(type, ghost_type).size();
-  normal.resize(nb_element);
-
-  Array<Element> & facets =
-      mesh.getMeshFacets().getSubelementToElement(type, ghost_type);
-  Array<std::vector<Element> > & segments =
-      mesh.getMeshFacets().getElementToSubelement(facet_type, ghost_type);
-
-  Real values[2];
-
-  for (UInt elem = 0; elem < nb_element; ++elem) {
-
-    for (UInt p = 0; p < 2; ++p) {
-      Element f = facets(elem, p);
-      Element seg = segments(f.element)[0];
-      Vector<Real> barycenter(values + p, 1);
-      mesh.getBarycenter(seg, barycenter);
-    }
-
-    Real difference = values[0] - values[1];
-
-    AKANTU_DEBUG_ASSERT(difference != 0.,
-                        "Error in normal computation for cohesive elements");
-
-    normal(elem) = difference / std::abs(difference);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
 
 } // akantu
diff --git a/src/fe_engine/shape_cohesive_inline_impl.cc b/src/fe_engine/shape_cohesive_inline_impl.cc
index 9477d6021..df81e9a8f 100644
--- a/src/fe_engine/shape_cohesive_inline_impl.cc
+++ b/src/fe_engine/shape_cohesive_inline_impl.cc
@@ -1,301 +1,328 @@
 /**
  * @file   shape_cohesive_inline_impl.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Feb 03 2012
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  ShapeCohesive inline implementation
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "shape_cohesive.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__
 #define __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 inline ShapeLagrange<_ek_cohesive>::ShapeLagrange(const Mesh & mesh,
                                                   const ID & id,
                                                   const MemoryID & memory_id)
     : ShapeLagrangeBase(mesh, _ek_cohesive, id, memory_id) {}
 
 #define INIT_SHAPE_FUNCTIONS(type)                                             \
   setIntegrationPointsByType<type>(integration_points, ghost_type);            \
   precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type);                \
   precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type);
 
 /* -------------------------------------------------------------------------- */
 inline void ShapeLagrange<_ek_cohesive>::initShapeFunctions(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     const ElementType & type, const GhostType & ghost_type) {
   AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS);
 }
 
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void ShapeLagrange<_ek_cohesive>::computeShapeDerivativesOnIntegrationPoints(
     const Array<Real> &, const Matrix<Real> & integration_points,
     Array<Real> & shape_derivatives, const GhostType & ghost_type,
     const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
-  UInt size_of_shapesd      = ElementClass<type>::getShapeDerivativesSize();
-  UInt spatial_dimension    = ElementClass<type>::getNaturalSpaceDimension();
-  UInt nb_nodes_per_element = ElementClass<type>::getNbNodesPerInterpolationElement();
+  UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize();
+  UInt spatial_dimension = ElementClass<type>::getNaturalSpaceDimension();
+  UInt nb_nodes_per_element =
+      ElementClass<type>::getNbNodesPerInterpolationElement();
 
   UInt nb_points = integration_points.cols();
   UInt nb_element = mesh.getConnectivity(type, ghost_type).size();
 
   AKANTU_DEBUG_ASSERT(shape_derivatives.getNbComponent() == size_of_shapesd,
                       "The shapes_derivatives array does not have the correct "
                           << "number of component");
 
   shape_derivatives.resize(nb_element * nb_points);
   Real * shapesd_val = shape_derivatives.storage();
 
   auto compute = [&](const auto & el) {
     auto ptr = shapesd_val + el * nb_points * size_of_shapesd;
     Tensor3<Real> B(ptr, spatial_dimension, nb_nodes_per_element, nb_points);
     ElementClass<type>::computeDNDS(integration_points, B);
   };
 
   for_each_element(nb_element, filter_elements, compute);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 inline void
 ShapeLagrange<_ek_cohesive>::computeShapeDerivativesOnIntegrationPoints(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     Array<Real> & shape_derivatives, const ElementType & type,
     const GhostType & ghost_type, const Array<UInt> & filter_elements) const {
 #define AKANTU_COMPUTE_SHAPES(type)                                            \
   computeShapeDerivativesOnIntegrationPoints<type>(                            \
       nodes, integration_points, shape_derivatives, ghost_type,                \
       filter_elements);
 
   AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES);
 
 #undef AKANTU_COMPUTE_SHAPES
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void ShapeLagrange<_ek_cohesive>::precomputeShapesOnIntegrationPoints(
     const Array<Real> & nodes, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
   Matrix<Real> & natural_coords = integration_points(type, ghost_type);
   UInt size_of_shapes = ElementClass<type>::getShapeSize();
 
   Array<Real> & shapes_tmp =
       shapes.alloc(0, size_of_shapes, itp_type, ghost_type);
 
   this->computeShapesOnIntegrationPoints<type>(nodes, natural_coords,
                                                shapes_tmp, ghost_type);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void ShapeLagrange<_ek_cohesive>::precomputeShapeDerivativesOnIntegrationPoints(
     const Array<Real> & nodes, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
   Matrix<Real> & natural_coords = integration_points(type, ghost_type);
   UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize();
 
   Array<Real> & shapes_derivatives_tmp =
       shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type);
 
   this->computeShapeDerivativesOnIntegrationPoints<type>(
       nodes, natural_coords, shapes_derivatives_tmp, ghost_type);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type, class ReduceFunction>
 void ShapeLagrange<_ek_cohesive>::extractNodalToElementField(
     const Array<Real> & nodal_f, Array<Real> & elemental_f,
     const GhostType & ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes_per_itp_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
   UInt nb_degree_of_freedom = nodal_f.getNbComponent();
   UInt nb_element = this->mesh.getNbElement(type, ghost_type);
 
   const auto & conn_array = this->mesh.getConnectivity(type, ghost_type);
   auto conn = conn_array.begin(conn_array.getNbComponent() / 2, 2);
 
   if (filter_elements != empty_filter) {
     nb_element = filter_elements.size();
   }
 
   elemental_f.resize(nb_element);
 
   Array<Real>::matrix_iterator u_it =
       elemental_f.begin(nb_degree_of_freedom, nb_nodes_per_itp_element);
 
   ReduceFunction reduce_function;
 
   auto compute = [&](const auto & el) {
     Matrix<Real> & u = *u_it;
     Matrix<UInt> el_conn(conn[el]);
 
     // compute the average/difference of the nodal field loaded from cohesive
     // element
     for (UInt n = 0; n < el_conn.rows(); ++n) {
       UInt node_plus = el_conn(n, 0);
       UInt node_minus = el_conn(n, 1);
       for (UInt d = 0; d < nb_degree_of_freedom; ++d) {
         Real u_plus = nodal_f(node_plus, d);
         Real u_minus = nodal_f(node_minus, d);
         u(d, n) = reduce_function(u_plus, u_minus);
       }
     }
 
     ++u_it;
   };
 
   for_each_element(nb_element, filter_elements, compute);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type, class ReduceFunction>
 void ShapeLagrange<_ek_cohesive>::interpolateOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom,
     GhostType ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
 
   AKANTU_DEBUG_ASSERT(this->shapes.exists(itp_type, ghost_type),
                       "No shapes for the type "
                           << this->shapes.printType(itp_type, ghost_type));
 
   UInt nb_nodes_per_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
   Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element);
   this->extractNodalToElementField<type, ReduceFunction>(in_u, u_el, ghost_type,
                                                          filter_elements);
 
   this->template interpolateElementalFieldOnIntegrationPoints<type>(
       u_el, out_uq, ghost_type, shapes(itp_type, ghost_type), filter_elements);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type, class ReduceFunction>
 void ShapeLagrange<_ek_cohesive>::variationOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & nablauq, UInt nb_degree_of_freedom,
     GhostType ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
 
   AKANTU_DEBUG_ASSERT(
       this->shapes_derivatives.exists(itp_type, ghost_type),
       "No shapes for the type "
           << this->shapes_derivatives.printType(itp_type, ghost_type));
 
   UInt nb_nodes_per_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
   Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element);
   this->extractNodalToElementField<type, ReduceFunction>(in_u, u_el, ghost_type,
                                                          filter_elements);
 
   this->template gradientElementalFieldOnIntegrationPoints<type>(
       u_el, nablauq, ghost_type, shapes_derivatives(itp_type, ghost_type),
       filter_elements);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
-
 template <ElementType type, class ReduceFunction>
 void ShapeLagrange<_ek_cohesive>::computeNormalsOnIntegrationPoints(
     const Array<Real> & u, Array<Real> & normals_u, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   UInt nb_element = this->mesh.getNbElement(type, ghost_type);
   UInt nb_points = this->integration_points(type, ghost_type).cols();
   UInt spatial_dimension = this->mesh.getSpatialDimension();
 
   if (filter_elements != empty_filter)
     nb_element = filter_elements.size();
 
   normals_u.resize(nb_points * nb_element);
 
-  Array<Real> tangents_u(nb_element * nb_points,
-                         (spatial_dimension * (spatial_dimension - 1)));
-
-  this->template variationOnIntegrationPoints<type, ReduceFunction>(
-      u, tangents_u, spatial_dimension, ghost_type, filter_elements);
+  Array<Real> tangents_u(0, (spatial_dimension * (spatial_dimension - 1)));
 
-  Array<Real>::vector_iterator normal = normals_u.begin(spatial_dimension);
-  Array<Real>::vector_iterator normal_end = normals_u.end(spatial_dimension);
+  if (spatial_dimension > 1) {
+    tangents_u.resize(nb_element * nb_points);
+    this->template variationOnIntegrationPoints<type, ReduceFunction>(
+        u, tangents_u, spatial_dimension, ghost_type, filter_elements);
+  }
 
   Real * tangent = tangents_u.storage();
 
-  if (spatial_dimension == 3)
-    for (; normal != normal_end; ++normal) {
+  if (spatial_dimension == 3) {
+    for (auto & normal : make_view(normals_u, spatial_dimension)) {
       Math::vectorProduct3(tangent, tangent + spatial_dimension,
-                           normal->storage());
+                           normal.storage());
 
-      (*normal) /= normal->norm();
+      normal /= normal.norm();
       tangent += spatial_dimension * 2;
     }
-  else if (spatial_dimension == 2)
-    for (; normal != normal_end; ++normal) {
+  } else if (spatial_dimension == 2) {
+    for (auto & normal : make_view(normals_u, spatial_dimension)) {
       Vector<Real> a1(tangent, spatial_dimension);
 
-      (*normal)(0) = -a1(1);
-      (*normal)(1) = a1(0);
-      (*normal) /= normal->norm();
+      normal(0) = -a1(1);
+      normal(1) = a1(0);
+      normal.normalize();
 
       tangent += spatial_dimension;
     }
+  } else if (spatial_dimension == 1) {
+    const auto facet_type = Mesh::getFacetType(type);
+    const auto & mesh_facets = mesh.getMeshFacets();
+    const auto & facets = mesh_facets.getSubelementToElement(type, ghost_type);
+    const auto & segments =
+        mesh_facets.getElementToSubelement(facet_type, ghost_type);
+
+    Real values[2];
+
+    for (auto el : arange(nb_element)) {
+      if (filter_elements != empty_filter)
+        el = filter_elements(el);
+
+      for (UInt p = 0; p < 2; ++p) {
+        Element facet = facets(el, p);
+        Element segment = segments(facet.element)[0];
+        Vector<Real> barycenter(values + p, 1);
+        mesh.getBarycenter(segment, barycenter);
+      }
+
+      Real difference = values[0] - values[1];
+
+      AKANTU_DEBUG_ASSERT(difference != 0.,
+                          "Error in normal computation for cohesive elements");
+
+      normals_u(el) = difference / std::abs(difference);
+    }
+  }
 
   AKANTU_DEBUG_OUT();
 }
 
 } // namespace akantu
 #endif /* __AKANTU_SHAPE_COHESIVE_INLINE_IMPL_CC__ */
diff --git a/src/fe_engine/shape_structural_inline_impl.cc b/src/fe_engine/shape_structural_inline_impl.cc
index 0eefa86d8..207ab5bea 100644
--- a/src/fe_engine/shape_structural_inline_impl.cc
+++ b/src/fe_engine/shape_structural_inline_impl.cc
@@ -1,383 +1,431 @@
 /**
  * @file   shape_structural_inline_impl.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Dec 13 2010
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  ShapeStructural inline implementation
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "mesh_iterators.hh"
 #include "shape_structural.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__
 #define __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__
 
 namespace akantu {
 
 namespace {
   /// Extract nodal coordinates per elements
   template <ElementType type>
   std::unique_ptr<Array<Real>>
   getNodesPerElement(const Mesh & mesh, const Array<Real> & nodes,
                      const GhostType & ghost_type) {
     const auto dim = ElementClass<type>::getSpatialDimension();
     const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 
     auto nodes_per_element = std::make_unique<Array<Real>>(0, dim * nb_nodes_per_element);
     FEEngine::extractNodalToElementField(mesh, nodes, *nodes_per_element, type, ghost_type);
     return nodes_per_element;
   }
 }
 
 template <ElementKind kind>
 inline void ShapeStructural<kind>::initShapeFunctions(
     const Array<Real> & /* unused */, const Matrix<Real> & /* unused */,
     const ElementType & /* unused */, const GhostType & /* unused */) {
   AKANTU_DEBUG_TO_IMPLEMENT();
 }
 
 /* -------------------------------------------------------------------------- */
 #define INIT_SHAPE_FUNCTIONS(type)                                             \
   setIntegrationPointsByType<type>(integration_points, ghost_type);            \
   precomputeRotationMatrices<type>(nodes, ghost_type);                         \
   precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type);                \
   precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type);
 
 template <>
 inline void ShapeStructural<_ek_structural>::initShapeFunctions(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     const ElementType & type, const GhostType & ghost_type) {
   AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS);
 }
 
 #undef INIT_SHAPE_FUNCTIONS
 
 /* -------------------------------------------------------------------------- */
 template <>
 template <ElementType type>
 void ShapeStructural<_ek_structural>::computeShapesOnIntegrationPoints(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     Array<Real> & shapes, const GhostType & ghost_type,
     const Array<UInt> & filter_elements) const {
 
   UInt nb_points = integration_points.cols();
   UInt nb_element = mesh.getConnectivity(type, ghost_type).size();
 
   shapes.resize(nb_element * nb_points);
 
   UInt ndof = ElementClass<type>::getNbDegreeOfFreedom();
 
 #if !defined(AKANTU_NDEBUG)
   UInt size_of_shapes = ElementClass<type>::getShapeSize();
   AKANTU_DEBUG_ASSERT(shapes.getNbComponent() == size_of_shapes,
                       "The shapes array does not have the correct "
                           << "number of component");
 #endif
 
   auto shapes_it = shapes.begin_reinterpret(
       ElementClass<type>::getNbNodesPerInterpolationElement(), ndof, nb_points,
       nb_element);
 
   auto shapes_begin = shapes_it;
   if (filter_elements != empty_filter) {
     nb_element = filter_elements.size();
   }
 
   auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type);
   auto nodes_it = nodes_per_element->begin(mesh.getSpatialDimension(),
                                            Mesh::getNbNodesPerElement(type));
   auto nodes_begin = nodes_it;
 
   for (UInt elem = 0; elem < nb_element; ++elem) {
     if (filter_elements != empty_filter) {
       shapes_it = shapes_begin + filter_elements(elem);
       nodes_it = nodes_begin + filter_elements(elem);
     }
 
     Tensor3<Real> & N = *shapes_it;
     auto & real_coord = *nodes_it;
     ElementClass<type>::computeShapes(integration_points, real_coord, N);
 
     if (filter_elements == empty_filter)
       ++shapes_it;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::precomputeRotationMatrices(
     const Array<Real> & nodes, const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   const auto spatial_dimension = mesh.getSpatialDimension();
   const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   const auto nb_element = mesh.getNbElement(type, ghost_type);
   const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom();
 
   if (not this->rotation_matrices.exists(type, ghost_type)) {
     this->rotation_matrices.alloc(0, nb_dof * nb_dof, type, ghost_type);
   }
 
   auto & rot_matrices = this->rotation_matrices(type, ghost_type);
   rot_matrices.resize(nb_element);
 
   Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element);
   FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type);
 
   bool has_extra_normal = mesh.hasData<Real>("extra_normal", type, ghost_type);
   Array<Real>::const_vector_iterator extra_normal;
   if (has_extra_normal)
     extra_normal = mesh.getData<Real>("extra_normal", type, ghost_type)
                        .begin(spatial_dimension);
 
   for (auto && tuple :
        zip(make_view(x_el, spatial_dimension, nb_nodes_per_element),
            make_view(rot_matrices, nb_dof, nb_dof))) {
     // compute shape derivatives
     auto & X = std::get<0>(tuple);
     auto & R = std::get<1>(tuple);
 
     if (has_extra_normal) {
       ElementClass<type>::computeRotationMatrix(R, X, *extra_normal);
       ++extra_normal;
     } else {
       ElementClass<type>::computeRotationMatrix(
           R, X, Vector<Real>(spatial_dimension));
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::precomputeShapesOnIntegrationPoints(
     const Array<Real> & nodes, const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   const auto & natural_coords = integration_points(type, ghost_type);
   auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   auto nb_points = integration_points(type, ghost_type).cols();
   auto nb_element = mesh.getNbElement(type, ghost_type);
   auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom();
   const auto dim = ElementClass<type>::getSpatialDimension();
 
   auto itp_type = FEEngine::getInterpolationType(type);
   if (not shapes.exists(itp_type, ghost_type)) {
     auto size_of_shapes = this->getShapeSize(type);
     this->shapes.alloc(0, size_of_shapes, itp_type, ghost_type);
   }
 
   auto & shapes_ = this->shapes(itp_type, ghost_type);
   shapes_.resize(nb_element * nb_points);
 
   auto nodes_per_element = getNodesPerElement<type>(mesh, nodes, ghost_type);
 
   for (auto && tuple :
 	 zip(make_view(shapes_, nb_dof, nb_dof * nb_nodes_per_element, nb_points),
 	     make_view(*nodes_per_element, dim, nb_nodes_per_element))) {
     auto & N = std::get<0>(tuple);
     auto & real_coord = std::get<1>(tuple);
     ElementClass<type>::computeShapes(natural_coords, real_coord, N);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::precomputeShapeDerivativesOnIntegrationPoints(
     const Array<Real> & nodes, const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   const auto & natural_coords = integration_points(type, ghost_type);
   const auto spatial_dimension = mesh.getSpatialDimension();
   const auto natural_spatial_dimension =
       ElementClass<type>::getNaturalSpaceDimension();
   const auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   const auto nb_points = natural_coords.cols();
   const auto nb_dof = ElementClass<type>::getNbDegreeOfFreedom();
   const auto nb_element = mesh.getNbElement(type, ghost_type);
   const auto nb_stress_components = ElementClass<type>::getNbStressComponents();
 
   auto itp_type = FEEngine::getInterpolationType(type);
   if (not this->shapes_derivatives.exists(itp_type, ghost_type)) {
     auto size_of_shapesd = this->getShapeDerivativesSize(type);
     this->shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type);
   }
 
   auto & rot_matrices = this->rotation_matrices(type, ghost_type);
 
   Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element);
   FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type);
 
   auto & shapesd = this->shapes_derivatives(itp_type, ghost_type);
   shapesd.resize(nb_element * nb_points);
 
 
   for (auto && tuple :
        zip(make_view(x_el, spatial_dimension, nb_nodes_per_element),
            make_view(shapesd, nb_stress_components,
                      nb_nodes_per_element * nb_dof, nb_points),
            make_view(rot_matrices, nb_dof, nb_dof))) {
     // compute shape derivatives
     auto & X = std::get<0>(tuple);
     auto & B = std::get<1>(tuple);
     auto & RDOFs = std::get<2>(tuple);
 
+
+    // /!\ This is a temporary variable with no specified size for columns !
+    // It is up to the element to resize
+    Tensor3<Real> dnds(natural_spatial_dimension,
+                       ElementClass<type>::interpolation_property::dnds_columns,
+                       B.size(2));
+    ElementClass<type>::computeDNDS(natural_coords, X, dnds);
+
+    Tensor3<Real> J(natural_spatial_dimension, natural_coords.rows(), natural_coords.cols());
+
+    // Computing the coordinates of the element in the natural space
     auto R = RDOFs.block(0, 0, spatial_dimension, spatial_dimension);
     Matrix<Real> T(B.size(1), B.size(1));
     T.block(RDOFs, 0, 0);
     T.block(RDOFs, RDOFs.rows(), RDOFs.rows());
 
     // Rotate to local basis
     auto x =
         (R * X).block(0, 0, natural_spatial_dimension, nb_nodes_per_element);
 
-    Tensor3<Real> dnds(B.size(0), B.size(1), B.size(2));
-    ElementClass<type>::computeDNDS(natural_coords, X, dnds);
-
-    Tensor3<Real> J(x.rows(), natural_coords.rows(), natural_coords.cols());
-
-    ElementClass<type>::computeJMat(dnds, x, J);
+    ElementClass<type>::computeJMat(natural_coords, x, J);
     ElementClass<type>::computeShapeDerivatives(J, dnds, T, B);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::interpolateOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_dof,
     const GhostType & ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(out_uq.getNbComponent() == nb_dof,
                       "The output array shape is not correct");
 
   auto itp_type = FEEngine::getInterpolationType(type);
   const auto & shapes_ = shapes(itp_type, ghost_type);
 
   auto nb_element = mesh.getNbElement(type, ghost_type);
   auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement();
   auto nb_quad_points_per_element = integration_points(type, ghost_type).cols();
 
   Array<Real> u_el(0, nb_nodes_per_element * nb_dof);
   FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type,
                                        filter_elements);
 
   auto nb_quad_points = nb_quad_points_per_element * u_el.size();
   out_uq.resize(nb_quad_points);
 
   auto out_it = out_uq.begin_reinterpret(nb_dof, 1, nb_quad_points_per_element,
                                          u_el.size());
   auto shapes_it =
       shapes_.begin_reinterpret(nb_dof, nb_dof * nb_nodes_per_element,
                                 nb_quad_points_per_element, nb_element);
   auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1,
                                      nb_quad_points_per_element, u_el.size());
 
   for_each_element(nb_element, filter_elements, [&](auto && el) {
     auto & uq = *out_it;
     const auto & u = *u_it;
     auto N = Tensor3<Real>(shapes_it[el]);
 
     for (auto && q : arange(uq.size(2))) {
       auto uq_q = Matrix<Real>(uq(q));
       auto u_q = Matrix<Real>(u(q));
       auto N_q = Matrix<Real>(N(q));
 
       uq_q.mul<false, false>(N_q, u_q);
     }
 
     ++out_it;
     ++u_it;
   });
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeStructural<kind>::gradientOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_nablauq, UInt nb_dof,
     const GhostType & ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   auto itp_type = FEEngine::getInterpolationType(type);
   const auto & shapesd = shapes_derivatives(itp_type, ghost_type);
 
   auto nb_element = mesh.getNbElement(type, ghost_type);
   auto element_dimension = ElementClass<type>::getSpatialDimension();
   auto nb_quad_points_per_element = integration_points(type, ghost_type).cols();
   auto nb_nodes_per_element = ElementClass<type>::getNbNodesPerElement();
 
   Array<Real> u_el(0, nb_nodes_per_element * nb_dof);
   FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type,
                                        filter_elements);
 
   auto nb_quad_points = nb_quad_points_per_element * u_el.size();
   out_nablauq.resize(nb_quad_points);
 
   auto out_it = out_nablauq.begin_reinterpret(
       element_dimension, 1, nb_quad_points_per_element, u_el.size());
   auto shapesd_it = shapesd.begin_reinterpret(
       element_dimension, nb_dof * nb_nodes_per_element,
       nb_quad_points_per_element, nb_element);
   auto u_it = u_el.begin_reinterpret(nb_dof * nb_nodes_per_element, 1,
                                      nb_quad_points_per_element, u_el.size());
 
   for_each_element(nb_element, filter_elements, [&](auto && el) {
     auto & nablau = *out_it;
     const auto & u = *u_it;
     auto B = Tensor3<Real>(shapesd_it[el]);
 
     for (auto && q : arange(nablau.size(2))) {
       auto nablau_q = Matrix<Real>(nablau(q));
       auto u_q = Matrix<Real>(u(q));
       auto B_q = Matrix<Real>(B(q));
 
       nablau_q.mul<false, false>(B_q, u_q);
     }
 
     ++out_it;
     ++u_it;
   });
 
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+template <>
+template <ElementType type>
+void ShapeStructural<_ek_structural>::computeBtD(
+    const Array<Real> & Ds, Array<Real> & BtDs,
+    GhostType ghost_type, const Array<UInt> & filter_elements) const {
+  auto itp_type = ElementClassProperty<type>::interpolation_type;
+
+  auto nb_stress = ElementClass<type>::getNbStressComponents();
+  auto nb_dof_per_element = ElementClass<type>::getNbDegreeOfFreedom() *
+                            mesh.getNbNodesPerElement(type);
+
+  const auto & shapes_derivatives =
+      this->shapes_derivatives(itp_type, ghost_type);
+
+  Array<Real> shapes_derivatives_filtered(0,
+                                          shapes_derivatives.getNbComponent());
+  auto && view = make_view(shapes_derivatives, nb_stress, nb_dof_per_element);
+  auto B_it = view.begin();
+  auto B_end = view.end();
+
+  if (filter_elements != empty_filter) {
+    FEEngine::filterElementalData(this->mesh, shapes_derivatives,
+                                  shapes_derivatives_filtered, type, ghost_type,
+                                  filter_elements);
+    auto && view =
+        make_view(shapes_derivatives_filtered, nb_stress, nb_dof_per_element);
+    B_it = view.begin();
+    B_end = view.end();
+  }
+
+  for (auto && values :
+       zip(range(B_it, B_end),
+           make_view(Ds, nb_stress),
+           make_view(BtDs, BtDs.getNbComponent()))) {
+    const auto & B = std::get<0>(values);
+    const auto & D = std::get<1>(values);
+    auto & Bt_D = std::get<2>(values);
+    Bt_D.template mul<true>(B, D);
+  }
+}
+
 } // namespace akantu
 
 #endif /* __AKANTU_SHAPE_STRUCTURAL_INLINE_IMPL_CC__ */
diff --git a/src/io/dumper/dumper_iohelper.cc b/src/io/dumper/dumper_iohelper.cc
index 9ea6c8642..534c2bad2 100644
--- a/src/io/dumper/dumper_iohelper.cc
+++ b/src/io/dumper/dumper_iohelper.cc
@@ -1,302 +1,305 @@
 /**
  * @file   dumper_iohelper.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Dana Christen <dana.christen@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Oct 26 2012
  * @date last modification: Thu Sep 17 2015
  *
  * @brief  implementation of DumperIOHelper
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include <io_helper.hh>
 
 #include "dumper_iohelper.hh"
 #include "dumper_elemental_field.hh"
 #include "dumper_nodal_field.hh"
 #include "dumper_filtered_connectivity.hh"
 #include "dumper_variable.hh"
 #include "mesh.hh"
 #if defined(AKANTU_IGFEM)
 #include "dumper_igfem_connectivity.hh"
 #endif
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 DumperIOHelper::DumperIOHelper() = default;
 
 /* -------------------------------------------------------------------------- */
 DumperIOHelper::~DumperIOHelper() {
   for (auto it = fields.begin(); it != fields.end(); ++it) {
     delete it->second;
   }
 
   delete dumper;
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::setParallelContext(bool is_parallel) {
   UInt whoami  = Communicator::getStaticCommunicator().whoAmI();
   UInt nb_proc = Communicator::getStaticCommunicator().getNbProc();
 
   if(is_parallel)
     dumper->setParallelContext(whoami, nb_proc);
   else
     dumper->setParallelContext(0, 1);
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::setDirectory(const std::string & directory) {
   this->directory = directory;
   dumper->setPrefix(directory);
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::setBaseName(const std::string & basename) {
   filename = basename;
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::setTimeStep(Real time_step) {
   if(!time_activated)
     this->dumper->activateTimeDescFiles(time_step);
   else
     this->dumper->setTimeStep(time_step);
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::dump() {
   try {
     dumper->dump(filename, count);
   } catch (iohelper::IOHelperException & e) {
     AKANTU_DEBUG_ERROR("I was not able to dump your data with a Dumper: " << e.what());
   }
 
   ++count;
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::dump(UInt step) {
   this->count = step;
   this->dump();
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::dump(Real current_time, UInt step) {
   this->dumper->setCurrentTime(current_time);
   this->dump(step);
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::registerMesh(const Mesh & mesh,
 				  UInt spatial_dimension,
 				  const GhostType & ghost_type,
 				  const ElementKind & element_kind) {
 
 #if defined(AKANTU_IGFEM)
   if (element_kind == _ek_igfem) {
     registerField("connectivities",
 		  new dumper::IGFEMConnectivityField(mesh.getConnectivities(),
 						     spatial_dimension,
 						     ghost_type));
   } else
 #endif
   
     registerField("connectivities",
 		  new dumper::ElementalField<UInt>(mesh.getConnectivities(),
 						   spatial_dimension,
 						   ghost_type,
 						   element_kind));
 
   registerField("positions",
 		new dumper::NodalField<Real>(mesh.getNodes()));
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::registerFilteredMesh(const Mesh & mesh,
 					  const ElementTypeMapArray<UInt> & elements_filter,
 					  const Array<UInt> & nodes_filter,
 					  UInt spatial_dimension,
 					  const GhostType & ghost_type,
 					  const ElementKind & element_kind) {
   auto * f_connectivities = new ElementTypeMapArrayFilter<UInt>(
       mesh.getConnectivities(), elements_filter);
 
   this->registerField("connectivities",
                       new dumper::FilteredConnectivityField(*f_connectivities,
                                                             nodes_filter,
                                                             spatial_dimension,
                                                             ghost_type,
                                                             element_kind));
 
   this->registerField("positions",new dumper::NodalField<Real,true>(
                                                                     mesh.getNodes(),
                                                                     0,
                                                                     0,
                                                                     &nodes_filter));
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::registerField(const std::string & field_id,
                                    dumper::Field * field) {
   auto it = fields.find(field_id);
   if(it != fields.end()) {
     AKANTU_DEBUG_WARNING("The field " << field_id
 			 << " is already registered in this Dumper. Field ignored.");
     return;
   }
 
   fields[field_id] = field;
   field->registerToDumper(field_id, *dumper);
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::unRegisterField(const std::string & field_id) {
   auto it = fields.find(field_id);
   if(it == fields.end()) {
     AKANTU_DEBUG_WARNING("The field " << field_id
 			 << " is not registered in this Dumper. Nothing to do.");
     return;
   }
 
   delete it->second;
   fields.erase(it);
 }
 
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::registerVariable(const std::string & variable_id,
                                       dumper::VariableBase * variable) {
   auto it = variables.find(variable_id);
 
   if(it != variables.end()) {
     AKANTU_DEBUG_WARNING("The Variable " << variable_id
 			 << " is already registered in this Dumper. Variable ignored.");
     return;
   }
 
   variables[variable_id] = variable;
   variable->registerToDumper(variable_id, *dumper);
 }
 
 /* -------------------------------------------------------------------------- */
 void DumperIOHelper::unRegisterVariable(const std::string & variable_id) {
   auto it = variables.find(variable_id);
 
   if(it == variables.end()) {
     AKANTU_DEBUG_WARNING("The variable " << variable_id
 			 << " is not registered in this Dumper. Nothing to do.");
     return;
   }
 
   delete it->second;
   variables.erase(it);
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 iohelper::ElemType getIOHelperType() {
   AKANTU_DEBUG_TO_IMPLEMENT();
   return iohelper::MAX_ELEM_TYPE;
 }
 
 template <>
 iohelper::ElemType getIOHelperType<_point_1>() { return iohelper::POINT_SET; }
 template <>
 iohelper::ElemType getIOHelperType<_segment_2>() { return iohelper::LINE1; }
 template <>
 iohelper::ElemType getIOHelperType<_segment_3>() { return iohelper::LINE2; }
 
 template <>
 iohelper::ElemType getIOHelperType<_triangle_3>() { return iohelper::TRIANGLE1; }
 template <>
 iohelper::ElemType getIOHelperType<_triangle_6>() { return iohelper::TRIANGLE2; }
 
 template <>
 iohelper::ElemType getIOHelperType<_quadrangle_4>() { return iohelper::QUAD1; }
 template <>
 iohelper::ElemType getIOHelperType<_quadrangle_8>() { return iohelper::QUAD2; }
 
 template <>
 iohelper::ElemType getIOHelperType<_tetrahedron_4>()  { return iohelper::TETRA1; }
 template <>
 iohelper::ElemType getIOHelperType<_tetrahedron_10>() { return iohelper::TETRA2; }
 
 template <>
 iohelper::ElemType getIOHelperType<_hexahedron_8>()  { return iohelper::HEX1; }
 template <>
 iohelper::ElemType getIOHelperType<_hexahedron_20>() { return iohelper::HEX2; }
 
 template <>
 iohelper::ElemType getIOHelperType<_pentahedron_6>() { return iohelper::PRISM1; }
 template <>
 iohelper::ElemType getIOHelperType<_pentahedron_15>() { return iohelper::PRISM2; }
 
 #if defined(AKANTU_COHESIVE_ELEMENT)
+template <>
+iohelper::ElemType getIOHelperType<_cohesive_1d_2>() { return iohelper::COH1D2; }
+
 template <>
 iohelper::ElemType getIOHelperType<_cohesive_2d_4>() { return iohelper::COH2D4; }
 template <>
 iohelper::ElemType getIOHelperType<_cohesive_2d_6>() { return iohelper::COH2D6; }
 
 template <>
 iohelper::ElemType getIOHelperType<_cohesive_3d_6>() { return iohelper::COH3D6; }
 template <>
 iohelper::ElemType getIOHelperType<_cohesive_3d_12>() { return iohelper::COH3D12; }
 
 template <>
 iohelper::ElemType getIOHelperType<_cohesive_3d_8>() { return iohelper::COH3D8; }
 //template <>
 //iohelper::ElemType getIOHelperType<_cohesive_3d_16>() { return iohelper::COH3D16; }
 #endif
 
 #if defined(AKANTU_STRUCTURAL_MECHANICS)
 template <>
 iohelper::ElemType getIOHelperType<_bernoulli_beam_2>() { return iohelper::BEAM2; }
 template <>
 iohelper::ElemType getIOHelperType<_bernoulli_beam_3>() { return iohelper::BEAM3; }
 #endif
 
 /* -------------------------------------------------------------------------- */
 UInt getIOHelperType(ElementType type) {
   UInt ioh_type = iohelper::MAX_ELEM_TYPE;
 #define GET_IOHELPER_TYPE(type)			\
   ioh_type = getIOHelperType<type>();
 
   AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_IOHELPER_TYPE);
 #undef GET_IOHELPER_TYPE
   return ioh_type;
 }
 
 /* -------------------------------------------------------------------------- */
 
 } // akantu
 
 namespace iohelper {
   template<>
   DataType getDataType<akantu::NodeType>() { return _int; }
 }
diff --git a/src/mesh/element_type_map.cc b/src/mesh/element_type_map.cc
index 10ed4c342..ee0fc8cca 100644
--- a/src/mesh/element_type_map.cc
+++ b/src/mesh/element_type_map.cc
@@ -1,59 +1,71 @@
 /**
  * @file   element_type_map.cc
  *
  * @author Nicolas Richart
  *
  * @date creation  Tue Jun 27 2017
  *
  * @brief A Documented file.
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "fe_engine.hh"
 #include "mesh.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
-FEEngineElementTypeMapArrayInializer::FEEngineElementTypeMapArrayInializer(
+FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer(
     const FEEngine & fe_engine, UInt nb_component, UInt spatial_dimension,
     const GhostType & ghost_type, const ElementKind & element_kind)
-    : MeshElementTypeMapArrayInializer(
-          fe_engine.getMesh(),
-          nb_component,
+    : MeshElementTypeMapArrayInitializer(
+          fe_engine.getMesh(), nb_component,
           spatial_dimension == UInt(-2)
               ? fe_engine.getMesh().getSpatialDimension()
               : spatial_dimension,
           ghost_type, element_kind, true, false),
       fe_engine(fe_engine) {}
 
-UInt FEEngineElementTypeMapArrayInializer::size(
+FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer(
+    const FEEngine & fe_engine,
+    const ElementTypeMapArrayInitializer::CompFunc & nb_component,
+    UInt spatial_dimension, const GhostType & ghost_type,
+    const ElementKind & element_kind)
+    : MeshElementTypeMapArrayInitializer(
+          fe_engine.getMesh(), nb_component,
+          spatial_dimension == UInt(-2)
+              ? fe_engine.getMesh().getSpatialDimension()
+              : spatial_dimension,
+          ghost_type, element_kind, true, false),
+      fe_engine(fe_engine) {}
+
+UInt FEEngineElementTypeMapArrayInitializer::size(
     const ElementType & type) const {
-  return MeshElementTypeMapArrayInializer::size(type) *
+  return MeshElementTypeMapArrayInitializer::size(type) *
          fe_engine.getNbIntegrationPoints(type, this->ghost_type);
 }
 
-FEEngineElementTypeMapArrayInializer::ElementTypesIteratorHelper
-FEEngineElementTypeMapArrayInializer::elementTypes() const {
+FEEngineElementTypeMapArrayInitializer::ElementTypesIteratorHelper
+FEEngineElementTypeMapArrayInitializer::elementTypes() const {
   return this->fe_engine.elementTypes(spatial_dimension, ghost_type,
                                       element_kind);
 }
 } // namespace akantu
diff --git a/src/mesh/element_type_map.hh b/src/mesh/element_type_map.hh
index c6fc7a798..f3aefd368 100644
--- a/src/mesh/element_type_map.hh
+++ b/src/mesh/element_type_map.hh
@@ -1,437 +1,449 @@
 /**
  * @file   element_type_map.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Aug 31 2011
  * @date last modification: Fri Oct 02 2015
  *
  * @brief  storage class by element type
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_array.hh"
 #include "aka_memory.hh"
 #include "aka_named_argument.hh"
 #include "element.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_TYPE_MAP_HH__
 #define __AKANTU_ELEMENT_TYPE_MAP_HH__
 
 namespace akantu {
 class FEEngine;
 } // namespace akantu
 
 namespace akantu {
 
 namespace {
   DECLARE_NAMED_ARGUMENT(all_ghost_types);
   DECLARE_NAMED_ARGUMENT(default_value);
   DECLARE_NAMED_ARGUMENT(element_kind);
   DECLARE_NAMED_ARGUMENT(ghost_type);
   DECLARE_NAMED_ARGUMENT(nb_component);
+  DECLARE_NAMED_ARGUMENT(nb_component_functor);
   DECLARE_NAMED_ARGUMENT(with_nb_element);
   DECLARE_NAMED_ARGUMENT(with_nb_nodes_per_element);
   DECLARE_NAMED_ARGUMENT(spatial_dimension);
   DECLARE_NAMED_ARGUMENT(do_not_default);
 } // namespace
 
 template <class Stored, typename SupportType = ElementType>
 class ElementTypeMap;
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMapBase */
 /* -------------------------------------------------------------------------- */
 /// Common non templated base class for the ElementTypeMap class
 class ElementTypeMapBase {
 public:
   virtual ~ElementTypeMapBase() = default;
 };
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMap */
 /* -------------------------------------------------------------------------- */
 
 template <class Stored, typename SupportType>
 class ElementTypeMap : public ElementTypeMapBase {
 
 public:
   ElementTypeMap();
   ~ElementTypeMap() override;
 
   inline static std::string printType(const SupportType & type,
                                       const GhostType & ghost_type);
 
   /*! Tests whether a type is present in the object
    *  @param type the type to check for
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return true if the type is present. */
   inline bool exists(const SupportType & type,
                      const GhostType & ghost_type = _not_ghost) const;
 
   /*! get the stored data corresponding to a type
    *  @param type the type to check for
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return stored data corresponding to type. */
   inline const Stored &
   operator()(const SupportType & type,
              const GhostType & ghost_type = _not_ghost) const;
 
   /*! get the stored data corresponding to a type
    *  @param type the type to check for
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return stored data corresponding to type. */
   inline Stored & operator()(const SupportType & type,
                              const GhostType & ghost_type = _not_ghost);
 
   /*! insert data of a new type (not yet present) into the map. THIS METHOD IS
    *  NOT ARRAY SAFE, when using ElementTypeMapArray, use setArray instead
    *  @param data to insert
    *  @param type type of data (if this type is already present in the map,
    *         an exception is thrown).
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @return stored data corresponding to type. */
-  inline Stored & operator()(const Stored & insert, const SupportType & type,
+  template <typename U>
+  inline Stored & operator()(U && insertee, const SupportType & type,
                              const GhostType & ghost_type = _not_ghost);
 
+public:
   /// print helper
   virtual void printself(std::ostream & stream, int indent = 0) const;
 
   /* ------------------------------------------------------------------------ */
   /* Element type Iterator                                                    */
   /* ------------------------------------------------------------------------ */
   /*! iterator allows to iterate over type-data pairs of the map. The interface
    *  expects the SupportType to be ElementType. */
   using DataMap = std::map<SupportType, Stored>;
   class type_iterator
       : private std::iterator<std::forward_iterator_tag, const SupportType> {
   public:
     using value_type = const SupportType;
     using pointer = const SupportType *;
     using reference = const SupportType &;
 
   protected:
     using DataMapIterator =
         typename ElementTypeMap<Stored>::DataMap::const_iterator;
 
   public:
     type_iterator(DataMapIterator & list_begin, DataMapIterator & list_end,
                   UInt dim, ElementKind ek);
 
     type_iterator(const type_iterator & it);
     type_iterator() = default;
 
     inline reference operator*();
     inline reference operator*() const;
     inline type_iterator & operator++();
     type_iterator operator++(int);
     inline bool operator==(const type_iterator & other) const;
     inline bool operator!=(const type_iterator & other) const;
     type_iterator & operator=(const type_iterator & other);
 
   private:
     DataMapIterator list_begin;
     DataMapIterator list_end;
     UInt dim;
     ElementKind kind;
   };
 
   /// helper class to use in range for constructions
   class ElementTypesIteratorHelper {
   public:
     using Container = ElementTypeMap<Stored, SupportType>;
     using iterator = typename Container::type_iterator;
 
     ElementTypesIteratorHelper(const Container & container, UInt dim,
                                GhostType ghost_type, ElementKind kind)
         : container(std::cref(container)), dim(dim), ghost_type(ghost_type),
           kind(kind) {}
 
     template <typename... pack>
     ElementTypesIteratorHelper(const Container & container, use_named_args_t,
                                pack &&... _pack)
         : ElementTypesIteratorHelper(
               container, OPTIONAL_NAMED_ARG(spatial_dimension, _all_dimensions),
               OPTIONAL_NAMED_ARG(ghost_type, _not_ghost),
               OPTIONAL_NAMED_ARG(element_kind, _ek_regular)) {}
 
     ElementTypesIteratorHelper(const ElementTypesIteratorHelper &) = default;
     ElementTypesIteratorHelper &
     operator=(const ElementTypesIteratorHelper &) = default;
     ElementTypesIteratorHelper &
     operator=(ElementTypesIteratorHelper &&) = default;
 
     iterator begin() {
       return container.get().firstType(dim, ghost_type, kind);
     }
     iterator end() { return container.get().lastType(dim, ghost_type, kind); }
 
   private:
     std::reference_wrapper<const Container> container;
     UInt dim;
     GhostType ghost_type;
     ElementKind kind;
   };
 
 private:
   ElementTypesIteratorHelper
   elementTypesImpl(UInt dim = _all_dimensions,
                    GhostType ghost_type = _not_ghost,
                    ElementKind kind = _ek_regular) const;
 
   template <typename... pack>
   ElementTypesIteratorHelper
   elementTypesImpl(const use_named_args_t & /*unused*/, pack &&... _pack) const;
 
 public:
+  /*!
+   * \param _spatial_dimension optional: filter for elements of given spatial
+   * dimension
+   * \param _ghost_type optional: filter for a certain ghost_type
+   * \param _element_kind optional: filter for elements of given kind
+   */
   template <typename... pack>
   std::enable_if_t<are_named_argument<pack...>::value,
                    ElementTypesIteratorHelper>
   elementTypes(pack &&... _pack) const {
     return elementTypesImpl(use_named_args,
                             std::forward<decltype(_pack)>(_pack)...);
   }
 
   template <typename... pack>
   std::enable_if_t<not are_named_argument<pack...>::value,
                    ElementTypesIteratorHelper>
   elementTypes(pack &&... _pack) const {
     return elementTypesImpl(std::forward<decltype(_pack)>(_pack)...);
   }
 
 public:
   /*! Get an iterator to the beginning of a subset datamap. This method expects
    *  the SupportType to be ElementType.
    *  @param dim optional: iterate over data of dimension dim (e.g. when
    *         iterating over (surface) facets of a 3D mesh, dim would be 2).
    *         by default, all dimensions are considered.
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is iterated over.
    *  @param kind optional: the kind of element to search for (see
    *         aka_common.hh), by default all kinds are considered
    *  @return an iterator to the first stored data matching the filters
    *          or an iterator to the end of the map if none match*/
   inline type_iterator firstType(UInt dim = _all_dimensions,
                                  GhostType ghost_type = _not_ghost,
                                  ElementKind kind = _ek_not_defined) const;
   /*! Get an iterator to the end of a subset datamap. This method expects
    *  the SupportType to be ElementType.
    *  @param dim optional: iterate over data of dimension dim (e.g. when
    *         iterating over (surface) facets of a 3D mesh, dim would be 2).
    *         by default, all dimensions are considered.
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is iterated over.
    *  @param kind optional: the kind of element to search for (see
    *         aka_common.hh), by default all kinds are considered
    *  @return an iterator to the last stored data matching the filters
    *          or an iterator to the end of the map if none match */
   inline type_iterator lastType(UInt dim = _all_dimensions,
                                 GhostType ghost_type = _not_ghost,
                                 ElementKind kind = _ek_not_defined) const;
 
 protected:
   /*! Direct access to the underlying data map. for internal use by daughter
    *  classes only
    *  @param ghost_type whether to return the data map or the ghost_data map
    *  @return the raw map */
   inline DataMap & getData(GhostType ghost_type);
   /*! Direct access to the underlying data map. for internal use by daughter
    *  classes only
    *  @param ghost_type whether to return the data map or the ghost_data map
    *  @return the raw map */
   inline const DataMap & getData(GhostType ghost_type) const;
 
   /* ------------------------------------------------------------------------ */
 protected:
   DataMap data;
   DataMap ghost_data;
 };
 
 /* -------------------------------------------------------------------------- */
 /* Some typedefs                                                              */
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 class ElementTypeMapArray : public ElementTypeMap<Array<T> *, SupportType>,
                             public Memory {
 public:
   using type = T;
   using array_type = Array<T>;
 
 protected:
   using parent = ElementTypeMap<Array<T> *, SupportType>;
   using DataMap = typename parent::DataMap;
 
 public:
   using type_iterator = typename parent::type_iterator;
 
   /// standard assigment (copy) operator
   void operator=(const ElementTypeMapArray &) = delete;
   ElementTypeMapArray(const ElementTypeMapArray &) = delete;
 
+  /// explicit copy
+  void copy(const ElementTypeMapArray & other);
+
   /*! Constructor
    *  @param id optional: identifier (string)
    *  @param parent_id optional: parent identifier. for organizational purposes
    *         only
    *  @param memory_id optional: choose a specific memory, defaults to memory 0
    */
   ElementTypeMapArray(const ID & id = "by_element_type_array",
                       const ID & parent_id = "no_parent",
                       const MemoryID & memory_id = 0)
       : parent(), Memory(parent_id + ":" + id, memory_id), name(id){};
 
   /*! allocate memory for a new array
    *  @param size number of tuples of the new array
    *  @param nb_component tuple size
    *  @param type the type under which the array is indexed in the map
    *  @param ghost_type whether to add the field to the data map or the
    *         ghost_data map
    *  @return a reference to the allocated array */
   inline Array<T> & alloc(UInt size, UInt nb_component,
                           const SupportType & type,
                           const GhostType & ghost_type,
                           const T & default_value = T());
 
   /*! allocate memory for a new array in both the data and the ghost_data map
    *  @param size number of tuples of the new array
    *  @param nb_component tuple size
    *  @param type the type under which the array is indexed in the map*/
   inline void alloc(UInt size, UInt nb_component, const SupportType & type,
                     const T & default_value = T());
 
   /* get a reference to the array of certain type
    * @param type data filed under type is returned
    * @param ghost_type optional: by default the non-ghost map is searched
    * @return a reference to the array */
   inline const Array<T> &
   operator()(const SupportType & type,
              const GhostType & ghost_type = _not_ghost) const;
 
   /// access the data of an element, this combine the map and array accessor
-  inline const T & operator()(const Element & element, UInt component = 0) const;
+  inline const T & operator()(const Element & element,
+                              UInt component = 0) const;
 
   /// access the data of an element, this combine the map and array accessor
   inline T & operator()(const Element & element, UInt component = 0);
 
   /* get a reference to the array of certain type
    * @param type data filed under type is returned
    * @param ghost_type optional: by default the non-ghost map is searched
    * @return a const reference to the array */
   inline Array<T> & operator()(const SupportType & type,
                                const GhostType & ghost_type = _not_ghost);
 
   /*! insert data of a new type (not yet present) into the map.
    *  @param type type of data (if this type is already present in the map,
    *         an exception is thrown).
    *  @param ghost_type optional: by default, the data map for non-ghost
    *         elements is searched
    *  @param vect the vector to include into the map
    *  @return stored data corresponding to type. */
   inline void setArray(const SupportType & type, const GhostType & ghost_type,
                        const Array<T> & vect);
   /*! frees all memory related to the data*/
   inline void free();
 
   /*! set all values in the ElementTypeMap to zero*/
   inline void clear();
 
   /*! set all values in the ElementTypeMap to value */
-  template<typename ST>
-  inline void set(const ST & value);
+  template <typename ST> inline void set(const ST & value);
 
   /*! deletes and reorders entries in the stored arrays
    *  @param new_numbering a ElementTypeMapArray of new indices. UInt(-1)
    * indicates
    *         deleted entries. */
   inline void
   onElementsRemoved(const ElementTypeMapArray<UInt> & new_numbering);
 
   /// text output helper
   void printself(std::ostream & stream, int indent = 0) const override;
 
   /*! set the id
    *  @param id the new name
    */
   inline void setID(const ID & id) { this->id = id; }
 
   ElementTypeMap<UInt>
   getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost,
                   ElementKind kind = _ek_not_defined) const {
 
     ElementTypeMap<UInt> nb_components;
 
     for (auto & type : this->elementTypes(dim, ghost_type, kind)) {
       UInt nb_comp = (*this)(type, ghost_type).getNbComponent();
       nb_components(type, ghost_type) = nb_comp;
     }
 
     return nb_components;
   }
 
   /* ------------------------------------------------------------------------ */
   /* more evolved allocators                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// initialize the arrays in accordance to a functor
   template <class Func>
   void initialize(const Func & f, const T & default_value, bool do_not_default);
 
   /// initialize with sizes and number of components in accordance of a mesh
   /// content
   template <typename... pack>
   void initialize(const Mesh & mesh, pack &&... _pack);
 
   /// initialize with sizes and number of components in accordance of a fe
   /// engine content (aka integration points)
   template <typename... pack>
   void initialize(const FEEngine & fe_engine, pack &&... _pack);
 
   /* ------------------------------------------------------------------------ */
   /* Accesssors                                                               */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the name of the internal field
   AKANTU_GET_MACRO(Name, name, ID);
 
   /// name of the elment type map: e.g. connectivity, grad_u
   ID name;
 };
 
 /// to store data Array<Real> by element type
 using ElementTypeMapReal = ElementTypeMapArray<Real>;
 /// to store data Array<Int> by element type
 using ElementTypeMapInt = ElementTypeMapArray<Int>;
 /// to store data Array<UInt> by element type
 using ElementTypeMapUInt = ElementTypeMapArray<UInt, ElementType>;
 
 /// Map of data of type UInt stored in a mesh
 using UIntDataMap = std::map<std::string, Array<UInt> *>;
 using ElementTypeMapUIntDataMap = ElementTypeMap<UIntDataMap, ElementType>;
 
 } // namespace akantu
 
 #endif /* __AKANTU_ELEMENT_TYPE_MAP_HH__ */
diff --git a/src/mesh/element_type_map_tmpl.hh b/src/mesh/element_type_map_tmpl.hh
index af2a331d6..23a34e1fe 100644
--- a/src/mesh/element_type_map_tmpl.hh
+++ b/src/mesh/element_type_map_tmpl.hh
@@ -1,661 +1,747 @@
 /**
  * @file   element_type_map_tmpl.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Aug 31 2011
  * @date last modification: Fri Oct 02 2015
  *
  * @brief  implementation of template functions of the ElementTypeMap and
  * ElementTypeMapArray classes
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_static_if.hh"
 #include "element_type_map.hh"
 #include "mesh.hh"
 /* -------------------------------------------------------------------------- */
 #include "element_type_conversion.hh"
 /* -------------------------------------------------------------------------- */
+#include <functional>
+/* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__
 #define __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMap                                                             */
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline std::string
 ElementTypeMap<Stored, SupportType>::printType(const SupportType & type,
                                                const GhostType & ghost_type) {
   std::stringstream sstr;
   sstr << "(" << ghost_type << ":" << type << ")";
   return sstr.str();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline bool ElementTypeMap<Stored, SupportType>::exists(
     const SupportType & type, const GhostType & ghost_type) const {
   return this->getData(ghost_type).find(type) !=
          this->getData(ghost_type).end();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline const Stored & ElementTypeMap<Stored, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) const {
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end())
     AKANTU_SILENT_EXCEPTION("No element of type "
                             << ElementTypeMap::printType(type, ghost_type)
                             << " in this ElementTypeMap<"
                             << debug::demangle(typeid(Stored).name())
                             << "> class");
   return it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline Stored & ElementTypeMap<Stored, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) {
   return this->getData(ghost_type)[type];
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
+template <typename U>
 inline Stored & ElementTypeMap<Stored, SupportType>::
-operator()(const Stored & insert, const SupportType & type,
+operator()(U && insertee, const SupportType & type,
            const GhostType & ghost_type) {
   auto it = this->getData(ghost_type).find(type);
 
   if (it != this->getData(ghost_type).end()) {
     AKANTU_SILENT_EXCEPTION("Element of type "
                             << ElementTypeMap::printType(type, ghost_type)
                             << " already in this ElementTypeMap<"
                             << debug::demangle(typeid(Stored).name())
                             << "> class");
   } else {
     auto & data = this->getData(ghost_type);
     const auto & res =
-        data.insert(std::pair<ElementType, Stored>(type, insert));
+        data.insert(std::make_pair(type, std::forward<U>(insertee)));
     it = res.first;
   }
 
   return it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::DataMap &
 ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) {
   if (ghost_type == _not_ghost)
     return data;
 
   return ghost_data;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline const typename ElementTypeMap<Stored, SupportType>::DataMap &
 ElementTypeMap<Stored, SupportType>::getData(GhostType ghost_type) const {
   if (ghost_type == _not_ghost)
     return data;
 
   return ghost_data;
 }
 
 /* -------------------------------------------------------------------------- */
 /// Works only if stored is a pointer to a class with a printself method
 template <class Stored, typename SupportType>
 void ElementTypeMap<Stored, SupportType>::printself(std::ostream & stream,
                                                     int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   stream << space << "ElementTypeMap<" << debug::demangle(typeid(Stored).name())
          << "> [" << std::endl;
   for (auto gt : ghost_types) {
     const DataMap & data = getData(gt);
     for (auto & pair : data) {
       stream << space << space << ElementTypeMap::printType(pair.first, gt)
              << std::endl;
     }
   }
 
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::ElementTypeMap() = default;
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::~ElementTypeMap() = default;
 
 /* -------------------------------------------------------------------------- */
 /* ElementTypeMapArray                                                        */
+/* -------------------------------------------------------------------------- */
+template <typename T, typename SupportType>
+void ElementTypeMapArray<T, SupportType>::copy(
+    const ElementTypeMapArray & other) {
+  for (auto && ghost_type : ghost_types) {
+    for (auto && type :
+         this->elementTypes(_all_dimensions, ghost_types, _ek_not_defined)) {
+      const auto & array_to_copy = other(type, ghost_type);
+      auto & array =
+          this->alloc(0, array_to_copy.getNbComponent(), type, ghost_type);
+      array.copy(array_to_copy);
+    }
+  }
+}
+
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline Array<T> & ElementTypeMapArray<T, SupportType>::alloc(
     UInt size, UInt nb_component, const SupportType & type,
     const GhostType & ghost_type, const T & default_value) {
   std::string ghost_id = "";
   if (ghost_type == _ghost)
     ghost_id = ":ghost";
 
   Array<T> * tmp;
 
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end()) {
     std::stringstream sstr;
     sstr << this->id << ":" << type << ghost_id;
     tmp = &(Memory::alloc<T>(sstr.str(), size, nb_component, default_value));
     std::stringstream sstrg;
     sstrg << ghost_type;
     // tmp->setTag(sstrg.str());
     this->getData(ghost_type)[type] = tmp;
   } else {
     AKANTU_DEBUG_INFO(
         "The vector "
         << this->id << this->printType(type, ghost_type)
         << " already exists, it is resized instead of allocated.");
     tmp = it->second;
     it->second->resize(size);
   }
 
   return *tmp;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void
 ElementTypeMapArray<T, SupportType>::alloc(UInt size, UInt nb_component,
                                            const SupportType & type,
                                            const T & default_value) {
   this->alloc(size, nb_component, type, _not_ghost, default_value);
   this->alloc(size, nb_component, type, _ghost, default_value);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void ElementTypeMapArray<T, SupportType>::free() {
   AKANTU_DEBUG_IN();
 
   for (auto gt : ghost_types) {
     auto & data = this->getData(gt);
     for (auto & pair : data) {
       dealloc(pair.second->getID());
     }
     data.clear();
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void ElementTypeMapArray<T, SupportType>::clear() {
   for (auto gt : ghost_types) {
     auto & data = this->getData(gt);
     for (auto & vect : data) {
       vect.second->clear();
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
-template<typename ST>
+template <typename ST>
 inline void ElementTypeMapArray<T, SupportType>::set(const ST & value) {
   for (auto gt : ghost_types) {
     auto & data = this->getData(gt);
     for (auto & vect : data) {
       vect.second->set(value);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline const Array<T> & ElementTypeMapArray<T, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) const {
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end())
     AKANTU_SILENT_EXCEPTION("No element of type "
                             << ElementTypeMapArray::printType(type, ghost_type)
                             << " in this const ElementTypeMapArray<"
                             << debug::demangle(typeid(T).name()) << "> class(\""
                             << this->id << "\")");
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline Array<T> & ElementTypeMapArray<T, SupportType>::
 operator()(const SupportType & type, const GhostType & ghost_type) {
   auto it = this->getData(ghost_type).find(type);
 
   if (it == this->getData(ghost_type).end())
     AKANTU_SILENT_EXCEPTION("No element of type "
                             << ElementTypeMapArray::printType(type, ghost_type)
                             << " in this ElementTypeMapArray<"
                             << debug::demangle(typeid(T).name())
                             << "> class (\"" << this->id << "\")");
 
   return *(it->second);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void
 ElementTypeMapArray<T, SupportType>::setArray(const SupportType & type,
                                               const GhostType & ghost_type,
                                               const Array<T> & vect) {
   auto it = this->getData(ghost_type).find(type);
 
   if (AKANTU_DEBUG_TEST(dblWarning) && it != this->getData(ghost_type).end() &&
       it->second != &vect) {
     AKANTU_DEBUG_WARNING(
         "The Array "
         << this->printType(type, ghost_type)
         << " is already registred, this call can lead to a memory leak.");
   }
 
   this->getData(ghost_type)[type] = &(const_cast<Array<T> &>(vect));
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 inline void ElementTypeMapArray<T, SupportType>::onElementsRemoved(
     const ElementTypeMapArray<UInt> & new_numbering) {
   for (auto gt : ghost_types) {
     for (auto & type :
          new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) {
       auto support_type = convertType<ElementType, SupportType>(type);
       if (this->exists(support_type, gt)) {
         const auto & renumbering = new_numbering(type, gt);
         if (renumbering.size() == 0)
           continue;
 
         auto & vect = this->operator()(support_type, gt);
         auto nb_component = vect.getNbComponent();
         Array<T> tmp(renumbering.size(), nb_component);
         UInt new_size = 0;
 
         for (UInt i = 0; i < vect.size(); ++i) {
           UInt new_i = renumbering(i);
           if (new_i != UInt(-1)) {
             memcpy(tmp.storage() + new_i * nb_component,
                    vect.storage() + i * nb_component, nb_component * sizeof(T));
             ++new_size;
           }
         }
         tmp.resize(new_size);
         vect.copy(tmp);
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 void ElementTypeMapArray<T, SupportType>::printself(std::ostream & stream,
                                                     int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   stream << space << "ElementTypeMapArray<" << debug::demangle(typeid(T).name())
          << "> [" << std::endl;
   for (UInt g = _not_ghost; g <= _ghost; ++g) {
     auto gt = (GhostType)g;
 
     const DataMap & data = this->getData(gt);
     typename DataMap::const_iterator it;
     for (it = data.begin(); it != data.end(); ++it) {
       stream << space << space << ElementTypeMapArray::printType(it->first, gt)
              << " [" << std::endl;
       it->second->printself(stream, indent + 3);
       stream << space << space << " ]" << std::endl;
     }
   }
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 /* SupportType Iterator                                                       */
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator(
     DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim,
     ElementKind ek)
     : list_begin(list_begin), list_end(list_end), dim(dim), kind(ek) {}
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 ElementTypeMap<Stored, SupportType>::type_iterator::type_iterator(
     const type_iterator & it)
     : list_begin(it.list_begin), list_end(it.list_end), dim(it.dim),
       kind(it.kind) {}
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 typename ElementTypeMap<Stored, SupportType>::type_iterator &
 ElementTypeMap<Stored, SupportType>::type_iterator::
 operator=(const type_iterator & it) {
   if (this != &it) {
     list_begin = it.list_begin;
     list_end = it.list_end;
     dim = it.dim;
     kind = it.kind;
   }
   return *this;
 }
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference
     ElementTypeMap<Stored, SupportType>::type_iterator::operator*() {
   return list_begin->first;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator::reference
     ElementTypeMap<Stored, SupportType>::type_iterator::operator*() const {
   return list_begin->first;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator &
     ElementTypeMap<Stored, SupportType>::type_iterator::operator++() {
   ++list_begin;
   while ((list_begin != list_end) &&
          (((dim != _all_dimensions) &&
            (dim != Mesh::getSpatialDimension(list_begin->first))) ||
           ((kind != _ek_not_defined) &&
            (kind != Mesh::getKind(list_begin->first)))))
     ++list_begin;
   return *this;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 typename ElementTypeMap<Stored, SupportType>::type_iterator
     ElementTypeMap<Stored, SupportType>::type_iterator::operator++(int) {
   type_iterator tmp(*this);
   operator++();
   return tmp;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline bool ElementTypeMap<Stored, SupportType>::type_iterator::
 operator==(const type_iterator & other) const {
   return this->list_begin == other.list_begin;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline bool ElementTypeMap<Stored, SupportType>::type_iterator::
 operator!=(const type_iterator & other) const {
   return this->list_begin != other.list_begin;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper
 ElementTypeMap<Stored, SupportType>::elementTypesImpl(UInt dim,
                                                       GhostType ghost_type,
                                                       ElementKind kind) const {
   return ElementTypesIteratorHelper(*this, dim, ghost_type, kind);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 template <typename... pack>
 typename ElementTypeMap<Stored, SupportType>::ElementTypesIteratorHelper
 ElementTypeMap<Stored, SupportType>::elementTypesImpl(
     const use_named_args_t & unused, pack &&... _pack) const {
   return ElementTypesIteratorHelper(*this, unused, _pack...);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator
 ElementTypeMap<Stored, SupportType>::firstType(UInt dim, GhostType ghost_type,
                                                ElementKind kind) const {
   typename DataMap::const_iterator b, e;
   b = getData(ghost_type).begin();
   e = getData(ghost_type).end();
 
   // loop until the first valid type
   while ((b != e) &&
          (((dim != _all_dimensions) &&
            (dim != Mesh::getSpatialDimension(b->first))) ||
           ((kind != _ek_not_defined) && (kind != Mesh::getKind(b->first)))))
     ++b;
 
   return typename ElementTypeMap<Stored, SupportType>::type_iterator(b, e, dim,
                                                                      kind);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Stored, typename SupportType>
 inline typename ElementTypeMap<Stored, SupportType>::type_iterator
 ElementTypeMap<Stored, SupportType>::lastType(UInt dim, GhostType ghost_type,
                                               ElementKind kind) const {
   typename DataMap::const_iterator e;
   e = getData(ghost_type).end();
   return typename ElementTypeMap<Stored, SupportType>::type_iterator(e, e, dim,
                                                                      kind);
 }
 
 /* -------------------------------------------------------------------------- */
 
 /// standard output stream operator
 template <class Stored, typename SupportType>
 inline std::ostream &
 operator<<(std::ostream & stream,
            const ElementTypeMap<Stored, SupportType> & _this) {
   _this.printself(stream);
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
-class ElementTypeMapArrayInializer {
+class ElementTypeMapArrayInitializer {
+protected:
+  using CompFunc = std::function<UInt(const ElementType &, const GhostType &)>;
+
 public:
-  ElementTypeMapArrayInializer(UInt spatial_dimension = _all_dimensions,
-                               UInt nb_component = 1,
-                               const GhostType & ghost_type = _not_ghost,
-                               const ElementKind & element_kind = _ek_regular)
-      : spatial_dimension(spatial_dimension), nb_component(nb_component),
+  ElementTypeMapArrayInitializer(const CompFunc & comp_func,
+                                 UInt spatial_dimension = _all_dimensions,
+                                 const GhostType & ghost_type = _not_ghost,
+                                 const ElementKind & element_kind = _ek_regular)
+      : comp_func(comp_func), spatial_dimension(spatial_dimension),
         ghost_type(ghost_type), element_kind(element_kind) {}
 
   const GhostType & ghostType() const { return ghost_type; }
 
+  virtual UInt nbComponent(const ElementType & type) const {
+    return comp_func(type, ghostType());
+  }
+
 protected:
+  CompFunc comp_func;
   UInt spatial_dimension;
-  UInt nb_component;
   GhostType ghost_type;
   ElementKind element_kind;
 };
 
 /* -------------------------------------------------------------------------- */
-class MeshElementTypeMapArrayInializer : public ElementTypeMapArrayInializer {
+class MeshElementTypeMapArrayInitializer
+    : public ElementTypeMapArrayInitializer {
+  using CompFunc = ElementTypeMapArrayInitializer::CompFunc;
+
 public:
-  MeshElementTypeMapArrayInializer(
+  MeshElementTypeMapArrayInitializer(
       const Mesh & mesh, UInt nb_component = 1,
       UInt spatial_dimension = _all_dimensions,
       const GhostType & ghost_type = _not_ghost,
       const ElementKind & element_kind = _ek_regular,
       bool with_nb_element = false, bool with_nb_nodes_per_element = false)
-      : ElementTypeMapArrayInializer(spatial_dimension, nb_component,
-                                     ghost_type, element_kind),
+      : MeshElementTypeMapArrayInitializer(
+            mesh,
+            [nb_component](const ElementType &, const GhostType &) -> UInt {
+              return nb_component;
+            },
+            spatial_dimension, ghost_type, element_kind, with_nb_element,
+            with_nb_nodes_per_element) {}
+
+  MeshElementTypeMapArrayInitializer(
+      const Mesh & mesh, const CompFunc & comp_func,
+      UInt spatial_dimension = _all_dimensions,
+      const GhostType & ghost_type = _not_ghost,
+      const ElementKind & element_kind = _ek_regular,
+      bool with_nb_element = false, bool with_nb_nodes_per_element = false)
+      : ElementTypeMapArrayInitializer(comp_func, spatial_dimension, ghost_type,
+                                       element_kind),
         mesh(mesh), with_nb_element(with_nb_element),
         with_nb_nodes_per_element(with_nb_nodes_per_element) {}
 
   decltype(auto) elementTypes() const {
     return mesh.elementTypes(this->spatial_dimension, this->ghost_type,
                              this->element_kind);
   }
 
   virtual UInt size(const ElementType & type) const {
     if (with_nb_element)
       return mesh.getNbElement(type, this->ghost_type);
 
     return 0;
   }
 
-  UInt nbComponent(const ElementType & type) const {
+  UInt nbComponent(const ElementType & type) const override {
+    UInt res = ElementTypeMapArrayInitializer::nbComponent(type);
     if (with_nb_nodes_per_element)
-      return (this->nb_component * mesh.getNbNodesPerElement(type));
+      return (res * mesh.getNbNodesPerElement(type));
 
-    return this->nb_component;
+    return res;
   }
 
 protected:
   const Mesh & mesh;
   bool with_nb_element;
   bool with_nb_nodes_per_element;
 };
 
 /* -------------------------------------------------------------------------- */
-class FEEngineElementTypeMapArrayInializer
-    : public MeshElementTypeMapArrayInializer {
+class FEEngineElementTypeMapArrayInitializer
+    : public MeshElementTypeMapArrayInitializer {
 public:
-  FEEngineElementTypeMapArrayInializer(
+  FEEngineElementTypeMapArrayInitializer(
       const FEEngine & fe_engine, UInt nb_component = 1,
       UInt spatial_dimension = _all_dimensions,
       const GhostType & ghost_type = _not_ghost,
       const ElementKind & element_kind = _ek_regular);
 
+  FEEngineElementTypeMapArrayInitializer(
+      const FEEngine & fe_engine,
+      const ElementTypeMapArrayInitializer::CompFunc & nb_component,
+      UInt spatial_dimension = _all_dimensions,
+      const GhostType & ghost_type = _not_ghost,
+      const ElementKind & element_kind = _ek_regular);
+
   UInt size(const ElementType & type) const override;
 
   using ElementTypesIteratorHelper =
       ElementTypeMapArray<Real, ElementType>::ElementTypesIteratorHelper;
 
   ElementTypesIteratorHelper elementTypes() const;
 
 protected:
   const FEEngine & fe_engine;
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T, typename SupportType>
 template <class Func>
 void ElementTypeMapArray<T, SupportType>::initialize(const Func & f,
                                                      const T & default_value,
                                                      bool do_not_default) {
+  auto ghost_type = f.ghostType();
   for (auto & type : f.elementTypes()) {
-    if (not this->exists(type, f.ghostType()))
+    if (not this->exists(type, ghost_type))
       if (do_not_default) {
-        auto & array = this->alloc(0, f.nbComponent(type), type, f.ghostType());
+        auto & array = this->alloc(0, f.nbComponent(type), type, ghost_type);
         array.resize(f.size(type));
       } else {
-        this->alloc(f.size(type), f.nbComponent(type), type, f.ghostType(),
+        this->alloc(f.size(type), f.nbComponent(type), type, ghost_type,
                     default_value);
       }
     else {
-      auto & array = this->operator()(type, f.ghostType());
+      auto & array = this->operator()(type, ghost_type);
       if (not do_not_default)
         array.resize(f.size(type), default_value);
       else
         array.resize(f.size(type));
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * All parameters are named optionals
+ *  \param _nb_component a functor giving the number of components per
+ *  (ElementType, GhostType) pair or a scalar giving a unique number of
+ * components
+ *  regardless of type
+ *  \param _spatial_dimension a filter for the elements of a specific dimension
+ *  \param _element_kind filter with element kind (_ek_regular, _ek_structural,
+ * ...)
+ *  \param _with_nb_element allocate the arrays with the number of elements for
+ * each
+ *  type in the mesh
+ *  \param _with_nb_nodes_per_element multiply the number of components by the
+ *  number of nodes per element
+ *  \param _default_value default inital value
+ *  \param _do_not_default do not initialize the allocated arrays
+ *  \param _ghost_type filter a type of ghost
+ */
 template <typename T, typename SupportType>
 template <typename... pack>
 void ElementTypeMapArray<T, SupportType>::initialize(const Mesh & mesh,
                                                      pack &&... _pack) {
   GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _casper);
   bool all_ghost_types = requested_ghost_type == _casper;
 
   for (auto ghost_type : ghost_types) {
     if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types))
       continue;
 
-    this->initialize(
-        MeshElementTypeMapArrayInializer(
-            mesh, OPTIONAL_NAMED_ARG(nb_component, 1),
-            OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()),
-            ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular),
-            OPTIONAL_NAMED_ARG(with_nb_element, false),
-            OPTIONAL_NAMED_ARG(with_nb_nodes_per_element, false)),
-        OPTIONAL_NAMED_ARG(default_value, T()),
-        OPTIONAL_NAMED_ARG(do_not_default, false));
+    // This thing should have a UInt or functor type
+    auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1);
+    auto functor = MeshElementTypeMapArrayInitializer(
+        mesh, std::forward<decltype(nb_components)>(nb_components),
+        OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()),
+        ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular),
+        OPTIONAL_NAMED_ARG(with_nb_element, false),
+        OPTIONAL_NAMED_ARG(with_nb_nodes_per_element, false));
+
+    this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()),
+                     OPTIONAL_NAMED_ARG(do_not_default, false));
   }
 }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * All parameters are named optionals
+ *  \param _nb_component a functor giving the number of components per
+ *  (ElementType, GhostType) pair or a scalar giving a unique number of
+ * components
+ *  regardless of type
+ *  \param _spatial_dimension a filter for the elements of a specific dimension
+ *  \param _element_kind filter with element kind (_ek_regular, _ek_structural,
+ * ...)
+ *  \param _default_value default inital value
+ *  \param _do_not_default do not initialize the allocated arrays
+ *  \param _ghost_type filter a specific ghost type
+ *  \param _all_ghost_types get all ghost types
+ */
 template <typename T, typename SupportType>
 template <typename... pack>
 void ElementTypeMapArray<T, SupportType>::initialize(const FEEngine & fe_engine,
                                                      pack &&... _pack) {
   bool all_ghost_types = OPTIONAL_NAMED_ARG(all_ghost_types, true);
   GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _not_ghost);
 
   for (auto ghost_type : ghost_types) {
     if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types))
       continue;
 
-    this->initialize(FEEngineElementTypeMapArrayInializer(
-                         fe_engine, OPTIONAL_NAMED_ARG(nb_component, 1),
-                         OPTIONAL_NAMED_ARG(spatial_dimension, UInt(-2)),
-                         ghost_type,
-                         OPTIONAL_NAMED_ARG(element_kind, _ek_regular)),
-                     OPTIONAL_NAMED_ARG(default_value, T()),
+    auto && nb_components = OPTIONAL_NAMED_ARG(nb_component, 1);
+    auto functor = FEEngineElementTypeMapArrayInitializer(
+        fe_engine, std::forward<decltype(nb_components)>(nb_components),
+        OPTIONAL_NAMED_ARG(spatial_dimension, UInt(-2)), ghost_type,
+        OPTIONAL_NAMED_ARG(element_kind, _ek_regular));
+
+    this->initialize(functor, OPTIONAL_NAMED_ARG(default_value, T()),
                      OPTIONAL_NAMED_ARG(do_not_default, false));
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <class T, typename SupportType>
 inline T & ElementTypeMapArray<T, SupportType>::
 operator()(const Element & element, UInt component) {
   return this->operator()(element.type, element.ghost_type)(element.element,
                                                             component);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class T, typename SupportType>
 inline const T & ElementTypeMapArray<T, SupportType>::
 operator()(const Element & element, UInt component) const {
   return this->operator()(element.type, element.ghost_type)(element.element,
                                                             component);
 }
 
 } // namespace akantu
 
 #endif /* __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ */
diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc
index 0991360f0..49cd44069 100644
--- a/src/mesh/mesh.cc
+++ b/src/mesh/mesh.cc
@@ -1,545 +1,571 @@
 /**
  * @file   mesh.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Fri Jan 22 2016
  *
  * @brief  class handling meshes
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_config.hh"
 /* -------------------------------------------------------------------------- */
 #include "element_class.hh"
 #include "group_manager_inline_impl.cc"
 #include "mesh.hh"
 #include "mesh_io.hh"
 #include "mesh_iterators.hh"
 #include "mesh_utils.hh"
 /* -------------------------------------------------------------------------- */
 #include "communicator.hh"
 #include "element_synchronizer.hh"
 #include "facet_synchronizer.hh"
 #include "mesh_utils_distribution.hh"
 #include "node_synchronizer.hh"
 /* -------------------------------------------------------------------------- */
 #ifdef AKANTU_USE_IOHELPER
 #include "dumper_field.hh"
 #include "dumper_internal_material_field.hh"
 #endif
 /* -------------------------------------------------------------------------- */
 #include <limits>
 #include <sstream>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id,
            Communicator & communicator)
     : Memory(id, memory_id),
       GroupManager(*this, id + ":group_manager", memory_id),
       nodes_type(0, 1, id + ":nodes_type"),
       connectivities("connectivities", id, memory_id),
       ghosts_counters("ghosts_counters", id, memory_id),
       normals("normals", id, memory_id), spatial_dimension(spatial_dimension),
       lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.),
       size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.),
       local_upper_bounds(spatial_dimension, 0.),
       mesh_data("mesh_data", id, memory_id), communicator(&communicator) {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Mesh::Mesh(UInt spatial_dimension, Communicator & communicator, const ID & id,
            const MemoryID & memory_id)
     : Mesh(spatial_dimension, id, memory_id, communicator) {
   AKANTU_DEBUG_IN();
 
   this->nodes =
       std::make_shared<Array<Real>>(0, spatial_dimension, id + ":coordinates");
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id)
     : Mesh(spatial_dimension, Communicator::getStaticCommunicator(), id,
            memory_id) {}
 
 /* -------------------------------------------------------------------------- */
 Mesh::Mesh(UInt spatial_dimension, const std::shared_ptr<Array<Real>> & nodes,
            const ID & id, const MemoryID & memory_id)
     : Mesh(spatial_dimension, id, memory_id,
            Communicator::getStaticCommunicator()) {
   this->nodes = nodes;
 
   this->nb_global_nodes = this->nodes->size();
 
   this->nodes_to_elements.resize(nodes->size());
   for (auto & node_set : nodes_to_elements) {
     node_set = std::make_unique<std::set<Element>>();
   }
 
   this->computeBoundingBox();
 }
 
+/* -------------------------------------------------------------------------- */
+void Mesh::getBarycenters(Array<Real> & barycenter, const ElementType & type,
+                          const GhostType & ghost_type) const {
+  barycenter.resize(getNbElement(type, ghost_type));
+  for (auto && data : enumerate(make_view(barycenter, spatial_dimension))) {
+    getBarycenter(Element{type, UInt(std::get<0>(data)), ghost_type},
+                  std::get<1>(data));
+  }
+}
+
 /* -------------------------------------------------------------------------- */
 Mesh & Mesh::initMeshFacets(const ID & id) {
   AKANTU_DEBUG_IN();
 
   if (!mesh_facets) {
     mesh_facets = std::make_unique<Mesh>(spatial_dimension, this->nodes,
                                          getID() + ":" + id, getMemoryID());
 
     mesh_facets->mesh_parent = this;
     mesh_facets->is_mesh_facets = true;
 
     MeshUtils::buildAllFacets(*this, *mesh_facets, 0);
 
     if (mesh.isDistributed()) {
       mesh_facets->is_distributed = true;
       mesh_facets->element_synchronizer = std::make_unique<FacetSynchronizer>(
           *mesh_facets, mesh.getElementSynchronizer());
     }
 
     /// transfers the the mesh physical names to the mesh facets
     if (not this->hasData("physical_names")) {
       AKANTU_DEBUG_OUT();
       return *mesh_facets;
     }
 
     if (not mesh_facets->hasData("physical_names")) {
       mesh_facets->registerData<std::string>("physical_names");
     }
 
     auto & mesh_phys_data = this->getData<std::string>("physical_names");
     auto & phys_data = mesh_facets->getData<std::string>("physical_names");
     phys_data.initialize(*mesh_facets,
                          _spatial_dimension = spatial_dimension - 1,
                          _with_nb_element = true);
 
+    ElementTypeMapArray<Real> barycenters(getID(), "temporary_barycenters");
+    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);
+      }
+    }
+
     for_each_element(
         mesh,
         [&](auto && element) {
           Vector<Real> barycenter(spatial_dimension);
           mesh.getBarycenter(element, barycenter);
           auto norm_barycenter = barycenter.norm();
+          auto tolerance = Math::getTolerance();
+          if (norm_barycenter > tolerance)
+            tolerance *= norm_barycenter;
 
           const auto & element_to_facet = mesh_facets->getElementToSubelement(
               element.type, element.ghost_type);
 
           Vector<Real> barycenter_facet(spatial_dimension);
-          auto nb_facet =
-              mesh_facets->getNbElement(element.type, element.ghost_type);
 
-          auto range = arange(nb_facet);
+          auto range =
+              enumerate(make_view(barycenters(element.type, element.ghost_type),
+                                  spatial_dimension));
 #ifndef AKANTU_NDEBUG
           auto min_dist = std::numeric_limits<Real>::max();
 #endif
           // this is a spacial search coded the most inefficient way.
           auto facet =
-              std::find_if(range.begin(), range.end(), [&](auto && facet) {
+              std::find_if(range.begin(), range.end(), [&](auto && data) {
+                auto facet = std::get<0>(data);
                 if (element_to_facet(facet)[1] == ElementNull)
                   return false;
 
-                mesh_facets->getBarycenter(
-                    Element{element.type, facet, element.ghost_type},
-                    barycenter_facet);
-                auto norm_distance = barycenter_facet.distance(barycenter);
+                auto norm_distance = barycenter.distance(std::get<1>(data));
 #ifndef AKANTU_NDEBUG
                 min_dist = std::min(min_dist, norm_distance);
 #endif
-                return (norm_distance <
-                        (Math::getTolerance() * norm_barycenter));
+                return (norm_distance < tolerance);
               });
+
           if (facet == range.end()) {
-            AKANTU_DEBUG_INFO(
-                "The element "
-                << element << " did not find its associated facet in the "
-                              "mesh_facets! Try to decrease math tolerance. "
-                              "The closest element was at a distance of "
-                << min_dist);
+            AKANTU_DEBUG_INFO("The element "
+                              << element
+                              << " did not find its associated facet in the "
+                                 "mesh_facets! Try to decrease math tolerance. "
+                                 "The closest element was at a distance of "
+                              << min_dist);
             return;
           }
 
           // set physical name
-          phys_data(Element{element.type, *facet, element.ghost_type}) =
-              mesh_phys_data(element);
+          phys_data(Element{element.type, UInt(std::get<0>(*facet)),
+                            element.ghost_type}) = mesh_phys_data(element);
         },
         _spatial_dimension = spatial_dimension - 1);
 
     mesh_facets->createGroupsFromMeshData<std::string>("physical_names");
   }
 
   AKANTU_DEBUG_OUT();
   return *mesh_facets;
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::defineMeshParent(const Mesh & mesh) {
   AKANTU_DEBUG_IN();
 
   this->mesh_parent = &mesh;
   this->is_mesh_facets = true;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Mesh::~Mesh() = default;
 
 /* -------------------------------------------------------------------------- */
 void Mesh::read(const std::string & filename, const MeshIOType & mesh_io_type) {
   MeshIO mesh_io;
   mesh_io.read(filename, *this, mesh_io_type);
 
   type_iterator it =
       this->firstType(spatial_dimension, _not_ghost, _ek_not_defined);
   type_iterator last =
       this->lastType(spatial_dimension, _not_ghost, _ek_not_defined);
   if (it == last)
     AKANTU_EXCEPTION(
         "The mesh contained in the file "
         << filename << " does not seem to be of the good dimension."
         << " No element of dimension " << spatial_dimension << " where read.");
 
   this->nb_global_nodes = this->nodes->size();
 
   this->computeBoundingBox();
 
   this->nodes_to_elements.resize(nodes->size());
   for (auto & node_set : nodes_to_elements) {
     node_set = std::make_unique<std::set<Element>>();
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::write(const std::string & filename,
                  const MeshIOType & mesh_io_type) {
   MeshIO mesh_io;
   mesh_io.write(filename, *this, mesh_io_type);
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::printself(std::ostream & stream, int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   stream << space << "Mesh [" << std::endl;
   stream << space << " + id                : " << getID() << std::endl;
   stream << space << " + spatial dimension : " << this->spatial_dimension
          << std::endl;
   stream << space << " + nodes [" << std::endl;
   nodes->printself(stream, indent + 2);
   stream << space << " + connectivities [" << std::endl;
   connectivities.printself(stream, indent + 2);
   stream << space << " ]" << std::endl;
 
   GroupManager::printself(stream, indent + 1);
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::computeBoundingBox() {
   AKANTU_DEBUG_IN();
   for (UInt k = 0; k < spatial_dimension; ++k) {
     local_lower_bounds(k) = std::numeric_limits<double>::max();
     local_upper_bounds(k) = -std::numeric_limits<double>::max();
   }
 
   for (UInt i = 0; i < nodes->size(); ++i) {
     //    if(!isPureGhostNode(i))
     for (UInt k = 0; k < spatial_dimension; ++k) {
       local_lower_bounds(k) = std::min(local_lower_bounds[k], (*nodes)(i, k));
       local_upper_bounds(k) = std::max(local_upper_bounds[k], (*nodes)(i, k));
     }
   }
 
   if (this->is_distributed) {
     Matrix<Real> reduce_bounds(spatial_dimension, 2);
     for (UInt k = 0; k < spatial_dimension; ++k) {
       reduce_bounds(k, 0) = local_lower_bounds(k);
       reduce_bounds(k, 1) = -local_upper_bounds(k);
     }
 
     communicator->allReduce(reduce_bounds, SynchronizerOperation::_min);
 
     for (UInt k = 0; k < spatial_dimension; ++k) {
       lower_bounds(k) = reduce_bounds(k, 0);
       upper_bounds(k) = -reduce_bounds(k, 1);
     }
   } else {
     this->lower_bounds = this->local_lower_bounds;
     this->upper_bounds = this->local_upper_bounds;
   }
 
   size = upper_bounds - lower_bounds;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::initNormals() {
   normals.initialize(*this, _nb_component = spatial_dimension,
                      _spatial_dimension = spatial_dimension,
                      _element_kind = _ek_not_defined);
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::getGlobalConnectivity(
     ElementTypeMapArray<UInt> & global_connectivity) {
   AKANTU_DEBUG_IN();
 
   for (auto && ghost_type : ghost_types) {
     for (auto type :
-         global_connectivity.elementTypes(_ghost_type = ghost_type)) {
+             global_connectivity.elementTypes(_spatial_dimension = _all_dimensions,
+                                              _element_kind = _ek_not_defined,
+                                              _ghost_type = ghost_type)) {
       if (not connectivities.exists(type, ghost_type))
         continue;
 
       auto & local_conn = connectivities(type, ghost_type);
       auto & g_connectivity = global_connectivity(type, ghost_type);
 
       UInt nb_nodes = local_conn.size() * local_conn.getNbComponent();
 
       if (not nodes_global_ids && is_mesh_facets) {
         std::transform(
             local_conn.begin_reinterpret(nb_nodes),
             local_conn.end_reinterpret(nb_nodes),
             g_connectivity.begin_reinterpret(nb_nodes),
             [& node_ids = *mesh_parent->nodes_global_ids](UInt l)->UInt {
               return node_ids(l);
             });
       } else {
         std::transform(local_conn.begin_reinterpret(nb_nodes),
                        local_conn.end_reinterpret(nb_nodes),
                        g_connectivity.begin_reinterpret(nb_nodes),
                        [& node_ids = *nodes_global_ids](UInt l)->UInt {
                          return node_ids(l);
                        });
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 DumperIOHelper & Mesh::getGroupDumper(const std::string & dumper_name,
                                       const std::string & group_name) {
   if (group_name == "all")
     return this->getDumper(dumper_name);
   else
     return element_groups[group_name]->getDumper(dumper_name);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 ElementTypeMap<UInt> Mesh::getNbDataPerElem(ElementTypeMapArray<T> & arrays,
                                             const ElementKind & element_kind) {
   ElementTypeMap<UInt> nb_data_per_elem;
 
   for (auto type : elementTypes(spatial_dimension, _not_ghost, element_kind)) {
     UInt nb_elements = this->getNbElement(type);
     auto & array = arrays(type);
 
     nb_data_per_elem(type) = array.getNbComponent() * array.size();
     nb_data_per_elem(type) /= nb_elements;
   }
 
   return nb_data_per_elem;
 }
 
 /* -------------------------------------------------------------------------- */
 template ElementTypeMap<UInt>
 Mesh::getNbDataPerElem(ElementTypeMapArray<Real> & array,
                        const ElementKind & element_kind);
 
 template ElementTypeMap<UInt>
 Mesh::getNbDataPerElem(ElementTypeMapArray<UInt> & array,
                        const ElementKind & element_kind);
 
 /* -------------------------------------------------------------------------- */
 #ifdef AKANTU_USE_IOHELPER
 template <typename T>
 dumper::Field *
 Mesh::createFieldFromAttachedData(const std::string & field_id,
                                   const std::string & group_name,
                                   const ElementKind & element_kind) {
 
   dumper::Field * field = nullptr;
   ElementTypeMapArray<T> * internal = nullptr;
   try {
     internal = &(this->getData<T>(field_id));
   } catch (...) {
     return nullptr;
   }
 
   ElementTypeMap<UInt> nb_data_per_elem =
       this->getNbDataPerElem(*internal, element_kind);
 
   field = this->createElementalField<T, dumper::InternalMaterialField>(
       *internal, group_name, this->spatial_dimension, element_kind,
       nb_data_per_elem);
 
   return field;
 }
 
 template dumper::Field *
 Mesh::createFieldFromAttachedData<Real>(const std::string & field_id,
                                         const std::string & group_name,
                                         const ElementKind & element_kind);
 
 template dumper::Field *
 Mesh::createFieldFromAttachedData<UInt>(const std::string & field_id,
                                         const std::string & group_name,
                                         const ElementKind & element_kind);
 #endif
 
 /* -------------------------------------------------------------------------- */
 void Mesh::distribute() {
   this->distribute(Communicator::getStaticCommunicator());
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::distribute(Communicator & communicator) {
   AKANTU_DEBUG_ASSERT(is_distributed == false,
                       "This mesh is already distribute");
   this->communicator = &communicator;
 
   this->element_synchronizer = std::make_unique<ElementSynchronizer>(
       *this, this->getID() + ":element_synchronizer", this->getMemoryID(),
       true);
 
   this->node_synchronizer = std::make_unique<NodeSynchronizer>(
       *this, this->getID() + ":node_synchronizer", this->getMemoryID(), true);
 
   Int psize = this->communicator->getNbProc();
 #ifdef AKANTU_USE_SCOTCH
   Int prank = this->communicator->whoAmI();
   if (prank == 0) {
     MeshPartitionScotch partition(*this, spatial_dimension);
     partition.partitionate(psize);
 
     MeshUtilsDistribution::distributeMeshCentralized(*this, 0, partition);
   } else {
     MeshUtilsDistribution::distributeMeshCentralized(*this, 0);
   }
 #else
   if (!(psize == 1)) {
     AKANTU_DEBUG_ERROR("Cannot distribute a mesh without a partitioning tool");
   }
 #endif
 
   this->is_distributed = true;
   this->computeBoundingBox();
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::getAssociatedElements(const Array<UInt> & node_list,
                                  Array<Element> & elements) {
   for (const auto & node : node_list)
     for (const auto & element : *nodes_to_elements[node])
       elements.push_back(element);
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::fillNodesToElements() {
   Element e;
 
   UInt nb_nodes = nodes->size();
   for (UInt n = 0; n < nb_nodes; ++n) {
     if (this->nodes_to_elements[n])
       this->nodes_to_elements[n]->clear();
     else
       this->nodes_to_elements[n] = std::make_unique<std::set<Element>>();
   }
 
   for (auto ghost_type : ghost_types) {
     e.ghost_type = ghost_type;
     for (const auto & type :
          elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) {
       e.type = type;
 
       UInt nb_element = this->getNbElement(type, ghost_type);
       Array<UInt>::const_iterator<Vector<UInt>> conn_it =
           connectivities(type, ghost_type)
               .begin(Mesh::getNbNodesPerElement(type));
 
       for (UInt el = 0; el < nb_element; ++el, ++conn_it) {
         e.element = el;
         const Vector<UInt> & conn = *conn_it;
         for (UInt n = 0; n < conn.size(); ++n)
           nodes_to_elements[conn(n)]->insert(e);
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void Mesh::eraseElements(const Array<Element> & elements) {
   ElementTypeMap<UInt> last_element;
 
   RemovedElementsEvent event(*this);
   auto & remove_list = event.getList();
   auto & new_numbering = event.getNewNumbering();
 
   for (auto && el : elements) {
     if (el.ghost_type != _not_ghost) {
       auto & count = ghosts_counters(el);
       --count;
       if (count > 0)
         continue;
     }
 
     remove_list.push_back(el);
     if (not last_element.exists(el.type, el.ghost_type)) {
       UInt nb_element = mesh.getNbElement(el.type, el.ghost_type);
       last_element(nb_element - 1, el.type, el.ghost_type);
       auto & numbering =
           new_numbering.alloc(nb_element, 1, el.type, el.ghost_type);
       for (auto && pair : enumerate(numbering)) {
         std::get<1>(pair) = std::get<0>(pair);
       }
     }
 
     UInt & pos = last_element(el.type, el.ghost_type);
     auto & numbering = new_numbering(el.type, el.ghost_type);
 
     numbering(el.element) = UInt(-1);
     numbering(pos) = el.element;
     --pos;
   }
 
   this->sendEvent(event);
 }
 
 } // namespace akantu
diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh
index 06d3a8481..ffdd11510 100644
--- a/src/mesh/mesh.hh
+++ b/src/mesh/mesh.hh
@@ -1,610 +1,613 @@
 /**
  * @file   mesh.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Dana Christen <dana.christen@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Thu Jan 14 2016
  *
  * @brief  the class representing the meshes
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #ifndef __AKANTU_MESH_HH__
 #define __AKANTU_MESH_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_array.hh"
 #include "aka_event_handler_manager.hh"
 #include "aka_memory.hh"
 #include "dumpable.hh"
 #include "element.hh"
 #include "element_class.hh"
 #include "element_type_map.hh"
 #include "group_manager.hh"
 #include "mesh_data.hh"
 #include "mesh_events.hh"
 /* -------------------------------------------------------------------------- */
 #include <set>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 class Communicator;
 class ElementSynchronizer;
 class NodeSynchronizer;
 } // namespace akantu
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /* Mesh                                                                       */
 /* -------------------------------------------------------------------------- */
 
 /**
  * @class  Mesh this  contain the  coordinates of  the nodes  in  the Mesh.nodes
  * Array,  and the  connectivity. The  connectivity  are stored  in by  element
  * types.
  *
  * In order to loop on all element you have to loop on all types like this :
  * @code{.cpp}
  for(auto & type : mesh.elementTypes()) {
    UInt nb_element  = mesh.getNbElement(type);
    const Array<UInt> & conn = mesh.getConnectivity(type);
    for(UInt e = 0; e < nb_element; ++e) {
      ...
    }
  }
 
  or
 
  for_each_element(mesh, [](Element & element) {
     std::cout << element << std::endl
   });
  @endcode
 */
 class Mesh : protected Memory,
              public EventHandlerManager<MeshEventHandler>,
              public GroupManager,
              public Dumpable {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 private:
   /// default constructor used for chaining, the last parameter is just to
   /// differentiate constructors
   Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id,
        Communicator & communicator);
 
 public:
   /// constructor that create nodes coordinates array
   Mesh(UInt spatial_dimension, const ID & id = "mesh",
        const MemoryID & memory_id = 0);
 
   /// mesh not distributed and not using the default communicator
   Mesh(UInt spatial_dimension, Communicator & communicator,
        const ID & id = "mesh", const MemoryID & memory_id = 0);
 
   /// constructor that use an existing nodes coordinates array, by knowing its
   /// ID
   // Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id,
   //      const MemoryID & memory_id = 0);
 
   /**
    * constructor that use an existing nodes coordinates
    * array, by getting the vector of coordinates
    */
   Mesh(UInt spatial_dimension, const std::shared_ptr<Array<Real>> & nodes,
        const ID & id = "mesh", const MemoryID & memory_id = 0);
 
   ~Mesh() override;
 
   /// @typedef ConnectivityTypeList list of the types present in a Mesh
   using ConnectivityTypeList = std::set<ElementType>;
 
   /// read the mesh from a file
   void read(const std::string & filename,
             const MeshIOType & mesh_io_type = _miot_auto);
   /// write the mesh to a file
   void write(const std::string & filename,
              const MeshIOType & mesh_io_type = _miot_auto);
 
 private:
   /// initialize the connectivity to NULL and other stuff
   void init();
 
   /// function that computes the bounding box (fills xmin, xmax)
   void computeBoundingBox();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// patitionate the mesh among the processors involved in their computation
   virtual void distribute(Communicator & communicator);
   virtual void distribute();
 
   /// function to print the containt of the class
   void printself(std::ostream & stream, int indent = 0) const override;
 
   /// extract coordinates of nodes from an element
   template <typename T>
   inline void extractNodalValuesFromElement(const Array<T> & nodal_values,
                                             T * elemental_values,
                                             UInt * connectivity, UInt n_nodes,
                                             UInt nb_degree_of_freedom) const;
 
   // /// extract coordinates of nodes from a reversed element
   // inline void extractNodalCoordinatesFromPBCElement(Real * local_coords,
   //                                                   UInt * connectivity,
   //                                                   UInt n_nodes);
 
   /// add a Array of connectivity for the type <type>.
   inline void addConnectivityType(const ElementType & type,
                                   const GhostType & ghost_type = _not_ghost);
 
   /* ------------------------------------------------------------------------ */
   template <class Event> inline void sendEvent(Event & event) {
     //    if(event.getList().size() != 0)
     EventHandlerManager<MeshEventHandler>::sendEvent<Event>(event);
   }
 
   /// prepare the  event to remove the elements listed
   void eraseElements(const Array<Element> & elements);
 
   /* ------------------------------------------------------------------------ */
   template <typename T>
   inline void removeNodesFromArray(Array<T> & vect,
                                    const Array<UInt> & new_numbering);
 
   /// initialize normals
   void initNormals();
 
   /// init facets' mesh
   Mesh & initMeshFacets(const ID & id = "mesh_facets");
 
   /// define parent mesh
   void defineMeshParent(const Mesh & mesh);
 
   /// get global connectivity array
   void getGlobalConnectivity(ElementTypeMapArray<UInt> & global_connectivity);
 
 public:
   void getAssociatedElements(const Array<UInt> & node_list,
                              Array<Element> & elements);
 
 private:
   /// fills the nodes_to_elements structure
   void fillNodesToElements();
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the id of the mesh
   AKANTU_GET_MACRO(ID, Memory::id, const ID &);
 
   /// get the id of the mesh
   AKANTU_GET_MACRO(MemoryID, Memory::memory_id, const MemoryID &);
 
   /// get the spatial dimension of the mesh = number of component of the
   /// coordinates
   AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt);
 
   /// get the nodes Array aka coordinates
   AKANTU_GET_MACRO(Nodes, *nodes, const Array<Real> &);
   AKANTU_GET_MACRO_NOT_CONST(Nodes, *nodes, Array<Real> &);
 
   /// get the normals for the elements
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Normals, normals, Real);
 
   /// get the number of nodes
   AKANTU_GET_MACRO(NbNodes, nodes->size(), UInt);
 
   /// get the Array of global ids of the nodes (only used in parallel)
   AKANTU_GET_MACRO(GlobalNodesIds, *nodes_global_ids, const Array<UInt> &);
   AKANTU_GET_MACRO_NOT_CONST(GlobalNodesIds, *nodes_global_ids, Array<UInt> &);
 
   /// get the global id of a node
   inline UInt getNodeGlobalId(UInt local_id) const;
 
   /// get the global id of a node
   inline UInt getNodeLocalId(UInt global_id) const;
 
   /// get the global number of nodes
   inline UInt getNbGlobalNodes() const;
 
   /// get the nodes type Array
   AKANTU_GET_MACRO(NodesType, nodes_type, const Array<NodeType> &);
 
 protected:
   AKANTU_GET_MACRO_NOT_CONST(NodesType, nodes_type, Array<NodeType> &);
 
 public:
   inline NodeType getNodeType(UInt local_id) const;
 
   /// say if a node is a pure ghost node
   inline bool isPureGhostNode(UInt n) const;
 
   /// say if a node is pur local or master node
   inline bool isLocalOrMasterNode(UInt n) const;
 
   inline bool isLocalNode(UInt n) const;
   inline bool isMasterNode(UInt n) const;
   inline bool isSlaveNode(UInt n) const;
 
   AKANTU_GET_MACRO(LowerBounds, lower_bounds, const Vector<Real> &);
   AKANTU_GET_MACRO(UpperBounds, upper_bounds, const Vector<Real> &);
   AKANTU_GET_MACRO(LocalLowerBounds, local_lower_bounds, const Vector<Real> &);
   AKANTU_GET_MACRO(LocalUpperBounds, local_upper_bounds, const Vector<Real> &);
 
   /// get the connectivity Array for a given type
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Connectivity, connectivities, UInt);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Connectivity, connectivities, UInt);
   AKANTU_GET_MACRO(Connectivities, connectivities,
                    const ElementTypeMapArray<UInt> &);
 
   /// get the number of element of a type in the mesh
   inline UInt getNbElement(const ElementType & type,
                            const GhostType & ghost_type = _not_ghost) const;
 
   /// get the number of element for a given ghost_type and a given dimension
   inline UInt getNbElement(const UInt spatial_dimension = _all_dimensions,
                            const GhostType & ghost_type = _not_ghost,
                            const ElementKind & kind = _ek_not_defined) const;
 
   // /// get the connectivity list either for the elements or the ghost elements
   // inline const ConnectivityTypeList &
   // getConnectivityTypeList(const GhostType & ghost_type = _not_ghost) const;
 
   /// compute the barycenter of a given element
 private:
   inline void getBarycenter(UInt element, const ElementType & type,
                             Real * barycenter,
                             GhostType ghost_type = _not_ghost) const;
 
 public:
   inline void getBarycenter(const Element & element,
                             Vector<Real> & barycenter) const;
 
+  void getBarycenters(Array<Real> & barycenter, const ElementType & type,
+                      const GhostType & ghost_type) const;
+
 #ifndef SWIG
   /// get the element connected to a subelement
   const auto & getElementToSubelement() const;
-  
+
   /// get the element connected to a subelement
   const auto &
   getElementToSubelement(const ElementType & el_type,
                          const GhostType & ghost_type = _not_ghost) const;
 
   /// get the element connected to a subelement
   auto & getElementToSubelement(const ElementType & el_type,
                                 const GhostType & ghost_type = _not_ghost);
 
   /// get the subelement connected to an element
   const auto &
   getSubelementToElement(const ElementType & el_type,
                          const GhostType & ghost_type = _not_ghost) const;
   /// get the subelement connected to an element
   auto & getSubelementToElement(const ElementType & el_type,
                                 const GhostType & ghost_type = _not_ghost);
 
 #endif
 
   /// register a new ElementalTypeMap in the MeshData
   template <typename T>
   inline ElementTypeMapArray<T> & registerData(const std::string & data_name);
 
   template <typename T>
   inline bool hasData(const ID & data_name, const ElementType & el_type,
                       const GhostType & ghost_type = _not_ghost) const;
 
   /// get a name field associated to the mesh
   template <typename T>
   inline const Array<T> &
   getData(const ID & data_name, const ElementType & el_type,
           const GhostType & ghost_type = _not_ghost) const;
 
   /// get a name field associated to the mesh
   template <typename T>
   inline Array<T> & getData(const ID & data_name, const ElementType & el_type,
                             const GhostType & ghost_type = _not_ghost);
 
   /// tells if the data data_name is contained in the mesh or not
   inline bool hasData(const ID & data_name) const;
 
   /// get a name field associated to the mesh
   template <typename T>
   inline const ElementTypeMapArray<T> & getData(const ID & data_name) const;
 
   /// get a name field associated to the mesh
   template <typename T>
   inline ElementTypeMapArray<T> & getData(const ID & data_name);
 
   template <typename T>
   ElementTypeMap<UInt> getNbDataPerElem(ElementTypeMapArray<T> & array,
                                         const ElementKind & element_kind);
 
   template <typename T>
   dumper::Field * createFieldFromAttachedData(const std::string & field_id,
                                               const std::string & group_name,
                                               const ElementKind & element_kind);
 
   /// templated getter returning the pointer to data in MeshData (modifiable)
   template <typename T>
   inline Array<T> &
   getDataPointer(const std::string & data_name, const ElementType & el_type,
                  const GhostType & ghost_type = _not_ghost,
                  UInt nb_component = 1, bool size_to_nb_element = true,
                  bool resize_with_parent = false);
 
   /// Facets mesh accessor
   inline const Mesh & getMeshFacets() const;
   inline Mesh & getMeshFacets();
 
   /// Parent mesh accessor
   inline const Mesh & getMeshParent() const;
 
   inline bool isMeshFacets() const { return this->is_mesh_facets; }
 
   /// defines is the mesh is distributed or not
   inline bool isDistributed() const { return this->is_distributed; }
 
 #ifndef SWIG
   /// return the dumper from a group and and a dumper name
   DumperIOHelper & getGroupDumper(const std::string & dumper_name,
                                   const std::string & group_name);
 #endif
   /* ------------------------------------------------------------------------ */
   /* Wrappers on ElementClass functions                                       */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the number of nodes per element for a given element type
   static inline UInt getNbNodesPerElement(const ElementType & type);
 
   /// get the number of nodes per element for a given element type considered as
   /// a first order element
   static inline ElementType getP1ElementType(const ElementType & type);
 
   /// get the kind of the element type
   static inline ElementKind getKind(const ElementType & type);
 
   /// get spatial dimension of a type of element
   static inline UInt getSpatialDimension(const ElementType & type);
 
   /// get number of facets of a given element type
   static inline UInt getNbFacetsPerElement(const ElementType & type);
 
   /// get number of facets of a given element type
   static inline UInt getNbFacetsPerElement(const ElementType & type, UInt t);
 
 #ifndef SWIG
 
   /// get local connectivity of a facet for a given facet type
   static inline auto getFacetLocalConnectivity(const ElementType & type,
                                                UInt t = 0);
 
   /// get connectivity of facets for a given element
   inline auto getFacetConnectivity(const Element & element, UInt t = 0) const;
 
 #endif
 
   /// get the number of type of the surface element associated to a given
   /// element type
   static inline UInt getNbFacetTypes(const ElementType & type, UInt t = 0);
 
 #ifndef SWIG
 
   /// get the type of the surface element associated to a given element
   static inline constexpr auto getFacetType(const ElementType & type,
                                             UInt t = 0);
 
   /// get all the type of the surface element associated to a given element
   static inline constexpr auto getAllFacetTypes(const ElementType & type);
 
 #endif
 
   /// get the number of nodes in the given element list
   static inline UInt getNbNodesPerElementList(const Array<Element> & elements);
 
   /* ------------------------------------------------------------------------ */
   /* Element type Iterator                                                    */
   /* ------------------------------------------------------------------------ */
   using type_iterator = ElementTypeMapArray<UInt, ElementType>::type_iterator;
   using ElementTypesIteratorHelper =
       ElementTypeMapArray<UInt, ElementType>::ElementTypesIteratorHelper;
 
   template <typename... pack>
   ElementTypesIteratorHelper elementTypes(pack &&... _pack) const;
 
   inline type_iterator firstType(UInt dim = _all_dimensions,
                                  GhostType ghost_type = _not_ghost,
                                  ElementKind kind = _ek_regular) const {
     return connectivities.firstType(dim, ghost_type, kind);
   }
 
   inline type_iterator lastType(UInt dim = _all_dimensions,
                                 GhostType ghost_type = _not_ghost,
                                 ElementKind kind = _ek_regular) const {
     return connectivities.lastType(dim, ghost_type, kind);
   }
 
   AKANTU_GET_MACRO(ElementSynchronizer, *element_synchronizer,
                    const ElementSynchronizer &);
   AKANTU_GET_MACRO_NOT_CONST(ElementSynchronizer, *element_synchronizer,
                              ElementSynchronizer &);
   AKANTU_GET_MACRO(NodeSynchronizer, *node_synchronizer,
                    const NodeSynchronizer &);
   AKANTU_GET_MACRO_NOT_CONST(NodeSynchronizer, *node_synchronizer,
                              NodeSynchronizer &);
 
 // AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, StaticCommunicator
 // &);
 #ifndef SWIG
   AKANTU_GET_MACRO(Communicator, *communicator, const auto &);
   AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, auto &);
 #endif
   /* ------------------------------------------------------------------------ */
   /* Private methods for friends                                              */
   /* ------------------------------------------------------------------------ */
 private:
   friend class MeshAccessor;
 
   AKANTU_GET_MACRO(NodesPointer, *nodes, Array<Real> &);
 
   /// get a pointer to the nodes_global_ids Array<UInt> and create it if
   /// necessary
   inline Array<UInt> & getNodesGlobalIdsPointer();
 
   /// get a pointer to the nodes_type Array<Int> and create it if necessary
   inline Array<NodeType> & getNodesTypePointer();
 
   /// get a pointer to the connectivity Array for the given type and create it
   /// if necessary
   inline Array<UInt> &
   getConnectivityPointer(const ElementType & type,
                          const GhostType & ghost_type = _not_ghost);
 
   /// get the ghost element counter
   inline Array<UInt> &
   getGhostsCounters(const ElementType & type,
                     const GhostType & ghost_type = _ghost) {
     AKANTU_DEBUG_ASSERT(ghost_type != _not_ghost,
                         "No ghost counter for _not_ghost elements");
     return ghosts_counters(type, ghost_type);
   }
 
   /// get a pointer to the element_to_subelement Array for the given type and
   /// create it if necessary
   inline Array<std::vector<Element>> &
   getElementToSubelementPointer(const ElementType & type,
                                 const GhostType & ghost_type = _not_ghost);
 
   /// get a pointer to the subelement_to_element Array for the given type and
   /// create it if necessary
   inline Array<Element> &
   getSubelementToElementPointer(const ElementType & type,
                                 const GhostType & ghost_type = _not_ghost);
 
   AKANTU_GET_MACRO_NOT_CONST(MeshData, mesh_data, MeshData &);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
   /// array of the nodes coordinates
   std::shared_ptr<Array<Real>> nodes;
 
   /// global node ids
   std::unique_ptr<Array<UInt>> nodes_global_ids;
 
   /// node type,  -3 pure ghost, -2  master for the  node, -1 normal node,  i in
   /// [0-N] slave node and master is proc i
   Array<NodeType> nodes_type;
 
   /// global number of nodes;
   UInt nb_global_nodes{0};
 
   /// all class of elements present in this mesh (for heterogenous meshes)
   ElementTypeMapArray<UInt> connectivities;
 
   /// count the references on ghost elements
   ElementTypeMapArray<UInt> ghosts_counters;
 
   /// map to normals for all class of elements present in this mesh
   ElementTypeMapArray<Real> normals;
 
   /// list of all existing types in the mesh
   // ConnectivityTypeList type_set;
 
   /// the spatial dimension of this mesh
   UInt spatial_dimension{0};
 
   /// types offsets
   // Array<UInt> types_offsets;
 
   // /// list of all existing types in the mesh
   // ConnectivityTypeList ghost_type_set;
   // /// ghost types offsets
   // Array<UInt> ghost_types_offsets;
 
   /// min of coordinates
   Vector<Real> lower_bounds;
   /// max of coordinates
   Vector<Real> upper_bounds;
   /// size covered by the mesh on each direction
   Vector<Real> size;
 
   /// local min of coordinates
   Vector<Real> local_lower_bounds;
   /// local max of coordinates
   Vector<Real> local_upper_bounds;
 
   /// Extra data loaded from the mesh file
   MeshData mesh_data;
 
   /// facets' mesh
   std::unique_ptr<Mesh> mesh_facets;
 
   /// parent mesh (this is set for mesh_facets meshes)
   const Mesh * mesh_parent{nullptr};
 
   /// defines if current mesh is mesh_facets or not
   bool is_mesh_facets{false};
 
   /// defines if the mesh is centralized or distributed
   bool is_distributed{false};
 
   /// Communicator on which mesh is distributed
   Communicator * communicator;
 
   /// Element synchronizer
   std::unique_ptr<ElementSynchronizer> element_synchronizer;
 
   /// Node synchronizer
   std::unique_ptr<NodeSynchronizer> node_synchronizer;
 
   using NodesToElements = std::vector<std::unique_ptr<std::set<Element>>>;
 
   /// This info is stored to simplify the dynamic changes
   NodesToElements nodes_to_elements;
 };
 
 /// standard output stream operator
 inline std::ostream & operator<<(std::ostream & stream, const Mesh & _this) {
   _this.printself(stream);
   return stream;
 }
 
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 /* Inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 
 #include "element_type_map_tmpl.hh"
 #include "mesh_inline_impl.cc"
 
 #endif /* __AKANTU_MESH_HH__ */
diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc
index 12bf9bdd4..7be630cf2 100644
--- a/src/mesh_utils/cohesive_element_inserter.cc
+++ b/src/mesh_utils/cohesive_element_inserter.cc
@@ -1,278 +1,281 @@
 /**
  * @file   cohesive_element_inserter.cc
  *
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Wed Dec 04 2013
  * @date last modification: Sun Oct 04 2015
  *
  * @brief  Cohesive element inserter functions
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "cohesive_element_inserter.hh"
 #include "communicator.hh"
 #include "element_group.hh"
 #include "global_ids_updater.hh"
 #include "mesh_iterators.hh"
 /* -------------------------------------------------------------------------- */
 #include <algorithm>
 #include <limits>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, const ID & id)
     : Parsable(ParserType::_cohesive_inserter), id(id), mesh(mesh),
       mesh_facets(mesh.initMeshFacets()),
       insertion_facets("insertion_facets", id),
       insertion_limits(mesh.getSpatialDimension(), 2),
       check_facets("check_facets", id) {
 
   this->registerParam("cohesive_surfaces", physical_groups, _pat_parsable,
                       "List of groups to consider for insertion");
   this->registerParam("bounding_box", insertion_limits, _pat_parsable,
                       "Global limit for insertion");
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   MeshUtils::resetFacetToDouble(mesh_facets);
 
   /// init insertion limits
   for (UInt dim = 0; dim < spatial_dimension; ++dim) {
     insertion_limits(dim, 0) = std::numeric_limits<Real>::max() * Real(-1.);
     insertion_limits(dim, 1) = std::numeric_limits<Real>::max();
   }
 
   insertion_facets.initialize(mesh_facets,
                               _spatial_dimension = spatial_dimension - 1,
                               _with_nb_element = true, _default_value = false);
 }
 
 /* -------------------------------------------------------------------------- */
 CohesiveElementInserter::~CohesiveElementInserter() = default;
 
 /* -------------------------------------------------------------------------- */
 void CohesiveElementInserter::parseSection(const ParserSection & section) {
   Parsable::parseSection(section);
 
   if (is_extrinsic)
     limitCheckFacets(this->check_facets);
 }
 
 /* -------------------------------------------------------------------------- */
 void CohesiveElementInserter::limitCheckFacets() {
   limitCheckFacets(this->check_facets);
 }
 
 /* -------------------------------------------------------------------------- */
 void CohesiveElementInserter::setLimit(SpacialDirection axis, Real first_limit,
                                        Real second_limit) {
   AKANTU_DEBUG_ASSERT(
       axis < mesh.getSpatialDimension(),
       "You are trying to limit insertion in a direction that doesn't exist");
 
   insertion_limits(axis, 0) = std::min(first_limit, second_limit);
   insertion_limits(axis, 1) = std::max(first_limit, second_limit);
 }
 
 /* -------------------------------------------------------------------------- */
 UInt CohesiveElementInserter::insertIntrinsicElements() {
   limitCheckFacets(insertion_facets);
   return insertElements();
 }
 
 /* -------------------------------------------------------------------------- */
 void CohesiveElementInserter::limitCheckFacets(
     ElementTypeMapArray<bool> & check_facets) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   check_facets.initialize(mesh_facets,
                           _spatial_dimension = spatial_dimension - 1,
                           _with_nb_element = true, _default_value = true);
   check_facets.set(true);
 
   // remove the pure ghost elements
   for_each_element(
       mesh_facets,
       [&](auto && facet) {
         const auto & element_to_facet = mesh_facets.getElementToSubelement(
             facet.type, facet.ghost_type)(facet.element);
         auto & left = element_to_facet[0];
         auto & right = element_to_facet[1];
         if (right == ElementNull ||
             (left.ghost_type == _ghost && right.ghost_type == _ghost)) {
           check_facets(facet) = false;
           return;
         }
 
         if (left.kind() == _ek_cohesive or right.kind() == _ek_cohesive) {
           check_facets(facet) = false;
         }
       },
       _spatial_dimension = spatial_dimension - 1);
 
   Vector<Real> bary_facet(spatial_dimension);
   // set the limits to the bounding box
   for_each_element(mesh_facets,
                    [&](auto && facet) {
                      auto & need_check = check_facets(facet);
                      if (not need_check)
                        return;
 
                      mesh_facets.getBarycenter(facet, bary_facet);
                      UInt coord_in_limit = 0;
 
                      while (coord_in_limit < spatial_dimension &&
                             bary_facet(coord_in_limit) >
                                 insertion_limits(coord_in_limit, 0) &&
                             bary_facet(coord_in_limit) <
                                 insertion_limits(coord_in_limit, 1))
                        ++coord_in_limit;
 
                      if (coord_in_limit != spatial_dimension)
                        need_check = false;
                    },
                    _spatial_dimension = spatial_dimension - 1);
 
   if (not mesh_facets.hasData("physical_names")) {
+    AKANTU_DEBUG_ASSERT(
+        physical_groups.size() == 0,
+        "No physical names in the mesh but insertion limited to a group");
     AKANTU_DEBUG_OUT();
     return;
   }
 
   const auto & physical_ids =
       mesh_facets.getData<std::string>("physical_names");
 
   // set the limits to the physical surfaces
   for_each_element(mesh_facets,
-                    [&](auto && facet) {
-                      auto & need_check = check_facets(facet);
-                      if (not need_check)
-                        return;
-
-                      const auto & physical_id = physical_ids(facet);
-                      auto it = find(physical_groups.begin(),
-                                     physical_groups.end(), physical_id);
-
-                      need_check = (it != physical_groups.end());
-                    },
-                    _spatial_dimension = spatial_dimension - 1);
+                   [&](auto && facet) {
+                     auto & need_check = check_facets(facet);
+                     if (not need_check)
+                       return;
+
+                     const auto & physical_id = physical_ids(facet);
+                     auto it = find(physical_groups.begin(),
+                                    physical_groups.end(), physical_id);
+
+                     need_check = (it != physical_groups.end());
+                   },
+                   _spatial_dimension = spatial_dimension - 1);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 UInt CohesiveElementInserter::insertElements(bool only_double_facets) {
 
   CohesiveNewNodesEvent node_event;
   NewElementsEvent element_event;
 
   Array<UInt> new_pairs(0, 2);
 
   UInt nb_new_elements = MeshUtils::insertCohesiveElements(
       mesh, mesh_facets, insertion_facets, new_pairs, element_event.getList(),
       only_double_facets);
 
   UInt nb_new_nodes = new_pairs.size();
   node_event.getList().reserve(nb_new_nodes);
   node_event.getOldNodesList().reserve(nb_new_nodes);
   for (UInt n = 0; n < nb_new_nodes; ++n) {
     node_event.getList().push_back(new_pairs(n, 1));
     node_event.getOldNodesList().push_back(new_pairs(n, 0));
   }
 
   if (mesh.isDistributed()) {
 
     /// update nodes type
     updateNodesType(mesh, node_event);
     updateNodesType(mesh_facets, node_event);
 
     /// update global ids
     nb_new_nodes = this->updateGlobalIDs(node_event);
 
     /// compute total number of new elements
     const auto & comm = mesh.getCommunicator();
     comm.allReduce(nb_new_elements, SynchronizerOperation::_sum);
   }
 
   if (nb_new_nodes > 0)
     mesh.sendEvent(node_event);
 
   if (nb_new_elements > 0) {
     updateInsertionFacets();
     // mesh.updateTypesOffsets(_not_ghost);
     mesh.sendEvent(element_event);
     MeshUtils::resetFacetToDouble(mesh_facets);
   }
 
   if (mesh.isDistributed()) {
     /// update global ids
     this->synchronizeGlobalIDs(node_event);
   }
 
   return nb_new_elements;
 }
 
 /* -------------------------------------------------------------------------- */
 void CohesiveElementInserter::updateInsertionFacets() {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   for (auto && facet_gt : ghost_types) {
     for (auto && facet_type :
          mesh_facets.elementTypes(spatial_dimension - 1, facet_gt)) {
       auto & ins_facets = insertion_facets(facet_type, facet_gt);
 
       // this is the intrinsic case
       if (not is_extrinsic)
         continue;
 
       auto & f_check = check_facets(facet_type, facet_gt);
       for (auto && pair : zip(ins_facets, f_check)) {
         bool & ins = std::get<0>(pair);
         bool & check = std::get<1>(pair);
         if (ins)
           ins = check = false;
       }
     }
   }
 
   // resize for the newly added facets
   insertion_facets.initialize(mesh_facets,
                               _spatial_dimension = spatial_dimension - 1,
                               _with_nb_element = true, _default_value = false);
 
   // resize for the newly added facets
   if (is_extrinsic) {
     check_facets.initialize(mesh_facets,
                             _spatial_dimension = spatial_dimension - 1,
                             _with_nb_element = true, _default_value = false);
   } else {
     insertion_facets.set(false);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 } // namespace akantu
diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc
index 1cb298d0d..93f8e8090 100644
--- a/src/mesh_utils/mesh_utils.cc
+++ b/src/mesh_utils/mesh_utils.cc
@@ -1,2172 +1,2173 @@
 /**
  * @file   mesh_utils.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Dana Christen <dana.christen@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Leonardo Snozzi <leonardo.snozzi@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Aug 20 2010
  * @date last modification: Fri Jan 22 2016
  *
  * @brief  All mesh utils necessary for various tasks
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "mesh_utils.hh"
 #include "element_synchronizer.hh"
 #include "fe_engine.hh"
 #include "mesh_accessor.hh"
 /* -------------------------------------------------------------------------- */
 #include <limits>
 #include <numeric>
 #include <queue>
 #include <set>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::buildNode2Elements(const Mesh & mesh,
                                    CSR<Element> & node_to_elem,
                                    UInt spatial_dimension) {
   AKANTU_DEBUG_IN();
   if (spatial_dimension == _all_dimensions)
     spatial_dimension = mesh.getSpatialDimension();
 
   /// count number of occurrence of each node
   UInt nb_nodes = mesh.getNbNodes();
 
   /// array for the node-element list
   node_to_elem.resizeRows(nb_nodes);
   node_to_elem.clearRows();
 
   AKANTU_DEBUG_ASSERT(
       mesh.firstType(spatial_dimension) != mesh.lastType(spatial_dimension),
       "Some elements must be found in right dimension to compute facets!");
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
     Mesh::type_iterator first =
         mesh.firstType(spatial_dimension, *gt, _ek_not_defined);
     Mesh::type_iterator last =
         mesh.lastType(spatial_dimension, *gt, _ek_not_defined);
 
     for (; first != last; ++first) {
       ElementType type = *first;
       UInt nb_element = mesh.getNbElement(type, *gt);
       Array<UInt>::const_iterator<Vector<UInt>> conn_it =
           mesh.getConnectivity(type, *gt).begin(
               Mesh::getNbNodesPerElement(type));
 
       for (UInt el = 0; el < nb_element; ++el, ++conn_it)
         for (UInt n = 0; n < conn_it->size(); ++n)
           ++node_to_elem.rowOffset((*conn_it)(n));
     }
   }
 
   node_to_elem.countToCSR();
   node_to_elem.resizeCols();
 
   /// rearrange element to get the node-element list
   Element e;
   node_to_elem.beginInsertions();
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
     Mesh::type_iterator first =
         mesh.firstType(spatial_dimension, *gt, _ek_not_defined);
     Mesh::type_iterator last =
         mesh.lastType(spatial_dimension, *gt, _ek_not_defined);
     e.ghost_type = *gt;
     for (; first != last; ++first) {
       ElementType type = *first;
       e.type = type;
       UInt nb_element = mesh.getNbElement(type, *gt);
       Array<UInt>::const_iterator<Vector<UInt>> conn_it =
           mesh.getConnectivity(type, *gt).begin(
               Mesh::getNbNodesPerElement(type));
 
       for (UInt el = 0; el < nb_element; ++el, ++conn_it) {
         e.element = el;
         for (UInt n = 0; n < conn_it->size(); ++n)
           node_to_elem.insertInRow((*conn_it)(n), e);
       }
     }
   }
 
   node_to_elem.endInsertions();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * This function should disappear in the future (used in mesh partitioning)
  */
 // void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR<UInt> &
 // node_to_elem,
 //                                    UInt spatial_dimension) {
 //   AKANTU_DEBUG_IN();
 //   if (spatial_dimension == _all_dimensions)
 //     spatial_dimension = mesh.getSpatialDimension();
 //   UInt nb_nodes = mesh.getNbNodes();
 
 //   const Mesh::ConnectivityTypeList & type_list =
 //   mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator
 //   it;
 
 //   UInt nb_types = type_list.size();
 //   UInt nb_good_types = 0;
 
 //   Vector<UInt> nb_nodes_per_element(nb_types);
 //   UInt ** conn_val = new UInt *[nb_types];
 //   Vector<UInt> nb_element(nb_types);
 
 //   for (it = type_list.begin(); it != type_list.end(); ++it) {
 //     ElementType type = *it;
 //     if (Mesh::getSpatialDimension(type) != spatial_dimension)
 //       continue;
 
 //     nb_nodes_per_element[nb_good_types] = Mesh::getNbNodesPerElement(type);
 //     conn_val[nb_good_types] = mesh.getConnectivity(type,
 //     _not_ghost).storage(); nb_element[nb_good_types] =
 //         mesh.getConnectivity(type, _not_ghost).size();
 //     nb_good_types++;
 //   }
 
 //   AKANTU_DEBUG_ASSERT(
 //       nb_good_types != 0,
 //       "Some elements must be found in right dimension to compute facets!");
 
 //   /// array for the node-element list
 //   node_to_elem.resizeRows(nb_nodes);
 //   node_to_elem.clearRows();
 
 //   /// count number of occurrence of each node
 //   for (UInt t = 0; t < nb_good_types; ++t) {
 //     for (UInt el = 0; el < nb_element[t]; ++el) {
 //       UInt el_offset = el * nb_nodes_per_element[t];
 //       for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) {
 //         ++node_to_elem.rowOffset(conn_val[t][el_offset + n]);
 //       }
 //     }
 //   }
 
 //   node_to_elem.countToCSR();
 //   node_to_elem.resizeCols();
 //   node_to_elem.beginInsertions();
 
 //   /// rearrange element to get the node-element list
 //   for (UInt t = 0, linearized_el = 0; t < nb_good_types; ++t)
 //     for (UInt el = 0; el < nb_element[t]; ++el, ++linearized_el) {
 //       UInt el_offset = el * nb_nodes_per_element[t];
 //       for (UInt n = 0; n < nb_nodes_per_element[t]; ++n)
 //         node_to_elem.insertInRow(conn_val[t][el_offset + n], linearized_el);
 //     }
 
 //   node_to_elem.endInsertions();
 //   delete[] conn_val;
 //   AKANTU_DEBUG_OUT();
 // }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::buildNode2ElementsElementTypeMap(const Mesh & mesh,
                                                  CSR<UInt> & node_to_elem,
                                                  const ElementType & type,
                                                  const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
   UInt nb_nodes = mesh.getNbNodes();
 
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_elements = mesh.getConnectivity(type, ghost_type).size();
 
   UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage();
 
   /// array for the node-element list
   node_to_elem.resizeRows(nb_nodes);
   node_to_elem.clearRows();
 
   /// count number of occurrence of each node
   for (UInt el = 0; el < nb_elements; ++el) {
     UInt el_offset = el * nb_nodes_per_element;
     for (UInt n = 0; n < nb_nodes_per_element; ++n)
       ++node_to_elem.rowOffset(conn_val[el_offset + n]);
   }
 
   /// convert the occurrence array in a csr one
   node_to_elem.countToCSR();
 
   node_to_elem.resizeCols();
   node_to_elem.beginInsertions();
 
   /// save the element index in the node-element list
   for (UInt el = 0; el < nb_elements; ++el) {
     UInt el_offset = el * nb_nodes_per_element;
     for (UInt n = 0; n < nb_nodes_per_element; ++n) {
       node_to_elem.insertInRow(conn_val[el_offset + n], el);
     }
   }
 
   node_to_elem.endInsertions();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::buildFacets(Mesh & mesh) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
     GhostType gt_facet = *gt;
     Mesh::type_iterator it = mesh.firstType(spatial_dimension - 1, gt_facet);
     Mesh::type_iterator end = mesh.lastType(spatial_dimension - 1, gt_facet);
     for (; it != end; ++it) {
       mesh.getConnectivity(*it, *gt).resize(0);
       // \todo inform the mesh event handler
     }
   }
 
   buildFacetsDimension(mesh, mesh, true, spatial_dimension);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets,
                                UInt to_dimension) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension);
 
   AKANTU_DEBUG_OUT();
 }
 /* -------------------------------------------------------------------------- */
 void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets,
                                UInt from_dimension, UInt to_dimension) {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(
       mesh_facets.isMeshFacets(),
       "The mesh_facets should be initialized with initMeshFacets");
 
   /// generate facets
   buildFacetsDimension(mesh, mesh_facets, false, from_dimension);
 
   /// copy nodes type
   MeshAccessor mesh_accessor_facets(mesh_facets);
   mesh_accessor_facets.getNodesType().copy(mesh.getNodesType());
 
   /// sort facets and generate sub-facets
   for (UInt i = from_dimension - 1; i > to_dimension; --i) {
     buildFacetsDimension(mesh_facets, mesh_facets, false, i);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets,
                                      bool boundary_only, UInt dimension) {
   AKANTU_DEBUG_IN();
 
   // save the current parent of mesh_facets and set it temporarly to mesh since
   // mesh is the one containing the elements for which mesh_facets has the
   // sub-elements
   // example: if the function is called with mesh = mesh_facets
   const Mesh * mesh_facets_parent = nullptr;
   try {
     mesh_facets_parent = &mesh_facets.getMeshParent();
   } catch (...) {
   }
 
   mesh_facets.defineMeshParent(mesh);
   MeshAccessor mesh_accessor(mesh_facets);
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   const Array<Real> & mesh_facets_nodes = mesh_facets.getNodes();
   const Array<Real>::const_vector_iterator mesh_facets_nodes_it =
       mesh_facets_nodes.begin(spatial_dimension);
 
   CSR<Element> node_to_elem;
   buildNode2Elements(mesh, node_to_elem, dimension);
 
   Array<UInt> counter;
   std::vector<Element> connected_elements;
 
   // init the SubelementToElement data to improve performance
   for (auto && ghost_type : ghost_types) {
     for (auto && type : mesh.elementTypes(dimension, ghost_type)) {
       mesh_accessor.getSubelementToElement(type, ghost_type);
 
       auto facet_types = mesh.getAllFacetTypes(type);
 
       for (auto && ft : arange(facet_types.size())) {
         auto facet_type = facet_types(ft);
         mesh_accessor.getElementToSubelement(facet_type, ghost_type);
         mesh_accessor.getConnectivity(facet_type, ghost_type);
       }
     }
   }
 
   const ElementSynchronizer * synchronizer = nullptr;
   if (mesh.isDistributed()) {
     synchronizer = &(mesh.getElementSynchronizer());
   }
 
   Element current_element;
   for (auto && ghost_type : ghost_types) {
     GhostType facet_ghost_type = ghost_type;
     current_element.ghost_type = ghost_type;
 
     for (auto && type : mesh.elementTypes(dimension, ghost_type)) {
       auto facet_types = mesh.getAllFacetTypes(type);
       current_element.type = type;
 
       for (auto && ft : arange(facet_types.size())) {
         auto facet_type = facet_types(ft);
         auto nb_element = mesh.getNbElement(type, ghost_type);
 
         auto element_to_subelement =
             &mesh_facets.getElementToSubelement(facet_type, ghost_type);
         auto connectivity_facets =
             &mesh_facets.getConnectivity(facet_type, ghost_type);
 
         auto nb_facet_per_element = mesh.getNbFacetsPerElement(type, ft);
         const auto & element_connectivity =
             mesh.getConnectivity(type, ghost_type);
         Matrix<const UInt> facet_local_connectivity(
             mesh.getFacetLocalConnectivity(type, ft));
 
         auto nb_nodes_per_facet = connectivity_facets->getNbComponent();
         Vector<UInt> facet(nb_nodes_per_facet);
 
         for (UInt el = 0; el < nb_element; ++el) {
           current_element.element = el;
 
           for (UInt f = 0; f < nb_facet_per_element; ++f) {
             for (UInt n = 0; n < nb_nodes_per_facet; ++n)
               facet(n) =
                   element_connectivity(el, facet_local_connectivity(f, n));
 
             UInt first_node_nb_elements = node_to_elem.getNbCols(facet(0));
             counter.resize(first_node_nb_elements);
             counter.clear();
 
             // loop over the other nodes to search intersecting elements,
             // which are the elements that share another node with the
             // starting element after first_node
             UInt local_el = 0;
             auto first_node_elements = node_to_elem.begin(facet(0));
             auto first_node_elements_end = node_to_elem.end(facet(0));
             for (; first_node_elements != first_node_elements_end;
                  ++first_node_elements, ++local_el) {
               for (UInt n = 1; n < nb_nodes_per_facet; ++n) {
                 auto node_elements_begin = node_to_elem.begin(facet(n));
                 auto node_elements_end = node_to_elem.end(facet(n));
                 counter(local_el) +=
                     std::count(node_elements_begin, node_elements_end,
                                *first_node_elements);
               }
             }
 
             // counting the number of elements connected to the facets and
             // taking the minimum element number, because the facet should
             // be inserted just once
             UInt nb_element_connected_to_facet = 0;
             Element minimum_el = ElementNull;
             connected_elements.clear();
             for (UInt el_f = 0; el_f < first_node_nb_elements; el_f++) {
               Element real_el = node_to_elem(facet(0), el_f);
               if (not(counter(el_f) == nb_nodes_per_facet - 1))
                 continue;
 
               ++nb_element_connected_to_facet;
               minimum_el = std::min(minimum_el, real_el);
               connected_elements.push_back(real_el);
             }
 
             if (minimum_el != current_element)
               continue;
 
             bool full_ghost_facet = false;
 
             UInt n = 0;
             while (n < nb_nodes_per_facet && mesh.isPureGhostNode(facet(n)))
               ++n;
             if (n == nb_nodes_per_facet)
               full_ghost_facet = true;
 
             if (full_ghost_facet)
               continue;
 
             if (boundary_only and nb_element_connected_to_facet != 1)
               continue;
 
             std::vector<Element> elements;
 
             // build elements_on_facets: linearized_el must come first
             // in order to store the facet in the correct direction
             // and avoid to invert the sign in the normal computation
             elements.push_back(current_element);
 
             if (nb_element_connected_to_facet == 1) { /// boundary facet
               elements.push_back(ElementNull);
             } else if (nb_element_connected_to_facet == 2) { /// internal facet
               elements.push_back(connected_elements[1]);
 
               /// check if facet is in between ghost and normal
               /// elements: if it's the case, the facet is either
               /// ghost or not ghost. The criterion to decide this
               /// is arbitrary. It was chosen to check the processor
               /// id (prank) of the two neighboring elements. If
               /// prank of the ghost element is lower than prank of
               /// the normal one, the facet is not ghost, otherwise
               /// it's ghost
               GhostType gt[2] = {_not_ghost, _not_ghost};
               for (UInt el = 0; el < connected_elements.size(); ++el)
                 gt[el] = connected_elements[el].ghost_type;
 
               if (gt[0] != gt[1] and
                   (gt[0] == _not_ghost or gt[1] == _not_ghost)) {
                 UInt prank[2];
                 for (UInt el = 0; el < 2; ++el) {
                   prank[el] = synchronizer->getRank(connected_elements[el]);
                 }
 
                 // ugly trick from Marco detected :P
                 bool ghost_one = (gt[0] != _ghost);
                 if (prank[ghost_one] > prank[!ghost_one])
                   facet_ghost_type = _not_ghost;
                 else
                   facet_ghost_type = _ghost;
 
                 connectivity_facets =
                     &mesh_facets.getConnectivity(facet_type, facet_ghost_type);
                 element_to_subelement = &mesh_facets.getElementToSubelement(
                     facet_type, facet_ghost_type);
               }
             } else { /// facet of facet
               for (UInt i = 1; i < nb_element_connected_to_facet; ++i) {
                 elements.push_back(connected_elements[i]);
               }
             }
 
             element_to_subelement->push_back(elements);
             connectivity_facets->push_back(facet);
 
             /// current facet index
             UInt current_facet = connectivity_facets->size() - 1;
 
             /// loop on every element connected to current facet and
             /// insert current facet in the first free spot of the
             /// subelement_to_element vector
             for (UInt elem = 0; elem < elements.size(); ++elem) {
               Element loc_el = elements[elem];
 
               if (loc_el.type == _not_defined)
                 continue;
 
               Array<Element> & subelement_to_element =
                   mesh_facets.getSubelementToElement(loc_el.type,
                                                      loc_el.ghost_type);
 
               UInt nb_facet_per_loc_element =
                   subelement_to_element.getNbComponent();
 
               for (UInt f_in = 0; f_in < nb_facet_per_loc_element; ++f_in) {
                 auto & el = subelement_to_element(loc_el.element, f_in);
                 if (el.type != _not_defined)
                   continue;
 
                 el.type = facet_type;
                 el.element = current_facet;
                 el.ghost_type = facet_ghost_type;
                 break;
               }
             }
 
             /// reset connectivity in case a facet was found in
             /// between ghost and normal elements
             if (facet_ghost_type != ghost_type) {
               facet_ghost_type = ghost_type;
               connectivity_facets =
                   &mesh_accessor.getConnectivity(facet_type, facet_ghost_type);
               element_to_subelement = &mesh_accessor.getElementToSubelement(
                   facet_type, facet_ghost_type);
             }
           }
         }
       }
     }
   }
 
   // restore the parent of mesh_facet
   if (mesh_facets_parent)
     mesh_facets.defineMeshParent(*mesh_facets_parent);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::renumberMeshNodes(Mesh & mesh,
                                   Array<UInt> & local_connectivities,
                                   UInt nb_local_element, UInt nb_ghost_element,
                                   ElementType type,
                                   Array<UInt> & old_nodes_numbers) {
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 
   std::map<UInt, UInt> renumbering_map;
   for (UInt i = 0; i < old_nodes_numbers.size(); ++i) {
     renumbering_map[old_nodes_numbers(i)] = i;
   }
 
   /// renumber the nodes
   renumberNodesInConnectivity(local_connectivities,
                               (nb_local_element + nb_ghost_element) *
                                   nb_nodes_per_element,
                               renumbering_map);
 
   old_nodes_numbers.resize(renumbering_map.size());
   for (auto & renumber_pair : renumbering_map) {
     old_nodes_numbers(renumber_pair.second) = renumber_pair.first;
   }
   renumbering_map.clear();
 
   MeshAccessor mesh_accessor(mesh);
 
   /// copy the renumbered connectivity to the right place
   auto & local_conn = mesh_accessor.getConnectivity(type);
   local_conn.resize(nb_local_element);
   memcpy(local_conn.storage(), local_connectivities.storage(),
          nb_local_element * nb_nodes_per_element * sizeof(UInt));
 
   auto & ghost_conn = mesh_accessor.getConnectivity(type, _ghost);
   ghost_conn.resize(nb_ghost_element);
   std::memcpy(ghost_conn.storage(),
               local_connectivities.storage() +
                   nb_local_element * nb_nodes_per_element,
               nb_ghost_element * nb_nodes_per_element * sizeof(UInt));
 
   auto & ghost_counter = mesh_accessor.getGhostsCounters(type, _ghost);
   ghost_counter.resize(nb_ghost_element, 1);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::renumberNodesInConnectivity(
     Array<UInt> & list_nodes, UInt nb_nodes,
     std::map<UInt, UInt> & renumbering_map) {
   AKANTU_DEBUG_IN();
 
   UInt * connectivity = list_nodes.storage();
   UInt new_node_num = renumbering_map.size();
   for (UInt n = 0; n < nb_nodes; ++n, ++connectivity) {
     UInt & node = *connectivity;
     auto it = renumbering_map.find(node);
     if (it == renumbering_map.end()) {
       UInt old_node = node;
       renumbering_map[old_node] = new_node_num;
       node = new_node_num;
       ++new_node_num;
     } else {
       node = it->second;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::purifyMesh(Mesh & mesh) {
   AKANTU_DEBUG_IN();
 
   std::map<UInt, UInt> renumbering_map;
 
   RemovedNodesEvent remove_nodes(mesh);
   Array<UInt> & nodes_removed = remove_nodes.getList();
 
   for (UInt gt = _not_ghost; gt <= _ghost; ++gt) {
     auto ghost_type = (GhostType)gt;
 
     Mesh::type_iterator it =
         mesh.firstType(_all_dimensions, ghost_type, _ek_not_defined);
     Mesh::type_iterator end =
         mesh.lastType(_all_dimensions, ghost_type, _ek_not_defined);
     for (; it != end; ++it) {
 
       ElementType type(*it);
       UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 
       Array<UInt> & connectivity = mesh.getConnectivity(type, ghost_type);
       UInt nb_element(connectivity.size());
 
       renumberNodesInConnectivity(
           connectivity, nb_element * nb_nodes_per_element, renumbering_map);
     }
   }
 
   Array<UInt> & new_numbering = remove_nodes.getNewNumbering();
   std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1));
 
   auto it = renumbering_map.begin();
   auto end = renumbering_map.end();
   for (; it != end; ++it) {
     new_numbering(it->first) = it->second;
   }
 
   for (UInt i = 0; i < new_numbering.size(); ++i) {
     if (new_numbering(i) == UInt(-1))
       nodes_removed.push_back(i);
   }
 
   mesh.sendEvent(remove_nodes);
 
   AKANTU_DEBUG_OUT();
 }
 
 #if defined(AKANTU_COHESIVE_ELEMENT)
 /* -------------------------------------------------------------------------- */
 UInt MeshUtils::insertCohesiveElements(
     Mesh & mesh, Mesh & mesh_facets,
     const ElementTypeMapArray<bool> & facet_insertion,
     Array<UInt> & doubled_nodes, Array<Element> & new_elements,
     bool only_double_facets) {
   UInt spatial_dimension = mesh.getSpatialDimension();
   UInt elements_to_insert = updateFacetToDouble(mesh_facets, facet_insertion);
 
   if (elements_to_insert > 0) {
 
     if (spatial_dimension == 1) {
       doublePointFacet(mesh, mesh_facets, doubled_nodes);
     } else {
       doubleFacet(mesh, mesh_facets, spatial_dimension - 1, doubled_nodes,
                   true);
       findSubfacetToDouble<false>(mesh, mesh_facets);
 
       if (spatial_dimension == 2) {
         doubleSubfacet<2>(mesh, mesh_facets, doubled_nodes);
       } else if (spatial_dimension == 3) {
         doubleFacet(mesh, mesh_facets, 1, doubled_nodes, false);
         findSubfacetToDouble<true>(mesh, mesh_facets);
         doubleSubfacet<3>(mesh, mesh_facets, doubled_nodes);
       }
     }
 
     if (!only_double_facets)
       updateCohesiveData(mesh, mesh_facets, new_elements);
   }
 
   return elements_to_insert;
 }
 #endif
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::doubleNodes(Mesh & mesh, const std::vector<UInt> & old_nodes,
                             Array<UInt> & doubled_nodes) {
   AKANTU_DEBUG_IN();
 
   Array<Real> & position = mesh.getNodes();
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   UInt old_nb_nodes = position.size();
   UInt new_nb_nodes = old_nb_nodes + old_nodes.size();
 
   UInt old_nb_doubled_nodes = doubled_nodes.size();
   UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.size();
 
   position.resize(new_nb_nodes);
   doubled_nodes.resize(new_nb_doubled_nodes);
 
   Array<Real>::iterator<Vector<Real>> position_begin =
       position.begin(spatial_dimension);
 
   for (UInt n = 0; n < old_nodes.size(); ++n) {
     UInt new_node = old_nb_nodes + n;
 
     /// store doubled nodes
     doubled_nodes(old_nb_doubled_nodes + n, 0) = old_nodes[n];
     doubled_nodes(old_nb_doubled_nodes + n, 1) = new_node;
 
     /// update position
     std::copy(position_begin + old_nodes[n], position_begin + old_nodes[n] + 1,
               position_begin + new_node);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::doubleFacet(Mesh & mesh, Mesh & mesh_facets,
                             UInt facet_dimension, Array<UInt> & doubled_nodes,
                             bool facet_mode) {
   AKANTU_DEBUG_IN();
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
 
     GhostType gt_facet = *gt;
 
     Mesh::type_iterator it = mesh_facets.firstType(facet_dimension, gt_facet);
     Mesh::type_iterator end = mesh_facets.lastType(facet_dimension, gt_facet);
 
     for (; it != end; ++it) {
 
       ElementType type_facet = *it;
 
       Array<UInt> & f_to_double =
           mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet);
       UInt nb_facet_to_double = f_to_double.size();
 
       if (nb_facet_to_double == 0)
         continue;
 
       ElementType type_subfacet = Mesh::getFacetType(type_facet);
       const UInt nb_subfacet_per_facet =
           Mesh::getNbFacetsPerElement(type_facet);
       GhostType gt_subfacet = _casper;
       Array<std::vector<Element>> * f_to_subfacet = nullptr;
 
       Array<Element> & subfacet_to_facet =
           mesh_facets.getSubelementToElement(type_facet, gt_facet);
 
       Array<UInt> & conn_facet =
           mesh_facets.getConnectivity(type_facet, gt_facet);
       UInt nb_nodes_per_facet = conn_facet.getNbComponent();
 
       UInt old_nb_facet = conn_facet.size();
       UInt new_nb_facet = old_nb_facet + nb_facet_to_double;
 
       conn_facet.resize(new_nb_facet);
       subfacet_to_facet.resize(new_nb_facet);
 
       UInt new_facet = old_nb_facet - 1;
       Element new_facet_el{type_facet, 0, gt_facet};
 
       Array<Element>::iterator<Vector<Element>> subfacet_to_facet_begin =
           subfacet_to_facet.begin(nb_subfacet_per_facet);
       Array<UInt>::iterator<Vector<UInt>> conn_facet_begin =
           conn_facet.begin(nb_nodes_per_facet);
 
       for (UInt facet = 0; facet < nb_facet_to_double; ++facet) {
         UInt old_facet = f_to_double(facet);
         ++new_facet;
 
         /// adding a new facet by copying original one
 
         /// copy connectivity in new facet
         std::copy(conn_facet_begin + old_facet,
                   conn_facet_begin + old_facet + 1,
                   conn_facet_begin + new_facet);
 
         /// update subfacet_to_facet
         std::copy(subfacet_to_facet_begin + old_facet,
                   subfacet_to_facet_begin + old_facet + 1,
                   subfacet_to_facet_begin + new_facet);
 
         new_facet_el.element = new_facet;
 
         /// loop on every subfacet
         for (UInt sf = 0; sf < nb_subfacet_per_facet; ++sf) {
           Element & subfacet = subfacet_to_facet(old_facet, sf);
           if (subfacet == ElementNull)
             continue;
 
           if (gt_subfacet != subfacet.ghost_type) {
             gt_subfacet = subfacet.ghost_type;
             f_to_subfacet = &mesh_facets.getElementToSubelement(
                 type_subfacet, subfacet.ghost_type);
           }
 
           /// update facet_to_subfacet array
           (*f_to_subfacet)(subfacet.element).push_back(new_facet_el);
         }
       }
 
       /// update facet_to_subfacet and _segment_3 facets if any
       if (!facet_mode) {
         updateSubfacetToFacet(mesh_facets, type_facet, gt_facet, true);
         updateFacetToSubfacet(mesh_facets, type_facet, gt_facet, true);
         updateQuadraticSegments<true>(mesh, mesh_facets, type_facet, gt_facet,
                                       doubled_nodes);
       } else
         updateQuadraticSegments<false>(mesh, mesh_facets, type_facet, gt_facet,
                                        doubled_nodes);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 UInt MeshUtils::updateFacetToDouble(
     Mesh & mesh_facets, const ElementTypeMapArray<bool> & facet_insertion) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh_facets.getSpatialDimension();
   UInt nb_facets_to_double = 0.;
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
 
     GhostType gt_facet = *gt;
 
     Mesh::type_iterator it =
         mesh_facets.firstType(spatial_dimension - 1, gt_facet);
     Mesh::type_iterator end =
         mesh_facets.lastType(spatial_dimension - 1, gt_facet);
 
     for (; it != end; ++it) {
 
       ElementType type_facet = *it;
 
       const Array<bool> & f_insertion = facet_insertion(type_facet, gt_facet);
       Array<UInt> & f_to_double =
           mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet);
 
       Array<std::vector<Element>> & element_to_facet =
           mesh_facets.getElementToSubelement(type_facet, gt_facet);
 
       ElementType el_type = _not_defined;
       GhostType el_gt = _casper;
       UInt nb_facet_per_element = 0;
       Element old_facet_el{type_facet, 0, gt_facet};
 
       Array<Element> * facet_to_element = nullptr;
 
       for (UInt f = 0; f < f_insertion.size(); ++f) {
 
         if (f_insertion(f) == false)
           continue;
 
         ++nb_facets_to_double;
 
         if (element_to_facet(f)[1].type == _not_defined
 #if defined(AKANTU_COHESIVE_ELEMENT)
             || element_to_facet(f)[1].kind() == _ek_cohesive
 #endif
         ) {
           AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary");
           continue;
         }
 
         f_to_double.push_back(f);
 
         UInt new_facet = mesh_facets.getNbElement(type_facet, gt_facet) +
                          f_to_double.size() - 1;
         old_facet_el.element = f;
 
         /// update facet_to_element vector
         Element & elem_to_update = element_to_facet(f)[1];
         UInt el = elem_to_update.element;
 
         if (elem_to_update.ghost_type != el_gt ||
             elem_to_update.type != el_type) {
           el_type = elem_to_update.type;
           el_gt = elem_to_update.ghost_type;
           facet_to_element =
               &mesh_facets.getSubelementToElement(el_type, el_gt);
           nb_facet_per_element = facet_to_element->getNbComponent();
         }
 
         Element * f_update =
             std::find(facet_to_element->storage() + el * nb_facet_per_element,
                       facet_to_element->storage() + el * nb_facet_per_element +
                           nb_facet_per_element,
                       old_facet_el);
 
         AKANTU_DEBUG_ASSERT(
             facet_to_element->storage() + el * nb_facet_per_element !=
                 facet_to_element->storage() + el * nb_facet_per_element +
                     nb_facet_per_element,
             "Facet not found");
 
         f_update->element = new_facet;
 
         /// update elements connected to facet
         std::vector<Element> first_facet_list = element_to_facet(f);
         element_to_facet.push_back(first_facet_list);
 
         /// set new and original facets as boundary facets
         element_to_facet(new_facet)[0] = element_to_facet(new_facet)[1];
 
         element_to_facet(f)[1] = ElementNull;
         element_to_facet(new_facet)[1] = ElementNull;
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
   return nb_facets_to_double;
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::resetFacetToDouble(Mesh & mesh_facets) {
   AKANTU_DEBUG_IN();
 
   for (UInt g = _not_ghost; g <= _ghost; ++g) {
     auto gt = (GhostType)g;
 
     Mesh::type_iterator it = mesh_facets.firstType(_all_dimensions, gt);
     Mesh::type_iterator end = mesh_facets.lastType(_all_dimensions, gt);
     for (; it != end; ++it) {
       ElementType type = *it;
       mesh_facets.getDataPointer<UInt>("facet_to_double", type, gt, 1, false);
 
       mesh_facets.getDataPointer<std::vector<Element>>(
           "facets_to_subfacet_double", type, gt, 1, false);
 
       mesh_facets.getDataPointer<std::vector<Element>>(
           "elements_to_subfacet_double", type, gt, 1, false);
 
       mesh_facets.getDataPointer<std::vector<Element>>(
           "subfacets_to_subsubfacet_double", type, gt, 1, false);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <bool subsubfacet_mode>
 void MeshUtils::findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh_facets.getSpatialDimension();
   if (spatial_dimension == 1)
     return;
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
 
     GhostType gt_facet = *gt;
 
     Mesh::type_iterator it =
         mesh_facets.firstType(spatial_dimension - 1, gt_facet);
     Mesh::type_iterator end =
         mesh_facets.lastType(spatial_dimension - 1, gt_facet);
 
     for (; it != end; ++it) {
 
       ElementType type_facet = *it;
 
       Array<UInt> & f_to_double =
           mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet);
       UInt nb_facet_to_double = f_to_double.size();
       if (nb_facet_to_double == 0)
         continue;
 
       ElementType type_subfacet = Mesh::getFacetType(type_facet);
       GhostType gt_subfacet = _casper;
 
       ElementType type_subsubfacet = Mesh::getFacetType(type_subfacet);
       GhostType gt_subsubfacet = _casper;
 
       Array<UInt> * conn_subfacet = nullptr;
       Array<UInt> * sf_to_double = nullptr;
       Array<std::vector<Element>> * sf_to_subfacet_double = nullptr;
       Array<std::vector<Element>> * f_to_subfacet_double = nullptr;
       Array<std::vector<Element>> * el_to_subfacet_double = nullptr;
 
       UInt nb_subfacet = Mesh::getNbFacetsPerElement(type_facet);
 
       UInt nb_subsubfacet;
       UInt nb_nodes_per_sf_el;
 
       if (subsubfacet_mode) {
         nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subsubfacet);
         nb_subsubfacet = Mesh::getNbFacetsPerElement(type_subfacet);
       } else
         nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subfacet);
 
       Array<Element> & subfacet_to_facet =
           mesh_facets.getSubelementToElement(type_facet, gt_facet);
 
       Array<std::vector<Element>> & element_to_facet =
           mesh_facets.getElementToSubelement(type_facet, gt_facet);
 
       Array<Element> * subsubfacet_to_subfacet = nullptr;
 
       UInt old_nb_facet = subfacet_to_facet.size() - nb_facet_to_double;
 
       Element current_facet{type_facet, 0, gt_facet};
       std::vector<Element> element_list;
       std::vector<Element> facet_list;
       std::vector<Element> * subfacet_list;
       if (subsubfacet_mode)
         subfacet_list = new std::vector<Element>;
 
       /// map to filter subfacets
       Array<std::vector<Element>> * facet_to_subfacet = nullptr;
 
       /// this is used to make sure that both new and old facets are
       /// checked
       UInt facets[2];
 
       /// loop on every facet
       for (UInt f_index = 0; f_index < 2; ++f_index) {
         for (UInt facet = 0; facet < nb_facet_to_double; ++facet) {
           facets[bool(f_index)] = f_to_double(facet);
           facets[!bool(f_index)] = old_nb_facet + facet;
 
           UInt old_facet = facets[0];
           UInt new_facet = facets[1];
 
           Element & starting_element = element_to_facet(new_facet)[0];
           current_facet.element = old_facet;
 
           /// loop on every subfacet
           for (UInt sf = 0; sf < nb_subfacet; ++sf) {
 
             Element & subfacet = subfacet_to_facet(old_facet, sf);
             if (subfacet == ElementNull)
               continue;
 
             if (gt_subfacet != subfacet.ghost_type) {
               gt_subfacet = subfacet.ghost_type;
 
               if (subsubfacet_mode) {
                 subsubfacet_to_subfacet = &mesh_facets.getSubelementToElement(
                     type_subfacet, gt_subfacet);
               } else {
                 conn_subfacet =
                     &mesh_facets.getConnectivity(type_subfacet, gt_subfacet);
                 sf_to_double = &mesh_facets.getData<UInt>(
                     "facet_to_double", type_subfacet, gt_subfacet);
 
                 f_to_subfacet_double =
                     &mesh_facets.getData<std::vector<Element>>(
                         "facets_to_subfacet_double", type_subfacet,
                         gt_subfacet);
 
                 el_to_subfacet_double =
                     &mesh_facets.getData<std::vector<Element>>(
                         "elements_to_subfacet_double", type_subfacet,
                         gt_subfacet);
 
                 facet_to_subfacet = &mesh_facets.getElementToSubelement(
                     type_subfacet, gt_subfacet);
               }
             }
 
             if (subsubfacet_mode) {
               /// loop on every subsubfacet
               for (UInt ssf = 0; ssf < nb_subsubfacet; ++ssf) {
                 Element & subsubfacet =
                     (*subsubfacet_to_subfacet)(subfacet.element, ssf);
 
                 if (subsubfacet == ElementNull)
                   continue;
 
                 if (gt_subsubfacet != subsubfacet.ghost_type) {
                   gt_subsubfacet = subsubfacet.ghost_type;
                   conn_subfacet = &mesh_facets.getConnectivity(type_subsubfacet,
                                                                gt_subsubfacet);
                   sf_to_double = &mesh_facets.getData<UInt>(
                       "facet_to_double", type_subsubfacet, gt_subsubfacet);
 
                   sf_to_subfacet_double =
                       &mesh_facets.getData<std::vector<Element>>(
                           "subfacets_to_subsubfacet_double", type_subsubfacet,
                           gt_subsubfacet);
 
                   f_to_subfacet_double =
                       &mesh_facets.getData<std::vector<Element>>(
                           "facets_to_subfacet_double", type_subsubfacet,
                           gt_subsubfacet);
 
                   el_to_subfacet_double =
                       &mesh_facets.getData<std::vector<Element>>(
                           "elements_to_subfacet_double", type_subsubfacet,
                           gt_subsubfacet);
 
                   facet_to_subfacet = &mesh_facets.getElementToSubelement(
                       type_subsubfacet, gt_subsubfacet);
                 }
 
                 UInt global_ssf = subsubfacet.element;
 
                 Vector<UInt> subsubfacet_connectivity(
                     conn_subfacet->storage() + global_ssf * nb_nodes_per_sf_el,
                     nb_nodes_per_sf_el);
 
                 /// check if subsubfacet is to be doubled
                 if (findElementsAroundSubfacet<true>(
                         mesh, mesh_facets, starting_element, current_facet,
                         subsubfacet_connectivity, element_list, facet_list,
                         subfacet_list) == false &&
                     removeElementsInVector(*subfacet_list,
                                            (*facet_to_subfacet)(global_ssf)) ==
                         false) {
 
                   sf_to_double->push_back(global_ssf);
                   sf_to_subfacet_double->push_back(*subfacet_list);
                   f_to_subfacet_double->push_back(facet_list);
                   el_to_subfacet_double->push_back(element_list);
                 }
               }
             } else {
               const UInt global_sf = subfacet.element;
 
               Vector<UInt> subfacet_connectivity(
                   conn_subfacet->storage() + global_sf * nb_nodes_per_sf_el,
                   nb_nodes_per_sf_el);
 
               /// check if subfacet is to be doubled
               if (findElementsAroundSubfacet<false>(
                       mesh, mesh_facets, starting_element, current_facet,
                       subfacet_connectivity, element_list,
                       facet_list) == false &&
                   removeElementsInVector(
                       facet_list, (*facet_to_subfacet)(global_sf)) == false) {
 
                 sf_to_double->push_back(global_sf);
                 f_to_subfacet_double->push_back(facet_list);
                 el_to_subfacet_double->push_back(element_list);
               }
             }
           }
         }
       }
 
       if (subsubfacet_mode)
         delete subfacet_list;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 #if defined(AKANTU_COHESIVE_ELEMENT)
 void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets,
                                    Array<Element> & new_elements) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   bool third_dimension = spatial_dimension == 3;
 
   MeshAccessor mesh_facets_accessor(mesh_facets);
 
   for (auto gt_facet : ghost_types) {
     for (auto type_facet :
          mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) {
 
       Array<UInt> & f_to_double =
           mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet);
 
       UInt nb_facet_to_double = f_to_double.size();
       if (nb_facet_to_double == 0)
         continue;
 
       ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet);
 
       auto & facet_to_coh_element =
           mesh_facets_accessor.getSubelementToElement(type_cohesive, gt_facet);
 
       auto & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet);
       auto & conn_cohesive = mesh.getConnectivity(type_cohesive, gt_facet);
       UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet);
 
       Array<std::vector<Element>> & element_to_facet =
           mesh_facets.getElementToSubelement(type_facet, gt_facet);
 
       UInt old_nb_cohesive_elements = conn_cohesive.size();
       UInt new_nb_cohesive_elements = conn_cohesive.size() + nb_facet_to_double;
 
       UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double;
       facet_to_coh_element.resize(new_nb_cohesive_elements);
       conn_cohesive.resize(new_nb_cohesive_elements);
 
       UInt new_elements_old_size = new_elements.size();
       new_elements.resize(new_elements_old_size + nb_facet_to_double);
 
       Element c_element{type_cohesive, 0, gt_facet};
       Element f_element{type_facet, 0, gt_facet};
 
       UInt facets[2];
 
       for (UInt facet = 0; facet < nb_facet_to_double; ++facet) {
 
         /// (in 3D cohesive elements connectivity is inverted)
         facets[third_dimension] = f_to_double(facet);
         facets[!third_dimension] = old_nb_facet + facet;
 
         UInt cohesive_element = old_nb_cohesive_elements + facet;
 
         /// store doubled facets
         f_element.element = facets[0];
         facet_to_coh_element(cohesive_element, 0) = f_element;
         f_element.element = facets[1];
         facet_to_coh_element(cohesive_element, 1) = f_element;
 
         /// modify cohesive elements' connectivity
         for (UInt n = 0; n < nb_nodes_per_facet; ++n) {
           conn_cohesive(cohesive_element, n) = conn_facet(facets[0], n);
           conn_cohesive(cohesive_element, n + nb_nodes_per_facet) =
               conn_facet(facets[1], n);
         }
 
         /// update element_to_facet vectors
         c_element.element = cohesive_element;
         element_to_facet(facets[0])[1] = c_element;
         element_to_facet(facets[1])[1] = c_element;
 
         /// add cohesive element to the element event list
         new_elements(new_elements_old_size + facet) = c_element;
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 #endif
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::doublePointFacet(Mesh & mesh, Mesh & mesh_facets,
                                  Array<UInt> & doubled_nodes) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   if (spatial_dimension != 1)
     return;
 
   Array<Real> & position = mesh.getNodes();
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
 
     GhostType gt_facet = *gt;
 
     Mesh::type_iterator it =
         mesh_facets.firstType(spatial_dimension - 1, gt_facet);
     Mesh::type_iterator end =
         mesh_facets.lastType(spatial_dimension - 1, gt_facet);
 
     for (; it != end; ++it) {
 
       ElementType type_facet = *it;
 
       Array<UInt> & conn_facet =
           mesh_facets.getConnectivity(type_facet, gt_facet);
       Array<std::vector<Element>> & element_to_facet =
           mesh_facets.getElementToSubelement(type_facet, gt_facet);
 
       const Array<UInt> & f_to_double =
           mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet);
 
       UInt nb_facet_to_double = f_to_double.size();
 
       UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double;
       UInt new_nb_facet = element_to_facet.size();
 
       UInt old_nb_nodes = position.size();
       UInt new_nb_nodes = old_nb_nodes + nb_facet_to_double;
 
       position.resize(new_nb_nodes);
       conn_facet.resize(new_nb_facet);
 
       UInt old_nb_doubled_nodes = doubled_nodes.size();
       doubled_nodes.resize(old_nb_doubled_nodes + nb_facet_to_double);
 
       for (UInt facet = 0; facet < nb_facet_to_double; ++facet) {
         UInt old_facet = f_to_double(facet);
         UInt new_facet = old_nb_facet + facet;
 
         ElementType type = element_to_facet(new_facet)[0].type;
         UInt el = element_to_facet(new_facet)[0].element;
         GhostType gt = element_to_facet(new_facet)[0].ghost_type;
 
         UInt old_node = conn_facet(old_facet);
         UInt new_node = old_nb_nodes + facet;
 
         /// update position
         position(new_node) = position(old_node);
 
         conn_facet(new_facet) = new_node;
         Array<UInt> & conn_segment = mesh.getConnectivity(type, gt);
         UInt nb_nodes_per_segment = conn_segment.getNbComponent();
 
         /// update facet connectivity
         UInt i;
         for (i = 0;
              conn_segment(el, i) != old_node && i <= nb_nodes_per_segment; ++i)
           ;
         conn_segment(el, i) = new_node;
 
         doubled_nodes(old_nb_doubled_nodes + facet, 0) = old_node;
         doubled_nodes(old_nb_doubled_nodes + facet, 1) = new_node;
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <bool third_dim_segments>
 void MeshUtils::updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets,
                                         ElementType type_facet,
                                         GhostType gt_facet,
                                         Array<UInt> & doubled_nodes) {
   AKANTU_DEBUG_IN();
 
   if (type_facet != _segment_3)
     return;
 
   Array<UInt> & f_to_double =
       mesh_facets.getData<UInt>("facet_to_double", type_facet, gt_facet);
   UInt nb_facet_to_double = f_to_double.size();
 
   UInt old_nb_facet =
       mesh_facets.getNbElement(type_facet, gt_facet) - nb_facet_to_double;
 
   Array<UInt> & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet);
 
   Array<std::vector<Element>> & element_to_facet =
       mesh_facets.getElementToSubelement(type_facet, gt_facet);
 
   /// this ones matter only for segments in 3D
   Array<std::vector<Element>> * el_to_subfacet_double = nullptr;
   Array<std::vector<Element>> * f_to_subfacet_double = nullptr;
 
   if (third_dim_segments) {
     el_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>(
         "elements_to_subfacet_double", type_facet, gt_facet);
 
     f_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>(
         "facets_to_subfacet_double", type_facet, gt_facet);
   }
 
   std::vector<UInt> middle_nodes;
 
   for (UInt facet = 0; facet < nb_facet_to_double; ++facet) {
     UInt old_facet = f_to_double(facet);
     UInt node = conn_facet(old_facet, 2);
     if (!mesh.isPureGhostNode(node))
       middle_nodes.push_back(node);
   }
 
   UInt n = doubled_nodes.size();
 
   doubleNodes(mesh, middle_nodes, doubled_nodes);
 
   for (UInt facet = 0; facet < nb_facet_to_double; ++facet) {
     UInt old_facet = f_to_double(facet);
     UInt old_node = conn_facet(old_facet, 2);
     if (mesh.isPureGhostNode(old_node))
       continue;
 
     UInt new_node = doubled_nodes(n, 1);
     UInt new_facet = old_nb_facet + facet;
 
     conn_facet(new_facet, 2) = new_node;
 
     if (third_dim_segments) {
       updateElementalConnectivity(mesh_facets, old_node, new_node,
                                   element_to_facet(new_facet));
 
       updateElementalConnectivity(mesh, old_node, new_node,
                                   (*el_to_subfacet_double)(facet),
                                   &(*f_to_subfacet_double)(facet));
     } else {
       updateElementalConnectivity(mesh, old_node, new_node,
                                   element_to_facet(new_facet));
     }
     ++n;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::updateSubfacetToFacet(Mesh & mesh_facets,
                                       ElementType type_subfacet,
                                       GhostType gt_subfacet, bool facet_mode) {
   AKANTU_DEBUG_IN();
 
   Array<UInt> & sf_to_double =
       mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet);
   UInt nb_subfacet_to_double = sf_to_double.size();
 
   /// update subfacet_to_facet vector
   ElementType type_facet = _not_defined;
   GhostType gt_facet = _casper;
   Array<Element> * subfacet_to_facet = nullptr;
   UInt nb_subfacet_per_facet = 0;
   UInt old_nb_subfacet = mesh_facets.getNbElement(type_subfacet, gt_subfacet) -
                          nb_subfacet_to_double;
 
   Array<std::vector<Element>> * facet_list = nullptr;
   if (facet_mode)
     facet_list = &mesh_facets.getData<std::vector<Element>>(
         "facets_to_subfacet_double", type_subfacet, gt_subfacet);
   else
     facet_list = &mesh_facets.getData<std::vector<Element>>(
         "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet);
 
   Element old_subfacet_el{type_subfacet, 0, gt_subfacet};
   Element new_subfacet_el{type_subfacet, 0, gt_subfacet};
 
   for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) {
     old_subfacet_el.element = sf_to_double(sf);
     new_subfacet_el.element = old_nb_subfacet + sf;
 
     for (UInt f = 0; f < (*facet_list)(sf).size(); ++f) {
       Element & facet = (*facet_list)(sf)[f];
 
       if (facet.type != type_facet || facet.ghost_type != gt_facet) {
         type_facet = facet.type;
         gt_facet = facet.ghost_type;
 
         subfacet_to_facet =
             &mesh_facets.getSubelementToElement(type_facet, gt_facet);
         nb_subfacet_per_facet = subfacet_to_facet->getNbComponent();
       }
 
       Element * sf_update = std::find(
           subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet,
           subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet +
               nb_subfacet_per_facet,
           old_subfacet_el);
 
       AKANTU_DEBUG_ASSERT(subfacet_to_facet->storage() +
                                   facet.element * nb_subfacet_per_facet !=
                               subfacet_to_facet->storage() +
                                   facet.element * nb_subfacet_per_facet +
                                   nb_subfacet_per_facet,
                           "Subfacet not found");
 
       *sf_update = new_subfacet_el;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::updateFacetToSubfacet(Mesh & mesh_facets,
                                       ElementType type_subfacet,
                                       GhostType gt_subfacet, bool facet_mode) {
   AKANTU_DEBUG_IN();
 
   Array<UInt> & sf_to_double =
       mesh_facets.getData<UInt>("facet_to_double", type_subfacet, gt_subfacet);
   UInt nb_subfacet_to_double = sf_to_double.size();
 
   Array<std::vector<Element>> & facet_to_subfacet =
       mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet);
 
   Array<std::vector<Element>> * facet_to_subfacet_double = nullptr;
 
   if (facet_mode) {
     facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>(
         "facets_to_subfacet_double", type_subfacet, gt_subfacet);
   } else {
     facet_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>(
         "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet);
   }
 
   UInt old_nb_subfacet = facet_to_subfacet.size();
   facet_to_subfacet.resize(old_nb_subfacet + nb_subfacet_to_double);
 
   for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf)
     facet_to_subfacet(old_nb_subfacet + sf) = (*facet_to_subfacet_double)(sf);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MeshUtils::doubleSubfacet(Mesh & mesh, Mesh & mesh_facets,
                                Array<UInt> & doubled_nodes) {
   AKANTU_DEBUG_IN();
 
   if (spatial_dimension == 1)
     return;
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
 
     GhostType gt_subfacet = *gt;
 
     Mesh::type_iterator it = mesh_facets.firstType(0, gt_subfacet);
     Mesh::type_iterator end = mesh_facets.lastType(0, gt_subfacet);
 
     for (; it != end; ++it) {
 
       ElementType type_subfacet = *it;
 
       Array<UInt> & sf_to_double = mesh_facets.getData<UInt>(
           "facet_to_double", type_subfacet, gt_subfacet);
       UInt nb_subfacet_to_double = sf_to_double.size();
 
       if (nb_subfacet_to_double == 0)
         continue;
 
       AKANTU_DEBUG_ASSERT(
           type_subfacet == _point_1,
           "Only _point_1 subfacet doubling is supported at the moment");
 
       Array<UInt> & conn_subfacet =
           mesh_facets.getConnectivity(type_subfacet, gt_subfacet);
 
       UInt old_nb_subfacet = conn_subfacet.size();
       UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double;
 
       conn_subfacet.resize(new_nb_subfacet);
 
       std::vector<UInt> nodes_to_double;
       UInt old_nb_doubled_nodes = doubled_nodes.size();
 
       /// double nodes
       for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) {
         UInt old_subfacet = sf_to_double(sf);
         nodes_to_double.push_back(conn_subfacet(old_subfacet));
       }
 
       doubleNodes(mesh, nodes_to_double, doubled_nodes);
 
       /// add new nodes in connectivity
       for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) {
         UInt new_subfacet = old_nb_subfacet + sf;
         UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1);
 
         conn_subfacet(new_subfacet) = new_node;
       }
 
       /// update facet and element connectivity
       Array<std::vector<Element>> & f_to_subfacet_double =
           mesh_facets.getData<std::vector<Element>>("facets_to_subfacet_double",
                                                     type_subfacet, gt_subfacet);
 
       Array<std::vector<Element>> & el_to_subfacet_double =
           mesh_facets.getData<std::vector<Element>>(
               "elements_to_subfacet_double", type_subfacet, gt_subfacet);
 
       Array<std::vector<Element>> * sf_to_subfacet_double = nullptr;
 
       if (spatial_dimension == 3)
         sf_to_subfacet_double = &mesh_facets.getData<std::vector<Element>>(
             "subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet);
 
       for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) {
         UInt old_node = doubled_nodes(old_nb_doubled_nodes + sf, 0);
         UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1);
 
         updateElementalConnectivity(mesh, old_node, new_node,
                                     el_to_subfacet_double(sf),
                                     &f_to_subfacet_double(sf));
 
         updateElementalConnectivity(mesh_facets, old_node, new_node,
                                     f_to_subfacet_double(sf));
 
         if (spatial_dimension == 3)
           updateElementalConnectivity(mesh_facets, old_node, new_node,
                                       (*sf_to_subfacet_double)(sf));
       }
 
       if (spatial_dimension == 2) {
         updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, true);
         updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, true);
       } else if (spatial_dimension == 3) {
         updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, false);
         updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, false);
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::flipFacets(
     Mesh & mesh_facets, const ElementTypeMapArray<UInt> & global_connectivity,
     GhostType gt_facet) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh_facets.getSpatialDimension();
 
   /// get global connectivity for local mesh
   ElementTypeMapArray<UInt> global_connectivity_tmp("global_connectivity_tmp",
                                                     mesh_facets.getID(),
                                                     mesh_facets.getMemoryID());
 
   global_connectivity_tmp.initialize(
       mesh_facets, _spatial_dimension = spatial_dimension - 1,
+      _ghost_type = gt_facet,
       _with_nb_nodes_per_element = true, _with_nb_element = true);
 
   mesh_facets.getGlobalConnectivity(global_connectivity_tmp);
 
   /// loop on every facet
   for (auto type_facet :
        mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) {
 
     auto & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet);
     const auto & g_connectivity = global_connectivity(type_facet, gt_facet);
 
     auto & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet);
     auto & subfacet_to_facet =
         mesh_facets.getSubelementToElement(type_facet, gt_facet);
 
     UInt nb_subfacet_per_facet = subfacet_to_facet.getNbComponent();
     UInt nb_nodes_per_facet = connectivity.getNbComponent();
     UInt nb_facet = connectivity.size();
 
     UInt nb_nodes_per_P1_facet =
         Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet));
 
     auto & global_conn_tmp = global_connectivity_tmp(type_facet, gt_facet);
 
     auto conn_it = connectivity.begin(nb_nodes_per_facet);
     auto gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet);
     auto conn_glob_it = g_connectivity.begin(nb_nodes_per_facet);
     auto subf_to_f = subfacet_to_facet.begin(nb_subfacet_per_facet);
 
     auto * conn_tmp_pointer = new UInt[nb_nodes_per_facet];
     Vector<UInt> conn_tmp(conn_tmp_pointer, nb_nodes_per_facet);
 
     Element el_tmp;
     auto * subf_tmp_pointer = new Element[nb_subfacet_per_facet];
     Vector<Element> subf_tmp(subf_tmp_pointer, nb_subfacet_per_facet);
 
     for (UInt f = 0; f < nb_facet;
          ++f, ++conn_it, ++gconn_tmp_it, ++subf_to_f, ++conn_glob_it) {
 
       Vector<UInt> & gconn_tmp = *gconn_tmp_it;
       const Vector<UInt> & conn_glob = *conn_glob_it;
       Vector<UInt> & conn_local = *conn_it;
 
       /// skip facet if connectivities are the same
       if (gconn_tmp == conn_glob)
         continue;
 
       /// re-arrange connectivity
       conn_tmp = conn_local;
 
       UInt * begin = conn_glob.storage();
       UInt * end = conn_glob.storage() + nb_nodes_per_facet;
 
       for (UInt n = 0; n < nb_nodes_per_facet; ++n) {
 
         UInt * new_node = std::find(begin, end, gconn_tmp(n));
         AKANTU_DEBUG_ASSERT(new_node != end, "Node not found");
 
         UInt new_position = new_node - begin;
 
         conn_local(new_position) = conn_tmp(n);
       }
 
       /// if 3D, check if facets are just rotated
       if (spatial_dimension == 3) {
         /// find first node
         UInt * new_node = std::find(begin, end, gconn_tmp(0));
         AKANTU_DEBUG_ASSERT(new_node != end, "Node not found");
 
         UInt new_position = new_node - begin;
         UInt n = 1;
 
         /// count how many nodes in the received connectivity follow
         /// the same order of those in the local connectivity
         for (; n < nb_nodes_per_P1_facet &&
                gconn_tmp(n) ==
                    conn_glob((new_position + n) % nb_nodes_per_P1_facet);
              ++n)
           ;
 
         /// skip the facet inversion if facet is just rotated
         if (n == nb_nodes_per_P1_facet)
           continue;
       }
 
       /// update data to invert facet
       el_tmp = el_to_f(f)[0];
       el_to_f(f)[0] = el_to_f(f)[1];
       el_to_f(f)[1] = el_tmp;
 
       subf_tmp = (*subf_to_f);
       (*subf_to_f)(0) = subf_tmp(1);
       (*subf_to_f)(1) = subf_tmp(0);
     }
 
     delete[] subf_tmp_pointer;
     delete[] conn_tmp_pointer;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::fillElementToSubElementsData(Mesh & mesh) {
   AKANTU_DEBUG_IN();
 
   if (mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) {
     AKANTU_DEBUG_INFO("There are not facets, add them in the mesh file or call "
                       "the buildFacet method.");
     return;
   }
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   ElementTypeMapArray<Real> barycenters("barycenter_tmp", mesh.getID(),
                                         mesh.getMemoryID());
   barycenters.initialize(mesh, _nb_component = spatial_dimension,
                          _spatial_dimension = _all_dimensions);
   // mesh.initElementTypeMapArray(barycenters, spatial_dimension,
   // _all_dimensions);
 
   Element element;
   for (auto ghost_type : ghost_types) {
     element.ghost_type = ghost_type;
     for (auto & type : mesh.elementTypes(_all_dimensions, ghost_type)) {
       element.type = type;
 
       UInt nb_element = mesh.getNbElement(type, ghost_type);
       Array<Real> & barycenters_arr = barycenters(type, ghost_type);
       barycenters_arr.resize(nb_element);
       auto bary = barycenters_arr.begin(spatial_dimension);
       auto bary_end = barycenters_arr.end(spatial_dimension);
 
       for (UInt el = 0; bary != bary_end; ++bary, ++el) {
         element.element = el;
         mesh.getBarycenter(element, *bary);
       }
     }
   }
 
   MeshAccessor mesh_accessor(mesh);
   for (Int sp(spatial_dimension); sp >= 1; --sp) {
     if (mesh.getNbElement(sp) == 0)
       continue;
 
     for (auto ghost_type : ghost_types) {
       for (auto & type : mesh.elementTypes(sp, ghost_type)) {
         mesh_accessor.getSubelementToElement(type, ghost_type)
             .resize(mesh.getNbElement(type, ghost_type));
         mesh_accessor.getSubelementToElement(type, ghost_type).clear();
       }
 
       for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) {
         mesh_accessor.getElementToSubelement(type, ghost_type)
             .resize(mesh.getNbElement(type, ghost_type));
         mesh.getElementToSubelement(type, ghost_type).clear();
       }
     }
 
     CSR<Element> nodes_to_elements;
     buildNode2Elements(mesh, nodes_to_elements, sp);
 
     Element facet_element;
 
     for (auto ghost_type : ghost_types) {
       facet_element.ghost_type = ghost_type;
       for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) {
         facet_element.type = type;
 
         auto & element_to_subelement =
             mesh.getElementToSubelement(type, ghost_type);
 
         const auto & connectivity = mesh.getConnectivity(type, ghost_type);
 
         auto fit = connectivity.begin(mesh.getNbNodesPerElement(type));
         auto fend = connectivity.end(mesh.getNbNodesPerElement(type));
 
         UInt fid = 0;
         for (; fit != fend; ++fit, ++fid) {
           const Vector<UInt> & facet = *fit;
           facet_element.element = fid;
           std::map<Element, UInt> element_seen_counter;
           UInt nb_nodes_per_facet =
               mesh.getNbNodesPerElement(Mesh::getP1ElementType(type));
 
           for (UInt n(0); n < nb_nodes_per_facet; ++n) {
 
             auto eit = nodes_to_elements.begin(facet(n));
             auto eend = nodes_to_elements.end(facet(n));
             for (; eit != eend; ++eit) {
               auto & elem = *eit;
               auto cit = element_seen_counter.find(elem);
               if (cit != element_seen_counter.end()) {
                 cit->second++;
               } else {
                 element_seen_counter[elem] = 1;
               }
             }
           }
 
           std::vector<Element> connected_elements;
           auto cit = element_seen_counter.begin();
           auto cend = element_seen_counter.end();
           for (; cit != cend; ++cit) {
             if (cit->second == nb_nodes_per_facet)
               connected_elements.push_back(cit->first);
           }
 
           auto ceit = connected_elements.begin();
           auto ceend = connected_elements.end();
           for (; ceit != ceend; ++ceit)
             element_to_subelement(fid).push_back(*ceit);
 
           for (UInt ce = 0; ce < connected_elements.size(); ++ce) {
             Element & elem = connected_elements[ce];
             Array<Element> & subelement_to_element =
                 mesh_accessor.getSubelementToElement(elem.type,
                                                      elem.ghost_type);
 
             UInt f(0);
             for (; f < mesh.getNbFacetsPerElement(elem.type) &&
                    subelement_to_element(elem.element, f) != ElementNull;
                  ++f)
               ;
 
             AKANTU_DEBUG_ASSERT(
                 f < mesh.getNbFacetsPerElement(elem.type),
                 "The element " << elem << " seems to have too many facets!! ("
                                << f << " < "
                                << mesh.getNbFacetsPerElement(elem.type) << ")");
 
             subelement_to_element(elem.element, f) = facet_element;
           }
         }
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <bool third_dim_points>
 bool MeshUtils::findElementsAroundSubfacet(
     const Mesh & mesh, const Mesh & mesh_facets,
     const Element & starting_element, const Element & end_facet,
     const Vector<UInt> & subfacet_connectivity,
     std::vector<Element> & elem_list, std::vector<Element> & facet_list,
     std::vector<Element> * subfacet_list) {
   AKANTU_DEBUG_IN();
 
   /// preallocated stuff before starting
   bool facet_matched = false;
 
   elem_list.clear();
   facet_list.clear();
 
   if (third_dim_points)
     subfacet_list->clear();
 
   elem_list.push_back(starting_element);
 
   const Array<UInt> * facet_connectivity = nullptr;
   const Array<UInt> * sf_connectivity = nullptr;
   const Array<Element> * facet_to_element = nullptr;
   const Array<Element> * subfacet_to_facet = nullptr;
 
   ElementType current_type = _not_defined;
   GhostType current_ghost_type = _casper;
 
   ElementType current_facet_type = _not_defined;
   GhostType current_facet_ghost_type = _casper;
 
   ElementType current_subfacet_type = _not_defined;
   GhostType current_subfacet_ghost_type = _casper;
 
   const Array<std::vector<Element>> * element_to_facet = nullptr;
 
   const Element * opposing_el = nullptr;
 
   std::queue<Element> elements_to_check;
   elements_to_check.push(starting_element);
 
   /// keep going until there are elements to check
   while (!elements_to_check.empty()) {
 
     /// check current element
     Element & current_el = elements_to_check.front();
 
     if (current_el.type != current_type ||
         current_el.ghost_type != current_ghost_type) {
 
       current_type = current_el.type;
       current_ghost_type = current_el.ghost_type;
 
       facet_to_element =
           &mesh_facets.getSubelementToElement(current_type, current_ghost_type);
     }
 
     /// loop over each facet of the element
     for (UInt f = 0; f < facet_to_element->getNbComponent(); ++f) {
 
       const Element & current_facet =
           (*facet_to_element)(current_el.element, f);
 
       if (current_facet == ElementNull)
         continue;
 
       if (current_facet_type != current_facet.type ||
           current_facet_ghost_type != current_facet.ghost_type) {
 
         current_facet_type = current_facet.type;
         current_facet_ghost_type = current_facet.ghost_type;
 
         element_to_facet = &mesh_facets.getElementToSubelement(
             current_facet_type, current_facet_ghost_type);
         facet_connectivity = &mesh_facets.getConnectivity(
             current_facet_type, current_facet_ghost_type);
 
         if (third_dim_points)
           subfacet_to_facet = &mesh_facets.getSubelementToElement(
               current_facet_type, current_facet_ghost_type);
       }
 
       /// check if end facet is reached
       if (current_facet == end_facet)
         facet_matched = true;
 
       /// add this facet if not already passed
       if (std::find(facet_list.begin(), facet_list.end(), current_facet) ==
               facet_list.end() &&
           hasElement(*facet_connectivity, current_facet,
                      subfacet_connectivity)) {
         facet_list.push_back(current_facet);
 
         if (third_dim_points) {
           /// check subfacets
           for (UInt sf = 0; sf < subfacet_to_facet->getNbComponent(); ++sf) {
             const Element & current_subfacet =
                 (*subfacet_to_facet)(current_facet.element, sf);
 
             if (current_subfacet == ElementNull)
               continue;
 
             if (current_subfacet_type != current_subfacet.type ||
                 current_subfacet_ghost_type != current_subfacet.ghost_type) {
               current_subfacet_type = current_subfacet.type;
               current_subfacet_ghost_type = current_subfacet.ghost_type;
 
               sf_connectivity = &mesh_facets.getConnectivity(
                   current_subfacet_type, current_subfacet_ghost_type);
             }
 
             if (std::find(subfacet_list->begin(), subfacet_list->end(),
                           current_subfacet) == subfacet_list->end() &&
                 hasElement(*sf_connectivity, current_subfacet,
                            subfacet_connectivity))
               subfacet_list->push_back(current_subfacet);
           }
         }
       } else
         continue;
 
       /// consider opposing element
       if ((*element_to_facet)(current_facet.element)[0] == current_el)
         opposing_el = &(*element_to_facet)(current_facet.element)[1];
       else
         opposing_el = &(*element_to_facet)(current_facet.element)[0];
 
       /// skip null elements since they are on a boundary
       if (*opposing_el == ElementNull)
         continue;
 
       /// skip this element if already added
       if (std::find(elem_list.begin(), elem_list.end(), *opposing_el) !=
           elem_list.end())
         continue;
 
       /// only regular elements have to be checked
       if (opposing_el->kind() == _ek_regular)
         elements_to_check.push(*opposing_el);
 
       elem_list.push_back(*opposing_el);
 
 #ifndef AKANTU_NDEBUG
       const Array<UInt> & conn_elem =
           mesh.getConnectivity(opposing_el->type, opposing_el->ghost_type);
 
       AKANTU_DEBUG_ASSERT(
           hasElement(conn_elem, *opposing_el, subfacet_connectivity),
           "Subfacet doesn't belong to this element");
 #endif
     }
 
     /// erased checked element from the list
     elements_to_check.pop();
   }
 
   AKANTU_DEBUG_OUT();
   return facet_matched;
 }
 
 /* -------------------------------------------------------------------------- */
 UInt MeshUtils::updateLocalMasterGlobalConnectivity(Mesh & mesh,
                                                     UInt local_nb_new_nodes) {
   const auto & comm = mesh.getCommunicator();
   Int rank = comm.whoAmI();
   Int nb_proc = comm.getNbProc();
   if (nb_proc == 1)
     return local_nb_new_nodes;
 
   /// resize global ids array
   Array<UInt> & nodes_global_ids = mesh.getGlobalNodesIds();
   UInt old_nb_nodes = mesh.getNbNodes() - local_nb_new_nodes;
 
   nodes_global_ids.resize(mesh.getNbNodes());
 
   /// compute the number of global nodes based on the number of old nodes
   Vector<UInt> old_local_master_nodes(nb_proc);
   for (UInt n = 0; n < old_nb_nodes; ++n)
     if (mesh.isLocalOrMasterNode(n))
       ++old_local_master_nodes(rank);
   comm.allGather(old_local_master_nodes);
   UInt old_global_nodes =
       std::accumulate(old_local_master_nodes.storage(),
                       old_local_master_nodes.storage() + nb_proc, 0);
 
   /// compute amount of local or master doubled nodes
   Vector<UInt> local_master_nodes(nb_proc);
   for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n)
     if (mesh.isLocalOrMasterNode(n))
       ++local_master_nodes(rank);
 
   comm.allGather(local_master_nodes);
 
   /// update global number of nodes
   UInt total_nb_new_nodes = std::accumulate(
       local_master_nodes.storage(), local_master_nodes.storage() + nb_proc, 0);
 
   if (total_nb_new_nodes == 0)
     return 0;
 
   /// set global ids of local and master nodes
   UInt starting_index =
       std::accumulate(local_master_nodes.storage(),
                       local_master_nodes.storage() + rank, old_global_nodes);
 
   for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) {
     if (mesh.isLocalOrMasterNode(n)) {
       nodes_global_ids(n) = starting_index;
       ++starting_index;
     }
   }
 
   MeshAccessor mesh_accessor(mesh);
   mesh_accessor.setNbGlobalNodes(old_global_nodes + total_nb_new_nodes);
   return total_nb_new_nodes;
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshUtils::updateElementalConnectivity(
     Mesh & mesh, UInt old_node, UInt new_node,
     const std::vector<Element> & element_list,
     __attribute__((unused)) const std::vector<Element> * facet_list) {
   AKANTU_DEBUG_IN();
 
   ElementType el_type = _not_defined;
   GhostType gt_type = _casper;
   Array<UInt> * conn_elem = nullptr;
 #if defined(AKANTU_COHESIVE_ELEMENT)
   const Array<Element> * cohesive_facets = nullptr;
 #endif
   UInt nb_nodes_per_element = 0;
   UInt * n_update = nullptr;
 
   for (UInt el = 0; el < element_list.size(); ++el) {
     const Element & elem = element_list[el];
     if (elem.type == _not_defined)
       continue;
 
     if (elem.type != el_type || elem.ghost_type != gt_type) {
       el_type = elem.type;
       gt_type = elem.ghost_type;
       conn_elem = &mesh.getConnectivity(el_type, gt_type);
       nb_nodes_per_element = conn_elem->getNbComponent();
 #if defined(AKANTU_COHESIVE_ELEMENT)
       if (elem.kind() == _ek_cohesive)
         cohesive_facets =
             &mesh.getMeshFacets().getSubelementToElement(el_type, gt_type);
 #endif
     }
 
 #if defined(AKANTU_COHESIVE_ELEMENT)
     if (elem.kind() == _ek_cohesive) {
 
       AKANTU_DEBUG_ASSERT(
           facet_list != nullptr,
           "Provide a facet list in order to update cohesive elements");
 
       /// loop over cohesive element's facets
       for (UInt f = 0, n = 0; f < 2; ++f, n += nb_nodes_per_element / 2) {
         const Element & facet = (*cohesive_facets)(elem.element, f);
 
         /// skip facets if not present in the list
         if (std::find(facet_list->begin(), facet_list->end(), facet) ==
             facet_list->end())
           continue;
 
         n_update = std::find(
             conn_elem->storage() + elem.element * nb_nodes_per_element + n,
             conn_elem->storage() + elem.element * nb_nodes_per_element + n +
                 nb_nodes_per_element / 2,
             old_node);
 
         AKANTU_DEBUG_ASSERT(n_update !=
                                 conn_elem->storage() +
                                     elem.element * nb_nodes_per_element + n +
                                     nb_nodes_per_element / 2,
                             "Node not found in current element");
 
         /// update connectivity
         *n_update = new_node;
       }
     } else {
 #endif
       n_update =
           std::find(conn_elem->storage() + elem.element * nb_nodes_per_element,
                     conn_elem->storage() + elem.element * nb_nodes_per_element +
                         nb_nodes_per_element,
                     old_node);
 
       AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() +
                                           elem.element * nb_nodes_per_element +
                                           nb_nodes_per_element,
                           "Node not found in current element");
 
       /// update connectivity
       *n_update = new_node;
 #if defined(AKANTU_COHESIVE_ELEMENT)
     }
 #endif
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 } // namespace akantu
diff --git a/src/model/boundary_condition_functor.hh b/src/model/boundary_condition_functor.hh
index 2c177874d..743bd322d 100644
--- a/src/model/boundary_condition_functor.hh
+++ b/src/model/boundary_condition_functor.hh
@@ -1,197 +1,217 @@
 /**
  * @file   boundary_condition_functor.hh
  *
  * @author Dana Christen <dana.christen@gmail.com>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri May 03 2013
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Definitions of the functors to apply boundary conditions
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "fe_engine.hh"
 #include "integration_point.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__
 #define __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__
 
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 namespace BC {
   using Axis = ::akantu::SpacialDirection;
 
   struct Functor {
     enum Type { _dirichlet, _neumann };
-};
-
-/* ------------------------------------------------------------------------ */
-/* Dirichlet                                                                */
-/* ------------------------------------------------------------------------ */
-namespace Dirichlet {
-  /* ---------------------------------------------------------------------- */
-  class DirichletFunctor : public Functor {
-  protected:
-    DirichletFunctor() = default;
-    explicit DirichletFunctor(Axis ax) : axis(ax) {}
-
-  public:
-    void operator()(__attribute__((unused)) UInt node,
-                    __attribute__((unused)) Vector<bool> & flags,
-                    __attribute__((unused)) Vector<Real> & primal,
-                    __attribute__((unused)) const Vector<Real> & coord) const {
-      AKANTU_DEBUG_TO_IMPLEMENT();
-    }
-
-  public:
-    static const Type type = _dirichlet;
-
-  protected:
-    Axis axis{_x};
   };
 
-  /* ---------------------------------------------------------------------- */
-  class FlagOnly : public DirichletFunctor {
-  public:
-    explicit FlagOnly(Axis ax = _x) : DirichletFunctor(ax) {}
-
-  public:
-    inline void operator()(UInt node, Vector<bool> & flags,
-                           Vector<Real> & primal,
-                           const Vector<Real> & coord) const;
-  };
-
-  /* ---------------------------------------------------------------------- */
-  class FreeBoundary : public DirichletFunctor {
-  public:
-    explicit FreeBoundary(Axis ax = _x) : DirichletFunctor(ax) {}
-
-  public:
-    inline void operator()(UInt node, Vector<bool> & flags,
-                           Vector<Real> & primal,
-                           const Vector<Real> & coord) const;
-  };
-
-  /* ---------------------------------------------------------------------- */
-  class FixedValue : public DirichletFunctor {
-  public:
-    FixedValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {}
-
-  public:
-    inline void operator()(UInt node, Vector<bool> & flags,
-                           Vector<Real> & primal,
-                           const Vector<Real> & coord) const;
-
-  protected:
-    Real value;
-  };
-
-  /* ---------------------------------------------------------------------- */
-  class IncrementValue : public DirichletFunctor {
-  public:
-    IncrementValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {}
-
-  public:
-    inline void operator()(UInt node, Vector<bool> & flags,
-                           Vector<Real> & primal,
-                           const Vector<Real> & coord) const;
-
-    inline void setIncrement(Real val) { this->value = val; }
-
-  protected:
-    Real value;
-  };
-} // end namespace Dirichlet
-
-/* ------------------------------------------------------------------------ */
-/* Neumann                                                                  */
-/* ------------------------------------------------------------------------ */
-namespace Neumann {
-  /* ---------------------------------------------------------------------- */
-  class NeumannFunctor : public Functor {
-
-  protected:
-    NeumannFunctor() = default;
-
-  public:
-    virtual void operator()(const IntegrationPoint & quad_point,
-                            Vector<Real> & dual, const Vector<Real> & coord,
-                            const Vector<Real> & normals) const = 0;
-
-    virtual ~NeumannFunctor() = default;
-
-  public:
-    static const Type type = _neumann;
-  };
-
-  /* ---------------------------------------------------------------------- */
-  class FromHigherDim : public NeumannFunctor {
-  public:
-    explicit FromHigherDim(const Matrix<Real> & mat) : bc_data(mat) {}
-    ~FromHigherDim() override = default;
-
-  public:
-    inline void operator()(const IntegrationPoint & quad_point,
-                           Vector<Real> & dual, const Vector<Real> & coord,
-                           const Vector<Real> & normals) const override;
-
-  protected:
-    Matrix<Real> bc_data;
-  };
-
-  /* ---------------------------------------------------------------------- */
-  class FromSameDim : public NeumannFunctor {
-  public:
-    explicit FromSameDim(const Vector<Real> & vec) : bc_data(vec) {}
-    ~FromSameDim() override = default;
-
-  public:
-    inline void operator()(const IntegrationPoint & quad_point,
-                           Vector<Real> & dual, const Vector<Real> & coord,
-                           const Vector<Real> & normals) const override;
-
-  protected:
-    Vector<Real> bc_data;
-  };
-
-  /* ---------------------------------------------------------------------- */
-  class FreeBoundary : public NeumannFunctor {
-  public:
-    inline void operator()(const IntegrationPoint & quad_point,
-                           Vector<Real> & dual, const Vector<Real> & coord,
-                           const Vector<Real> & normals) const override;
-  };
-} // end namespace Neumann
+  /* ------------------------------------------------------------------------ */
+  /* Dirichlet                                                                */
+  /* ------------------------------------------------------------------------ */
+  namespace Dirichlet {
+    /* ---------------------------------------------------------------------- */
+    class DirichletFunctor : public Functor {
+    protected:
+      DirichletFunctor() = default;
+      explicit DirichletFunctor(Axis ax) : axis(ax) {}
+
+    public:
+      void operator()(__attribute__((unused)) UInt node,
+                      __attribute__((unused)) Vector<bool> & flags,
+                      __attribute__((unused)) Vector<Real> & primal,
+                      __attribute__((unused))
+                      const Vector<Real> & coord) const {
+        AKANTU_DEBUG_TO_IMPLEMENT();
+      }
+
+    public:
+      static const Type type = _dirichlet;
+
+    protected:
+      Axis axis{_x};
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class FlagOnly : public DirichletFunctor {
+    public:
+      explicit FlagOnly(Axis ax = _x) : DirichletFunctor(ax) {}
+
+    public:
+      inline void operator()(UInt node, Vector<bool> & flags,
+                             Vector<Real> & primal,
+                             const Vector<Real> & coord) const;
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class FreeBoundary : public DirichletFunctor {
+    public:
+      explicit FreeBoundary(Axis ax = _x) : DirichletFunctor(ax) {}
+
+    public:
+      inline void operator()(UInt node, Vector<bool> & flags,
+                             Vector<Real> & primal,
+                             const Vector<Real> & coord) const;
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class FixedValue : public DirichletFunctor {
+    public:
+      FixedValue(Real val, Axis ax = _x) : DirichletFunctor(ax), value(val) {}
+
+    public:
+      inline void operator()(UInt node, Vector<bool> & flags,
+                             Vector<Real> & primal,
+                             const Vector<Real> & coord) const;
+
+    protected:
+      Real value;
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class IncrementValue : public DirichletFunctor {
+    public:
+      IncrementValue(Real val, Axis ax = _x)
+          : DirichletFunctor(ax), value(val) {}
+
+    public:
+      inline void operator()(UInt node, Vector<bool> & flags,
+                             Vector<Real> & primal,
+                             const Vector<Real> & coord) const;
+
+      inline void setIncrement(Real val) { this->value = val; }
+
+    protected:
+      Real value;
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class Increment : public DirichletFunctor {
+    public:
+      explicit Increment(const Vector<Real> & val)
+          : DirichletFunctor(_x), value(val) {}
+
+    public:
+      inline void operator()(UInt node, Vector<bool> & flags,
+                             Vector<Real> & primal,
+                             const Vector<Real> & coord) const;
+
+      inline void setIncrement(const Vector<Real> & val) { this->value = val; }
+
+    protected:
+      Vector<Real> value;
+    };
+
+  } // end namespace Dirichlet
+
+  /* ------------------------------------------------------------------------ */
+  /* Neumann                                                                  */
+  /* ------------------------------------------------------------------------ */
+  namespace Neumann {
+    /* ---------------------------------------------------------------------- */
+    class NeumannFunctor : public Functor {
+
+    protected:
+      NeumannFunctor() = default;
+
+    public:
+      virtual void operator()(const IntegrationPoint & quad_point,
+                              Vector<Real> & dual, const Vector<Real> & coord,
+                              const Vector<Real> & normals) const = 0;
+
+      virtual ~NeumannFunctor() = default;
+
+    public:
+      static const Type type = _neumann;
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class FromHigherDim : public NeumannFunctor {
+    public:
+      explicit FromHigherDim(const Matrix<Real> & mat) : bc_data(mat) {}
+      ~FromHigherDim() override = default;
+
+    public:
+      inline void operator()(const IntegrationPoint & quad_point,
+                             Vector<Real> & dual, const Vector<Real> & coord,
+                             const Vector<Real> & normals) const override;
+
+    protected:
+      Matrix<Real> bc_data;
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class FromSameDim : public NeumannFunctor {
+    public:
+      explicit FromSameDim(const Vector<Real> & vec) : bc_data(vec) {}
+      ~FromSameDim() override = default;
+
+    public:
+      inline void operator()(const IntegrationPoint & quad_point,
+                             Vector<Real> & dual, const Vector<Real> & coord,
+                             const Vector<Real> & normals) const override;
+
+    protected:
+      Vector<Real> bc_data;
+    };
+
+    /* ---------------------------------------------------------------------- */
+    class FreeBoundary : public NeumannFunctor {
+    public:
+      inline void operator()(const IntegrationPoint & quad_point,
+                             Vector<Real> & dual, const Vector<Real> & coord,
+                             const Vector<Real> & normals) const override;
+    };
+  } // end namespace Neumann
 } // end namespace BC
 
 } // akantu
 
 #include "boundary_condition_functor_inline_impl.cc"
 
 #endif /* __AKANTU_BOUNDARY_CONDITION_FUNCTOR_HH__ */
diff --git a/src/model/boundary_condition_functor_inline_impl.cc b/src/model/boundary_condition_functor_inline_impl.cc
index 2d497c547..abe306794 100644
--- a/src/model/boundary_condition_functor_inline_impl.cc
+++ b/src/model/boundary_condition_functor_inline_impl.cc
@@ -1,144 +1,156 @@
 /**
  * @file   boundary_condition_functor_inline_impl.cc
  *
  * @author Dana Christen <dana.christen@gmail.com>
  *
  * @date creation: Fri May 03 2013
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  implementation of the BC::Functors
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "boundary_condition_functor.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__
 #define __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__
 
 /* -------------------------------------------------------------------------- */
 #define DIRICHLET_SANITY_CHECK                                                 \
   AKANTU_DEBUG_ASSERT(                                                         \
       coord.size() <= flags.size(),                                            \
       "The coordinates and flags vectors given to the boundary"                \
           << " condition functor have different sizes!");                      \
   AKANTU_DEBUG_ASSERT(                                                         \
       primal.size() <= coord.size(),                                           \
       "The primal vector and coordinates vector given"                         \
           << " to the boundary condition functor have different sizes!");
 
 #define NEUMANN_SANITY_CHECK                                                   \
   AKANTU_DEBUG_ASSERT(                                                         \
       coord.size() <= normals.size(),                                          \
       "The coordinates and normals vectors given to the"                       \
           << " boundary condition functor have different sizes!");             \
   AKANTU_DEBUG_ASSERT(                                                         \
       dual.size() <= coord.size(),                                             \
       "The dual vector and coordinates vector given to"                        \
           << " the boundary condition functor have different sizes!");
 
 namespace akantu {
 namespace BC {
   namespace Dirichlet {
     /* ---------------------------------------------------------------------- */
     inline void FlagOnly::
     operator()(__attribute__((unused)) UInt node, Vector<bool> & flags,
                __attribute__((unused)) Vector<Real> & primal,
                __attribute__((unused)) const Vector<Real> & coord) const {
 
       DIRICHLET_SANITY_CHECK;
 
       flags(this->axis) = true;
     }
 
     /* ---------------------------------------------------------------------- */
     inline void FreeBoundary::
     operator()(__attribute__((unused)) UInt node, Vector<bool> & flags,
                __attribute__((unused)) Vector<Real> & primal,
                __attribute__((unused)) const Vector<Real> & coord) const {
 
       DIRICHLET_SANITY_CHECK;
 
       flags(this->axis) = false;
     }
 
     /* ---------------------------------------------------------------------- */
     inline void FixedValue::operator()(__attribute__((unused)) UInt node,
                                        Vector<bool> & flags,
                                        Vector<Real> & primal,
                                        __attribute__((unused))
                                        const Vector<Real> & coord) const {
       DIRICHLET_SANITY_CHECK;
       flags(this->axis) = true;
       primal(this->axis) = value;
     }
 
     /* ---------------------------------------------------------------------- */
     inline void IncrementValue::operator()(__attribute__((unused)) UInt node,
                                            Vector<bool> & flags,
                                            Vector<Real> & primal,
                                            __attribute__((unused))
                                            const Vector<Real> & coord) const {
       DIRICHLET_SANITY_CHECK;
       flags(this->axis) = true;
       primal(this->axis) += value;
     }
+
+    /* ---------------------------------------------------------------------- */
+    inline void Increment::operator()(__attribute__((unused)) UInt node,
+                                      Vector<bool> & flags,
+                                      Vector<Real> & primal,
+                                      __attribute__((unused))
+                                      const Vector<Real> & coord) const {
+      DIRICHLET_SANITY_CHECK;
+      flags.set(true);
+      primal += value;
+    }
+
   } // end namespace Dirichlet
 
   /* ------------------------------------------------------------------------ */
   /* Neumann */
   /* ------------------------------------------------------------------------ */
   namespace Neumann {
     /* ---------------------------------------------------------------------- */
     inline void FreeBoundary::
     operator()(__attribute__((unused)) const IntegrationPoint & quad_point,
                Vector<Real> & dual,
                __attribute__((unused)) const Vector<Real> & coord,
                __attribute__((unused)) const Vector<Real> & normals) const {
       for (UInt i(0); i < dual.size(); ++i) {
         dual(i) = 0.0;
       }
     }
 
     /* ---------------------------------------------------------------------- */
     inline void FromHigherDim::operator()(__attribute__((unused))
                                           const IntegrationPoint & quad_point,
                                           Vector<Real> & dual,
                                           __attribute__((unused))
                                           const Vector<Real> & coord,
                                           const Vector<Real> & normals) const {
       dual.mul<false>(this->bc_data, normals);
     }
 
     /* ---------------------------------------------------------------------- */
     inline void FromSameDim::
     operator()(__attribute__((unused)) const IntegrationPoint & quad_point,
                Vector<Real> & dual,
                __attribute__((unused)) const Vector<Real> & coord,
                __attribute__((unused)) const Vector<Real> & normals) const {
       dual = this->bc_data;
     }
   } // namespace Neumann
 } // namespace BC
 
 } // namespace akantu
 
 #endif /* __AKANTU_BOUNDARY_CONDITION_FUNCTOR_INLINE_IMPL_CC__ */
diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc
index 000762ce9..16058656f 100644
--- a/src/model/solid_mechanics/material.cc
+++ b/src/model/solid_mechanics/material.cc
@@ -1,1553 +1,1554 @@
 /**
  * @file   material.cc
  *
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Tue Jul 27 2010
  * @date last modification: Tue Nov 24 2015
  *
  * @brief  Implementation of the common part of the material class
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "material.hh"
 #include "solid_mechanics_model.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 Material::Material(SolidMechanicsModel & model, const ID & id)
     : Memory(id, model.getMemoryID()), Parsable(ParserType::_material, id),
       is_init(false), fem(model.getFEEngine()), finite_deformation(false),
       name(""), model(model),
       spatial_dimension(this->model.getSpatialDimension()),
       element_filter("element_filter", id, this->memory_id),
       stress("stress", *this), eigengradu("eigen_grad_u", *this),
       gradu("grad_u", *this), green_strain("green_strain", *this),
       piola_kirchhoff_2("piola_kirchhoff_2", *this),
       potential_energy("potential_energy", *this), is_non_local(false),
       use_previous_stress(false), use_previous_gradu(false),
       interpolation_inverse_coordinates("interpolation inverse coordinates",
                                         *this),
       interpolation_points_matrices("interpolation points matrices", *this) {
   AKANTU_DEBUG_IN();
 
   /// for each connectivity types allocate the element filer array of the
   /// material
   element_filter.initialize(model.getMesh(),
                             _spatial_dimension = spatial_dimension);
   // model.getMesh().initElementTypeMapArray(element_filter, 1,
   // spatial_dimension,
   //                                         false, _ek_regular);
 
   this->initialize();
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Material::Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh,
                    FEEngine & fe_engine, const ID & id)
     : Memory(id, model.getMemoryID()), Parsable(ParserType::_material, id),
-      is_init(false), fem(model.getFEEngine()), finite_deformation(false),
+      is_init(false), fem(fe_engine), finite_deformation(false),
       name(""), model(model), spatial_dimension(dim),
       element_filter("element_filter", id, this->memory_id),
       stress("stress", *this, dim, fe_engine, this->element_filter),
       eigengradu("eigen_grad_u", *this, dim, fe_engine, this->element_filter),
       gradu("gradu", *this, dim, fe_engine, this->element_filter),
       green_strain("green_strain", *this, dim, fe_engine, this->element_filter),
-      piola_kirchhoff_2("poila_kirchhoff_2", *this, dim, fe_engine,
+      piola_kirchhoff_2("piola_kirchhoff_2", *this, dim, fe_engine,
                         this->element_filter),
       potential_energy("potential_energy", *this, dim, fe_engine,
                        this->element_filter),
       is_non_local(false), use_previous_stress(false),
       use_previous_gradu(false),
       interpolation_inverse_coordinates("interpolation inverse_coordinates",
                                         *this, dim, fe_engine,
                                         this->element_filter),
       interpolation_points_matrices("interpolation points matrices", *this, dim,
                                     fe_engine, this->element_filter) {
 
   AKANTU_DEBUG_IN();
   element_filter.initialize(mesh, _spatial_dimension = spatial_dimension);
   // mesh.initElementTypeMapArray(element_filter, 1, spatial_dimension, false,
   //                              _ek_regular);
 
   this->initialize();
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Material::~Material() = default;
 
 /* -------------------------------------------------------------------------- */
 void Material::initialize() {
   registerParam("rho", rho, Real(0.), _pat_parsable | _pat_modifiable,
                 "Density");
   registerParam("name", name, std::string(), _pat_parsable | _pat_readable);
   registerParam("finite_deformation", finite_deformation, false,
                 _pat_parsable | _pat_readable, "Is finite deformation");
   registerParam("inelastic_deformation", inelastic_deformation, false,
                 _pat_internal, "Is inelastic deformation");
 
   /// allocate gradu stress for local elements
   eigengradu.initialize(spatial_dimension * spatial_dimension);
   gradu.initialize(spatial_dimension * spatial_dimension);
   stress.initialize(spatial_dimension * spatial_dimension);
 
   potential_energy.initialize(1);
 
   this->model.registerEventHandler(*this);
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::initMaterial() {
   AKANTU_DEBUG_IN();
 
   if (finite_deformation) {
     this->piola_kirchhoff_2.initialize(spatial_dimension * spatial_dimension);
     if (use_previous_stress)
       this->piola_kirchhoff_2.initializeHistory();
     this->green_strain.initialize(spatial_dimension * spatial_dimension);
   }
 
   if (use_previous_stress)
     this->stress.initializeHistory();
   if (use_previous_gradu)
     this->gradu.initializeHistory();
 
   for (auto it = internal_vectors_real.begin();
        it != internal_vectors_real.end(); ++it)
     it->second->resize();
 
   for (auto it = internal_vectors_uint.begin();
        it != internal_vectors_uint.end(); ++it)
     it->second->resize();
 
   for (auto it = internal_vectors_bool.begin();
        it != internal_vectors_bool.end(); ++it)
     it->second->resize();
 
   is_init = true;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::savePreviousState() {
   AKANTU_DEBUG_IN();
 
   for (auto it = internal_vectors_real.begin();
        it != internal_vectors_real.end(); ++it) {
     if (it->second->hasHistory())
       it->second->saveCurrentValues();
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Compute  the  residual  by  assembling  @f$\int_{e}  \sigma_e  \frac{\partial
  * \varphi}{\partial X} dX @f$
  *
  * @param[in] displacements nodes displacements
  * @param[in] ghost_type compute the residual for _ghost or _not_ghost element
  */
 // void Material::updateResidual(GhostType ghost_type) {
 //   AKANTU_DEBUG_IN();
 
 //   computeAllStresses(ghost_type);
 //   assembleResidual(ghost_type);
 
 //   AKANTU_DEBUG_OUT();
 // }
 
 /* -------------------------------------------------------------------------- */
 void Material::assembleInternalForces(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = model.getSpatialDimension();
 
   if (!finite_deformation) {
 
     auto & internal_force = const_cast<Array<Real> &>(model.getInternalForce());
 
     // Mesh & mesh = fem.getMesh();
     for (auto && type :
          element_filter.elementTypes(spatial_dimension, ghost_type)) {
       Array<UInt> & elem_filter = element_filter(type, ghost_type);
       UInt nb_element = elem_filter.size();
 
       if (nb_element == 0)
         continue;
 
       const Array<Real> & shapes_derivatives =
           fem.getShapesDerivatives(type, ghost_type);
 
       UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent();
       UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
       UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 
       /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by
       /// @f$\mathbf{B}^t \mathbf{\sigma}_q@f$
       Array<Real> * sigma_dphi_dx =
           new Array<Real>(nb_element * nb_quadrature_points,
                           size_of_shapes_derivatives, "sigma_x_dphi_/_dX");
 
       fem.computeBtD(stress(type, ghost_type), *sigma_dphi_dx, type, ghost_type,
                      elem_filter);
 
       // Array<Real> * shapesd_filtered =
       //     new Array<Real>(0, size_of_shapes_derivatives, "filtered shapesd");
 
       // FEEngine::filterElementalData(mesh, shapes_derivatives,
       // *shapesd_filtered,
       //                               *it, ghost_type, elem_filter);
 
       // Array<Real> & stress_vect = this->stress(*it, ghost_type);
 
       // Array<Real>::matrix_iterator sigma =
       //     stress_vect.begin(spatial_dimension, spatial_dimension);
       // Array<Real>::matrix_iterator B =
       //     shapesd_filtered->begin(spatial_dimension, nb_nodes_per_element);
       // Array<Real>::matrix_iterator Bt_sigma_it =
       //     sigma_dphi_dx->begin(spatial_dimension, nb_nodes_per_element);
 
       // for (UInt q = 0; q < nb_element * nb_quadrature_points;
       //      ++q, ++sigma, ++B, ++Bt_sigma_it)
       //   Bt_sigma_it->mul<false, false>(*sigma, *B);
 
       // delete shapesd_filtered;
 
       /**
        * compute @f$\int \sigma  * \frac{\partial \varphi}{\partial X}dX@f$ by
        * @f$ \sum_q \mathbf{B}^t
        * \mathbf{\sigma}_q \overline w_q J_q@f$
        */
       Array<Real> * int_sigma_dphi_dx =
           new Array<Real>(nb_element, nb_nodes_per_element * spatial_dimension,
                           "int_sigma_x_dphi_/_dX");
 
       fem.integrate(*sigma_dphi_dx, *int_sigma_dphi_dx,
                     size_of_shapes_derivatives, type, ghost_type, elem_filter);
       delete sigma_dphi_dx;
 
       /// assemble
       model.getDOFManager().assembleElementalArrayLocalArray(
           *int_sigma_dphi_dx, internal_force, type, ghost_type, -1,
           elem_filter);
       delete int_sigma_dphi_dx;
     }
   } else {
     switch (spatial_dimension) {
     case 1:
       this->assembleInternalForces<1>(ghost_type);
       break;
     case 2:
       this->assembleInternalForces<2>(ghost_type);
       break;
     case 3:
       this->assembleInternalForces<3>(ghost_type);
       break;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Compute  the  stress from the gradu
  *
  * @param[in] current_position nodes postition + displacements
  * @param[in] ghost_type compute the residual for _ghost or _not_ghost element
  */
 void Material::computeAllStresses(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = model.getSpatialDimension();
 
   for (const auto & type :
        element_filter.elementTypes(spatial_dimension, ghost_type)) {
     Array<UInt> & elem_filter = element_filter(type, ghost_type);
 
     if (elem_filter.size() == 0)
       continue;
     Array<Real> & gradu_vect = gradu(type, ghost_type);
 
     /// compute @f$\nabla u@f$
     fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect,
                                     spatial_dimension, type, ghost_type,
                                     elem_filter);
 
     gradu_vect -= eigengradu(type, ghost_type);
 
     /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$
     computeStress(type, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::computeAllCauchyStresses(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(finite_deformation, "The Cauchy stress can only be "
                                           "computed if you are working in "
                                           "finite deformation.");
 
   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) {
     switch (spatial_dimension) {
     case 1:
       this->computeCauchyStress<1>(type, ghost_type);
       break;
     case 2:
       this->computeCauchyStress<2>(type, ghost_type);
       break;
     case 3:
       this->computeCauchyStress<3>(type, ghost_type);
       break;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 void Material::computeCauchyStress(ElementType el_type, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Array<Real>::matrix_iterator gradu_it =
       this->gradu(el_type, ghost_type).begin(dim, dim);
 
   Array<Real>::matrix_iterator gradu_end =
       this->gradu(el_type, ghost_type).end(dim, dim);
 
   Array<Real>::matrix_iterator piola_it =
       this->piola_kirchhoff_2(el_type, ghost_type).begin(dim, dim);
 
   Array<Real>::matrix_iterator stress_it =
       this->stress(el_type, ghost_type).begin(dim, dim);
 
   Matrix<Real> F_tensor(dim, dim);
 
   for (; gradu_it != gradu_end; ++gradu_it, ++piola_it, ++stress_it) {
     Matrix<Real> & grad_u = *gradu_it;
     Matrix<Real> & piola = *piola_it;
     Matrix<Real> & sigma = *stress_it;
 
     gradUToF<dim>(grad_u, F_tensor);
     this->computeCauchyStressOnQuad<dim>(F_tensor, piola, sigma);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::setToSteadyState(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   const Array<Real> & displacement = model.getDisplacement();
 
   // resizeInternalArray(gradu);
 
   UInt spatial_dimension = model.getSpatialDimension();
 
   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) {
     Array<UInt> & elem_filter = element_filter(type, ghost_type);
     Array<Real> & gradu_vect = gradu(type, ghost_type);
 
     /// compute @f$\nabla u@f$
     fem.gradientOnIntegrationPoints(displacement, gradu_vect, spatial_dimension,
                                     type, ghost_type, elem_filter);
 
     setToSteadyState(type, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Compute  the stiffness  matrix by  assembling @f$\int_{\omega}  B^t  \times D
  * \times B d\omega @f$
  *
  * @param[in] current_position nodes postition + displacements
  * @param[in] ghost_type compute the residual for _ghost or _not_ghost element
  */
 void Material::assembleStiffnessMatrix(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = model.getSpatialDimension();
 
   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) {
     if (finite_deformation) {
       switch (spatial_dimension) {
       case 1: {
         assembleStiffnessMatrixNL<1>(type, ghost_type);
         assembleStiffnessMatrixL2<1>(type, ghost_type);
         break;
       }
       case 2: {
         assembleStiffnessMatrixNL<2>(type, ghost_type);
         assembleStiffnessMatrixL2<2>(type, ghost_type);
         break;
       }
       case 3: {
         assembleStiffnessMatrixNL<3>(type, ghost_type);
         assembleStiffnessMatrixL2<3>(type, ghost_type);
         break;
       }
       }
     } else {
       switch (spatial_dimension) {
       case 1: {
         assembleStiffnessMatrix<1>(type, ghost_type);
         break;
       }
       case 2: {
         assembleStiffnessMatrix<2>(type, ghost_type);
         break;
       }
       case 3: {
         assembleStiffnessMatrix<3>(type, ghost_type);
         break;
       }
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 void Material::assembleStiffnessMatrix(const ElementType & type,
                                        GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Array<UInt> & elem_filter = element_filter(type, ghost_type);
   if (elem_filter.size() == 0) {
     AKANTU_DEBUG_OUT();
     return;
   }
 
   // const Array<Real> & shapes_derivatives =
   //     fem.getShapesDerivatives(type, ghost_type);
 
   Array<Real> & gradu_vect = gradu(type, ghost_type);
 
   UInt nb_element = elem_filter.size();
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
 
   gradu_vect.resize(nb_quadrature_points * nb_element);
 
   fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim,
                                   type, ghost_type, elem_filter);
 
   UInt tangent_size = getTangentStiffnessVoigtSize(dim);
 
   Array<Real> * tangent_stiffness_matrix =
       new Array<Real>(nb_element * nb_quadrature_points,
                       tangent_size * tangent_size, "tangent_stiffness_matrix");
 
   tangent_stiffness_matrix->clear();
 
   computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type);
 
   // Array<Real> * shapesd_filtered = new Array<Real>(
   //     nb_element, dim * nb_nodes_per_element, "filtered shapesd");
 
   // fem.filterElementalData(fem.getMesh(), shapes_derivatives,
   //                         *shapesd_filtered, type, ghost_type,
   //                         elem_filter);
 
   /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   UInt bt_d_b_size = dim * nb_nodes_per_element;
 
   Array<Real> * bt_d_b = new Array<Real>(nb_element * nb_quadrature_points,
                                          bt_d_b_size * bt_d_b_size, "B^t*D*B");
 
-  fem.computeBtDB(*tangent_stiffness_matrix, *bt_d_b, 4, type, ghost_type);
+  fem.computeBtDB(*tangent_stiffness_matrix, *bt_d_b, 4, type, ghost_type, elem_filter);
   // Matrix<Real> B(tangent_size, dim * nb_nodes_per_element);
   // Matrix<Real> Bt_D(dim * nb_nodes_per_element, tangent_size);
 
   // Array<Real>::matrix_iterator shapes_derivatives_filtered_it =
   //     shapesd_filtered->begin(dim, nb_nodes_per_element);
 
   // Array<Real>::matrix_iterator Bt_D_B_it =
   //     bt_d_b->begin(dim * nb_nodes_per_element, dim * nb_nodes_per_element);
 
   // Array<Real>::matrix_iterator D_it =
   //     tangent_stiffness_matrix->begin(tangent_size, tangent_size);
 
   // Array<Real>::matrix_iterator D_end =
   //     tangent_stiffness_matrix->end(tangent_size, tangent_size);
 
   // for (; D_it != D_end; ++D_it, ++Bt_D_B_it,
   // ++shapes_derivatives_filtered_it) {
   //   Matrix<Real> & D = *D_it;
   //   Matrix<Real> & Bt_D_B = *Bt_D_B_it;
 
   //   VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(
   //       *shapes_derivatives_filtered_it, B, nb_nodes_per_element);
   //   Bt_D.mul<true, false>(B, D);
   //   Bt_D_B.mul<false, false>(Bt_D, B);
   // }
 
   delete tangent_stiffness_matrix;
   // delete shapesd_filtered;
 
   /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   Array<Real> * K_e =
       new Array<Real>(nb_element, bt_d_b_size * bt_d_b_size, "K_e");
 
   fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type,
                 elem_filter);
 
   delete bt_d_b;
 
   model.getDOFManager().assembleElementalMatricesToMatrix(
       "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter);
   delete K_e;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 void Material::assembleStiffnessMatrixNL(const ElementType & type,
                                          GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   const Array<Real> & shapes_derivatives =
       fem.getShapesDerivatives(type, ghost_type);
 
   Array<UInt> & elem_filter = element_filter(type, ghost_type);
   // Array<Real> & gradu_vect = delta_gradu(type, ghost_type);
 
   UInt nb_element = elem_filter.size();
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
 
   Array<Real> * shapes_derivatives_filtered = new Array<Real>(
       nb_element * nb_quadrature_points, dim * nb_nodes_per_element,
       "shapes derivatives filtered");
 
   fem.filterElementalData(fem.getMesh(), shapes_derivatives,
                           *shapes_derivatives_filtered, type, ghost_type,
                           elem_filter);
 
   /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   UInt bt_s_b_size = dim * nb_nodes_per_element;
 
   Array<Real> * bt_s_b = new Array<Real>(nb_element * nb_quadrature_points,
                                          bt_s_b_size * bt_s_b_size, "B^t*D*B");
 
   UInt piola_matrix_size = getCauchyStressMatrixSize(dim);
 
   Matrix<Real> B(piola_matrix_size, bt_s_b_size);
   Matrix<Real> Bt_S(bt_s_b_size, piola_matrix_size);
   Matrix<Real> S(piola_matrix_size, piola_matrix_size);
 
   auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(
       spatial_dimension, nb_nodes_per_element);
 
   auto Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size);
   auto Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size);
   auto piola_it = piola_kirchhoff_2(type, ghost_type).begin(dim, dim);
 
   for (; Bt_S_B_it != Bt_S_B_end;
        ++Bt_S_B_it, ++shapes_derivatives_filtered_it, ++piola_it) {
     auto & Bt_S_B = *Bt_S_B_it;
     const auto & Piola_kirchhoff_matrix = *piola_it;
 
     setCauchyStressMatrix<dim>(Piola_kirchhoff_matrix, S);
     VoigtHelper<dim>::transferBMatrixToBNL(*shapes_derivatives_filtered_it, B,
                                            nb_nodes_per_element);
     Bt_S.template mul<true, false>(B, S);
     Bt_S_B.template mul<false, false>(Bt_S, B);
   }
 
   delete shapes_derivatives_filtered;
 
   /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   Array<Real> * K_e =
       new Array<Real>(nb_element, bt_s_b_size * bt_s_b_size, "K_e");
 
   fem.integrate(*bt_s_b, *K_e, bt_s_b_size * bt_s_b_size, type, ghost_type,
                 elem_filter);
 
   delete bt_s_b;
 
   model.getDOFManager().assembleElementalMatricesToMatrix(
       "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter);
 
   delete K_e;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 void Material::assembleStiffnessMatrixL2(const ElementType & type,
                                          GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   const Array<Real> & shapes_derivatives =
       fem.getShapesDerivatives(type, ghost_type);
 
   Array<UInt> & elem_filter = element_filter(type, ghost_type);
   Array<Real> & gradu_vect = gradu(type, ghost_type);
 
   UInt nb_element = elem_filter.size();
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
 
   gradu_vect.resize(nb_quadrature_points * nb_element);
 
   fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim,
                                   type, ghost_type, elem_filter);
 
   UInt tangent_size = getTangentStiffnessVoigtSize(dim);
 
   Array<Real> * tangent_stiffness_matrix =
       new Array<Real>(nb_element * nb_quadrature_points,
                       tangent_size * tangent_size, "tangent_stiffness_matrix");
 
   tangent_stiffness_matrix->clear();
 
   computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type);
 
   Array<Real> * shapes_derivatives_filtered = new Array<Real>(
       nb_element * nb_quadrature_points, dim * nb_nodes_per_element,
       "shapes derivatives filtered");
   fem.filterElementalData(fem.getMesh(), shapes_derivatives,
                           *shapes_derivatives_filtered, type, ghost_type,
                           elem_filter);
 
   /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   UInt bt_d_b_size = dim * nb_nodes_per_element;
 
   Array<Real> * bt_d_b = new Array<Real>(nb_element * nb_quadrature_points,
                                          bt_d_b_size * bt_d_b_size, "B^t*D*B");
 
   Matrix<Real> B(tangent_size, dim * nb_nodes_per_element);
   Matrix<Real> B2(tangent_size, dim * nb_nodes_per_element);
   Matrix<Real> Bt_D(dim * nb_nodes_per_element, tangent_size);
 
   auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(
       spatial_dimension, nb_nodes_per_element);
 
   auto Bt_D_B_it = bt_d_b->begin(bt_d_b_size, bt_d_b_size);
   auto grad_u_it = gradu_vect.begin(dim, dim);
   auto D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size);
   auto D_end = tangent_stiffness_matrix->end(tangent_size, tangent_size);
 
   for (; D_it != D_end;
        ++D_it, ++Bt_D_B_it, ++shapes_derivatives_filtered_it, ++grad_u_it) {
     const auto & grad_u = *grad_u_it;
     const auto & D = *D_it;
     auto & Bt_D_B = *Bt_D_B_it;
 
     // transferBMatrixToBL1<dim > (*shapes_derivatives_filtered_it, B,
     // nb_nodes_per_element);
     VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(
         *shapes_derivatives_filtered_it, B, nb_nodes_per_element);
     VoigtHelper<dim>::transferBMatrixToBL2(*shapes_derivatives_filtered_it,
                                            grad_u, B2, nb_nodes_per_element);
     B += B2;
     Bt_D.template mul<true, false>(B, D);
     Bt_D_B.template mul<false, false>(Bt_D, B);
   }
 
   delete tangent_stiffness_matrix;
   delete shapes_derivatives_filtered;
 
   /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   Array<Real> * K_e =
       new Array<Real>(nb_element, bt_d_b_size * bt_d_b_size, "K_e");
 
   fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type,
                 elem_filter);
 
   delete bt_d_b;
 
   model.getDOFManager().assembleElementalMatricesToMatrix(
       "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter);
   delete K_e;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 void Material::assembleInternalForces(GhostType ghost_type) {
 
   AKANTU_DEBUG_IN();
 
   Array<Real> & internal_force = model.getInternalForce();
 
   Mesh & mesh = fem.getMesh();
   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) {
     const Array<Real> & shapes_derivatives =
         fem.getShapesDerivatives(type, ghost_type);
 
     Array<UInt> & elem_filter = element_filter(type, ghost_type);
     if (elem_filter.size() == 0)
       continue;
     UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent();
     UInt nb_element = elem_filter.size();
     UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
     UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
 
     Array<Real> * shapesd_filtered = new Array<Real>(
         nb_element, size_of_shapes_derivatives, "filtered shapesd");
 
     fem.filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, type,
                             ghost_type, elem_filter);
 
     Array<Real>::matrix_iterator shapes_derivatives_filtered_it =
         shapesd_filtered->begin(dim, nb_nodes_per_element);
 
     // Set stress vectors
     UInt stress_size = getTangentStiffnessVoigtSize(dim);
 
     // Set matrices B and BNL*
     UInt bt_s_size = dim * nb_nodes_per_element;
 
     auto * bt_s =
         new Array<Real>(nb_element * nb_quadrature_points, bt_s_size, "B^t*S");
 
     auto grad_u_it = this->gradu(type, ghost_type).begin(dim, dim);
     auto grad_u_end = this->gradu(type, ghost_type).end(dim, dim);
     auto stress_it = this->piola_kirchhoff_2(type, ghost_type).begin(dim, dim);
     shapes_derivatives_filtered_it =
         shapesd_filtered->begin(dim, nb_nodes_per_element);
 
     Array<Real>::matrix_iterator bt_s_it = bt_s->begin(bt_s_size, 1);
 
     Matrix<Real> S_vect(stress_size, 1);
     Matrix<Real> B_tensor(stress_size, bt_s_size);
     Matrix<Real> B2_tensor(stress_size, bt_s_size);
 
     for (; grad_u_it != grad_u_end; ++grad_u_it, ++stress_it,
                                     ++shapes_derivatives_filtered_it,
                                     ++bt_s_it) {
       auto & grad_u = *grad_u_it;
       auto & r_it = *bt_s_it;
       auto & S_it = *stress_it;
 
       setCauchyStressArray<dim>(S_it, S_vect);
       VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(
           *shapes_derivatives_filtered_it, B_tensor, nb_nodes_per_element);
       VoigtHelper<dim>::transferBMatrixToBL2(*shapes_derivatives_filtered_it,
                                              grad_u, B2_tensor,
                                              nb_nodes_per_element);
 
       B_tensor += B2_tensor;
 
       r_it.template mul<true, false>(B_tensor, S_vect);
     }
 
     delete shapesd_filtered;
 
     /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
     Array<Real> * r_e = new Array<Real>(nb_element, bt_s_size, "r_e");
 
     fem.integrate(*bt_s, *r_e, bt_s_size, type, ghost_type, elem_filter);
 
     delete bt_s;
 
     model.getDOFManager().assembleElementalArrayLocalArray(
         *r_e, internal_force, type, ghost_type, -1., elem_filter);
     delete r_e;
   }
   AKANTU_DEBUG_OUT();
 }
 
 // /* -------------------------------------------------------------------------- */
 // void Material::computeAllStressesFromTangentModuli(GhostType ghost_type) {
 //   AKANTU_DEBUG_IN();
 
 //   UInt spatial_dimension = model.getSpatialDimension();
 
 //   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) {
 //     switch (spatial_dimension) {
 //     case 1: {
 //       computeAllStressesFromTangentModuli<1>(type, ghost_type);
 //       break;
 //     }
 //     case 2: {
 //       computeAllStressesFromTangentModuli<2>(type, ghost_type);
 //       break;
 //     }
 //     case 3: {
 //       computeAllStressesFromTangentModuli<3>(type, ghost_type);
 //       break;
 //     }
 //     }
 //   }
 
 //   AKANTU_DEBUG_OUT();
 // }
 
 // /* -------------------------------------------------------------------------- */
 // template <UInt dim>
 // void Material::computeAllStressesFromTangentModuli(const ElementType & type,
 //                                                    GhostType ghost_type) {
 //   AKANTU_DEBUG_IN();
 
 //   const Array<Real> & shapes_derivatives =
 //       fem.getShapesDerivatives(type, ghost_type);
 //   Array<UInt> & elem_filter = element_filter(type, ghost_type);
 //   Array<Real> & gradu_vect = gradu(type, ghost_type);
 
 //   UInt nb_element = elem_filter.size();
 //   if (nb_element) {
 //     UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 //     UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
 
 //     gradu_vect.resize(nb_quadrature_points * nb_element);
 
 //     Array<Real> & disp = model.getDisplacement();
 
 //     fem.gradientOnIntegrationPoints(disp, gradu_vect, dim, type, ghost_type,
 //                                     elem_filter);
 
 //     UInt tangent_moduli_size = getTangentStiffnessVoigtSize(dim);
 
 //     Array<Real> * tangent_moduli_tensors = new Array<Real>(
 //         nb_element * nb_quadrature_points,
 //         tangent_moduli_size * tangent_moduli_size, "tangent_moduli_tensors");
 
 //     tangent_moduli_tensors->clear();
 //     computeTangentModuli(type, *tangent_moduli_tensors, ghost_type);
 
 //     Array<Real> * shapesd_filtered = new Array<Real>(
 //         nb_element, dim * nb_nodes_per_element, "filtered shapesd");
 
 //     FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives,
 //                                   *shapesd_filtered, type, ghost_type,
 //                                   elem_filter);
 
 //     Array<Real> filtered_u(nb_element,
 //                            nb_nodes_per_element * spatial_dimension);
 
 //     fem.extractNodalToElementField(fem.getMesh(), disp, filtered_u, type,
 //                                    ghost_type, elem_filter);
 
 //     /// compute @f$\mathbf{D} \mathbf{B} \mathbf{u}@f$
 //     auto shapes_derivatives_filtered_it =
 //         shapesd_filtered->begin(dim, nb_nodes_per_element);
 
 //     auto D_it =
 //         tangent_moduli_tensors->begin(tangent_moduli_size, tangent_moduli_size);
 //     auto sigma_it =
 //         stress(type, ghost_type).begin(spatial_dimension, spatial_dimension);
 //     auto u_it = filtered_u.begin(spatial_dimension * nb_nodes_per_element);
 
 //     Matrix<Real> B(tangent_moduli_size,
 //                    spatial_dimension * nb_nodes_per_element);
 //     Vector<Real> Bu(tangent_moduli_size);
 //     Vector<Real> DBu(tangent_moduli_size);
 
 //     for (UInt e = 0; e < nb_element; ++e, ++u_it) {
 //       for (UInt q = 0; q < nb_quadrature_points;
 //            ++q, ++D_it, ++shapes_derivatives_filtered_it, ++sigma_it) {
 //         const auto & u = *u_it;
 //         const auto & D = *D_it;
 //         auto & sigma = *sigma_it;
 
 //         VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(
 //             *shapes_derivatives_filtered_it, B, nb_nodes_per_element);
 
 //         Bu.mul<false>(B, u);
 //         DBu.mul<false>(D, Bu);
 
 //         // Voigt notation to full symmetric tensor
 //         for (UInt i = 0; i < dim; ++i)
 //           sigma(i, i) = DBu(i);
 //         if (dim == 2) {
 //           sigma(0, 1) = sigma(1, 0) = DBu(2);
 //         } else if (dim == 3) {
 //           sigma(1, 2) = sigma(2, 1) = DBu(3);
 //           sigma(0, 2) = sigma(2, 0) = DBu(4);
 //           sigma(0, 1) = sigma(1, 0) = DBu(5);
 //         }
 //       }
 //     }
 //   }
 //   AKANTU_DEBUG_OUT();
 // }
 
 /* -------------------------------------------------------------------------- */
 void Material::computePotentialEnergyByElements() {
   AKANTU_DEBUG_IN();
 
   for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) {
     computePotentialEnergy(type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::computePotentialEnergy(ElementType, GhostType) {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Real Material::getPotentialEnergy() {
   AKANTU_DEBUG_IN();
   Real epot = 0.;
 
   computePotentialEnergyByElements();
 
   /// integrate the potential energy for each type of elements
   for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) {
     epot += fem.integrate(potential_energy(type, _not_ghost), type, _not_ghost,
                           element_filter(type, _not_ghost));
   }
 
   AKANTU_DEBUG_OUT();
   return epot;
 }
 
 /* -------------------------------------------------------------------------- */
 Real Material::getPotentialEnergy(ElementType & type, UInt index) {
   AKANTU_DEBUG_IN();
   Real epot = 0.;
 
   Vector<Real> epot_on_quad_points(fem.getNbIntegrationPoints(type));
 
   computePotentialEnergyByElement(type, index, epot_on_quad_points);
 
   epot = fem.integrate(epot_on_quad_points, type, element_filter(type)(index));
 
   AKANTU_DEBUG_OUT();
   return epot;
 }
 
 /* -------------------------------------------------------------------------- */
 Real Material::getEnergy(const std::string & type) {
   AKANTU_DEBUG_IN();
   if (type == "potential")
     return getPotentialEnergy();
   AKANTU_DEBUG_OUT();
   return 0.;
 }
 
 /* -------------------------------------------------------------------------- */
 Real Material::getEnergy(const std::string & energy_id, ElementType type,
                          UInt index) {
   AKANTU_DEBUG_IN();
   if (energy_id == "potential")
     return getPotentialEnergy(type, index);
   AKANTU_DEBUG_OUT();
   return 0.;
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::initElementalFieldInterpolation(
     const ElementTypeMapArray<Real> & interpolation_points_coordinates) {
   AKANTU_DEBUG_IN();
 
   this->fem.initElementalFieldInterpolationFromIntegrationPoints(
       interpolation_points_coordinates, this->interpolation_points_matrices,
       this->interpolation_inverse_coordinates, &(this->element_filter));
+
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::interpolateStress(ElementTypeMapArray<Real> & result,
                                  const GhostType ghost_type) {
 
   this->fem.interpolateElementalFieldFromIntegrationPoints(
       this->stress, this->interpolation_points_matrices,
       this->interpolation_inverse_coordinates, result, ghost_type,
       &(this->element_filter));
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::interpolateStressOnFacets(
     ElementTypeMapArray<Real> & result,
     ElementTypeMapArray<Real> & by_elem_result, const GhostType ghost_type) {
 
   interpolateStress(by_elem_result, ghost_type);
 
   UInt stress_size = this->stress.getNbComponent();
 
   const Mesh & mesh = this->model.getMesh();
   const Mesh & mesh_facets = mesh.getMeshFacets();
 
   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) {
     Array<UInt> & elem_fil = element_filter(type, ghost_type);
     Array<Real> & by_elem_res = by_elem_result(type, ghost_type);
     UInt nb_element = elem_fil.size();
     UInt nb_element_full = this->model.getMesh().getNbElement(type, ghost_type);
     UInt nb_interpolation_points_per_elem =
         by_elem_res.size() / nb_element_full;
 
     const Array<Element> & facet_to_element =
         mesh_facets.getSubelementToElement(type, ghost_type);
     ElementType type_facet = Mesh::getFacetType(type);
     UInt nb_facet_per_elem = facet_to_element.getNbComponent();
     UInt nb_quad_per_facet =
         nb_interpolation_points_per_elem / nb_facet_per_elem;
     Element element_for_comparison{type, 0, ghost_type};
     const Array<std::vector<Element>> * element_to_facet = nullptr;
     GhostType current_ghost_type = _casper;
     Array<Real> * result_vec = nullptr;
 
     Array<Real>::const_matrix_iterator result_it =
         by_elem_res.begin_reinterpret(
             stress_size, nb_interpolation_points_per_elem, nb_element_full);
 
     for (UInt el = 0; el < nb_element; ++el) {
       UInt global_el = elem_fil(el);
       element_for_comparison.element = global_el;
       for (UInt f = 0; f < nb_facet_per_elem; ++f) {
 
         Element facet_elem = facet_to_element(global_el, f);
         UInt global_facet = facet_elem.element;
         if (facet_elem.ghost_type != current_ghost_type) {
           current_ghost_type = facet_elem.ghost_type;
           element_to_facet = &mesh_facets.getElementToSubelement(
               type_facet, current_ghost_type);
           result_vec = &result(type_facet, current_ghost_type);
         }
 
         bool is_second_element =
             (*element_to_facet)(global_facet)[0] != element_for_comparison;
 
         for (UInt q = 0; q < nb_quad_per_facet; ++q) {
           Vector<Real> result_local(result_vec->storage() +
                                         (global_facet * nb_quad_per_facet + q) *
                                             result_vec->getNbComponent() +
                                         is_second_element * stress_size,
                                     stress_size);
 
           const Matrix<Real> & result_tmp(result_it[global_el]);
           result_local = result_tmp(f * nb_quad_per_facet + q);
         }
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 const Array<T> &
 Material::getArray(__attribute__((unused)) const ID & vect_id,
                    __attribute__((unused)) const ElementType & type,
                    __attribute__((unused)) const GhostType & ghost_type) const {
   AKANTU_DEBUG_TO_IMPLEMENT();
   return NULL;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Array<T> & Material::getArray(__attribute__((unused)) const ID & vect_id,
                               __attribute__((unused)) const ElementType & type,
                               __attribute__((unused))
                               const GhostType & ghost_type) {
   AKANTU_DEBUG_TO_IMPLEMENT();
   return NULL;
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 const Array<Real> & Material::getArray(const ID & vect_id,
                                        const ElementType & type,
                                        const GhostType & ghost_type) const {
   std::stringstream sstr;
   std::string ghost_id = "";
   if (ghost_type == _ghost)
     ghost_id = ":ghost";
   sstr << getID() << ":" << vect_id << ":" << type << ghost_id;
 
   ID fvect_id = sstr.str();
   try {
     return Memory::getArray<Real>(fvect_id);
   } catch (debug::Exception & e) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain a vector "
                                             << vect_id << "(" << fvect_id
                                             << ") [" << e << "]");
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 Array<Real> & Material::getArray(const ID & vect_id, const ElementType & type,
                                  const GhostType & ghost_type) {
   std::stringstream sstr;
   std::string ghost_id = "";
   if (ghost_type == _ghost)
     ghost_id = ":ghost";
   sstr << getID() << ":" << vect_id << ":" << type << ghost_id;
 
   ID fvect_id = sstr.str();
   try {
     return Memory::getArray<Real>(fvect_id);
   } catch (debug::Exception & e) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain a vector "
                                             << vect_id << "(" << fvect_id
                                             << ") [" << e << "]");
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 const Array<UInt> & Material::getArray(const ID & vect_id,
                                        const ElementType & type,
                                        const GhostType & ghost_type) const {
   std::stringstream sstr;
   std::string ghost_id = "";
   if (ghost_type == _ghost)
     ghost_id = ":ghost";
   sstr << getID() << ":" << vect_id << ":" << type << ghost_id;
 
   ID fvect_id = sstr.str();
   try {
     return Memory::getArray<UInt>(fvect_id);
   } catch (debug::Exception & e) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain a vector "
                                             << vect_id << "(" << fvect_id
                                             << ") [" << e << "]");
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 Array<UInt> & Material::getArray(const ID & vect_id, const ElementType & type,
                                  const GhostType & ghost_type) {
   std::stringstream sstr;
   std::string ghost_id = "";
   if (ghost_type == _ghost)
     ghost_id = ":ghost";
   sstr << getID() << ":" << vect_id << ":" << type << ghost_id;
 
   ID fvect_id = sstr.str();
   try {
     return Memory::getArray<UInt>(fvect_id);
   } catch (debug::Exception & e) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain a vector "
                                             << vect_id << "(" << fvect_id
                                             << ") [" << e << "]");
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 const InternalField<T> & Material::getInternal(__attribute__((unused))
                                                const ID & int_id) const {
   AKANTU_DEBUG_TO_IMPLEMENT();
   return NULL;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 InternalField<T> & Material::getInternal(__attribute__((unused))
                                          const ID & int_id) {
   AKANTU_DEBUG_TO_IMPLEMENT();
   return NULL;
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 const InternalField<Real> & Material::getInternal(const ID & int_id) const {
   auto it = internal_vectors_real.find(getID() + ":" + int_id);
   if (it == internal_vectors_real.end()) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain an internal "
                                             << int_id << " ("
                                             << (getID() + ":" + int_id) << ")");
   }
   return *it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <> InternalField<Real> & Material::getInternal(const ID & int_id) {
   auto it = internal_vectors_real.find(getID() + ":" + int_id);
   if (it == internal_vectors_real.end()) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain an internal "
                                             << int_id << " ("
                                             << (getID() + ":" + int_id) << ")");
   }
   return *it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 const InternalField<UInt> & Material::getInternal(const ID & int_id) const {
   auto it = internal_vectors_uint.find(getID() + ":" + int_id);
   if (it == internal_vectors_uint.end()) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain an internal "
                                             << int_id << " ("
                                             << (getID() + ":" + int_id) << ")");
   }
   return *it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <> InternalField<UInt> & Material::getInternal(const ID & int_id) {
   auto it = internal_vectors_uint.find(getID() + ":" + int_id);
   if (it == internal_vectors_uint.end()) {
     AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID()
                                             << ") does not contain an internal "
                                             << int_id << " ("
                                             << (getID() + ":" + int_id) << ")");
   }
   return *it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::addElements(const Array<Element> & elements_to_add) {
   AKANTU_DEBUG_IN();
   UInt mat_id = model.getInternalIndexFromID(getID());
   Array<Element>::const_iterator<Element> el_begin = elements_to_add.begin();
   Array<Element>::const_iterator<Element> el_end = elements_to_add.end();
   for (; el_begin != el_end; ++el_begin) {
     const Element & element = *el_begin;
     Array<UInt> & mat_indexes =
         model.getMaterialByElement(element.type, element.ghost_type);
     Array<UInt> & mat_loc_num =
         model.getMaterialLocalNumbering(element.type, element.ghost_type);
 
     UInt index =
         this->addElement(element.type, element.element, element.ghost_type);
     mat_indexes(element.element) = mat_id;
     mat_loc_num(element.element) = index;
   }
 
   this->resizeInternals();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::removeElements(const Array<Element> & elements_to_remove) {
   AKANTU_DEBUG_IN();
 
   Array<Element>::const_iterator<Element> el_begin = elements_to_remove.begin();
   Array<Element>::const_iterator<Element> el_end = elements_to_remove.end();
 
   if (el_begin == el_end)
     return;
 
   ElementTypeMapArray<UInt> material_local_new_numbering(
       "remove mat filter elem", getID(), getMemoryID());
 
   Element element;
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
     GhostType ghost_type = *gt;
     element.ghost_type = ghost_type;
 
     ElementTypeMapArray<UInt>::type_iterator it =
         element_filter.firstType(_all_dimensions, ghost_type, _ek_not_defined);
     ElementTypeMapArray<UInt>::type_iterator end =
         element_filter.lastType(_all_dimensions, ghost_type, _ek_not_defined);
 
     for (; it != end; ++it) {
       ElementType type = *it;
       element.type = type;
 
       Array<UInt> & elem_filter = this->element_filter(type, ghost_type);
       Array<UInt> & mat_loc_num =
           this->model.getMaterialLocalNumbering(type, ghost_type);
 
       if (!material_local_new_numbering.exists(type, ghost_type))
         material_local_new_numbering.alloc(elem_filter.size(), 1, type,
                                            ghost_type);
       Array<UInt> & mat_renumbering =
           material_local_new_numbering(type, ghost_type);
 
       UInt nb_element = elem_filter.size();
       Array<UInt> elem_filter_tmp;
 
       UInt new_id = 0;
       for (UInt el = 0; el < nb_element; ++el) {
         element.element = elem_filter(el);
 
         if (std::find(el_begin, el_end, element) == el_end) {
           elem_filter_tmp.push_back(element.element);
 
           mat_renumbering(el) = new_id;
           mat_loc_num(element.element) = new_id;
           ++new_id;
         } else {
           mat_renumbering(el) = UInt(-1);
         }
       }
 
       elem_filter.resize(elem_filter_tmp.size());
       elem_filter.copy(elem_filter_tmp);
     }
   }
 
   for (auto it = internal_vectors_real.begin();
        it != internal_vectors_real.end(); ++it)
     it->second->removeIntegrationPoints(material_local_new_numbering);
 
   for (auto it = internal_vectors_uint.begin();
        it != internal_vectors_uint.end(); ++it)
     it->second->removeIntegrationPoints(material_local_new_numbering);
 
   for (auto it = internal_vectors_bool.begin();
        it != internal_vectors_bool.end(); ++it)
     it->second->removeIntegrationPoints(material_local_new_numbering);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::resizeInternals() {
   AKANTU_DEBUG_IN();
   for (auto it = internal_vectors_real.begin();
        it != internal_vectors_real.end(); ++it)
     it->second->resize();
 
   for (auto it = internal_vectors_uint.begin();
        it != internal_vectors_uint.end(); ++it)
     it->second->resize();
 
   for (auto it = internal_vectors_bool.begin();
        it != internal_vectors_bool.end(); ++it)
     it->second->resize();
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::onElementsAdded(const Array<Element> &,
                                const NewElementsEvent &) {
   this->resizeInternals();
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::onElementsRemoved(
     const Array<Element> & element_list,
     const ElementTypeMapArray<UInt> & new_numbering,
     __attribute__((unused)) const RemovedElementsEvent & event) {
   UInt my_num = model.getInternalIndexFromID(getID());
 
   ElementTypeMapArray<UInt> material_local_new_numbering(
       "remove mat filter elem", getID(), getMemoryID());
 
   Array<Element>::const_iterator<Element> el_begin = element_list.begin();
   Array<Element>::const_iterator<Element> el_end = element_list.end();
 
   for (ghost_type_t::iterator g = ghost_type_t::begin();
        g != ghost_type_t::end(); ++g) {
     GhostType gt = *g;
 
     ElementTypeMapArray<UInt>::type_iterator it =
         new_numbering.firstType(_all_dimensions, gt, _ek_not_defined);
     ElementTypeMapArray<UInt>::type_iterator end =
         new_numbering.lastType(_all_dimensions, gt, _ek_not_defined);
     for (; it != end; ++it) {
       ElementType type = *it;
       if (element_filter.exists(type, gt) && element_filter(type, gt).size()) {
         Array<UInt> & elem_filter = element_filter(type, gt);
 
         Array<UInt> & mat_indexes = this->model.getMaterialByElement(*it, gt);
         Array<UInt> & mat_loc_num =
             this->model.getMaterialLocalNumbering(*it, gt);
         UInt nb_element = this->model.getMesh().getNbElement(type, gt);
 
         // all materials will resize of the same size...
         mat_indexes.resize(nb_element);
         mat_loc_num.resize(nb_element);
 
         if (!material_local_new_numbering.exists(type, gt))
           material_local_new_numbering.alloc(elem_filter.size(), 1, type, gt);
 
         Array<UInt> & mat_renumbering = material_local_new_numbering(type, gt);
         const Array<UInt> & renumbering = new_numbering(type, gt);
         Array<UInt> elem_filter_tmp;
         UInt ni = 0;
         Element el{type, 0, gt};
 
         for (UInt i = 0; i < elem_filter.size(); ++i) {
           el.element = elem_filter(i);
           if (std::find(el_begin, el_end, el) == el_end) {
             UInt new_el = renumbering(el.element);
             AKANTU_DEBUG_ASSERT(
                 new_el != UInt(-1),
                 "A not removed element as been badly renumbered");
             elem_filter_tmp.push_back(new_el);
             mat_renumbering(i) = ni;
 
             mat_indexes(new_el) = my_num;
             mat_loc_num(new_el) = ni;
             ++ni;
           } else {
             mat_renumbering(i) = UInt(-1);
           }
         }
 
         elem_filter.resize(elem_filter_tmp.size());
         elem_filter.copy(elem_filter_tmp);
       }
     }
   }
 
   for (auto it = internal_vectors_real.begin();
        it != internal_vectors_real.end(); ++it)
     it->second->removeIntegrationPoints(material_local_new_numbering);
 
   for (auto it = internal_vectors_uint.begin();
        it != internal_vectors_uint.end(); ++it)
     it->second->removeIntegrationPoints(material_local_new_numbering);
 
   for (auto it = internal_vectors_bool.begin();
        it != internal_vectors_bool.end(); ++it)
     it->second->removeIntegrationPoints(material_local_new_numbering);
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::beforeSolveStep() { this->savePreviousState(); }
 
 /* -------------------------------------------------------------------------- */
 void Material::afterSolveStep() {
   for (auto & type : element_filter.elementTypes(_all_dimensions, _not_ghost,
                                                  _ek_not_defined)) {
     this->updateEnergies(type, _not_ghost);
   }
 }
 /* -------------------------------------------------------------------------- */
 void Material::onDamageIteration() { this->savePreviousState(); }
 
 /* -------------------------------------------------------------------------- */
 void Material::onDamageUpdate() {
   ElementTypeMapArray<UInt>::type_iterator it = this->element_filter.firstType(
       _all_dimensions, _not_ghost, _ek_not_defined);
   ElementTypeMapArray<UInt>::type_iterator end =
       element_filter.lastType(_all_dimensions, _not_ghost, _ek_not_defined);
 
   for (; it != end; ++it) {
     this->updateEnergiesAfterDamage(*it, _not_ghost);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::onDump() {
   if (this->isFiniteDeformation())
     this->computeAllCauchyStresses(_not_ghost);
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::printself(std::ostream & stream, int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   std::string type = getID().substr(getID().find_last_of(':') + 1);
 
   stream << space << "Material " << type << " [" << std::endl;
   Parsable::printself(stream, indent);
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 /// extrapolate internal values
 void Material::extrapolateInternal(const ID & id, const Element & element,
                                    __attribute__((unused))
                                    const Matrix<Real> & point,
                                    Matrix<Real> & extrapolated) {
   if (this->isInternal<Real>(id, element.kind())) {
     UInt nb_element =
         this->element_filter(element.type, element.ghost_type).size();
     const ID name = this->getID() + ":" + id;
     UInt nb_quads =
         this->internal_vectors_real[name]->getFEEngine().getNbIntegrationPoints(
             element.type, element.ghost_type);
     const Array<Real> & internal =
         this->getArray<Real>(id, element.type, element.ghost_type);
     UInt nb_component = internal.getNbComponent();
     Array<Real>::const_matrix_iterator internal_it =
         internal.begin_reinterpret(nb_component, nb_quads, nb_element);
     Element local_element = this->convertToLocalElement(element);
 
     /// instead of really extrapolating, here the value of the first GP
     /// is copied into the result vector. This works only for linear
     /// elements
     /// @todo extrapolate!!!!
     AKANTU_DEBUG_WARNING("This is a fix, values are not truly extrapolated");
 
     const Matrix<Real> & values = internal_it[local_element.element];
     UInt index = 0;
     Vector<Real> tmp(nb_component);
     for (UInt j = 0; j < values.cols(); ++j) {
       tmp = values(j);
       if (tmp.norm() > 0) {
         index = j;
         break;
       }
     }
 
     for (UInt i = 0; i < extrapolated.size(); ++i) {
       extrapolated(i) = values(index);
     }
   } else {
     Matrix<Real> default_values(extrapolated.rows(), extrapolated.cols(), 0.);
     extrapolated = default_values;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void Material::applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u,
                                const GhostType ghost_type) {
 
   for (auto && type : element_filter.elementTypes(_all_dimensions, _not_ghost,
                                                   _ek_not_defined)) {
     if (!element_filter(type, ghost_type).size())
       continue;
     auto eigen_it = this->eigengradu(type, ghost_type)
                         .begin(spatial_dimension, spatial_dimension);
     auto eigen_end = this->eigengradu(type, ghost_type)
                          .end(spatial_dimension, spatial_dimension);
     for (; eigen_it != eigen_end; ++eigen_it) {
       auto & current_eigengradu = *eigen_it;
       current_eigengradu = prescribed_eigen_grad_u;
     }
   }
 }
 
 } // namespace akantu
diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh
index 0a0505dee..a3f68b552 100644
--- a/src/model/solid_mechanics/material.hh
+++ b/src/model/solid_mechanics/material.hh
@@ -1,681 +1,683 @@
 
+
 /**
  * @file   material.hh
  *
  * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Wed Nov 25 2015
  *
  * @brief  Mother class for all materials
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_factory.hh"
 #include "aka_voigthelper.hh"
 #include "data_accessor.hh"
 #include "integration_point.hh"
 #include "parsable.hh"
 #include "parser.hh"
 /* -------------------------------------------------------------------------- */
 #include "internal_field.hh"
 #include "random_internal_field.hh"
 /* -------------------------------------------------------------------------- */
 #include "mesh_events.hh"
 #include "solid_mechanics_model_event_handler.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_MATERIAL_HH__
 #define __AKANTU_MATERIAL_HH__
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 class Model;
 class SolidMechanicsModel;
 } // namespace akantu
 
 namespace akantu {
 
 /**
  * Interface of all materials
  * Prerequisites for a new material
  * - inherit from this class
  * - implement the following methods:
  * \code
  *  virtual Real getStableTimeStep(Real h, const Element & element =
  * ElementNull);
  *
  *  virtual void computeStress(ElementType el_type,
  *                             GhostType ghost_type = _not_ghost);
  *
  *  virtual void computeTangentStiffness(const ElementType & el_type,
  *                                       Array<Real> & tangent_matrix,
  *                                       GhostType ghost_type = _not_ghost);
  * \endcode
  *
  */
 class Material : public Memory,
                  public DataAccessor<Element>,
                  public Parsable,
                  public MeshEventHandler,
                  protected SolidMechanicsModelEventHandler {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
 #if __cplusplus > 199711L
   Material(const Material & mat) = delete;
   Material & operator=(const Material & mat) = delete;
 #endif
 
   /// Initialize material with defaults
   Material(SolidMechanicsModel & model, const ID & id = "");
 
   /// Initialize material with custom mesh & fe_engine
   Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh,
            FEEngine & fe_engine, const ID & id = "");
 
   /// Destructor
   ~Material() override;
 
 protected:
   void initialize();
 
   /* ------------------------------------------------------------------------ */
   /* Function that materials can/should reimplement                           */
   /* ------------------------------------------------------------------------ */
 protected:
   /// constitutive law
   virtual void computeStress(__attribute__((unused)) ElementType el_type,
                              __attribute__((unused))
                              GhostType ghost_type = _not_ghost) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// compute the tangent stiffness matrix
   virtual void computeTangentModuli(__attribute__((unused))
                                     const ElementType & el_type,
                                     __attribute__((unused))
                                     Array<Real> & tangent_matrix,
                                     __attribute__((unused))
                                     GhostType ghost_type = _not_ghost) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// compute the potential energy
   virtual void computePotentialEnergy(ElementType el_type,
                                       GhostType ghost_type = _not_ghost);
 
   /// compute the potential energy for an element
   virtual void
   computePotentialEnergyByElement(__attribute__((unused)) ElementType type,
                                   __attribute__((unused)) UInt index,
                                   __attribute__((unused))
                                   Vector<Real> & epot_on_quad_points) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   virtual void updateEnergies(__attribute__((unused)) ElementType el_type,
                               __attribute__((unused))
                               GhostType ghost_type = _not_ghost) {}
 
   virtual void updateEnergiesAfterDamage(__attribute__((unused))
                                          ElementType el_type,
                                          __attribute__((unused))
                                          GhostType ghost_type = _not_ghost) {}
 
   /// set the material to steady state (to be implemented for materials that
   /// need it)
   virtual void setToSteadyState(__attribute__((unused)) ElementType el_type,
                                 __attribute__((unused))
                                 GhostType ghost_type = _not_ghost) {}
 
   /// function called to update the internal parameters when the modifiable
   /// parameters are modified
   virtual void updateInternalParameters() {}
 
 public:
   /// extrapolate internal values
   virtual void extrapolateInternal(const ID & id, const Element & element,
                                    const Matrix<Real> & points,
                                    Matrix<Real> & extrapolated);
 
   /// compute the p-wave speed in the material
   virtual Real getPushWaveSpeed(__attribute__((unused))
                                 const Element & element) const {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// compute the s-wave speed in the material
   virtual Real getShearWaveSpeed(__attribute__((unused))
                                  const Element & element) const {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// get a material celerity to compute the stable time step (default: is the
   /// push wave speed)
   virtual Real getCelerity(const Element & element) const {
     return getPushWaveSpeed(element);
   }
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   template <typename T>
   void registerInternal(__attribute__((unused)) InternalField<T> & vect) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   template <typename T>
   void unregisterInternal(__attribute__((unused)) InternalField<T> & vect) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// initialize the material computed parameter
   virtual void initMaterial();
 
   /// compute the residual for this material
   //  virtual void updateResidual(GhostType ghost_type = _not_ghost);
 
   /// assemble the residual for this material
   virtual void assembleInternalForces(GhostType ghost_type);
 
   /// save the stress in the previous_stress if needed
   virtual void savePreviousState();
 
   /// compute the stresses for this material
   virtual void computeAllStresses(GhostType ghost_type = _not_ghost);
   // virtual void
   // computeAllStressesFromTangentModuli(GhostType ghost_type = _not_ghost);
   virtual void computeAllCauchyStresses(GhostType ghost_type = _not_ghost);
 
   /// set material to steady state
   void setToSteadyState(GhostType ghost_type = _not_ghost);
 
   /// compute the stiffness matrix
   virtual void assembleStiffnessMatrix(GhostType ghost_type);
 
   /// add an element to the local mesh filter
   inline UInt addElement(const ElementType & type, UInt element,
                          const GhostType & ghost_type);
   inline UInt addElement(const Element & element);
 
   /// add many elements at once
   void addElements(const Array<Element> & elements_to_add);
 
   /// remove many element at once
   void removeElements(const Array<Element> & elements_to_remove);
 
   /// function to print the contain of the class
   void printself(std::ostream & stream, int indent = 0) const override;
 
   /**
    * interpolate stress on given positions for each element by means
    * of a geometrical interpolation on quadrature points
    */
   void interpolateStress(ElementTypeMapArray<Real> & result,
                          const GhostType ghost_type = _not_ghost);
 
   /**
    * interpolate stress on given positions for each element by means
    * of a geometrical interpolation on quadrature points and store the
    * results per facet
    */
   void interpolateStressOnFacets(ElementTypeMapArray<Real> & result,
                                  ElementTypeMapArray<Real> & by_elem_result,
                                  const GhostType ghost_type = _not_ghost);
 
   /**
    * function to initialize the elemental field interpolation
    * function by inverting the quadrature points' coordinates
    */
   void initElementalFieldInterpolation(
       const ElementTypeMapArray<Real> & interpolation_points_coordinates);
 
   /* ------------------------------------------------------------------------ */
   /* Common part                                                              */
   /* ------------------------------------------------------------------------ */
 protected:
   /* ------------------------------------------------------------------------ */
   inline UInt getTangentStiffnessVoigtSize(UInt spatial_dimension) const;
 
   /// compute the potential energy by element
   void computePotentialEnergyByElements();
 
   /// resize the intenals arrays
   virtual void resizeInternals();
 
   /* ------------------------------------------------------------------------ */
   /* Finite deformation functions                                             */
   /* This functions area implementing what is described in the paper of Bathe */
   /* et al, in IJNME, Finite Element Formulations For Large Deformation       */
   /* Dynamic Analysis, Vol 9, 353-386, 1975                                   */
   /* ------------------------------------------------------------------------ */
 protected:
   /// assemble the residual
   template <UInt dim> void assembleInternalForces(GhostType ghost_type);
 
   /// Computation of Cauchy stress tensor in the case of finite deformation from
   /// the 2nd Piola-Kirchhoff for a given element type
   template <UInt dim>
   void computeCauchyStress(ElementType el_type,
                            GhostType ghost_type = _not_ghost);
 
   /// Computation the Cauchy stress the 2nd Piola-Kirchhoff and the deformation
   /// gradient
   template <UInt dim>
   inline void computeCauchyStressOnQuad(const Matrix<Real> & F,
                                         const Matrix<Real> & S,
                                         Matrix<Real> & cauchy,
                                         const Real & C33 = 1.0) const;
 
   template <UInt dim>
   void computeAllStressesFromTangentModuli(const ElementType & type,
                                            GhostType ghost_type);
 
   template <UInt dim>
   void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type);
 
   /// assembling in finite deformation
   template <UInt dim>
   void assembleStiffnessMatrixNL(const ElementType & type,
                                  GhostType ghost_type);
 
   template <UInt dim>
   void assembleStiffnessMatrixL2(const ElementType & type,
                                  GhostType ghost_type);
 
   /// Size of the Stress matrix for the case of finite deformation see: Bathe et
   /// al, IJNME, Vol 9, 353-386, 1975
   inline UInt getCauchyStressMatrixSize(UInt spatial_dimension) const;
 
   /// Sets the stress matrix according to Bathe et al, IJNME, Vol 9, 353-386,
   /// 1975
   template <UInt dim>
   inline void setCauchyStressMatrix(const Matrix<Real> & S_t,
                                     Matrix<Real> & sigma);
 
   /// write the stress tensor in the Voigt notation.
   template <UInt dim>
   inline void setCauchyStressArray(const Matrix<Real> & S_t,
                                    Matrix<Real> & sigma_voight);
 
   /* ------------------------------------------------------------------------ */
   /* Conversion functions                                                     */
   /* ------------------------------------------------------------------------ */
 public:
   template <UInt dim>
   static inline void gradUToF(const Matrix<Real> & grad_u, Matrix<Real> & F);
   static inline void rightCauchy(const Matrix<Real> & F, Matrix<Real> & C);
   static inline void leftCauchy(const Matrix<Real> & F, Matrix<Real> & B);
 
   template <UInt dim>
   static inline void gradUToEpsilon(const Matrix<Real> & grad_u,
                                     Matrix<Real> & epsilon);
   template <UInt dim>
   static inline void gradUToGreenStrain(const Matrix<Real> & grad_u,
                                         Matrix<Real> & epsilon);
 
   static inline Real stressToVonMises(const Matrix<Real> & stress);
 
 protected:
   /// converts global element to local element
   inline Element convertToLocalElement(const Element & global_element) const;
   /// converts local element to global element
   inline Element convertToGlobalElement(const Element & local_element) const;
 
   /// converts global quadrature point to local quadrature point
   inline IntegrationPoint
   convertToLocalPoint(const IntegrationPoint & global_point) const;
   /// converts local quadrature point to global quadrature point
   inline IntegrationPoint
   convertToGlobalPoint(const IntegrationPoint & local_point) const;
 
   /* ------------------------------------------------------------------------ */
   /* DataAccessor inherited members                                           */
   /* ------------------------------------------------------------------------ */
 public:
   inline UInt 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;
 
   template <typename T>
   inline void packElementDataHelper(const ElementTypeMapArray<T> & data_to_pack,
                                     CommunicationBuffer & buffer,
                                     const Array<Element> & elements,
                                     const ID & fem_id = ID()) const;
 
   template <typename T>
   inline void unpackElementDataHelper(ElementTypeMapArray<T> & data_to_unpack,
                                       CommunicationBuffer & buffer,
                                       const Array<Element> & elements,
                                       const ID & fem_id = ID());
 
   /* ------------------------------------------------------------------------ */
   /* MeshEventHandler inherited members                                       */
   /* ------------------------------------------------------------------------ */
 public:
   /* ------------------------------------------------------------------------ */
   void onNodesAdded(const Array<UInt> &, const NewNodesEvent &) override{};
   void onNodesRemoved(const Array<UInt> &, const Array<UInt> &,
                       const RemovedNodesEvent &) override{};
 
   void onElementsAdded(const Array<Element> & element_list,
                        const NewElementsEvent & event) override;
 
   void onElementsRemoved(const Array<Element> & element_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const RemovedElementsEvent & event) override;
 
   void onElementsChanged(const Array<Element> &, const Array<Element> &,
                          const ElementTypeMapArray<UInt> &,
                          const ChangedElementsEvent &) override{};
 
   /* ------------------------------------------------------------------------ */
   /* SolidMechanicsModelEventHandler inherited members                        */
   /* ------------------------------------------------------------------------ */
 public:
   virtual void beforeSolveStep();
   virtual void afterSolveStep();
 
   void onDamageIteration() override;
   void onDamageUpdate() override;
   void onDump() override;
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   AKANTU_GET_MACRO(Name, name, const std::string &);
 
   AKANTU_GET_MACRO(Model, model, const SolidMechanicsModel &)
 
   AKANTU_GET_MACRO(ID, Memory::getID(), const ID &);
   AKANTU_GET_MACRO(Rho, rho, Real);
   AKANTU_SET_MACRO(Rho, rho, Real);
 
   AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt);
 
   /// return the potential energy for the subset of elements contained by the
   /// material
   Real getPotentialEnergy();
   /// return the potential energy for the provided element
   Real getPotentialEnergy(ElementType & type, UInt index);
 
   /// return the energy (identified by id) for the subset of elements contained
   /// by the material
   virtual Real getEnergy(const std::string & energy_id);
   /// return the energy (identified by id) for the provided element
   virtual Real getEnergy(const std::string & energy_id, ElementType type,
                          UInt index);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementFilter, element_filter, UInt);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(GradU, gradu, Real);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PotentialEnergy, potential_energy,
                                          Real);
   AKANTU_GET_MACRO(GradU, gradu, const ElementTypeMapArray<Real> &);
   AKANTU_GET_MACRO(Stress, stress, const ElementTypeMapArray<Real> &);
   AKANTU_GET_MACRO(ElementFilter, element_filter,
                    const ElementTypeMapArray<UInt> &);
   AKANTU_GET_MACRO(FEEngine, fem, FEEngine &);
 
   bool isNonLocal() const { return is_non_local; }
 
   template <typename T>
   const Array<T> & getArray(const ID & id, const ElementType & type,
                             const GhostType & ghost_type = _not_ghost) const;
   template <typename T>
   Array<T> & getArray(const ID & id, const ElementType & type,
                       const GhostType & ghost_type = _not_ghost);
 
   template <typename T>
   const InternalField<T> & getInternal(const ID & id) const;
   template <typename T> InternalField<T> & getInternal(const ID & id);
 
   template <typename T>
   inline bool isInternal(const ID & id, const ElementKind & element_kind) const;
 
   template <typename T>
   ElementTypeMap<UInt>
   getInternalDataPerElem(const ID & id, const ElementKind & element_kind) const;
 
   bool isFiniteDeformation() const { return finite_deformation; }
   bool isInelasticDeformation() const { return inelastic_deformation; }
 
   template <typename T> inline void setParam(const ID & param, T value);
+  template <typename T> inline void setParamNoUpdate(const ID & param, T value);
   inline const Parameter & getParam(const ID & param) const;
 
   template <typename T>
   void flattenInternal(const std::string & field_id,
                        ElementTypeMapArray<T> & internal_flat,
                        const GhostType ghost_type = _not_ghost,
                        ElementKind element_kind = _ek_not_defined) const;
 
   /// apply a constant eigengrad_u everywhere in the material
   virtual void applyEigenGradU(const Matrix<Real> & prescribed_eigen_grad_u,
                                const GhostType = _not_ghost);
 
   /// specify if the matrix need to be recomputed for this material
   virtual bool hasStiffnessMatrixChanged() { return true; }
 
 protected:
   bool isInit() const { return is_init; }
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// boolean to know if the material has been initialized
   bool is_init;
 
   std::map<ID, InternalField<Real> *> internal_vectors_real;
   std::map<ID, InternalField<UInt> *> internal_vectors_uint;
   std::map<ID, InternalField<bool> *> internal_vectors_bool;
 
 protected:
   /// Link to the fem object in the model
   FEEngine & fem;
 
   /// Finite deformation
   bool finite_deformation;
 
   /// Finite deformation
   bool inelastic_deformation;
 
   /// material name
   std::string name;
 
   /// The model to witch the material belong
   SolidMechanicsModel & model;
 
   /// density : rho
   Real rho;
 
   /// spatial dimension
   UInt spatial_dimension;
 
   /// list of element handled by the material
   ElementTypeMapArray<UInt> element_filter;
 
   /// stresses arrays ordered by element types
   InternalField<Real> stress;
 
   /// eigengrad_u arrays ordered by element types
   InternalField<Real> eigengradu;
 
   /// grad_u arrays ordered by element types
   InternalField<Real> gradu;
 
   /// Green Lagrange strain (Finite deformation)
   InternalField<Real> green_strain;
 
   /// Second Piola-Kirchhoff stress tensor arrays ordered by element types
   /// (Finite deformation)
   InternalField<Real> piola_kirchhoff_2;
 
   /// potential energy by element
   InternalField<Real> potential_energy;
 
   /// tell if using in non local mode or not
   bool is_non_local;
 
   /// tell if the material need the previous stress state
   bool use_previous_stress;
 
   /// tell if the material need the previous strain state
   bool use_previous_gradu;
 
   /// elemental field interpolation coordinates
   InternalField<Real> interpolation_inverse_coordinates;
 
   /// elemental field interpolation points
   InternalField<Real> interpolation_points_matrices;
 
   /// vector that contains the names of all the internals that need to
   /// be transferred when material interfaces move
   std::vector<ID> internals_to_transfer;
 };
 
 /// standard output stream operator
 inline std::ostream & operator<<(std::ostream & stream,
                                  const Material & _this) {
   _this.printself(stream);
   return stream;
 }
 
 } // namespace akantu
 
 #include "material_inline_impl.cc"
 
 #include "internal_field_tmpl.hh"
 #include "random_internal_field_tmpl.hh"
 
 /* -------------------------------------------------------------------------- */
 /* Auto loop                                                                  */
 /* -------------------------------------------------------------------------- */
 /// This can be used to automatically write the loop on quadrature points in
 /// functions such as computeStress. This macro in addition to write the loop
 /// provides two tensors (matrices) sigma and grad_u
 #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type)       \
   Array<Real>::matrix_iterator gradu_it =                                      \
       this->gradu(el_type, ghost_type)                                         \
           .begin(this->spatial_dimension, this->spatial_dimension);            \
   Array<Real>::matrix_iterator gradu_end =                                     \
       this->gradu(el_type, ghost_type)                                         \
           .end(this->spatial_dimension, this->spatial_dimension);              \
                                                                                \
   this->stress(el_type, ghost_type)                                            \
       .resize(this->gradu(el_type, ghost_type).size());                        \
                                                                                \
   Array<Real>::iterator<Matrix<Real>> stress_it =                              \
       this->stress(el_type, ghost_type)                                        \
           .begin(this->spatial_dimension, this->spatial_dimension);            \
                                                                                \
   if (this->isFiniteDeformation()) {                                           \
     this->piola_kirchhoff_2(el_type, ghost_type)                               \
         .resize(this->gradu(el_type, ghost_type).size());                      \
     stress_it = this->piola_kirchhoff_2(el_type, ghost_type)                   \
                     .begin(this->spatial_dimension, this->spatial_dimension);  \
   }                                                                            \
                                                                                \
   for (; gradu_it != gradu_end; ++gradu_it, ++stress_it) {                     \
     Matrix<Real> & __attribute__((unused)) grad_u = *gradu_it;                 \
     Matrix<Real> & __attribute__((unused)) sigma = *stress_it
 
 #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END }
 
 /// This can be used to automatically write the loop on quadrature points in
 /// functions such as computeTangentModuli. This macro in addition to write the
 /// loop provides two tensors (matrices) sigma_tensor, grad_u, and a matrix
 /// where the elemental tangent moduli should be stored in Voigt Notation
 #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_mat)              \
   Array<Real>::matrix_iterator gradu_it =                                      \
       this->gradu(el_type, ghost_type)                                         \
           .begin(this->spatial_dimension, this->spatial_dimension);            \
   Array<Real>::matrix_iterator gradu_end =                                     \
       this->gradu(el_type, ghost_type)                                         \
           .end(this->spatial_dimension, this->spatial_dimension);              \
   Array<Real>::matrix_iterator sigma_it =                                      \
       this->stress(el_type, ghost_type)                                        \
           .begin(this->spatial_dimension, this->spatial_dimension);            \
                                                                                \
   tangent_mat.resize(this->gradu(el_type, ghost_type).size());                 \
                                                                                \
   UInt tangent_size =                                                          \
       this->getTangentStiffnessVoigtSize(this->spatial_dimension);             \
   Array<Real>::matrix_iterator tangent_it =                                    \
       tangent_mat.begin(tangent_size, tangent_size);                           \
                                                                                \
   for (; gradu_it != gradu_end; ++gradu_it, ++sigma_it, ++tangent_it) {        \
     Matrix<Real> & __attribute__((unused)) grad_u = *gradu_it;                 \
     Matrix<Real> & __attribute__((unused)) sigma_tensor = *sigma_it;           \
     Matrix<Real> & tangent = *tangent_it
 
 #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END }
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 using MaterialFactory =
     Factory<Material, ID, UInt, const ID &, SolidMechanicsModel &, const ID &>;
 } // namespace akantu
 
 #define INSTANTIATE_MATERIAL_ONLY(mat_name)                                    \
   template class mat_name<1>;                                                  \
   template class mat_name<2>;                                                  \
   template class mat_name<3>
 
 #define MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name)                       \
   [](UInt dim, const ID &, SolidMechanicsModel & model,                        \
      const ID & id) -> std::unique_ptr<Material> {                             \
     switch (dim) {                                                             \
     case 1:                                                                    \
       return std::make_unique<mat_name<1>>(model, id);                         \
     case 2:                                                                    \
       return std::make_unique<mat_name<2>>(model, id);                         \
     case 3:                                                                    \
       return std::make_unique<mat_name<3>>(model, id);                         \
     default:                                                                   \
       AKANTU_EXCEPTION("The dimension "                                        \
                        << dim << "is not a valid dimension for the material "  \
                        << #id);                                                \
     }                                                                          \
   }
 
 #define INSTANTIATE_MATERIAL(id, mat_name)                                     \
   INSTANTIATE_MATERIAL_ONLY(mat_name);                                         \
   static bool material_is_alocated_##id [[gnu::unused]] =                      \
       MaterialFactory::getInstance().registerAllocator(                        \
           #id, MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name))
 
 #endif /* __AKANTU_MATERIAL_HH__ */
diff --git a/src/model/solid_mechanics/material_inline_impl.cc b/src/model/solid_mechanics/material_inline_impl.cc
index f6141480e..1f6d1c0dd 100644
--- a/src/model/solid_mechanics/material_inline_impl.cc
+++ b/src/model/solid_mechanics/material_inline_impl.cc
@@ -1,463 +1,475 @@
 /**
  * @file   material_inline_impl.cc
  *
  * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Tue Jul 27 2010
  * @date last modification: Wed Nov 25 2015
  *
  * @brief  Implementation of the inline functions of the class material
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "solid_mechanics_model.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_MATERIAL_INLINE_IMPL_CC__
 #define __AKANTU_MATERIAL_INLINE_IMPL_CC__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 inline UInt Material::addElement(const ElementType & type, UInt element,
                                  const GhostType & ghost_type) {
   Array<UInt> & el_filter = this->element_filter(type, ghost_type);
   el_filter.push_back(element);
   return el_filter.size() - 1;
 }
 
 /* -------------------------------------------------------------------------- */
 inline UInt Material::addElement(const Element & element) {
   return this->addElement(element.type, element.element, element.ghost_type);
 }
 
 /* -------------------------------------------------------------------------- */
 inline UInt Material::getTangentStiffnessVoigtSize(UInt dim) const {
   return (dim * (dim - 1) / 2 + dim);
 }
 /* -------------------------------------------------------------------------- */
 inline UInt Material::getCauchyStressMatrixSize(UInt dim) const {
   return (dim * dim);
 }
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 inline void Material::gradUToF(const Matrix<Real> & grad_u, Matrix<Real> & F) {
   AKANTU_DEBUG_ASSERT(F.size() >= grad_u.size() && grad_u.size() == dim * dim,
                       "The dimension of the tensor F should be greater or "
                       "equal to the dimension of the tensor grad_u.");
 
   F.eye();
 
   for (UInt i = 0; i < dim; ++i)
     for (UInt j = 0; j < dim; ++j)
       F(i, j) += grad_u(i, j);
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 inline void Material::computeCauchyStressOnQuad(const Matrix<Real> & F,
                                                 const Matrix<Real> & piola,
                                                 Matrix<Real> & sigma,
                                                 const Real & C33) const {
 
   Real J = F.det() * sqrt(C33);
 
   Matrix<Real> F_S(dim, dim);
   F_S.mul<false, false>(F, piola);
   Real constant = J ? 1. / J : 0;
   sigma.mul<false, true>(F_S, F, constant);
 }
 
 /* -------------------------------------------------------------------------- */
 inline void Material::rightCauchy(const Matrix<Real> & F, Matrix<Real> & C) {
   C.mul<true, false>(F, F);
 }
 
 /* -------------------------------------------------------------------------- */
 inline void Material::leftCauchy(const Matrix<Real> & F, Matrix<Real> & B) {
   B.mul<false, true>(F, F);
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 inline void Material::gradUToEpsilon(const Matrix<Real> & grad_u,
                                      Matrix<Real> & epsilon) {
   for (UInt i = 0; i < dim; ++i)
     for (UInt j = 0; j < dim; ++j)
       epsilon(i, j) = 0.5 * (grad_u(i, j) + grad_u(j, i));
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 inline void Material::gradUToGreenStrain(const Matrix<Real> & grad_u,
                                          Matrix<Real> & epsilon) {
   epsilon.mul<true, false>(grad_u, grad_u, .5);
 
   for (UInt i = 0; i < dim; ++i)
     for (UInt j = 0; j < dim; ++j)
       epsilon(i, j) += 0.5 * (grad_u(i, j) + grad_u(j, i));
 }
 
 /* -------------------------------------------------------------------------- */
 inline Real Material::stressToVonMises(const Matrix<Real> & stress) {
   // compute deviatoric stress
   UInt dim = stress.cols();
   Matrix<Real> deviatoric_stress =
       Matrix<Real>::eye(dim, -1. * stress.trace() / 3.);
 
   for (UInt i = 0; i < dim; ++i)
     for (UInt j = 0; j < dim; ++j)
       deviatoric_stress(i, j) += stress(i, j);
 
   // return Von Mises stress
   return std::sqrt(3. * deviatoric_stress.doubleDot(deviatoric_stress) / 2.);
 }
 
 /* ---------------------------------------------------------------------------*/
 template <UInt dim>
 inline void Material::setCauchyStressArray(const Matrix<Real> & S_t,
                                            Matrix<Real> & sigma_voight) {
   AKANTU_DEBUG_IN();
   sigma_voight.clear();
   // see Finite element formulations for large deformation dynamic analysis,
   // Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau
 
   /*
    * 1d: [ s11 ]'
    * 2d: [ s11 s22 s12 ]'
    * 3d: [ s11 s22 s33 s23 s13 s12 ]
    */
   for (UInt i = 0; i < dim; ++i) // diagonal terms
     sigma_voight(i, 0) = S_t(i, i);
 
   for (UInt i = 1; i < dim; ++i) // term s12 in 2D and terms s23 s13 in 3D
     sigma_voight(dim + i - 1, 0) = S_t(dim - i - 1, dim - 1);
 
   for (UInt i = 2; i < dim; ++i) // term s13 in 3D
     sigma_voight(dim + i, 0) = S_t(0, 1);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 inline void Material::setCauchyStressMatrix(const Matrix<Real> & S_t,
                                             Matrix<Real> & sigma) {
   AKANTU_DEBUG_IN();
 
   sigma.clear();
 
   /// see Finite ekement formulations for large deformation dynamic analysis,
   /// Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau
   for (UInt i = 0; i < dim; ++i) {
     for (UInt m = 0; m < dim; ++m) {
       for (UInt n = 0; n < dim; ++n) {
         sigma(i * dim + m, i * dim + n) = S_t(m, n);
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 inline Element
 Material::convertToLocalElement(const Element & global_element) const {
   UInt ge = global_element.element;
 #ifndef AKANTU_NDEBUG
   UInt model_mat_index = this->model.getMaterialByElement(
       global_element.type, global_element.ghost_type)(ge);
 
   UInt mat_index = this->model.getMaterialIndex(this->name);
   AKANTU_DEBUG_ASSERT(model_mat_index == mat_index,
                       "Conversion of a global  element in a local element for "
                       "the wrong material "
                           << this->name << std::endl);
 #endif
   UInt le = this->model.getMaterialLocalNumbering(
       global_element.type, global_element.ghost_type)(ge);
 
   Element tmp_quad{global_element.type, le, global_element.ghost_type};
   return tmp_quad;
 }
 
 /* -------------------------------------------------------------------------- */
 inline Element
 Material::convertToGlobalElement(const Element & local_element) const {
   UInt le = local_element.element;
   UInt ge =
       this->element_filter(local_element.type, local_element.ghost_type)(le);
 
   Element tmp_quad{local_element.type, ge, local_element.ghost_type};
   return tmp_quad;
 }
 
 /* -------------------------------------------------------------------------- */
 inline IntegrationPoint
 Material::convertToLocalPoint(const IntegrationPoint & global_point) const {
   const FEEngine & fem = this->model.getFEEngine();
   UInt nb_quad = fem.getNbIntegrationPoints(global_point.type);
   Element el =
       this->convertToLocalElement(static_cast<const Element &>(global_point));
   IntegrationPoint tmp_quad(el, global_point.num_point, nb_quad);
   return tmp_quad;
 }
 
 /* -------------------------------------------------------------------------- */
 inline IntegrationPoint
 Material::convertToGlobalPoint(const IntegrationPoint & local_point) const {
   const FEEngine & fem = this->model.getFEEngine();
   UInt nb_quad = fem.getNbIntegrationPoints(local_point.type);
   Element el =
       this->convertToGlobalElement(static_cast<const Element &>(local_point));
   IntegrationPoint tmp_quad(el, local_point.num_point, nb_quad);
   return tmp_quad;
 }
 
 /* -------------------------------------------------------------------------- */
 inline UInt Material::getNbData(const Array<Element> & elements,
                                 const SynchronizationTag & tag) const {
   if (tag == _gst_smm_stress) {
     return (this->isFiniteDeformation() ? 3 : 1) * spatial_dimension *
            spatial_dimension * sizeof(Real) *
            this->getModel().getNbIntegrationPoints(elements);
   }
   return 0;
 }
 
 /* -------------------------------------------------------------------------- */
 inline void Material::packData(CommunicationBuffer & buffer,
                                const Array<Element> & elements,
                                const SynchronizationTag & tag) const {
   if (tag == _gst_smm_stress) {
     if (this->isFiniteDeformation()) {
       packElementDataHelper(piola_kirchhoff_2, buffer, elements);
       packElementDataHelper(gradu, buffer, elements);
     }
     packElementDataHelper(stress, buffer, elements);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 inline void Material::unpackData(CommunicationBuffer & buffer,
                                  const Array<Element> & elements,
                                  const SynchronizationTag & tag) {
   if (tag == _gst_smm_stress) {
     if (this->isFiniteDeformation()) {
       unpackElementDataHelper(piola_kirchhoff_2, buffer, elements);
       unpackElementDataHelper(gradu, buffer, elements);
     }
     unpackElementDataHelper(stress, buffer, elements);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 inline const Parameter & Material::getParam(const ID & param) const {
   try {
     return get(param);
   } catch (...) {
     AKANTU_EXCEPTION("No parameter " << param << " in the material "
                                      << getID());
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline void Material::setParam(const ID & param, T value) {
   try {
     set<T>(param, value);
   } catch (...) {
     AKANTU_EXCEPTION("No parameter " << param << " in the material "
                                      << getID());
   }
   updateInternalParameters();
 }
 
+/* -------------------------------------------------------------------------- */
+template <typename T>
+inline void Material::setParamNoUpdate(const ID & param, T value) {
+  try {
+    set<T>(param, value);
+  } catch (...) {
+    AKANTU_EXCEPTION("No parameter " << param << " in the material "
+                     << getID());
+  }
+}
+
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline void Material::packElementDataHelper(
     const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer,
     const Array<Element> & elements, const ID & fem_id) const {
   DataAccessor::packElementalDataHelper<T>(data_to_pack, buffer, elements, true,
                                            model.getFEEngine(fem_id));
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline void Material::unpackElementDataHelper(
     ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer,
     const Array<Element> & elements, const ID & fem_id) {
   DataAccessor::unpackElementalDataHelper<T>(data_to_unpack, buffer, elements,
                                              true, model.getFEEngine(fem_id));
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void Material::registerInternal<Real>(InternalField<Real> & vect) {
   internal_vectors_real[vect.getID()] = &vect;
 }
 
 template <>
 inline void Material::registerInternal<UInt>(InternalField<UInt> & vect) {
   internal_vectors_uint[vect.getID()] = &vect;
 }
 
 template <>
 inline void Material::registerInternal<bool>(InternalField<bool> & vect) {
   internal_vectors_bool[vect.getID()] = &vect;
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
 inline void Material::unregisterInternal<Real>(InternalField<Real> & vect) {
   internal_vectors_real.erase(vect.getID());
 }
 
 template <>
 inline void Material::unregisterInternal<UInt>(InternalField<UInt> & vect) {
   internal_vectors_uint.erase(vect.getID());
 }
 
 template <>
 inline void Material::unregisterInternal<bool>(InternalField<bool> & vect) {
   internal_vectors_bool.erase(vect.getID());
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline bool Material::isInternal(__attribute__((unused)) const ID & id,
-                                 __attribute__((unused)) const ElementKind & element_kind) const {
+                                 __attribute__((unused))
+                                 const ElementKind & element_kind) const {
   AKANTU_DEBUG_TO_IMPLEMENT();
 }
 
 template <>
 inline bool Material::isInternal<Real>(const ID & id,
                                        const ElementKind & element_kind) const {
   auto internal_array = internal_vectors_real.find(this->getID() + ":" + id);
 
   if (internal_array == internal_vectors_real.end() ||
       internal_array->second->getElementKind() != element_kind)
     return false;
   return true;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline ElementTypeMap<UInt>
 Material::getInternalDataPerElem(const ID & field_id,
                                  const ElementKind & element_kind) const {
 
   if (!this->template isInternal<T>(field_id, element_kind))
     AKANTU_EXCEPTION("Cannot find internal field " << id << " in material "
                                                    << this->name);
 
   const InternalField<T> & internal_field =
       this->template getInternal<T>(field_id);
   const FEEngine & fe_engine = internal_field.getFEEngine();
   UInt nb_data_per_quad = internal_field.getNbComponent();
 
   ElementTypeMap<UInt> res;
   for (ghost_type_t::iterator gt = ghost_type_t::begin();
        gt != ghost_type_t::end(); ++gt) {
 
     using type_iterator = typename InternalField<T>::type_iterator;
     type_iterator tit = internal_field.firstType(*gt);
     type_iterator tend = internal_field.lastType(*gt);
 
     for (; tit != tend; ++tit) {
       UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(*tit, *gt);
       res(*tit, *gt) = nb_data_per_quad * nb_quadrature_points;
     }
   }
   return res;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 void Material::flattenInternal(const std::string & field_id,
                                ElementTypeMapArray<T> & internal_flat,
                                const GhostType ghost_type,
                                ElementKind element_kind) const {
 
   if (!this->template isInternal<T>(field_id, element_kind))
     AKANTU_EXCEPTION("Cannot find internal field " << id << " in material "
                                                    << this->name);
 
   const InternalField<T> & internal_field =
       this->template getInternal<T>(field_id);
 
   const FEEngine & fe_engine = internal_field.getFEEngine();
   const Mesh & mesh = fe_engine.getMesh();
 
   using type_iterator = typename InternalField<T>::filter_type_iterator;
   type_iterator tit = internal_field.filterFirstType(ghost_type);
   type_iterator tend = internal_field.filterLastType(ghost_type);
 
   for (; tit != tend; ++tit) {
     ElementType type = *tit;
 
     const Array<Real> & src_vect = internal_field(type, ghost_type);
     const Array<UInt> & filter = internal_field.getFilter(type, ghost_type);
 
     // total number of elements in the corresponding mesh
     UInt nb_element_dst = mesh.getNbElement(type, ghost_type);
     // number of element in the internal field
     UInt nb_element_src = filter.size();
     // number of quadrature points per elem
     UInt nb_quad_per_elem = fe_engine.getNbIntegrationPoints(type);
     // number of data per quadrature point
     UInt nb_data_per_quad = internal_field.getNbComponent();
 
     if (!internal_flat.exists(type, ghost_type)) {
       internal_flat.alloc(nb_element_dst * nb_quad_per_elem, nb_data_per_quad,
                           type, ghost_type);
     }
 
     if (nb_element_src == 0)
       continue;
 
     // number of data per element
     UInt nb_data = nb_quad_per_elem * nb_data_per_quad;
 
     Array<Real> & dst_vect = internal_flat(type, ghost_type);
     dst_vect.resize(nb_element_dst * nb_quad_per_elem);
 
     Array<UInt>::const_scalar_iterator it = filter.begin();
     Array<UInt>::const_scalar_iterator end = filter.end();
 
     Array<Real>::const_vector_iterator it_src =
         src_vect.begin_reinterpret(nb_data, nb_element_src);
     Array<Real>::vector_iterator it_dst =
         dst_vect.begin_reinterpret(nb_data, nb_element_dst);
 
     for (; it != end; ++it, ++it_src) {
       it_dst[*it] = *it_src;
     }
   }
 }
 
 } // akantu
 
 #endif /* __AKANTU_MATERIAL_INLINE_IMPL_CC__ */
diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc
index e24a266cd..5f08a8369 100644
--- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc
+++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.cc
@@ -1,308 +1,266 @@
 /**
  * @file   material_elastic_linear_anisotropic.cc
  *
  * @author Till Junge <till.junge@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Sep 25 2013
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Anisotropic elastic material
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 #include "material_elastic_linear_anisotropic.hh"
 #include "solid_mechanics_model.hh"
 #include <algorithm>
 #include <sstream>
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 MaterialElasticLinearAnisotropic<dim>::MaterialElasticLinearAnisotropic(
     SolidMechanicsModel & model, const ID & id, bool symmetric)
     : Material(model, id), rot_mat(dim, dim), Cprime(dim * dim, dim * dim),
       C(voigt_h::size, voigt_h::size), eigC(voigt_h::size),
       symmetric(symmetric), alpha(0), was_stiffness_assembled(false) {
   AKANTU_DEBUG_IN();
 
   this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim));
   (*this->dir_vecs.back())[0] = 1.;
   this->registerParam("n1", *(this->dir_vecs.back()), _pat_parsmod,
                       "Direction of main material axis");
 
   if (dim > 1) {
     this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim));
     (*this->dir_vecs.back())[1] = 1.;
     this->registerParam("n2", *(this->dir_vecs.back()), _pat_parsmod,
                         "Direction of secondary material axis");
   }
 
   if (dim > 2) {
     this->dir_vecs.push_back(std::make_unique<Vector<Real>>(dim));
     (*this->dir_vecs.back())[2] = 1.;
     this->registerParam("n3", *(this->dir_vecs.back()), _pat_parsmod,
                         "Direction of tertiary material axis");
   }
 
   for (UInt i = 0; i < voigt_h::size; ++i) {
     UInt start = 0;
     if (this->symmetric) {
       start = i;
     }
     for (UInt j = start; j < voigt_h::size; ++j) {
       std::stringstream param("C");
       param << "C" << i + 1 << j + 1;
       this->registerParam(param.str(), this->Cprime(i, j), Real(0.),
                           _pat_parsmod, "Coefficient " + param.str());
     }
   }
 
   this->registerParam("alpha", this->alpha, _pat_parsmod,
                       "Proportion of viscous stress");
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim> void MaterialElasticLinearAnisotropic<dim>::initMaterial() {
   AKANTU_DEBUG_IN();
   Material::initMaterial();
 
   updateInternalParameters();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 void MaterialElasticLinearAnisotropic<dim>::updateInternalParameters() {
   Material::updateInternalParameters();
   if (this->symmetric) {
     for (UInt i = 0; i < voigt_h::size; ++i) {
       for (UInt j = i + 1; j < voigt_h::size; ++j) {
         this->Cprime(j, i) = this->Cprime(i, j);
       }
     }
   }
   this->rotateCprime();
   this->C.eig(this->eigC);
 
   this->was_stiffness_assembled = false;
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt Dim> void MaterialElasticLinearAnisotropic<Dim>::rotateCprime() {
   // start by filling the empty parts fo Cprime
   UInt diff = Dim * Dim - voigt_h::size;
   for (UInt i = voigt_h::size; i < Dim * Dim; ++i) {
     for (UInt j = 0; j < Dim * Dim; ++j) {
       this->Cprime(i, j) = this->Cprime(i - diff, j);
     }
   }
   for (UInt i = 0; i < Dim * Dim; ++i) {
     for (UInt j = voigt_h::size; j < Dim * Dim; ++j) {
       this->Cprime(i, j) = this->Cprime(i, j - diff);
     }
   }
   // construction of rotator tensor
   // normalise rotation matrix
   for (UInt j = 0; j < Dim; ++j) {
     Vector<Real> rot_vec = this->rot_mat(j);
     rot_vec = *this->dir_vecs[j];
     rot_vec.normalize();
   }
 
   // make sure the vectors form a right-handed base
   Vector<Real> test_axis(3);
   Vector<Real> v1(3), v2(3), v3(3);
 
   if (Dim == 2) {
     for (UInt i = 0; i < Dim; ++i) {
       v1[i] = this->rot_mat(0, i);
       v2[i] = this->rot_mat(1, i);
       v3[i] = 0.;
     }
     v3[2] = 1.;
     v1[2] = 0.;
     v2[2] = 0.;
   } else if (Dim == 3) {
     v1 = this->rot_mat(0);
     v2 = this->rot_mat(1);
     v3 = this->rot_mat(2);
   }
 
   test_axis.crossProduct(v1, v2);
   test_axis -= v3;
   if (test_axis.norm() > 8 * std::numeric_limits<Real>::epsilon()) {
     AKANTU_DEBUG_ERROR("The axis vectors do not form a right-handed coordinate "
                        << "system. I. e., ||n1 x n2 - n3|| should be zero, but "
                        << "it is " << test_axis.norm() << ".");
   }
 
   // create the rotator and the reverse rotator
   Matrix<Real> rotator(Dim * Dim, Dim * Dim);
   Matrix<Real> revrotor(Dim * Dim, Dim * Dim);
   for (UInt i = 0; i < Dim; ++i) {
     for (UInt j = 0; j < Dim; ++j) {
       for (UInt k = 0; k < Dim; ++k) {
         for (UInt l = 0; l < Dim; ++l) {
           UInt I = voigt_h::mat[i][j];
           UInt J = voigt_h::mat[k][l];
           rotator(I, J) = this->rot_mat(k, i) * this->rot_mat(l, j);
           revrotor(I, J) = this->rot_mat(i, k) * this->rot_mat(j, l);
         }
       }
     }
   }
 
   // create the full rotated matrix
   Matrix<Real> Cfull(Dim * Dim, Dim * Dim);
   Cfull = rotator * Cprime * revrotor;
 
   for (UInt i = 0; i < voigt_h::size; ++i) {
     for (UInt j = 0; j < voigt_h::size; ++j) {
       this->C(i, j) = Cfull(i, j);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
-void MaterialElasticLinearAnisotropic<dim>::computeStress(
-    ElementType el_type, GhostType ghost_type) {
+void MaterialElasticLinearAnisotropic<dim>::computeStress(ElementType el_type,
+                                                          GhostType ghost_type) {
   // Wikipedia convention:
   // 2*eps_ij (i!=j) = voigt_eps_I
   // http://en.wikipedia.org/wiki/Voigt_notation
   AKANTU_DEBUG_IN();
 
-  Array<Real>::iterator<Matrix<Real>> gradu_it =
-      this->gradu(el_type, ghost_type).begin(dim, dim);
-  Array<Real>::iterator<Matrix<Real>> gradu_end =
-      this->gradu(el_type, ghost_type).end(dim, dim);
-
-  UInt nb_quad_pts = gradu_end - gradu_it;
-
-  // create array for strains and stresses of all dof of all gauss points
-  // for efficient computation of stress
-  Matrix<Real> voigt_strains(voigt_h::size, nb_quad_pts);
-  Matrix<Real> voigt_stresses(voigt_h::size, nb_quad_pts);
-
-  // copy strains
   Matrix<Real> strain(dim, dim);
 
-  for (UInt q = 0; gradu_it != gradu_end; ++gradu_it, ++q) {
-    Matrix<Real> & grad_u = *gradu_it;
-
-    for (UInt I = 0; I < voigt_h::size; ++I) {
-      Real voigt_factor = voigt_h::factors[I];
-      UInt i = voigt_h::vec[I][0];
-      UInt j = voigt_h::vec[I][1];
-
-      voigt_strains(I, q) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.;
-    }
-  }
-
-  // compute the strain rate proportional part if needed
-  // bool viscous = this->alpha == 0.; // only works if default value
-  bool viscous = false;
-  if (viscous) {
-    Array<Real> strain_rate(0, dim * dim, "strain_rate");
-
-    Array<Real> & velocity = this->model.getVelocity();
-    const Array<UInt> & elem_filter = this->element_filter(el_type, ghost_type);
+  MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type);
 
-    this->fem.gradientOnIntegrationPoints(velocity, strain_rate, dim, el_type,
-                                          ghost_type, elem_filter);
+  this->computeStressOnQuad(strain,sigma);
 
-    Array<Real>::matrix_iterator gradu_dot_it = strain_rate.begin(dim, dim);
-    Array<Real>::matrix_iterator gradu_dot_end = strain_rate.end(dim, dim);
-
-    Matrix<Real> strain_dot(dim, dim);
-    for (UInt q = 0; gradu_dot_it != gradu_dot_end; ++gradu_dot_it, ++q) {
-      Matrix<Real> & grad_u_dot = *gradu_dot_it;
-
-      for (UInt I = 0; I < voigt_h::size; ++I) {
-        Real voigt_factor = voigt_h::factors[I];
-        UInt i = voigt_h::vec[I][0];
-        UInt j = voigt_h::vec[I][1];
-
-        voigt_strains(I, q) = this->alpha * voigt_factor *
-                              (grad_u_dot(i, j) + grad_u_dot(j, i)) / 2.;
-      }
-    }
-  }
+  MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END;
+}
 
-  // compute stresses
-  voigt_stresses = this->C * voigt_strains;
+/* -------------------------------------------------------------------------- */
+template <UInt dim>
+void MaterialElasticLinearAnisotropic<dim>::computeTangentModuli(
+    const ElementType & el_type, Array<Real> & tangent_matrix,
+    GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
 
-  // copy stresses back
-  Array<Real>::iterator<Matrix<Real>> stress_it =
-      this->stress(el_type, ghost_type).begin(dim, dim);
+  MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix);
 
-  Array<Real>::iterator<Matrix<Real>> stress_end =
-      this->stress(el_type, ghost_type).end(dim, dim);
+  this->computeTangentModuliOnQuad(tangent);
 
-  for (UInt q = 0; stress_it != stress_end; ++stress_it, ++q) {
-    Matrix<Real> & stress = *stress_it;
+  MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END;
 
-    for (UInt I = 0; I < voigt_h::size; ++I) {
-      UInt i = voigt_h::vec[I][0];
-      UInt j = voigt_h::vec[I][1];
-      stress(i, j) = stress(j, i) = voigt_stresses(I, q);
-    }
-  }
+  this->was_stiffness_assembled = true;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
-void MaterialElasticLinearAnisotropic<dim>::computeTangentModuli(
-    const ElementType & el_type, Array<Real> & tangent_matrix,
-    GhostType ghost_type) {
+void MaterialElasticLinearAnisotropic<dim>::computePotentialEnergy(
+    ElementType el_type, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
-  MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix);
-  tangent.copy(this->C);
-  MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END;
+  Material::computePotentialEnergy(el_type, ghost_type);
 
-  this->was_stiffness_assembled = true;
+  AKANTU_DEBUG_ASSERT(!this->finite_deformation,
+                      "finite deformation not possible in material anisotropic "
+                      "(TO BE IMPLEMENTED)");
+
+  if (ghost_type != _not_ghost)
+    return;
+  Array<Real>::scalar_iterator epot =
+    this->potential_energy(el_type, ghost_type).begin();
+
+  MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type);
+
+  computePotentialEnergyOnQuad(grad_u, sigma, *epot);
+  ++epot;
+
+  MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim>
 Real MaterialElasticLinearAnisotropic<dim>::getCelerity(
     __attribute__((unused)) const Element & element) const {
   return std::sqrt(this->eigC(0) / rho);
 }
 
 /* -------------------------------------------------------------------------- */
 
 INSTANTIATE_MATERIAL(elastic_anisotropic, MaterialElasticLinearAnisotropic);
 
 } // akantu
diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh
index dec6765fd..2cfa119bb 100644
--- a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh
+++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic.hh
@@ -1,122 +1,139 @@
 /**
  * @file   material_elastic_linear_anisotropic.hh
  *
  * @author Till Junge <till.junge@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Tue Aug 18 2015
  *
  * @brief  Orthotropic elastic material
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "material.hh"
 #include "material_elastic.hh"
 /* -------------------------------------------------------------------------- */
 #include <vector>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__
 #define __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__
 
 namespace akantu {
 
 /**
  * General linear anisotropic elastic material
  * The only constraint on the elastic tensor is that it can be represented
  * as a symmetric 6x6 matrix (3D) or 3x3 (2D).
  *
  * parameters in the material files :
  *   - rho  : density (default: 0)
  *   - C_ij  : entry on the stiffness
  */
 template <UInt Dim> class MaterialElasticLinearAnisotropic : public Material {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   MaterialElasticLinearAnisotropic(SolidMechanicsModel & model,
                                    const ID & id = "", bool symmetric = true);
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   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(const ElementType & el_type,
                             Array<Real> & tangent_matrix,
                             GhostType ghost_type = _not_ghost) override;
 
+  /// compute the elastic potential energy
+  void computePotentialEnergy(ElementType el_type,
+                              GhostType ghost_type = _not_ghost) override;
+
   void updateInternalParameters() override;
 
   bool hasStiffnessMatrixChanged() override {
     return (!was_stiffness_assembled);
   }
 
 protected:
   // compute C from Cprime
   void rotateCprime();
 
+  /// constitutive law for a given quadrature point
+  inline void computeStressOnQuad(const Matrix<Real> & grad_u,
+                                  Matrix<Real> & sigma) const;
+
+  /// tangent matrix for a given quadrature point
+  inline void computeTangentModuliOnQuad(Matrix<Real> & tangent) const;
+
+  inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u,
+                                           const Matrix<Real> & sigma,
+                                           Real & epot);
+
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// compute max wave celerity
   Real getCelerity(const Element & element) const override;
 
   AKANTU_GET_MACRO(VoigtStiffness, C, Matrix<Real>);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   using voigt_h = VoigtHelper<Dim>;
 
   /// direction matrix and vectors
   std::vector<std::unique_ptr<Vector<Real>>> dir_vecs;
 
   Matrix<Real> rot_mat;
   /// Elastic stiffness tensor in material frame and full vectorised notation
   Matrix<Real> Cprime;
   /// Elastic stiffness tensor in voigt notation
   Matrix<Real> C;
   /// eigenvalues of stiffness tensor
   Vector<Real> eigC;
 
   bool symmetric;
 
   /// viscous proportion
   Real alpha;
 
   /// defines if the stiffness was computed
   bool was_stiffness_assembled;
 };
 } // akantu
 
+#include "material_elastic_linear_anisotropic_inline_impl.cc"
+
 #endif /* __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_HH__ */
diff --git a/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc
new file mode 100644
index 000000000..900b8d5ae
--- /dev/null
+++ b/src/model/solid_mechanics/materials/material_elastic_linear_anisotropic_inline_impl.cc
@@ -0,0 +1,96 @@
+/**
+ * @file   material_elastic_linear_anisotropic_inline_impl.cc
+ *
+ * @author Enrico Milanese <enrico.milanese@epfl.ch>
+ * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ *
+ * @date creation: Mon Feb 12 2018
+ * @date last modification: Mon Feb 12 2018
+ *
+ * @brief Implementation of the inline functions of the material elastic linear
+ * anisotropic
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
+ * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
+ * Solides)
+ *
+ * Akantu is free  software: you can redistribute it and/or  modify it under the
+ * terms  of the  GNU Lesser  General Public  License as  published by  the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
+ * details.
+ *
+ * You should  have received  a copy  of the GNU  Lesser General  Public License
+ * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* -------------------------------------------------------------------------- */
+#include "material_elastic_linear_anisotropic.hh"
+/* -------------------------------------------------------------------------- */
+
+#ifndef __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__
+#define __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+template <UInt dim>
+inline void MaterialElasticLinearAnisotropic<dim>::computeStressOnQuad(const Matrix<Real> & grad_u,
+                                                                       Matrix<Real> & sigma) const {
+  // Wikipedia convention:
+  // 2*eps_ij (i!=j) = voigt_eps_I
+  // http://en.wikipedia.org/wiki/Voigt_notation
+  Vector<Real> voigt_strain(voigt_h::size);
+  Vector<Real> voigt_stress(voigt_h::size);
+
+  for (UInt I = 0; I < voigt_h::size; ++I){
+    Real voigt_factor = voigt_h::factors[I];
+    UInt i = voigt_h::vec[I][0];
+    UInt j = voigt_h::vec[I][1];
+
+    voigt_strain(I) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.;
+
+  }
+
+  voigt_stress = this->C * voigt_strain;
+
+  for (UInt I = 0; I < voigt_h::size; ++I){
+    UInt i = voigt_h::vec[I][0];
+    UInt j = voigt_h::vec[I][1];
+
+    sigma(i, j) = sigma(j, i) = voigt_stress(I);
+
+  }
+
+}
+
+/* -------------------------------------------------------------------------- */
+template <UInt dim>
+inline void MaterialElasticLinearAnisotropic<dim>::computeTangentModuliOnQuad(Matrix<Real> & tangent) const {
+
+  tangent.copy(this->C);
+
+}
+
+/* -------------------------------------------------------------------------- */
+template <UInt dim>
+inline void MaterialElasticLinearAnisotropic<dim>::computePotentialEnergyOnQuad(
+    const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot) {
+
+  AKANTU_DEBUG_ASSERT(this->symmetric,
+                      "The elastic constants matrix is not symmetric,"
+                      "energy is not path independent.");
+
+  epot = .5 * sigma.doubleDot(grad_u);
+}
+
+} // akantu
+
+#endif /* __AKANTU_MATERIAL_ELASTIC_LINEAR_ANISOTROPIC_INLINE_IMPL_CC__ */
diff --git a/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc b/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc
index 22815792a..331a25fbe 100644
--- a/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc
+++ b/src/model/solid_mechanics/materials/material_elastic_orthotropic.cc
@@ -1,212 +1,168 @@
 /**
  * @file   material_elastic_orthotropic.cc
  *
  * @author Till Junge <till.junge@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Orthotropic elastic material
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 #include "material_elastic_orthotropic.hh"
 #include "solid_mechanics_model.hh"
 #include <algorithm>
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <UInt Dim>
 MaterialElasticOrthotropic<Dim>::MaterialElasticOrthotropic(
     SolidMechanicsModel & model, const ID & id)
     : MaterialElasticLinearAnisotropic<Dim>(model, id) {
   AKANTU_DEBUG_IN();
   this->registerParam("E1", E1, Real(0.), _pat_parsmod, "Young's modulus (n1)");
   this->registerParam("E2", E2, Real(0.), _pat_parsmod, "Young's modulus (n2)");
   this->registerParam("nu12", nu12, Real(0.), _pat_parsmod,
                       "Poisson's ratio (12)");
   this->registerParam("G12", G12, Real(0.), _pat_parsmod, "Shear modulus (12)");
 
   if (Dim > 2) {
     this->registerParam("E3", E3, Real(0.), _pat_parsmod,
                         "Young's modulus (n3)");
     this->registerParam("nu13", nu13, Real(0.), _pat_parsmod,
                         "Poisson's ratio (13)");
     this->registerParam("nu23", nu23, Real(0.), _pat_parsmod,
                         "Poisson's ratio (23)");
     this->registerParam("G13", G13, Real(0.), _pat_parsmod,
                         "Shear modulus (13)");
     this->registerParam("G23", G23, Real(0.), _pat_parsmod,
                         "Shear modulus (23)");
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt Dim> void MaterialElasticOrthotropic<Dim>::initMaterial() {
   AKANTU_DEBUG_IN();
   Material::initMaterial();
 
   updateInternalParameters();
 
   AKANTU_DEBUG_OUT();
 }
 
-/* -------------------------------------------------------------------------- */
-inline Real vector_norm(Vector<Real> & vec) {
-  Real norm = 0;
-  for (UInt i = 0; i < vec.size(); ++i) {
-    norm += vec(i) * vec(i);
-  }
-  return std::sqrt(norm);
-}
-
 /* -------------------------------------------------------------------------- */
 template <UInt Dim>
 void MaterialElasticOrthotropic<Dim>::updateInternalParameters() {
   /* 1) construction of temporary material frame stiffness tensor------------ */
   // http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
   Real nu21 = nu12 * E2 / E1;
   Real nu31 = nu13 * E3 / E1;
   Real nu32 = nu23 * E3 / E2;
 
   // Full (i.e. dim^2 by dim^2) stiffness tensor in material frame
   if (Dim == 1) {
     AKANTU_DEBUG_ERROR("Dimensions 1 not implemented: makes no sense to have "
                        "orthotropy for 1D");
   }
 
   Real Gamma;
 
   if (Dim == 3)
     Gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 -
                  2 * nu21 * nu32 * nu13);
 
   if (Dim == 2)
     Gamma = 1 / (1 - nu12 * nu21);
 
   // Lamé's first parameters
   this->Cprime(0, 0) = E1 * (1 - nu23 * nu32) * Gamma;
   this->Cprime(1, 1) = E2 * (1 - nu13 * nu31) * Gamma;
   if (Dim == 3)
     this->Cprime(2, 2) = E3 * (1 - nu12 * nu21) * Gamma;
 
   // normalised poisson's ratio's
   this->Cprime(1, 0) = this->Cprime(0, 1) = E1 * (nu21 + nu31 * nu23) * Gamma;
   if (Dim == 3) {
     this->Cprime(2, 0) = this->Cprime(0, 2) = E1 * (nu31 + nu21 * nu32) * Gamma;
     this->Cprime(2, 1) = this->Cprime(1, 2) = E2 * (nu32 + nu12 * nu31) * Gamma;
   }
 
   // Lamé's second parameters (shear moduli)
   if (Dim == 3) {
     this->Cprime(3, 3) = G23;
     this->Cprime(4, 4) = G13;
     this->Cprime(5, 5) = G12;
   } else
     this->Cprime(2, 2) = G12;
 
   /* 1) rotation of C into the global frame */
   this->rotateCprime();
   this->C.eig(this->eigC);
 }
 
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim>
-inline void MaterialElasticOrthotropic<dim>::computePotentialEnergyOnQuad(
-    const Matrix<Real> & grad_u, const Matrix<Real> & sigma, Real & epot) {
-  epot = .5 * sigma.doubleDot(grad_u);
-}
-
-/* -------------------------------------------------------------------------- */
-template <UInt spatial_dimension>
-void MaterialElasticOrthotropic<spatial_dimension>::computePotentialEnergy(
-    ElementType el_type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Material::computePotentialEnergy(el_type, ghost_type);
-
-  AKANTU_DEBUG_ASSERT(!this->finite_deformation,
-                      "finite deformation not possible in material orthotropic "
-                      "(TO BE IMPLEMENTED)");
-
-  if (ghost_type != _not_ghost)
-    return;
-  Array<Real>::scalar_iterator epot =
-      this->potential_energy(el_type, ghost_type).begin();
-
-  MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type);
-
-  computePotentialEnergyOnQuad(grad_u, sigma, *epot);
-  ++epot;
-
-  MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END;
-
-  AKANTU_DEBUG_OUT();
-}
-
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialElasticOrthotropic<spatial_dimension>::
     computePotentialEnergyByElement(ElementType type, UInt index,
                                     Vector<Real> & epot_on_quad_points) {
 
   AKANTU_DEBUG_ASSERT(!this->finite_deformation,
                       "finite deformation not possible in material orthotropic "
                       "(TO BE IMPLEMENTED)");
 
   Array<Real>::matrix_iterator gradu_it =
       this->gradu(type).begin(spatial_dimension, spatial_dimension);
   Array<Real>::matrix_iterator gradu_end =
       this->gradu(type).begin(spatial_dimension, spatial_dimension);
   Array<Real>::matrix_iterator stress_it =
       this->stress(type).begin(spatial_dimension, spatial_dimension);
 
   UInt nb_quadrature_points = this->fem.getNbIntegrationPoints(type);
 
   gradu_it += index * nb_quadrature_points;
   gradu_end += (index + 1) * nb_quadrature_points;
   stress_it += index * nb_quadrature_points;
 
   Real * epot_quad = epot_on_quad_points.storage();
 
   Matrix<Real> grad_u(spatial_dimension, spatial_dimension);
 
   for (; gradu_it != gradu_end; ++gradu_it, ++stress_it, ++epot_quad) {
     grad_u.copy(*gradu_it);
 
-    computePotentialEnergyOnQuad(grad_u, *stress_it, *epot_quad);
+    this->computePotentialEnergyOnQuad(grad_u, *stress_it, *epot_quad);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 INSTANTIATE_MATERIAL(elastic_orthotropic, MaterialElasticOrthotropic);
 
 } // akantu
diff --git a/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh b/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh
index f5bad0fe2..60110342c 100644
--- a/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh
+++ b/src/model/solid_mechanics/materials/material_elastic_orthotropic.hh
@@ -1,145 +1,136 @@
 /**
  * @file   material_elastic_orthotropic.hh
  *
  * @author Till Junge <till.junge@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Orthotropic elastic material
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "material_elastic_linear_anisotropic.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__
 #define __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__
 
 namespace akantu {
 
 /**
  * Orthotropic elastic material
  *
  * parameters in the material files :
  *   - n1   : direction of x-axis in material base, normalisation not necessary
  * (default: {1, 0, 0})
  *   - n2   : direction of y-axis in material base, normalisation not necessary
  * (default: {0, 1, 0})
  *   - n3   : direction of z-axis in material base, normalisation not necessary
  * (default: {0, 0, 1})
  *   - rho  : density (default: 0)
  *   - E1   : Young's modulus along n1 (default: 0)
  *   - E2   : Young's modulus along n2 (default: 0)
  *   - E3   : Young's modulus along n3 (default: 0)
  *   - nu12 : Poisson's ratio along 12 (default: 0)
  *   - nu13 : Poisson's ratio along 13 (default: 0)
  *   - nu23 : Poisson's ratio along 23 (default: 0)
  *   - G12  : Shear modulus along 12 (default: 0)
  *   - G13  : Shear modulus along 13 (default: 0)
  *   - G23  : Shear modulus along 23 (default: 0)
  */
 
 template <UInt Dim>
 class MaterialElasticOrthotropic
     : public MaterialElasticLinearAnisotropic<Dim> {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   MaterialElasticOrthotropic(SolidMechanicsModel & model, const ID & id = "");
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   void initMaterial() override;
 
   void updateInternalParameters() override;
 
-  /// compute the elastic potential energy
-  void computePotentialEnergy(ElementType el_type,
-                              GhostType ghost_type = _not_ghost) override;
-
   void
   computePotentialEnergyByElement(ElementType type, UInt index,
                                   Vector<Real> & epot_on_quad_points) override;
 
-protected:
-  inline void computePotentialEnergyOnQuad(const Matrix<Real> & grad_u,
-                                           const Matrix<Real> & sigma,
-                                           Real & epot);
-
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   AKANTU_GET_MACRO(E1, E1, Real);
   AKANTU_GET_MACRO(E2, E2, Real);
   AKANTU_GET_MACRO(E3, E3, Real);
   AKANTU_GET_MACRO(Nu12, nu12, Real);
   AKANTU_GET_MACRO(Nu13, nu13, Real);
   AKANTU_GET_MACRO(Nu23, nu23, Real);
   AKANTU_GET_MACRO(G12, G12, Real);
   AKANTU_GET_MACRO(G13, G13, Real);
   AKANTU_GET_MACRO(G23, G23, Real);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// the n1 young modulus
   Real E1;
 
   /// the n2 young modulus
   Real E2;
 
   /// the n3 young modulus
   Real E3;
 
   /// 12 Poisson coefficient
   Real nu12;
 
   /// 13 Poisson coefficient
   Real nu13;
 
   /// 23 Poisson coefficient
   Real nu23;
 
   /// 12 shear modulus
   Real G12;
 
   /// 13 shear modulus
   Real G13;
 
   /// 23 shear modulus
   Real G23;
 };
 
 } // akantu
 
 #endif /* __AKANTU_MATERIAL_ELASTIC_ORTHOTROPIC_HH__ */
diff --git a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh b/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh
deleted file mode 100644
index 9c8ad1ea4..000000000
--- a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * @file   embedded_internal_field.hh
- *
- * @author Lucas Frerot <lucas.frerot@epfl.ch>
- *
- * @date creation: Fri Jun 18 2010
- * @date last modification: Tue Jun 30 2015
- *
- * @brief  Embedded Material internal properties
- *
- * @section LICENSE
- *
- * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
- * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
- * Solides)
- *
- * Akantu is free  software: you can redistribute it and/or  modify it under the
- * terms  of the  GNU Lesser  General Public  License as  published by  the Free
- * Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
- * details.
- *
- * You should  have received  a copy  of the GNU  Lesser General  Public License
- * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* -------------------------------------------------------------------------- */
-#include "aka_common.hh"
-#include "internal_field.hh"
-/* -------------------------------------------------------------------------- */
-
-#ifndef __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__
-#define __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__
-
-namespace akantu {
-
-class Material;
-class FEEngine;
-
-/// This class is used for MaterialReinforcement internal fields
-template<typename T>
-class EmbeddedInternalField : public InternalField<T> {
-  /* ------------------------------------------------------------------------ */
-  /* Constructors/Destructors                                                 */
-  /* ------------------------------------------------------------------------ */
-public:
-  /// Constructor
-  EmbeddedInternalField(const ID & id, Material & material):
-    InternalField<T>(id,
-                     material,
-                     material.getModel().getFEEngine("EmbeddedInterfaceFEEngine"),
-                     material.getElementFilter()) {
-    this->spatial_dimension = 1;
-  }
-
-  /// Copy constructor
-  EmbeddedInternalField(const ID & id, const EmbeddedInternalField & other):
-    InternalField<T>(id, other) {
-    this->spatial_dimension = 1;
-  }
-
-  void operator=(const EmbeddedInternalField & other) {
-    InternalField<T>::operator=(other);
-    this->spatial_dimension = 1;
-  }
-};
-
-/// Method used to initialise the embedded internal fields from material file
-template <>
-inline void ParameterTyped<EmbeddedInternalField<Real>>::setAuto(
-    const ParserParameter & in_param) {
-  Parameter::setAuto(in_param);
-  Real r = in_param;
-  param.setDefaultValue(r);
-}
-
-} // akantu
-
-#endif // __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh b/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh
index d00d9f035..3c04d7b6b 100644
--- a/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh
+++ b/src/model/solid_mechanics/materials/material_embedded/material_embedded_includes.hh
@@ -1,43 +1,41 @@
 /**
  * @file   material_embedded_includes.hh
  *
  * @author Lucas Frerot <lucas.frerot@epfl.ch>
  *
  * @date creation: Fri Jan 04 2013
  * @date last modification: Fri May 29 2015
  *
  * @brief  List of includes for embedded elements
  *
  * @section LICENSE
  *
  * Copyright  (©)  2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #ifndef AKANTU_CMAKE_LIST_MATERIALS
 #  include "material_reinforcement.hh"
-#  include "material_reinforcement_template.hh"
 #endif
 
 #define AKANTU_MATERIAL_REINFORCEMENT_LAW_TMPL_LIST       \
   ((elastic, (MaterialElastic<1>)))                       \
   ((plastic, (MaterialLinearIsotropicHardening<1>)))
 
 #define AKANTU_EMBEDDED_MATERIAL_LIST                     \
-  ((3, (reinforcement, MaterialReinforcementTemplate,     \
-        AKANTU_MATERIAL_REINFORCEMENT_LAW_TMPL_LIST )))
+  ((2, (reinforcement, MaterialReinforcement)))
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc
deleted file mode 100644
index def0887e8..000000000
--- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc
+++ /dev/null
@@ -1,766 +0,0 @@
-/**
- * @file   material_reinforcement.cc
- *
- * @author Lucas Frerot <lucas.frerot@epfl.ch>
- *
- * @date creation: Wed Mar 25 2015
- * @date last modification: Tue Dec 08 2015
- *
- * @brief  Reinforcement material
- *
- * @section LICENSE
- *
- * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
- * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
- *
- * Akantu is free  software: you can redistribute it and/or  modify it under the
- * terms  of the  GNU Lesser  General Public  License as  published by  the Free
- * Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
- * details.
- *
- * You should  have received  a copy  of the GNU  Lesser General  Public License
- * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* -------------------------------------------------------------------------- */
-
-#include "aka_common.hh"
-#include "aka_voigthelper.hh"
-#include "material_reinforcement.hh"
-
-namespace akantu {
-
-/* -------------------------------------------------------------------------- */
-template <UInt dim>
-MaterialReinforcement<dim>::MaterialReinforcement(SolidMechanicsModel & model,
-                                                  UInt /*spatial_dimension*/,
-                                                  const Mesh & mesh,
-                                                  FEEngine & fe_engine,
-                                                  const ID & id)
-    : Material(model, dim, mesh, fe_engine,
-               id), // /!\ dim, not spatial_dimension !
-      model(NULL),
-      stress_embedded("stress_embedded", *this, 1, fe_engine,
-                      this->element_filter),
-      gradu_embedded("gradu_embedded", *this, 1, fe_engine,
-                     this->element_filter),
-      directing_cosines("directing_cosines", *this, 1, fe_engine,
-                        this->element_filter),
-      pre_stress("pre_stress", *this, 1, fe_engine, this->element_filter),
-      area(1.0), shape_derivatives() {
-  AKANTU_DEBUG_IN();
-  this->initialize(model);
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-template <UInt dim>
-void MaterialReinforcement<dim>::initialize(SolidMechanicsModel & a_model) {
-  AKANTU_DEBUG_IN();
-  this->model = dynamic_cast<EmbeddedInterfaceModel *>(&a_model);
-  AKANTU_DEBUG_ASSERT(this->model != NULL,
-                      "MaterialReinforcement needs an EmbeddedInterfaceModel");
-
-  this->registerParam("area", area, _pat_parsable | _pat_modifiable,
-                      "Reinforcement cross-sectional area");
-  this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable,
-                      "Uniform pre-stress");
-
-  this->unregisterInternal(this->stress);
-
-  // Fool the AvgHomogenizingFunctor
-  // stress.initialize(dim * dim);
-
-  // Reallocate the element filter
-  this->element_filter.initialize(this->model->getInterfaceMesh(),
-				  _spatial_dimension = 1);
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim> MaterialReinforcement<dim>::~MaterialReinforcement() {
-  AKANTU_DEBUG_IN();
-
-  ElementTypeMap<ElementTypeMapArray<Real> *>::type_iterator
-    it = shape_derivatives.firstType(),
-    end = shape_derivatives.lastType();
-
-  for (; it != end; ++it) {
-    delete shape_derivatives(*it, _not_ghost);
-    delete shape_derivatives(*it, _ghost);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim> void MaterialReinforcement<dim>::initMaterial() {
-  Material::initMaterial();
-
-  stress_embedded.initialize(dim * dim);
-  gradu_embedded.initialize(dim * dim);
-  pre_stress.initialize(1);
-
-  /// We initialise the stuff that is not going to change during the simulation
-  this->allocBackgroundShapeDerivatives();
-  this->initBackgroundShapeDerivatives();
-  this->initDirectingCosines();
-}
-
-/* -------------------------------------------------------------------------- */
-
-/**
- * Background shape derivatives need to be stored per background element
- * types but also per embedded element type, which is why they are stored
- * in an ElementTypeMap<ElementTypeMapArray<Real> *>. The outer ElementTypeMap
- * refers to the embedded types, and the inner refers to the background types.
- */
-template <UInt dim>
-void MaterialReinforcement<dim>::allocBackgroundShapeDerivatives() {
-  AKANTU_DEBUG_IN();
-
-  Mesh & interface_mesh = model->getInterfaceMesh();
-  Mesh & mesh = model->getMesh();
-
-  ghost_type_t::iterator int_ghost_it = ghost_type_t::begin();
-
-  // Loop over interface ghosts
-  for (; int_ghost_it != ghost_type_t::end(); ++int_ghost_it) {
-    Mesh::type_iterator interface_type_it =
-        interface_mesh.firstType(1, *int_ghost_it);
-    Mesh::type_iterator interface_type_end =
-        interface_mesh.lastType(1, *int_ghost_it);
-
-    // Loop over interface types
-    for (; interface_type_it != interface_type_end; ++interface_type_it) {
-      Mesh::type_iterator background_type_it =
-          mesh.firstType(dim, *int_ghost_it);
-      Mesh::type_iterator background_type_end =
-          mesh.lastType(dim, *int_ghost_it);
-
-      // Loop over background types
-      for (; background_type_it != background_type_end ; ++background_type_it) {
-        const ElementType & int_type = *interface_type_it;
-        const ElementType & back_type = *background_type_it;
-        const GhostType & int_ghost = *int_ghost_it;
-
-        std::string shaped_id = "embedded_shape_derivatives";
-
-        if (int_ghost == _ghost) shaped_id += ":ghost";
-
-        ElementTypeMapArray<Real> * shaped_etma = new ElementTypeMapArray<Real>(shaped_id, this->name);
-
-        UInt nb_points = Mesh::getNbNodesPerElement(back_type);
-        UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbIntegrationPoints(int_type);
-        UInt nb_elements = element_filter(int_type, int_ghost).size();
-
-        // Alloc the background ElementTypeMapArray
-        shaped_etma->alloc(nb_elements * nb_quad_points,
-                           dim * nb_points,
-                           back_type);
-
-        // Insert the background ElementTypeMapArray in the interface
-        // ElementTypeMap
-        shape_derivatives(shaped_etma, int_type, int_ghost);
-      }
-    }
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim>
-void MaterialReinforcement<dim>::initBackgroundShapeDerivatives() {
-  AKANTU_DEBUG_IN();
-
-  Mesh & mesh = model->getMesh();
-
-  Mesh::type_iterator type_it = mesh.firstType(dim, _not_ghost);
-  Mesh::type_iterator type_end = mesh.lastType(dim, _not_ghost);
-
-  for (; type_it != type_end; ++type_it) {
-    computeBackgroundShapeDerivatives(*type_it, _not_ghost);
-    // computeBackgroundShapeDerivatives(*type_it, _ghost);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim> void MaterialReinforcement<dim>::initDirectingCosines() {
-  AKANTU_DEBUG_IN();
-
-  Mesh & mesh = model->getInterfaceMesh();
-
-  Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost);
-  Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost);
-
-  const UInt voigt_size = getTangentStiffnessVoigtSize(dim);
-  directing_cosines.initialize(voigt_size * voigt_size);
-
-  for (; type_it != type_end; ++type_it) {
-    computeDirectingCosines(*type_it, _not_ghost);
-    // computeDirectingCosines(*type_it, _ghost);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim>
-void MaterialReinforcement<dim>::assembleStiffnessMatrix(GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Mesh & interface_mesh = model->getInterfaceMesh();
-
-  Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost);
-  Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost);
-
-  for (; type_it != type_end; ++type_it) {
-    assembleStiffnessMatrix(*type_it, ghost_type);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim>
-void MaterialReinforcement<dim>::assembleInternalForces(GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Mesh & interface_mesh = model->getInterfaceMesh();
-
-  Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost);
-  Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost);
-
-  for (; type_it != type_end; ++type_it) {
-    this->assembleInternalForces(*type_it, ghost_type);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-template <UInt dim>
-void MaterialReinforcement<dim>::computeGradU(const ElementType & type,
-                                              GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Array<UInt> & elem_filter = element_filter(type, ghost_type);
-  UInt nb_element = elem_filter.size();
-  UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine")
-                            .getNbIntegrationPoints(type);
-
-  Array<Real> & gradu_vec = gradu_embedded(type, ghost_type);
-
-  Mesh::type_iterator back_it = model->getMesh().firstType(dim, ghost_type);
-  Mesh::type_iterator back_end = model->getMesh().lastType(dim, ghost_type);
-
-  for (; back_it != back_end; ++back_it) {
-    UInt nodes_per_background_e = Mesh::getNbNodesPerElement(*back_it);
-
-    Array<Real> & shapesd =
-        shape_derivatives(type, ghost_type)->operator()(*back_it, ghost_type);
-
-    Array<UInt> * background_filter =
-        new Array<UInt>(nb_element, 1, "background_filter");
-    filterInterfaceBackgroundElements(*background_filter, *back_it, type,
-                                      ghost_type);
-
-    Array<Real> * disp_per_element = new Array<Real>(0, dim * nodes_per_background_e, "disp_elem");
-    FEEngine::extractNodalToElementField(model->getMesh(),
-                                         model->getDisplacement(),
-                                         *disp_per_element,
-                                         *back_it, ghost_type, *background_filter);
-
-    Array<Real>::matrix_iterator disp_it =
-        disp_per_element->begin(dim, nodes_per_background_e);
-    Array<Real>::matrix_iterator disp_end =
-        disp_per_element->end(dim, nodes_per_background_e);
-
-    Array<Real>::matrix_iterator shapes_it =
-        shapesd.begin(dim, nodes_per_background_e);
-    Array<Real>::matrix_iterator grad_u_it = gradu_vec.begin(dim, dim);
-
-    for (; disp_it != disp_end; ++disp_it) {
-      for (UInt i = 0; i < nb_quad_points; i++, ++shapes_it, ++grad_u_it) {
-        Matrix<Real> & B = *shapes_it;
-        Matrix<Real> & du = *grad_u_it;
-        Matrix<Real> & u = *disp_it;
-
-        du.mul<false, true>(u, B);
-      }
-    }
-
-    delete background_filter;
-    delete disp_per_element;
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-template <UInt dim>
-void MaterialReinforcement<dim>::computeAllStresses(GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Mesh::type_iterator it = model->getInterfaceMesh().firstType();
-  Mesh::type_iterator last_type = model->getInterfaceMesh().lastType();
-
-  for (; it != last_type; ++it) {
-    computeGradU(*it, ghost_type);
-    computeStress(*it, ghost_type);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-template <UInt dim>
-void MaterialReinforcement<dim>::assembleInternalForces(
-    const ElementType & type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Mesh & mesh = model->getMesh();
-
-  Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type);
-  Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type);
-
-  for (; type_it != type_end; ++type_it) {
-    assembleInternalForcesInterface(type, *type_it, ghost_type);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-/**
- * Computes and assemble the residual. Residual in reinforcement is computed as:
- *
- * \f[
- * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s}
- * \f]
- */
-template <UInt dim>
-void MaterialReinforcement<dim>::assembleInternalForcesInterface(
-    const ElementType & interface_type, const ElementType & background_type,
-    GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  UInt voigt_size = getTangentStiffnessVoigtSize(dim);
-
-  FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine");
-
-  Array<UInt> & elem_filter = element_filter(interface_type, ghost_type);
-
-  UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type);
-  UInt nb_quadrature_points =
-      interface_engine.getNbIntegrationPoints(interface_type, ghost_type);
-  UInt nb_element = elem_filter.size();
-
-  UInt back_dof = dim * nodes_per_background_e;
-
-  Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))(
-      background_type, ghost_type);
-
-  Array<Real> integrant(nb_quadrature_points * nb_element, back_dof,
-                        "integrant");
-
-  Array<Real>::vector_iterator integrant_it = integrant.begin(back_dof);
-  Array<Real>::vector_iterator integrant_end = integrant.end(back_dof);
-
-  Array<Real>::matrix_iterator B_it =
-      shapesd.begin(dim, nodes_per_background_e);
-  Array<Real>::matrix_iterator C_it =
-      directing_cosines(interface_type, ghost_type)
-          .begin(voigt_size, voigt_size);
-  Array<Real>::matrix_iterator sigma_it =
-      stress_embedded(interface_type, ghost_type).begin(dim, dim);
-
-  Vector<Real> sigma(voigt_size);
-  Matrix<Real> Bvoigt(voigt_size, back_dof);
-  Vector<Real> Ct_sigma(voigt_size);
-
-  for (; integrant_it != integrant_end ; ++integrant_it,
-         ++B_it,
-         ++C_it,
-         ++sigma_it) {
-    VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, nodes_per_background_e);
-    Matrix<Real> & C = *C_it;
-    Vector<Real> & BtCt_sigma = *integrant_it;
-
-    stressTensorToVoigtVector(*sigma_it, sigma);
-
-    Ct_sigma.mul<true>(C, sigma);
-    BtCt_sigma.mul<true>(Bvoigt, Ct_sigma);
-    BtCt_sigma *= area;
-  }
-
-  Array<Real> residual_interface(nb_element, back_dof, "residual_interface");
-  interface_engine.integrate(integrant, residual_interface, back_dof,
-                             interface_type, ghost_type, elem_filter);
-  integrant.resize(0);
-
-  Array<UInt> background_filter(nb_element, 1, "background_filter");
-
-  filterInterfaceBackgroundElements(background_filter, background_type,
-                                    interface_type, ghost_type);
-
-  model->getDOFManager().assembleElementalArrayLocalArray(
-      residual_interface, model->getInternalForce(), background_type, ghost_type, -1.,
-      background_filter);
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-template <UInt dim>
-void MaterialReinforcement<dim>::filterInterfaceBackgroundElements(
-    Array<UInt> & filter, const ElementType & type,
-    const ElementType & interface_type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  filter.resize(0);
-  filter.clear();
-
-  Array<Element> & elements =
-      model->getInterfaceAssociatedElements(interface_type, ghost_type);
-  Array<UInt> & elem_filter = element_filter(interface_type, ghost_type);
-
-  Array<UInt>::scalar_iterator filter_it = elem_filter.begin(),
-                               filter_end = elem_filter.end();
-
-  for (; filter_it != filter_end; ++filter_it) {
-    Element & elem = elements(*filter_it);
-    if (elem.type == type)
-      filter.push_back(elem.element);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim>
-void MaterialReinforcement<dim>::computeDirectingCosines(
-    const ElementType & type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Mesh & interface_mesh = this->model->getInterfaceMesh();
-
-  const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
-  const UInt steel_dof = dim * nb_nodes_per_element;
-  const UInt voigt_size = getTangentStiffnessVoigtSize(dim);
-  const UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine")
-                                  .getNbIntegrationPoints(type, ghost_type);
-
-  Array<Real> node_coordinates(this->element_filter(type, ghost_type).size(),
-                               steel_dof);
-
-  this->model->getFEEngine().template extractNodalToElementField<Real>(interface_mesh,
-                                                                       interface_mesh.getNodes(),
-                                                                       node_coordinates,
-                                                                       type,
-                                                                       ghost_type,
-                                                                       this->element_filter(type, ghost_type));
-
-  Array<Real>::matrix_iterator directing_cosines_it =
-      directing_cosines(type, ghost_type).begin(voigt_size, voigt_size);
-
-  Array<Real>::matrix_iterator node_coordinates_it =
-      node_coordinates.begin(dim, nb_nodes_per_element);
-  Array<Real>::matrix_iterator node_coordinates_end =
-      node_coordinates.end(dim, nb_nodes_per_element);
-
-  for (; node_coordinates_it != node_coordinates_end; ++node_coordinates_it) {
-    for (UInt i = 0; i < nb_quad_points; i++, ++directing_cosines_it) {
-      Matrix<Real> & nodes = *node_coordinates_it;
-      Matrix<Real> & cosines = *directing_cosines_it;
-
-      computeDirectingCosinesOnQuad(nodes, cosines);
-    }
-  }
-
-  // Mauro: the directing_cosines internal is defined on the quadrature points of each element
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim>
-void MaterialReinforcement<dim>::assembleStiffnessMatrix(
-    const ElementType & type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Mesh & mesh = model->getMesh();
-
-  Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type);
-  Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type);
-
-  for (; type_it != type_end; ++type_it) {
-    assembleStiffnessMatrixInterface(type, *type_it, ghost_type);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-/**
- * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001)
- * \f[
- * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T
- * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}}
- * \f]
- */
-template <UInt dim>
-void MaterialReinforcement<dim>::assembleStiffnessMatrixInterface(
-    const ElementType & interface_type, const ElementType & background_type,
-    GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  UInt voigt_size = getTangentStiffnessVoigtSize(dim);
-
-  FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine");
-
-  Array<UInt> & elem_filter = element_filter(interface_type, ghost_type);
-  Array<Real> & grad_u = gradu_embedded(interface_type, ghost_type);
-
-  UInt nb_element = elem_filter.size();
-  UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type);
-  UInt nb_quadrature_points =
-      interface_engine.getNbIntegrationPoints(interface_type, ghost_type);
-
-  UInt back_dof = dim * nodes_per_background_e;
-
-  UInt integrant_size = back_dof;
-
-  grad_u.resize(nb_quadrature_points * nb_element);
-
-  Array<Real> tangent_moduli(nb_element * nb_quadrature_points, 1,
-                             "interface_tangent_moduli");
-  computeTangentModuli(interface_type, tangent_moduli, ghost_type);
-
-  Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))(
-      background_type, ghost_type);
-
-  Array<Real> integrant(nb_element * nb_quadrature_points,
-                        integrant_size * integrant_size, "B^t*C^t*D*C*B");
-
-  /// Temporary matrices for integrant product
-  Matrix<Real> Bvoigt(voigt_size, back_dof);
-  Matrix<Real> DC(voigt_size, voigt_size);
-  Matrix<Real> DCB(voigt_size, back_dof);
-  Matrix<Real> CtDCB(voigt_size, back_dof);
-
-  Array<Real>::scalar_iterator D_it = tangent_moduli.begin();
-  Array<Real>::scalar_iterator D_end = tangent_moduli.end();
-
-  Array<Real>::matrix_iterator C_it =
-      directing_cosines(interface_type, ghost_type)
-          .begin(voigt_size, voigt_size);
-  Array<Real>::matrix_iterator B_it =
-      shapesd.begin(dim, nodes_per_background_e);
-  Array<Real>::matrix_iterator integrant_it =
-      integrant.begin(integrant_size, integrant_size);
-
-  for (; D_it != D_end; ++D_it, ++C_it, ++B_it, ++integrant_it) {
-    Real & D = *D_it;
-    Matrix<Real> & C = *C_it;
-    Matrix<Real> & B = *B_it;
-    Matrix<Real> & BtCtDCB = *integrant_it;
-
-    VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt,
-                                                       nodes_per_background_e);
-
-    DC.clear();
-    DC(0, 0) = D * area;
-    DC *= C;
-    DCB.mul<false, false>(DC, Bvoigt);
-    CtDCB.mul<true, false>(C, DCB);
-    BtCtDCB.mul<true, false>(Bvoigt, CtDCB);
-  }
-
-  tangent_moduli.resize(0);
-
-  Array<Real> K_interface(
-      nb_element, integrant_size * integrant_size, "K_interface");
-  interface_engine.integrate(integrant, K_interface,
-                             integrant_size * integrant_size, interface_type,
-                             ghost_type, elem_filter);
-
-  integrant.resize(0);
-
-  // Mauro: Here K_interface contains the local stiffness matrices,
-  // directing_cosines contains the information about the orientation
-  // of the reinforcements, any rotation of the local stiffness matrix
-  // can be done here
-
-  Array<UInt> background_filter(nb_element, 1, "background_filter");
-
-  filterInterfaceBackgroundElements(background_filter, background_type,
-                                    interface_type, ghost_type);
-
-  model->getDOFManager().assembleElementalMatricesToMatrix(
-      "K", "displacement", K_interface, background_type, ghost_type,
-      _symmetric, background_filter);
-
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-/// In this function, type and ghost_type refer to background elements
-template <UInt dim>
-void MaterialReinforcement<dim>::computeBackgroundShapeDerivatives(
-    const ElementType & type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  Mesh & interface_mesh = model->getInterfaceMesh();
-
-  FEEngine & engine = model->getFEEngine();
-  FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine");
-
-  Mesh::type_iterator interface_type = interface_mesh.firstType();
-  Mesh::type_iterator interface_last = interface_mesh.lastType();
-
-  for (; interface_type != interface_last; ++interface_type) {
-    Array<UInt> & filter = element_filter(*interface_type, ghost_type);
-
-    const UInt nb_elements = filter.size();
-    const UInt nb_nodes = Mesh::getNbNodesPerElement(type);
-    const UInt nb_quad_per_element =
-        interface_engine.getNbIntegrationPoints(*interface_type);
-
-    Array<Real> quad_pos(nb_quad_per_element * nb_elements, dim,
-                         "interface_quad_points");
-    quad_pos.resize(nb_quad_per_element * nb_elements);
-    interface_engine.interpolateOnIntegrationPoints(
-        interface_mesh.getNodes(), quad_pos, dim, *interface_type, ghost_type,
-        filter);
-
-    Array<Real> & background_shapesd =
-        shape_derivatives(*interface_type, ghost_type)
-            ->
-            operator()(type, ghost_type);
-    background_shapesd.clear();
-
-    Array<UInt> * background_elements = new Array<UInt>(
-        nb_elements, 1, "computeBackgroundShapeDerivatives:background_filter");
-    filterInterfaceBackgroundElements(*background_elements, type,
-                                      *interface_type, ghost_type);
-
-    Array<UInt>::scalar_iterator back_it = background_elements->begin(),
-                                 back_end = background_elements->end();
-
-    Array<Real>::matrix_iterator shapesd_it =
-        background_shapesd.begin(dim, nb_nodes);
-
-    Array<Real>::vector_iterator quad_pos_it = quad_pos.begin(dim);
-
-    for (; back_it != back_end; ++back_it) {
-      for (UInt i = 0; i < nb_quad_per_element;
-           i++, ++shapesd_it, ++quad_pos_it)
-        engine.computeShapeDerivatives(*quad_pos_it, *back_it, type,
-                                       *shapesd_it, ghost_type);
-    }
-
-    delete background_elements;
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-template <UInt dim>
-Real MaterialReinforcement<dim>::getEnergy(const std::string & id) {
-  AKANTU_DEBUG_IN();
-  if (id == "potential") {
-    Real epot = 0.;
-
-    computePotentialEnergyByElements();
-
-    Mesh::type_iterator it = element_filter.firstType(spatial_dimension),
-                        end = element_filter.lastType(spatial_dimension);
-
-    for (; it != end; ++it) {
-      FEEngine & interface_engine =
-          model->getFEEngine("EmbeddedInterfaceFEEngine");
-      epot += interface_engine.integrate(potential_energy(*it, _not_ghost), *it,
-                                         _not_ghost,
-                                         element_filter(*it, _not_ghost));
-      epot *= area;
-    }
-
-    return epot;
-  }
-
-  AKANTU_DEBUG_OUT();
-  return 0;
-}
-
-// /* --------------------------------------------------------------------------
-// */
-// template<UInt dim>
-// ElementTypeMap<UInt> MaterialReinforcement<dim>::getInternalDataPerElem(const
-// ID & field_name,
-//                                                                         const
-//                                                                         ElementKind
-//                                                                         &
-//                                                                         kind,
-//                                                                         const
-//                                                                         ID &
-//                                                                         fe_engine_id)
-//                                                                         const
-//                                                                         {
-//   return Material::getInternalDataPerElem(field_name, kind,
-//   "EmbeddedInterfaceFEEngine");
-// }
-
-// /* --------------------------------------------------------------------------
-// */
-// // Author is Guillaume Anciaux, see material.cc
-// template<UInt dim>
-// void MaterialReinforcement<dim>::flattenInternal(const std::string &
-// field_id,
-//                                                  ElementTypeMapArray<Real> &
-//                                                  internal_flat,
-//                                                  const GhostType ghost_type,
-//                                                  ElementKind element_kind)
-//                                                  const {
-//   AKANTU_DEBUG_IN();
-
-//   if (field_id == "stress_embedded" || field_id == "inelastic_strain") {
-//     Material::flattenInternalIntern(field_id,
-//                                     internal_flat,
-//                                     1,
-//                                     ghost_type,
-//                                     _ek_not_defined,
-//                                     &(this->element_filter),
-//                                     &(this->model->getInterfaceMesh()));
-//   }
-
-//   AKANTU_DEBUG_OUT();
-// }
-
-/* -------------------------------------------------------------------------- */
-
-INSTANTIATE_MATERIAL_ONLY(MaterialReinforcement);
-
-/* -------------------------------------------------------------------------- */
-
-} // akantu
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh
index 09925013b..fa320e42a 100644
--- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh
+++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh
@@ -1,192 +1,209 @@
 /**
  * @file   material_reinforcement.hh
  *
  * @author Lucas Frerot <lucas.frerot@epfl.ch>
  *
  * @date creation: Fri Mar 13 2015
  * @date last modification: Tue Nov 24 2015
  *
  * @brief  Reinforcement material
  *
  * @section LICENSE
  *
  * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
  * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_MATERIAL_REINFORCEMENT_HH__
 #define __AKANTU_MATERIAL_REINFORCEMENT_HH__
 
 #include "aka_common.hh"
 
 #include "material.hh"
 #include "embedded_interface_model.hh"
-#include "embedded_internal_field.hh"
 
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /**
  * @brief Material used to represent embedded reinforcements
  *
  * This class is used for computing the reinforcement stiffness matrix
  * along with the reinforcement residual. Room is made for constitutive law,
  * but actual use of contitutive laws is made in MaterialReinforcementTemplate.
  *
  * Be careful with the dimensions in this class :
  *  -  this->spatial_dimension is always 1
  *  -  the template parameter dim is the dimension of the problem
  */
-template <UInt dim> class MaterialReinforcement : virtual public Material {
+
+template <class Mat, UInt dim> class MaterialReinforcement : public Mat {
 
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   /// Constructor
-  MaterialReinforcement(SolidMechanicsModel & model, UInt spatial_dimension,
-                        const Mesh & mesh, FEEngine & fe_engine,
-                        const ID & id = "");
+  MaterialReinforcement(EmbeddedInterfaceModel & model, const ID & id = "");
 
   /// Destructor
   ~MaterialReinforcement() override;
 
 protected:
-  void initialize(SolidMechanicsModel & a_model);
+  void initialize();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// Init the material
   void initMaterial() override;
 
+  /// Init the filters for background elements
+  void initFilters();
+
   /// Init the background shape derivatives
   void initBackgroundShapeDerivatives();
 
   /// Init the cosine matrices
   void initDirectingCosines();
 
   /// Assemble stiffness matrix
   void assembleStiffnessMatrix(GhostType ghost_type) override;
 
   /// Compute all the stresses !
   void computeAllStresses(GhostType ghost_type) override;
 
   /// Compute energy
   Real getEnergy(const std::string & id) override;
 
   /// Assemble the residual of one type of element (typically _segment_2)
   void assembleInternalForces(GhostType ghost_type) override;
 
-  // virtual ElementTypeMap<UInt> getInternalDataPerElem(const ID & field_name,
-  //                                                     const ElementKind &
-  //                                                     kind,
-  //                                                     const ID &
-  //                                                     fe_engine_id) const;
-
-  // /// Reimplementation of Material's function to accomodate for interface
-  // mesh
-  // virtual void flattenInternal(const std::string & field_id,
-  //                              ElementTypeMapArray<Real> & internal_flat,
-  //                              const GhostType ghost_type = _not_ghost,
-  //                              ElementKind element_kind = _ek_not_defined)
-  //                              const;
-
   /* ------------------------------------------------------------------------ */
   /* Protected methods                                                        */
   /* ------------------------------------------------------------------------ */
 protected:
   /// Allocate the background shape derivatives
   void allocBackgroundShapeDerivatives();
 
   /// Compute the directing cosines matrix for one element type
   void computeDirectingCosines(const ElementType & type, GhostType ghost_type);
 
   /// Compute the directing cosines matrix on quadrature points.
   inline void computeDirectingCosinesOnQuad(const Matrix<Real> & nodes,
                                             Matrix<Real> & cosines);
 
+  /// Add the prestress to the computed stress
+  void addPrestress(const ElementType & type, GhostType ghost_type);
+
+  /// Compute displacement gradient in reinforcement
+  void computeGradU(const ElementType & interface_type, GhostType ghost_type);
+
   /// Assemble the stiffness matrix for an element type (typically _segment_2)
   void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type);
 
   /// Assemble the stiffness matrix for background & interface types
   void assembleStiffnessMatrixInterface(const ElementType & interface_type,
                                         const ElementType & background_type,
                                         GhostType ghost_type);
 
   /// Compute the background shape derivatives for a type
   void computeBackgroundShapeDerivatives(const ElementType & type,
                                          GhostType ghost_type);
 
+  /// Compute the background shape derivatives for a type pair
+  void computeBackgroundShapeDerivatives(const ElementType & interface_type,
+					 const ElementType & bg_type,
+					 GhostType ghost_type,
+					 const Array<UInt> & filter);
+
   /// Filter elements crossed by interface of a type
-  void filterInterfaceBackgroundElements(Array<UInt> & filter,
+  void filterInterfaceBackgroundElements(Array<UInt> & foreground,
+					 Array<UInt> & background,
                                          const ElementType & type,
                                          const ElementType & interface_type,
                                          GhostType ghost_type);
 
   /// Assemble the residual of one type of element (typically _segment_2)
   void assembleInternalForces(const ElementType & type, GhostType ghost_type);
 
   /// Assemble the residual for a pair of elements
   void assembleInternalForcesInterface(const ElementType & interface_type,
                                        const ElementType & background_type,
                                        GhostType ghost_type);
 
   // TODO figure out why voigt size is 4 in 2D
   inline void stressTensorToVoigtVector(const Matrix<Real> & tensor,
                                         Vector<Real> & vector);
   inline void strainTensorToVoigtVector(const Matrix<Real> & tensor,
                                         Vector<Real> & vector);
 
-  /// Compute gradu on the interface quadrature points
-  virtual void computeGradU(const ElementType & type, GhostType ghost_type);
+  /// Get background filter
+  Array<UInt> & getBackgroundFilter(const ElementType & fg_type,
+                                    const ElementType & bg_type,
+                                    GhostType ghost_type) {
+    return (*background_filter(fg_type, ghost_type))(bg_type, ghost_type);
+  }
+
+  /// Get foreground filter
+  Array<UInt> & getForegroundFilter(const ElementType & fg_type,
+                                    const ElementType & bg_type,
+                                    GhostType ghost_type) {
+    return (*foreground_filter(fg_type, ghost_type))(bg_type, ghost_type);
+  }
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// Embedded model
-  EmbeddedInterfaceModel * model;
-
-  /// Stress in the reinforcement
-  InternalField<Real> stress_embedded;
+  EmbeddedInterfaceModel & emodel;
 
   /// Gradu of concrete on reinforcement
   InternalField<Real> gradu_embedded;
 
   /// C matrix on quad
   InternalField<Real> directing_cosines;
 
   /// Prestress on quad
   InternalField<Real> pre_stress;
 
   /// Cross-sectional area
   Real area;
 
+  template <typename T>
+  using CrossMap = ElementTypeMap<std::unique_ptr<ElementTypeMapArray<T>>>;
+
   /// Background mesh shape derivatives
-  ElementTypeMap<ElementTypeMapArray<Real> *> shape_derivatives;
-};
+  CrossMap<Real> shape_derivatives;
 
-#include "material_reinforcement_inline_impl.cc"
+  /// Foreground mesh filter (contains segment ids)
+  CrossMap<UInt> foreground_filter;
+
+  /// Background element filter (contains bg ids)
+  CrossMap<UInt> background_filter;
+};
 
 } // akantu
 
+#include "material_reinforcement_tmpl.hh"
+
 #endif // __AKANTU_MATERIAL_REINFORCEMENT_HH__
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc
deleted file mode 100644
index cf23faf42..000000000
--- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_inline_impl.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * @file   material_reinforcement_inline_impl.cc
- *
- * @author Lucas Frerot <lucas.frerot@epfl.ch>
- *
- * @date creation: Fri Jun 18 2010
- * @date last modification: Tue Jul 14 2015
- *
- * @brief  Reinforcement material
- *
- * @section LICENSE
- *
- * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
- * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
- * Solides)
- *
- * Akantu is free  software: you can redistribute it and/or  modify it under the
- * terms  of the  GNU Lesser  General Public  License as  published by  the Free
- * Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
- * details.
- *
- * You should  have received  a copy  of the GNU  Lesser General  Public License
- * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* -------------------------------------------------------------------------- */
-
-/**
- * The structure of the directing cosines matrix is :
- * \f{eqnarray*}{
- *  C_{1,\cdot} & = & (l^2, m^2, n^2, mn, ln, lm) \\
- *  C_{i,j} & = & 0
- * \f}
- *
- * with :
- * \f[
- * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}
- * \f]
- */
-template<UInt dim>
-inline void MaterialReinforcement<dim>::computeDirectingCosinesOnQuad(const Matrix<Real> & nodes,
-                                                                 Matrix<Real> & cosines) {
-  AKANTU_DEBUG_IN();
-
-  AKANTU_DEBUG_ASSERT(nodes.cols() == 2, "Higher order reinforcement elements not implemented");
-
-  const Vector<Real> & a = nodes(0), b = nodes(1);
-  Vector<Real> delta = b - a;
-
-  cosines.clear();
-
-  Real sq_length = 0.;
-  for (UInt i = 0 ; i < dim ; i++) {
-    sq_length += Math::pow<2, Real>(delta(i));
-  }
-
-  if (dim == 2) {
-    cosines(0, 0) = Math::pow<2, Real>(delta(0)); // l^2
-    cosines(0, 1) = Math::pow<2, Real>(delta(1)); // m^2
-    cosines(0, 2) = delta(0) * delta(1); // lm
-  } else if (dim == 3) {
-    cosines(0, 0) = Math::pow<2, Real>(delta(0)); // l^2
-    cosines(0, 1) = Math::pow<2, Real>(delta(1)); // m^2
-    cosines(0, 2) = Math::pow<2, Real>(delta(2)); // n^2
-
-    cosines(0, 3) = delta(1) * delta(2); // mn
-    cosines(0, 4) = delta(0) * delta(2); // ln
-    cosines(0, 5) = delta(0) * delta(1); // lm
-  }
-
-  cosines /= sq_length;
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template<UInt dim>
-inline void MaterialReinforcement<dim>::stressTensorToVoigtVector(const Matrix<Real> & tensor,
-                                                                  Vector<Real> & vector) {
-  AKANTU_DEBUG_IN();
-  
-  for (UInt i = 0; i < dim; i++) {
-    vector(i) = tensor(i, i);
-  }
-
-  if (dim == 2) {
-    vector(2) = tensor(0, 1);
-  } else if (dim == 3) {
-    vector(3) = tensor(1, 2);
-    vector(4) = tensor(0, 2);
-    vector(5) = tensor(0, 1);
-  }
-  
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template<UInt dim>
-inline void MaterialReinforcement<dim>::strainTensorToVoigtVector(const Matrix<Real> & tensor,
-                                                                  Vector<Real> & vector) {
-  AKANTU_DEBUG_IN();
-  
-  for (UInt i = 0; i < dim; i++) {
-    vector(i) = tensor(i, i);
-  }
-
-  if (dim == 2) {
-    vector(2) = 2 * tensor(0, 1);
-  } else if (dim == 3) {
-    vector(3) = 2 * tensor(1, 2);
-    vector(4) = 2 * tensor(0, 2);
-    vector(5) = 2 * tensor(0, 1);
-  }
-  
-  AKANTU_DEBUG_OUT();
-}
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh
deleted file mode 100644
index 881d5f0df..000000000
--- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template.hh
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * @file   material_reinforcement_template.hh
- *
- * @author Lucas Frerot <lucas.frerot@epfl.ch>
- *
- * @date creation: Wed Mar 25 2015
- * @date last modification: Mon Jun 01 2015
- *
- * @brief  Reinforcement material templated with constitutive law
- *
- * @section LICENSE
- *
- * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
- * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
- *
- * Akantu is free  software: you can redistribute it and/or  modify it under the
- * terms  of the  GNU Lesser  General Public  License as  published by  the Free
- * Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
- * details.
- *
- * You should  have received  a copy  of the GNU  Lesser General  Public License
- * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* -------------------------------------------------------------------------- */
-
-#ifndef __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__
-#define __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__
-
-/* -------------------------------------------------------------------------- */
-
-#include "aka_common.hh"
-#include "material_elastic.hh"
-#include "material_linear_isotropic_hardening.hh"
-#include "material_reinforcement.hh"
-
-namespace akantu {
-
-/**
- * @brief Implementation of MaterialReinforcement with 1D constitutive law
- * @see MaterialReinforcement, MaterialElastic
- *
- * This class is a reinforcement featuring a constitutive law.
- * <strong>Be careful !</strong> Because of multiple inheritance, this class
- * forms a diamond.
- */
-template <UInt dim, class ConstLaw = MaterialElastic<1>>
-class MaterialReinforcementTemplate : virtual public MaterialReinforcement<dim>,
-                                      public ConstLaw {
-
-  /* ------------------------------------------------------------------------ */
-  /* Constructors/Destructors                                                 */
-  /* ------------------------------------------------------------------------ */
-public:
-  /// Constructor
-  MaterialReinforcementTemplate(SolidMechanicsModel & a_model,
-                                const ID & id = "");
-
-  /// Destructor
-  ~MaterialReinforcementTemplate() override;
-
-  /* ------------------------------------------------------------------------ */
-  /* Methods                                                                  */
-  /* ------------------------------------------------------------------------ */
-public:
-  /// Initialises the material
-  void initMaterial();
-
-  /// Compute the stiffness parameter for elements of a type
-  void computeTangentModuli(const ElementType & type, Array<Real> & tangent,
-                            GhostType ghost_type) override;
-
-  /// Computes stress used by constitutive law
-  void computeStress(ElementType type, GhostType ghost_type) override;
-
-  /// Computes gradu to be used by the constitutive law
-  void computeGradU(const ElementType & type, GhostType ghost_type) override;
-
-  /// Compute the potential energy of the reinforcement
-  void computePotentialEnergy(ElementType type,
-                              GhostType ghost_type = _not_ghost) override;
-
-  /// Get energy in reinforcement (currently limited to potential)
-  Real getEnergy(const std::string & id) override;
-
-protected:
-  /**
-   * @brief Compute interface gradu from bulk gradu
-   * \f[
-   *  \varepsilon_s = C \varepsilon_c
-   * \f]
-   */
-  inline void computeInterfaceGradUOnQuad(const Matrix<Real> & full_gradu,
-                                          Real & gradu, const Matrix<Real> & C);
-};
-
-#include "material_reinforcement_template_tmpl.hh"
-
-} // akantu
-
-#endif // __AKANTU_MATERIAL_REINFORCEMENT_TEMPLATE_HH__
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh
deleted file mode 100644
index 0dcb83d01..000000000
--- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_tmpl.hh
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * @file   material_reinforcement_template_tmpl.hh
- *
- * @author Lucas Frerot <lucas.frerot@epfl.ch>
- *
- * @date creation: Wed Mar 25 2015
- * @date last modification: Thu Oct 15 2015
- *
- * @brief  Reinforcement material templated with constitutive law
- *
- * @section LICENSE
- *
- * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
- * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
- *
- * Akantu is free  software: you can redistribute it and/or  modify it under the
- * terms  of the  GNU Lesser  General Public  License as  published by  the Free
- * Software Foundation, either version 3 of the License, or (at your option) any
- * later version.
- *
- * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
- * details.
- *
- * You should  have received  a copy  of the GNU  Lesser General  Public License
- * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-// /!\ no namespace here !
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-MaterialReinforcementTemplate<dim, ConstLaw>::MaterialReinforcementTemplate(
-    SolidMechanicsModel & a_model, const ID & id)
-    : Material(
-          a_model, 1,
-          dynamic_cast<EmbeddedInterfaceModel &>(a_model).getInterfaceMesh(),
-          a_model.getFEEngine("EmbeddedInterfaceFEEngine"), id),
-      MaterialReinforcement<dim>(
-          a_model, 1,
-          dynamic_cast<EmbeddedInterfaceModel &>(a_model).getInterfaceMesh(),
-          a_model.getFEEngine("EmbeddedInterfaceFEEngine"), id),
-      ConstLaw(
-          a_model, 1,
-          dynamic_cast<EmbeddedInterfaceModel &>(a_model).getInterfaceMesh(),
-          a_model.getFEEngine("EmbeddedInterfaceFEEngine"), id + "const_law") {}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-MaterialReinforcementTemplate<dim, ConstLaw>::~MaterialReinforcementTemplate() {
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-void MaterialReinforcementTemplate<dim, ConstLaw>::initMaterial() {
-  MaterialReinforcement<dim>::initMaterial();
-  ConstLaw::initMaterial();
-
-  // Needed for plasticity law
-  this->ConstLaw::nu = 0.5;
-  this->ConstLaw::updateInternalParameters();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-void MaterialReinforcementTemplate<dim, ConstLaw>::computeGradU(
-    const ElementType & el_type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  MaterialReinforcement<dim>::computeGradU(el_type, ghost_type);
-
-  const UInt voigt_size = ConstLaw::getTangentStiffnessVoigtSize(dim);
-
-  Array<Real>::matrix_iterator full_gradu_it =
-      this->MaterialReinforcement<dim>::gradu_embedded(el_type, ghost_type)
-          .begin(dim, dim);
-  Array<Real>::matrix_iterator full_gradu_end =
-      this->MaterialReinforcement<dim>::gradu_embedded(el_type, ghost_type)
-          .end(dim, dim);
-
-  Array<Real>::scalar_iterator gradu_it =
-      this->ConstLaw::gradu(el_type, ghost_type).begin();
-
-  Array<Real>::matrix_iterator cosines_it =
-      this->directing_cosines(el_type, ghost_type)
-          .begin(voigt_size, voigt_size);
-
-  for (; full_gradu_it != full_gradu_end;
-       ++full_gradu_it, ++gradu_it, ++cosines_it) {
-    Matrix<Real> & full_gradu = *full_gradu_it;
-    Real & gradu = *gradu_it;
-    Matrix<Real> & C = *cosines_it;
-
-    computeInterfaceGradUOnQuad(full_gradu, gradu, C);
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-void MaterialReinforcementTemplate<dim, ConstLaw>::computeInterfaceGradUOnQuad(
-    const Matrix<Real> & full_gradu, Real & gradu, const Matrix<Real> & C) {
-  const UInt voigt_size = ConstLaw::getTangentStiffnessVoigtSize(dim);
-
-  Matrix<Real> epsilon(dim, dim);
-  Vector<Real> e_voigt(voigt_size);
-  Vector<Real> e_interface_voigt(voigt_size);
-
-  epsilon = 0.5 * (full_gradu + full_gradu.transpose());
-  MaterialReinforcement<dim>::strainTensorToVoigtVector(epsilon, e_voigt);
-  e_interface_voigt.mul<false>(C, e_voigt);
-
-  gradu = e_interface_voigt(0);
-}
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-void MaterialReinforcementTemplate<dim, ConstLaw>::computeTangentModuli(
-    const ElementType & el_type, Array<Real> & tangent, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  AKANTU_DEBUG_ASSERT(tangent.getNbComponent() == 1,
-                      "Reinforcements only work in 1D");
-
-  ConstLaw::computeTangentModuli(el_type, tangent, ghost_type);
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-void MaterialReinforcementTemplate<dim, ConstLaw>::computeStress(
-    ElementType type, GhostType ghost_type) {
-  AKANTU_DEBUG_IN();
-
-  ConstLaw::computeStress(type, ghost_type);
-
-  Array<Real>::matrix_iterator full_sigma_it =
-      this->MaterialReinforcement<dim>::stress_embedded(type, ghost_type)
-          .begin(dim, dim);
-  Array<Real>::matrix_iterator full_sigma_end =
-      this->MaterialReinforcement<dim>::stress_embedded(type, ghost_type)
-          .end(dim, dim);
-  Array<Real>::scalar_iterator sigma_it =
-      this->ConstLaw::stress(type, ghost_type).begin();
-  Array<Real>::scalar_iterator pre_stress_it =
-      this->MaterialReinforcement<dim>::pre_stress(type, ghost_type).begin();
-
-  for (; full_sigma_it != full_sigma_end;
-       ++full_sigma_it, ++sigma_it, ++pre_stress_it) {
-    Matrix<Real> & sigma = *full_sigma_it;
-
-    sigma(0, 0) = *sigma_it + *pre_stress_it;
-  }
-
-  AKANTU_DEBUG_OUT();
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-Real MaterialReinforcementTemplate<dim, ConstLaw>::getEnergy(
-    const std::string & id) {
-  return MaterialReinforcement<dim>::getEnergy(id);
-}
-
-/* -------------------------------------------------------------------------- */
-
-template <UInt dim, class ConstLaw>
-void MaterialReinforcementTemplate<dim, ConstLaw>::computePotentialEnergy(
-    ElementType type, GhostType ghost_type) {
-  const UInt nb_elements =
-      this->MaterialReinforcement<dim>::element_filter(type, ghost_type).size();
-  const UInt nb_quad = this->MaterialReinforcement<dim>::model
-                           ->getFEEngine("EmbeddedInterfaceFEEngine")
-                           .getNbIntegrationPoints(type);
-  this->ConstLaw::potential_energy.alloc(nb_quad * nb_elements, 1, type,
-                                         ghost_type, 0.);
-
-  ConstLaw::computePotentialEnergy(type, ghost_type);
-}
diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh
new file mode 100644
index 000000000..4dc96d2e7
--- /dev/null
+++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_tmpl.hh
@@ -0,0 +1,803 @@
+/**
+ * @file   material_reinforcement_tmpl.hh
+ *
+ * @author Lucas Frerot <lucas.frerot@epfl.ch>
+ *
+ * @date creation: Thu Feb 1 2018
+ *
+ * @brief  Reinforcement material
+ *
+ * @section LICENSE
+ *
+ * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
+ * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * Akantu is free  software: you can redistribute it and/or  modify it under the
+ * terms  of the  GNU Lesser  General Public  License as  published by  the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
+ * details.
+ *
+ * You should  have received  a copy  of the GNU  Lesser General  Public License
+ * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include "aka_common.hh"
+#include "aka_voigthelper.hh"
+#include "material_reinforcement.hh"
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+template <class Mat, UInt dim>
+MaterialReinforcement<Mat, dim>::MaterialReinforcement(
+    EmbeddedInterfaceModel & model, const ID & id)
+    : Mat(model, 1,
+          model.getInterfaceMesh(),
+          model.getFEEngine("EmbeddedInterfaceFEEngine"), id),
+      emodel(model),
+      gradu_embedded("gradu_embedded", *this, 1,
+                     model.getFEEngine("EmbeddedInterfaceFEEngine"),
+                     this->element_filter),
+      directing_cosines("directing_cosines", *this, 1,
+                        model.getFEEngine("EmbeddedInterfaceFEEngine"),
+                        this->element_filter),
+      pre_stress("pre_stress", *this, 1,
+                 model.getFEEngine("EmbeddedInterfaceFEEngine"),
+                 this->element_filter),
+      area(1.0), shape_derivatives() {
+  AKANTU_DEBUG_IN();
+  this->initialize();
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::initialize() {
+  AKANTU_DEBUG_IN();
+
+  this->registerParam("area", area, _pat_parsable | _pat_modifiable,
+                      "Reinforcement cross-sectional area");
+  this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable,
+                      "Uniform pre-stress");
+
+  // this->unregisterInternal(this->stress);
+
+  // Fool the AvgHomogenizingFunctor
+  // stress.initialize(dim * dim);
+
+  // Reallocate the element filter
+  this->element_filter.initialize(this->emodel.getInterfaceMesh(),
+                                  _spatial_dimension = 1);
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+MaterialReinforcement<Mat, dim>::~MaterialReinforcement() {
+  AKANTU_DEBUG_IN();
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::initMaterial() {
+  Mat::initMaterial();
+
+  gradu_embedded.initialize(dim * dim);
+  pre_stress.initialize(1);
+
+  /// We initialise the stuff that is not going to change during the simulation
+  this->initFilters();
+  this->allocBackgroundShapeDerivatives();
+  this->initBackgroundShapeDerivatives();
+  this->initDirectingCosines();
+}
+
+/* -------------------------------------------------------------------------- */
+/// Initialize the filter for background elements
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::initFilters() {
+  for (auto gt : ghost_types) {
+    for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) {
+      std::string shaped_id = "filter";
+      if (gt == _ghost)
+        shaped_id += ":ghost";
+
+      auto & background =
+          background_filter(std::make_unique<ElementTypeMapArray<UInt>>(
+                                "bg_" + shaped_id, this->name),
+                            type, gt);
+      auto & foreground = foreground_filter(
+          std::make_unique<ElementTypeMapArray<UInt>>(shaped_id, this->name),
+          type, gt);
+      foreground->initialize(emodel.getMesh(), _nb_component = 1,
+                             _ghost_type = gt);
+      background->initialize(emodel.getMesh(), _nb_component = 1,
+                             _ghost_type = gt);
+
+      // Computing filters
+      for (auto && bg_type : background->elementTypes(dim, gt)) {
+        filterInterfaceBackgroundElements(
+            (*foreground)(bg_type), (*background)(bg_type), bg_type, type, gt);
+      }
+    }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+/// Construct a filter for a (interface_type, background_type) pair
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::filterInterfaceBackgroundElements(
+    Array<UInt> & foreground, Array<UInt> & background,
+    const ElementType & type, const ElementType & interface_type,
+    GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  foreground.resize(0);
+  background.resize(0);
+
+  Array<Element> & elements =
+      emodel.getInterfaceAssociatedElements(interface_type, ghost_type);
+  Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type);
+
+  for (auto & elem_id : elem_filter) {
+    Element & elem = elements(elem_id);
+    if (elem.type == type) {
+      background.push_back(elem.element);
+      foreground.push_back(elem_id);
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+namespace detail {
+  class BackgroundShapeDInitializer : public ElementTypeMapArrayInitializer {
+  public:
+    BackgroundShapeDInitializer(UInt spatial_dimension, FEEngine & engine,
+                                const ElementType & foreground_type,
+                                const ElementTypeMapArray<UInt> & filter,
+                                const GhostType & ghost_type)
+        : ElementTypeMapArrayInitializer(
+              [](const ElementType & bgtype, const GhostType &) {
+                return ShapeFunctions::getShapeDerivativesSize(bgtype);
+              },
+              spatial_dimension, ghost_type, _ek_regular) {
+      auto nb_quad = engine.getNbIntegrationPoints(foreground_type);
+      // Counting how many background elements are affected by elements of
+      // interface_type
+      for (auto type : filter.elementTypes(this->spatial_dimension)) {
+        // Inserting size
+        array_size_per_bg_type(filter(type).size() * nb_quad, type,
+                               this->ghost_type);
+      }
+    }
+
+    auto elementTypes() const -> decltype(auto) {
+      return array_size_per_bg_type.elementTypes();
+    }
+
+    UInt size(const ElementType & bgtype) const {
+      return array_size_per_bg_type(bgtype, this->ghost_type);
+    }
+
+  protected:
+    ElementTypeMap<UInt> array_size_per_bg_type;
+  };
+}
+
+/**
+ * Background shape derivatives need to be stored per background element
+ * types but also per embedded element type, which is why they are stored
+ * in an ElementTypeMap<ElementTypeMapArray<Real> *>. The outer ElementTypeMap
+ * refers to the embedded types, and the inner refers to the background types.
+ */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::allocBackgroundShapeDerivatives() {
+  AKANTU_DEBUG_IN();
+
+  for (auto gt : ghost_types) {
+    for (auto && type : emodel.getInterfaceMesh().elementTypes(1, gt)) {
+      std::string shaped_id = "embedded_shape_derivatives";
+      if (gt == _ghost)
+        shaped_id += ":ghost";
+
+      auto & shaped_etma = shape_derivatives(
+          std::make_unique<ElementTypeMapArray<Real>>(shaped_id, this->name),
+          type, gt);
+      shaped_etma->initialize(
+          detail::BackgroundShapeDInitializer(
+              emodel.getSpatialDimension(),
+              emodel.getFEEngine("EmbeddedInterfaceFEEngine"), type,
+              *background_filter(type, gt), gt),
+          0, true);
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::initBackgroundShapeDerivatives() {
+  AKANTU_DEBUG_IN();
+
+  for (auto interface_type :
+       this->element_filter.elementTypes(this->spatial_dimension)) {
+    for (auto type : background_filter(interface_type)->elementTypes(dim)) {
+      computeBackgroundShapeDerivatives(interface_type, type, _not_ghost,
+                                        this->element_filter(interface_type));
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::computeBackgroundShapeDerivatives(
+    const ElementType & interface_type, const ElementType & bg_type,
+    GhostType ghost_type, const Array<UInt> & filter) {
+  auto & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine");
+  auto & engine = emodel.getFEEngine();
+  auto & interface_mesh = emodel.getInterfaceMesh();
+
+  const auto nb_nodes_elem_bg = Mesh::getNbNodesPerElement(bg_type);
+  // const auto nb_strss = VoigtHelper<dim>::size;
+  const auto nb_quads_per_elem =
+      interface_engine.getNbIntegrationPoints(interface_type);
+
+  Array<Real> quad_pos(0, dim, "interface_quad_pos");
+  interface_engine.interpolateOnIntegrationPoints(interface_mesh.getNodes(),
+                                                  quad_pos, dim, interface_type,
+                                                  ghost_type, filter);
+  auto & background_shapesd =
+      (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type);
+  auto & background_elements =
+      (*background_filter(interface_type, ghost_type))(bg_type, ghost_type);
+  auto & foreground_elements =
+      (*foreground_filter(interface_type, ghost_type))(bg_type, ghost_type);
+
+  auto shapesd_begin =
+    background_shapesd.begin(dim, nb_nodes_elem_bg, nb_quads_per_elem);
+  auto quad_begin = quad_pos.begin(dim, nb_quads_per_elem);
+
+  for (auto && tuple : zip(background_elements, foreground_elements)) {
+    UInt bg = std::get<0>(tuple), fg = std::get<1>(tuple);
+    for (UInt i = 0; i < nb_quads_per_elem; ++i) {
+      Matrix<Real> shapesd = Tensor3<Real>(shapesd_begin[fg])(i);
+      Vector<Real> quads = Matrix<Real>(quad_begin[fg])(i);
+
+      engine.computeShapeDerivatives(quads, bg, bg_type, shapesd,
+                                     ghost_type);
+    }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::initDirectingCosines() {
+  AKANTU_DEBUG_IN();
+
+  Mesh & mesh = emodel.getInterfaceMesh();
+
+  Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost);
+  Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost);
+
+  const UInt voigt_size = VoigtHelper<dim>::size;
+  directing_cosines.initialize(voigt_size);
+
+  for (; type_it != type_end; ++type_it) {
+    computeDirectingCosines(*type_it, _not_ghost);
+    // computeDirectingCosines(*type_it, _ghost);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix(
+    GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  Mesh & interface_mesh = emodel.getInterfaceMesh();
+
+  Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost);
+  Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost);
+
+  for (; type_it != type_end; ++type_it) {
+    assembleStiffnessMatrix(*type_it, ghost_type);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::assembleInternalForces(
+    GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  Mesh & interface_mesh = emodel.getInterfaceMesh();
+
+  Mesh::type_iterator type_it = interface_mesh.firstType(1, _not_ghost);
+  Mesh::type_iterator type_end = interface_mesh.lastType(1, _not_ghost);
+
+  for (; type_it != type_end; ++type_it) {
+    this->assembleInternalForces(*type_it, ghost_type);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::computeAllStresses(GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  Mesh::type_iterator it = emodel.getInterfaceMesh().firstType();
+  Mesh::type_iterator last_type = emodel.getInterfaceMesh().lastType();
+
+  for (; it != last_type; ++it) {
+    computeGradU(*it, ghost_type);
+    this->computeStress(*it, ghost_type);
+    addPrestress(*it, ghost_type);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::addPrestress(const ElementType & type,
+                                                   GhostType ghost_type) {
+  auto & stress = this->stress(type, ghost_type);
+  auto & sigma_p = this->pre_stress(type, ghost_type);
+
+  for (auto && tuple : zip(stress, sigma_p)) {
+    std::get<0>(tuple) += std::get<1>(tuple);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::assembleInternalForces(
+    const ElementType & type, GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  Mesh & mesh = emodel.getMesh();
+
+  Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type);
+  Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type);
+
+  for (; type_it != type_end; ++type_it) {
+    assembleInternalForcesInterface(type, *type_it, ghost_type);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Computes and assemble the residual. Residual in reinforcement is computed as:
+ *
+ * \f[
+ * \vec{r} = A_s \int_S{\mathbf{B}^T\mathbf{C}^T \vec{\sigma_s}\,\mathrm{d}s}
+ * \f]
+ */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::assembleInternalForcesInterface(
+    const ElementType & interface_type, const ElementType & background_type,
+    GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  UInt voigt_size = VoigtHelper<dim>::size;
+
+  FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine");
+
+  Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type);
+
+  UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type);
+  UInt nb_quadrature_points =
+      interface_engine.getNbIntegrationPoints(interface_type, ghost_type);
+  UInt nb_element = elem_filter.size();
+
+  UInt back_dof = dim * nodes_per_background_e;
+
+  Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))(
+      background_type, ghost_type);
+
+  Array<Real> integrant(nb_quadrature_points * nb_element, back_dof,
+                        "integrant");
+
+  Array<Real>::vector_iterator integrant_it = integrant.begin(back_dof);
+  Array<Real>::vector_iterator integrant_end = integrant.end(back_dof);
+
+  Array<Real>::matrix_iterator B_it =
+      shapesd.begin(dim, nodes_per_background_e);
+  Array<Real>::vector_iterator C_it =
+      directing_cosines(interface_type, ghost_type).begin(voigt_size);
+
+  auto sigma_it = this->stress(interface_type, ghost_type).begin();
+
+  Matrix<Real> Bvoigt(voigt_size, back_dof);
+
+  for (; integrant_it != integrant_end;
+       ++integrant_it, ++B_it, ++C_it, ++sigma_it) {
+    VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt,
+                                                       nodes_per_background_e);
+    Vector<Real> & C = *C_it;
+    Vector<Real> & BtCt_sigma = *integrant_it;
+
+    BtCt_sigma.mul<true>(Bvoigt, C);
+    BtCt_sigma *= *sigma_it * area;
+  }
+
+  Array<Real> residual_interface(nb_element, back_dof, "residual_interface");
+  interface_engine.integrate(integrant, residual_interface, back_dof,
+                             interface_type, ghost_type, elem_filter);
+  integrant.resize(0);
+
+  Array<UInt> background_filter(nb_element, 1, "background_filter");
+
+  auto & filter =
+      getBackgroundFilter(interface_type, background_type, ghost_type);
+
+  emodel.getDOFManager().assembleElementalArrayLocalArray(
+      residual_interface, emodel.getInternalForce(), background_type,
+      ghost_type, -1., filter);
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::computeDirectingCosines(
+    const ElementType & type, GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  Mesh & interface_mesh = emodel.getInterfaceMesh();
+
+  const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+  const UInt steel_dof = dim * nb_nodes_per_element;
+  const UInt voigt_size = VoigtHelper<dim>::size;
+  const UInt nb_quad_points = emodel.getFEEngine("EmbeddedInterfaceFEEngine")
+                                  .getNbIntegrationPoints(type, ghost_type);
+
+  Array<Real> node_coordinates(this->element_filter(type, ghost_type).size(),
+                               steel_dof);
+
+  this->emodel.getFEEngine().template extractNodalToElementField<Real>(
+      interface_mesh, interface_mesh.getNodes(), node_coordinates, type,
+      ghost_type, this->element_filter(type, ghost_type));
+
+  Array<Real>::matrix_iterator directing_cosines_it =
+    directing_cosines(type, ghost_type).begin(1, voigt_size);
+
+  Array<Real>::matrix_iterator node_coordinates_it =
+      node_coordinates.begin(dim, nb_nodes_per_element);
+  Array<Real>::matrix_iterator node_coordinates_end =
+      node_coordinates.end(dim, nb_nodes_per_element);
+
+  for (; node_coordinates_it != node_coordinates_end; ++node_coordinates_it) {
+    for (UInt i = 0; i < nb_quad_points; i++, ++directing_cosines_it) {
+      Matrix<Real> & nodes = *node_coordinates_it;
+      Matrix<Real> & cosines = *directing_cosines_it;
+
+      computeDirectingCosinesOnQuad(nodes, cosines);
+    }
+  }
+
+  // Mauro: the directing_cosines internal is defined on the quadrature points
+  // of each element
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrix(
+    const ElementType & type, GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  Mesh & mesh = emodel.getMesh();
+
+  Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type);
+  Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type);
+
+  for (; type_it != type_end; ++type_it) {
+    assembleStiffnessMatrixInterface(type, *type_it, ghost_type);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+/**
+ * Computes the reinforcement stiffness matrix (Gomes & Awruch, 2001)
+ * \f[
+ * \mathbf{K}_e = \sum_{i=1}^R{A_i\int_{S_i}{\mathbf{B}^T
+ * \mathbf{C}_i^T \mathbf{D}_{s, i} \mathbf{C}_i \mathbf{B}\,\mathrm{d}s}}
+ * \f]
+ */
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::assembleStiffnessMatrixInterface(
+    const ElementType & interface_type, const ElementType & background_type,
+    GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  UInt voigt_size = VoigtHelper<dim>::size;
+
+  FEEngine & interface_engine = emodel.getFEEngine("EmbeddedInterfaceFEEngine");
+
+  Array<UInt> & elem_filter = this->element_filter(interface_type, ghost_type);
+  Array<Real> & grad_u = gradu_embedded(interface_type, ghost_type);
+
+  UInt nb_element = elem_filter.size();
+  UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type);
+  UInt nb_quadrature_points =
+      interface_engine.getNbIntegrationPoints(interface_type, ghost_type);
+
+  UInt back_dof = dim * nodes_per_background_e;
+
+  UInt integrant_size = back_dof;
+
+  grad_u.resize(nb_quadrature_points * nb_element);
+
+  Array<Real> tangent_moduli(nb_element * nb_quadrature_points, 1,
+                             "interface_tangent_moduli");
+  this->computeTangentModuli(interface_type, tangent_moduli, ghost_type);
+
+  Array<Real> & shapesd = (*shape_derivatives(interface_type, ghost_type))(
+      background_type, ghost_type);
+
+  Array<Real> integrant(nb_element * nb_quadrature_points,
+                        integrant_size * integrant_size, "B^t*C^t*D*C*B");
+
+  /// Temporary matrices for integrant product
+  Matrix<Real> Bvoigt(voigt_size, back_dof);
+  Matrix<Real> DCB(1, back_dof);
+  Matrix<Real> CtDCB(voigt_size, back_dof);
+
+  Array<Real>::scalar_iterator D_it = tangent_moduli.begin();
+  Array<Real>::scalar_iterator D_end = tangent_moduli.end();
+
+  Array<Real>::matrix_iterator C_it =
+      directing_cosines(interface_type, ghost_type).begin(1, voigt_size);
+  Array<Real>::matrix_iterator B_it =
+      shapesd.begin(dim, nodes_per_background_e);
+  Array<Real>::matrix_iterator integrant_it =
+      integrant.begin(integrant_size, integrant_size);
+
+  for (; D_it != D_end; ++D_it, ++C_it, ++B_it, ++integrant_it) {
+    Real & D = *D_it;
+    Matrix<Real> & C = *C_it;
+    Matrix<Real> & B = *B_it;
+    Matrix<Real> & BtCtDCB = *integrant_it;
+
+    VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt,
+                                                       nodes_per_background_e);
+
+    DCB.mul<false, false>(C, Bvoigt);
+    DCB *= D * area;
+    CtDCB.mul<true, false>(C, DCB);
+    BtCtDCB.mul<true, false>(Bvoigt, CtDCB);
+  }
+
+  tangent_moduli.resize(0);
+
+  Array<Real> K_interface(nb_element, integrant_size * integrant_size,
+                          "K_interface");
+  interface_engine.integrate(integrant, K_interface,
+                             integrant_size * integrant_size, interface_type,
+                             ghost_type, elem_filter);
+
+  integrant.resize(0);
+
+  // Mauro: Here K_interface contains the local stiffness matrices,
+  // directing_cosines contains the information about the orientation
+  // of the reinforcements, any rotation of the local stiffness matrix
+  // can be done here
+
+  auto & filter =
+      getBackgroundFilter(interface_type, background_type, ghost_type);
+
+  emodel.getDOFManager().assembleElementalMatricesToMatrix(
+      "K", "displacement", K_interface, background_type, ghost_type, _symmetric,
+      filter);
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+template <class Mat, UInt dim>
+Real MaterialReinforcement<Mat, dim>::getEnergy(const std::string & id) {
+  AKANTU_DEBUG_IN();
+  if (id == "potential") {
+    Real epot = 0.;
+
+    this->computePotentialEnergyByElements();
+
+    Mesh::type_iterator it = this->element_filter.firstType(
+                            this->spatial_dimension),
+                        end = this->element_filter.lastType(
+                            this->spatial_dimension);
+
+    for (; it != end; ++it) {
+      FEEngine & interface_engine =
+          emodel.getFEEngine("EmbeddedInterfaceFEEngine");
+      epot += interface_engine.integrate(
+          this->potential_energy(*it, _not_ghost), *it, _not_ghost,
+          this->element_filter(*it, _not_ghost));
+      epot *= area;
+    }
+
+    return epot;
+  }
+
+  AKANTU_DEBUG_OUT();
+  return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+void MaterialReinforcement<Mat, dim>::computeGradU(
+    const ElementType & interface_type, GhostType ghost_type) {
+  // Looping over background types
+  for (auto && bg_type :
+       background_filter(interface_type, ghost_type)->elementTypes(dim)) {
+
+    const UInt nodes_per_background_e = Mesh::getNbNodesPerElement(bg_type);
+    const UInt voigt_size = VoigtHelper<dim>::size;
+
+    auto & bg_shapesd =
+        (*shape_derivatives(interface_type, ghost_type))(bg_type, ghost_type);
+
+    auto & filter = getBackgroundFilter(interface_type, bg_type, ghost_type);
+
+    Array<Real> disp_per_element(0, dim * nodes_per_background_e, "disp_elem");
+
+    FEEngine::extractNodalToElementField(
+        emodel.getMesh(), emodel.getDisplacement(), disp_per_element, bg_type,
+        ghost_type, filter);
+
+    Matrix<Real> concrete_du(dim, dim);
+    Matrix<Real> epsilon(dim, dim);
+    Vector<Real> evoigt(voigt_size);
+
+    for (auto && tuple :
+         zip(make_view(disp_per_element, dim, nodes_per_background_e),
+             make_view(bg_shapesd, dim, nodes_per_background_e),
+             this->gradu(interface_type, ghost_type),
+             make_view(this->directing_cosines(interface_type, ghost_type),
+                       voigt_size))) {
+      auto & u = std::get<0>(tuple);
+      auto & B = std::get<1>(tuple);
+      auto & du = std::get<2>(tuple);
+      auto & C = std::get<3>(tuple);
+
+      concrete_du.mul<false, true>(u, B);
+      auto epsilon = 0.5 * (concrete_du + concrete_du.transpose());
+      strainTensorToVoigtVector(epsilon, evoigt);
+      du = C.dot(evoigt);
+    }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * The structure of the directing cosines matrix is :
+ * \f{eqnarray*}{
+ *  C_{1,\cdot} & = & (l^2, m^2, n^2, mn, ln, lm) \\
+ *  C_{i,j} & = & 0
+ * \f}
+ *
+ * with :
+ * \f[
+ * (l, m, n) = \frac{1}{\|\frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}\|} \cdot
+ * \frac{\mathrm{d}\vec{r}(s)}{\mathrm{d}s}
+ * \f]
+ */
+template <class Mat, UInt dim>
+inline void MaterialReinforcement<Mat, dim>::computeDirectingCosinesOnQuad(
+    const Matrix<Real> & nodes, Matrix<Real> & cosines) {
+  AKANTU_DEBUG_IN();
+
+  AKANTU_DEBUG_ASSERT(nodes.cols() == 2,
+                      "Higher order reinforcement elements not implemented");
+
+  const Vector<Real> a = nodes(0), b = nodes(1);
+  Vector<Real> delta = b - a;
+
+  Real sq_length = 0.;
+  for (UInt i = 0; i < dim; i++) {
+    sq_length += delta(i) * delta(i);
+  }
+
+  if (dim == 2) {
+    cosines(0, 0) = delta(0) * delta(0); // l^2
+    cosines(0, 1) = delta(1) * delta(1); // m^2
+    cosines(0, 2) = delta(0) * delta(1); // lm
+  } else if (dim == 3) {
+    cosines(0, 0) = delta(0) * delta(0); // l^2
+    cosines(0, 1) = delta(1) * delta(1); // m^2
+    cosines(0, 2) = delta(2) * delta(2); // n^2
+
+    cosines(0, 3) = delta(1) * delta(2); // mn
+    cosines(0, 4) = delta(0) * delta(2); // ln
+    cosines(0, 5) = delta(0) * delta(1); // lm
+  }
+
+  cosines /= sq_length;
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+inline void MaterialReinforcement<Mat, dim>::stressTensorToVoigtVector(
+    const Matrix<Real> & tensor, Vector<Real> & vector) {
+  AKANTU_DEBUG_IN();
+
+  for (UInt i = 0; i < dim; i++) {
+    vector(i) = tensor(i, i);
+  }
+
+  if (dim == 2) {
+    vector(2) = tensor(0, 1);
+  } else if (dim == 3) {
+    vector(3) = tensor(1, 2);
+    vector(4) = tensor(0, 2);
+    vector(5) = tensor(0, 1);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <class Mat, UInt dim>
+inline void MaterialReinforcement<Mat, dim>::strainTensorToVoigtVector(
+    const Matrix<Real> & tensor, Vector<Real> & vector) {
+  AKANTU_DEBUG_IN();
+
+  for (UInt i = 0; i < dim; i++) {
+    vector(i) = tensor(i, i);
+  }
+
+  if (dim == 2) {
+    vector(2) = 2 * tensor(0, 1);
+  } else if (dim == 3) {
+    vector(3) = 2 * tensor(1, 2);
+    vector(4) = 2 * tensor(0, 2);
+    vector(5) = 2 * tensor(0, 1);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+} // akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc
index 61d01bcbd..5780ec6e0 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/constitutive_laws/material_cohesive_linear.cc
@@ -1,653 +1,651 @@
 /**
  * @file   material_cohesive_linear.cc
  *
  * @author Mauro Corrado <mauro.corrado@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Wed Feb 22 2012
  * @date last modification: Thu Jan 14 2016
  *
  * @brief  Linear irreversible cohesive law of mixed mode loading with
  * random stress definition for extrinsic type
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include <algorithm>
 #include <numeric>
 
 /* -------------------------------------------------------------------------- */
 #include "dof_synchronizer.hh"
 #include "material_cohesive_linear.hh"
 #include "solid_mechanics_model_cohesive.hh"
 #include "sparse_matrix.hh"
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 MaterialCohesiveLinear<spatial_dimension>::MaterialCohesiveLinear(
     SolidMechanicsModel & model, const ID & id)
     : MaterialCohesive(model, id), sigma_c_eff("sigma_c_eff", *this),
       delta_c_eff("delta_c_eff", *this),
       insertion_stress("insertion_stress", *this),
       opening_prec("opening_prec", *this),
       reduction_penalty("reduction_penalty", *this) {
   AKANTU_DEBUG_IN();
 
   this->registerParam("beta", beta, Real(0.), _pat_parsable | _pat_readable,
                       "Beta parameter");
 
   this->registerParam("G_c", G_c, Real(0.), _pat_parsable | _pat_readable,
                       "Mode I fracture energy");
 
   this->registerParam("penalty", penalty, Real(0.),
                       _pat_parsable | _pat_readable, "Penalty coefficient");
 
   this->registerParam("volume_s", volume_s, Real(0.),
                       _pat_parsable | _pat_readable,
                       "Reference volume for sigma_c scaling");
 
   this->registerParam("m_s", m_s, Real(1.), _pat_parsable | _pat_readable,
                       "Weibull exponent for sigma_c scaling");
 
   this->registerParam("kappa", kappa, Real(1.), _pat_parsable | _pat_readable,
                       "Kappa parameter");
 
   this->registerParam(
       "contact_after_breaking", contact_after_breaking, false,
       _pat_parsable | _pat_readable,
       "Activation of contact when the elements are fully damaged");
 
   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");
 
   this->registerParam("recompute", recompute, false,
                       _pat_parsable | _pat_modifiable, "recompute solution");
 
   this->use_previous_delta_max = true;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialCohesiveLinear<spatial_dimension>::initMaterial() {
   AKANTU_DEBUG_IN();
 
   MaterialCohesive::initMaterial();
 
   /// compute scalars
   beta2_kappa2 = beta * beta / kappa / kappa;
   beta2_kappa = beta * beta / kappa;
 
   if (Math::are_float_equal(beta, 0))
     beta2_inv = 0;
   else
     beta2_inv = 1. / beta / beta;
 
   sigma_c_eff.initialize(1);
   delta_c_eff.initialize(1);
   insertion_stress.initialize(spatial_dimension);
   opening_prec.initialize(spatial_dimension);
   reduction_penalty.initialize(1);
 
   if (!Math::are_float_equal(delta_c, 0.))
     delta_c_eff.setDefaultValue(delta_c);
   else
     delta_c_eff.setDefaultValue(2 * G_c / sigma_c);
 
   if (model->getIsExtrinsic())
     scaleInsertionTraction();
   opening_prec.initializeHistory();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialCohesiveLinear<spatial_dimension>::scaleInsertionTraction() {
   AKANTU_DEBUG_IN();
 
   // do nothing if volume_s hasn't been specified by the user
   if (Math::are_float_equal(volume_s, 0.))
     return;
 
   const Mesh & mesh_facets = model->getMeshFacets();
   const FEEngine & fe_engine = model->getFEEngine();
   const FEEngine & fe_engine_facet = model->getFEEngine("FacetsFEEngine");
 
   // loop over facet type
   Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1);
   Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1);
 
   Real base_sigma_c = sigma_c;
 
   for (; first != last; ++first) {
     ElementType type_facet = *first;
 
     const Array<std::vector<Element>> & facet_to_element =
         mesh_facets.getElementToSubelement(type_facet);
 
     UInt nb_facet = facet_to_element.size();
     UInt nb_quad_per_facet = fe_engine_facet.getNbIntegrationPoints(type_facet);
 
     // iterator to modify sigma_c for all the quadrature points of a facet
     Array<Real>::vector_iterator sigma_c_iterator =
         sigma_c(type_facet).begin_reinterpret(nb_quad_per_facet, nb_facet);
 
     for (UInt f = 0; f < nb_facet; ++f, ++sigma_c_iterator) {
 
       const std::vector<Element> & element_list = facet_to_element(f);
 
       // compute bounding volume
       Real volume = 0;
 
       auto elem = element_list.begin();
       auto elem_end = element_list.end();
 
       for (; elem != elem_end; ++elem) {
         if (*elem == ElementNull)
           continue;
 
         // unit vector for integration in order to obtain the volume
         UInt nb_quadrature_points =
             fe_engine.getNbIntegrationPoints(elem->type);
         Vector<Real> unit_vector(nb_quadrature_points, 1);
 
         volume += fe_engine.integrate(unit_vector, elem->type, elem->element,
                                       elem->ghost_type);
       }
 
       // scale sigma_c
       *sigma_c_iterator -= base_sigma_c;
       *sigma_c_iterator *= std::pow(volume_s / volume, 1. / m_s);
       *sigma_c_iterator += base_sigma_c;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialCohesiveLinear<spatial_dimension>::checkInsertion(
     bool check_only) {
   AKANTU_DEBUG_IN();
 
   const Mesh & mesh_facets = model->getMeshFacets();
   CohesiveElementInserter & inserter = model->getElementInserter();
 
-  Real tolerance = Math::getTolerance();
-
   for (auto && type_facet : mesh_facets.elementTypes(spatial_dimension - 1)) {
     ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet);
     const Array<bool> & facets_check = inserter.getCheckFacets(type_facet);
     auto & f_insertion = inserter.getInsertionFacets(type_facet);
     auto & f_filter = facet_filter(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_old(type_cohesive);
+    auto & trac_old = tractions.previous(type_cohesive);
     auto & open_prec = opening_prec(type_cohesive);
     auto & red_penalty = reduction_penalty(type_cohesive);
     const auto & f_stress = model->getStressOnFacets(type_facet);
     const auto & sigma_lim = sigma_c(type_facet);
     Real max_ratio = 0.;
     UInt index_f = 0;
     UInt index_filter = 0;
     UInt nn = 0;
 
     UInt nb_quad_facet =
         model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet);
     UInt 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");
 
     UInt nb_facet = f_filter.size();
     //  if (nb_facet == 0) continue;
 
     auto sigma_lim_it = sigma_lim.begin();
 
     Matrix<Real> stress_tmp(spatial_dimension, spatial_dimension);
     Matrix<Real> normal_traction(spatial_dimension, nb_quad_facet);
     Vector<Real> stress_check(nb_quad_facet);
     UInt sp2 = spatial_dimension * spatial_dimension;
 
     const auto & tangents = model->getTangents(type_facet);
     const auto & normals = model->getFEEngine("FacetsFEEngine")
                                .getNormalsOnIntegrationPoints(type_facet);
     auto normal_begin = normals.begin(spatial_dimension);
     auto tangent_begin = tangents.begin(tangents.getNbComponent());
     auto facet_stress_begin =
         f_stress.begin(spatial_dimension, spatial_dimension * 2);
 
     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 (UInt f = 0; f < nb_facet; ++f, ++sigma_lim_it) {
       UInt facet = f_filter(f);
       // 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 (UInt q = 0; q < nb_quad_facet; ++q) {
         UInt current_quad = facet * nb_quad_facet + q;
         const Vector<Real> & normal = normal_begin[current_quad];
         const Vector<Real> & tangent = tangent_begin[current_quad];
         const Matrix<Real> & facet_stress_it = facet_stress_begin[current_quad];
 
         // compute average stress on the current quadrature point
         Matrix<Real> stress_1(facet_stress_it.storage(), spatial_dimension,
                               spatial_dimension);
 
         Matrix<Real> stress_2(facet_stress_it.storage() + sp2,
                               spatial_dimension, spatial_dimension);
 
         stress_tmp.copy(stress_1);
         stress_tmp += stress_2;
         stress_tmp /= 2.;
 
         Vector<Real> normal_traction_vec(normal_traction(q));
 
         // compute normal and effective stress
         stress_check(q) = computeEffectiveNorm(stress_tmp, normal, tangent,
                                                normal_traction_vec);
       }
 
       // verify if the effective stress overcomes the threshold
       Real final_stress = stress_check.mean();
       if (max_quad_stress_insertion)
         final_stress = *std::max_element(
             stress_check.storage(), stress_check.storage() + nb_quad_facet);
 
-      if (final_stress > (*sigma_lim_it - tolerance)) {
+      if (final_stress > *sigma_lim_it) {
         if (model->isDefaultSolverExplicit()) {
           f_insertion(facet) = true;
 
           if (check_only)
             continue;
 
           // store the new cohesive material parameters for each quadrature
           // point
           for (UInt q = 0; q < nb_quad_facet; ++q) {
             Real new_sigma = stress_check(q);
             Vector<Real> normal_traction_vec(normal_traction(q));
 
             if (spatial_dimension != 3)
               normal_traction_vec *= -1.;
 
             new_sigmas.push_back(new_sigma);
             new_normal_traction.push_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_lim_it) / new_sigma * delta_c;
 
             new_delta_c.push_back(new_delta);
           }
 
         } else {
           Real ratio = final_stress / (*sigma_lim_it);
           if (ratio > max_ratio) {
             ++nn;
             max_ratio = ratio;
             index_f = f;
             index_filter = f_filter(f);
           }
         }
       }
     }
 
     /// Insertion of only 1 cohesive element in case of implicit approach. The
     /// one subjected to the highest stress.
     if (!model->isDefaultSolverExplicit()) {
       const Communicator & comm = model->getMesh().getCommunicator();
       Array<Real> abs_max(comm.getNbProc());
       abs_max(comm.whoAmI()) = max_ratio;
       comm.allGather(abs_max);
 
       auto it = std::max_element(abs_max.begin(), abs_max.end());
       Int pos = it - abs_max.begin();
 
       if (pos != comm.whoAmI()) {
         AKANTU_DEBUG_OUT();
         return;
       }
 
       if (nn) {
         f_insertion(index_filter) = true;
 
         if (!check_only) {
           //  Array<Real>::iterator<Matrix<Real> > normal_traction_it =
           //  normal_traction.begin_reinterpret(nb_quad_facet,
           //  spatial_dimension, nb_facet);
           Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin();
 
           for (UInt q = 0; q < nb_quad_cohesive; ++q) {
 
             Real new_sigma = (sigma_lim_it[index_f]);
             Vector<Real> normal_traction_vec(spatial_dimension, 0.0);
 
             new_sigmas.push_back(new_sigma);
             new_normal_traction.push_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 = delta_c;
             else
               new_delta = 2 * G_c / (new_sigma);
 
             new_delta_c.push_back(new_delta);
           }
         }
       }
     }
 
     // update material data for the new elements
     UInt old_nb_quad_points = sig_c_eff.size();
     UInt new_nb_quad_points = 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);
     open_prec.resize(old_nb_quad_points + new_nb_quad_points);
     red_penalty.resize(old_nb_quad_points + new_nb_quad_points);
 
     for (UInt 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];
       red_penalty(old_nb_quad_points + q) = false;
       for (UInt dim = 0; dim < spatial_dimension; ++dim) {
         ins_stress(old_nb_quad_points + q, dim) = new_normal_traction[q](dim);
         trac_old(old_nb_quad_points + q, dim) = new_normal_traction[q](dim);
         open_prec(old_nb_quad_points + q, dim) = 0.;
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialCohesiveLinear<spatial_dimension>::computeTraction(
     const Array<Real> & normal, ElementType el_type, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   /// define iterators
   auto traction_it = tractions(el_type, ghost_type).begin(spatial_dimension);
   auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension);
   /// opening_prec is the opening of the previous step in the
   /// Newton-Raphson loop
   auto opening_prec_it =
       opening_prec(el_type, ghost_type).begin(spatial_dimension);
 
   auto contact_traction_it =
       contact_tractions(el_type, ghost_type).begin(spatial_dimension);
   auto contact_opening_it =
       contact_opening(el_type, ghost_type).begin(spatial_dimension);
 
   auto normal_it = normal.begin(spatial_dimension);
   auto traction_end = tractions(el_type, ghost_type).end(spatial_dimension);
   auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin();
   auto delta_max_it = delta_max(el_type, ghost_type).begin();
   auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin();
   auto delta_c_it = delta_c_eff(el_type, ghost_type).begin();
   auto damage_it = damage(el_type, ghost_type).begin();
   auto insertion_stress_it =
       insertion_stress(el_type, ghost_type).begin(spatial_dimension);
   auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin();
 
   Vector<Real> normal_opening(spatial_dimension);
   Vector<Real> tangential_opening(spatial_dimension);
 
   if (!this->model->isDefaultSolverExplicit())
     this->delta_max(el_type, ghost_type)
         .copy(this->delta_max.previous(el_type, ghost_type));
 
   /// loop on each quadrature point
   for (; traction_it != traction_end;
        ++traction_it, ++opening_it, ++opening_prec_it, ++normal_it,
        ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it,
        ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it,
        ++delta_max_prev_it, ++reduction_penalty_it) {
 
     Real normal_opening_norm, tangential_opening_norm;
     bool penetration;
     Real current_penalty = 0.;
     this->computeTractionOnQuad(
         *traction_it, *delta_max_it, *delta_max_prev_it, *delta_c_it,
         *insertion_stress_it, *sigma_c_it, *opening_it, *opening_prec_it,
         *normal_it, normal_opening, tangential_opening, normal_opening_norm,
         tangential_opening_norm, *damage_it, penetration, *reduction_penalty_it,
         current_penalty, *contact_traction_it, *contact_opening_it);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialCohesiveLinear<spatial_dimension>::checkDeltaMax(
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   /**
   * This function set a predefined value to the parameter
   * delta_max_prev of the elements that have been inserted in the
   * last loading step for which convergence has not been
   * reached. This is done before reducing the loading and re-doing
   * the step.  Otherwise, the updating of delta_max_prev would be
   * done with reference to the non-convergent solution. In this
   * function also other variables related to the contact and
   * friction behavior are correctly set.
   */
 
   Mesh & mesh = fem_cohesive.getMesh();
   Mesh::type_iterator it =
       mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive);
   Mesh::type_iterator last_type =
       mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive);
 
   /**
   * the variable "recompute" is set to true to activate the
   * procedure that reduce the penalty parameter for
   * compression. This procedure is set true only during the phase of
   * load_reduction, that has to be set in the maiin file. The
   * penalty parameter will be reduced only for the elements having
   * reduction_penalty = true.
   */
   recompute = true;
 
   for (; it != last_type; ++it) {
     Array<UInt> & elem_filter = element_filter(*it, ghost_type);
 
     UInt nb_element = elem_filter.size();
     if (nb_element == 0)
       continue;
 
     ElementType el_type = *it;
 
     /// define iterators
     auto delta_max_it = delta_max(el_type, ghost_type).begin();
     auto delta_max_end = delta_max(el_type, ghost_type).end();
     auto delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin();
     auto delta_c_it = delta_c_eff(el_type, ghost_type).begin();
     auto opening_prec_it =
         opening_prec(el_type, ghost_type).begin(spatial_dimension);
     auto opening_prec_prev_it =
         opening_prec.previous(el_type, ghost_type).begin(spatial_dimension);
 
     /// loop on each quadrature point
     for (; delta_max_it != delta_max_end; ++delta_max_it, ++delta_max_prev_it,
                                           ++delta_c_it, ++opening_prec_it,
                                           ++opening_prec_prev_it) {
 
       if (*delta_max_prev_it == 0)
         /// elements inserted in the last incremental step, that did
         /// not converge
         *delta_max_it = *delta_c_it / 1000;
       else
         /// elements introduced in previous incremental steps, for
         /// which a correct value of delta_max_prev already exists
         *delta_max_it = *delta_max_prev_it;
 
       /// in case convergence is not reached, set opening_prec to the
       /// value referred to the previous incremental step
       *opening_prec_it = *opening_prec_prev_it;
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialCohesiveLinear<spatial_dimension>::resetVariables(
     GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   /**
   * This function set the variables "recompute" and
   * "reduction_penalty" to false. It is called by solveStepCohesive
   * when convergence is reached. Such variables, in fact, have to be
   * false at the beginning of a new incremental step.
   */
 
   Mesh & mesh = fem_cohesive.getMesh();
   Mesh::type_iterator it =
       mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive);
   Mesh::type_iterator last_type =
       mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive);
 
   recompute = false;
 
   for (; it != last_type; ++it) {
     Array<UInt> & elem_filter = element_filter(*it, ghost_type);
 
     UInt nb_element = elem_filter.size();
     if (nb_element == 0)
       continue;
 
     ElementType el_type = *it;
 
     auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin();
     auto reduction_penalty_end = reduction_penalty(el_type, ghost_type).end();
 
     /// loop on each quadrature point
     for (; reduction_penalty_it != reduction_penalty_end;
          ++reduction_penalty_it) {
 
       *reduction_penalty_it = false;
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialCohesiveLinear<spatial_dimension>::computeTangentTraction(
     const ElementType & el_type, Array<Real> & tangent_matrix,
     const Array<Real> & normal, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   /// define iterators
   auto tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension);
 
   auto tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension);
 
   auto normal_it = normal.begin(spatial_dimension);
 
   auto opening_it = opening(el_type, ghost_type).begin(spatial_dimension);
 
   /// NB: delta_max_it points on delta_max_previous, i.e. the
   /// delta_max related to the solution of the previous incremental
   /// step
   auto delta_max_it = delta_max.previous(el_type, ghost_type).begin();
 
   auto sigma_c_it = sigma_c_eff(el_type, ghost_type).begin();
 
   auto delta_c_it = delta_c_eff(el_type, ghost_type).begin();
 
   auto damage_it = damage(el_type, ghost_type).begin();
 
   auto contact_opening_it =
       contact_opening(el_type, ghost_type).begin(spatial_dimension);
 
   auto reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin();
 
   Vector<Real> normal_opening(spatial_dimension);
   Vector<Real> tangential_opening(spatial_dimension);
 
   for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it,
                                     ++delta_max_it, ++sigma_c_it, ++delta_c_it,
                                     ++damage_it, ++contact_opening_it,
                                     ++reduction_penalty_it) {
 
     Real normal_opening_norm, tangential_opening_norm;
     bool penetration;
     Real current_penalty = 0.;
     this->computeTangentTractionOnQuad(
         *tangent_it, *delta_max_it, *delta_c_it, *sigma_c_it, *opening_it,
         *normal_it, normal_opening, tangential_opening, normal_opening_norm,
         tangential_opening_norm, *damage_it, penetration, *reduction_penalty_it,
         current_penalty, *contact_opening_it);
 
     // check if the tangential stiffness matrix is symmetric
     //    for (UInt h = 0; h < spatial_dimension; ++h){
     //      for (UInt l = h; l < spatial_dimension; ++l){
     //        if (l > h){
     //          Real k_ls = (*tangent_it)[spatial_dimension*h+l];
     //          Real k_us =  (*tangent_it)[spatial_dimension*l+h];
     //          //          std::cout << "k_ls = " << k_ls << std::endl;
     //          //          std::cout << "k_us = " << k_us << std::endl;
     //          if (std::abs(k_ls) > 1e-13 && std::abs(k_us) > 1e-13){
     //            Real error = std::abs((k_ls - k_us) / k_us);
     //            if (error > 1e-10){
     //	      std::cout << "non symmetric cohesive matrix" << std::endl;
     //	      //  std::cout << "error " << error << std::endl;
     //            }
     //          }
     //        }
     //      }
     //    }
   }
 
   AKANTU_DEBUG_OUT();
 }
 /* -------------------------------------------------------------------------- */
 
 INSTANTIATE_MATERIAL(cohesive_linear, MaterialCohesiveLinear);
 
 } // akantu
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 de473fdf3..130bf7a92 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
@@ -1,581 +1,572 @@
 /**
  * @file   material_cohesive.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Wed Feb 22 2012
  * @date last modification: Tue Jan 12 2016
  *
  * @brief  Specialization of the material class for cohesive elements
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "material_cohesive.hh"
 #include "aka_random_generator.hh"
 #include "dof_synchronizer.hh"
 #include "fe_engine_template.hh"
 #include "integrator_gauss.hh"
 #include "shape_cohesive.hh"
 #include "solid_mechanics_model_cohesive.hh"
 #include "sparse_matrix.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 MaterialCohesive::MaterialCohesive(SolidMechanicsModel & model, const ID & id)
     : Material(model, id),
       facet_filter("facet_filter", id, this->getMemoryID()),
       fem_cohesive(
           model.getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine")),
       reversible_energy("reversible_energy", *this),
       total_energy("total_energy", *this), opening("opening", *this),
-      opening_old("opening (old)", *this), tractions("tractions", *this),
-      tractions_old("tractions (old)", *this),
+      tractions("tractions", *this),
       contact_tractions("contact_tractions", *this),
       contact_opening("contact_opening", *this), delta_max("delta max", *this),
       use_previous_delta_max(false), use_previous_opening(false),
       damage("damage", *this), sigma_c("sigma_c", *this),
       normal(0, spatial_dimension, "normal") {
 
   AKANTU_DEBUG_IN();
 
   this->model = dynamic_cast<SolidMechanicsModelCohesive *>(&model);
 
   this->registerParam("sigma_c", sigma_c, _pat_parsable | _pat_readable,
                       "Critical stress");
   this->registerParam("delta_c", delta_c, Real(0.),
                       _pat_parsable | _pat_readable, "Critical displacement");
 
   this->element_filter.initialize(this->model->getMesh(),
                                   _spatial_dimension = spatial_dimension,
                                   _element_kind = _ek_cohesive);
   // this->model->getMesh().initElementTypeMapArray(
   //     this->element_filter, 1, spatial_dimension, false, _ek_cohesive);
 
   if (this->model->getIsExtrinsic())
     this->facet_filter.initialize(this->model->getMeshFacets(),
                                   _spatial_dimension = spatial_dimension - 1,
                                   _element_kind = _ek_regular);
   // this->model->getMeshFacets().initElementTypeMapArray(facet_filter, 1,
   //                                                      spatial_dimension -
   //                                                      1);
 
   this->reversible_energy.initialize(1);
   this->total_energy.initialize(1);
-  this->tractions_old.initialize(spatial_dimension);
+
   this->tractions.initialize(spatial_dimension);
-  this->opening_old.initialize(spatial_dimension);
+  this->tractions.initializeHistory();
+
   this->contact_tractions.initialize(spatial_dimension);
   this->contact_opening.initialize(spatial_dimension);
+
   this->opening.initialize(spatial_dimension);
+  this->opening.initializeHistory();
+
   this->delta_max.initialize(1);
   this->damage.initialize(1);
 
   if (this->model->getIsExtrinsic())
     this->sigma_c.initialize(1);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 MaterialCohesive::~MaterialCohesive() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MaterialCohesive::initMaterial() {
   AKANTU_DEBUG_IN();
   Material::initMaterial();
   if (this->use_previous_delta_max)
     this->delta_max.initializeHistory();
   if (this->use_previous_opening)
     this->opening.initializeHistory();
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MaterialCohesive::assembleInternalForces(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
 #if defined(AKANTU_DEBUG_TOOLS)
   debug::element_manager.printData(debug::_dm_material_cohesive,
                                    "Cohesive Tractions", tractions);
 #endif
 
   auto & internal_force = const_cast<Array<Real> &>(model->getInternalForce());
 
   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type,
                                                _ek_cohesive)) {
     auto & elem_filter = element_filter(type, ghost_type);
     UInt nb_element = elem_filter.size();
     if (nb_element == 0)
       continue;
 
     const auto & shapes = fem_cohesive.getShapes(type, ghost_type);
     auto & traction = tractions(type, ghost_type);
     auto & contact_traction = contact_tractions(type, ghost_type);
 
     UInt size_of_shapes = shapes.getNbComponent();
     UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
     UInt nb_quadrature_points =
         fem_cohesive.getNbIntegrationPoints(type, ghost_type);
 
     /// compute @f$t_i N_a@f$
 
     Array<Real> * traction_cpy = new Array<Real>(
         nb_element * nb_quadrature_points, spatial_dimension * size_of_shapes);
 
     auto traction_it = traction.begin(spatial_dimension, 1);
     auto contact_traction_it = contact_traction.begin(spatial_dimension, 1);
     auto shapes_filtered_begin = shapes.begin(1, size_of_shapes);
     auto traction_cpy_it =
         traction_cpy->begin(spatial_dimension, size_of_shapes);
 
     Matrix<Real> traction_tmp(spatial_dimension, 1);
 
     for (UInt el = 0; el < nb_element; ++el) {
 
       UInt current_quad = elem_filter(el) * nb_quadrature_points;
 
       for (UInt q = 0; q < nb_quadrature_points; ++q, ++traction_it,
                 ++contact_traction_it, ++current_quad, ++traction_cpy_it) {
 
         const Matrix<Real> & shapes_filtered =
             shapes_filtered_begin[current_quad];
 
         traction_tmp.copy(*traction_it);
         traction_tmp += *contact_traction_it;
 
         traction_cpy_it->mul<false, false>(traction_tmp, shapes_filtered);
       }
     }
 
     /**
      * compute @f$\int t \cdot N\, dS@f$ by  @f$ \sum_q \mathbf{N}^t
      * \mathbf{t}_q \overline w_q J_q@f$
      */
     Array<Real> * int_t_N = new Array<Real>(
         nb_element, spatial_dimension * size_of_shapes, "int_t_N");
 
     fem_cohesive.integrate(*traction_cpy, *int_t_N,
                            spatial_dimension * size_of_shapes, type, ghost_type,
                            elem_filter);
 
     delete traction_cpy;
 
     int_t_N->extendComponentsInterlaced(2, int_t_N->getNbComponent());
 
     Real * int_t_N_val = int_t_N->storage();
     for (UInt el = 0; el < nb_element; ++el) {
       for (UInt n = 0; n < size_of_shapes * spatial_dimension; ++n)
         int_t_N_val[n] *= -1.;
       int_t_N_val += nb_nodes_per_element * spatial_dimension;
     }
 
     /// assemble
     model->getDOFManager().assembleElementalArrayLocalArray(
         *int_t_N, internal_force, type, ghost_type, -1, elem_filter);
 
     delete int_t_N;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) {
 
   AKANTU_DEBUG_IN();
 
   for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type,
                                                _ek_cohesive)) {
     UInt nb_quadrature_points =
         fem_cohesive.getNbIntegrationPoints(type, ghost_type);
     UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 
     const Array<Real> & shapes = fem_cohesive.getShapes(type, ghost_type);
     Array<UInt> & elem_filter = element_filter(type, ghost_type);
 
     UInt nb_element = elem_filter.size();
 
     if (!nb_element)
       continue;
 
     UInt size_of_shapes = shapes.getNbComponent();
 
     Array<Real> * shapes_filtered = new Array<Real>(
         nb_element * nb_quadrature_points, size_of_shapes, "filtered shapes");
 
     Real * shapes_filtered_val = shapes_filtered->storage();
     UInt * elem_filter_val = elem_filter.storage();
 
     for (UInt el = 0; el < nb_element; ++el) {
-      auto shapes_val = shapes.storage() +
-                   elem_filter_val[el] * size_of_shapes * nb_quadrature_points;
+      auto shapes_val =
+          shapes.storage() +
+          elem_filter_val[el] * size_of_shapes * nb_quadrature_points;
       memcpy(shapes_filtered_val, shapes_val,
              size_of_shapes * nb_quadrature_points * sizeof(Real));
       shapes_filtered_val += size_of_shapes * nb_quadrature_points;
     }
 
     /**
      * compute A matrix @f$ \mathbf{A} = \left[\begin{array}{c c c c c c c c c c
      *c c}
      * 1 & 0 & 0 & 0 & 0 & 0 & -1 &  0 &  0 &  0 &  0 &  0 \\
      * 0 & 1 & 0 & 0 & 0 & 0 &  0 & -1 &  0 &  0 &  0 &  0 \\
      * 0 & 0 & 1 & 0 & 0 & 0 &  0 &  0 & -1 &  0 &  0 &  0 \\
      * 0 & 0 & 0 & 1 & 0 & 0 &  0 &  0 &  0 & -1 &  0 &  0 \\
      * 0 & 0 & 0 & 0 & 1 & 0 &  0 &  0 &  0 &  0 & -1 &  0 \\
      * 0 & 0 & 0 & 0 & 0 & 1 &  0 &  0 &  0 &  0 &  0 & -1
      * \end{array} \right]@f$
      **/
 
     // UInt size_of_A =
     // spatial_dimension*size_of_shapes*spatial_dimension*nb_nodes_per_element;
     // Real * A = new Real[size_of_A];
     // memset(A, 0, size_of_A*sizeof(Real));
     Matrix<Real> A(spatial_dimension * size_of_shapes,
                    spatial_dimension * nb_nodes_per_element);
 
     for (UInt i = 0; i < spatial_dimension * size_of_shapes; ++i) {
       A(i, i) = 1;
       A(i, i + spatial_dimension * size_of_shapes) = -1;
     }
 
     // compute traction. This call is not necessary for the linear
     // cohesive law that, currently, is the only one used for the
     // extrinsic approach.
     //    if (!model->getIsExtrinsic()){
     //  computeTraction(ghost_type);
     //}
 
     /// get the tangent matrix @f$\frac{\partial{(t/\delta)}}{\partial{\delta}}
     /// @f$
     Array<Real> * tangent_stiffness_matrix = new Array<Real>(
         nb_element * nb_quadrature_points,
         spatial_dimension * spatial_dimension, "tangent_stiffness_matrix");
 
     //    Array<Real> * normal = new Array<Real>(nb_element *
     //    nb_quadrature_points, spatial_dimension, "normal");
     normal.resize(nb_quadrature_points);
 
     computeNormal(model->getCurrentPosition(), normal, type, ghost_type);
 
     /// compute openings @f$\mathbf{\delta}@f$
     // computeOpening(model->getDisplacement(), opening(type, ghost_type), type,
     // ghost_type);
 
     tangent_stiffness_matrix->clear();
 
     computeTangentTraction(type, *tangent_stiffness_matrix, normal, ghost_type);
 
     // delete normal;
 
     UInt size_at_nt_d_n_a = spatial_dimension * nb_nodes_per_element *
                             spatial_dimension * nb_nodes_per_element;
     Array<Real> * at_nt_d_n_a = new Array<Real>(
         nb_element * nb_quadrature_points, size_at_nt_d_n_a, "A^t*N^t*D*N*A");
 
     Array<Real>::iterator<Vector<Real>> shapes_filt_it =
         shapes_filtered->begin(size_of_shapes);
 
     Array<Real>::matrix_iterator D_it =
         tangent_stiffness_matrix->begin(spatial_dimension, spatial_dimension);
 
     Array<Real>::matrix_iterator At_Nt_D_N_A_it =
         at_nt_d_n_a->begin(spatial_dimension * nb_nodes_per_element,
                            spatial_dimension * nb_nodes_per_element);
 
     Array<Real>::matrix_iterator At_Nt_D_N_A_end =
         at_nt_d_n_a->end(spatial_dimension * nb_nodes_per_element,
                          spatial_dimension * nb_nodes_per_element);
 
     Matrix<Real> N(spatial_dimension, spatial_dimension * size_of_shapes);
     Matrix<Real> N_A(spatial_dimension,
                      spatial_dimension * nb_nodes_per_element);
     Matrix<Real> D_N_A(spatial_dimension,
                        spatial_dimension * nb_nodes_per_element);
 
     for (; At_Nt_D_N_A_it != At_Nt_D_N_A_end;
          ++At_Nt_D_N_A_it, ++D_it, ++shapes_filt_it) {
       N.clear();
       /**
        * store  the   shapes  in  voigt   notations  matrix  @f$\mathbf{N}  =
        * \begin{array}{cccccc} N_0(\xi) & 0 & N_1(\xi)  &0 & N_2(\xi) & 0 \\
        * 0 & * N_0(\xi)& 0 &N_1(\xi)& 0 & N_2(\xi) \end{array} @f$
        **/
       for (UInt i = 0; i < spatial_dimension; ++i)
         for (UInt n = 0; n < size_of_shapes; ++n)
           N(i, i + spatial_dimension * n) = (*shapes_filt_it)(n);
 
       /**
        * compute stiffness matrix  @f$   \mathbf{K}    =    \delta \mathbf{U}^T
        * \int_{\Gamma_c}    {\mathbf{P}^t \frac{\partial{\mathbf{t}}}
        *{\partial{\delta}}
        * \mathbf{P} d\Gamma \Delta \mathbf{U}}  @f$
        **/
       N_A.mul<false, false>(N, A);
       D_N_A.mul<false, false>(*D_it, N_A);
       (*At_Nt_D_N_A_it).mul<true, false>(D_N_A, N_A);
     }
 
     delete tangent_stiffness_matrix;
     delete shapes_filtered;
 
     Array<Real> * K_e = new Array<Real>(nb_element, size_at_nt_d_n_a, "K_e");
 
     fem_cohesive.integrate(*at_nt_d_n_a, *K_e, size_at_nt_d_n_a, type,
                            ghost_type, elem_filter);
 
     delete at_nt_d_n_a;
 
     model->getDOFManager().assembleElementalMatricesToMatrix(
         "K", "displacement", *K_e, type, ghost_type, _unsymmetric, elem_filter);
 
     delete K_e;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- *
  * Compute traction from displacements
  *
  * @param[in] ghost_type compute the residual for _ghost or _not_ghost element
  */
 void MaterialCohesive::computeTraction(GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
 #if defined(AKANTU_DEBUG_TOOLS)
   debug::element_manager.printData(debug::_dm_material_cohesive,
                                    "Cohesive Openings", opening);
 #endif
 
   for (auto & type : element_filter.elementTypes(spatial_dimension, ghost_type,
                                                  _ek_cohesive)) {
     Array<UInt> & elem_filter = element_filter(type, ghost_type);
 
     UInt nb_element = elem_filter.size();
     if (nb_element == 0)
       continue;
 
     UInt nb_quadrature_points =
         nb_element * fem_cohesive.getNbIntegrationPoints(type, ghost_type);
 
     normal.resize(nb_quadrature_points);
 
     /// compute normals @f$\mathbf{n}@f$
     computeNormal(model->getCurrentPosition(), normal, type, 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(normal, type, ghost_type);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MaterialCohesive::computeNormal(const Array<Real> & position,
                                      Array<Real> & normal, ElementType type,
                                      GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   auto & fem_cohesive =
       this->model->getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine");
 
-  if (type == _cohesive_1d_2)
-    fem_cohesive.computeNormalsOnIntegrationPoints(position, normal, type,
-                                                   ghost_type);
-  else {
 #define COMPUTE_NORMAL(type)                                                   \
   fem_cohesive.getShapeFunctions()                                             \
       .computeNormalsOnIntegrationPoints<type, CohesiveReduceFunctionMean>(    \
           position, normal, ghost_type, element_filter(type, ghost_type));
 
     AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_NORMAL);
 #undef COMPUTE_NORMAL
-  }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void MaterialCohesive::computeOpening(const Array<Real> & displacement,
                                       Array<Real> & opening, ElementType type,
                                       GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   auto & fem_cohesive =
       this->model->getFEEngineClass<MyFEEngineCohesiveType>("CohesiveFEEngine");
 
 #define COMPUTE_OPENING(type)                                                  \
   fem_cohesive.getShapeFunctions()                                             \
       .interpolateOnIntegrationPoints<type, CohesiveReduceFunctionOpening>(    \
           displacement, opening, spatial_dimension, ghost_type,                \
           element_filter(type, ghost_type));
 
   AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_OPENING);
 #undef COMPUTE_OPENING
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
-void MaterialCohesive::computeEnergies() {
+void MaterialCohesive::updateEnergies(ElementType type,
+                                      GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
+  if(Mesh::getKind(type) != _ek_cohesive) return;
+
   Vector<Real> b(spatial_dimension);
   Vector<Real> h(spatial_dimension);
-
-  for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost,
-                                                 _ek_cohesive)) {
-    auto erev = reversible_energy(type, _not_ghost).begin();
-    auto etot = total_energy(type, _not_ghost).begin();
-    auto traction_it = tractions(type, _not_ghost).begin(spatial_dimension);
-    auto traction_old_it =
-        tractions_old(type, _not_ghost).begin(spatial_dimension);
-    auto opening_it = opening(type, _not_ghost).begin(spatial_dimension);
-    auto opening_old_it =
-        opening_old(type, _not_ghost).begin(spatial_dimension);
-
-    auto traction_end = tractions(type, _not_ghost).end(spatial_dimension);
-
-    /// loop on each quadrature point
-    for (; traction_it != traction_end; ++traction_it, ++traction_old_it,
-                                        ++opening_it, ++opening_old_it, ++erev,
-                                        ++etot) {
-      /// trapezoidal integration
-      b = *opening_it;
-      b -= *opening_old_it;
-
-      h = *traction_old_it;
-      h += *traction_it;
-
-      *etot += .5 * b.dot(h);
-      *erev = .5 * traction_it->dot(*opening_it);
-    }
+  auto erev = reversible_energy(type, ghost_type).begin();
+  auto etot = total_energy(type, ghost_type).begin();
+  auto traction_it = tractions(type, ghost_type).begin(spatial_dimension);
+  auto traction_old_it =
+      tractions.previous(type, ghost_type).begin(spatial_dimension);
+  auto opening_it = opening(type, ghost_type).begin(spatial_dimension);
+  auto opening_old_it = opening.previous(type, ghost_type).begin(spatial_dimension);
+
+  auto traction_end = tractions(type, ghost_type).end(spatial_dimension);
+
+  /// loop on each quadrature point
+  for (; traction_it != traction_end; ++traction_it, ++traction_old_it,
+                                      ++opening_it, ++opening_old_it, ++erev,
+                                      ++etot) {
+    /// trapezoidal integration
+    b = *opening_it;
+    b -= *opening_old_it;
+
+    h = *traction_old_it;
+    h += *traction_it;
+
+    *etot += .5 * b.dot(h);
+    *erev = .5 * traction_it->dot(*opening_it);
   }
 
   /// update old values
-  GhostType ghost_type = _not_ghost;
-  for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost,
-                                                 _ek_cohesive)) {
-    tractions_old(type, ghost_type).copy(tractions(type, ghost_type));
-    opening_old(type, ghost_type).copy(opening(type, ghost_type));
-  }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Real MaterialCohesive::getReversibleEnergy() {
   AKANTU_DEBUG_IN();
   Real erev = 0.;
 
   /// integrate reversible energy for each type of elements
   for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost,
                                                  _ek_cohesive)) {
     erev +=
         fem_cohesive.integrate(reversible_energy(type, _not_ghost), type,
                                _not_ghost, element_filter(type, _not_ghost));
   }
 
   AKANTU_DEBUG_OUT();
   return erev;
 }
 
 /* -------------------------------------------------------------------------- */
 Real MaterialCohesive::getDissipatedEnergy() {
   AKANTU_DEBUG_IN();
   Real edis = 0.;
 
   /// integrate dissipated energy for each type of elements
   for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost,
                                                  _ek_cohesive)) {
     Array<Real> dissipated_energy(total_energy(type, _not_ghost));
     dissipated_energy -= reversible_energy(type, _not_ghost);
     edis += fem_cohesive.integrate(dissipated_energy, type, _not_ghost,
                                    element_filter(type, _not_ghost));
   }
 
   AKANTU_DEBUG_OUT();
   return edis;
 }
 
 /* -------------------------------------------------------------------------- */
 Real MaterialCohesive::getContactEnergy() {
   AKANTU_DEBUG_IN();
   Real econ = 0.;
 
   /// integrate contact energy for each type of elements
   for (auto & type : element_filter.elementTypes(spatial_dimension, _not_ghost,
                                                  _ek_cohesive)) {
 
     auto & el_filter = element_filter(type, _not_ghost);
     UInt nb_quad_per_el = fem_cohesive.getNbIntegrationPoints(type, _not_ghost);
     UInt nb_quad_points = el_filter.size() * nb_quad_per_el;
     Array<Real> contact_energy(nb_quad_points);
 
     auto contact_traction_it =
         contact_tractions(type, _not_ghost).begin(spatial_dimension);
     auto contact_opening_it =
         contact_opening(type, _not_ghost).begin(spatial_dimension);
 
     /// loop on each quadrature point
     for (UInt q = 0; q < nb_quad_points;
          ++contact_traction_it, ++contact_opening_it, ++q) {
 
       contact_energy(q) = .5 * contact_traction_it->dot(*contact_opening_it);
     }
 
     econ += fem_cohesive.integrate(contact_energy, type, _not_ghost, el_filter);
   }
 
   AKANTU_DEBUG_OUT();
   return econ;
 }
 
 /* -------------------------------------------------------------------------- */
 Real MaterialCohesive::getEnergy(const std::string & type) {
   AKANTU_DEBUG_IN();
 
   if (type == "reversible")
     return getReversibleEnergy();
   else if (type == "dissipated")
     return getDissipatedEnergy();
   else if (type == "cohesive contact")
     return getContactEnergy();
 
   AKANTU_DEBUG_OUT();
   return 0.;
 }
 
 /* -------------------------------------------------------------------------- */
 } // namespace akantu
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 4643f98ac..596297cc9 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
@@ -1,256 +1,251 @@
 /**
  * @file   material_cohesive.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Seyedeh Mohadeseh Taheri Mousavi <mohadeseh.taherimousavi@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Tue Jan 12 2016
  *
  * @brief  Specialization of the material class for cohesive elements
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "material.hh"
 /* -------------------------------------------------------------------------- */
 #include "cohesive_internal_field.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_MATERIAL_COHESIVE_HH__
 #define __AKANTU_MATERIAL_COHESIVE_HH__
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 class SolidMechanicsModelCohesive;
 }
 
 namespace akantu {
 
 class MaterialCohesive : public Material {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   using MyFEEngineCohesiveType =
       FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>;
 
 public:
   MaterialCohesive(SolidMechanicsModel & model, const ID & id = "");
   ~MaterialCohesive() override;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// initialize the material computed parameter
   void initMaterial() override;
 
   /// compute tractions (including normals and openings)
   void computeTraction(GhostType ghost_type = _not_ghost);
 
   /// assemble residual
   void assembleInternalForces(GhostType ghost_type = _not_ghost) override;
 
-  /// compute reversible and total energies by element
-  void computeEnergies();
-
-  /// check stress for cohesive elements' insertion, by default it
+    /// check stress for cohesive elements' insertion, by default it
   /// also updates the cohesive elements' data
   virtual void checkInsertion(bool /*check_only*/ = false) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// check delta_max for cohesive elements in case of no convergence
   /// in the solveStep (only for extrinsic-implicit)
   virtual void checkDeltaMax(GhostType /*ghost_type*/ = _not_ghost) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// reset variables when convergence is reached (only for
   /// extrinsic-implicit)
   virtual void resetVariables(GhostType /*ghost_type*/ = _not_ghost) {
     AKANTU_DEBUG_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*/,
 
                                  Array<Real> & /*result*/){};
 
   /// compute the stresses
   void computeAllStresses(GhostType /*ghost_type*/ = _not_ghost) override{};
 
   // add the facet to be handled by the material
   UInt addFacet(const Element & element);
 
 protected:
   virtual void computeTangentTraction(const ElementType & /*el_type*/,
                                       Array<Real> & /*tangent_matrix*/,
                                       const Array<Real> & /*normal*/,
                                       GhostType /*ghost_type*/ = _not_ghost) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /// compute the normal
   void computeNormal(const Array<Real> & position, Array<Real> & normal,
                      ElementType type, GhostType ghost_type);
 
   /// compute the opening
   void computeOpening(const Array<Real> & displacement, Array<Real> & opening,
                       ElementType type, GhostType ghost_type);
 
   template <ElementType type>
   void computeNormal(const Array<Real> & position, Array<Real> & normal,
                      GhostType ghost_type);
 
   /// assemble stiffness
   void assembleStiffnessMatrix(GhostType ghost_type) override;
 
   /// constitutive law
   virtual void computeTraction(const Array<Real> & normal, ElementType el_type,
                                GhostType ghost_type = _not_ghost) = 0;
 
   /// parallelism functions
   inline UInt getNbDataForElements(const Array<Element> & elements,
                                    SynchronizationTag tag) const;
 
   inline void packElementData(CommunicationBuffer & buffer,
                               const Array<Element> & elements,
                               SynchronizationTag tag) const;
 
   inline void unpackElementData(CommunicationBuffer & buffer,
                                 const Array<Element> & elements,
                                 SynchronizationTag tag);
 
+protected:
+  void updateEnergies(ElementType el_type, GhostType ghost_type) override;
+
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the opening
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Opening, opening, Real);
 
   /// get the traction
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Traction, tractions, Real);
 
   /// get damage
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real);
 
   /// get facet filter
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetFilter, facet_filter, UInt);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetFilter, facet_filter, UInt);
   AKANTU_GET_MACRO(FacetFilter, facet_filter,
                    const ElementTypeMapArray<UInt> &);
   // AKANTU_GET_MACRO(ElementFilter, element_filter, const
   // ElementTypeMapArray<UInt> &);
 
   /// compute reversible energy
   Real getReversibleEnergy();
 
   /// compute dissipated energy
   Real getDissipatedEnergy();
 
   /// compute contact energy
   Real getContactEnergy();
 
   /// get energy
-  Real getEnergy(const std::string &type) override;
+  Real getEnergy(const std::string & type) override;
 
   /// return the energy (identified by id) for the provided element
-  Real getEnergy(const std::string &energy_id, ElementType type, UInt index) override {
+  Real getEnergy(const std::string & energy_id, ElementType type,
+                 UInt index) override {
     return Material::getEnergy(energy_id, type, index);
   }
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// list of facets assigned to this material
   ElementTypeMapArray<UInt> facet_filter;
 
   /// Link to the cohesive fem object in the model
   FEEngine & fem_cohesive;
 
 private:
   /// reversible energy by quadrature point
   CohesiveInternalField<Real> reversible_energy;
 
   /// total energy by quadrature point
   CohesiveInternalField<Real> total_energy;
 
 protected:
   /// opening in all elements and quadrature points
   CohesiveInternalField<Real> opening;
 
-  /// opening in all elements and quadrature points (previous time step)
-  CohesiveInternalField<Real> opening_old;
-
   /// traction in all elements and quadrature points
   CohesiveInternalField<Real> tractions;
 
-  /// traction in all elements and quadrature points (previous time step)
-  CohesiveInternalField<Real> tractions_old;
-
   /// traction due to contact
   CohesiveInternalField<Real> contact_tractions;
 
   /// normal openings for contact tractions
   CohesiveInternalField<Real> contact_opening;
 
   /// maximum displacement
   CohesiveInternalField<Real> delta_max;
 
   /// tell if the previous delta_max state is needed (in iterative schemes)
   bool use_previous_delta_max;
 
   /// tell if the previous opening state is needed (in iterative schemes)
   bool use_previous_opening;
 
   /// damage
   CohesiveInternalField<Real> damage;
 
   /// pointer to the solid mechanics model for cohesive elements
   SolidMechanicsModelCohesive * model;
 
   /// critical stress
   RandomInternalField<Real, FacetInternalField> sigma_c;
 
   /// critical displacement
   Real delta_c;
 
   /// array to temporarily store the normals
   Array<Real> normal;
 };
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 
 #include "material_cohesive_inline_impl.cc"
 
 } // namespace akantu
 
 #include "cohesive_internal_field_tmpl.hh"
 
 #endif /* __AKANTU_MATERIAL_COHESIVE_HH__ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc
index 3a03852bf..5e6a2cf69 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.cc
@@ -1,95 +1,102 @@
 /**
  * @file   material_cohesive_inline_impl.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Wed Aug 04 2010
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  MaterialCohesive inline implementation
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 inline UInt MaterialCohesive::addFacet(const Element & element) {
   Array<UInt> & f_filter = facet_filter(element.type, element.ghost_type);
   f_filter.push_back(element.element);
-  return f_filter.size()-1;
+  return f_filter.size() - 1;
 }
 
-
 /* -------------------------------------------------------------------------- */
-template<ElementType type>
+template <ElementType type>
 void MaterialCohesive::computeNormal(const Array<Real> & /*position*/,
-				     Array<Real> & /*normal*/,
-				     GhostType /*ghost_type*/) {
-}
+                                     Array<Real> & /*normal*/,
+                                     GhostType /*ghost_type*/) {}
 
 /* -------------------------------------------------------------------------- */
-inline UInt MaterialCohesive::getNbDataForElements(const Array<Element> & elements,
-						   SynchronizationTag tag) const {
+inline UInt
+MaterialCohesive::getNbDataForElements(const Array<Element> & elements,
+                                       SynchronizationTag tag) const {
 
   switch (tag) {
   case _gst_smm_stress: {
-    return 2 * spatial_dimension * sizeof(Real) * this->getModel().getNbIntegrationPoints(elements, "CohesiveFEEngine");
+    return 2 * spatial_dimension * sizeof(Real) *
+           this->getModel().getNbIntegrationPoints(elements,
+                                                   "CohesiveFEEngine");
   }
   case _gst_smmc_damage: {
-    return sizeof(Real) * this->getModel().getNbIntegrationPoints(elements, "CohesiveFEEngine");
+    return sizeof(Real) *
+           this->getModel().getNbIntegrationPoints(elements,
+                                                   "CohesiveFEEngine");
   }
   default: {}
   }
 
   return 0;
 }
 
 /* -------------------------------------------------------------------------- */
 inline void MaterialCohesive::packElementData(CommunicationBuffer & buffer,
-					      const Array<Element> & elements,
-					      SynchronizationTag tag) const {
+                                              const Array<Element> & elements,
+                                              SynchronizationTag tag) const {
   switch (tag) {
   case _gst_smm_stress: {
     packElementDataHelper(tractions, buffer, elements, "CohesiveFEEngine");
-    packElementDataHelper(contact_tractions, buffer, elements, "CohesiveFEEngine");
+    packElementDataHelper(contact_tractions, buffer, elements,
+                          "CohesiveFEEngine");
     break;
   }
   case _gst_smmc_damage:
-    packElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); break;
+    packElementDataHelper(damage, buffer, elements, "CohesiveFEEngine");
+    break;
   default: {}
   }
 }
 
 /* -------------------------------------------------------------------------- */
 inline void MaterialCohesive::unpackElementData(CommunicationBuffer & buffer,
-						const Array<Element> & elements,
-						SynchronizationTag tag) {
+                                                const Array<Element> & elements,
+                                                SynchronizationTag tag) {
   switch (tag) {
   case _gst_smm_stress: {
     unpackElementDataHelper(tractions, buffer, elements, "CohesiveFEEngine");
-    unpackElementDataHelper(contact_tractions, buffer, elements, "CohesiveFEEngine");
+    unpackElementDataHelper(contact_tractions, buffer, elements,
+                            "CohesiveFEEngine");
     break;
   }
   case _gst_smmc_damage:
-    unpackElementDataHelper(damage, buffer, elements, "CohesiveFEEngine"); break;
+    unpackElementDataHelper(damage, buffer, elements, "CohesiveFEEngine");
+    break;
   default: {}
   }
 }
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 4af001104..ab54a0dc6 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
@@ -1,752 +1,713 @@
 /**
  * @file   solid_mechanics_model_cohesive.cc
  *
  * @author Mauro Corrado <mauro.corrado@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Tue May 08 2012
  * @date last modification: Wed Jan 13 2016
  *
  * @brief  Solid mechanics model for cohesive elements
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "solid_mechanics_model_cohesive.hh"
 #include "aka_iterators.hh"
 #include "cohesive_element_inserter.hh"
 #include "element_synchronizer.hh"
 #include "facet_synchronizer.hh"
 #include "fe_engine_template.hh"
 #include "integrator_gauss.hh"
 #include "material_cohesive.hh"
 #include "parser.hh"
 #include "shape_cohesive.hh"
 
 #include "dumpable_inline_impl.hh"
 #ifdef AKANTU_USE_IOHELPER
 #include "dumper_iohelper_paraview.hh"
 #endif
 /* -------------------------------------------------------------------------- */
 #include <algorithm>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
-const SolidMechanicsModelCohesiveOptions
-    default_solid_mechanics_model_cohesive_options(_explicit_lumped_mass,
-                                                   false);
-
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModelCohesive::SolidMechanicsModelCohesive(
     Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id)
     : SolidMechanicsModel(mesh, dim, id, memory_id,
                           ModelType::_solid_mechanics_model_cohesive),
       tangents("tangents", id), facet_stress("facet_stress", id),
       facet_material("facet_material", id) {
   AKANTU_DEBUG_IN();
 
   auto && tmp_material_selector =
       std::make_shared<DefaultMaterialCohesiveSelector>(*this);
 
   tmp_material_selector->setFallback(this->material_selector);
   this->material_selector = tmp_material_selector;
 
 #if defined(AKANTU_USE_IOHELPER)
   this->mesh.registerDumper<DumperParaview>("cohesive elements", id);
   this->mesh.addDumpMeshToDumper("cohesive elements", mesh,
                                  Model::spatial_dimension, _not_ghost,
                                  _ek_cohesive);
 #endif
 
   if (this->mesh.isDistributed()) {
     /// create the distributed synchronizer for cohesive elements
     this->cohesive_synchronizer = std::make_unique<ElementSynchronizer>(
         mesh, "cohesive_distributed_synchronizer");
 
     auto & synchronizer = mesh.getElementSynchronizer();
     this->cohesive_synchronizer->split(synchronizer, [](auto && el) {
       return Mesh::getKind(el.type) == _ek_cohesive;
     });
 
     this->registerSynchronizer(*cohesive_synchronizer, _gst_material_id);
     this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_stress);
     this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_boundary);
   }
 
   this->inserter = std::make_unique<CohesiveElementInserter>(
       this->mesh, id + ":cohesive_element_inserter");
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModelCohesive::~SolidMechanicsModelCohesive() = default;
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::setTimeStep(Real time_step,
                                               const ID & solver_id) {
   SolidMechanicsModel::setTimeStep(time_step, solver_id);
 
 #if defined(AKANTU_USE_IOHELPER)
   this->mesh.getDumper("cohesive elements").setTimeStep(time_step);
 #endif
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::initFullImpl(const ModelOptions & options) {
   AKANTU_DEBUG_IN();
 
   const auto & smmc_options =
       dynamic_cast<const SolidMechanicsModelCohesiveOptions &>(options);
 
   this->is_extrinsic = smmc_options.extrinsic;
 
   inserter->setIsExtrinsic(is_extrinsic);
 
   if (mesh.isDistributed()) {
     auto & mesh_facets = inserter->getMeshFacets();
     auto & synchronizer =
         dynamic_cast<FacetSynchronizer &>(mesh_facets.getElementSynchronizer());
     this->registerSynchronizer(synchronizer, _gst_smmc_facets);
     this->registerSynchronizer(synchronizer, _gst_smmc_facets_conn);
 
     synchronizeGhostFacetsConnectivity();
 
     /// create the facet synchronizer for extrinsic simulations
     if (is_extrinsic) {
-      facet_stress_synchronizer =
-          std::make_unique<ElementSynchronizer>(mesh_facets);
-
-      facet_stress_synchronizer->updateSchemes(
-          [&](auto & scheme, auto & proc, auto & direction) {
-            scheme.copy(const_cast<const FacetSynchronizer &>(synchronizer)
-                            .getCommunications()
-                            .getScheme(proc, direction));
-          });
+      facet_stress_synchronizer = std::make_unique<ElementSynchronizer>(
+          synchronizer, id + ":facet_stress_synchronizer");
+
       this->registerSynchronizer(*facet_stress_synchronizer,
                                  _gst_smmc_facets_stress);
     }
 
     inserter->initParallel(*cohesive_synchronizer);
   }
 
   ParserSection section;
   bool is_empty;
   std::tie(section, is_empty) = this->getParserSection();
 
   if (not is_empty) {
     auto inserter_section =
         section.getSubSections(ParserType::_cohesive_inserter);
     if (inserter_section.begin() != inserter_section.end()) {
       inserter->parseSection(*inserter_section.begin());
     }
   }
 
   SolidMechanicsModel::initFullImpl(options);
 
   AKANTU_DEBUG_OUT();
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::initMaterials() {
   AKANTU_DEBUG_IN();
 
   // make sure the material are instantiated
   if (!are_materials_instantiated)
     instantiateMaterials();
 
   /// find the first cohesive material
   UInt cohesive_index = UInt(-1);
 
   for (auto && material : enumerate(materials)) {
     if (dynamic_cast<MaterialCohesive *>(std::get<1>(material).get())) {
       cohesive_index = std::get<0>(material);
       break;
     }
   }
 
   if (cohesive_index == UInt(-1))
     AKANTU_EXCEPTION("No cohesive materials in the material input file");
 
   material_selector->setFallback(cohesive_index);
 
   // set the facet information in the material in case of dynamic insertion
   // to know what material to call for stress checks
   if (is_extrinsic) {
     this->initExtrinsicMaterials();
   } else {
     this->initIntrinsicMaterials();
   }
 
   AKANTU_DEBUG_OUT();
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::initExtrinsicMaterials() {
   const Mesh & mesh_facets = inserter->getMeshFacets();
   facet_material.initialize(
       mesh_facets, _spatial_dimension = spatial_dimension - 1,
       _with_nb_element = true,
       _default_value = material_selector->getFallbackValue());
 
-  for_each_element(mesh_facets,
-                   [&](auto && element) {
-                     auto mat_index = (*material_selector)(element);
-                     auto & mat = dynamic_cast<MaterialCohesive &>(
-                         *materials[mat_index]);
-                     facet_material(element) = mat_index;
-                     mat.addFacet(element);
-                   },
-                   _spatial_dimension = spatial_dimension - 1);
+  for_each_element(
+      mesh_facets,
+      [&](auto && element) {
+        auto mat_index = (*material_selector)(element);
+        auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]);
+        facet_material(element) = mat_index;
+        mat.addFacet(element);
+      },
+      _spatial_dimension = spatial_dimension - 1, _ghost_type = _not_ghost);
 
   SolidMechanicsModel::initMaterials();
 
   this->initAutomaticInsertion();
 }
 
 /* -------------------------------------------------------------------------- */
 #if 0
 void SolidMechanicsModelCohesive::initIntrinsicCohesiveMaterials(
     const std::string & cohesive_surfaces) {
 
   AKANTU_DEBUG_IN();
 
 #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT)
   if (facet_synchronizer != nullptr)
     inserter->initParallel(facet_synchronizer, cohesive_element_synchronizer);
 //    inserter->initParallel(facet_synchronizer, synch_parallel);
 #endif
   std::istringstream split(cohesive_surfaces);
   std::string physname;
   while (std::getline(split, physname, ',')) {
     AKANTU_DEBUG_INFO(
         "Pre-inserting cohesive elements along facets from physical surface: "
         << physname);
     insertElementsFromMeshData(physname);
   }
 
   synchronizeInsertionData();
 
   SolidMechanicsModel::initMaterials();
 
   auto && tmp = std::make_shared<MeshDataMaterialCohesiveSelector>(*this);
   tmp->setFallback(material_selector->getFallbackValue());
   tmp->setFallback(material_selector->getFallbackSelector());
   material_selector = tmp;
 
   // UInt nb_new_elements =
   inserter->insertElements();
   // if (nb_new_elements > 0) {
   //   this->reinitializeSolver();
   // }
 
   AKANTU_DEBUG_OUT();
 }
 #endif
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::synchronizeInsertionData() {
   if (inserter->getMeshFacets().isDistributed()) {
     inserter->getMeshFacets().getElementSynchronizer().synchronizeOnce(
         *inserter, _gst_ce_groups);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::initIntrinsicMaterials() {
   AKANTU_DEBUG_IN();
 
   SolidMechanicsModel::initMaterials();
 
   this->insertIntrinsicElements();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Initialize the model,basically it  pre-compute the shapes, shapes derivatives
  * and jacobian
  */
 void SolidMechanicsModelCohesive::initModel() {
   AKANTU_DEBUG_IN();
 
   SolidMechanicsModel::initModel();
 
   registerFEEngineObject<MyFEEngineCohesiveType>("CohesiveFEEngine", mesh,
                                                  Model::spatial_dimension);
 
   /// add cohesive type connectivity
   ElementType type = _not_defined;
   for (auto && type_ghost : ghost_types) {
     for (const auto & tmp_type :
          mesh.elementTypes(spatial_dimension, type_ghost)) {
       const auto & connectivity = mesh.getConnectivity(tmp_type, type_ghost);
       if (connectivity.size() == 0)
         continue;
 
       type = tmp_type;
       auto type_facet = Mesh::getFacetType(type);
       auto type_cohesive = FEEngine::getCohesiveElementType(type_facet);
       mesh.addConnectivityType(type_cohesive, type_ghost);
     }
   }
   AKANTU_DEBUG_ASSERT(type != _not_defined, "No elements in the mesh");
 
   getFEEngine("CohesiveFEEngine").initShapeFunctions(_not_ghost);
   getFEEngine("CohesiveFEEngine").initShapeFunctions(_ghost);
 
   registerFEEngineObject<MyFEEngineFacetType>(
       "FacetsFEEngine", mesh.getMeshFacets(), Model::spatial_dimension - 1);
 
   if (is_extrinsic) {
     getFEEngine("FacetsFEEngine").initShapeFunctions(_not_ghost);
     getFEEngine("FacetsFEEngine").initShapeFunctions(_ghost);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::insertIntrinsicElements() {
   AKANTU_DEBUG_IN();
   inserter->insertIntrinsicElements();
   AKANTU_DEBUG_OUT();
 }
 
-/* -------------------------------------------------------------------------- */
-void SolidMechanicsModelCohesive::updateFacetStressSynchronizer() {
-  if (facet_stress_synchronizer != nullptr) {
-    const auto & rank_to_element =
-        mesh.getElementSynchronizer().getElementToRank();
-    const auto & facet_checks = inserter->getCheckFacets();
-    const auto & element_to_facet = mesh.getElementToSubelement();
-    UInt rank = mesh.getCommunicator().whoAmI();
-
-    facet_stress_synchronizer->updateSchemes(
-        [&](auto & scheme, auto & proc, auto & /*direction*/) {
-          UInt el = 0;
-          for (auto && element : scheme) {
-            if (not facet_checks(element))
-              continue;
-
-            const auto & next_el = element_to_facet(element);
-            UInt rank_left = rank_to_element(next_el[0]);
-            UInt rank_right = rank_to_element(next_el[1]);
-
-            if ((rank_left == rank and rank_right == proc) or
-                (rank_left == proc and rank_right == rank)) {
-              scheme[el] = element;
-              ++el;
-            }
-          }
-          scheme.resize(el);
-        });
-  }
-}
-
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::initAutomaticInsertion() {
   AKANTU_DEBUG_IN();
 
   this->inserter->limitCheckFacets();
-
   this->updateFacetStressSynchronizer();
-
   this->resizeFacetStress();
 
   /// compute normals on facets
   this->computeNormals();
 
   this->initStressInterpolation();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::updateAutomaticInsertion() {
   AKANTU_DEBUG_IN();
 
   this->inserter->limitCheckFacets();
   this->updateFacetStressSynchronizer();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::initStressInterpolation() {
   Mesh & mesh_facets = inserter->getMeshFacets();
 
   /// compute quadrature points coordinates on facets
   Array<Real> & position = mesh.getNodes();
 
   ElementTypeMapArray<Real> quad_facets("quad_facets", id);
   quad_facets.initialize(mesh_facets, _nb_component = Model::spatial_dimension,
                          _spatial_dimension = Model::spatial_dimension - 1);
   // mesh_facets.initElementTypeMapArray(quad_facets, Model::spatial_dimension,
   //                                     Model::spatial_dimension - 1);
 
   getFEEngine("FacetsFEEngine")
       .interpolateOnIntegrationPoints(position, quad_facets);
 
   /// compute elements quadrature point positions and build
   /// element-facet quadrature points data structure
   ElementTypeMapArray<Real> elements_quad_facets("elements_quad_facets", id);
 
   elements_quad_facets.initialize(
       mesh, _nb_component = Model::spatial_dimension,
       _spatial_dimension = Model::spatial_dimension);
   // mesh.initElementTypeMapArray(elements_quad_facets,
   // Model::spatial_dimension,
   //                              Model::spatial_dimension);
 
   for (auto elem_gt : ghost_types) {
     for (auto & type : mesh.elementTypes(Model::spatial_dimension, elem_gt)) {
       UInt nb_element = mesh.getNbElement(type, elem_gt);
       if (nb_element == 0)
         continue;
 
       /// compute elements' quadrature points and list of facet
       /// quadrature points positions by element
-      Array<Element> & facet_to_element =
+      const auto & facet_to_element =
           mesh_facets.getSubelementToElement(type, elem_gt);
-      UInt nb_facet_per_elem = facet_to_element.getNbComponent();
-      Array<Real> & el_q_facet = elements_quad_facets(type, elem_gt);
-      ElementType facet_type = Mesh::getFacetType(type);
-      UInt nb_quad_per_facet =
-          getFEEngine("FacetsFEEngine").getNbIntegrationPoints(facet_type);
+      auto & el_q_facet = elements_quad_facets(type, elem_gt);
 
-      el_q_facet.resize(nb_element * nb_facet_per_elem * nb_quad_per_facet);
-
-      for (UInt el = 0; el < nb_element; ++el) {
-        for (UInt f = 0; f < nb_facet_per_elem; ++f) {
-          Element global_facet_elem = facet_to_element(el, f);
-          UInt global_facet = global_facet_elem.element;
-          GhostType facet_gt = global_facet_elem.ghost_type;
-          const Array<Real> & quad_f = quad_facets(facet_type, facet_gt);
-
-          for (UInt q = 0; q < nb_quad_per_facet; ++q) {
-            for (UInt s = 0; s < Model::spatial_dimension; ++s) {
-              el_q_facet(el * nb_facet_per_elem * nb_quad_per_facet +
-                             f * nb_quad_per_facet + q,
-                         s) = quad_f(global_facet * nb_quad_per_facet + q, s);
-            }
-          }
-        }
+      auto facet_type = Mesh::getFacetType(type);
+      auto nb_quad_per_facet =
+          getFEEngine("FacetsFEEngine").getNbIntegrationPoints(facet_type);
+      auto nb_facet_per_elem = facet_to_element.getNbComponent();
+
+      // small hack in the loop to skip boundary elements, they are silently
+      // initialized to NaN to see if this causes problems
+      el_q_facet.resize(nb_element * nb_facet_per_elem * nb_quad_per_facet,
+                        std::numeric_limits<Real>::quiet_NaN());
+
+      for (auto && data :
+           zip(make_view(facet_to_element),
+               make_view(el_q_facet, spatial_dimension, nb_quad_per_facet))) {
+        const auto & global_facet = std::get<0>(data);
+        auto & el_q = std::get<1>(data);
+
+        if (global_facet == ElementNull)
+          continue;
+
+        Matrix<Real> quad_f =
+            make_view(quad_facets(global_facet.type, global_facet.ghost_type),
+                      spatial_dimension, nb_quad_per_facet)
+                .begin()[global_facet.element];
+
+        el_q = quad_f;
+
+        // for (UInt q = 0; q < nb_quad_per_facet; ++q) {
+        //   for (UInt s = 0; s < Model::spatial_dimension; ++s) {
+        //     el_q_facet(el * nb_facet_per_elem * nb_quad_per_facet +
+        //                    f * nb_quad_per_facet + q,
+        //                s) = quad_f(global_facet * nb_quad_per_facet + q,
+        //                s);
+        //   }
+        // }
+        //}
       }
     }
   }
 
   /// loop over non cohesive materials
   for (auto && material : materials) {
     if (dynamic_cast<MaterialCohesive *>(material.get()))
       continue;
     /// initialize the interpolation function
     material->initElementalFieldInterpolation(elements_quad_facets);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::assembleInternalForces() {
   AKANTU_DEBUG_IN();
 
   // f_int += f_int_cohe
   for (auto & material : this->materials) {
     try {
       auto & mat = dynamic_cast<MaterialCohesive &>(*material);
       mat.computeTraction(_not_ghost);
     } catch (std::bad_cast & bce) {
     }
   }
 
   SolidMechanicsModel::assembleInternalForces();
 
-  if (isDefaultSolverExplicit()) {
-    for (auto & material : materials) {
-      try {
-        auto & mat = dynamic_cast<MaterialCohesive &>(*material);
-        mat.computeEnergies();
-      } catch (std::bad_cast & bce) {
-      }
-    }
-  }
-
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::computeNormals() {
   AKANTU_DEBUG_IN();
 
   Mesh & mesh_facets = this->inserter->getMeshFacets();
   this->getFEEngine("FacetsFEEngine")
       .computeNormalsOnIntegrationPoints(_not_ghost);
 
   /**
    *  @todo store tangents while computing normals instead of
    *  recomputing them as follows:
    */
   /* ------------------------------------------------------------------------ */
   UInt tangent_components =
       Model::spatial_dimension * (Model::spatial_dimension - 1);
 
   tangents.initialize(mesh_facets, _nb_component = tangent_components,
                       _spatial_dimension = Model::spatial_dimension - 1);
   // mesh_facets.initElementTypeMapArray(tangents, tangent_components,
   //                                     Model::spatial_dimension - 1);
 
   for (auto facet_type :
        mesh_facets.elementTypes(Model::spatial_dimension - 1)) {
     const Array<Real> & normals =
         this->getFEEngine("FacetsFEEngine")
             .getNormalsOnIntegrationPoints(facet_type);
 
     Array<Real> & tangents = this->tangents(facet_type);
 
     Math::compute_tangents(normals, tangents);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::interpolateStress() {
 
   ElementTypeMapArray<Real> by_elem_result("temporary_stress_by_facets", id);
 
   for (auto & material : materials) {
-    try {
-      auto & mat __attribute__((unused)) =
-          dynamic_cast<MaterialCohesive &>(*material);
-    } catch (std::bad_cast &) {
+    auto * mat = dynamic_cast<MaterialCohesive *>(material.get());
+    if (mat == nullptr)
       /// interpolate stress on facet quadrature points positions
       material->interpolateStressOnFacets(facet_stress, by_elem_result);
-    }
   }
 
 #if defined(AKANTU_DEBUG_TOOLS)
   debug::element_manager.printData(
       debug::_dm_model_cohesive, "Interpolated stresses before", facet_stress);
 #endif
 
   this->synchronize(_gst_smmc_facets_stress);
 
 #if defined(AKANTU_DEBUG_TOOLS)
   debug::element_manager.printData(debug::_dm_model_cohesive,
                                    "Interpolated stresses", facet_stress);
 #endif
 }
 
 /* -------------------------------------------------------------------------- */
 UInt SolidMechanicsModelCohesive::checkCohesiveStress() {
+  AKANTU_DEBUG_IN();
+
   interpolateStress();
 
   for (auto & mat : materials) {
-    try {
-      auto & mat_cohesive = dynamic_cast<MaterialCohesive &>(*mat);
+    auto * mat_cohesive = dynamic_cast<MaterialCohesive *>(mat.get());
+    if(mat_cohesive) {
       /// check which not ghost cohesive elements are to be created
-      mat_cohesive.checkInsertion();
-    } catch (std::bad_cast &) {
+      mat_cohesive->checkInsertion();
     }
   }
 
   /// communicate data among processors
   this->synchronize(_gst_smmc_facets);
 
   /// insert cohesive elements
   UInt nb_new_elements = inserter->insertElements();
 
   // if (nb_new_elements > 0) {
   //   this->reinitializeSolver();
   // }
 
+  AKANTU_DEBUG_OUT();
+
   return nb_new_elements;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::onElementsAdded(
     const Array<Element> & element_list, const NewElementsEvent & event) {
   AKANTU_DEBUG_IN();
 
   updateCohesiveSynchronizers();
 
   SolidMechanicsModel::onElementsAdded(element_list, event);
 
   if (cohesive_synchronizer != nullptr)
     cohesive_synchronizer->computeAllBufferSizes(*this);
 
   if (is_extrinsic)
     resizeFacetStress();
 
   ///  if (method != _explicit_lumped_mass) {
   ///    this->initSolver();
   ///  }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::onNodesAdded(const Array<UInt> & new_nodes,
                                                const NewNodesEvent & event) {
   AKANTU_DEBUG_IN();
 
   // Array<UInt> nodes_list(nb_new_nodes);
 
   // for (UInt n = 0; n < nb_new_nodes; ++n)
   //   nodes_list(n) = doubled_nodes(n, 1);
   SolidMechanicsModel::onNodesAdded(new_nodes, event);
 
   UInt new_node, old_node;
 
   try {
     const auto & cohesive_event =
         dynamic_cast<const CohesiveNewNodesEvent &>(event);
     const auto & old_nodes = cohesive_event.getOldNodesList();
 
     auto copy = [this, &new_node, &old_node](auto & arr) {
       for (UInt s = 0; s < spatial_dimension; ++s) {
         arr(new_node, s) = arr(old_node, s);
       }
     };
 
     for (auto && pair : zip(new_nodes, old_nodes)) {
       std::tie(new_node, old_node) = pair;
 
       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 (this->getDOFManager().hasMatrix("M")) {
     //   this->assembleMass(old_nodes);
     // }
 
     // if (this->getDOFManager().hasLumpedMatrix("M")) {
     //   this->assembleMassLumped(old_nodes);
     // }
 
   } catch (std::bad_cast &) {
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::onEndSolveStep(const AnalysisMethod &) {
 
   AKANTU_DEBUG_IN();
 
   /*
    * This is required because the Cauchy stress is the stress measure that
    * is used to check the insertion of cohesive elements
    */
   for (auto & mat : materials) {
     if (mat->isFiniteDeformation())
       mat->computeAllCauchyStresses(_not_ghost);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::printself(std::ostream & stream,
                                             int indent) const {
   std::string space;
   for (Int i = 0; i < indent; i++, space += AKANTU_INDENT)
     ;
 
   stream << space << "SolidMechanicsModelCohesive [" << std::endl;
 
   SolidMechanicsModel::printself(stream, indent + 1);
 
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::resizeFacetStress() {
   AKANTU_DEBUG_IN();
 
   this->facet_stress.initialize(getFEEngine("FacetsFEEngine"),
                                 _nb_component =
                                     2 * spatial_dimension * spatial_dimension,
                                 _spatial_dimension = spatial_dimension - 1);
 
   // for (auto && ghost_type : ghost_types) {
   //   for (const auto & type :
   //        mesh_facets.elementTypes(spatial_dimension - 1, ghost_type)) {
   //     UInt nb_facet = mesh_facets.getNbElement(type, ghost_type);
 
   //     UInt nb_quadrature_points = getFEEngine("FacetsFEEngine")
   //                                     .getNbIntegrationPoints(type,
   //                                     ghost_type);
 
   //     UInt new_size = nb_facet * nb_quadrature_points;
 
   //     facet_stress(type, ghost_type).resize(new_size);
   //   }
   // }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::addDumpGroupFieldToDumper(
     const std::string & dumper_name, const std::string & field_id,
     const std::string & group_name, const ElementKind & element_kind,
     bool padding_flag) {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = Model::spatial_dimension;
   ElementKind _element_kind = element_kind;
   if (dumper_name == "cohesive elements") {
     _element_kind = _ek_cohesive;
   } else if (dumper_name == "facets") {
     spatial_dimension = Model::spatial_dimension - 1;
   }
   SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id,
                                                  group_name, spatial_dimension,
                                                  _element_kind, padding_flag);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 void SolidMechanicsModelCohesive::onDump() {
   this->flattenAllRegisteredInternals(_ek_cohesive);
   SolidMechanicsModel::onDump();
 }
 
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc
index c9deec2a9..ba6037031 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc
@@ -1,399 +1,484 @@
 /**
  * @file   solid_mechanics_model_cohesive_parallel.cc
  *
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  *
  * @brief  Functions for parallel cohesive elements
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  */
 /* -------------------------------------------------------------------------- */
+#include "communicator.hh"
 #include "element_synchronizer.hh"
+#include "material_cohesive.hh"
 #include "solid_mechanics_model_cohesive.hh"
 #include "solid_mechanics_model_tmpl.hh"
-#include "communicator.hh"
 /* -------------------------------------------------------------------------- */
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::synchronizeGhostFacetsConnectivity() {
   AKANTU_DEBUG_IN();
 
   const Communicator & comm = mesh.getCommunicator();
   Int psize = comm.getNbProc();
 
   if (psize > 1) {
     /// get global connectivity for not ghost facets
     global_connectivity =
         new ElementTypeMapArray<UInt>("global_connectivity", id);
 
     auto & mesh_facets = inserter->getMeshFacets();
 
     global_connectivity->initialize(
         mesh_facets, _spatial_dimension = spatial_dimension - 1,
         _with_nb_element = true, _with_nb_nodes_per_element = true,
-        _element_kind = _ek_regular,
-        _ghost_type = _not_ghost);
+        _element_kind = _ek_regular);
 
     mesh_facets.getGlobalConnectivity(*global_connectivity);
 
     /// communicate
     synchronize(_gst_smmc_facets_conn);
 
     /// flip facets
     MeshUtils::flipFacets(mesh_facets, *global_connectivity, _ghost);
 
     delete global_connectivity;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::updateCohesiveSynchronizers() {
   /// update synchronizers if needed
 
   if (not mesh.isDistributed())
     return;
 
   auto & mesh_facets = inserter->getMeshFacets();
   auto & facet_synchronizer = mesh_facets.getElementSynchronizer();
   const auto & cfacet_synchronizer = facet_synchronizer;
 
   // update the cohesive element synchronizer
-  cohesive_synchronizer->updateSchemes(
-      [&](auto && scheme, auto && proc, auto && direction) {
-        auto & facet_scheme =
-            cfacet_synchronizer.getCommunications().getScheme(proc, direction);
-
-        for (auto && facet : facet_scheme) {
-          const auto & connected_elements = mesh_facets.getElementToSubelement(
-              facet.type,
-              facet.ghost_type)(facet.element); // slow access here
-          const auto & cohesive_element = connected_elements[1];
-
-          auto && cohesive_type = FEEngine::getCohesiveElementType(facet.type);
-          auto old_nb_cohesive_elements =
-              mesh.getNbElement(cohesive_type, facet.ghost_type);
-          old_nb_cohesive_elements -=
-            mesh.getData<UInt>("facet_to_double", facet.type,
-                               facet.ghost_type).size();
-
-          if (cohesive_element.kind() == _ek_cohesive and
-              cohesive_element.element >= old_nb_cohesive_elements) {
-            scheme.push_back(cohesive_element);
-          }
-        }
-      });
+  cohesive_synchronizer->updateSchemes([&](auto && scheme, auto && proc,
+                                           auto && direction) {
+    auto & facet_scheme =
+        cfacet_synchronizer.getCommunications().getScheme(proc, direction);
+
+    for (auto && facet : facet_scheme) {
+      const auto & connected_elements = mesh_facets.getElementToSubelement(
+          facet.type,
+          facet.ghost_type)(facet.element); // slow access here
+      const auto & cohesive_element = connected_elements[1];
+
+      auto && cohesive_type = FEEngine::getCohesiveElementType(facet.type);
+      auto old_nb_cohesive_elements =
+          mesh.getNbElement(cohesive_type, facet.ghost_type);
+      old_nb_cohesive_elements -=
+          mesh.getData<UInt>("facet_to_double", facet.type, facet.ghost_type)
+              .size();
+
+      if (cohesive_element.kind() == _ek_cohesive and
+          cohesive_element.element >= old_nb_cohesive_elements) {
+        scheme.push_back(cohesive_element);
+      }
+    }
+  });
 
   const auto & comm = mesh.getCommunicator();
   auto && my_rank = comm.whoAmI();
 
   // update the facet stress synchronizer
-  facet_stress_synchronizer->updateSchemes([&](auto && scheme, auto && proc,
-                                               auto && /*direction*/) {
-    auto it_element = scheme.begin();
-    for (auto && element : scheme) {
-      auto && facet_check = inserter->getCheckFacets(
-          element.type, element.ghost_type)(element.element); // slow access
-                                                              // here
-
-      if (facet_check) {
-        auto && connected_elements = mesh_facets.getElementToSubelement(
+  if (facet_stress_synchronizer)
+    facet_stress_synchronizer->updateSchemes([&](auto && scheme, auto && proc,
+                                                 auto && /*direction*/) {
+      auto it_element = scheme.begin();
+      for (auto && element : scheme) {
+        auto && facet_check = inserter->getCheckFacets(
             element.type, element.ghost_type)(element.element); // slow access
                                                                 // here
-        auto && rank_left = facet_synchronizer.getRank(connected_elements[0]);
-        auto && rank_right = facet_synchronizer.getRank(connected_elements[1]);
-
-        // keep element if the element is still a boundary element between two
-        // processors
-        if ((rank_left == Int(proc) and rank_right == my_rank) or
-            (rank_left == my_rank and rank_right == Int(proc))) {
-          *it_element = element;
-          ++it_element;
+
+        if (facet_check) {
+          auto && connected_elements = mesh_facets.getElementToSubelement(
+              element.type, element.ghost_type)(element.element); // slow access
+                                                                  // here
+          auto && rank_left = facet_synchronizer.getRank(connected_elements[0]);
+          auto && rank_right =
+              facet_synchronizer.getRank(connected_elements[1]);
+
+          // keep element if the element is still a boundary element between two
+          // processors
+          if ((rank_left == Int(proc) and rank_right == my_rank) or
+              (rank_left == my_rank and rank_right == Int(proc))) {
+            *it_element = element;
+            ++it_element;
+          }
         }
       }
-    }
-    scheme.resize(it_element - scheme.begin());
-  });
+      scheme.resize(it_element - scheme.begin());
+    });
+}
+
+/* -------------------------------------------------------------------------- */
+void SolidMechanicsModelCohesive::updateFacetStressSynchronizer() {
+  if (facet_stress_synchronizer != nullptr) {
+    const auto & rank_to_element =
+        mesh.getElementSynchronizer().getElementToRank();
+    const auto & facet_checks = inserter->getCheckFacets();
+    const auto & mesh_facets = inserter->getMeshFacets();
+    const auto & element_to_facet = mesh_facets.getElementToSubelement();
+    UInt rank = mesh.getCommunicator().whoAmI();
+
+    facet_stress_synchronizer->updateSchemes(
+        [&](auto & scheme, auto & proc, auto & /*direction*/) {
+          UInt el = 0;
+          for (auto && element : scheme) {
+            if (not facet_checks(element))
+              continue;
+
+            const auto & next_el = element_to_facet(element);
+            UInt rank_left = rank_to_element(next_el[0]);
+            UInt rank_right = rank_to_element(next_el[1]);
+
+            if ((rank_left == rank and rank_right == proc) or
+                (rank_left == proc and rank_right == rank)) {
+              scheme[el] = element;
+              ++el;
+            }
+          }
+          scheme.resize(el);
+        });
+  }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 void SolidMechanicsModelCohesive::packFacetStressDataHelper(
     const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer,
     const Array<Element> & elements) const {
   packUnpackFacetStressDataHelper<T, true>(
       const_cast<ElementTypeMapArray<T> &>(data_to_pack), buffer, elements);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 void SolidMechanicsModelCohesive::unpackFacetStressDataHelper(
     ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer,
     const Array<Element> & elements) const {
   packUnpackFacetStressDataHelper<T, false>(data_to_unpack, buffer, elements);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, bool pack_helper>
 void SolidMechanicsModelCohesive::packUnpackFacetStressDataHelper(
     ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer,
     const Array<Element> & elements) const {
   ElementType current_element_type = _not_defined;
   GhostType current_ghost_type = _casper;
   UInt nb_quad_per_elem = 0;
   UInt sp2 = spatial_dimension * spatial_dimension;
   UInt nb_component = sp2 * 2;
   bool element_rank = false;
   Mesh & mesh_facets = inserter->getMeshFacets();
 
   Array<T> * vect = nullptr;
   Array<std::vector<Element>> * element_to_facet = nullptr;
 
   auto & fe_engine = this->getFEEngine("FacetsFEEngine");
   for (auto && el : elements) {
     if (el.type == _not_defined)
-      AKANTU_EXCEPTION("packUnpackFacetStressDataHelper called with wrong inputs");
+      AKANTU_EXCEPTION(
+          "packUnpackFacetStressDataHelper called with wrong inputs");
 
     if (el.type != current_element_type ||
         el.ghost_type != current_ghost_type) {
       current_element_type = el.type;
       current_ghost_type = el.ghost_type;
       vect = &data_to_pack(el.type, el.ghost_type);
 
       element_to_facet =
           &(mesh_facets.getElementToSubelement(el.type, el.ghost_type));
 
       nb_quad_per_elem =
           fe_engine.getNbIntegrationPoints(el.type, el.ghost_type);
     }
 
     if (pack_helper)
       element_rank =
           (*element_to_facet)(el.element)[0].ghost_type != _not_ghost;
     else
       element_rank =
           (*element_to_facet)(el.element)[0].ghost_type == _not_ghost;
 
     for (UInt q = 0; q < nb_quad_per_elem; ++q) {
       Vector<T> data(vect->storage() +
                          (el.element * nb_quad_per_elem + q) * nb_component +
                          element_rank * sp2,
                      sp2);
 
       if (pack_helper)
         buffer << data;
       else
         buffer >> data;
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 UInt SolidMechanicsModelCohesive::getNbQuadsForFacetCheck(
     const Array<Element> & elements) const {
   UInt nb_quads = 0;
   UInt nb_quad_per_facet = 0;
 
   ElementType current_element_type = _not_defined;
   GhostType current_ghost_type = _casper;
   auto & fe_engine = this->getFEEngine("FacetsFEEngine");
-  for(auto & el : elements) {
+  for (auto & el : elements) {
     if (el.type != current_element_type ||
         el.ghost_type != current_ghost_type) {
       current_element_type = el.type;
       current_ghost_type = el.ghost_type;
 
-      nb_quad_per_facet = fe_engine
-                              .getNbIntegrationPoints(el.type, el.ghost_type);
+      nb_quad_per_facet =
+          fe_engine.getNbIntegrationPoints(el.type, el.ghost_type);
     }
 
     nb_quads += nb_quad_per_facet;
   }
 
   return nb_quads;
 }
 
 /* -------------------------------------------------------------------------- */
 UInt SolidMechanicsModelCohesive::getNbData(
     const Array<Element> & elements, const SynchronizationTag & tag) const {
   AKANTU_DEBUG_IN();
 
   UInt size = 0;
   if (elements.size() == 0)
     return 0;
 
   /// regular element case
   if (elements(0).kind() == _ek_regular) {
 
     switch (tag) {
     case _gst_smmc_facets: {
       size += elements.size() * sizeof(bool);
       break;
     }
     case _gst_smmc_facets_conn: {
       UInt nb_nodes = Mesh::getNbNodesPerElementList(elements);
       size += nb_nodes * sizeof(UInt);
       break;
     }
     case _gst_smmc_facets_stress: {
       UInt nb_quads = getNbQuadsForFacetCheck(elements);
       size += nb_quads * spatial_dimension * spatial_dimension * sizeof(Real);
       break;
     }
+    case _gst_material_id: {
+      for (auto && element : elements) {
+        if (Mesh::getSpatialDimension(element.type) == (spatial_dimension - 1))
+          size += sizeof(UInt);
+      }
+
+      size += SolidMechanicsModel::getNbData(elements, tag);
+      break;
+    }
+
     default: { size += SolidMechanicsModel::getNbData(elements, tag); }
     }
   }
   /// cohesive element case
   else if (elements(0).kind() == _ek_cohesive) {
 
     switch (tag) {
     case _gst_material_id: {
       size += elements.size() * sizeof(UInt);
       break;
     }
     case _gst_smm_boundary: {
       UInt nb_nodes_per_element = 0;
 
       for (auto && el : elements) {
         nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type);
       }
 
       // force, displacement, boundary
       size += nb_nodes_per_element * spatial_dimension *
               (2 * sizeof(Real) + sizeof(bool));
       break;
     }
     default:
       break;
     }
 
     if (tag != _gst_material_id && tag != _gst_smmc_facets) {
       splitByMaterial(elements, [&](auto && mat, auto && elements) {
         size += mat.getNbData(elements, tag);
       });
     }
   }
 
   AKANTU_DEBUG_OUT();
   return size;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::packData(
     CommunicationBuffer & buffer, const Array<Element> & elements,
     const SynchronizationTag & tag) const {
   AKANTU_DEBUG_IN();
 
   if (elements.size() == 0)
     return;
 
   if (elements(0).kind() == _ek_regular) {
     switch (tag) {
     case _gst_smmc_facets: {
       packElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer,
                               elements, false, getFEEngine());
       break;
     }
     case _gst_smmc_facets_conn: {
       packElementalDataHelper(*global_connectivity, buffer, elements, false,
                               getFEEngine());
       break;
     }
     case _gst_smmc_facets_stress: {
       packFacetStressDataHelper(facet_stress, buffer, elements);
       break;
     }
+    case _gst_material_id: {
+      for (auto && element : elements) {
+        if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1))
+          continue;
+        buffer << material_index(element);
+      }
+
+      SolidMechanicsModel::packData(buffer, elements, tag);
+      break;
+    }
     default: { SolidMechanicsModel::packData(buffer, elements, tag); }
     }
-  } else if (elements(0).kind() == _ek_cohesive) {
+
+    AKANTU_DEBUG_OUT();
+    return;
+  }
+
+  if (elements(0).kind() == _ek_cohesive) {
     switch (tag) {
     case _gst_material_id: {
       packElementalDataHelper(material_index, buffer, elements, false,
                               getFEEngine("CohesiveFEEngine"));
       break;
     }
     case _gst_smm_boundary: {
       packNodalDataHelper(*internal_force, buffer, elements, mesh);
       packNodalDataHelper(*velocity, buffer, elements, mesh);
       packNodalDataHelper(*blocked_dofs, buffer, elements, mesh);
       break;
     }
     default: {}
     }
 
     if (tag != _gst_material_id && tag != _gst_smmc_facets) {
       splitByMaterial(elements, [&](auto && mat, auto && elements) {
         mat.packData(buffer, elements, tag);
       });
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModelCohesive::unpackData(CommunicationBuffer & buffer,
                                              const Array<Element> & elements,
                                              const SynchronizationTag & tag) {
   AKANTU_DEBUG_IN();
 
   if (elements.size() == 0)
     return;
 
   if (elements(0).kind() == _ek_regular) {
     switch (tag) {
     case _gst_smmc_facets: {
       unpackElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer,
                                 elements, false, getFEEngine());
       break;
     }
     case _gst_smmc_facets_conn: {
       unpackElementalDataHelper(*global_connectivity, buffer, elements, false,
                                 getFEEngine());
       break;
     }
     case _gst_smmc_facets_stress: {
       unpackFacetStressDataHelper(facet_stress, buffer, elements);
       break;
     }
+    case _gst_material_id: {
+      for (auto && element : elements) {
+        if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1))
+          continue;
+
+        UInt recv_mat_index;
+        buffer >> recv_mat_index;
+        UInt & mat_index = material_index(element);
+        if (mat_index != UInt(-1))
+          continue;
+
+        // add ghosts element to the correct material
+        mat_index = recv_mat_index;
+        auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]);
+        mat.addFacet(element);
+        facet_material(element) = recv_mat_index;
+      }
+      SolidMechanicsModel::unpackData(buffer, elements, tag);
+      break;
+    }
     default: { SolidMechanicsModel::unpackData(buffer, elements, tag); }
     }
-  } else if (elements(0).kind() == _ek_cohesive) {
+
+    AKANTU_DEBUG_OUT();
+    return;
+  }
+
+  if (elements(0).kind() == _ek_cohesive) {
     switch (tag) {
     case _gst_material_id: {
       unpackElementalDataHelper(material_index, buffer, elements, false,
                                 getFEEngine("CohesiveFEEngine"));
       break;
     }
     case _gst_smm_boundary: {
       unpackNodalDataHelper(*internal_force, buffer, elements, mesh);
       unpackNodalDataHelper(*velocity, buffer, elements, mesh);
       unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh);
       break;
     }
     default: {}
     }
 
     if (tag != _gst_material_id && tag != _gst_smmc_facets) {
       splitByMaterial(elements, [&](auto && mat, auto && elements) {
         mat.unpackData(buffer, elements, tag);
       });
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc
index f3418e008..39e0c4939 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model_embedded_interface/embedded_interface_model.cc
@@ -1,174 +1,176 @@
 /**
  * @file   embedded_interface_model.cc
  *
  * @author Lucas Frerot <lucas.frerot@epfl.ch>
  *
  * @date creation: Fri Mar 13 2015
  * @date last modification: Mon Dec 14 2015
  *
  * @brief  Model of Solid Mechanics with embedded interfaces
  *
  * @section LICENSE
  *
  * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
  * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 #include "embedded_interface_model.hh"
-#include "material_reinforcement_template.hh"
+#include "material_reinforcement.hh"
+#include "material_elastic.hh"
 #include "mesh_iterators.hh"
 #include "integrator_gauss.hh"
 #include "shape_lagrange.hh"
 
 #ifdef AKANTU_USE_IOHELPER
 #  include "dumper_iohelper_paraview.hh"
 #  include "dumpable_inline_impl.hh"
 #endif
 
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 EmbeddedInterfaceModel::EmbeddedInterfaceModel(Mesh & mesh,
                                                Mesh & primitive_mesh,
                                                UInt spatial_dimension,
                                                const ID & id,
                                                const MemoryID & memory_id) :
   SolidMechanicsModel(mesh, spatial_dimension, id, memory_id),
   intersector(mesh, primitive_mesh),
   interface_mesh(nullptr),
   primitive_mesh(primitive_mesh),
   interface_material_selector(nullptr)
 {
   this->model_type = ModelType::_embedded_model;
 
   // This pointer should be deleted by ~SolidMechanicsModel()
   auto mat_sel_pointer =
       std::make_shared<MeshDataMaterialSelector<std::string>>("physical_names",
                                                               *this);
 
   this->setMaterialSelector(mat_sel_pointer);
 
   interface_mesh = &(intersector.getInterfaceMesh());
 
   // Create 1D FEEngine on the interface mesh
   registerFEEngineObject<MyFEEngineType>("EmbeddedInterfaceFEEngine",
                                          *interface_mesh, 1);
 
   // Registering allocator for material reinforcement
   MaterialFactory::getInstance().registerAllocator(
       "reinforcement",
       [&](UInt dim, const ID & constitutive, SolidMechanicsModel &,
           const ID & id) -> std::unique_ptr<Material> {
         if (constitutive == "elastic") {
           using mat = MaterialElastic<1>;
           switch (dim) {
           case 2:
-            return std::unique_ptr<MaterialReinforcement<2>>{
-                new MaterialReinforcementTemplate<2, mat>(*this, id)};
+            return std::make_unique<MaterialReinforcement<mat, 2>>(*this, id);
           case 3:
-            return std::unique_ptr<MaterialReinforcement<3>>{
-                new MaterialReinforcementTemplate<3, mat>(*this, id)};
+            return std::make_unique<MaterialReinforcement<mat, 3>>(*this, id);
           default:
             AKANTU_EXCEPTION("Dimension 1 is invalid for reinforcements");
           }
         } else {
           AKANTU_EXCEPTION("Reinforcement type" << constitutive
                                                 << " is not recognized");
         }
       });
 }
 
 /* -------------------------------------------------------------------------- */
 EmbeddedInterfaceModel::~EmbeddedInterfaceModel() {
   delete interface_material_selector;
 }
 
 /* -------------------------------------------------------------------------- */
 void EmbeddedInterfaceModel::initFullImpl(const ModelOptions & options) {
   const auto & eim_options =
       dynamic_cast<const EmbeddedInterfaceModelOptions &>(options);
 
   // Do no initialize interface_mesh if told so
   if (eim_options.has_intersections)
     intersector.constructData();
 
   SolidMechanicsModel::initFullImpl(options);
 
 #if defined(AKANTU_USE_IOHELPER)
   this->mesh.registerDumper<DumperParaview>("reinforcement", id);
   this->mesh.addDumpMeshToDumper("reinforcement", *interface_mesh,
                                  1, _not_ghost, _ek_regular);
 #endif
 }
 
 void EmbeddedInterfaceModel::initModel() {
   // Initialize interface FEEngine
+  SolidMechanicsModel::initModel();
   FEEngine & engine = getFEEngine("EmbeddedInterfaceFEEngine");
   engine.initShapeFunctions(_not_ghost);
   engine.initShapeFunctions(_ghost);
 }
 
 /* -------------------------------------------------------------------------- */
 void EmbeddedInterfaceModel::assignMaterialToElements(
     const ElementTypeMapArray<UInt> * filter) {
   delete interface_material_selector;
   interface_material_selector =
       new InterfaceMeshDataMaterialSelector<std::string>("physical_names",
                                                          *this);
 
-  for_each_element(mesh,
+  for_each_element(getInterfaceMesh(),
                    [&](auto && element) {
                      auto mat_index = (*interface_material_selector)(element);
-                     material_index(element) = mat_index;
+                     // material_index(element) = mat_index;
                      materials[mat_index]->addElement(element);
+		     // this->material_local_numbering(element) = index;
                    },
-                   _element_filter = filter);
+                   _element_filter = filter,
+		   _spatial_dimension = 1);
 
   SolidMechanicsModel::assignMaterialToElements(filter);
 }
 
 /* -------------------------------------------------------------------------- */
 void EmbeddedInterfaceModel::addDumpGroupFieldToDumper(const std::string & dumper_name,
                                                        const std::string & field_id,
                                                        const std::string & group_name,
                                                        const ElementKind & element_kind,
                                                        bool padding_flag) {
 #ifdef AKANTU_USE_IOHELPER
   dumper::Field * field = NULL;
 
   // If dumper is reinforcement, create a 1D elemental field
   if (dumper_name == "reinforcement")
     field = this->createElementalField(field_id, group_name, padding_flag, 1, element_kind);
   else {
     try {
       SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, element_kind, padding_flag);
     } catch (...) {}
   }
   if (field) {
     DumperIOHelper & dumper = mesh.getGroupDumper(dumper_name,group_name);
     Model::addDumpGroupFieldToDumper(field_id,field,dumper);
   }
 
 #endif
 }
 
 } // akantu
 
diff --git a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh
index 116c8d9fc..68a85eac0 100644
--- a/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh
+++ b/src/model/structural_mechanics/structural_elements/structural_element_kirchhoff_shell.hh
@@ -1,107 +1,76 @@
 /**
  * @file   structural_element_bernoulli_kirchhoff_shell.hh
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation  Tue Sep 19 2017
  *
  * @brief Specific functions for bernoulli kirchhoff shell
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #ifndef __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__
 #define __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_KIRCHHOFF_SHELL_HH__
 
+#include "structural_mechanics_model.hh"
+
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <>
-inline void StructuralMechanicsModel::assembleMass<_discrete_kirchhoff_triangle_18>() {
-
+inline void
+StructuralMechanicsModel::assembleMass<_discrete_kirchhoff_triangle_18>() {
   AKANTU_DEBUG_TO_IMPLEMENT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
-void StructuralMechanicsModel::computeRotationMatrix<_discrete_kirchhoff_triangle_18>(
-    Array<Real> & rotations) {
-  ElementType type = _discrete_kirchhoff_triangle_18;
-  Mesh & mesh = getFEEngine().getMesh();
-  UInt nb_element = mesh.getNbElement(type);
-
-  Array<UInt>::iterator<Vector<UInt> > connec_it =
-      mesh.getConnectivity(type).begin(3);
-  Array<Real>::vector_iterator nodes_it =
-      mesh.getNodes().begin(spatial_dimension);
-
-  Matrix<Real> Pe(spatial_dimension, spatial_dimension);
-  Matrix<Real> Pg(spatial_dimension, spatial_dimension);
-  Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension);
-
-  Array<Real>::matrix_iterator R_it =
-      rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom);
-
-  for (UInt e = 0; e < nb_element; ++e, ++connec_it, ++R_it) {
-
-    Pe.eye();
-
-    Matrix<Real> & R = *R_it;
-    Vector<UInt> & connec = *connec_it;
-
-    Vector<Real> x2;
-    x2 = nodes_it[connec(1)]; // X2
-    Vector<Real> x1;
-    x1 = nodes_it[connec(0)]; // X1
-    Vector<Real> x3;
-    x3 = nodes_it[connec(2)]; // X3
-
-    Vector<Real> Pg_col_1 = x2 - x1;
-
-    Vector<Real> Pg_col_2 = x3 - x1;
-
-    Vector<Real> Pg_col_3(spatial_dimension);
-    Pg_col_3.crossProduct(Pg_col_1, Pg_col_2);
-
-    for (UInt i = 0; i < spatial_dimension; ++i) {
-      Pg(i, 0) = Pg_col_1(i);
-      Pg(i, 1) = Pg_col_2(i);
-      Pg(i, 2) = Pg_col_3(i);
-    }
-
-    inv_Pg.inverse(Pg);
-    // Pe *= inv_Pg;
-    Pe.eye();
-
-    for (UInt i = 0; i < spatial_dimension; ++i) {
-      for (UInt j = 0; j < spatial_dimension; ++j) {
-        R(i, j) = Pe(i, j);
-        R(i + spatial_dimension, j + spatial_dimension) = Pe(i, j);
-      }
+void StructuralMechanicsModel::computeTangentModuli<
+    _discrete_kirchhoff_triangle_18>(Array<Real> & tangent_moduli) {
+
+  auto tangent_size =
+    ElementClass<_discrete_kirchhoff_triangle_18>::getNbStressComponents();
+  auto nb_quad =
+      getFEEngine().getNbIntegrationPoints(_discrete_kirchhoff_triangle_18);
+
+  auto H_it = tangent_moduli.begin(tangent_size, tangent_size);
+
+  for (UInt mat :
+       element_material(_discrete_kirchhoff_triangle_18, _not_ghost)) {
+    auto & m = materials[mat];
+
+    for (UInt q = 0; q < nb_quad; ++q, ++H_it) {
+      auto & H = *H_it;
+      H.clear();
+      Matrix<Real> D = {{1, m.nu, 0}, {m.nu, 1, 0}, {0, 0, (1 - m.nu) / 2}};
+      D *= m.E / (1 - m.nu * m.nu);
+      H.block(D, 0, 0);                           // in plane membrane behavior
+      H.block(D * Math::pow<3>(m.t) / 12., 3, 3); // bending behavior
     }
   }
 }
 
 }  // akantu
 
 #endif /* __AKANTU_STRUCTURAL_ELEMENT_BERNOULLI_DISCRETE_KIRCHHOFF_TRIANGLE_18_HH__ */
diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc
index 4ff13730b..8ed981deb 100644
--- a/src/model/structural_mechanics/structural_mechanics_model.cc
+++ b/src/model/structural_mechanics/structural_mechanics_model.cc
@@ -1,441 +1,490 @@
 /**
  * @file   structural_mechanics_model.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Model implementation for StucturalMechanics elements
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "structural_mechanics_model.hh"
 #include "dof_manager.hh"
-#include "sparse_matrix.hh"
 #include "integrator_gauss.hh"
-#include "shape_structural.hh"
 #include "mesh.hh"
+#include "shape_structural.hh"
+#include "sparse_matrix.hh"
 /* -------------------------------------------------------------------------- */
 #ifdef AKANTU_USE_IOHELPER
+#include "dumpable_inline_impl.hh"
 #include "dumper_elemental_field.hh"
 #include "dumper_iohelper_paraview.hh"
-#include "dumpable_inline_impl.hh"
 #include "group_manager_inline_impl.cc"
 #endif
 /* -------------------------------------------------------------------------- */
 #include "structural_mechanics_model_inline_impl.cc"
 /* -------------------------------------------------------------------------- */
 
-
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 StructuralMechanicsModel::StructuralMechanicsModel(Mesh & mesh, UInt dim,
                                                    const ID & id,
                                                    const MemoryID & memory_id)
-    : Model(mesh, ModelType::_structural_mechanics_model, dim, id, memory_id), time_step(NAN), f_m2a(1.0),
-      stress("stress", id, memory_id),
+    : Model(mesh, ModelType::_structural_mechanics_model, dim, id, memory_id),
+      time_step(NAN), f_m2a(1.0), stress("stress", id, memory_id),
       element_material("element_material", id, memory_id),
       set_ID("beam sets", id, memory_id),
       rotation_matrix("rotation_matices", id, memory_id) {
   AKANTU_DEBUG_IN();
 
   registerFEEngineObject<MyFEEngineType>("StructuralMechanicsFEEngine", mesh,
                                          spatial_dimension);
 
   if (spatial_dimension == 2)
     nb_degree_of_freedom = 3;
   else if (spatial_dimension == 3)
     nb_degree_of_freedom = 6;
   else {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
 #ifdef AKANTU_USE_IOHELPER
   this->mesh.registerDumper<DumperParaview>("paraview_all", id, true);
 #endif
   this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_structural);
 
   this->initDOFManager();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 StructuralMechanicsModel::~StructuralMechanicsModel() = default;
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::initFullImpl(const ModelOptions & options) {
   // <<<< This is the SolidMechanicsModel implementation for future ref >>>>
   // material_index.initialize(mesh, _element_kind = _ek_not_defined,
-  //                           _default_value = UInt(-1), _with_nb_element = true);
+  //                           _default_value = UInt(-1), _with_nb_element =
+  //                           true);
   // material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined,
   //                                     _with_nb_element = true);
 
   // Model::initFullImpl(options);
 
   // // initialize pbc
   // if (this->pbc_pair.size() != 0)
   //   this->initPBC();
 
   // // initialize the materials
   // if (this->parser.getLastParsedFile() != "") {
   //   this->instantiateMaterials();
   // }
 
   // this->initMaterials();
-  // this->initBC(*this, *displacement, *displacement_increment, *external_force);
+  // this->initBC(*this, *displacement, *displacement_increment,
+  // *external_force);
 
   // <<<< END >>>>
 
   Model::initFullImpl(options);
+
+  // Initializing stresses
+  ElementTypeMap<UInt> stress_components;
+
+  /// TODO this is ugly af, maybe add a function to FEEngine
+  for (auto & type : mesh.elementTypes(_spatial_dimension = _all_dimensions,
+				       _element_kind = _ek_structural)) {
+    UInt nb_components = 0;
+
+    // Getting number of components for each element type
+#define GET_(type) nb_components = ElementClass<type>::getNbStressComponents()
+    AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(GET_);
+#undef GET_
+
+    stress_components(nb_components, type);
+  }
+
+  stress.initialize(getFEEngine(), _spatial_dimension = _all_dimensions,
+                    _element_kind = _ek_structural,
+		    _all_ghost_types = true,
+                    _nb_component = [&stress_components](
+                        const ElementType & type, const GhostType &) -> UInt {
+                      return stress_components(type);
+                    });
 }
 
 /* -------------------------------------------------------------------------- */
 
 void StructuralMechanicsModel::initFEEngineBoundary() {
   /// TODO: this function should not be reimplemented
   /// we're just avoiding a call to Model::initFEEngineBoundary()
 }
 
 /* -------------------------------------------------------------------------- */
 // void StructuralMechanicsModel::setTimeStep(Real time_step) {
 //   this->time_step = time_step;
 
 // #if defined(AKANTU_USE_IOHELPER)
 //   this->mesh.getDumper().setTimeStep(time_step);
 // #endif
 // }
 
 /* -------------------------------------------------------------------------- */
 /* Initialisation                                                             */
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::initSolver(
     TimeStepSolverType time_step_solver_type, NonLinearSolverType) {
   AKANTU_DEBUG_IN();
 
   this->allocNodalField(displacement_rotation, nb_degree_of_freedom,
                         "displacement");
-  this->allocNodalField(external_force_momentum, nb_degree_of_freedom,
+  this->allocNodalField(external_force, nb_degree_of_freedom,
                         "external_force");
-  this->allocNodalField(internal_force_momentum, nb_degree_of_freedom,
+  this->allocNodalField(internal_force, nb_degree_of_freedom,
                         "internal_force");
   this->allocNodalField(blocked_dofs, nb_degree_of_freedom, "blocked_dofs");
 
   auto & dof_manager = this->getDOFManager();
 
   if (!dof_manager.hasDOFs("displacement")) {
     dof_manager.registerDOFs("displacement", *displacement_rotation,
                              _dst_nodal);
     dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs);
   }
 
   if (time_step_solver_type == _tsst_dynamic ||
       time_step_solver_type == _tsst_dynamic_lumped) {
     this->allocNodalField(velocity, spatial_dimension, "velocity");
     this->allocNodalField(acceleration, spatial_dimension, "acceleration");
 
     if (!dof_manager.hasDOFsDerivatives("displacement", 1)) {
       dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity);
       dof_manager.registerDOFsDerivative("displacement", 2,
                                          *this->acceleration);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::initModel() {
-  for (auto && type :
-       mesh.elementTypes(_element_kind = _ek_structural)) {
+  for (auto && type : mesh.elementTypes(_element_kind = _ek_structural)) {
     // computeRotationMatrix(type);
     element_material.alloc(mesh.getNbElement(type), 1, type);
   }
 
   getFEEngine().initShapeFunctions(_not_ghost);
   getFEEngine().initShapeFunctions(_ghost);
 }
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::assembleStiffnessMatrix() {
   AKANTU_DEBUG_IN();
 
   getDOFManager().getMatrix("K").clear();
 
-  for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) {
+  for (auto & type :
+       mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) {
 #define ASSEMBLE_STIFFNESS_MATRIX(type) assembleStiffnessMatrix<type>();
 
     AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(ASSEMBLE_STIFFNESS_MATRIX);
 #undef ASSEMBLE_STIFFNESS_MATRIX
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::computeStresses() {
   AKANTU_DEBUG_IN();
 
-  for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) {
+  for (auto & type :
+       mesh.elementTypes(spatial_dimension, _not_ghost, _ek_structural)) {
 #define COMPUTE_STRESS_ON_QUAD(type) computeStressOnQuad<type>();
 
     AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_STRESS_ON_QUAD);
 #undef COMPUTE_STRESS_ON_QUAD
   }
 
   AKANTU_DEBUG_OUT();
 }
 
-/* -------------------------------------------------------------------------- */
-void StructuralMechanicsModel::updateResidual() {
-  AKANTU_DEBUG_IN();
-
-  auto & K = getDOFManager().getMatrix("K");
-
-  internal_force_momentum->clear();
-  K.matVecMul(*displacement_rotation, *internal_force_momentum);
-  *internal_force_momentum *= -1.;
-
-  getDOFManager().assembleToResidual("displacement", *external_force_momentum,
-                                     1.);
-
-  getDOFManager().assembleToResidual("displacement", *internal_force_momentum,
-                                     1.);
-
-  AKANTU_DEBUG_OUT();
-}
-
 /* -------------------------------------------------------------------------- */
 void StructuralMechanicsModel::computeRotationMatrix(const ElementType & type) {
   Mesh & mesh = getFEEngine().getMesh();
 
   UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   UInt nb_element = mesh.getNbElement(type);
 
   if (!rotation_matrix.exists(type)) {
     rotation_matrix.alloc(nb_element,
                           nb_degree_of_freedom * nb_nodes_per_element *
-                          nb_degree_of_freedom * nb_nodes_per_element,
+                              nb_degree_of_freedom * nb_nodes_per_element,
                           type);
   } else {
     rotation_matrix(type).resize(nb_element);
   }
   rotation_matrix(type).clear();
 
   Array<Real> rotations(nb_element,
                         nb_degree_of_freedom * nb_degree_of_freedom);
   rotations.clear();
 
 #define COMPUTE_ROTATION_MATRIX(type) computeRotationMatrix<type>(rotations);
 
   AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_ROTATION_MATRIX);
 #undef COMPUTE_ROTATION_MATRIX
 
   auto R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom);
   auto T_it =
       rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element,
                                   nb_degree_of_freedom * nb_nodes_per_element);
 
   for (UInt el = 0; el < nb_element; ++el, ++R_it, ++T_it) {
     auto & T = *T_it;
     auto & R = *R_it;
     for (UInt k = 0; k < nb_nodes_per_element; ++k) {
       for (UInt i = 0; i < nb_degree_of_freedom; ++i)
         for (UInt j = 0; j < nb_degree_of_freedom; ++j)
           T(k * nb_degree_of_freedom + i, k * nb_degree_of_freedom + j) =
               R(i, j);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 dumper::Field * StructuralMechanicsModel::createNodalFieldBool(
     const std::string & field_name, const std::string & group_name,
     __attribute__((unused)) bool padding_flag) {
 
   std::map<std::string, Array<bool> *> uint_nodal_fields;
   uint_nodal_fields["blocked_dofs"] = blocked_dofs;
 
   dumper::Field * field = NULL;
   field = mesh.createNodalField(uint_nodal_fields[field_name], group_name);
   return field;
 }
 
 /* -------------------------------------------------------------------------- */
 dumper::Field *
 StructuralMechanicsModel::createNodalFieldReal(const std::string & field_name,
                                                const std::string & group_name,
                                                bool padding_flag) {
 
   UInt n;
   if (spatial_dimension == 2) {
     n = 2;
   } else {
     n = 3;
   }
 
   if (field_name == "displacement") {
     return mesh.createStridedNodalField(displacement_rotation, group_name, n, 0,
                                         padding_flag);
   }
 
   if (field_name == "rotation") {
     return mesh.createStridedNodalField(displacement_rotation, group_name,
                                         nb_degree_of_freedom - n, n,
                                         padding_flag);
   }
 
   if (field_name == "force") {
-    return mesh.createStridedNodalField(external_force_momentum, group_name, n,
+    return mesh.createStridedNodalField(external_force, group_name, n,
                                         0, padding_flag);
   }
 
   if (field_name == "momentum") {
-    return mesh.createStridedNodalField(external_force_momentum, group_name,
+    return mesh.createStridedNodalField(external_force, group_name,
                                         nb_degree_of_freedom - n, n,
                                         padding_flag);
   }
 
   if (field_name == "internal_force") {
-    return mesh.createStridedNodalField(internal_force_momentum, group_name, n,
+    return mesh.createStridedNodalField(internal_force, group_name, n,
                                         0, padding_flag);
   }
 
   if (field_name == "internal_momentum") {
-    return mesh.createStridedNodalField(internal_force_momentum, group_name,
+    return mesh.createStridedNodalField(internal_force, group_name,
                                         nb_degree_of_freedom - n, n,
                                         padding_flag);
   }
 
   return nullptr;
 }
 
 /* -------------------------------------------------------------------------- */
 dumper::Field * StructuralMechanicsModel::createElementalField(
     const std::string & field_name, const std::string & group_name, bool,
     const ElementKind & kind, const std::string &) {
 
   dumper::Field * field = NULL;
 
   if (field_name == "element_index_by_material")
     field = mesh.createElementalField<UInt, Vector, dumper::ElementalField>(
         field_name, group_name, this->spatial_dimension, kind);
 
   return field;
 }
 
 /* -------------------------------------------------------------------------- */
 /* Virtual methods from SolverCallback */
 /* -------------------------------------------------------------------------- */
 /// get the type of matrix needed
 MatrixType StructuralMechanicsModel::getMatrixType(const ID & /*id*/) {
   return _symmetric;
 }
 
 /// callback to assemble a Matrix
 void StructuralMechanicsModel::assembleMatrix(const ID & id) {
   if (id == "K")
     assembleStiffnessMatrix();
 }
 
 /// callback to assemble a lumped Matrix
 void StructuralMechanicsModel::assembleLumpedMatrix(const ID & /*id*/) {}
 
 /// callback to assemble the residual StructuralMechanicsModel::(rhs)
 void StructuralMechanicsModel::assembleResidual() {
-  this->getDOFManager().assembleToResidual("displacement",
-                                           *this->external_force_momentum, 1);
+  AKANTU_DEBUG_IN();
+
+  internal_force->clear();
+  computeStresses();
+  assembleInternalForce();
+
+  getDOFManager().assembleToResidual("displacement", *external_force,
+                                     1.);
+
+  getDOFManager().assembleToResidual("displacement", *internal_force,
+                                     -1);
+
+  AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /* Virtual methods from MeshEventHandler */
 /* -------------------------------------------------------------------------- */
 
 /// function to implement to react on  akantu::NewNodesEvent
 void StructuralMechanicsModel::onNodesAdded(const Array<UInt> & /*nodes_list*/,
                                             const NewNodesEvent & /*event*/) {}
 /// function to implement to react on  akantu::RemovedNodesEvent
 void StructuralMechanicsModel::onNodesRemoved(
     const Array<UInt> & /*nodes_list*/, const Array<UInt> & /*new_numbering*/,
     const RemovedNodesEvent & /*event*/) {}
 /// function to implement to react on  akantu::NewElementsEvent
 void StructuralMechanicsModel::onElementsAdded(
     const Array<Element> & /*elements_list*/,
     const NewElementsEvent & /*event*/) {}
 /// function to implement to react on  akantu::RemovedElementsEvent
 void StructuralMechanicsModel::onElementsRemoved(
     const Array<Element> & /*elements_list*/,
     const ElementTypeMapArray<UInt> & /*new_numbering*/,
     const RemovedElementsEvent & /*event*/) {}
 /// function to implement to react on  akantu::ChangedElementsEvent
 void StructuralMechanicsModel::onElementsChanged(
     const Array<Element> & /*old_elements_list*/,
     const Array<Element> & /*new_elements_list*/,
     const ElementTypeMapArray<UInt> & /*new_numbering*/,
     const ChangedElementsEvent & /*event*/) {}
 
 /* -------------------------------------------------------------------------- */
 /* Virtual methods from Model */
 /* -------------------------------------------------------------------------- */
 /// get some default values for derived classes
-std::tuple<ID, TimeStepSolverType> StructuralMechanicsModel::getDefaultSolverID(
-    const AnalysisMethod & method) {
+std::tuple<ID, TimeStepSolverType>
+StructuralMechanicsModel::getDefaultSolverID(const AnalysisMethod & method) {
   switch (method) {
   case _static: {
     return std::make_tuple("static", _tsst_static);
   }
   case _implicit_dynamic: {
     return std::make_tuple("implicit", _tsst_dynamic);
   }
   default:
     return std::make_tuple("unknown", _tsst_not_defined);
   }
 }
 
 /* ------------------------------------------------------------------------ */
 ModelSolverOptions StructuralMechanicsModel::getDefaultSolverOptions(
     const TimeStepSolverType & type) const {
   ModelSolverOptions options;
 
   switch (type) {
   case _tsst_static: {
     options.non_linear_solver_type = _nls_linear;
     options.integration_scheme_type["displacement"] = _ist_pseudo_time;
     options.solution_type["displacement"] = IntegrationScheme::_not_defined;
     break;
   }
   default:
     AKANTU_EXCEPTION(type << " is not a valid time step solver type");
   }
 
   return options;
 }
+
 /* -------------------------------------------------------------------------- */
+void StructuralMechanicsModel::assembleInternalForce() {
+  for (auto type : mesh.elementTypes(_spatial_dimension = _all_dimensions,
+				     _element_kind = _ek_structural)) {
+    assembleInternalForce(type, _not_ghost);
+    // assembleInternalForce(type, _ghost);
+  }
+}
 
+/* -------------------------------------------------------------------------- */
+void StructuralMechanicsModel::assembleInternalForce(const ElementType & type,
+                                                     GhostType gt) {
+  auto & fem = getFEEngine();
+  auto & sigma = stress(type, gt);
+  auto ndof = getNbDegreeOfFreedom(type);
+  auto nb_nodes = mesh.getNbNodesPerElement(type);
+  auto ndof_per_elem = ndof * nb_nodes;
+
+  Array<Real> BtSigma(fem.getNbIntegrationPoints(type) *
+                          mesh.getNbElement(type),
+                      ndof_per_elem, "BtSigma");
+  fem.computeBtD(sigma, BtSigma, type, gt);
+
+  Array<Real> intBtSigma(0, ndof_per_elem,
+                         "intBtSigma");
+  fem.integrate(BtSigma, intBtSigma, ndof_per_elem, type, gt);
+  BtSigma.resize(0);
+
+  getDOFManager().assembleElementalArrayLocalArray(intBtSigma, *internal_force,
+                                                   type, gt, 1);
+}
+/* -------------------------------------------------------------------------- */
 
 } // namespace akantu
diff --git a/src/model/structural_mechanics/structural_mechanics_model.hh b/src/model/structural_mechanics/structural_mechanics_model.hh
index fcb036768..b06e1ea41 100644
--- a/src/model/structural_mechanics/structural_mechanics_model.hh
+++ b/src/model/structural_mechanics/structural_mechanics_model.hh
@@ -1,327 +1,333 @@
 /**
  * @file   structural_mechanics_model.hh
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Thu Jan 21 2016
  *
  * @brief  Particular implementation of the structural elements in the
  * StructuralMechanicsModel
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "aka_named_argument.hh"
 #include "boundary_condition.hh"
 #include "model.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__
 #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 class Material;
 class MaterialSelector;
 class DumperIOHelper;
 class NonLocalManager;
 template <ElementKind kind, class IntegrationOrderFunctor>
 class IntegratorGauss;
 template <ElementKind kind> class ShapeStructural;
 } // namespace akantu
 
 namespace akantu {
 
 struct StructuralMaterial {
   Real E{0};
   Real A{1};
   Real I{0};
   Real Iz{0};
   Real Iy{0};
   Real GJ{0};
   Real rho{0};
   Real t{0};
   Real nu{0};
 };
 
 class StructuralMechanicsModel : public Model {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   using MyFEEngineType =
       FEEngineTemplate<IntegratorGauss, ShapeStructural, _ek_structural>;
 
   StructuralMechanicsModel(Mesh & mesh,
                            UInt spatial_dimension = _all_dimensions,
                            const ID & id = "structural_mechanics_model",
                            const MemoryID & memory_id = 0);
 
   virtual ~StructuralMechanicsModel();
 
   /// Init full model
   void initFullImpl(const ModelOptions & options) override;
 
   /// Init boundary FEEngine
   void initFEEngineBoundary() override;
 
 
   /* ------------------------------------------------------------------------ */
   /* Virtual methods from SolverCallback */
   /* ------------------------------------------------------------------------ */
   /// get the type of matrix needed
   MatrixType getMatrixType(const ID &) override;
 
   /// callback to assemble a Matrix
   void assembleMatrix(const ID &) override;
 
   /// callback to assemble a lumped Matrix
   void assembleLumpedMatrix(const ID &) override;
 
   /// callback to assemble the residual (rhs)
   void assembleResidual() override;
 
   /* ------------------------------------------------------------------------ */
   /* Virtual methods from MeshEventHandler */
   /* ------------------------------------------------------------------------ */
 
   /// function to implement to react on  akantu::NewNodesEvent
   void onNodesAdded(const Array<UInt> & nodes_list,
                     const NewNodesEvent & event) override;
   /// function to implement to react on  akantu::RemovedNodesEvent
   void onNodesRemoved(const Array<UInt> & nodes_list,
                       const Array<UInt> & new_numbering,
                       const RemovedNodesEvent & event) override;
   /// function to implement to react on  akantu::NewElementsEvent
   void onElementsAdded(const Array<Element> & elements_list,
                        const NewElementsEvent & event) override;
   /// function to implement to react on  akantu::RemovedElementsEvent
   void onElementsRemoved(const Array<Element> & elements_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const RemovedElementsEvent & event) override;
   /// function to implement to react on  akantu::ChangedElementsEvent
   void onElementsChanged(const Array<Element> & old_elements_list,
                          const Array<Element> & new_elements_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const ChangedElementsEvent & event) override;
 
   /* ------------------------------------------------------------------------ */
   /* Virtual methods from Model */
   /* ------------------------------------------------------------------------ */
 protected:
   /// get some default values for derived classes
   std::tuple<ID, TimeStepSolverType>
   getDefaultSolverID(const AnalysisMethod & method) override;
 
   ModelSolverOptions
   getDefaultSolverOptions(const TimeStepSolverType & type) const override;
 
+  UInt getNbDegreeOfFreedom(const ElementType & type) const;
+
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
   void initSolver(TimeStepSolverType, NonLinearSolverType) override;
 
   /// initialize the model
   void initModel() override;
 
   /// compute the stresses per elements
   void computeStresses();
 
+  /// compute the nodal forces
+  void assembleInternalForce();
+
+  /// compute the nodal forces for an element type
+  void assembleInternalForce(const ElementType & type, GhostType gt);
+
   /// assemble the stiffness matrix
   void assembleStiffnessMatrix();
 
   /// assemble the mass matrix for consistent mass resolutions
   void assembleMass();
 
-  /// update the residual vector
-  void updateResidual();
-
+  /// TODO remove
   void computeRotationMatrix(const ElementType & type);
 
 protected:
   /// compute Rotation Matrices
   template <const ElementType type>
   void computeRotationMatrix(__attribute__((unused)) Array<Real> & rotations) {}
 
   /* ------------------------------------------------------------------------ */
   /* Mass (structural_mechanics_model_mass.cc) */
   /* ------------------------------------------------------------------------ */
 
   /// assemble the mass matrix for either _ghost or _not_ghost elements
   void assembleMass(GhostType ghost_type);
 
   /// computes rho
   void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type);
 
   /// finish the computation of residual to solve in increment
   void updateResidualInternal();
 
   /* ------------------------------------------------------------------------ */
 private:
   template <ElementType type> void assembleStiffnessMatrix();
   template <ElementType type> void assembleMass();
   template <ElementType type> void computeStressOnQuad();
   template <ElementType type>
   void computeTangentModuli(Array<Real> & tangent_moduli);
 
   /* ------------------------------------------------------------------------ */
   /* Dumpable interface                                                       */
   /* ------------------------------------------------------------------------ */
 public:
   virtual dumper::Field * createNodalFieldReal(const std::string & field_name,
                                                const std::string & group_name,
                                                bool padding_flag);
 
   virtual dumper::Field * createNodalFieldBool(const std::string & field_name,
                                                const std::string & group_name,
                                                bool padding_flag);
 
   virtual dumper::Field *
   createElementalField(const std::string & field_name,
                        const std::string & group_name, bool padding_flag,
                        const ElementKind & kind,
                        const std::string & fe_engine_id = "");
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// set the value of the time step
   // void setTimeStep(Real time_step, const ID & solver_id = "") override;
 
   /// return the dimension of the system space
   AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt);
 
   /// get the StructuralMechanicsModel::displacement vector
   AKANTU_GET_MACRO(Displacement, *displacement_rotation, Array<Real> &);
 
   /// get the StructuralMechanicsModel::velocity vector
   AKANTU_GET_MACRO(Velocity, *velocity, Array<Real> &);
 
   /// get    the    StructuralMechanicsModel::acceleration    vector,   updated
   /// by
   /// StructuralMechanicsModel::updateAcceleration
   AKANTU_GET_MACRO(Acceleration, *acceleration, Array<Real> &);
 
   /// get the StructuralMechanicsModel::external_force vector
-  AKANTU_GET_MACRO(ExternalForce, *external_force_momentum, Array<Real> &);
+  AKANTU_GET_MACRO(ExternalForce, *external_force, Array<Real> &);
 
   /// get the StructuralMechanicsModel::internal_force vector (boundary forces)
-  AKANTU_GET_MACRO(InternalForce, *internal_force_momentum, Array<Real> &);
+  AKANTU_GET_MACRO(InternalForce, *internal_force, Array<Real> &);
 
   /// get the StructuralMechanicsModel::boundary vector
   AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(RotationMatrix, rotation_matrix, Real);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementMaterial, element_material, UInt);
 
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Set_ID, set_ID, UInt);
 
   void addMaterial(StructuralMaterial & material) {
     materials.push_back(material);
   }
 
   const StructuralMaterial & getMaterial(const Element & element) const {
     return materials[element_material(element)];
   }
 
   /* ------------------------------------------------------------------------ */
   /* Boundaries (structural_mechanics_model_boundary.cc)                      */
   /* ------------------------------------------------------------------------ */
 public:
   /// Compute Linear load function set in global axis
   template <ElementType type>
   void computeForcesByGlobalTractionArray(const Array<Real> & tractions);
 
   /// Compute Linear load function set in local axis
   template <ElementType type>
   void computeForcesByLocalTractionArray(const Array<Real> & tractions);
 
   /// compute force vector from a function(x,y,momentum) that describe stresses
   // template <ElementType type>
   // void computeForcesFromFunction(BoundaryFunction in_function,
   //                                BoundaryFunctionType function_type);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
   /// time step
   Real time_step;
 
   /// conversion coefficient form force/mass to acceleration
   Real f_m2a;
 
   /// displacements array
   Array<Real> * displacement_rotation{nullptr};
 
   /// velocities array
   Array<Real> * velocity{nullptr};
 
   /// accelerations array
   Array<Real> * acceleration{nullptr};
 
   /// forces array
-  Array<Real> * internal_force_momentum{nullptr};
+  Array<Real> * internal_force{nullptr};
 
   /// forces array
-  Array<Real> * external_force_momentum{nullptr};
+  Array<Real> * external_force{nullptr};
 
   /// lumped mass array
   Array<Real> * mass{nullptr};
 
   /// boundaries array
   Array<bool> * blocked_dofs{nullptr};
 
   /// stress array
   ElementTypeMapArray<Real> stress;
 
   ElementTypeMapArray<UInt> element_material;
 
   // Define sets of beams
   ElementTypeMapArray<UInt> set_ID;
 
   /// number of degre of freedom
   UInt nb_degree_of_freedom;
 
   // Rotation matrix
   ElementTypeMapArray<Real> rotation_matrix;
 
   // /// analysis method check the list in akantu::AnalysisMethod
   // AnalysisMethod method;
 
   /// flag defining if the increment must be computed or not
   bool increment_flag;
 
   /* ------------------------------------------------------------------------ */
   std::vector<StructuralMaterial> materials;
 };
 
 } // namespace akantu
 
 #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_HH__ */
diff --git a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc
index ec27c7ede..7ef7ed0cc 100644
--- a/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc
+++ b/src/model/structural_mechanics/structural_mechanics_model_inline_impl.cc
@@ -1,361 +1,370 @@
 /**
  * @file   structural_mechanics_model_inline_impl.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Damien Spielmann <damien.spielmann@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Implementation of inline functions of StructuralMechanicsModel
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "structural_mechanics_model.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__
 #define __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__
 
 namespace akantu {
+/* -------------------------------------------------------------------------- */
+inline UInt
+StructuralMechanicsModel::getNbDegreeOfFreedom(const ElementType & type) const {
+  UInt ndof = 0;
+#define GET_(type) ndof = ElementClass<type>::getNbDegreeOfFreedom()
+  AKANTU_BOOST_KIND_ELEMENT_SWITCH(GET_, _ek_structural);
+#undef GET_
+
+  return ndof;
+}
+
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeTangentModuli(
     Array<Real> & /*tangent_moduli*/) {
   AKANTU_DEBUG_TO_IMPLEMENT();
 }
 } // namespace akantu
 
 #include "structural_element_bernoulli_beam_2.hh"
 #include "structural_element_bernoulli_beam_3.hh"
 #include "structural_element_kirchhoff_shell.hh"
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::assembleStiffnessMatrix() {
   AKANTU_DEBUG_IN();
 
   auto nb_element = getFEEngine().getMesh().getNbElement(type);
   auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type);
   auto tangent_size = ElementClass<type>::getNbStressComponents();
 
   auto tangent_moduli = std::make_unique<Array<Real>>(
       nb_element * nb_quadrature_points, tangent_size * tangent_size,
       "tangent_stiffness_matrix");
   computeTangentModuli<type>(*tangent_moduli);
 
   /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   UInt bt_d_b_size = nb_degree_of_freedom * nb_nodes_per_element;
 
   auto bt_d_b = std::make_unique<Array<Real>>(
       nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B");
 
   const auto & b = getFEEngine().getShapesDerivatives(type);
 
   Matrix<Real> BtD(bt_d_b_size, tangent_size);
 
   for (auto && tuple :
        zip(make_view(b, tangent_size, bt_d_b_size),
            make_view(*tangent_moduli, tangent_size, tangent_size),
            make_view(*bt_d_b, bt_d_b_size, bt_d_b_size))) {
     auto & B = std::get<0>(tuple);
     auto & D = std::get<1>(tuple);
     auto & BtDB = std::get<2>(tuple);
     BtD.mul<true, false>(B, D);
     BtDB.template mul<false, false>(BtD, B);
   }
 
   /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
   auto int_bt_d_b = std::make_unique<Array<Real>>(
       nb_element, bt_d_b_size * bt_d_b_size, "int_B^t*D*B");
 
   getFEEngine().integrate(*bt_d_b, *int_bt_d_b, bt_d_b_size * bt_d_b_size,
                           type);
 
   getDOFManager().assembleElementalMatricesToMatrix(
       "K", "displacement", *int_bt_d_b, type, _not_ghost, _symmetric);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeStressOnQuad() {
   AKANTU_DEBUG_IN();
 
   Array<Real> & sigma = stress(type, _not_ghost);
 
   auto nb_element = mesh.getNbElement(type);
   auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
   auto nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type);
   auto tangent_size = ElementClass<type>::getNbStressComponents();
 
   auto tangent_moduli = std::make_unique<Array<Real>>(
       nb_element * nb_quadrature_points, tangent_size * tangent_size,
       "tangent_stiffness_matrix");
 
   computeTangentModuli<type>(*tangent_moduli);
 
   /// compute DB
   auto d_b_size = nb_degree_of_freedom * nb_nodes_per_element;
 
   auto d_b = std::make_unique<Array<Real>>(nb_element * nb_quadrature_points,
                                            d_b_size * tangent_size, "D*B");
 
   const auto & b = getFEEngine().getShapesDerivatives(type);
 
   auto B = b.begin(tangent_size, d_b_size);
   auto D = tangent_moduli->begin(tangent_size, tangent_size);
   auto D_B = d_b->begin(tangent_size, d_b_size);
 
   for (UInt e = 0; e < nb_element; ++e) {
     for (UInt q = 0; q < nb_quadrature_points; ++q, ++B, ++D, ++D_B) {
       D_B->template mul<false, false>(*D, *B);
     }
   }
 
   /// compute DBu
   D_B = d_b->begin(tangent_size, d_b_size);
   auto DBu = sigma.begin(tangent_size);
-  Vector<Real> ul(d_b_size);
 
   Array<Real> u_el(0, d_b_size);
   FEEngine::extractNodalToElementField(mesh, *displacement_rotation, u_el,
                                        type);
 
   auto ug = u_el.begin(d_b_size);
-  auto T = rotation_matrix(type).begin(d_b_size, d_b_size);
 
-  for (UInt e = 0; e < nb_element; ++e, ++T, ++ug) {
-    ul.mul<false>(*T, *ug);
+  // No need to rotate because B is post-multiplied
+  for (UInt e = 0; e < nb_element; ++e, ++ug) {
     for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_B, ++DBu) {
-      DBu->template mul<false>(*D_B, ul);
+      DBu->template mul<false>(*D_B, *ug);
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeForcesByLocalTractionArray(
     const Array<Real> & tractions) {
   AKANTU_DEBUG_IN();
 
 #if 0
   UInt nb_element = getFEEngine().getMesh().getNbElement(type);
   UInt nb_nodes_per_element =
       getFEEngine().getMesh().getNbNodesPerElement(type);
   UInt nb_quad = getFEEngine().getNbIntegrationPoints(type);
 
   // check dimension match
   AKANTU_DEBUG_ASSERT(
       Mesh::getSpatialDimension(type) == getFEEngine().getElementDimension(),
       "element type dimension does not match the dimension of boundaries : "
           << getFEEngine().getElementDimension()
           << " != " << Mesh::getSpatialDimension(type));
 
   // check size of the vector
   AKANTU_DEBUG_ASSERT(
       tractions.size() == nb_quad * nb_element,
       "the size of the vector should be the total number of quadrature points");
 
   // check number of components
   AKANTU_DEBUG_ASSERT(tractions.getNbComponent() == nb_degree_of_freedom,
                       "the number of components should be the spatial "
                       "dimension of the problem");
 
   Array<Real> Nvoigt(nb_element * nb_quad, nb_degree_of_freedom *
                                                nb_degree_of_freedom *
                                                nb_nodes_per_element);
   transferNMatrixToSymVoigtNMatrix<type>(Nvoigt);
 
   Array<Real>::const_matrix_iterator N_it = Nvoigt.begin(
       nb_degree_of_freedom, nb_degree_of_freedom * nb_nodes_per_element);
   Array<Real>::const_matrix_iterator T_it =
       rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element,
                                   nb_degree_of_freedom * nb_nodes_per_element);
   Array<Real>::const_vector_iterator te_it =
       tractions.begin(nb_degree_of_freedom);
 
   Array<Real> funct(nb_element * nb_quad,
                     nb_degree_of_freedom * nb_nodes_per_element, 0.);
   Array<Real>::iterator<Vector<Real>> Fe_it =
       funct.begin(nb_degree_of_freedom * nb_nodes_per_element);
 
   Vector<Real> fe(nb_degree_of_freedom * nb_nodes_per_element);
   for (UInt e = 0; e < nb_element; ++e, ++T_it) {
     const Matrix<Real> & T = *T_it;
     for (UInt q = 0; q < nb_quad; ++q, ++N_it, ++te_it, ++Fe_it) {
       const Matrix<Real> & N = *N_it;
       const Vector<Real> & te = *te_it;
       Vector<Real> & Fe = *Fe_it;
 
       // compute N^t tl
       fe.mul<true>(N, te);
       // turn N^t tl back in the global referential
       Fe.mul<true>(T, fe);
     }
   }
 
   // allocate the vector that will contain the integrated values
   std::stringstream name;
   name << id << type << ":integral_boundary";
   Array<Real> int_funct(nb_element, nb_degree_of_freedom * nb_nodes_per_element,
                         name.str());
 
   // do the integration
   getFEEngine().integrate(funct, int_funct,
                           nb_degree_of_freedom * nb_nodes_per_element, type);
 
   // assemble the result into force vector
   getFEEngine().assembleArray(int_funct, *force_momentum,
                               dof_synchronizer->getLocalDOFEquationNumbers(),
                               nb_degree_of_freedom, type);
 #endif
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementType type>
 void StructuralMechanicsModel::computeForcesByGlobalTractionArray(
     const Array<Real> & traction_global) {
   AKANTU_DEBUG_IN();
 #if 0
   UInt nb_element = mesh.getNbElement(type);
   UInt nb_quad = getFEEngine().getNbIntegrationPoints(type);
   UInt nb_nodes_per_element =
       getFEEngine().getMesh().getNbNodesPerElement(type);
 
   std::stringstream name;
   name << id << ":structuralmechanics:imposed_linear_load";
   Array<Real> traction_local(nb_element * nb_quad, nb_degree_of_freedom,
                              name.str());
 
   Array<Real>::const_matrix_iterator T_it =
       rotation_matrix(type).begin(nb_degree_of_freedom * nb_nodes_per_element,
                                   nb_degree_of_freedom * nb_nodes_per_element);
 
   Array<Real>::const_iterator<Vector<Real>> Te_it =
       traction_global.begin(nb_degree_of_freedom);
   Array<Real>::iterator<Vector<Real>> te_it =
       traction_local.begin(nb_degree_of_freedom);
 
   Matrix<Real> R(nb_degree_of_freedom, nb_degree_of_freedom);
   for (UInt e = 0; e < nb_element; ++e, ++T_it) {
     const Matrix<Real> & T = *T_it;
     for (UInt i = 0; i < nb_degree_of_freedom; ++i)
       for (UInt j = 0; j < nb_degree_of_freedom; ++j)
         R(i, j) = T(i, j);
 
     for (UInt q = 0; q < nb_quad; ++q, ++Te_it, ++te_it) {
       const Vector<Real> & Te = *Te_it;
       Vector<Real> & te = *te_it;
       // turn the traction in the local referential
       te.mul<false>(R, Te);
     }
   }
 
   computeForcesByLocalTractionArray<type>(traction_local);
 #endif
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * @param myf pointer  to a function that fills a  vector/tensor with respect to
  * passed coordinates
  */
 #if 0
 template <ElementType type>
 inline void StructuralMechanicsModel::computeForcesFromFunction(
     BoundaryFunction myf, BoundaryFunctionType function_type) {
   /** function type is
    ** _bft_forces : linear load is given
    ** _bft_stress : stress function is given -> Not already done for this kind
    *of model
    */
 
   std::stringstream name;
   name << id << ":structuralmechanics:imposed_linear_load";
   Array<Real> lin_load(0, nb_degree_of_freedom, name.str());
   name.clear();
 
   UInt offset = nb_degree_of_freedom;
 
   // prepare the loop over element types
   UInt nb_quad = getFEEngine().getNbIntegrationPoints(type);
   UInt nb_element = getFEEngine().getMesh().getNbElement(type);
 
   name.clear();
   name << id << ":structuralmechanics:quad_coords";
   Array<Real> quad_coords(nb_element * nb_quad, spatial_dimension,
                           "quad_coords");
 
   getFEEngineClass<MyFEEngineType>()
       .getShapeFunctions()
       .interpolateOnIntegrationPoints<type>(getFEEngine().getMesh().getNodes(),
                                             quad_coords, spatial_dimension);
   getFEEngineClass<MyFEEngineType>()
       .getShapeFunctions()
       .interpolateOnIntegrationPoints<type>(
           getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension,
           _not_ghost, empty_filter, true, 0, 1, 1);
   if (spatial_dimension == 3)
     getFEEngineClass<MyFEEngineType>()
         .getShapeFunctions()
         .interpolateOnIntegrationPoints<type>(
             getFEEngine().getMesh().getNodes(), quad_coords, spatial_dimension,
             _not_ghost, empty_filter, true, 0, 2, 2);
   lin_load.resize(nb_element * nb_quad);
   Real * imposed_val = lin_load.storage();
 
   /// sigma/load on each quadrature points
   Real * qcoord = quad_coords.storage();
   for (UInt el = 0; el < nb_element; ++el) {
     for (UInt q = 0; q < nb_quad; ++q) {
       myf(qcoord, imposed_val, NULL, 0);
       imposed_val += offset;
       qcoord += spatial_dimension;
     }
   }
 
   switch (function_type) {
   case _bft_traction_local:
     computeForcesByLocalTractionArray<type>(lin_load);
     break;
   case _bft_traction:
     computeForcesByGlobalTractionArray<type>(lin_load);
     break;
   default:
     break;
   }
 }
 #endif
 } // namespace akantu
 
 #endif /* __AKANTU_STRUCTURAL_MECHANICS_MODEL_INLINE_IMPL_CC__ */
diff --git a/src/synchronizer/communications.hh b/src/synchronizer/communications.hh
index 528a8274f..58f56ca01 100644
--- a/src/synchronizer/communications.hh
+++ b/src/synchronizer/communications.hh
@@ -1,272 +1,273 @@
 /**
  * @file   communications.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Aug 24 13:56:14 2016
  *
  * @brief
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "communication_descriptor.hh"
 #include "communicator.hh"
 /* -------------------------------------------------------------------------- */
 #include <map>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_COMMUNICATIONS_HH__
 #define __AKANTU_COMMUNICATIONS_HH__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <class Entity> class Communications {
 public:
   using Scheme = Array<Entity>;
 
 protected:
   using CommunicationPerProcs = std::map<UInt, Communication>;
   using CommunicationsPerTags =
       std::map<SynchronizationTag, CommunicationPerProcs>;
   using CommunicationSchemes = std::map<UInt, Scheme>;
   using Request = std::map<UInt, std::vector<CommunicationRequest>>;
 
   friend class CommunicationDescriptor<Entity>;
 
 public:
   using scheme_iterator = typename CommunicationSchemes::iterator;
   using const_scheme_iterator = typename CommunicationSchemes::const_iterator;
 
   /* ------------------------------------------------------------------------ */
   class iterator;
   class tag_iterator;
   /* ------------------------------------------------------------------------ */
 
 public:
   CommunicationPerProcs & getCommunications(const SynchronizationTag & tag,
                                             const CommunicationSendRecv & sr);
 
   /* ------------------------------------------------------------------------ */
   bool hasPending(const SynchronizationTag & tag,
                   const CommunicationSendRecv & sr) const;
   UInt getPending(const SynchronizationTag & tag,
                   const CommunicationSendRecv & sr) const;
 
   /* ------------------------------------------------------------------------ */
   iterator begin(const SynchronizationTag & tag,
                  const CommunicationSendRecv & sr);
   iterator end(const SynchronizationTag & tag,
                const CommunicationSendRecv & sr);
 
   /* ------------------------------------------------------------------------ */
   iterator waitAny(const SynchronizationTag & tag,
                    const CommunicationSendRecv & sr);
 
   /* ------------------------------------------------------------------------ */
   void waitAll(const SynchronizationTag & tag,
                const CommunicationSendRecv & sr);
   void incrementPending(const SynchronizationTag & tag,
                         const CommunicationSendRecv & sr);
   void decrementPending(const SynchronizationTag & tag,
                         const CommunicationSendRecv & sr);
   void freeRequests(const SynchronizationTag & tag,
                     const CommunicationSendRecv & sr);
 
   /* ------------------------------------------------------------------------ */
   Scheme & createScheme(UInt proc, const CommunicationSendRecv & sr);
   void resetSchemes(const CommunicationSendRecv & sr);
 
   /* ------------------------------------------------------------------------ */
   void setCommunicationSize(const SynchronizationTag & tag, UInt proc,
                             UInt size, const CommunicationSendRecv & sr);
 
 public:
   explicit Communications(const Communicator & communicator);
+  explicit Communications(const Communications & communications);
 
   /* ------------------------------------------------------------------------ */
   class IterableCommunicationDesc {
   public:
     IterableCommunicationDesc(Communications & communications,
                               SynchronizationTag tag,
                               CommunicationSendRecv sr)
         : communications(communications), tag(std::move(tag)), sr(std::move(sr)) {}
     auto begin() { return communications.begin(tag, sr); }
     auto end() { return communications.end(tag, sr); }
 
   private:
     Communications & communications;
     SynchronizationTag tag;
     CommunicationSendRecv sr;
   };
 
   auto iterateRecv(const SynchronizationTag & tag) {
     return IterableCommunicationDesc(*this, tag, _recv);
   }
   auto iterateSend(const SynchronizationTag & tag) {
     return IterableCommunicationDesc(*this, tag, _send);
   }
 
   /* ------------------------------------------------------------------------ */
   // iterator begin_send(const SynchronizationTag & tag);
   // iterator end_send(const SynchronizationTag & tag);
 
   /* ------------------------------------------------------------------------ */
   // iterator begin_recv(const SynchronizationTag & tag);
   // iterator end_recv(const SynchronizationTag & tag);
 
   /* ------------------------------------------------------------------------ */
   class IterableTags {
   public:
     explicit IterableTags(Communications & communications)
         : communications(communications) {}
     decltype(auto) begin() { return communications.begin_tag(); }
     decltype(auto) end() { return communications.end_tag(); }
 
   private:
     Communications & communications;
   };
 
   decltype(auto) iterateTags() { return IterableTags(*this); }
 
   tag_iterator begin_tag();
   tag_iterator end_tag();
 
   /* ------------------------------------------------------------------------ */
   bool hasCommunication(const SynchronizationTag & tag) const;
   void incrementCounter(const SynchronizationTag & tag);
   UInt getCounter(const SynchronizationTag & tag) const;
   bool hasCommunicationSize(const SynchronizationTag & tag) const;
   void invalidateSizes();
 
   /* ------------------------------------------------------------------------ */
   bool hasPendingRecv(const SynchronizationTag & tag) const;
   bool hasPendingSend(const SynchronizationTag & tag) const;
 
   const auto & getCommunicator() const;
 
   /* ------------------------------------------------------------------------ */
   iterator waitAnyRecv(const SynchronizationTag & tag);
   iterator waitAnySend(const SynchronizationTag & tag);
 
   void waitAllRecv(const SynchronizationTag & tag);
   void waitAllSend(const SynchronizationTag & tag);
 
   void freeSendRequests(const SynchronizationTag & tag);
   void freeRecvRequests(const SynchronizationTag & tag);
 
   /* ------------------------------------------------------------------------ */
   /* ------------------------------------------------------------------------ */
   class IterableSchemes {
   public:
     IterableSchemes(Communications & communications,
                     CommunicationSendRecv sr)
         : communications(communications), sr(std::move(sr)) {}
     decltype(auto) begin() { return communications.begin_scheme(sr); }
     decltype(auto) end() { return communications.end_scheme(sr); }
 
   private:
     Communications & communications;
     CommunicationSendRecv sr;
   };
 
   class ConstIterableSchemes {
   public:
     ConstIterableSchemes(const Communications & communications,
                          CommunicationSendRecv sr)
         : communications(communications), sr(std::move(sr)) {}
     decltype(auto) begin() const { return communications.begin_scheme(sr); }
     decltype(auto) end() const { return communications.end_scheme(sr); }
 
   private:
     const Communications & communications;
     CommunicationSendRecv sr;
   };
 
   decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) {
     return IterableSchemes(*this, sr);
   }
   decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) const {
     return ConstIterableSchemes(*this, sr);
   }
 
   decltype(auto) iterateSendSchemes() { return IterableSchemes(*this, _send); }
   decltype(auto) iterateSendSchemes() const {
     return ConstIterableSchemes(*this, _send);
   }
 
   decltype(auto) iterateRecvSchemes() { return IterableSchemes(*this, _recv); }
   decltype(auto) iterateRecvSchemes() const {
     return ConstIterableSchemes(*this, _recv);
   }
 
   scheme_iterator begin_scheme(const CommunicationSendRecv & sr);
   scheme_iterator end_scheme(const CommunicationSendRecv & sr);
   const_scheme_iterator begin_scheme(const CommunicationSendRecv & sr) const;
   const_scheme_iterator end_scheme(const CommunicationSendRecv & sr) const;
 
   /* ------------------------------------------------------------------------ */
   scheme_iterator begin_send_scheme();
   scheme_iterator end_send_scheme();
   const_scheme_iterator begin_send_scheme() const;
   const_scheme_iterator end_send_scheme() const;
 
   /* ------------------------------------------------------------------------ */
   scheme_iterator begin_recv_scheme();
   scheme_iterator end_recv_scheme();
   const_scheme_iterator begin_recv_scheme() const;
   const_scheme_iterator end_recv_scheme() const;
 
   /* ------------------------------------------------------------------------ */
   Scheme & createSendScheme(UInt proc);
   Scheme & createRecvScheme(UInt proc);
 
   /* ------------------------------------------------------------------------ */
   Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr);
   const Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr) const;
 
   /* ------------------------------------------------------------------------ */
   void resetSchemes();
   /* ------------------------------------------------------------------------ */
   void setSendCommunicationSize(const SynchronizationTag & tag, UInt proc,
                                 UInt size);
   void setRecvCommunicationSize(const SynchronizationTag & tag, UInt proc,
                                 UInt size);
 
   void initializeCommunications(const SynchronizationTag & tag);
 
 protected:
   CommunicationSchemes schemes[2];
   CommunicationsPerTags communications[2];
 
   std::map<SynchronizationTag, UInt> comm_counter;
   std::map<SynchronizationTag, UInt> pending_communications[2];
   std::map<SynchronizationTag, bool> comm_size_computed;
 
   const Communicator & communicator;
 };
 
 } // namespace akantu
 
 #include "communications_tmpl.hh"
 
 #endif /* __AKANTU_COMMUNICATIONS_HH__ */
diff --git a/src/synchronizer/communications_tmpl.hh b/src/synchronizer/communications_tmpl.hh
index 5bef47632..f87ced61a 100644
--- a/src/synchronizer/communications_tmpl.hh
+++ b/src/synchronizer/communications_tmpl.hh
@@ -1,534 +1,550 @@
 /**
  * @file   communications_tmpl.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Tue Sep  6 17:14:06 2016
  *
  * @brief  Implementation of Communications
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "communications.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_COMMUNICATIONS_TMPL_HH__
 #define __AKANTU_COMMUNICATIONS_TMPL_HH__
 
 namespace akantu {
 
+/* -------------------------------------------------------------------------- */
+template <class Entity>
+Communications<Entity>::Communications(const Communicator & communicator)
+    : communicator(communicator) {}
+
+/* -------------------------------------------------------------------------- */
+template <class Entity>
+Communications<Entity>::Communications(const Communications & other)
+    : communicator(other.communicator) {
+  for(auto && sr : iterate_send_recv) {
+    for (const auto & scheme_pair : other.iterateSchemes(sr)) {
+      auto proc = scheme_pair.first;
+      auto & other_scheme = scheme_pair.second;
+      auto & scheme = this->createScheme(proc, sr);
+      scheme.copy(other_scheme);
+    }
+  }
+
+  this->invalidateSizes();
+}
+
 /* -------------------------------------------------------------------------- */
 template <class Entity> class Communications<Entity>::iterator {
   using communication_iterator =
       typename std::map<UInt, Communication>::iterator;
 
 public:
   iterator() : communications(nullptr) {}
   iterator(scheme_iterator scheme_it, communication_iterator comm_it,
            Communications<Entity> & communications,
            const SynchronizationTag & tag)
       : scheme_it(scheme_it), comm_it(comm_it), communications(&communications),
         tag(tag) {}
 
   iterator & operator=(const iterator & other) {
     if (this != &other) {
       this->scheme_it = other.scheme_it;
       this->comm_it = other.comm_it;
       this->communications = other.communications;
       this->tag = other.tag;
     }
     return *this;
   }
 
   iterator & operator++() {
     ++scheme_it;
     ++comm_it;
     return *this;
   }
 
   CommunicationDescriptor<Entity> operator*() {
     AKANTU_DEBUG_ASSERT(
         scheme_it->first == comm_it->first,
         "The two iterators are not in phase, something wrong"
             << " happened, time to take out your favorite debugger ("
             << scheme_it->first << " != " << comm_it->first << ")");
     return CommunicationDescriptor<Entity>(comm_it->second, scheme_it->second,
                                            *communications, tag,
                                            scheme_it->first);
   }
 
   bool operator==(const iterator & other) const {
     return scheme_it == other.scheme_it && comm_it == other.comm_it;
   }
 
   bool operator!=(const iterator & other) const {
     return scheme_it != other.scheme_it || comm_it != other.comm_it;
   }
 
 private:
   scheme_iterator scheme_it;
   communication_iterator comm_it;
   Communications<Entity> * communications;
   SynchronizationTag tag;
 };
 
 /* -------------------------------------------------------------------------- */
 template <class Entity> class Communications<Entity>::tag_iterator {
   using internal_iterator = std::map<SynchronizationTag, UInt>::const_iterator;
 
 public:
   tag_iterator(const internal_iterator & it) : it(it) {}
   tag_iterator & operator++() {
     ++it;
     return *this;
   }
   SynchronizationTag operator*() { return it->first; }
   bool operator==(const tag_iterator & other) const { return it == other.it; }
   bool operator!=(const tag_iterator & other) const { return it != other.it; }
 
 private:
   internal_iterator it;
 };
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::CommunicationPerProcs &
 Communications<Entity>::getCommunications(const SynchronizationTag & tag,
                                           const CommunicationSendRecv & sr) {
   auto comm_it = this->communications[sr].find(tag);
   if (comm_it == this->communications[sr].end())
     AKANTU_CUSTOM_EXCEPTION_INFO(
         debug::CommunicationException(),
         "No known communications for the tag: " << tag);
   return comm_it->second;
 }
 
 /* ---------------------------------------------------------------------- */
 template <class Entity>
 UInt Communications<Entity>::getPending(
     const SynchronizationTag & tag, const CommunicationSendRecv & sr) const {
   const std::map<SynchronizationTag, UInt> & pending =
       pending_communications[sr];
   auto it = pending.find(tag);
 
   if (it == pending.end())
     return 0;
   return it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 bool Communications<Entity>::hasPending(
     const SynchronizationTag & tag, const CommunicationSendRecv & sr) const {
   return this->hasCommunication(tag) && (this->getPending(tag, sr) != 0);
 }
 
 /* ---------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::iterator
 Communications<Entity>::begin(const SynchronizationTag & tag,
                               const CommunicationSendRecv & sr) {
   auto & comms = this->getCommunications(tag, sr);
   return iterator(this->schemes[sr].begin(), comms.begin(), *this, tag);
 }
 
 template <class Entity>
 typename Communications<Entity>::iterator
 Communications<Entity>::end(const SynchronizationTag & tag,
                             const CommunicationSendRecv & sr) {
   auto & comms = this->getCommunications(tag, sr);
   return iterator(this->schemes[sr].end(), comms.end(), *this, tag);
 }
 
 /* ---------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::iterator
 Communications<Entity>::waitAny(const SynchronizationTag & tag,
                                 const CommunicationSendRecv & sr) {
   auto & comms = this->getCommunications(tag, sr);
   auto it = comms.begin();
   auto end = comms.end();
 
   std::vector<CommunicationRequest> requests;
 
   for (; it != end; ++it) {
     auto & request = it->second.request();
     if (!request.isFreed())
       requests.push_back(request);
   }
 
   UInt req_id = communicator.waitAny(requests);
   if (req_id != UInt(-1)) {
     auto & request = requests[req_id];
     UInt proc = sr == _recv ? request.getSource() : request.getDestination();
 
     return iterator(this->schemes[sr].find(proc), comms.find(proc), *this, tag);
   } else {
     return this->end(tag, sr);
   }
 }
 
 /* ---------------------------------------------------------------------- */
 template <class Entity>
 void Communications<Entity>::waitAll(const SynchronizationTag & tag,
                                      const CommunicationSendRecv & sr) {
   auto & comms = this->getCommunications(tag, sr);
   auto it = comms.begin();
   auto end = comms.end();
 
   std::vector<CommunicationRequest> requests;
 
   for (; it != end; ++it) {
     requests.push_back(it->second.request());
   }
 
   communicator.waitAll(requests);
 }
 
 template <class Entity>
 void Communications<Entity>::incrementPending(
     const SynchronizationTag & tag, const CommunicationSendRecv & sr) {
   ++(pending_communications[sr][tag]);
 }
 
 template <class Entity>
 void Communications<Entity>::decrementPending(
     const SynchronizationTag & tag, const CommunicationSendRecv & sr) {
   --(pending_communications[sr][tag]);
 }
 
 template <class Entity>
 void Communications<Entity>::freeRequests(const SynchronizationTag & tag,
                                           const CommunicationSendRecv & sr) {
   iterator it = this->begin(tag, sr);
   iterator end = this->end(tag, sr);
 
   for (; it != end; ++it) {
     (*it).freeRequest();
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::Scheme &
 Communications<Entity>::createScheme(UInt proc,
                                      const CommunicationSendRecv & sr) {
   // scheme_iterator it = schemes[sr].find(proc);
   // if (it != schemes[sr].end()) {
   //   AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(),
   //                                "Communication scheme("
   //                                    << sr
   //                                    << ") already created for proc: " <<
   //                                    proc);
   // }
   return schemes[sr][proc];
 }
 
 template <class Entity>
 void Communications<Entity>::resetSchemes(const CommunicationSendRecv & sr) {
   auto it = this->schemes[sr].begin();
   auto end = this->schemes[sr].end();
   for (; it != end; ++it) {
     it->second.resize(0);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void Communications<Entity>::setCommunicationSize(
     const SynchronizationTag & tag, UInt proc, UInt size,
     const CommunicationSendRecv & sr) {
   // accessor that fails if it does not exists
   comm_size_computed[tag] = true; // TODO: need perhaps to be split based on sr
   auto & comms = this->communications[sr];
   auto & comms_per_tag = comms.at(tag);
 
   comms_per_tag.at(proc).resize(size);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void Communications<Entity>::initializeCommunications(
     const SynchronizationTag & tag) {
 
   for (auto t = send_recv_t::begin(); t != send_recv_t::end(); ++t) {
     pending_communications[*t].insert(std::make_pair(tag, 0));
 
     auto & comms = this->communications[*t];
     auto & comms_per_tag =
         comms.insert(std::make_pair(tag, CommunicationPerProcs()))
             .first->second;
 
     for (auto pair : this->schemes[*t]) {
       comms_per_tag.emplace(std::piecewise_construct,
                             std::forward_as_tuple(pair.first),
                             std::forward_as_tuple(*t));
     }
   }
 
   comm_counter.insert(std::make_pair(tag, 0));
 }
 
-/* -------------------------------------------------------------------------- */
-template <class Entity>
-Communications<Entity>::Communications(const Communicator & communicator)
-    : communicator(communicator) {}
-
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::tag_iterator
 Communications<Entity>::begin_tag() {
   return tag_iterator(comm_counter.begin());
 }
 
 template <class Entity>
 typename Communications<Entity>::tag_iterator
 Communications<Entity>::end_tag() {
   return tag_iterator(comm_counter.end());
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::scheme_iterator
 Communications<Entity>::begin_scheme(const CommunicationSendRecv & sr) {
   return this->schemes[sr].begin();
 }
 
 template <class Entity>
 typename Communications<Entity>::scheme_iterator
 Communications<Entity>::end_scheme(const CommunicationSendRecv & sr) {
   return this->schemes[sr].end();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::const_scheme_iterator
 Communications<Entity>::begin_scheme(const CommunicationSendRecv & sr) const {
   return this->schemes[sr].begin();
 }
 
 template <class Entity>
 typename Communications<Entity>::const_scheme_iterator
 Communications<Entity>::end_scheme(const CommunicationSendRecv & sr) const {
   return this->schemes[sr].end();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::scheme_iterator
 Communications<Entity>::begin_send_scheme() {
   return this->begin_scheme(_send);
 }
 
 template <class Entity>
 typename Communications<Entity>::scheme_iterator
 Communications<Entity>::end_send_scheme() {
   return this->end_scheme(_send);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::const_scheme_iterator
 Communications<Entity>::begin_send_scheme() const {
   return this->begin_scheme(_send);
 }
 
 template <class Entity>
 typename Communications<Entity>::const_scheme_iterator
 Communications<Entity>::end_send_scheme() const {
   return this->end_scheme(_send);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::scheme_iterator
 Communications<Entity>::begin_recv_scheme() {
   return this->begin_scheme(_recv);
 }
 
 template <class Entity>
 typename Communications<Entity>::scheme_iterator
 Communications<Entity>::end_recv_scheme() {
   return this->end_scheme(_recv);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::const_scheme_iterator
 Communications<Entity>::begin_recv_scheme() const {
   return this->begin_scheme(_recv);
 }
 
 template <class Entity>
 typename Communications<Entity>::const_scheme_iterator
 Communications<Entity>::end_recv_scheme() const {
   return this->end_scheme(_recv);
 }
 
 /* ------------------------------------------------------------------------ */
 template <class Entity>
 bool Communications<Entity>::hasCommunication(
     const SynchronizationTag & tag) const {
   return (communications[_send].find(tag) != communications[_send].end());
 }
 
 template <class Entity>
 void Communications<Entity>::incrementCounter(const SynchronizationTag & tag) {
   auto it = comm_counter.find(tag);
   if (it == comm_counter.end()) {
     AKANTU_CUSTOM_EXCEPTION_INFO(
         debug::CommunicationException(),
         "No counter initialized in communications for the tags: " << tag);
   }
 
   ++(it->second);
 }
 
 template <class Entity>
 UInt Communications<Entity>::getCounter(const SynchronizationTag & tag) const {
   auto it = comm_counter.find(tag);
   if (it == comm_counter.end()) {
     AKANTU_CUSTOM_EXCEPTION_INFO(
         debug::CommunicationException(),
         "No counter initialized in communications for the tags: " << tag);
   }
 
   return it->second;
 }
 
 template <class Entity>
 bool Communications<Entity>::hasCommunicationSize(
     const SynchronizationTag & tag) const {
   auto it = comm_size_computed.find(tag);
   if (it == comm_size_computed.end()) {
     return false;
   }
 
   return it->second;
 }
 
 template <class Entity> void Communications<Entity>::invalidateSizes() {
   for (auto && pair : comm_size_computed) {
     pair.second = true;
   }
 }
 
 template <class Entity>
 bool Communications<Entity>::hasPendingRecv(
     const SynchronizationTag & tag) const {
   return this->hasPending(tag, _recv);
 }
 
 template <class Entity>
 bool Communications<Entity>::hasPendingSend(
     const SynchronizationTag & tag) const {
   return this->hasPending(tag, _send);
 }
 
 template <class Entity>
 const auto & Communications<Entity>::getCommunicator() const {
   return communicator;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::iterator
 Communications<Entity>::waitAnyRecv(const SynchronizationTag & tag) {
   return this->waitAny(tag, _recv);
 }
 
 template <class Entity>
 typename Communications<Entity>::iterator
 Communications<Entity>::waitAnySend(const SynchronizationTag & tag) {
   return this->waitAny(tag, _send);
 }
 
 template <class Entity>
 void Communications<Entity>::waitAllRecv(const SynchronizationTag & tag) {
   this->waitAll(tag, _recv);
 }
 
 template <class Entity>
 void Communications<Entity>::waitAllSend(const SynchronizationTag & tag) {
   this->waitAll(tag, _send);
 }
 
 template <class Entity>
 void Communications<Entity>::freeSendRequests(const SynchronizationTag & tag) {
   this->freeRequests(tag, _send);
 }
 
 template <class Entity>
 void Communications<Entity>::freeRecvRequests(const SynchronizationTag & tag) {
   this->freeRequests(tag, _recv);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::Scheme &
 Communications<Entity>::createSendScheme(UInt proc) {
   return createScheme(proc, _send);
 }
 
 template <class Entity>
 typename Communications<Entity>::Scheme &
 Communications<Entity>::createRecvScheme(UInt proc) {
   return createScheme(proc, _recv);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity> void Communications<Entity>::resetSchemes() {
   resetSchemes(_send);
   resetSchemes(_recv);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 typename Communications<Entity>::Scheme &
 Communications<Entity>::getScheme(UInt proc, const CommunicationSendRecv & sr) {
   return this->schemes[sr].find(proc)->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 const typename Communications<Entity>::Scheme &
 Communications<Entity>::getScheme(UInt proc,
                                   const CommunicationSendRecv & sr) const {
   return this->schemes[sr].find(proc)->second;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void Communications<Entity>::setSendCommunicationSize(
     const SynchronizationTag & tag, UInt proc, UInt size) {
   this->setCommunicationSize(tag, proc, size, _send);
 }
 
 template <class Entity>
 void Communications<Entity>::setRecvCommunicationSize(
     const SynchronizationTag & tag, UInt proc, UInt size) {
   this->setCommunicationSize(tag, proc, size, _recv);
 }
 
 } // namespace akantu
 
 #endif /* __AKANTU_COMMUNICATIONS_TMPL_HH__ */
diff --git a/src/synchronizer/data_accessor.cc b/src/synchronizer/data_accessor.cc
index c4855e9ab..3a51a7016 100644
--- a/src/synchronizer/data_accessor.cc
+++ b/src/synchronizer/data_accessor.cc
@@ -1,163 +1,155 @@
 /**
  * @file   data_accessor.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  data accessors constructor functions
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "data_accessor.hh"
 #include "fe_engine.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <typename T, bool pack_helper>
 void DataAccessor<Element>::packUnpackNodalDataHelper(
     Array<T> & data, CommunicationBuffer & buffer,
     const Array<Element> & elements, const Mesh & mesh) {
   UInt nb_component = data.getNbComponent();
   UInt nb_nodes_per_element = 0;
 
   ElementType current_element_type = _not_defined;
   GhostType current_ghost_type = _casper;
   UInt * conn = nullptr;
 
-  Array<Element>::const_iterator<Element> it = elements.begin();
-  Array<Element>::const_iterator<Element> end = elements.end();
-  for (; it != end; ++it) {
-    const Element & el = *it;
+  for (auto & el : elements) {
     if (el.type != current_element_type ||
         el.ghost_type != current_ghost_type) {
       current_element_type = el.type;
       current_ghost_type = el.ghost_type;
       conn = mesh.getConnectivity(el.type, el.ghost_type).storage();
       nb_nodes_per_element = Mesh::getNbNodesPerElement(el.type);
     }
 
     UInt el_offset = el.element * nb_nodes_per_element;
     for (UInt n = 0; n < nb_nodes_per_element; ++n) {
       UInt offset_conn = conn[el_offset + n];
       Vector<T> data_vect(data.storage() + offset_conn * nb_component,
                           nb_component);
 
       if (pack_helper)
         buffer << data_vect;
       else
         buffer >> data_vect;
     }
   }
 }
 
 /* ------------------------------------------------------------------------ */
 template <typename T, bool pack_helper>
 void DataAccessor<Element>::packUnpackElementalDataHelper(
     ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer,
     const Array<Element> & element, bool per_quadrature_point_data,
     const FEEngine & fem) {
   ElementType current_element_type = _not_defined;
   GhostType current_ghost_type = _casper;
   UInt nb_quad_per_elem = 0;
   UInt nb_component = 0;
 
   Array<T> * vect = nullptr;
 
-  Array<Element>::const_iterator<Element> it = element.begin();
-  Array<Element>::const_iterator<Element> end = element.end();
-  for (; it != end; ++it) {
-    const Element & el = *it;
+  for (auto & el : element) {
     if (el.type != current_element_type ||
         el.ghost_type != current_ghost_type) {
       current_element_type = el.type;
       current_ghost_type = el.ghost_type;
       vect = &data_to_pack(el.type, el.ghost_type);
-      if (per_quadrature_point_data)
-        nb_quad_per_elem = fem.getNbIntegrationPoints(el.type, el.ghost_type);
-      else
-        nb_quad_per_elem = 1;
+
+      nb_quad_per_elem =
+          per_quadrature_point_data
+              ? fem.getNbIntegrationPoints(el.type, el.ghost_type)
+              : 1;
       nb_component = vect->getNbComponent();
     }
 
     Vector<T> data(vect->storage() +
                        el.element * nb_component * nb_quad_per_elem,
                    nb_component * nb_quad_per_elem);
     if (pack_helper)
       buffer << data;
     else
       buffer >> data;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T, bool pack_helper>
 void DataAccessor<UInt>::packUnpackDOFDataHelper(Array<T> & data,
                                                  CommunicationBuffer & buffer,
                                                  const Array<UInt> & dofs) {
-  Array<UInt>::const_scalar_iterator it_dof = dofs.begin();
-  Array<UInt>::const_scalar_iterator end_dof = dofs.end();
   T * data_ptr = data.storage();
-
-  for (; it_dof != end_dof; ++it_dof) {
+  for (const auto & dof : dofs) {
     if (pack_helper)
-      buffer << data_ptr[*it_dof];
+      buffer << data_ptr[dof];
     else
-      buffer >> data_ptr[*it_dof];
+      buffer >> data_ptr[dof];
   }
 }
 
 /* -------------------------------------------------------------------------- */
 #define DECLARE_HELPERS(T)                                                     \
   template void DataAccessor<Element>::packUnpackNodalDataHelper<T, false>(    \
       Array<T> & data, CommunicationBuffer & buffer,                           \
       const Array<Element> & elements, const Mesh & mesh);                     \
   template void DataAccessor<Element>::packUnpackNodalDataHelper<T, true>(     \
       Array<T> & data, CommunicationBuffer & buffer,                           \
       const Array<Element> & elements, const Mesh & mesh);                     \
   template void                                                                \
   DataAccessor<Element>::packUnpackElementalDataHelper<T, false>(              \
       ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer,     \
       const Array<Element> & element, bool per_quadrature_point_data,          \
       const FEEngine & fem);                                                   \
   template void DataAccessor<Element>::packUnpackElementalDataHelper<T, true>( \
       ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer,     \
       const Array<Element> & element, bool per_quadrature_point_data,          \
       const FEEngine & fem);                                                   \
   template void DataAccessor<UInt>::packUnpackDOFDataHelper<T, true>(          \
       Array<T> & data, CommunicationBuffer & buffer,                           \
       const Array<UInt> & dofs);                                               \
   template void DataAccessor<UInt>::packUnpackDOFDataHelper<T, false>(         \
       Array<T> & data, CommunicationBuffer & buffer, const Array<UInt> & dofs)
 
 /* -------------------------------------------------------------------------- */
 DECLARE_HELPERS(Real);
 DECLARE_HELPERS(UInt);
 DECLARE_HELPERS(bool);
 /* -------------------------------------------------------------------------- */
 
 } // akantu
diff --git a/src/synchronizer/element_synchronizer.cc b/src/synchronizer/element_synchronizer.cc
index 9ffc5f5f8..32698e302 100644
--- a/src/synchronizer/element_synchronizer.cc
+++ b/src/synchronizer/element_synchronizer.cc
@@ -1,353 +1,369 @@
 /**
  * @file   element_synchronizer.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Dana Christen <dana.christen@epfl.ch>
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Wed Sep 01 2010
  * @date last modification: Fri Jan 22 2016
  *
  * @brief  implementation of a  communicator using a static_communicator for
  * real
  * send/receive
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "element_synchronizer.hh"
 #include "aka_common.hh"
 #include "mesh.hh"
 #include "mesh_utils.hh"
 /* -------------------------------------------------------------------------- */
 #include <algorithm>
 #include <iostream>
 #include <map>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 ElementSynchronizer::ElementSynchronizer(Mesh & mesh, const ID & id,
                                          MemoryID memory_id,
                                          bool register_to_event_manager,
                                          EventHandlerPriority event_priority)
     : SynchronizerImpl<Element>(mesh.getCommunicator(), id, memory_id),
       mesh(mesh), element_to_prank("element_to_prank", id, memory_id) {
+  AKANTU_DEBUG_IN();
+
+  if (register_to_event_manager)
+    this->mesh.registerEventHandler(*this, event_priority);
 
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+ElementSynchronizer::ElementSynchronizer(const ElementSynchronizer & other,
+                                         const ID & id,
+                                         bool register_to_event_manager,
+                                         EventHandlerPriority event_priority)
+    : SynchronizerImpl<Element>(other, id), mesh(other.mesh),
+      element_to_prank("element_to_prank", id, other.memory_id) {
   AKANTU_DEBUG_IN();
 
+  element_to_prank.copy(other.element_to_prank);
+
   if (register_to_event_manager)
     this->mesh.registerEventHandler(*this, event_priority);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 ElementSynchronizer::~ElementSynchronizer() = default;
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::substituteElements(
     const std::map<Element, Element> & old_to_new_elements) {
   auto found_element_end = old_to_new_elements.end();
 
   // substitute old elements with new ones
   for (auto && sr : iterate_send_recv) {
     for (auto && scheme_pair : communications.iterateSchemes(sr)) {
       auto & list = scheme_pair.second;
       for (auto & el : list) {
         auto found_element_it = old_to_new_elements.find(el);
         if (found_element_it != found_element_end)
           el = found_element_it->second;
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::onElementsChanged(
     const Array<Element> & old_elements_list,
     const Array<Element> & new_elements_list, const ElementTypeMapArray<UInt> &,
     const ChangedElementsEvent &) {
   // create a map to link old elements to new ones
   std::map<Element, Element> old_to_new_elements;
 
   for (UInt el = 0; el < old_elements_list.size(); ++el) {
     AKANTU_DEBUG_ASSERT(old_to_new_elements.find(old_elements_list(el)) ==
                             old_to_new_elements.end(),
                         "The same element cannot appear twice in the list");
 
     old_to_new_elements[old_elements_list(el)] = new_elements_list(el);
   }
 
   substituteElements(old_to_new_elements);
 
   communications.invalidateSizes();
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::onElementsRemoved(
     const Array<Element> & element_to_remove,
     const ElementTypeMapArray<UInt> & new_numbering,
     const RemovedElementsEvent &) {
   AKANTU_DEBUG_IN();
 
   this->removeElements(element_to_remove);
   this->renumberElements(new_numbering);
 
   communications.invalidateSizes();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::buildElementToPrank() {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   element_to_prank.initialize(mesh, _spatial_dimension = spatial_dimension,
                               _element_kind = _ek_not_defined,
                               _with_nb_element = true, _default_value = rank);
 
   /// assign prank to all ghost elements
   for (auto && scheme : communications.iterateSchemes(_recv)) {
     auto & recv = scheme.second;
     auto proc = scheme.first;
 
     for (auto & element : recv) {
       element_to_prank(element) = proc;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Int ElementSynchronizer::getRank(const Element & element) const {
   if (not element_to_prank.exists(element.type, element.ghost_type)) {
     // Nicolas: Ok This is nasty I know....
     const_cast<ElementSynchronizer *>(this)->buildElementToPrank();
   }
 
   return element_to_prank(element);
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::reset() {
   AKANTU_DEBUG_IN();
 
   communications.resetSchemes();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::removeElements(
     const Array<Element> & element_to_remove) {
   AKANTU_DEBUG_IN();
 
   std::vector<CommunicationRequest> send_requests;
   std::map<UInt, Array<UInt>> list_of_elements_per_proc;
 
   auto filter_list = [](const Array<UInt> & keep, Array<Element> & list) {
     Array<Element> new_list;
     for (UInt e = 0; e < keep.size() - 1; ++e) {
       Element & el = list(keep(e));
       new_list.push_back(el);
     }
     list.copy(new_list);
   };
 
   // Handling ghost elements
   for (auto && scheme_pair : communications.iterateSchemes(_recv)) {
     auto proc = scheme_pair.first;
     auto & recv = scheme_pair.second;
     Array<UInt> & keep_list = list_of_elements_per_proc[proc];
 
     auto rem_it = element_to_remove.begin();
     auto rem_end = element_to_remove.end();
 
     for (auto && pair : enumerate(recv)) {
       const auto & el = std::get<1>(pair);
       auto pos = std::find(rem_it, rem_end, el);
 
       if (pos == rem_end) {
         keep_list.push_back(std::get<0>(pair));
       }
     }
 
     keep_list.push_back(UInt(-1)); // To no send empty arrays
 
     auto && tag = Tag::genTag(proc, 0, Tag::_MODIFY_SCHEME, this->hash_id);
     AKANTU_DEBUG_INFO("Sending a message of size "
                       << keep_list.size() << " to proc " << proc << " TAG("
                       << tag << ")");
     send_requests.push_back(this->communicator.asyncSend(keep_list, proc, tag));
 
 #ifndef AKANTU_NDEBUG
     auto old_size = recv.size();
 #endif
     filter_list(keep_list, recv);
 
     AKANTU_DEBUG_INFO("I had " << old_size << " elements to recv from proc "
                                << proc << " and " << keep_list.size()
                                << " elements to keep. I have " << recv.size()
                                << " elements left.");
   }
 
   for (auto && scheme_pair : communications.iterateSchemes(_send)) {
     auto proc = scheme_pair.first;
     auto & send = scheme_pair.second;
 
     CommunicationStatus status;
     auto && tag = Tag::genTag(rank, 0, Tag::_MODIFY_SCHEME, this->hash_id);
     AKANTU_DEBUG_INFO("Getting number of elements of proc "
                       << proc << " to keep - TAG(" << tag << ")");
     this->communicator.probe<UInt>(proc, tag, status);
     Array<UInt> keep_list(status.size());
 
     AKANTU_DEBUG_INFO("Receiving list of elements ("
                       << keep_list.size() << " elements) to keep for proc "
                       << proc << " TAG(" << tag << ")");
     this->communicator.receive(keep_list, proc, tag);
 
 #ifndef AKANTU_NDEBUG
     auto old_size = send.size();
 #endif
     filter_list(keep_list, send);
 
     AKANTU_DEBUG_INFO("I had " << old_size << " elements to send to proc "
                                << proc << " and " << keep_list.size()
                                << " elements to keep. I have " << send.size()
                                << " elements left.");
   }
 
   this->communicator.waitAll(send_requests);
   this->communicator.freeCommunicationRequest(send_requests);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::renumberElements(
     const ElementTypeMapArray<UInt> & new_numbering) {
   for (auto && sr : iterate_send_recv) {
     for (auto && scheme_pair : communications.iterateSchemes(sr)) {
       auto & list = scheme_pair.second;
       for (auto && el : list) {
         if (new_numbering.exists(el.type, el.ghost_type))
           el.element = new_numbering(el);
       }
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 UInt ElementSynchronizer::sanityCheckDataSize(
     const Array<Element> & elements, const SynchronizationTag &) const {
   UInt size = 0;
   size += sizeof(SynchronizationTag); // tag
   size += sizeof(UInt);               // comm_desc.getNbData();
   size += sizeof(UInt);               // comm_desc.getProc();
   size += sizeof(UInt);               // mesh.getCommunicator().whoAmI();
 
   // barycenters
   size += (elements.size() * mesh.getSpatialDimension() * sizeof(Real));
   return size;
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::packSanityCheckData(
     CommunicationDescriptor<Element> & comm_desc) const {
   auto & buffer = comm_desc.getBuffer();
   buffer << comm_desc.getTag();
   buffer << comm_desc.getNbData();
   buffer << comm_desc.getProc();
   buffer << mesh.getCommunicator().whoAmI();
 
   auto & send_element = comm_desc.getScheme();
 
   /// pack barycenters in debug mode
   for (auto && element : send_element) {
     Vector<Real> barycenter(mesh.getSpatialDimension());
     mesh.getBarycenter(element, barycenter);
     buffer << barycenter;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void ElementSynchronizer::unpackSanityCheckData(
     CommunicationDescriptor<Element> & comm_desc) const {
   auto & buffer = comm_desc.getBuffer();
   const auto & tag = comm_desc.getTag();
 
   auto nb_data = comm_desc.getNbData();
   auto proc = comm_desc.getProc();
   auto rank = mesh.getCommunicator().whoAmI();
 
   decltype(nb_data) recv_nb_data;
   decltype(proc) recv_proc;
   decltype(rank) recv_rank;
 
   SynchronizationTag t;
   buffer >> t;
   buffer >> recv_nb_data;
   buffer >> recv_proc;
   buffer >> recv_rank;
 
   AKANTU_DEBUG_ASSERT(
       t == tag, "The tag received does not correspond to the tag expected");
 
   AKANTU_DEBUG_ASSERT(
       nb_data == recv_nb_data,
       "The nb_data received does not correspond to the nb_data expected");
 
   AKANTU_DEBUG_ASSERT(UInt(recv_rank) == proc,
                       "The rank received does not correspond to the proc");
 
   AKANTU_DEBUG_ASSERT(recv_proc == UInt(rank),
                       "The proc received does not correspond to the rank");
 
   auto & recv_element = comm_desc.getScheme();
   auto spatial_dimension = mesh.getSpatialDimension();
 
   for (auto && element : recv_element) {
     Vector<Real> barycenter_loc(spatial_dimension);
     mesh.getBarycenter(element, barycenter_loc);
 
     Vector<Real> barycenter(spatial_dimension);
     buffer >> barycenter;
 
     auto dist = barycenter_loc.distance(barycenter);
     if (not Math::are_float_equal(dist, 0.))
       AKANTU_EXCEPTION("Unpacking an unknown value for the element "
                        << element << "(barycenter " << barycenter_loc
                        << " != buffer " << barycenter << ") [" << dist
                        << "] - tag: " << tag << " comm from " << proc << " to "
                        << rank);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 } // namespace akantu
diff --git a/src/synchronizer/element_synchronizer.hh b/src/synchronizer/element_synchronizer.hh
index 53fbc6e76..8764beb79 100644
--- a/src/synchronizer/element_synchronizer.hh
+++ b/src/synchronizer/element_synchronizer.hh
@@ -1,211 +1,216 @@
 /**
  * @file   element_synchronizer.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Dana Christen <dana.christen@epfl.ch>
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Tue Dec 08 2015
  *
  * @brief  Main element synchronizer
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_ELEMENT_SYNCHRONIZER_HH__
 #define __AKANTU_ELEMENT_SYNCHRONIZER_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_array.hh"
 #include "aka_common.hh"
 #include "mesh_partition.hh"
 #include "synchronizer_impl.hh"
 
 namespace akantu {
 class Mesh;
 }
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 
 class ElementSynchronizer : public SynchronizerImpl<Element>,
                             public MeshEventHandler {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   ElementSynchronizer(Mesh & mesh, const ID & id = "element_synchronizer",
                       MemoryID memory_id = 0,
                       bool register_to_event_manager = true,
                       EventHandlerPriority event_priority = _ehp_synchronizer);
 
+  ElementSynchronizer(const ElementSynchronizer & other,
+                      const ID & id = "element_synchronizer_copy",
+                      bool register_to_event_manager = true,
+                      EventHandlerPriority event_priority = _ehp_synchronizer);
+
 public:
   ~ElementSynchronizer() override;
 
   friend class ElementInfoPerProc;
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /* ------------------------------------------------------------------------ */
   /// mesh event handler onElementsChanged
   void onElementsChanged(const Array<Element> & old_elements_list,
                          const Array<Element> & new_elements_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const ChangedElementsEvent & event) override;
 
   /// mesh event handler onRemovedElement
   void onElementsRemoved(const Array<Element> & element_list,
                          const ElementTypeMapArray<UInt> & new_numbering,
                          const RemovedElementsEvent & event) override;
   /// mesh event handler onNodesAdded
   void onNodesAdded(const Array<UInt> & /* nodes_list*/,
                     const NewNodesEvent & /*event*/) override{};
 
   /// mesh event handler onRemovedNodes
   void onNodesRemoved(const Array<UInt> & /*nodes_list*/,
                       const Array<UInt> & /*new_numbering*/,
                       const RemovedNodesEvent & /*event*/) override{};
 
   /// mesh event handler onElementsAdded
   void onElementsAdded(const Array<Element> & /*elements_list*/,
                        const NewElementsEvent & /*event*/) override{};
 
 protected:
   /// reset send and recv element lists
   void reset();
 
   /// remove elements from the synchronizer without renumbering them
   void removeElements(const Array<Element> & element_to_remove);
 
   /// renumber the elements in the synchronizer
   void renumberElements(const ElementTypeMapArray<UInt> & new_numbering);
 
   /// build processor to element correspondence
   void buildElementToPrank();
 
 protected:
   /// fill the nodes type vector
   void fillNodesType(const MeshData & mesh_data,
                      DynamicCommunicationBuffer * buffers,
                      const std::string & tag_name, const ElementType & el_type,
                      const Array<UInt> & partition_num);
 
   template <typename T>
   void fillTagBufferTemplated(const MeshData & mesh_data,
                               DynamicCommunicationBuffer * buffers,
                               const std::string & tag_name,
                               const ElementType & el_type,
                               const Array<UInt> & partition_num,
                               const CSR<UInt> & ghost_partition);
 
   void fillTagBuffer(const MeshData & mesh_data,
                      DynamicCommunicationBuffer * buffers,
                      const std::string & tag_name, const ElementType & el_type,
                      const Array<UInt> & partition_num,
                      const CSR<UInt> & ghost_partition);
 
   /// function that handels the MeshData to be split (root side)
   static void synchronizeTagsSend(ElementSynchronizer & communicator, UInt root,
                                   Mesh & mesh, UInt nb_tags,
                                   const ElementType & type,
                                   const Array<UInt> & partition_num,
                                   const CSR<UInt> & ghost_partition,
                                   UInt nb_local_element, UInt nb_ghost_element);
 
   /// function that handles the MeshData to be split (other nodes)
   static void synchronizeTagsRecv(ElementSynchronizer & communicator, UInt root,
                                   Mesh & mesh, UInt nb_tags,
                                   const ElementType & type,
                                   UInt nb_local_element, UInt nb_ghost_element);
 
   /// function that handles the preexisting groups in the mesh
   static void synchronizeElementGroups(ElementSynchronizer & communicator,
                                        UInt root, Mesh & mesh,
                                        const ElementType & type,
                                        const Array<UInt> & partition_num,
                                        const CSR<UInt> & ghost_partition,
                                        UInt nb_element);
 
   /// function that handles the preexisting groups in the mesh
   static void synchronizeElementGroups(ElementSynchronizer & communicator,
                                        UInt root, Mesh & mesh,
                                        const ElementType & type);
 
   /// function that handles the preexisting groups in the mesh
   static void synchronizeNodeGroupsMaster(ElementSynchronizer & communicator,
                                           UInt root, Mesh & mesh);
 
   /// function that handles the preexisting groups in the mesh
   static void synchronizeNodeGroupsSlaves(ElementSynchronizer & communicator,
                                           UInt root, Mesh & mesh);
 
   template <class CommunicationBuffer>
   static void fillNodeGroupsFromBuffer(ElementSynchronizer & communicator,
                                        Mesh & mesh,
                                        CommunicationBuffer & buffer);
 
   /// substitute elements in the send and recv arrays
   void
   substituteElements(const std::map<Element, Element> & old_to_new_elements);
 
   /* ------------------------------------------------------------------------ */
   /* Sanity checks                                                            */
   /* ------------------------------------------------------------------------ */
   UInt sanityCheckDataSize(const Array<Element> & elements,
                            const SynchronizationTag & tag) const override;
   /* ------------------------------------------------------------------------ */
   void packSanityCheckData(
       CommunicationDescriptor<Element> & comm_desc) const override;
   /* ------------------------------------------------------------------------ */
   void unpackSanityCheckData(
       CommunicationDescriptor<Element> & comm_desc) const override;
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   AKANTU_GET_MACRO(Mesh, mesh, Mesh &);
   AKANTU_GET_MACRO(ElementToRank, element_to_prank,
                    const ElementTypeMapArray<Int> &);
 
   Int getRank(const Element & element) const final;
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// reference to the underlying mesh
   Mesh & mesh;
 
   friend class FacetSynchronizer;
 
   ElementTypeMapArray<Int> element_to_prank;
 };
 
 /* -------------------------------------------------------------------------- */
 } // namespace akantu
 
 #endif /* __AKANTU_ELEMENT_SYNCHRONIZER_HH__ */
diff --git a/src/synchronizer/synchronizer.hh b/src/synchronizer/synchronizer.hh
index 0f809526e..8f3501158 100644
--- a/src/synchronizer/synchronizer.hh
+++ b/src/synchronizer/synchronizer.hh
@@ -1,123 +1,125 @@
 /**
  * @file   synchronizer.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Thu Dec 10 2015
  *
  * @brief  Common interface for synchronizers
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "aka_memory.hh"
 /* -------------------------------------------------------------------------- */
 #include <map>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SYNCHRONIZER_HH__
 #define __AKANTU_SYNCHRONIZER_HH__
 
 namespace akantu {
 class Communicator;
 }
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /* Base class for synchronizers                                               */
 /* -------------------------------------------------------------------------- */
 class Synchronizer : protected Memory {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   Synchronizer(const Communicator & comm, const ID & id = "synchronizer",
                MemoryID memory_id = 0);
 
+  Synchronizer(const Synchronizer & other) = default;
+
   ~Synchronizer() override = default;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// synchronize ghosts without state
   template <class DataAccessor>
   void synchronizeOnce(DataAccessor & data_accessor,
                        const SynchronizationTag & tag) const;
 
   /// synchronize ghosts
   template <class DataAccessor>
   void synchronize(DataAccessor & data_accessor,
                    const SynchronizationTag & tag);
 
   /// asynchronous synchronization of ghosts
   template <class DataAccessor>
   void asynchronousSynchronize(const DataAccessor & data_accessor,
                                const SynchronizationTag & tag);
 
   /// wait end of asynchronous synchronization of ghosts
   template <class DataAccessor>
   void waitEndSynchronize(DataAccessor & data_accessor,
                           const SynchronizationTag & tag);
 
   /// compute buffer size for a given tag and data accessor
   template <class DataAccessor>
   void computeBufferSize(const DataAccessor & data_accessor,
                          const SynchronizationTag & tag);
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   AKANTU_GET_MACRO(Communicator, communicator, const Communicator &);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// id of the synchronizer
   ID id;
 
   /// hashed version of the id
   int hash_id;
 
   /// message counter per tag
   std::map<SynchronizationTag, UInt> tag_counter;
 
   /// the static memory instance
   const Communicator & communicator;
 
   /// nb processors in the communicator
   UInt nb_proc;
 
   /// rank in the communicator
   UInt rank;
 };
 
 } // namespace akantu
 
 #include "synchronizer_tmpl.hh"
 
 #endif /* __AKANTU_SYNCHRONIZER_HH__ */
diff --git a/src/synchronizer/synchronizer_impl.hh b/src/synchronizer/synchronizer_impl.hh
index b4b87c96d..fcfedb3e8 100644
--- a/src/synchronizer/synchronizer_impl.hh
+++ b/src/synchronizer/synchronizer_impl.hh
@@ -1,121 +1,123 @@
 /**
  * @file   synchronizer_impl.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Aug 24 13:26:47 2016
  *
  * @brief  Implementation of the generic part of synchronizers
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "communications.hh"
 #include "synchronizer.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SYNCHRONIZER_IMPL_HH__
 #define __AKANTU_SYNCHRONIZER_IMPL_HH__
 
 namespace akantu {
 
 template <class Entity> class SynchronizerImpl : public Synchronizer {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   SynchronizerImpl(const Communicator & communicator,
                    const ID & id = "synchronizer", MemoryID memory_id = 0);
 
+  SynchronizerImpl(const SynchronizerImpl & other, const ID & id);
+
   ~SynchronizerImpl() override = default;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// synchronous synchronization without state
   virtual void synchronizeOnceImpl(DataAccessor<Entity> & data_accessor,
                                    const SynchronizationTag & tag) const;
 
   /// asynchronous synchronization of ghosts
   virtual void
   asynchronousSynchronizeImpl(const DataAccessor<Entity> & data_accessor,
                               const SynchronizationTag & tag);
 
   /// wait end of asynchronous synchronization of ghosts
   virtual void waitEndSynchronizeImpl(DataAccessor<Entity> & data_accessor,
                                       const SynchronizationTag & tag);
 
   /// compute all buffer sizes
   virtual void
   computeAllBufferSizes(const DataAccessor<Entity> & data_accessor);
 
   /// compute buffer size for a given tag and data accessor
   virtual void computeBufferSizeImpl(const DataAccessor<Entity> & data_accessor,
                                      const SynchronizationTag & tag);
 
   /* ------------------------------------------------------------------------ */
   virtual void synchronizeImpl(DataAccessor<Entity> & data_accessor,
                                const SynchronizationTag & tag) {
     this->asynchronousSynchronizeImpl(data_accessor, tag);
     this->waitEndSynchronizeImpl(data_accessor, tag);
   }
 
   /* ------------------------------------------------------------------------ */
   /// extract the elements that have a true predicate from in_synchronizer and
   /// store them in the current synchronizer
   template <typename Pred>
   void split(SynchronizerImpl & in_synchronizer, Pred && pred);
 
   /// update schemes in a synchronizer
   template <typename Updater> void updateSchemes(Updater && scheme_updater);
 
   /* ------------------------------------------------------------------------ */
   virtual UInt sanityCheckDataSize(const Array<Entity> & elements,
                                    const SynchronizationTag & tag) const;
   virtual void
   packSanityCheckData(CommunicationDescriptor<Entity> & comm_desc) const;
   virtual void
   unpackSanityCheckData(CommunicationDescriptor<Entity> & comm_desc) const;
 
 public:
   AKANTU_GET_MACRO(Communications, communications,
                    const Communications<Entity> &);
 
 protected:
   AKANTU_GET_MACRO_NOT_CONST(Communications, communications,
                              Communications<Entity> &);
 
   virtual Int getRank(const Entity & entity) const = 0;
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// information on the communications
   Communications<Entity> communications;
 };
 
 } // namespace akantu
 
 #include "synchronizer_impl_tmpl.hh"
 
 #endif /* __AKANTU_SYNCHRONIZER_IMPL_HH__ */
diff --git a/src/synchronizer/synchronizer_impl_tmpl.hh b/src/synchronizer/synchronizer_impl_tmpl.hh
index 8cd7a2cdf..b8129ce99 100644
--- a/src/synchronizer/synchronizer_impl_tmpl.hh
+++ b/src/synchronizer/synchronizer_impl_tmpl.hh
@@ -1,305 +1,314 @@
 /**
  * @file   synchronizer_impl_tmpl.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Aug 24 13:29:47 2016
  *
  * @brief  Implementation of the SynchronizerImpl
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "synchronizer_impl.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__
 #define __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
-SynchronizerImpl<Entity>::SynchronizerImpl(const Communicator & comm, const ID & id, MemoryID memory_id)
+SynchronizerImpl<Entity>::SynchronizerImpl(const Communicator & comm,
+                                           const ID & id, MemoryID memory_id)
 
     : Synchronizer(comm, id, memory_id), communications(comm) {}
 
+/* -------------------------------------------------------------------------- */
+template <class Entity>
+SynchronizerImpl<Entity>::SynchronizerImpl(const SynchronizerImpl & other,
+                                            const ID & id)
+    : Synchronizer(other), communications(other.communications) {
+  this->id = id;
+}
+
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void SynchronizerImpl<Entity>::synchronizeOnceImpl(
     DataAccessor<Entity> & data_accessor,
     const SynchronizationTag & tag) const {
   // no need to synchronize
   if (this->nb_proc == 1)
     return;
 
   using CommunicationRequests = std::vector<CommunicationRequest>;
   using CommunicationBuffers = std::map<UInt, CommunicationBuffer>;
 
   CommunicationRequests send_requests, recv_requests;
   CommunicationBuffers send_buffers, recv_buffers;
 
   auto postComm = [&](const CommunicationSendRecv & sr,
                       CommunicationBuffers & buffers,
                       CommunicationRequests & requests) -> void {
     for (auto && pair : communications.iterateSchemes(sr)) {
       auto & proc = pair.first;
       const auto & scheme = pair.second;
 
       auto & buffer = buffers[proc];
       UInt buffer_size = data_accessor.getNbData(scheme, tag);
       buffer.resize(buffer_size);
 
       if (sr == _recv) {
         requests.push_back(communicator.asyncReceive(
             buffer, proc,
             Tag::genTag(this->rank, 0, Tag::_SYNCHRONIZE, this->hash_id)));
       } else {
         data_accessor.packData(buffer, scheme, tag);
         send_requests.push_back(communicator.asyncSend(
             buffer, proc,
             Tag::genTag(proc, 0, Tag::_SYNCHRONIZE, this->hash_id)));
       }
     }
   };
 
   // post the receive requests
   postComm(_recv, recv_buffers, recv_requests);
 
   // post the send data requests
   postComm(_send, send_buffers, send_requests);
 
   // treat the receive requests
   UInt request_ready;
   while ((request_ready = communicator.waitAny(recv_requests)) != UInt(-1)) {
     CommunicationRequest & req = recv_requests[request_ready];
     UInt proc = req.getSource();
 
     CommunicationBuffer & buffer = recv_buffers[proc];
     const auto & scheme = this->communications.getScheme(proc, _recv);
 
     data_accessor.unpackData(buffer, scheme, tag);
 
     req.free();
     recv_requests.erase(recv_requests.begin() + request_ready);
   }
 
   communicator.waitAll(send_requests);
   communicator.freeCommunicationRequest(send_requests);
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void SynchronizerImpl<Entity>::asynchronousSynchronizeImpl(
     const DataAccessor<Entity> & data_accessor,
     const SynchronizationTag & tag) {
   AKANTU_DEBUG_IN();
 
   if (not this->communications.hasCommunicationSize(tag))
     this->computeBufferSize(data_accessor, tag);
 
   this->communications.incrementCounter(tag);
 
   // Posting the receive -------------------------------------------------------
   if (this->communications.hasPendingRecv(tag)) {
     AKANTU_CUSTOM_EXCEPTION_INFO(
         debug::CommunicationException(),
         "There must still be some pending receive communications."
             << " Tag is " << tag << " Cannot start new ones");
   }
 
   for (auto && comm_desc : this->communications.iterateRecv(tag)) {
     comm_desc.postRecv(this->hash_id);
   }
 
   // Posting the sends -------------------------------------------------------
   if (communications.hasPendingSend(tag)) {
     AKANTU_CUSTOM_EXCEPTION_INFO(
         debug::CommunicationException(),
         "There must be some pending sending communications."
             << " Tag is " << tag);
   }
 
   for (auto && comm_desc : this->communications.iterateSend(tag)) {
     comm_desc.resetBuffer();
 
 #ifndef AKANTU_NDEBUG
     this->packSanityCheckData(comm_desc);
 #endif
 
     comm_desc.packData(data_accessor);
     comm_desc.postSend(this->hash_id);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void SynchronizerImpl<Entity>::waitEndSynchronizeImpl(
     DataAccessor<Entity> & data_accessor, const SynchronizationTag & tag) {
   AKANTU_DEBUG_IN();
 
 #ifndef AKANTU_NDEBUG
   if (this->communications.begin(tag, _recv) !=
-      this->communications.end(tag, _recv) &&
+          this->communications.end(tag, _recv) &&
       !this->communications.hasPendingRecv(tag))
     AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(),
                                  "No pending communication with the tag \""
                                      << tag);
 #endif
 
   auto recv_end = this->communications.end(tag, _recv);
   decltype(recv_end) recv_it;
 
   while ((recv_it = this->communications.waitAnyRecv(tag)) != recv_end) {
     auto && comm_desc = *recv_it;
 #ifndef AKANTU_NDEBUG
     this->unpackSanityCheckData(comm_desc);
 #endif
 
     comm_desc.unpackData(data_accessor);
     comm_desc.resetBuffer();
     comm_desc.freeRequest();
   }
 
   this->communications.waitAllSend(tag);
   this->communications.freeSendRequests(tag);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void SynchronizerImpl<Entity>::computeAllBufferSizes(
     const DataAccessor<Entity> & data_accessor) {
   for (auto && tag : this->communications.iterateTags()) {
     this->computeBufferSize(data_accessor, tag);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void SynchronizerImpl<Entity>::computeBufferSizeImpl(
     const DataAccessor<Entity> & data_accessor,
     const SynchronizationTag & tag) {
   AKANTU_DEBUG_IN();
 
   if (not this->communications.hasCommunication(tag)) {
     this->communications.initializeCommunications(tag);
     AKANTU_DEBUG_ASSERT(communications.hasCommunication(tag) == true,
                         "Communications where not properly initialized");
   }
 
   for (auto sr : iterate_send_recv) {
     for (auto && pair : this->communications.iterateSchemes(sr)) {
       auto proc = pair.first;
       const auto & scheme = pair.second;
       UInt size = 0;
 #ifndef AKANTU_NDEBUG
       size += this->sanityCheckDataSize(scheme, tag);
 #endif
       size += data_accessor.getNbData(scheme, tag);
       AKANTU_DEBUG_INFO("I have "
                         << size << "(" << printMemorySize<char>(size) << " - "
                         << scheme.size() << " element(s)) data to "
                         << std::string(sr == _recv ? "receive from" : "send to")
                         << proc << " for tag " << tag);
 
       this->communications.setCommunicationSize(tag, proc, size, sr);
     }
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename Entity>
 template <typename Pred>
 void SynchronizerImpl<Entity>::split(SynchronizerImpl<Entity> & in_synchronizer,
                                      Pred && pred) {
   AKANTU_DEBUG_IN();
 
   auto filter_list = [&](auto & list, auto & new_list) {
     auto copy = list;
     list.resize(0);
     new_list.resize(0);
 
     for (auto && entity : copy) {
       if (std::forward<Pred>(pred)(entity)) {
         new_list.push_back(entity);
       } else {
         list.push_back(entity);
       }
     }
   };
 
   for (auto sr : iterate_send_recv) {
     for (auto & scheme_pair :
          in_synchronizer.communications.iterateSchemes(sr)) {
       auto proc = scheme_pair.first;
       auto & scheme = scheme_pair.second;
       auto & new_scheme = communications.createScheme(proc, sr);
-      filter_list(new_scheme, scheme);
+      filter_list(scheme, new_scheme);
     }
   }
 
   in_synchronizer.communications.invalidateSizes();
   communications.invalidateSizes();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename Entity>
 template <typename Updater>
 void SynchronizerImpl<Entity>::updateSchemes(Updater && scheme_updater) {
   for (auto sr : iterate_send_recv) {
     for (auto & scheme_pair : communications.iterateSchemes(sr)) {
       auto proc = scheme_pair.first;
       auto & scheme = scheme_pair.second;
       std::forward<Updater>(scheme_updater)(scheme, proc, sr);
     }
   }
 
   communications.invalidateSizes();
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 UInt SynchronizerImpl<Entity>::sanityCheckDataSize(
     const Array<Entity> &, const SynchronizationTag &) const {
   return 0;
 }
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void SynchronizerImpl<Entity>::packSanityCheckData(
     CommunicationDescriptor<Entity> &) const {}
 
 /* -------------------------------------------------------------------------- */
 template <class Entity>
 void SynchronizerImpl<Entity>::unpackSanityCheckData(
     CommunicationDescriptor<Entity> &) const {}
 
 /* -------------------------------------------------------------------------- */
 } // namespace akantu
 
 #endif /* __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ */
diff --git a/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh b/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh
index 741047074..7422ecdb9 100644
--- a/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh
+++ b/test/test_fe_engine/_discrete_kirchhoff_triangle_18.msh
@@ -1,50 +1,271 @@
 $MeshFormat
 2.2 0 8
 $EndMeshFormat
 $Nodes
-13
+100
 1 0 0 0
 2 1 0 0
 3 1 1 0
 4 0 1 0
-5 0.4999999999990217 0 0
-6 1 0.4999999999990217 0
-7 0.5000000000013878 1 0
-8 0 0.5000000000013878 0
-9 0.5000000000000262 0.5000000000000762 0
-10 0.2500000000004626 0.7500000000004626 0
-11 0.7500000000004626 0.7499999999996739 0
-12 0.7499999999996739 0.2499999999996739 0
-13 0.24999999999961 0.2500000000004752 0
+5 0.1111111111109082 0 0
+6 0.2222222222217143 0 0
+7 0.333333333332501 0 0
+8 0.4444444444432878 0 0
+9 0.5555555555543833 0 0
+10 0.6666666666657874 0 0
+11 0.7777777777771916 0 0
+12 0.8888888888885959 0 0
+13 1 0.1111111111109082 0
+14 1 0.2222222222217143 0
+15 1 0.333333333332501 0
+16 1 0.4444444444432878 0
+17 1 0.5555555555543833 0
+18 1 0.6666666666657874 0
+19 1 0.7777777777771916 0
+20 1 0.8888888888885959 0
+21 0.8888888888884262 1 0
+22 0.777777777777932 1 0
+23 0.6666666666675918 1 0
+24 0.5555555555572513 1 0
+25 0.4444444444462943 1 0
+26 0.3333333333347207 1 0
+27 0.2222222222231471 1 0
+28 0.1111111111115736 1 0
+29 0 0.8888888888884262 0
+30 0 0.777777777777932 0
+31 0 0.6666666666675918 0
+32 0 0.5555555555572513 0
+33 0 0.4444444444462943 0
+34 0 0.3333333333347207 0
+35 0 0.2222222222231471 0
+36 0 0.1111111111115736 0
+37 0.1111111111109822 0.1111111111114996 0
+38 0.1111111111110561 0.2222222222229879 0
+39 0.11111111111113 0.3333333333344741 0
+40 0.1111111111112039 0.4444444444459603 0
+41 0.1111111111112778 0.5555555555569326 0
+42 0.1111111111113518 0.6666666666673913 0
+43 0.1111111111114257 0.7777777777778498 0
+44 0.1111111111114996 0.8888888888884451 0
+45 0.2222222222218735 0.1111111111114257 0
+46 0.2222222222220326 0.2222222222228287 0
+47 0.2222222222221919 0.3333333333342274 0
+48 0.2222222222223511 0.4444444444456261 0
+49 0.2222222222225103 0.5555555555566142 0
+50 0.2222222222226695 0.6666666666671908 0
+51 0.2222222222228287 0.7777777777777674 0
+52 0.2222222222229879 0.888888888888464 0
+53 0.3333333333327477 0.1111111111113518 0
+54 0.3333333333329943 0.2222222222226695 0
+55 0.3333333333332409 0.3333333333339809 0
+56 0.3333333333334876 0.4444444444452921 0
+57 0.3333333333337343 0.5555555555562953 0
+58 0.3333333333339809 0.6666666666669903 0
+59 0.3333333333342274 0.7777777777776852 0
+60 0.3333333333344741 0.8888888888884829 0
+61 0.4444444444436218 0.1111111111112778 0
+62 0.444444444443956 0.2222222222225103 0
+63 0.44444444444429 0.3333333333337343 0
+64 0.4444444444446239 0.4444444444449581 0
+65 0.4444444444449581 0.5555555555559767 0
+66 0.4444444444452921 0.66666666666679 0
+67 0.4444444444456261 0.7777777777776029 0
+68 0.4444444444459603 0.8888888888885014 0
+69 0.5555555555547019 0.1111111111112039 0
+70 0.5555555555550206 0.2222222222223511 0
+71 0.5555555555553394 0.3333333333334876 0
+72 0.5555555555556581 0.444444444444624 0
+73 0.5555555555559767 0.5555555555556581 0
+74 0.5555555555562953 0.6666666666665895 0
+75 0.555555555556614 0.7777777777775207 0
+76 0.5555555555569326 0.8888888888885206 0
+77 0.6666666666659877 0.11111111111113 0
+78 0.6666666666661885 0.2222222222221919 0
+79 0.6666666666663887 0.3333333333332409 0
+80 0.6666666666665892 0.44444444444429 0
+81 0.66666666666679 0.5555555555553392 0
+82 0.6666666666669905 0.6666666666663887 0
+83 0.6666666666671908 0.7777777777774383 0
+84 0.6666666666673913 0.8888888888885393 0
+85 0.7777777777772739 0.1111111111110561 0
+86 0.7777777777773561 0.2222222222220327 0
+87 0.7777777777774385 0.3333333333329943 0
+88 0.7777777777775208 0.4444444444439559 0
+89 0.7777777777776028 0.5555555555550208 0
+90 0.7777777777776852 0.6666666666661885 0
+91 0.7777777777777674 0.7777777777773561 0
+92 0.7777777777778497 0.8888888888885581 0
+93 0.888888888888577 0.1111111111109821 0
+94 0.8888888888885583 0.2222222222218735 0
+95 0.8888888888885393 0.3333333333327477 0
+96 0.8888888888885205 0.4444444444436219 0
+97 0.8888888888885017 0.5555555555547019 0
+98 0.8888888888884829 0.666666666665988 0
+99 0.888888888888464 0.777777777777274 0
+100 0.8888888888884451 0.888888888888577 0
 $EndNodes
 $Elements
-28
-1 15 2 0 101 1
-2 15 2 0 102 2
-3 15 2 0 103 3
-4 15 2 0 104 4
-5 1 2 0 101 1 5
-6 1 2 0 101 5 2
-7 1 2 0 102 2 6
-8 1 2 0 102 6 3
-9 1 2 0 103 3 7
-10 1 2 0 103 7 4
-11 1 2 0 104 4 8
-12 1 2 0 104 8 1
-13 2 2 0 101 4 10 7
-14 2 2 0 101 1 13 8
-15 2 2 0 101 3 11 6
-16 2 2 0 101 2 12 5
-17 2 2 0 101 8 9 10
-18 2 2 0 101 7 10 9
-19 2 2 0 101 7 9 11
-20 2 2 0 101 8 13 9
-21 2 2 0 101 6 11 9
-22 2 2 0 101 5 9 13
-23 2 2 0 101 5 12 9
-24 2 2 0 101 6 9 12
-25 2 2 0 101 1 5 13
-26 2 2 0 101 4 8 10
-27 2 2 0 101 2 6 12
-28 2 2 0 101 3 7 11
+162
+1 2 2 1 101 1 5 36
+2 2 2 1 101 36 5 37
+3 2 2 1 101 36 37 35
+4 2 2 1 101 35 37 38
+5 2 2 1 101 35 38 34
+6 2 2 1 101 34 38 39
+7 2 2 1 101 34 39 33
+8 2 2 1 101 33 39 40
+9 2 2 1 101 33 40 32
+10 2 2 1 101 32 40 41
+11 2 2 1 101 32 41 31
+12 2 2 1 101 31 41 42
+13 2 2 1 101 31 42 30
+14 2 2 1 101 30 42 43
+15 2 2 1 101 30 43 29
+16 2 2 1 101 29 43 44
+17 2 2 1 101 29 44 4
+18 2 2 1 101 4 44 28
+19 2 2 1 101 5 6 37
+20 2 2 1 101 37 6 45
+21 2 2 1 101 37 45 38
+22 2 2 1 101 38 45 46
+23 2 2 1 101 38 46 39
+24 2 2 1 101 39 46 47
+25 2 2 1 101 39 47 40
+26 2 2 1 101 40 47 48
+27 2 2 1 101 40 48 41
+28 2 2 1 101 41 48 49
+29 2 2 1 101 41 49 42
+30 2 2 1 101 42 49 50
+31 2 2 1 101 42 50 43
+32 2 2 1 101 43 50 51
+33 2 2 1 101 43 51 44
+34 2 2 1 101 44 51 52
+35 2 2 1 101 44 52 28
+36 2 2 1 101 28 52 27
+37 2 2 1 101 6 7 45
+38 2 2 1 101 45 7 53
+39 2 2 1 101 45 53 46
+40 2 2 1 101 46 53 54
+41 2 2 1 101 46 54 47
+42 2 2 1 101 47 54 55
+43 2 2 1 101 47 55 48
+44 2 2 1 101 48 55 56
+45 2 2 1 101 48 56 49
+46 2 2 1 101 49 56 57
+47 2 2 1 101 49 57 50
+48 2 2 1 101 50 57 58
+49 2 2 1 101 50 58 51
+50 2 2 1 101 51 58 59
+51 2 2 1 101 51 59 52
+52 2 2 1 101 52 59 60
+53 2 2 1 101 52 60 27
+54 2 2 1 101 27 60 26
+55 2 2 1 101 7 8 53
+56 2 2 1 101 53 8 61
+57 2 2 1 101 53 61 54
+58 2 2 1 101 54 61 62
+59 2 2 1 101 54 62 55
+60 2 2 1 101 55 62 63
+61 2 2 1 101 55 63 56
+62 2 2 1 101 56 63 64
+63 2 2 1 101 56 64 57
+64 2 2 1 101 57 64 65
+65 2 2 1 101 57 65 58
+66 2 2 1 101 58 65 66
+67 2 2 1 101 58 66 59
+68 2 2 1 101 59 66 67
+69 2 2 1 101 59 67 60
+70 2 2 1 101 60 67 68
+71 2 2 1 101 60 68 26
+72 2 2 1 101 26 68 25
+73 2 2 1 101 8 9 61
+74 2 2 1 101 61 9 69
+75 2 2 1 101 61 69 62
+76 2 2 1 101 62 69 70
+77 2 2 1 101 62 70 63
+78 2 2 1 101 63 70 71
+79 2 2 1 101 63 71 64
+80 2 2 1 101 64 71 72
+81 2 2 1 101 64 72 65
+82 2 2 1 101 65 72 73
+83 2 2 1 101 65 73 66
+84 2 2 1 101 66 73 74
+85 2 2 1 101 66 74 67
+86 2 2 1 101 67 74 75
+87 2 2 1 101 67 75 68
+88 2 2 1 101 68 75 76
+89 2 2 1 101 68 76 25
+90 2 2 1 101 25 76 24
+91 2 2 1 101 9 10 69
+92 2 2 1 101 69 10 77
+93 2 2 1 101 69 77 70
+94 2 2 1 101 70 77 78
+95 2 2 1 101 70 78 71
+96 2 2 1 101 71 78 79
+97 2 2 1 101 71 79 72
+98 2 2 1 101 72 79 80
+99 2 2 1 101 72 80 73
+100 2 2 1 101 73 80 81
+101 2 2 1 101 73 81 74
+102 2 2 1 101 74 81 82
+103 2 2 1 101 74 82 75
+104 2 2 1 101 75 82 83
+105 2 2 1 101 75 83 76
+106 2 2 1 101 76 83 84
+107 2 2 1 101 76 84 24
+108 2 2 1 101 24 84 23
+109 2 2 1 101 10 11 77
+110 2 2 1 101 77 11 85
+111 2 2 1 101 77 85 78
+112 2 2 1 101 78 85 86
+113 2 2 1 101 78 86 79
+114 2 2 1 101 79 86 87
+115 2 2 1 101 79 87 80
+116 2 2 1 101 80 87 88
+117 2 2 1 101 80 88 81
+118 2 2 1 101 81 88 89
+119 2 2 1 101 81 89 82
+120 2 2 1 101 82 89 90
+121 2 2 1 101 82 90 83
+122 2 2 1 101 83 90 91
+123 2 2 1 101 83 91 84
+124 2 2 1 101 84 91 92
+125 2 2 1 101 84 92 23
+126 2 2 1 101 23 92 22
+127 2 2 1 101 11 12 85
+128 2 2 1 101 85 12 93
+129 2 2 1 101 85 93 86
+130 2 2 1 101 86 93 94
+131 2 2 1 101 86 94 87
+132 2 2 1 101 87 94 95
+133 2 2 1 101 87 95 88
+134 2 2 1 101 88 95 96
+135 2 2 1 101 88 96 89
+136 2 2 1 101 89 96 97
+137 2 2 1 101 89 97 90
+138 2 2 1 101 90 97 98
+139 2 2 1 101 90 98 91
+140 2 2 1 101 91 98 99
+141 2 2 1 101 91 99 92
+142 2 2 1 101 92 99 100
+143 2 2 1 101 92 100 22
+144 2 2 1 101 22 100 21
+145 2 2 1 101 12 2 93
+146 2 2 1 101 93 2 13
+147 2 2 1 101 93 13 94
+148 2 2 1 101 94 13 14
+149 2 2 1 101 94 14 95
+150 2 2 1 101 95 14 15
+151 2 2 1 101 95 15 96
+152 2 2 1 101 96 15 16
+153 2 2 1 101 96 16 97
+154 2 2 1 101 97 16 17
+155 2 2 1 101 97 17 98
+156 2 2 1 101 98 17 18
+157 2 2 1 101 98 18 99
+158 2 2 1 101 99 18 19
+159 2 2 1 101 99 19 100
+160 2 2 1 101 100 19 20
+161 2 2 1 101 100 20 21
+162 2 2 1 101 21 20 3
 $EndElements
diff --git a/test/test_fe_engine/test_fe_engine_fixture.hh b/test/test_fe_engine/test_fe_engine_fixture.hh
index 822bf968c..8e2ba7b74 100644
--- a/test/test_fe_engine/test_fe_engine_fixture.hh
+++ b/test/test_fe_engine/test_fe_engine_fixture.hh
@@ -1,84 +1,83 @@
 /* -------------------------------------------------------------------------- */
 #include "element_class.hh"
 #include "fe_engine.hh"
 #include "integrator_gauss.hh"
 #include "shape_lagrange.hh"
 #include "test_gtest_utils.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_TEST_FE_ENGINE_FIXTURE_HH__
 #define __AKANTU_TEST_FE_ENGINE_FIXTURE_HH__
 
 using namespace akantu;
 
 /// Generic class for FEEngine tests
 template <typename type_, template <ElementKind> class shape_t,
           ElementKind kind = _ek_regular>
 class TestFEMBaseFixture : public ::testing::Test {
 public:
   static constexpr const ElementType type = type_::value;
   static constexpr const size_t dim = ElementClass<type>::getSpatialDimension();
   using FEM = FEEngineTemplate<IntegratorGauss, shape_t, kind>;
 
   /// Setup reads mesh corresponding to element type and initializes an FEEngine
   void SetUp() override {
     const auto dim = this->dim;
     const auto type = this->type;
     mesh = std::make_unique<Mesh>(dim);
 
     std::stringstream meshfilename;
     meshfilename << type << ".msh";
     this->readMesh(meshfilename.str());
 
     lower = mesh->getLowerBounds();
     upper = mesh->getUpperBounds();
 
     nb_element = this->mesh->getNbElement(type);
 
     fem = std::make_unique<FEM>(*mesh, dim, "my_fem");
-    fem->initShapeFunctions();
-
-    nb_quadrature_points_total = fem->getNbIntegrationPoints(type) * nb_element;
+    nb_quadrature_points_total =
+        GaussIntegrationElement<type>::getNbQuadraturePoints() * nb_element;
 
     SCOPED_TRACE(aka::to_string(type));
   }
 
   void TearDown() override {
     fem.reset(nullptr);
     mesh.reset(nullptr);
   }
 
   /// Should be reimplemented if further treatment of the mesh is needed
   virtual void readMesh(std::string file_name) { mesh->read(file_name); }
 
 protected:
   std::unique_ptr<FEM> fem;
   std::unique_ptr<Mesh> mesh;
   UInt nb_element;
   UInt nb_quadrature_points_total;
   Vector<Real> lower;
   Vector<Real> upper;
 };
 
 template <typename type_, template <ElementKind> class shape_t,
           ElementKind kind>
 constexpr const ElementType TestFEMBaseFixture<type_, shape_t, kind>::type;
 
 template <typename type_, template <ElementKind> class shape_t,
           ElementKind kind>
 constexpr const size_t TestFEMBaseFixture<type_, shape_t, kind>::dim;
 
 /* -------------------------------------------------------------------------- */
 /// Base class for test with Lagrange FEEngine and regular elements
 template <typename type_>
 using TestFEMFixture = TestFEMBaseFixture<type_, ShapeLagrange>;
 
 /* -------------------------------------------------------------------------- */
 
 using types = gtest_list_t<TestElementTypes>;
 
 TYPED_TEST_CASE(TestFEMFixture, types);
 
 #endif /* __AKANTU_TEST_FE_ENGINE_FIXTURE_HH__ */
diff --git a/test/test_fe_engine/test_fe_engine_gauss_integration.cc b/test/test_fe_engine/test_fe_engine_gauss_integration.cc
index 9e44bc23e..48fee7c9f 100644
--- a/test/test_fe_engine/test_fe_engine_gauss_integration.cc
+++ b/test/test_fe_engine/test_fe_engine_gauss_integration.cc
@@ -1,153 +1,155 @@
 /**
  * @file   test_fe_engine_precomputation.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Jun 14 2010
  * @date last modification: Mon Jul 13 2015
  *
  * @brief test integration on elements, this test consider that mesh is a cube
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <iostream>
 /* -------------------------------------------------------------------------- */
 using namespace akantu;
 
 namespace {
 /* -------------------------------------------------------------------------- */
 template <size_t t> using degree_t = std::integral_constant<size_t, t>;
 
 /* -------------------------------------------------------------------------- */
 using TestDegreeTypes = std::tuple<degree_t<0>, degree_t<1>, degree_t<2>, degree_t<3>, degree_t<4>, degree_t<5>>;
 
 std::array<Polynomial<5>, 3> global_polys{
     {{0.40062394, 0.13703225, 0.51731446, 0.87830084, 0.5410543, 0.71842292},
      {0.41861835, 0.11080576, 0.49874043, 0.49077504, 0.85073835, 0.66259755},
      {0.92620845, 0.7503478, 0.62962232, 0.31662719, 0.64069644, 0.30878135}}};
 
 template <typename T>
 class TestGaussIntegrationFixture
     : public TestFEMFixture<std::tuple_element_t<0, T>> {
 protected:
   using parent = TestFEMFixture<std::tuple_element_t<0, T>>;
   static constexpr size_t degree{std::tuple_element_t<1, T>::value};
 
 public:
   TestGaussIntegrationFixture() : integration_points_pos(0, parent::dim) {}
 
   void SetUp() override {
     parent::SetUp();
+    this->fem->initShapeFunctions();
+
     auto integration_points =
              this->fem->getIntegrator().template getIntegrationPoints <
              parent::type,
          degree == 0 ? 1 : degree > ();
 
     nb_integration_points = integration_points.cols();
 
     auto shapes_size = ElementClass<parent::type>::getShapeSize();
     Array<Real> shapes(0, shapes_size);
     this->fem->getShapeFunctions()
         .template computeShapesOnIntegrationPoints<parent::type>(
             this->mesh->getNodes(), integration_points, shapes, _not_ghost);
 
     auto vect_size = this->nb_integration_points * this->nb_element;
     integration_points_pos.resize(vect_size);
     this->fem->getShapeFunctions()
         .template interpolateOnIntegrationPoints<parent::type>(
             this->mesh->getNodes(), integration_points_pos, this->dim, shapes);
 
     for (size_t d = 0; d < this->dim; ++d) {
       polys[d] = global_polys[d].extract(degree);
     }
   }
 
   void testIntegrate() {
     std::stringstream sstr;
     sstr << this->type << ":" << this->degree;
     SCOPED_TRACE(sstr.str().c_str());
 
     auto vect_size = this->nb_integration_points * this->nb_element;
     Array<Real> polynomial(vect_size);
     size_t dim = parent::dim;
 
     for (size_t d = 0; d < dim; ++d) {
       auto poly = this->polys[d];
       for (auto && pair :
            zip(polynomial, make_view(this->integration_points_pos, dim))) {
         auto && p = std::get<0>(pair);
         auto & x = std::get<1>(pair);
         p = poly(x(d));
       }
 
       auto res =
           this->fem->getIntegrator()
           .template integrate<parent::type, (degree == 0 ? 1 : degree)>(polynomial);
       auto expect = poly.integrate(this->lower(d), this->upper(d));
 
       for (size_t o = 0; o < dim; ++o) {
         if (o == d)
           continue;
         expect *= this->upper(d) - this->lower(d);
       }
 
       EXPECT_NEAR(expect, res, 5e-14);
     }
   }
 
 protected:
   UInt nb_integration_points;
   std::array<Array<Real>, parent::dim> polynomial;
   Array<Real> integration_points_pos;
   std::array<Polynomial<5>, 3> polys;
 };
 
 template <typename T>
 constexpr size_t TestGaussIntegrationFixture<T>::degree;
 
 /* -------------------------------------------------------------------------- */
 /* Tests                                                                      */
 /* -------------------------------------------------------------------------- */
 TYPED_TEST_CASE_P(TestGaussIntegrationFixture);
 
 TYPED_TEST_P(TestGaussIntegrationFixture, ArbitraryOrder) {
   this->testIntegrate();
 }
 
 REGISTER_TYPED_TEST_CASE_P(TestGaussIntegrationFixture, ArbitraryOrder);
 
 
 using TestTypes =
     gtest_list_t<tuple_split_t<50, cross_product_t<TestElementTypes, TestDegreeTypes>>>;
 
 INSTANTIATE_TYPED_TEST_CASE_P(Split1, TestGaussIntegrationFixture, TestTypes);
 
 using TestTypesTail =
     gtest_list_t<tuple_split_tail_t<50, cross_product_t<TestElementTypes, TestDegreeTypes>>>;
 
 INSTANTIATE_TYPED_TEST_CASE_P(Split2, TestGaussIntegrationFixture, TestTypesTail);
 
 }
diff --git a/test/test_fe_engine/test_fe_engine_precomputation.cc b/test/test_fe_engine/test_fe_engine_precomputation.cc
index c66054cc6..149785f5b 100644
--- a/test/test_fe_engine/test_fe_engine_precomputation.cc
+++ b/test/test_fe_engine/test_fe_engine_precomputation.cc
@@ -1,112 +1,113 @@
 /**
  * @file   test_fe_engine_precomputation.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Jun 14 2010
  * @date last modification: Mon Jul 13 2015
  *
  * @brief  test of the fem class
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "pybind11_akantu.hh"
 #include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <pybind11/embed.h>
 #include <pybind11/numpy.h>
 /* -------------------------------------------------------------------------- */
 using namespace akantu;
 
 namespace py = pybind11;
 using namespace py::literals;
 
 template <typename type_>
 class TestFEMPyFixture : public TestFEMFixture<type_> {
   using parent = TestFEMFixture<type_>;
 
 public:
   void SetUp() override {
     parent::SetUp();
 
     const auto & connectivities = this->mesh->getConnectivity(this->type);
     const auto & nodes = this->mesh->getNodes().begin(this->dim);
     coordinates = std::make_unique<Array<Real>>(
         connectivities.size(), connectivities.getNbComponent() * this->dim);
 
     for (auto && tuple :
          zip(make_view(connectivities, connectivities.getNbComponent()),
              make_view(*coordinates, this->dim,
                        connectivities.getNbComponent()))) {
       const auto & conn = std::get<0>(tuple);
       const auto & X = std::get<1>(tuple);
       for (auto s : arange(conn.size())) {
         Vector<Real>(X(s)) = Vector<Real>(nodes[conn(s)]);
       }
     }
   }
 
   void TearDown() override {
     parent::TearDown();
     coordinates.reset(nullptr);
   }
 
 protected:
   std::unique_ptr<Array<Real>> coordinates;
 };
 
 TYPED_TEST_CASE(TestFEMPyFixture, types);
 
 TYPED_TEST(TestFEMPyFixture, Precompute) {
   SCOPED_TRACE(aka::to_string(this->type));
+  this->fem->initShapeFunctions();
   const auto & N = this->fem->getShapeFunctions().getShapes(this->type);
   const auto & B =
       this->fem->getShapeFunctions().getShapesDerivatives(this->type);
   const auto & j = this->fem->getIntegrator().getJacobians(this->type);
 
   // Array<Real> ref_N(this->nb_quadrature_points_total, N.getNbComponent());
   // Array<Real> ref_B(this->nb_quadrature_points_total, B.getNbComponent());
   Array<Real> ref_j(this->nb_quadrature_points_total, j.getNbComponent());
   auto ref_N(N);
   auto ref_B(B);
   py::module py_engine = py::module::import("py_engine");
   auto py_shape = py_engine.attr("Shapes")(py::str(aka::to_string(this->type)));
   auto kwargs = py::dict(
       "N"_a = make_proxy(ref_N), "B"_a = make_proxy(ref_B),
       "j"_a = make_proxy(ref_j), "X"_a = make_proxy(*this->coordinates),
       "Q"_a = make_proxy(
           this->fem->getIntegrationPoints(this->type)));
 
   auto ret = py_shape.attr("precompute")(**kwargs);
   auto check = [&](auto & ref_A, auto & A, const auto & id) {
     SCOPED_TRACE(aka::to_string(this->type) + " " + id);
     for (auto && n : zip(make_view(ref_A, ref_A.getNbComponent()),
                          make_view(A, A.getNbComponent()))) {
       auto diff = (std::get<0>(n) - std::get<1>(n)).template norm<L_inf>();
       EXPECT_NEAR(0., diff, 1e-10);
     }
   };
   check(ref_N, N, "N");
   check(ref_B, B, "B");
   check(ref_j, j, "j");
 }
diff --git a/test/test_fe_engine/test_fe_engine_precomputation_structural.cc b/test/test_fe_engine/test_fe_engine_precomputation_structural.cc
index fc69aaa56..fc7e3b8e5 100644
--- a/test/test_fe_engine/test_fe_engine_precomputation_structural.cc
+++ b/test/test_fe_engine/test_fe_engine_precomputation_structural.cc
@@ -1,109 +1,126 @@
 /**
  * @file   test_fe_engine_precomputation_structural.cc
  *
  * @author Lucas Frérot
  *
  * @date creation: Fri Feb 26 2018
  *
  * @brief  test of the structural precomputations
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "fe_engine.hh"
 #include "integrator_gauss.hh"
 #include "shape_structural.hh"
 #include "test_fe_engine_structural_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 /* -------------------------------------------------------------------------- */
 // Need a special fixture for the extra normal
 class TestBernoulliB3
     : public TestFEMStructuralFixture<element_type_t<_bernoulli_beam_3>> {
   using parent = TestFEMStructuralFixture<element_type_t<_bernoulli_beam_3>>;
 public:
 
   /// Load the mesh and provide extra normal direction
   void readMesh(std::string filename) override {
     parent::readMesh(filename);
     auto & normals = this->mesh->registerData<Real>("extra_normal")
                          .alloc(0, dim, type, _not_ghost);
     Vector<Real> normal = {-36. / 65, -48. / 65, 5. / 13};
     normals.push_back(normal);
   }
 };
 
 /* -------------------------------------------------------------------------- */
 /// Type alias
 using TestBernoulliB2 =
     TestFEMStructuralFixture<element_type_t<_bernoulli_beam_2>>;
+ using TestDKT18 =
+   TestFEMStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>>;
 /* -------------------------------------------------------------------------- */
 
 /// Solution for 2D rotation matrices
 Matrix<Real> globalToLocalRotation(Real theta) {
   auto c = std::cos(theta);
   auto s = std::sin(theta);
   return {{c, s, 0}, {-s, c, 0}, {0, 0, 1}};
 }
 
 /* -------------------------------------------------------------------------- */
 TEST_F(TestBernoulliB2, PrecomputeRotations) {
+  this->fem->initShapeFunctions();
   using ShapeStruct = ShapeStructural<_ek_structural>;
   auto & shape = dynamic_cast<const ShapeStruct &>(fem->getShapeFunctions());
   auto & rot = shape.getRotations(type);
 
   Real a = std::atan(4. / 3);
   std::vector<Real> angles = {a, -a, 0};
 
   Math::setTolerance(1e-15);
 
   for (auto && tuple : zip(make_view(rot, ndof, ndof), angles)) {
     auto rotation = std::get<0>(tuple);
     auto angle = std::get<1>(tuple);
     auto rotation_error = (rotation - globalToLocalRotation(angle)).norm<L_2>();
     EXPECT_NEAR(rotation_error, 0., Math::getTolerance());
   }
 }
 
 /* -------------------------------------------------------------------------- */
 TEST_F(TestBernoulliB3, PrecomputeRotations) {
+  this->fem->initShapeFunctions();
   using ShapeStruct = ShapeStructural<_ek_structural>;
   auto & shape = dynamic_cast<const ShapeStruct &>(fem->getShapeFunctions());
   auto & rot = shape.getRotations(type);
 
   Matrix<Real> ref = {{3. / 13, 4. / 13, 12. / 13},
                       {-4. / 5, 3. / 5, 0},
                       {-36. / 65, -48. / 65, 5. / 13}};
   Matrix<Real> solution{ndof, ndof};
   solution.block(ref, 0, 0);
   solution.block(ref, dim, dim);
 
   // The default tolerance is too much, really
   Math::setTolerance(1e-15);
 
   for (auto & rotation : make_view(rot, ndof, ndof)) {
     auto rotation_error = (rotation - solution).norm<L_2>();
     EXPECT_NEAR(rotation_error, 0., Math::getTolerance());
   }
 }
+
+/* -------------------------------------------------------------------------- */
+TEST_F(TestDKT18, PrecomputeRotations) {
+  this->fem->initShapeFunctions();
+  using ShapeStruct = ShapeStructural<_ek_structural>;
+  auto & shape = dynamic_cast<const ShapeStruct &>(fem->getShapeFunctions());
+  auto & rot = shape.getRotations(type);
+
+  for (auto & rotation : make_view(rot, ndof, ndof)) {
+    std::cout << rotation << "\n";
+  }
+  std::cout.flush();
+}
diff --git a/test/test_fe_engine/test_gradient.cc b/test/test_fe_engine/test_gradient.cc
index edd30e6a9..4afb40172 100644
--- a/test/test_fe_engine/test_gradient.cc
+++ b/test/test_fe_engine/test_gradient.cc
@@ -1,103 +1,105 @@
 /**
  * @file   test_gradient.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Peter Spijker <peter.spijker@epfl.ch>
  *
  * @date creation: Fri Sep 03 2010
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  test of the fem class
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  * @section DESCRIPTION
  *
  * This code is computing the gradient of a linear field and check that it gives
  * a constant result.  It also compute the gradient the  coordinates of the mesh
  * and check that it gives the identity
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <cstdlib>
 #include <iostream>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 namespace {
 
 TYPED_TEST(TestFEMFixture, GradientPoly) {
+  this->fem->initShapeFunctions();
   Real alpha[2][3] = {{13, 23, 31}, {11, 7, 5}};
 
   const auto dim = this->dim;
   const auto type = this->type;
 
   const auto & position = this->fem->getMesh().getNodes();
   Array<Real> const_val(this->fem->getMesh().getNbNodes(), 2, "const_val");
   for(auto && pair : zip(make_view(position, dim), make_view(const_val, 2))) {
     auto & pos = std::get<0>(pair);
     auto & const_ = std::get<1>(pair);
 
     const_.set(0.);
 
     for (UInt d = 0; d < dim; ++d) {
       const_(0) += alpha[0][d] * pos(d);
       const_(1) += alpha[1][d] * pos(d);
     }
   }
 
   /// compute the gradient
   Array<Real> grad_on_quad(this->nb_quadrature_points_total, 2 * dim, "grad_on_quad");
   this->fem->gradientOnIntegrationPoints(const_val, grad_on_quad, 2, type);
 
   /// check the results
   for(auto && grad : make_view(grad_on_quad, 2, dim)) {
     for (UInt d = 0; d < dim; ++d) {
       EXPECT_NEAR(grad(0, d), alpha[0][d], 5e-13);
       EXPECT_NEAR(grad(1, d), alpha[1][d], 5e-13);
     }
   }
 }
 
 TYPED_TEST(TestFEMFixture, GradientPositions) {
+  this->fem->initShapeFunctions();
   const auto dim = this->dim;
   const auto type = this->type;
 
   UInt nb_quadrature_points = this->fem->getNbIntegrationPoints(type) * this->nb_element;
   Array<Real> grad_coord_on_quad(nb_quadrature_points, dim * dim,
                                  "grad_coord_on_quad");
 
   const auto & position = this->mesh->getNodes();
   this->fem->gradientOnIntegrationPoints(position, grad_coord_on_quad,
                                          dim, type);
 
    auto I = Matrix<Real>::eye(UInt(dim));
 
    for(auto && grad : make_view(grad_coord_on_quad, dim, dim)) {
      auto diff = (I - grad).template norm<L_inf>();
 
      EXPECT_NEAR(0., diff, 2e-14);
    }
 }
 
 }
diff --git a/test/test_fe_engine/test_integrate.cc b/test/test_fe_engine/test_integrate.cc
index 40200579e..74ad310ad 100644
--- a/test/test_fe_engine/test_integrate.cc
+++ b/test/test_fe_engine/test_integrate.cc
@@ -1,75 +1,77 @@
 /**
  * @file   test_integrate.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Peter Spijker <peter.spijker@epfl.ch>
  *
  * @date creation: Fri Sep 03 2010
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  test of the fem class
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <cstdlib>
 #include <iostream>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 namespace {
 
 TYPED_TEST(TestFEMFixture, IntegrateConstant) {
+  this->fem->initShapeFunctions();
+
   const auto type = this->type;
 
   const auto & position = this->fem->getMesh().getNodes();
 
   Array<Real> const_val(position.size(), 2, "const_val");
   Array<Real> val_on_quad(this->nb_quadrature_points_total, 2, "val_on_quad");
 
   Vector<Real> value{1, 2};
   for (auto && const_ : make_view(const_val, 2)) {
     const_ = value;
   }
 
   // interpolate function on quadrature points
   this->fem->interpolateOnIntegrationPoints(const_val, val_on_quad, 2, type);
 
   // integrate function on elements
   Array<Real> int_val_on_elem(this->nb_element, 2, "int_val_on_elem");
   this->fem->integrate(val_on_quad, int_val_on_elem, 2, type);
 
   // get global integration value
   Vector<Real> sum{0., 0.};
 
   for (auto && int_ : make_view(int_val_on_elem, 2)) {
     sum += int_;
   }
 
   auto diff = (value - sum).template norm<L_inf>();
   EXPECT_NEAR(0, diff, 1e-14);
 }
 
 } // namespace
diff --git a/test/test_fe_engine/test_inverse_map.cc b/test/test_fe_engine/test_inverse_map.cc
index b4a0e9518..6da60b1df 100644
--- a/test/test_fe_engine/test_inverse_map.cc
+++ b/test/test_fe_engine/test_inverse_map.cc
@@ -1,69 +1,71 @@
 /**
  * @file   test_inverse_map.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  *
  * @date creation: Fri Sep 03 2010
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  test of the fem class
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 /* -------------------------------------------------------------------------- */
 #include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 namespace {
 
 TYPED_TEST(TestFEMFixture, InverseMap) {
+  this->fem->initShapeFunctions();
+
   Matrix<Real> quad = GaussIntegrationElement<TestFixture::type>::getQuadraturePoints();
 
   const auto & position = this->fem->getMesh().getNodes();
 
 /// get the quadrature points coordinates
   Array<Real> coord_on_quad(quad.cols() * this->nb_element, this->dim,
                             "coord_on_quad");
 
   this->fem->interpolateOnIntegrationPoints(position, coord_on_quad, this->dim, this->type);
 
   Vector<Real> natural_coords(this->dim);
 
   auto length = (this->upper - this->lower).template norm<L_inf>();
 
   for(auto && enum_ : enumerate(make_view(coord_on_quad, this->dim, quad.cols()))) {
     auto el = std::get<0>(enum_);
     const auto & quads_coords = std::get<1>(enum_);
 
     for (auto q : arange(quad.cols())) {
       Vector<Real> quad_coord = quads_coords(q);
       Vector<Real> ref_quad_coord = quad(q);
       this->fem->inverseMap(quad_coord, el, this->type, natural_coords);
 
       auto dis_normalized = ref_quad_coord.distance(natural_coords) / length;
       EXPECT_NEAR(0., dis_normalized, 5e-12);
     }
   }
 }
 
 } // namespace
diff --git a/test/test_model/patch_tests/CMakeLists.txt b/test/test_model/patch_tests/CMakeLists.txt
index aebad9be4..d845ec350 100644
--- a/test/test_model/patch_tests/CMakeLists.txt
+++ b/test/test_model/patch_tests/CMakeLists.txt
@@ -1,112 +1,117 @@
 #===============================================================================
 # @file   CMakeLists.txt
 #
 # @author David Simon Kammer <david.kammer@epfl.ch>
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Fri Oct 22 2010
 # @date last modification: Mon Dec 07 2015
 #
 # @brief  configuration for patch tests
 #
 # @section LICENSE
 #
 # Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
 # Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
 # Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 # @section DESCRIPTION
 #
 #===============================================================================
 add_subdirectory(data)
 
 register_gtest_sources(SOURCES patch_test_linear_elastic_explicit.cc
   PACKAGE solid_mechanics
   FILES_TO_COPY data/material_check_stress_plane_strain.dat
                 data/material_check_stress_plane_stress.dat)
 register_gtest_sources(SOURCES patch_test_linear_elastic_implicit.cc
   PACKAGE solid_mechanics implicit
   FILES_TO_COPY data/material_check_stress_plane_strain.dat
                 data/material_check_stress_plane_stress.dat)
+
 register_gtest_sources(SOURCES patch_test_linear_anisotropic_explicit.cc
-  PACKAGE solid_mechanics
-  FILES_TO_COPY data/material_anisotropic.dat
-  UNSTABLE)
+  PACKAGE solid_mechanics lapack
+  FILES_TO_COPY data/material_anisotropic.dat)
 
 register_gtest_sources(SOURCES test_lumped_mass.cc
   PACKAGE solid_mechanics
   FILES_TO_COPY data/material_lumped.dat)
 
 register_gtest_sources(
   SOURCES patch_test_linear_heat_transfer_explicit.cc
   FILES_TO_COPY data/heat_transfer_input.dat
   PACKAGE heat_transfer)
 
 register_gtest_sources(
   SOURCES patch_test_linear_heat_transfer_static.cc
   FILES_TO_COPY data/heat_transfer_input.dat
   PACKAGE heat_transfer implicit)
 
+register_gtest_sources(
+  SOURCES patch_test_linear_heat_transfer_implicit.cc
+  FILES_TO_COPY data/heat_transfer_input.dat
+  PACKAGE heat_transfer implicit)
+
 register_gtest_test(patch_test_linear
   FILES_TO_COPY ${PATCH_TEST_MESHES})
 
 register_test(test_linear_elastic_explicit_python
   SCRIPT patch_test_linear_elastic_explicit.py
   PYTHON
   PACKAGE python_interface
   FILES_TO_COPY patch_test_linear_fixture.py
   FILES_TO_COPY patch_test_linear_solid_mechanics_fixture.py
   FILES_TO_COPY ${PATCH_TEST_MESHES})
 
 register_test(test_linear_elastic_static_python
   SCRIPT patch_test_linear_elastic_static.py
   PYTHON
   PACKAGE python_interface implicit
   FILES_TO_COPY patch_test_linear_fixture.py
   FILES_TO_COPY patch_test_linear_solid_mechanics_fixture.py)
 
 register_test(test_linear_anisotropic_explicit_python
   SCRIPT patch_test_linear_anisotropic_explicit.py
   PYTHON
-  PACKAGE python_interface
+  PACKAGE python_interface lapack
   FILES_TO_COPY patch_test_linear_fixture.py
   FILES_TO_COPY patch_test_linear_solid_mechanics_fixture.py
   FILES_TO_COPY data/material_anisotropic.dat)
 
 
 register_test(patch_test_linear_heat_transfer_explicit_python
   SCRIPT patch_test_linear_heat_transfer_explicit.py
   PYTHON
   PACKAGE python_interface heat_transfer
   FILES_TO_COPY patch_test_linear_fixture.py
   FILES_TO_COPY patch_test_linear_heat_transfer_fixture.py
   FILES_TO_COPY data/heat_transfer_input.dat)
 
 register_test(patch_test_linear_heat_transfer_static_python
   SCRIPT patch_test_linear_heat_transfer_static.py
   PYTHON
   PACKAGE python_interface heat_transfer implicit
   FILES_TO_COPY patch_test_linear_fixture.py
   FILES_TO_COPY patch_test_linear_heat_transfer_fixture.py
   FILES_TO_COPY data/heat_transfer_input.dat)
 
 register_test(patch_test_linear_heat_transfer_implicit_python
   SCRIPT patch_test_linear_heat_transfer_implicit.py
   PYTHON
   PACKAGE python_interface heat_transfer implicit
   FILES_TO_COPY patch_test_linear_fixture.py
   FILES_TO_COPY patch_test_linear_heat_transfer_fixture.py
   FILES_TO_COPY data/heat_transfer_input.dat)
diff --git a/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc b/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc
index d85e51e86..f34a42414 100644
--- a/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc
+++ b/test/test_model/patch_tests/patch_test_linear_anisotropic_explicit.cc
@@ -1,109 +1,114 @@
 /**
  * @file   patch_test_explicit_anisotropic.cc
  *
  * @author Till Junge <till.junge@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  * @author Cyprien Wolff <cyprien.wolff@epfl.ch>
  *
  * @date creation: Sat Apr 16 2011
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  patch test for elastic material in solid mechanics model
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
-#include "patch_test_linear_fixture.hh"
+#include "patch_test_linear_solid_mechanics_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 // Stiffness tensor, rotated by hand
 Real C[3][3][3]
       [3] = {{{{112.93753505, 1.85842452538e-10, -4.47654358027e-10},
                {1.85847317471e-10, 54.2334345331, -3.69840984824},
                {-4.4764768395e-10, -3.69840984824, 56.848605217}},
               {{1.85847781609e-10, 25.429294233, -3.69840984816},
                {25.429294233, 3.31613847493e-10, -8.38797920011e-11},
                {-3.69840984816, -8.38804581349e-11, -1.97875715813e-10}},
               {{-4.47654358027e-10, -3.69840984816, 28.044464917},
                {-3.69840984816, 2.09374961813e-10, 9.4857455224e-12},
                {28.044464917, 9.48308098714e-12, -2.1367885239e-10}}},
              {{{1.85847781609e-10, 25.429294233, -3.69840984816},
                {25.429294233, 3.31613847493e-10, -8.38793479119e-11},
                {-3.69840984816, -8.38795699565e-11, -1.97876381947e-10}},
               {{54.2334345331, 3.31617400207e-10, 2.09372075233e-10},
                {3.3161562385e-10, 115.552705733, -3.15093728886e-10},
                {2.09372075233e-10, -3.15090176173e-10, 54.2334345333}},
               {{-3.69840984824, -8.38795699565e-11, 9.48219280872e-12},
                {-8.38795699565e-11, -3.1509195253e-10, 25.4292942335},
                {9.48441325477e-12, 25.4292942335, 3.69840984851}}},
              {{{-4.47653469848e-10, -3.69840984816, 28.044464917},
                {-3.69840984816, 2.09374073634e-10, 9.48752187924e-12},
                {28.044464917, 9.48552347779e-12, -2.1367885239e-10}},
               {{-3.69840984824, -8.3884899027e-11, 9.48219280872e-12},
                {-8.3884899027e-11, -3.150972816e-10, 25.4292942335},
                {9.48041645188e-12, 25.4292942335, 3.69840984851}},
               {{56.848605217, -1.97875493768e-10, -2.13681516925e-10},
                {-1.97877270125e-10, 54.2334345333, 3.69840984851},
                {-2.13683293282e-10, 3.69840984851, 112.93753505}}}};
 
 /* -------------------------------------------------------------------------- */
-TYPED_TEST(TestPatchTestLinear, AnisotropicExplicit) {
+TYPED_TEST(TestPatchTestSMMLinear, AnisotropicExplicit) {
   this->initModel(_explicit_lumped_mass, "material_anisotropic.dat");
 
   const auto & coordinates = this->mesh->getNodes();
   auto & displacement = this->model->getDisplacement();
 
   // set the position of all nodes to the static solution
   for (auto && tuple : zip(make_view(coordinates, this->dim),
                            make_view(displacement, this->dim))) {
-    this->setDisplacement(std::get<1>(tuple), std::get<0>(tuple));
+    this->setLinearDOF(std::get<1>(tuple), std::get<0>(tuple));
   }
 
   for (UInt s = 0; s < 100; ++s) {
     this->model->solveStep();
   }
 
   auto ekin = this->model->getEnergy("kinetic");
   EXPECT_NEAR(0, ekin, 1e-16);
 
-  this->checkDisplacements();
-  this->checkStrains();
-  this->checkStresses([&](const Matrix<Real> & pstrain) {
+  auto & mat = this->model->getMaterial(0);
+    
+  this->checkDOFs(displacement);
+  this->checkGradient(mat.getGradU(this->type), displacement);
+
+
+  this->checkResults([&](const Matrix<Real> & pstrain) {
     auto strain = (pstrain + pstrain.transpose()) / 2.;
     decltype(strain) stress(this->dim, this->dim);
 
     for (UInt i = 0; i < this->dim; ++i) {
       for (UInt j = 0; j < this->dim; ++j) {
         stress(i, j) = 0;
         for (UInt k = 0; k < this->dim; ++k) {
           for (UInt l = 0; l < this->dim; ++l) {
             stress(i, j) += C[i][j][k][l] * strain(k, l);
           }
         }
       }
     }
     return stress;
-  });
+    },
+    mat.getStress(this->type), displacement);
 }
diff --git a/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc
index 08e3ddd1f..c14e0207b 100644
--- a/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc
+++ b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.cc
@@ -1,21 +1,21 @@
 /* -------------------------------------------------------------------------- */
 #include "patch_test_linear_heat_transfer_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
-TYPED_TEST(TestPatchTestHTMLinear, Explicit) {
+TYPED_TEST(TestPatchTestHTMLinear, Implicit) {
   this->initModel(_implicit_dynamic, "heat_transfer_input.dat");
 
   const auto & coordinates = this->mesh->getNodes();
   auto & temperature = this->model->getTemperature();
   // set the position of all nodes to the static solution
   for (auto && tuple : zip(make_view(coordinates, this->dim),
                            make_view(temperature, 1))) {
     this->setLinearDOF(std::get<1>(tuple), std::get<0>(tuple));
   }
 
   for (UInt s = 0; s < 100; ++s) {
     this->model->solveStep();
   }
 
   this->checkAll();
 }
diff --git a/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.py b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.py
new file mode 100644
index 000000000..c78ad8bfa
--- /dev/null
+++ b/test/test_model/patch_tests/patch_test_linear_heat_transfer_implicit.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+
+from patch_test_linear_heat_transfer_fixture import TestPatchTestHTMLinear
+import akantu
+
+
+def foo(self):
+    self.initModel(akantu.HeatTransferModelOptions(akantu._implicit_dynamic),
+                   "heat_transfer_input.dat")
+
+    coordinates = self.mesh.getNodes()
+    temperature = self.model.getTemperature()
+    #  set the position of all nodes to the static solution
+    self.setLinearDOF(temperature, coordinates)
+
+    for s in range(0, 100):
+        self.model.solveStep()
+
+    self.checkAll()
+
+
+TestPatchTestHTMLinear.TYPED_TEST(foo, "Explicit")
diff --git a/test/test_model/patch_tests/patch_test_linear_heat_transfer_static.py b/test/test_model/patch_tests/patch_test_linear_heat_transfer_static.py
new file mode 100644
index 000000000..5d1749b10
--- /dev/null
+++ b/test/test_model/patch_tests/patch_test_linear_heat_transfer_static.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+
+from patch_test_linear_heat_transfer_fixture import TestPatchTestHTMLinear
+import akantu
+
+
+def foo(self):
+    self.initModel(akantu.HeatTransferModelOptions(akantu._static),
+                   "heat_transfer_input.dat")
+
+    solver = self.model.getNonLinearSolver()
+    solver.set("max_iterations", 2)
+    solver.set("threshold", 2e-4)
+    solver.set("convergence_type", akantu._scc_residual)
+
+    self.model.solveStep()
+
+    self.checkAll()
+
+
+TestPatchTestHTMLinear.TYPED_TEST(foo, "Implicit")
diff --git a/test/test_model/test_model_solver/test_model_solver_dynamic.cc b/test/test_model/test_model_solver/test_model_solver_dynamic.cc
index 1373d2946..7956e1e98 100644
--- a/test/test_model/test_model_solver/test_model_solver_dynamic.cc
+++ b/test/test_model/test_model_solver/test_model_solver_dynamic.cc
@@ -1,171 +1,171 @@
 /**
  * @file   test_dof_manager_default.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date   Wed Feb 24 12:28:44 2016
  *
  * @brief  Test default dof manager
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "data_accessor.hh"
 #include "dof_manager.hh"
 #include "dof_manager_default.hh"
 #include "element_synchronizer.hh"
 #include "mesh.hh"
 #include "mesh_accessor.hh"
 #include "model_solver.hh"
 #include "non_linear_solver.hh"
 #include "sparse_matrix.hh"
 #include "communicator.hh"
 #include "synchronizer_registry.hh"
 /* -------------------------------------------------------------------------- */
 #include "test_model_solver_my_model.hh"
 /* -------------------------------------------------------------------------- */
 #include <fstream>
 /* -------------------------------------------------------------------------- */
 
 #ifndef EXPLICIT
 #define EXPLICIT true
 #endif
 
 using namespace akantu;
 
 static void genMesh(Mesh & mesh, UInt nb_nodes);
 
 /* -------------------------------------------------------------------------- */
 int main(int argc, char * argv[]) {
   initialize(argc, argv);
 
   UInt prank = Communicator::getStaticCommunicator().whoAmI();
   UInt global_nb_nodes = 201;
   UInt max_steps = 200;
   Real time_step = 0.001;
   Mesh mesh(1);
   Real F = -9.81;
   bool _explicit = EXPLICIT;
 
   if (prank == 0)
     genMesh(mesh, global_nb_nodes);
 
   mesh.distribute();
 
   MyModel model(F, mesh, _explicit);
 
   if (!_explicit) {
     model.getNewSolver("dynamic", _tsst_dynamic, _nls_newton_raphson);
     model.setIntegrationScheme("dynamic", "disp", _ist_trapezoidal_rule_2,
                                IntegrationScheme::_displacement);
   } else {
     model.getNewSolver("dynamic", _tsst_dynamic_lumped, _nls_lumped);
     model.setIntegrationScheme("dynamic", "disp", _ist_central_difference,
                                IntegrationScheme::_acceleration);
   }
 
   model.setTimeStep(time_step);
 
   // #if EXPLICIT == true
   //   std::ofstream output("output_dynamic_explicit.csv");
   // #else
   //   std::ofstream output("output_dynamic_implicit.csv");
   // #endif
 
   if (prank == 0) {
     std::cout << std::scientific;
     std::cout << std::setw(14) << "time"
               << "," << std::setw(14) << "wext"
               << "," << std::setw(14) << "epot"
               << "," << std::setw(14) << "ekin"
               << "," << std::setw(14) << "total" << std::endl;
   }
   Real wext = 0.;
 
   model.getDOFManager().clearResidual();
   model.assembleResidual();
 
   Real epot = 0;//model.getPotentialEnergy();
   Real ekin = 0;//model.getKineticEnergy();
   Real einit = ekin + epot;
   Real etot = ekin + epot - wext - einit;
   if (prank == 0) {
     std::cout << std::setw(14) << 0. << "," << std::setw(14) << wext << ","
               << std::setw(14) << epot << "," << std::setw(14) << ekin << ","
               << std::setw(14) << etot << std::endl;
   }
 
 #if EXPLICIT == false
   NonLinearSolver & solver =
       model.getDOFManager().getNonLinearSolver("dynamic");
 
   solver.set("max_iterations", 20);
 #endif
 
   for (UInt i = 1; i < max_steps + 1; ++i) {
-    model.solveStep();
+    model.solveStep("dynamic");
 
 #if EXPLICIT == false
     //int nb_iter = solver.get("nb_iterations");
     //Real error = solver.get("error");
     //bool converged = solver.get("converged");
     //if (prank == 0)
     // std::cerr << error << " " << nb_iter << " -> " << converged << std::endl;
 #endif
 
     epot = model.getPotentialEnergy();
     ekin = model.getKineticEnergy();
     wext += model.getExternalWorkIncrement();
     etot = ekin + epot - wext - einit;
     if (prank == 0) {
       std::cout << std::setw(14) << time_step * i << "," << std::setw(14)
                 << wext << "," << std::setw(14) << epot << "," << std::setw(14)
                 << ekin << "," << std::setw(14) << etot << std::endl;
     }
 
     if (std::abs(etot) > 1e-1) {
       AKANTU_DEBUG_ERROR("The total energy of the system is not conserved!");
     }
   }
 
   // output.close();
   finalize();
   return EXIT_SUCCESS;
 }
 
 /* -------------------------------------------------------------------------- */
 void genMesh(Mesh & mesh, UInt nb_nodes) {
   MeshAccessor mesh_accessor(mesh);
   Array<Real> & nodes = mesh_accessor.getNodes();
   Array<UInt> & conn = mesh_accessor.getConnectivity(_segment_2);
 
   nodes.resize(nb_nodes);
 
   for (UInt n = 0; n < nb_nodes; ++n) {
     nodes(n, _x) = n * (1. / (nb_nodes - 1));
   }
 
   conn.resize(nb_nodes - 1);
   for (UInt n = 0; n < nb_nodes - 1; ++n) {
     conn(n, 0) = n;
     conn(n, 1) = n + 1;
   }
 }
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt b/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt
index bce3d66b5..816e1ed21 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/CMakeLists.txt
@@ -1,55 +1,110 @@
 #===============================================================================
 # @file   CMakeLists.txt
 #
 # @author Marco Vocialta <marco.vocialta@epfl.ch>
 #
 # @date creation: Fri Oct 22 2010
 # @date last modification: Thu Jan 14 2016
 #
 # @brief  configuration for cohesive elements tests
 #
 # @section LICENSE
 #
 # Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
 # Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
 # Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 # @section DESCRIPTION
 #
 #===============================================================================
 
 #add_akantu_test(test_cohesive_intrinsic "test_cohesive_intrinsic")
 #add_akantu_test(test_cohesive_extrinsic "test_cohesive_extrinsic")
 #add_akantu_test(test_cohesive_intrinsic_impl "test_cohesive_intrinsic_impl")
 #add_akantu_test(test_cohesive_1d_element "test_cohesive_1d_element")
 #add_akantu_test(test_cohesive_extrinsic_implicit "test_cohesive_extrinsic_implicit")
 
 add_akantu_test(test_cohesive_buildfragments "test_cohesive_buildfragments")
 add_akantu_test(test_cohesive_insertion "test_cohesive_insertion")
 add_akantu_test(test_cohesive_linear_friction "test_cohesive_linear_friction")
 #add_akantu_test(test_parallel_cohesive "parallel_cohesive_test")
 
-add_mesh(cohesive_2d_4 data/cohesive_strait_2D.geo 2 1 OUTPUT _cohesive_2d_4.msh)
-add_mesh(cohesive_2d_6 data/cohesive_strait_2D.geo 2 2 OUTPUT _cohesive_2d_6.msh)
+set(_meshes)
+
+add_mesh(cohesive_1d_2_seg data/cohesive_1D.geo
+  DIM 2 ORDER 1
+  OUTPUT _cohesive_1d_2_segment_2.msh)
+list(APPEND _meshes cohesive_1d_2_seg)
+
+add_mesh(cohesive_2d_4_tri data/cohesive_strait_2D.geo
+  DIM 2 ORDER 1
+  OUTPUT _cohesive_2d_4_triangle_3.msh)
+list(APPEND _meshes cohesive_2d_4_tri)
+
+add_mesh(cohesive_2d_6_tri data/cohesive_strait_2D.geo
+  DIM 2 ORDER 2
+  OUTPUT _cohesive_2d_6_triangle_6.msh)
+list(APPEND _meshes cohesive_2d_6_tri)
+
+add_mesh(cohesive_2d_4_quad data/cohesive_strait_2D_structured.geo
+  DIM 2 ORDER 1
+  OUTPUT _cohesive_2d_4_quadrangle_4.msh)
+list(APPEND _meshes cohesive_2d_4_quad)
+
+add_mesh(cohesive_2d_6_quad data/cohesive_strait_2D_structured.geo
+  DIM 2 ORDER 2
+  OUTPUT _cohesive_2d_6_quadrangle_8.msh)
+list(APPEND _meshes cohesive_2d_6_quad)
+
+add_mesh(cohesive_2d_4_tri_quad data/cohesive_strait_2D_mixte.geo
+  DIM 2 ORDER 1
+  OUTPUT _cohesive_2d_4_triangle_3_quadrangle_4.msh)
+list(APPEND _meshes cohesive_2d_4_tri_quad)
+
+add_mesh(cohesive_2d_6_tri_quad data/cohesive_strait_2D_mixte.geo
+  DIM 2 ORDER 2
+  OUTPUT _cohesive_2d_6_triangle_6_quadrangle_8.msh)
+list(APPEND _meshes cohesive_2d_6_tri_quad)
+
+add_mesh(cohesive_3d_6_tet data/cohesive_strait_3D.geo
+  DIM 3 ORDER 1
+  OUTPUT _cohesive_3d_6_tetrahedron_4.msh)
+list(APPEND _meshes cohesive_3d_6_tet)
+
+add_mesh(cohesive_3d_12_tet data/cohesive_strait_3D.geo
+  DIM 3 ORDER 2
+  OUTPUT _cohesive_3d_12_tetrahedron_10.msh)
+list(APPEND _meshes cohesive_3d_12_tet)
+
+add_mesh(cohesive_3d_8_hex data/cohesive_strait_3D_structured.geo
+  DIM 3 ORDER 1
+  OUTPUT _cohesive_3d_8_hexahedron_8.msh)
+list(APPEND _meshes cohesive_3d_8_hex)
+
+add_mesh(cohesive_3d_16_hex data/cohesive_strait_3D_structured.geo
+  DIM 3 ORDER 2
+  OUTPUT _cohesive_3d_16_hexahedron_20.msh)
+list(APPEND _meshes cohesive_3d_16_hex)
 
 register_gtest_sources(
   SOURCES test_cohesive.cc
   PACKAGE cohesive_element
-  DEPENDS cohesive_2d_4 cohesive_2d_6
+  DEPENDS ${_meshes}
+  FILES_TO_COPY material_0.dat material_1.dat
   )
 
 register_gtest_test(test_solid_mechanics_model_cohesive)
 #===============================================================================
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_1D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_1D.geo
new file mode 100644
index 000000000..f52f56ea0
--- /dev/null
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_1D.geo
@@ -0,0 +1,15 @@
+h = 0.5;
+
+Point(1) = { 1., 0., 0., h};
+Point(3) = { 0., 0., 0., h};
+Point(2) = {-1., 0., 0., h};
+
+Line(1) = {2, 3};
+Line(2) = {3, 1};
+
+Physical Point ("loading") = {1};
+Physical Point ("fixed") = {2};
+
+Physical Point ("insertion") = {3};
+
+Physical Line ("body") = {1, 2};
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 be9cd3a9b..65c7a7dd0 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
@@ -1,29 +1,30 @@
-h = 1.;
+h = 0.5;
 
 Point(1) = { 1, 1, 0, h};
 Point(2) = {-1, 1, 0, h};
 Point(3) = {-1,-1, 0, h};
 Point(4) = { 1,-1, 0, h};
 
 Point(5) = {-1, 0, 0, h};
 Point(6) = { 1, 0, 0, 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};
 
 Physical Line("fixed") = {6};
 Physical Line("loading") = {1};
 Physical Line("insertion") = {3};
+Physical Line("sides") = {2, 5, 7, 4};
 
 Physical Surface("body") = {1, 2};
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_mixte.geo
similarity index 80%
copy from test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo
copy to test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo
index be9cd3a9b..5550c66de 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_mixte.geo
@@ -1,29 +1,34 @@
-h = 1.;
+h = 0.4;
 
 Point(1) = { 1, 1, 0, h};
 Point(2) = {-1, 1, 0, h};
 Point(3) = {-1,-1, 0, h};
 Point(4) = { 1,-1, 0, h};
 
 Point(5) = {-1, 0, 0, h};
 Point(6) = { 1, 0, 0, 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};
 
 Physical Line("fixed") = {6};
 Physical Line("loading") = {1};
 Physical Line("insertion") = {3};
+Physical Line("sides") = {2, 5, 7, 4};
 
 Physical Surface("body") = {1, 2};
+
+Recombine Surface {2};
+Transfinite Surface {2};
+Mesh.SecondOrderIncomplete = 1;
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_structured.geo
similarity index 80%
copy from test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo
copy to test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo
index be9cd3a9b..c571a062e 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_structured.geo
@@ -1,29 +1,34 @@
-h = 1.;
+h = 0.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};
 
 Point(5) = {-1, 0, 0, h};
 Point(6) = { 1, 0, 0, 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};
 
 Physical Line("fixed") = {6};
 Physical Line("loading") = {1};
 Physical Line("insertion") = {3};
+Physical Line("sides") = {2, 5, 7, 4};
 
 Physical Surface("body") = {1, 2};
+
+Recombine Surface "*";
+Transfinite Surface "*";
+Mesh.SecondOrderIncomplete = 1;
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
new file mode 100644
index 000000000..ad9490148
--- /dev/null
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo
@@ -0,0 +1,33 @@
+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};
+}
+
+Physical Surface("fixed") = {46};
+Physical Surface("insertion") = {24};
+Physical Surface("loading") = {16};
+Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42};
+
+Physical Volume("body") = {1, 2};
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
new file mode 100644
index 000000000..c54ed8705
--- /dev/null
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo
@@ -0,0 +1,40 @@
+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};
+}
+
+Physical Surface("fixed") = {46};
+Physical Surface("insertion") = {24};
+Physical Surface("loading") = {16};
+Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42};
+
+Physical Volume("body") = {1, 2};
+
+Transfinite Surface "*";
+Transfinite Volume "*";
+
+Recombine Surface "*";
+
+Mesh.SecondOrderIncomplete = 1;
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat b/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat
index ad4749045..5e89a3873 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat
@@ -1,19 +1,19 @@
 model solid_mechanics_model_cohesive [
   cohesive_inserter [
     cohesive_surfaces = [insertion]
   ]
 
   material elastic [
-    name = steel
+    name = body
     rho = 1e3   # density
-    E   = 1e3   # young's modulus
-    nu  = 0.001 # poisson's ratio
+    E   = 1e9   # young's modulus
+    nu  = 0.2 # poisson's ratio
   ]
 
   material cohesive_linear [
     name = insertion
     beta = 1
-    G_c = 100
-    sigma_c = 100
+    G_c = 10
+    sigma_c = 1e6
   ]
 ]
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat b/test/test_model/test_solid_mechanics_model/test_cohesive/material_0.dat
similarity index 65%
copy from test/test_model/test_solid_mechanics_model/test_cohesive/material.dat
copy to test/test_model/test_solid_mechanics_model/test_cohesive/material_0.dat
index ad4749045..5e89a3873 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/material_0.dat
@@ -1,19 +1,19 @@
 model solid_mechanics_model_cohesive [
   cohesive_inserter [
     cohesive_surfaces = [insertion]
   ]
 
   material elastic [
-    name = steel
+    name = body
     rho = 1e3   # density
-    E   = 1e3   # young's modulus
-    nu  = 0.001 # poisson's ratio
+    E   = 1e9   # young's modulus
+    nu  = 0.2 # poisson's ratio
   ]
 
   material cohesive_linear [
     name = insertion
     beta = 1
-    G_c = 100
-    sigma_c = 100
+    G_c = 10
+    sigma_c = 1e6
   ]
 ]
diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat b/test/test_model/test_solid_mechanics_model/test_cohesive/material_1.dat
similarity index 54%
copy from test/test_model/test_solid_mechanics_model/test_cohesive/material.dat
copy to test/test_model/test_solid_mechanics_model/test_cohesive/material_1.dat
index ad4749045..1d5cc574d 100644
--- a/test/test_model/test_solid_mechanics_model/test_cohesive/material.dat
+++ b/test/test_model/test_solid_mechanics_model/test_cohesive/material_1.dat
@@ -1,19 +1,20 @@
 model solid_mechanics_model_cohesive [
   cohesive_inserter [
     cohesive_surfaces = [insertion]
   ]
 
   material elastic [
-    name = steel
+    name = body
     rho = 1e3   # density
-    E   = 1e3   # young's modulus
-    nu  = 0.001 # poisson's ratio
+    E   = 1e9   # young's modulus
+    nu  = 0.2 # poisson's ratio
   ]
 
-  material cohesive_linear [
+  material cohesive_bilinear [
     name = insertion
     beta = 1
-    G_c = 100
-    sigma_c = 100
+    G_c = 10
+    sigma_c = 1e6
+    delta_0 = 1e-7
   ]
 ]
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 593c99e1d..043b77e70 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
@@ -1,50 +1,64 @@
 /* -------------------------------------------------------------------------- */
-#include "test_cohesive_fixture.hh"
 #include "aka_iterators.hh"
+#include "test_cohesive_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
-TYPED_TEST(TestSMMCFixture, ModeI) {
-  auto max_steps = 100;
-  auto disp_inc = 0.1;
-  for(auto _ [[gnu::unused]] : arange(max_steps)) {
-    this->model->applyBC(BC::Dirichlet::IncrementValue(disp_inc, _x), "loading");
-    if(this->is_extrinsic)
-      this->model->checkCohesiveStress();
+TYPED_TEST(TestSMMCFixture, ExtrinsicModeI) {
+  getStaticParser().parse("material_0.dat");
+  this->is_extrinsic = true;
+  this->analysis_method = _explicit_lumped_mass;
+
+  this->testModeI();
+
+  this->checkInsertion();
+
+  auto & mat_co = this->model->getMaterial("insertion");
+  Real G_c = mat_co.get("G_c");
+
+  this->checkDissipated(G_c);
+}
+
+TYPED_TEST(TestSMMCFixture, ExtrinsicModeII) {
+  getStaticParser().parse("material_0.dat");
+  this->is_extrinsic = true;
+  this->analysis_method = _explicit_lumped_mass;
+
+  this->testModeII();
+
+  this->checkInsertion();
+
+  auto & mat_co = this->model->getMaterial("insertion");
+  Real G_c = mat_co.get("G_c");
+
+  this->checkDissipated(G_c);
+}
+
+TYPED_TEST(TestSMMCFixture, IntrinsicModeI) {
+  getStaticParser().parse("material_1.dat");
+  this->is_extrinsic = false;
+  this->analysis_method = _explicit_lumped_mass;
 
-    this->model->solveStep();
-  }
+  this->testModeI();
 
-  auto nb_cohesive_element = this->mesh->getNbElement(TestFixture::cohesive_type);
-  auto & mesh_facets = this->mesh->getMeshFacets();
-  auto facet_type = mesh_facets.getFacetType(this->cohesive_type);
-  const auto & group = mesh_facets.getElementGroup("insertion").getElements(facet_type);
+  this->checkInsertion();
 
-  std::cout << nb_cohesive_element << " " << group.size() << std::endl;
+  auto & mat_co = this->model->getMaterial("insertion");
+  Real G_c = mat_co.get("G_c");
 
-  Real sigma = this->model->getMaterial("insertion").get("sigma_c");
-  Real edis = this->model->getEnergy("dissipated");
-  EXPECT_NEAR(this->surface * sigma, edis, 1e-8);
+  this->checkDissipated(G_c);
 }
 
-TYPED_TEST(TestSMMCFixture, ModeII) {
-  auto max_steps = 100;
-  auto disp_inc = 0.1;
-  for(auto _ [[gnu::unused]] : arange(max_steps)) {
-    this->model->applyBC(BC::Dirichlet::IncrementValue(disp_inc, _y ), "loading");
-    if(this->is_extrinsic)
-      this->model->checkCohesiveStress();
+TYPED_TEST(TestSMMCFixture, IntrinsicModeII) {
+  getStaticParser().parse("material_1.dat");
+  this->is_extrinsic = false;
+  this->analysis_method = _explicit_lumped_mass;
 
-    this->model->solveStep();
-  }
+  this->testModeII();
 
-  auto nb_cohesive_element = this->mesh->getNbElement(TestFixture::cohesive_type);
-  auto & mesh_facets = this->mesh->getMeshFacets();
-  auto facet_type = mesh_facets.getFacetType(this->cohesive_type);
-  const auto & group = mesh_facets.getElementGroup("insertion").getElements(facet_type);
+  this->checkInsertion();
 
-  std::cout << nb_cohesive_element << " " << group.size() << std::endl;
+  auto & mat_co = this->model->getMaterial("insertion");
+  Real G_c = mat_co.get("G_c");
 
-  Real sigma = this->model->getMaterial("insertion").get("sigma_c");
-  Real edis = this->model->getEnergy("dissipated");
-  EXPECT_NEAR(this->surface * sigma, edis, 1e-8);
+  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 7888df67b..9d97a7293 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
@@ -1,78 +1,274 @@
 /* -------------------------------------------------------------------------- */
+#include "communicator.hh"
 #include "solid_mechanics_model_cohesive.hh"
 #include "test_gtest_utils.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <vector>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_TEST_COHESIVE_FIXTURE_HH__
 #define __AKANTU_TEST_COHESIVE_FIXTURE_HH__
 
 using namespace akantu;
 
+template <::akantu::AnalysisMethod t>
+using analysis_method_t = std::integral_constant<::akantu::AnalysisMethod, t>;
+
 template <typename param_> class TestSMMCFixture : public ::testing::Test {
 public:
   static constexpr ElementType cohesive_type =
       std::tuple_element_t<0, param_>::value;
+  static constexpr ElementType type_1 = std::tuple_element_t<1, param_>::value;
+  static constexpr ElementType type_2 = std::tuple_element_t<2, param_>::value;
+
   static constexpr size_t dim =
       ElementClass<cohesive_type>::getSpatialDimension();
-  static constexpr bool is_extrinsic = std::tuple_element_t<1, param_>::value;
 
   void SetUp() override {
-    getStaticParser().parse(this->input_file);
+    normal = Vector<Real>(this->dim, 0.);
+    if (dim == 1)
+      normal(_x) = 1.;
+    else
+      normal(_y) = 1.;
 
     mesh = std::make_unique<Mesh>(this->dim);
-    EXPECT_NO_THROW({ mesh->read(this->mesh_name); });
+    if (Communicator::getStaticCommunicator().whoAmI() == 0) {
+      EXPECT_NO_THROW({ mesh->read(this->mesh_name); });
+    }
+    mesh->distribute();
+  }
+
+  void TearDown() override {
+    model.reset(nullptr);
+    mesh.reset(nullptr);
+  }
 
+  void createModel() {
     model = std::make_unique<SolidMechanicsModelCohesive>(*mesh);
     model->initFull(_analysis_method = this->analysis_method,
                     _is_extrinsic = this->is_extrinsic);
 
-    model->applyBC(BC::Dirichlet::FlagOnly(_x), "fixed");
-    if (this->dim > 1)
-      model->applyBC(BC::Dirichlet::FlagOnly(_y), "fixed");
-    if (this->dim > 2)
-      model->applyBC(BC::Dirichlet::FlagOnly(_z), "fixed");
+    //    auto stable_time_step = this->model->getStableTimeStep();
+    this->model->setTimeStep(4e-6);
+
+    //  std::cout << stable_time_step *0.0 << std::endl;
+    if (dim == 1) {
+      surface = 1;
+      return;
+    }
+
+    auto facet_type = mesh->getFacetType(this->cohesive_type);
 
-    auto & fe_engine = model->getFEEngine("FacetsFEEngine");
-    auto & mesh_facets = fe_engine.getMesh();
-    auto facet_type = mesh_facets.getFacetType(this->cohesive_type);
-    auto & group =
-        mesh_facets.getElementGroup("insertion").getElements(facet_type);
+    auto & fe_engine = model->getFEEngineBoundary();
+    auto & group = mesh->getElementGroup("insertion").getElements(facet_type);
     Array<Real> ones(fe_engine.getNbIntegrationPoints(facet_type) *
                      group.size());
     ones.set(1.);
 
     surface = fe_engine.integrate(ones, facet_type, _not_ghost, group);
+    mesh->getCommunicator().allReduce(surface, SynchronizerOperation::_sum);
   }
 
-  void TearDown() override {
-    model.reset(nullptr);
-    mesh.reset(nullptr);
+  void setInitialCondition(const Vector<Real> & direction, Real strain) {
+    auto lower = this->mesh->getLowerBounds().dot(normal);
+    auto upper = this->mesh->getUpperBounds().dot(normal);
+
+    Real L = upper - lower;
+
+    for (auto && data :
+         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);
+
+      auto x = pos.dot(normal) - (upper + lower) / 2.;
+      disp = direction * (x * 2. * strain / L);
+    }
+  }
+
+#define debug 1
+
+  void steps(const Vector<Real> & displacement_max) {
+#if debug
+    this->model->addDumpFieldVector("displacement");
+    this->model->addDumpFieldVector("velocity");
+    this->model->addDumpField("stress");
+    this->model->addDumpField("strain");
+    this->model->assembleInternalForces();
+    this->model->setBaseNameToDumper("cohesive elements", "cohesive_elements");
+    this->model->addDumpFieldVectorToDumper("cohesive elements",
+                                            "displacement");
+    this->model->addDumpFieldToDumper("cohesive elements", "damage");
+    this->model->addDumpFieldToDumper("cohesive elements", "tractions");
+    this->model->addDumpFieldToDumper("cohesive elements", "opening");
+    this->model->dump();
+    this->model->dump("cohesive elements");
+#endif
+    auto inc_load = BC::Dirichlet::Increment(displacement_max / Real(nb_steps));
+    auto inc_fix =
+        BC::Dirichlet::Increment(-1. / Real(nb_steps) * displacement_max);
+
+    for (auto _[[gnu::unused]] : arange(nb_steps)) {
+      this->model->applyBC(inc_load, "loading");
+      this->model->applyBC(inc_fix, "fixed");
+      if (this->is_extrinsic)
+        this->model->checkCohesiveStress();
+
+      this->model->solveStep();
+#if debug
+      this->model->dump();
+      this->model->dump("cohesive elements");
+#endif
+    }
+  }
+  void checkInsertion() {
+    auto nb_cohesive_element = this->mesh->getNbElement(cohesive_type);
+    mesh->getCommunicator().allReduce(nb_cohesive_element,
+                                      SynchronizerOperation::_sum);
+
+    auto facet_type = this->mesh->getFacetType(this->cohesive_type);
+    const auto & group =
+        this->mesh->getElementGroup("insertion").getElements(facet_type);
+    auto group_size = group.size();
+    mesh->getCommunicator().allReduce(group_size, SynchronizerOperation::_sum);
+
+    EXPECT_EQ(nb_cohesive_element, group_size);
+  }
+
+  void checkDissipated(Real expected_density) {
+    Real edis = this->model->getEnergy("dissipated");
+
+    EXPECT_NEAR(this->surface * expected_density, edis, 4e-1);
+  }
+
+  void testModeI() {
+    Vector<Real> direction(this->dim, 0.);
+    if (dim == 1)
+      direction(_x) = 1.;
+    else
+      direction(_y) = 1.;
+
+    //  EXPECT_NO_THROW(this->createModel());
+    this->createModel();
+
+    if (this->dim > 1)
+      this->model->applyBC(BC::Dirichlet::FlagOnly(_x), "sides");
+    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");
+    Real G_c = mat_co.get("G_c");
+
+    auto & mat_el = this->model->getMaterial("body");
+    Real E = mat_el.get("E");
+    Real nu = mat_el.get("nu");
+
+    auto delta_c = 2. * G_c / sigma_c;
+    Real strain = sigma_c / E;
+
+    if (dim == 1)
+      strain *= .9999;
+    else
+      strain *= .935; // there must be an error in my computations
+
+    if (this->dim == 2)
+      strain *= (1. - nu) * (1. + nu);
+
+    auto max_travel = .5 * delta_c;
+    this->setInitialCondition(direction, strain);
+    this->steps(direction * max_travel);
+  }
+
+  void testModeII() {
+    Vector<Real> direction(this->dim, 0.);
+    direction(_x) = 1.;
+
+    EXPECT_NO_THROW(this->createModel());
+
+    if (this->dim > 1)
+      this->model->applyBC(BC::Dirichlet::FlagOnly(_y), "sides");
+    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");
+    Real G_c = mat_co.get("G_c");
+    Real beta = mat_co.get("beta");
+
+    auto & mat_el = this->model->getMaterial("body");
+    Real E = mat_el.get("E");
+    Real nu = mat_el.get("nu");
+
+    auto L = this->mesh->getUpperBounds().dot(direction) -
+             this->mesh->getLowerBounds().dot(direction);
+
+    auto delta_c = 2. * G_c / sigma_c;
+    Real strain = .99999 * L * beta * beta * sigma_c / E;
+    if (this->dim > 1) {
+      strain *= (1. + nu);
+    }
+    auto max_travel = 1.2 * delta_c;
+    this->setInitialCondition(direction, strain);
+    this->steps(direction * max_travel);
   }
 
 protected:
   std::unique_ptr<Mesh> mesh;
   std::unique_ptr<SolidMechanicsModelCohesive> model;
-  AnalysisMethod analysis_method{_explicit_lumped_mass};
-  std::string mesh_name{aka::to_string(cohesive_type) + ".msh"};
-  std::string input_file{"material.dat"};
 
+  std::string mesh_name{aka::to_string(cohesive_type) + aka::to_string(type_1) +
+                        (type_1 == type_2 ? "" : aka::to_string(type_2)) +
+                        ".msh"};
+
+  bool is_extrinsic;
+  AnalysisMethod analysis_method;
+
+  Vector<Real> normal;
   Real surface{0};
+  UInt nb_steps{300};
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename param_>
 constexpr ElementType TestSMMCFixture<param_>::cohesive_type;
+template <typename param_>
+constexpr ElementType TestSMMCFixture<param_>::type_1;
+template <typename param_>
+constexpr ElementType TestSMMCFixture<param_>::type_2;
+
 template <typename param_> constexpr size_t TestSMMCFixture<param_>::dim;
-template <typename param_> constexpr bool TestSMMCFixture<param_>::is_extrinsic;
 /* -------------------------------------------------------------------------- */
 
 using IsExtrinsicTypes = std::tuple<std::true_type, std::false_type>;
-using types =
-    gtest_list_t<cross_product_t<TestCohesiveElementTypes, IsExtrinsicTypes>>;
+using AnalysisMethodTypes =
+    std::tuple<analysis_method_t<_explicit_lumped_mass>>;
+
+using types = gtest_list_t<std::tuple<
+    std::tuple<element_type_t<_cohesive_1d_2>, element_type_t<_segment_2>,
+               element_type_t<_segment_2>>,
+    std::tuple<element_type_t<_cohesive_2d_4>, element_type_t<_triangle_3>,
+               element_type_t<_triangle_3>>,
+    std::tuple<element_type_t<_cohesive_2d_4>, element_type_t<_quadrangle_4>,
+               element_type_t<_quadrangle_4>>,
+    std::tuple<element_type_t<_cohesive_2d_4>, element_type_t<_triangle_3>,
+               element_type_t<_quadrangle_4>>,
+    std::tuple<element_type_t<_cohesive_2d_6>, element_type_t<_triangle_6>,
+               element_type_t<_triangle_6>>,
+    std::tuple<element_type_t<_cohesive_2d_6>, element_type_t<_quadrangle_8>,
+               element_type_t<_quadrangle_8>>,
+    std::tuple<element_type_t<_cohesive_2d_6>, element_type_t<_triangle_6>,
+               element_type_t<_quadrangle_8>>,
+    std::tuple<element_type_t<_cohesive_3d_6>, element_type_t<_tetrahedron_4>,
+               element_type_t<_tetrahedron_4>>,
+    std::tuple<element_type_t<_cohesive_3d_12>, element_type_t<_tetrahedron_10>,
+               element_type_t<_tetrahedron_10>>,
+    std::tuple<element_type_t<_cohesive_3d_8>, element_type_t<_hexahedron_8>,
+               element_type_t<_hexahedron_8>>,
+    std::tuple<element_type_t<_cohesive_3d_16>, element_type_t<_hexahedron_20>,
+               element_type_t<_hexahedron_20>>>>;
 
 TYPED_TEST_CASE(TestSMMCFixture, types);
 
 #endif /* __AKANTU_TEST_COHESIVE_FIXTURE_HH__ */
diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc
index 6ad371486..be0eeabd1 100644
--- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc
+++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_element_matrix.cc
@@ -1,87 +1,96 @@
 /**
  * @file   test_embedded_element_matrix.cc
  *
  * @author Lucas Frerot <lucas.frerot@epfl.ch>
  *
  * @date creation: Wed Mar 25 2015
  * @date last modification: Wed May 13 2015
  *
  * @brief  test of the class EmbeddedInterfaceModel
  *
  * @section LICENSE
  *
  * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
  * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 #include "embedded_interface_model.hh"
+#include "sparse_solver.hh"
 #include "sparse_matrix_aij.hh"
 
 using namespace akantu;
 
 int main(int argc, char * argv[]) {
   debug::setDebugLevel(dblWarning);
   initialize("embedded_element.dat", argc, argv);
 
   constexpr UInt dim = 2;
   constexpr ElementType type = _segment_2;
-  const Real height = 0.5;
+  const Real height = 0.4;
 
   Mesh mesh(dim);
   mesh.read("triangle.msh");
 
   Mesh reinforcement_mesh(dim, "reinforcement_mesh");
   auto & nodes = reinforcement_mesh.getNodes();
   nodes.push_back(Vector<Real>({0, height}));
   nodes.push_back(Vector<Real>({1, height}));
 
   reinforcement_mesh.addConnectivityType(type);
   auto & connectivity = reinforcement_mesh.getConnectivity(type);
   connectivity.push_back(Vector<UInt>({0, 1}));
 
   Array<std::string> names_vec(1, 1, "reinforcement", "reinforcement_names");
   reinforcement_mesh.registerData<std::string>("physical_names").alloc(1, 1, type);
   reinforcement_mesh.getData<std::string>("physical_names")(type).copy(names_vec);
 
   EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim);
 
   model.initFull(_analysis_method = _static);
 
   if (model.getInterfaceMesh().getNbElement(type) != 1)
     return EXIT_FAILURE;
 
   if (model.getInterfaceMesh().getSpatialDimension() != 2)
     return EXIT_FAILURE;
 
-  model.assembleStiffnessMatrix();
+  try { // matrix should be singular
+    model.solveStep();
+  } catch (debug::SingularMatrixException & e) {
+    std::cerr << "Matrix is singular, relax, everything is fine :)" << std::endl;
+  } catch (debug::Exception & e) {
+    std::cerr << "Unexpceted error: " << e.what() << std::endl;
+    throw e;
+  }
 
   SparseMatrixAIJ & K =
       dynamic_cast<SparseMatrixAIJ &>(model.getDOFManager().getMatrix("K"));
+  K.saveMatrix("stiffness.mtx");
 
   Math::setTolerance(1e-8);
 
   // Testing the assembled stiffness matrix
   if (!Math::are_float_equal(K(0, 0), 1. - height) ||
       !Math::are_float_equal(K(0, 2), height - 1.) ||
       !Math::are_float_equal(K(2, 0), height - 1.) ||
       !Math::are_float_equal(K(2, 2), 1. - height))
     return EXIT_FAILURE;
 
   return EXIT_SUCCESS;
 }
diff --git a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc
index 76a80f295..116108dc1 100644
--- a/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc
+++ b/test/test_model/test_solid_mechanics_model/test_embedded_interface/test_embedded_interface_model_prestress.cc
@@ -1,222 +1,224 @@
 /**
  * @file   test_embedded_interface_model_prestress.cc
  *
  * @author Lucas Frerot <lucas.frerot@epfl.ch>
  *
  * @date creation: Tue Apr 28 2015
  * @date last modification: Thu Oct 15 2015
  *
  * @brief  Embedded model test for prestressing (bases on stress norm)
  *
  * @section LICENSE
  *
  * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
  * (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 #include "aka_common.hh"
 #include "embedded_interface_model.hh"
 
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 #define YG 0.483644859
 #define I_eq 0.012488874
 #define A_eq (1e-2 + 1. / 7. * 1.)
 
 /* -------------------------------------------------------------------------- */
 
 struct StressSolution : public BC::Neumann::FromHigherDim {
   Real M;
   Real I;
   Real yg;
   Real pre_stress;
 
   StressSolution(UInt dim, Real M, Real I, Real yg = 0, Real pre_stress = 0) :
     BC::Neumann::FromHigherDim(Matrix<Real>(dim, dim)),
     M(M), I(I), yg(yg), pre_stress(pre_stress)
   {}
 
   virtual ~StressSolution() {}
 
   void operator()(const IntegrationPoint & /*quad_point*/, Vector<Real> & dual,
                   const Vector<Real> & coord,
                   const Vector<Real> & normals) const {
     UInt dim = coord.size();
 
     if (dim < 2) AKANTU_DEBUG_ERROR("Solution not valid for 1D");
 
     Matrix<Real> stress(dim, dim); stress.clear();
     stress(0, 0) = this->stress(coord(1));
     dual.mul<false>(stress, normals);
   }
 
   inline Real stress(Real height) const {
     return -M / I * (height - yg) + pre_stress;
   }
 
   inline Real neutral_axis() const {
     return -I * pre_stress / M + yg;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 
 int main (int argc, char * argv[]) {
   initialize("prestress.dat", argc, argv);
   debug::setDebugLevel(dblError);
 
   Math::setTolerance(1e-6);
 
   const UInt dim = 2;
 
 /* -------------------------------------------------------------------------- */
 
   Mesh mesh(dim);
   mesh.read("embedded_mesh_prestress.msh");
-  mesh.createGroupsFromMeshData<std::string>("physical_names");
+  // mesh.createGroupsFromMeshData<std::string>("physical_names");
 
   Mesh reinforcement_mesh(dim, "reinforcement_mesh");
   try {
     reinforcement_mesh.read("embedded_mesh_prestress_reinforcement.msh");
   } catch(debug::Exception & e) {}
 
-  reinforcement_mesh.createGroupsFromMeshData<std::string>("physical_names");
+  // reinforcement_mesh.createGroupsFromMeshData<std::string>("physical_names");
 
   EmbeddedInterfaceModel model(mesh, reinforcement_mesh, dim);
   model.initFull(EmbeddedInterfaceModelOptions(_static));
 
 /* -------------------------------------------------------------------------- */
 /* Computation of analytical residual                                         */
 /* -------------------------------------------------------------------------- */
 
   /*
    * q = 1000 N/m
    * L = 20 m
    * a = 1 m
    */
 
-  Real steel_area =
-      model.getMaterial("reinforcement").get("area");
-  Real pre_stress = 1e6;
+  Real steel_area = model.getMaterial("reinforcement").get("area");
+  Real pre_stress = model.getMaterial("reinforcement").get("pre_stress");
   Real stress_norm = 0.;
 
-  StressSolution * concrete_stress = NULL, * steel_stress = NULL;
+  StressSolution * concrete_stress = nullptr, * steel_stress = nullptr;
 
   Real pre_force = pre_stress * steel_area;
   Real pre_moment = -pre_force * (YG - 0.25);
   Real neutral_axis = YG - I_eq / A_eq * pre_force / pre_moment;
 
   concrete_stress = new StressSolution(dim, pre_moment, 7. * I_eq, YG, -pre_force / (7. * A_eq));
   steel_stress = new StressSolution(dim, pre_moment, I_eq, YG, pre_stress - pre_force / A_eq);
 
   stress_norm = std::abs(concrete_stress->stress(1)) * (1 - neutral_axis) * 0.5
     + std::abs(concrete_stress->stress(0)) * neutral_axis * 0.5
     + std::abs(steel_stress->stress(0.25)) * steel_area;
 
   model.applyBC(*concrete_stress, "XBlocked");
-  ElementGroup & end_node = mesh.getElementGroup("EndNode");
-  NodeGroup & end_node_group = end_node.getNodeGroup();
-  NodeGroup::const_node_iterator end_node_it = end_node_group.begin();
+  auto end_node = *mesh.getElementGroup("EndNode").getNodeGroup().begin();
 
-  Vector<Real> end_node_force = model.getForce().begin(dim)[*end_node_it];
+  Vector<Real> end_node_force = model.getForce().begin(dim)[end_node];
   end_node_force(0) += steel_stress->stress(0.25) * steel_area; 
 
   Array<Real> analytical_residual(mesh.getNbNodes(), dim, "analytical_residual");
   analytical_residual.copy(model.getForce());
   model.getForce().clear();
 
   delete concrete_stress;
   delete steel_stress;
 
 /* -------------------------------------------------------------------------- */
 
   model.applyBC(BC::Dirichlet::FixedValue(0.0, _x), "XBlocked");
   model.applyBC(BC::Dirichlet::FixedValue(0.0, _y), "YBlocked");
 
   try {
     model.solveStep();
   } catch (debug::Exception e) {
     std::cerr << e.what() << std::endl;
     return EXIT_FAILURE;
   }
 
 /* -------------------------------------------------------------------------- */
 /* Computation of FEM residual norm                                           */
 /* -------------------------------------------------------------------------- */
 
   ElementGroup & xblocked = mesh.getElementGroup("XBlocked");
   NodeGroup & boundary_nodes = xblocked.getNodeGroup();
   NodeGroup::const_node_iterator
     nodes_it = boundary_nodes.begin(),
     nodes_end = boundary_nodes.end();
-  Array<Real>::vector_iterator com_res = model.getInternalForce().begin(dim);
-  Array<Real>::vector_iterator ana_res = analytical_residual.begin(dim);
+  model.assembleInternalForces();
+  Array<Real> residual(mesh.getNbNodes(), dim, "my_residual");
+  residual.copy(model.getInternalForce());
+  residual -= model.getForce();
+
+  Array<Real>::vector_iterator com_res = residual.begin(dim);
   Array<Real>::vector_iterator position = mesh.getNodes().begin(dim);
 
   Real res_sum = 0.;
   UInt lower_node = -1;
   UInt upper_node = -1;
   Real lower_dist = 1;
   Real upper_dist = 1;
 
   for (; nodes_it != nodes_end ; ++nodes_it) {
     UInt node_number = *nodes_it;
     const Vector<Real> res = com_res[node_number];
-    const Vector<Real> ana = ana_res[node_number];
     const Vector<Real> pos = position[node_number];
 
     if (!Math::are_float_equal(pos(1), 0.25)) {
       if ((std::abs(pos(1) - 0.25) < lower_dist) && (pos(1) < 0.25)) {
         lower_dist = std::abs(pos(1) - 0.25);
         lower_node = node_number;
       }
 
       if ((std::abs(pos(1) - 0.25) < upper_dist) && (pos(1) > 0.25)) {
         upper_dist = std::abs(pos(1) - 0.25);
         upper_node = node_number;
       }
     }
 
     for (UInt i = 0 ; i < dim ; i++) {
       if (!Math::are_float_equal(pos(1), 0.25)) {
         res_sum += std::abs(res(i));
       }
     }
   }
 
   const Vector<Real> upper_res = com_res[upper_node], lower_res = com_res[lower_node];
-  const Vector<Real> end_node_res = com_res[*end_node_it];
+  const Vector<Real> end_node_res = com_res[end_node];
   Vector<Real> delta = upper_res - lower_res;
   delta *= lower_dist / (upper_dist + lower_dist);
   Vector<Real> concrete_residual = lower_res + delta;
   Vector<Real> steel_residual = end_node_res - concrete_residual;
 
   for (UInt i = 0 ; i < dim ; i++) {
     res_sum += std::abs(concrete_residual(i));
     res_sum += std::abs(steel_residual(i));
   }
 
   Real relative_error = std::abs(res_sum - stress_norm) / stress_norm;
 
-  if (relative_error > 1e-3)
+  if (relative_error > 1e-3) {
+    std::cerr << "Relative error = " << relative_error << std::endl;
     return EXIT_FAILURE;
+  }
 
   finalize();
   return 0;
 }
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc
index ed8a61267..24445e0f4 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_damage_materials.cc
@@ -1,48 +1,43 @@
 /* -------------------------------------------------------------------------- */
 #include "material_marigo.hh"
 #include "material_mazars.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types = ::testing::Types<
 
     Traits<MaterialMarigo, 1>, Traits<MaterialMarigo, 2>,
     Traits<MaterialMarigo, 3>,
 
     Traits<MaterialMazars, 1>, Traits<MaterialMazars, 2>,
     Traits<MaterialMazars, 3>>;
 
-
 /*****************************************************************/
 
 namespace {
 
 template <typename T>
 class TestDamageMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestDamageMaterialFixture, types);
 
 TYPED_TEST(TestDamageMaterialFixture, DamageComputeStress) {
   this->material->testComputeStress();
 }
 TYPED_TEST(TestDamageMaterialFixture, DamageEnergyDensity) {
   this->material->testEnergyDensity();
 }
 TYPED_TEST(TestDamageMaterialFixture, DamageComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
 
-TYPED_TEST(TestDamageMaterialFixture, DamageComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
-}
-
-TYPED_TEST(TestDamageMaterialFixture, DamageComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
+TYPED_TEST(TestDamageMaterialFixture, DamageComputeCelerity) {
+  this->material->testCelerity();
 }
 }
 /*****************************************************************/
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc
index 98b0cb329..f89fcb12d 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_elastic_materials.cc
@@ -1,313 +1,1074 @@
 /* -------------------------------------------------------------------------- */
 #include "material_elastic.hh"
 #include "material_elastic_orthotropic.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types =
     ::testing::Types<Traits<MaterialElastic, 1>, Traits<MaterialElastic, 2>,
                      Traits<MaterialElastic, 3>,
 
-                     Traits<MaterialElasticOrthotropic, 1>,
                      Traits<MaterialElasticOrthotropic, 2>,
                      Traits<MaterialElasticOrthotropic, 3>,
 
-                     Traits<MaterialElasticLinearAnisotropic, 1>,
                      Traits<MaterialElasticLinearAnisotropic, 2>,
                      Traits<MaterialElasticLinearAnisotropic, 3>>;
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<3>>::testPushWaveSpeed() {
+template <> void FriendMaterial<MaterialElastic<1>>::testComputeStress() {
+  Real E = 3.;
+  setParam("E", E);
+
+  Matrix<Real> eps = {{2}};
+  Matrix<Real> sigma(1, 1);
+  Real sigma_th = 2;
+  this->computeStressOnQuad(eps, sigma, sigma_th);
+
+  auto solution = E * eps(0, 0) + sigma_th;
+  ASSERT_NEAR(sigma(0, 0), solution, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <> void FriendMaterial<MaterialElastic<1>>::testEnergyDensity() {
+  Real eps = 2, sigma = 2;
+  Real epot = 0;
+  this->computePotentialEnergyOnQuad({{eps}}, {{sigma}}, epot);
+  Real solution = 2;
+  ASSERT_NEAR(epot, solution, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElastic<1>>::testComputeTangentModuli() {
+  Real E = 2;
+  setParam("E", E);
+  Matrix<Real> tangent(1, 1);
+  this->computeTangentModuliOnQuad(tangent);
+  ASSERT_NEAR(tangent(0, 0), E, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <> void FriendMaterial<MaterialElastic<1>>::testCelerity() {
+  Real E = 3., rho = 2.;
+  setParam("E", E);
+  setParam("rho", rho);
+
+  auto wave_speed = this->getCelerity(Element());
+  auto solution = std::sqrt(E / rho);
+  ASSERT_NEAR(wave_speed, solution, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <> void FriendMaterial<MaterialElastic<2>>::testComputeStress() {
   Real E = 1.;
   Real nu = .3;
-  Real rho = 2;
+  Real sigma_th = 0.3; // thermal stress
   setParam("E", E);
   setParam("nu", nu);
-  setParam("rho", rho);
-  auto wave_speed = this->getPushWaveSpeed(Element());
 
-  Real K = E / (3 * (1 - 2 * nu));
-  Real mu = E / (2 * (1 + nu));
-  Real sol = std::sqrt((K + 4. / 3 * mu) / rho);
+  Real bulk_modulus_K = E / 3. / (1 - 2. * nu);
+  Real shear_modulus_mu = 0.5 * E / (1 + nu);
+
+  Matrix<Real> rotation_matrix = getRandomRotation2d();
+
+  auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2);
+
+  auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
+
+  Matrix<Real> sigma_rot(2, 2);
+  this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th);
+
+  auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
+
+  Matrix<Real> identity(2, 2);
+  identity.eye();
+
+  Matrix<Real> strain = 0.5 * (grad_u + grad_u.transpose());
+  Matrix<Real> deviatoric_strain = strain - 1. / 3. * strain.trace() * identity;
+
+  Matrix<Real> sigma_expected = 2 * shear_modulus_mu * deviatoric_strain +
+                                (sigma_th + 2. * bulk_modulus_K) * identity;
+
+  auto diff = sigma - sigma_expected;
+  Real stress_error = diff.norm<L_inf>();
+  ASSERT_NEAR(stress_error, 0., 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <> void FriendMaterial<MaterialElastic<2>>::testEnergyDensity() {
+  Matrix<Real> sigma = {{1, 2}, {2, 4}};
+  Matrix<Real> eps = {{1, 0}, {0, 1}};
+  Real epot = 0;
+  Real solution = 2.5;
+  this->computePotentialEnergyOnQuad(eps, sigma, epot);
+  ASSERT_NEAR(epot, solution, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElastic<2>>::testComputeTangentModuli() {
+  Real E = 1.;
+  Real nu = .3;
+  setParam("E", E);
+  setParam("nu", nu);
+  Matrix<Real> tangent(3, 3);
+
+  /* Plane Strain */
+  // clang-format off
+  Matrix<Real> solution = {
+    {1 - nu, nu, 0},
+    {nu, 1 - nu, 0},
+    {0, 0, (1 - 2 * nu) / 2},
+  };
+  // clang-format on
+  solution *= E / ((1 + nu) * (1 - 2 * nu));
+
+  this->computeTangentModuliOnQuad(tangent);
+  Real tangent_error = (tangent - solution).norm<L_2>();
+  ASSERT_NEAR(tangent_error, 0, 1e-14);
+
+  /* Plane Stress */
+  this->plane_stress = true;
+  this->updateInternalParameters();
+  // clang-format off
+  solution = {
+    {1, nu, 0},
+    {nu, 1, 0},
+    {0, 0, (1 - nu) / 2},
+  };
+  // clang-format on
+  solution *= E / (1 - nu * nu);
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
+  this->computeTangentModuliOnQuad(tangent);
+  tangent_error = (tangent - solution).norm<L_2>();
+  ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<3>>::testShearWaveSpeed() {
+template <> void FriendMaterial<MaterialElastic<2>>::testCelerity() {
   Real E = 1.;
   Real nu = .3;
   Real rho = 2;
   setParam("E", E);
   setParam("nu", nu);
   setParam("rho", rho);
-  auto wave_speed = this->getShearWaveSpeed(Element());
+  auto push_wave_speed = this->getPushWaveSpeed(Element());
+  auto celerity = this->getCelerity(Element());
 
+  Real K = E / (3 * (1 - 2 * nu));
   Real mu = E / (2 * (1 + nu));
-  Real sol = std::sqrt(mu / rho);
+  Real sol = std::sqrt((K + 4. / 3 * mu) / rho);
+
+  ASSERT_NEAR(push_wave_speed, sol, 1e-14);
+  ASSERT_NEAR(celerity, sol, 1e-14);
+
+  auto shear_wave_speed = this->getShearWaveSpeed(Element());
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
+  sol = std::sqrt(mu / rho);
+
+  ASSERT_NEAR(shear_wave_speed, sol, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
+
 template <> void FriendMaterial<MaterialElastic<3>>::testComputeStress() {
   Real E = 1.;
   Real nu = .3;
   Real sigma_th = 0.3; // thermal stress
   setParam("E", E);
   setParam("nu", nu);
 
+  Real bulk_modulus_K = E / 3. / (1 - 2. * nu);
+  Real shear_modulus_mu = 0.5 * E / (1 + nu);
+
   Matrix<Real> rotation_matrix = getRandomRotation3d();
 
-  auto grad_u = this->getDeviatoricStrain(1.);
+  auto grad_u = this->getComposedStrain(1.);
 
   auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
 
   Matrix<Real> sigma_rot(3, 3);
   this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th);
 
   auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
 
   Matrix<Real> identity(3, 3);
   identity.eye();
 
-  Matrix<Real> sigma_expected =
-      0.5 * E / (1 + nu) * (grad_u + grad_u.transpose()) + sigma_th * identity;
+  Matrix<Real> strain = 0.5 * (grad_u + grad_u.transpose());
+  Matrix<Real> deviatoric_strain = strain - 1. / 3. * strain.trace() * identity;
+
+  Matrix<Real> sigma_expected = 2 * shear_modulus_mu * deviatoric_strain +
+                                (sigma_th + 3. * bulk_modulus_K) * identity;
 
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
   ASSERT_NEAR(stress_error, 0., 1e-14);
 }
 
+/* -------------------------------------------------------------------------- */
+template <> void FriendMaterial<MaterialElastic<3>>::testEnergyDensity() {
+  Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}};
+  Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+  Real epot = 0;
+  Real solution = 5.5;
+  this->computePotentialEnergyOnQuad(eps, sigma, epot);
+  ASSERT_NEAR(epot, solution, 1e-14);
+}
+
 /* -------------------------------------------------------------------------- */
 template <>
 void FriendMaterial<MaterialElastic<3>>::testComputeTangentModuli() {
   Real E = 1.;
   Real nu = .3;
   setParam("E", E);
   setParam("nu", nu);
   Matrix<Real> tangent(6, 6);
 
   // clang-format off
   Matrix<Real> solution = {
       {1 - nu, nu, nu, 0, 0, 0},
       {nu, 1 - nu, nu, 0, 0, 0},
       {nu, nu, 1 - nu, 0, 0, 0},
       {0, 0, 0, (1 - 2 * nu) / 2, 0, 0},
       {0, 0, 0, 0, (1 - 2 * nu) / 2, 0},
       {0, 0, 0, 0, 0, (1 - 2 * nu) / 2},
   };
   // clang-format on
   solution *= E / ((1 + nu) * (1 - 2 * nu));
 
   this->computeTangentModuliOnQuad(tangent);
   Real tangent_error = (tangent - solution).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<3>>::testEnergyDensity() {
-  Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}};
-  Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
-  Real epot = 0;
-  Real solution = 5.5;
-  this->computePotentialEnergyOnQuad(eps, sigma, epot);
-  ASSERT_NEAR(epot, solution, 1e-14);
+template <> void FriendMaterial<MaterialElastic<3>>::testCelerity() {
+  Real E = 1.;
+  Real nu = .3;
+  Real rho = 2;
+  setParam("E", E);
+  setParam("nu", nu);
+  setParam("rho", rho);
+
+  auto push_wave_speed = this->getPushWaveSpeed(Element());
+  auto celerity = this->getCelerity(Element());
+
+  Real K = E / (3 * (1 - 2 * nu));
+  Real mu = E / (2 * (1 + nu));
+  Real sol = std::sqrt((K + 4. / 3 * mu) / rho);
+
+  ASSERT_NEAR(push_wave_speed, sol, 1e-14);
+  ASSERT_NEAR(celerity, sol, 1e-14);
+
+  auto shear_wave_speed = this->getShearWaveSpeed(Element());
+
+  sol = std::sqrt(mu / rho);
+
+  ASSERT_NEAR(shear_wave_speed, sol, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<1>>::testComputeStress() {
-  Real E = 3.;
-  setParam("E", E);
+template <>
+void FriendMaterial<MaterialElasticOrthotropic<2>>::testComputeStress() {
+  UInt Dim = 2;
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real nu12 = 0.1;
+  Real G12 = 2.;
 
-  Matrix<Real> eps = {{2}};
-  Matrix<Real> sigma(1, 1);
-  Real sigma_th = 2;
-  this->computeStressOnQuad(eps, sigma, sigma_th);
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("G12", G12);
 
-  auto solution = E * eps(0, 0) + sigma_th;
-  ASSERT_NEAR(sigma(0, 0), solution, 1e-14);
+  // material frame of reference is rotate by rotation_matrix starting from
+  // canonical basis
+  Matrix<Real> rotation_matrix = getRandomRotation2d();
+
+  // canonical basis as expressed in the material frame of reference, as
+  // required by MaterialElasticOrthotropic class (it is simply given by the
+  // columns of the rotation_matrix; the lines give the material basis expressed
+  // in the canonical frame of reference)
+  Vector<Real> v1(Dim);
+  Vector<Real> v2(Dim);
+  for (UInt i = 0; i < Dim; ++i) {
+    v1[i] = rotation_matrix(i, 0);
+    v2[i] = rotation_matrix(i, 1);
+  }
+
+  setParamNoUpdate("n1", v1.normalize());
+  setParamNoUpdate("n2", v2.normalize());
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // gradient in material frame of reference
+  auto grad_u = this->getComposedStrain(2.).block(0, 0, 2, 2);
+
+  // gradient in canonical basis (we need to rotate *back* to the canonical
+  // basis)
+  auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
+
+  // stress in the canonical basis
+  Matrix<Real> sigma_rot(2, 2);
+  this->computeStressOnQuad(grad_u_rot, sigma_rot);
+
+  // stress in the material reference (we need to apply the rotation)
+  auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real gamma = 1 / (1 - nu12 * nu21);
+
+  Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0);
+  C_expected(0, 0) = gamma * E1;
+  C_expected(1, 1) = gamma * E2;
+  C_expected(2, 2) = G12;
+
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21;
+
+  // epsilon is computed directly in the *material* frame of reference
+  Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
+
+  // sigma_expected is computed directly in the *material* frame of reference
+  Matrix<Real> sigma_expected(Dim, Dim);
+  for (UInt i = 0; i < Dim; ++i) {
+    for (UInt j = 0; j < Dim; ++j) {
+      sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j);
+    }
+  }
+
+  sigma_expected(0, 1) = sigma_expected(1, 0) =
+      C_expected(2, 2) * 2 * epsilon(0, 1);
+
+  // sigmas are checked in the *material* frame of reference
+  auto diff = sigma - sigma_expected;
+  Real stress_error = diff.norm<L_inf>();
+  ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<1>>::testEnergyDensity() {
-  Real eps = 2, sigma = 2;
+template <>
+void FriendMaterial<MaterialElasticOrthotropic<2>>::testEnergyDensity() {
+  Matrix<Real> sigma = {{1, 2}, {2, 4}};
+  Matrix<Real> eps = {{1, 0}, {0, 1}};
   Real epot = 0;
-  this->computePotentialEnergyOnQuad({{eps}}, {{sigma}}, epot);
-  Real solution = 2;
+  Real solution = 2.5;
+  this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
-void FriendMaterial<MaterialElastic<1>>::testComputeTangentModuli() {
-  Real E = 2;
-  setParam("E", E);
-  Matrix<Real> tangent(1, 1);
+void FriendMaterial<MaterialElasticOrthotropic<2>>::testComputeTangentModuli() {
+
+  // Note: for this test material and canonical basis coincide
+  Vector<Real> n1 = {1, 0};
+  Vector<Real> n2 = {0, 1};
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real nu12 = 0.1;
+  Real G12 = 2.;
+
+  setParamNoUpdate("n1", n1);
+  setParamNoUpdate("n2", n2);
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("G12", G12);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real gamma = 1 / (1 - nu12 * nu21);
+
+  Matrix<Real> C_expected(3, 3);
+  C_expected(0, 0) = gamma * E1;
+  C_expected(1, 1) = gamma * E2;
+  C_expected(2, 2) = G12;
+
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21;
+
+  Matrix<Real> tangent(3, 3);
   this->computeTangentModuliOnQuad(tangent);
-  ASSERT_NEAR(tangent(0, 0), E, 1e-14);
+
+  Real tangent_error = (tangent - C_expected).norm<L_2>();
+  ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<1>>::testPushWaveSpeed() {
-  Real E = 3., rho = 2.;
-  setParam("E", E);
-  setParam("rho", rho);
 
-  auto wave_speed = this->getPushWaveSpeed(Element());
-  auto solution = std::sqrt(E / rho);
-  ASSERT_NEAR(wave_speed, solution, 1e-14);
+template <> void FriendMaterial<MaterialElasticOrthotropic<2>>::testCelerity() {
+
+  // Note: for this test material and canonical basis coincide
+  Vector<Real> n1 = {1, 0};
+  Vector<Real> n2 = {0, 1};
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real nu12 = 0.1;
+  Real G12 = 2.;
+  Real rho = 2.5;
+
+  setParamNoUpdate("n1", n1);
+  setParamNoUpdate("n2", n2);
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("G12", G12);
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real gamma = 1 / (1 - nu12 * nu21);
+
+  Matrix<Real> C_expected(3, 3);
+  C_expected(0, 0) = gamma * E1;
+  C_expected(1, 1) = gamma * E2;
+  C_expected(2, 2) = G12;
+
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * nu21;
+
+  Vector<Real> eig_expected(3);
+  C_expected.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<1>>::testShearWaveSpeed() {
-  ASSERT_THROW(this->getShearWaveSpeed(Element()), debug::Exception);
+template <>
+void FriendMaterial<MaterialElasticOrthotropic<3>>::testComputeStress() {
+  UInt Dim = 3;
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real E3 = 3.;
+  Real nu12 = 0.1;
+  Real nu13 = 0.2;
+  Real nu23 = 0.3;
+  Real G12 = 2.;
+  Real G13 = 3.;
+  Real G23 = 1.;
+
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("E3", E3);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("nu13", nu13);
+  setParamNoUpdate("nu23", nu23);
+  setParamNoUpdate("G12", G12);
+  setParamNoUpdate("G13", G13);
+  setParamNoUpdate("G23", G23);
+
+  // material frame of reference is rotate by rotation_matrix starting from
+  // canonical basis
+  Matrix<Real> rotation_matrix = getRandomRotation3d();
+
+  // canonical basis as expressed in the material frame of reference, as
+  // required by MaterialElasticOrthotropic class (it is simply given by the
+  // columns of the rotation_matrix; the lines give the material basis expressed
+  // in the canonical frame of reference)
+  Vector<Real> v1(Dim);
+  Vector<Real> v2(Dim);
+  Vector<Real> v3(Dim);
+  for (UInt i = 0; i < Dim; ++i) {
+    v1[i] = rotation_matrix(i, 0);
+    v2[i] = rotation_matrix(i, 1);
+    v3[i] = rotation_matrix(i, 2);
+  }
+
+  setParamNoUpdate("n1", v1.normalize());
+  setParamNoUpdate("n2", v2.normalize());
+  setParamNoUpdate("n3", v3.normalize());
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // gradient in material frame of reference
+  auto grad_u = this->getComposedStrain(2.);
+
+  // gradient in canonical basis (we need to rotate *back* to the canonical
+  // basis)
+  auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
+
+  // stress in the canonical basis
+  Matrix<Real> sigma_rot(3, 3);
+  this->computeStressOnQuad(grad_u_rot, sigma_rot);
+
+  // stress in the material reference (we need to apply the rotation)
+  auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real nu31 = nu13 * E3 / E1;
+  Real nu32 = nu23 * E3 / E2;
+  Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 -
+                    2 * nu21 * nu32 * nu13);
+
+  Matrix<Real> C_expected(6, 6);
+  C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32);
+  C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31);
+  C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21);
+
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23);
+  C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32);
+  C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31);
+
+  C_expected(3, 3) = G23;
+  C_expected(4, 4) = G13;
+  C_expected(5, 5) = G12;
+
+  // epsilon is computed directly in the *material* frame of reference
+  Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
+
+  // sigma_expected is computed directly in the *material* frame of reference
+  Matrix<Real> sigma_expected(Dim, Dim);
+  for (UInt i = 0; i < Dim; ++i) {
+    for (UInt j = 0; j < Dim; ++j) {
+      sigma_expected(i, i) += C_expected(i, j) * epsilon(j, j);
+    }
+  }
+
+  sigma_expected(0, 1) = C_expected(5, 5) * 2 * epsilon(0, 1);
+  sigma_expected(0, 2) = C_expected(4, 4) * 2 * epsilon(0, 2);
+  sigma_expected(1, 2) = C_expected(3, 3) * 2 * epsilon(1, 2);
+  sigma_expected(1, 0) = sigma_expected(0, 1);
+  sigma_expected(2, 0) = sigma_expected(0, 2);
+  sigma_expected(2, 1) = sigma_expected(1, 2);
+
+  // sigmas are checked in the *material* frame of reference
+  auto diff = sigma - sigma_expected;
+  Real stress_error = diff.norm<L_inf>();
+  ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<2>>::testPushWaveSpeed() {
-  Real E = 1.;
-  Real nu = .3;
-  Real rho = 2;
-  setParam("E", E);
-  setParam("nu", nu);
-  setParam("rho", rho);
-  auto wave_speed = this->getPushWaveSpeed(Element());
+template <>
+void FriendMaterial<MaterialElasticOrthotropic<3>>::testEnergyDensity() {
+  Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}};
+  Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+  Real epot = 0;
+  Real solution = 5.5;
+  this->computePotentialEnergyOnQuad(eps, sigma, epot);
+  ASSERT_NEAR(epot, solution, 1e-14);
+}
 
-  Real K = E / (3 * (1 - 2 * nu));
-  Real mu = E / (2 * (1 + nu));
-  Real sol = std::sqrt((K + 4. / 3 * mu) / rho);
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElasticOrthotropic<3>>::testComputeTangentModuli() {
+
+  // Note: for this test material and canonical basis coincide
+  UInt Dim = 3;
+  Vector<Real> n1 = {1, 0, 0};
+  Vector<Real> n2 = {0, 1, 0};
+  Vector<Real> n3 = {0, 0, 1};
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real E3 = 3.;
+  Real nu12 = 0.1;
+  Real nu13 = 0.2;
+  Real nu23 = 0.3;
+  Real G12 = 2.;
+  Real G13 = 3.;
+  Real G23 = 1.;
+
+  setParamNoUpdate("n1", n1);
+  setParamNoUpdate("n2", n2);
+  setParamNoUpdate("n3", n3);
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("E3", E3);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("nu13", nu13);
+  setParamNoUpdate("nu23", nu23);
+  setParamNoUpdate("G12", G12);
+  setParamNoUpdate("G13", G13);
+  setParamNoUpdate("G23", G23);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real nu31 = nu13 * E3 / E1;
+  Real nu32 = nu23 * E3 / E2;
+  Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 -
+                    2 * nu21 * nu32 * nu13);
+
+  Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0);
+  C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32);
+  C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31);
+  C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21);
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23);
+  C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32);
+  C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31);
+
+  C_expected(3, 3) = G23;
+  C_expected(4, 4) = G13;
+  C_expected(5, 5) = G12;
+
+  Matrix<Real> tangent(6, 6);
+  this->computeTangentModuliOnQuad(tangent);
+
+  Real tangent_error = (tangent - C_expected).norm<L_2>();
+  ASSERT_NEAR(tangent_error, 0, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<2>>::testShearWaveSpeed() {
-  Real E = 1.;
-  Real nu = .3;
-  Real rho = 2;
-  setParam("E", E);
-  setParam("nu", nu);
-  setParam("rho", rho);
-  auto wave_speed = this->getShearWaveSpeed(Element());
+template <> void FriendMaterial<MaterialElasticOrthotropic<3>>::testCelerity() {
 
-  Real mu = E / (2 * (1 + nu));
-  Real sol = std::sqrt(mu / rho);
+  // Note: for this test material and canonical basis coincide
+  UInt Dim = 3;
+  Vector<Real> n1 = {1, 0, 0};
+  Vector<Real> n2 = {0, 1, 0};
+  Vector<Real> n3 = {0, 0, 1};
+  Real E1 = 1.;
+  Real E2 = 2.;
+  Real E3 = 3.;
+  Real nu12 = 0.1;
+  Real nu13 = 0.2;
+  Real nu23 = 0.3;
+  Real G12 = 2.;
+  Real G13 = 3.;
+  Real G23 = 1.;
+  Real rho = 2.3;
+
+  setParamNoUpdate("n1", n1);
+  setParamNoUpdate("n2", n2);
+  setParamNoUpdate("n3", n3);
+  setParamNoUpdate("E1", E1);
+  setParamNoUpdate("E2", E2);
+  setParamNoUpdate("E3", E3);
+  setParamNoUpdate("nu12", nu12);
+  setParamNoUpdate("nu13", nu13);
+  setParamNoUpdate("nu23", nu23);
+  setParamNoUpdate("G12", G12);
+  setParamNoUpdate("G13", G13);
+  setParamNoUpdate("G23", G23);
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // construction of Cijkl engineering tensor in the *material* frame of
+  // reference
+  // ref: http://solidmechanics.org/Text/Chapter3_2/Chapter3_2.php#Sect3_2_13
+  Real nu21 = nu12 * E2 / E1;
+  Real nu31 = nu13 * E3 / E1;
+  Real nu32 = nu23 * E3 / E2;
+  Real gamma = 1 / (1 - nu12 * nu21 - nu23 * nu32 - nu31 * nu13 -
+                    2 * nu21 * nu32 * nu13);
+
+  Matrix<Real> C_expected(2 * Dim, 2 * Dim, 0);
+  C_expected(0, 0) = gamma * E1 * (1 - nu23 * nu32);
+  C_expected(1, 1) = gamma * E2 * (1 - nu13 * nu31);
+  C_expected(2, 2) = gamma * E3 * (1 - nu12 * nu21);
+
+  C_expected(1, 0) = C_expected(0, 1) = gamma * E1 * (nu21 + nu31 * nu23);
+  C_expected(2, 0) = C_expected(0, 2) = gamma * E1 * (nu31 + nu21 * nu32);
+  C_expected(2, 1) = C_expected(1, 2) = gamma * E2 * (nu32 + nu12 * nu31);
+
+  C_expected(3, 3) = G23;
+  C_expected(4, 4) = G13;
+  C_expected(5, 5) = G12;
 
-  ASSERT_NEAR(wave_speed, sol, 1e-14);
+  Vector<Real> eig_expected(6);
+  C_expected.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<2>>::testComputeStress() {
-  Real E = 1.;
-  Real nu = .3;
-  Real sigma_th = 0.3; // thermal stress
-  setParam("E", E);
-  setParam("nu", nu);
+template <>
+void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testComputeStress() {
+  UInt Dim = 2;
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5},
+  };
+
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C33", C(2, 2));
 
+  // material frame of reference is rotate by rotation_matrix starting from
+  // canonical basis
   Matrix<Real> rotation_matrix = getRandomRotation2d();
 
-  auto grad_u = this->getDeviatoricStrain(1.).block(0, 0, 2, 2);
+  // canonical basis as expressed in the material frame of reference, as
+  // required by MaterialElasticLinearAnisotropic class (it is simply given by
+  // the columns of the rotation_matrix; the lines give the material basis
+  // expressed in the canonical frame of reference)
+  Vector<Real> v1(Dim);
+  Vector<Real> v2(Dim);
+  for (UInt i = 0; i < Dim; ++i) {
+    v1[i] = rotation_matrix(i, 0);
+    v2[i] = rotation_matrix(i, 1);
+  }
 
-  auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
+  setParamNoUpdate("n1", v1.normalize());
+  setParamNoUpdate("n2", v2.normalize());
 
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // gradient in material frame of reference
+  auto grad_u = this->getComposedStrain(1.).block(0, 0, 2, 2);
+
+  // gradient in canonical basis (we need to rotate *back* to the canonical
+  // basis)
+  auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
+
+  // stress in the canonical basis
   Matrix<Real> sigma_rot(2, 2);
-  this->computeStressOnQuad(grad_u_rot, sigma_rot, sigma_th);
+  this->computeStressOnQuad(grad_u_rot, sigma_rot);
 
-  auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
+  // stress in the material reference (we need to apply the rotation)
+  auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
 
-  Matrix<Real> identity(2, 2);
-  identity.eye();
+  // epsilon is computed directly in the *material* frame of reference
+  Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
+  Vector<Real> epsilon_voigt(3);
+  epsilon_voigt(0) = epsilon(0, 0);
+  epsilon_voigt(1) = epsilon(1, 1);
+  epsilon_voigt(2) = 2 * epsilon(0, 1);
 
-  Matrix<Real> sigma_expected =
-      0.5 * E / (1 + nu) * (grad_u + grad_u.transpose()) + sigma_th * identity;
+  // sigma_expected is computed directly in the *material* frame of reference
+  Vector<Real> sigma_voigt = C * epsilon_voigt;
+  Matrix<Real> sigma_expected(Dim, Dim);
+  sigma_expected(0, 0) = sigma_voigt(0);
+  sigma_expected(1, 1) = sigma_voigt(1);
+  sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(2);
 
+  // sigmas are checked in the *material* frame of reference
   auto diff = sigma - sigma_expected;
   Real stress_error = diff.norm<L_inf>();
-  ASSERT_NEAR(stress_error, 0., 1e-14);
+  ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
 template <>
-void FriendMaterial<MaterialElastic<2>>::testComputeTangentModuli() {
-  Real E = 1.;
-  Real nu = .3;
-  setParam("E", E);
-  setParam("nu", nu);
-  Matrix<Real> tangent(3, 3);
+void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testEnergyDensity() {
+  Matrix<Real> sigma = {{1, 2}, {2, 4}};
+  Matrix<Real> eps = {{1, 0}, {0, 1}};
+  Real epot = 0;
+  Real solution = 2.5;
+  this->computePotentialEnergyOnQuad(eps, sigma, epot);
+  ASSERT_NEAR(epot, solution, 1e-14);
+}
 
-  /* Plane Strain */
-  // clang-format off
-  Matrix<Real> solution = {
-    {1 - nu, nu, 0},
-    {nu, 1 - nu, 0},
-    {0, 0, (1 - 2 * nu) / 2},
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<
+    MaterialElasticLinearAnisotropic<2>>::testComputeTangentModuli() {
+
+  // Note: for this test material and canonical basis coincide
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5},
   };
-  // clang-format on
-  solution *= E / ((1 + nu) * (1 - 2 * nu));
 
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C33", C(2, 2));
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  Matrix<Real> tangent(3, 3);
   this->computeTangentModuliOnQuad(tangent);
-  Real tangent_error = (tangent - solution).norm<L_2>();
+
+  Real tangent_error = (tangent - C).norm<L_2>();
   ASSERT_NEAR(tangent_error, 0, 1e-14);
+}
 
-  /* Plane Stress */
-  this->plane_stress = true;
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElasticLinearAnisotropic<2>>::testCelerity() {
+
+  // Note: for this test material and canonical basis coincide
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4}, {0.3, 2.0, 0.1}, {0.4, 0.1, 1.5},
+  };
+
+  Real rho = 2.7;
+
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
   this->updateInternalParameters();
-  // clang-format off
-  solution = {
-    {1, nu, 0},
-    {nu, 1, 0},
-    {0, 0, (1 - nu) / 2},
+
+  Vector<Real> eig_expected(3);
+  C.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testComputeStress() {
+  UInt Dim = 3;
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2},
+      {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4},
+      {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2},
   };
-  // clang-format on
-  solution *= E / (1 - nu * nu);
 
-  this->computeTangentModuliOnQuad(tangent);
-  tangent_error = (tangent - solution).norm<L_2>();
-  ASSERT_NEAR(tangent_error, 0, 1e-14);
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C14", C(0, 3));
+  setParamNoUpdate("C15", C(0, 4));
+  setParamNoUpdate("C16", C(0, 5));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C24", C(1, 3));
+  setParamNoUpdate("C25", C(1, 4));
+  setParamNoUpdate("C26", C(1, 5));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("C34", C(2, 3));
+  setParamNoUpdate("C35", C(2, 4));
+  setParamNoUpdate("C36", C(2, 5));
+  setParamNoUpdate("C44", C(3, 3));
+  setParamNoUpdate("C45", C(3, 4));
+  setParamNoUpdate("C46", C(3, 5));
+  setParamNoUpdate("C55", C(4, 4));
+  setParamNoUpdate("C56", C(4, 5));
+  setParamNoUpdate("C66", C(5, 5));
+
+  // material frame of reference is rotate by rotation_matrix starting from
+  // canonical basis
+  Matrix<Real> rotation_matrix = getRandomRotation3d();
+
+  // canonical basis as expressed in the material frame of reference, as
+  // required by MaterialElasticLinearAnisotropic class (it is simply given by
+  // the columns of the rotation_matrix; the lines give the material basis
+  // expressed in the canonical frame of reference)
+  Vector<Real> v1(Dim);
+  Vector<Real> v2(Dim);
+  Vector<Real> v3(Dim);
+  for (UInt i = 0; i < Dim; ++i) {
+    v1[i] = rotation_matrix(i, 0);
+    v2[i] = rotation_matrix(i, 1);
+    v3[i] = rotation_matrix(i, 2);
+  }
+
+  setParamNoUpdate("n1", v1.normalize());
+  setParamNoUpdate("n2", v2.normalize());
+  setParamNoUpdate("n3", v3.normalize());
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  // gradient in material frame of reference
+  auto grad_u = this->getComposedStrain(2.);
+
+  // gradient in canonical basis (we need to rotate *back* to the canonical
+  // basis)
+  auto grad_u_rot = this->reverseRotation(grad_u, rotation_matrix);
+
+  // stress in the canonical basis
+  Matrix<Real> sigma_rot(3, 3);
+  this->computeStressOnQuad(grad_u_rot, sigma_rot);
+
+  // stress in the material reference (we need to apply the rotation)
+  auto sigma = this->applyRotation(sigma_rot, rotation_matrix);
+
+  // epsilon is computed directly in the *material* frame of reference
+  Matrix<Real> epsilon = 0.5 * (grad_u + grad_u.transpose());
+  Vector<Real> epsilon_voigt(6);
+  epsilon_voigt(0) = epsilon(0, 0);
+  epsilon_voigt(1) = epsilon(1, 1);
+  epsilon_voigt(2) = epsilon(2, 2);
+  epsilon_voigt(3) = 2 * epsilon(1, 2);
+  epsilon_voigt(4) = 2 * epsilon(0, 2);
+  epsilon_voigt(5) = 2 * epsilon(0, 1);
+
+  // sigma_expected is computed directly in the *material* frame of reference
+  Vector<Real> sigma_voigt = C * epsilon_voigt;
+  Matrix<Real> sigma_expected(Dim, Dim);
+  sigma_expected(0, 0) = sigma_voigt(0);
+  sigma_expected(1, 1) = sigma_voigt(1);
+  sigma_expected(2, 2) = sigma_voigt(2);
+  sigma_expected(1, 2) = sigma_expected(2, 1) = sigma_voigt(3);
+  sigma_expected(0, 2) = sigma_expected(2, 0) = sigma_voigt(4);
+  sigma_expected(0, 1) = sigma_expected(1, 0) = sigma_voigt(5);
+
+  // sigmas are checked in the *material* frame of reference
+  auto diff = sigma - sigma_expected;
+  Real stress_error = diff.norm<L_inf>();
+  ASSERT_NEAR(stress_error, 0., 1e-13);
 }
 
 /* -------------------------------------------------------------------------- */
-template <> void FriendMaterial<MaterialElastic<2>>::testEnergyDensity() {
-  Matrix<Real> sigma = {{1, 2}, {2, 4}};
-  Matrix<Real> eps = {{1, 0}, {0, 1}};
+template <>
+void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testEnergyDensity() {
+  Matrix<Real> sigma = {{1, 2, 3}, {2, 4, 5}, {3, 5, 6}};
+  Matrix<Real> eps = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
   Real epot = 0;
-  Real solution = 2.5;
+  Real solution = 5.5;
   this->computePotentialEnergyOnQuad(eps, sigma, epot);
   ASSERT_NEAR(epot, solution, 1e-14);
 }
 
 /* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<
+    MaterialElasticLinearAnisotropic<3>>::testComputeTangentModuli() {
+
+  // Note: for this test material and canonical basis coincide
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2},
+      {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4},
+      {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2},
+  };
+
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C14", C(0, 3));
+  setParamNoUpdate("C15", C(0, 4));
+  setParamNoUpdate("C16", C(0, 5));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C24", C(1, 3));
+  setParamNoUpdate("C25", C(1, 4));
+  setParamNoUpdate("C26", C(1, 5));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("C34", C(2, 3));
+  setParamNoUpdate("C35", C(2, 4));
+  setParamNoUpdate("C36", C(2, 5));
+  setParamNoUpdate("C44", C(3, 3));
+  setParamNoUpdate("C45", C(3, 4));
+  setParamNoUpdate("C46", C(3, 5));
+  setParamNoUpdate("C55", C(4, 4));
+  setParamNoUpdate("C56", C(4, 5));
+  setParamNoUpdate("C66", C(5, 5));
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  Matrix<Real> tangent(6, 6);
+  this->computeTangentModuliOnQuad(tangent);
+
+  Real tangent_error = (tangent - C).norm<L_2>();
+  ASSERT_NEAR(tangent_error, 0, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+template <>
+void FriendMaterial<MaterialElasticLinearAnisotropic<3>>::testCelerity() {
+
+  // Note: for this test material and canonical basis coincide
+  Matrix<Real> C = {
+      {1.0, 0.3, 0.4, 0.3, 0.2, 0.1}, {0.3, 2.0, 0.1, 0.2, 0.3, 0.2},
+      {0.4, 0.1, 1.5, 0.1, 0.4, 0.3}, {0.3, 0.2, 0.1, 2.4, 0.1, 0.4},
+      {0.2, 0.3, 0.4, 0.1, 0.9, 0.1}, {0.1, 0.2, 0.3, 0.4, 0.1, 1.2},
+  };
+  Real rho = 2.9;
+
+  setParamNoUpdate("C11", C(0, 0));
+  setParamNoUpdate("C12", C(0, 1));
+  setParamNoUpdate("C13", C(0, 2));
+  setParamNoUpdate("C14", C(0, 3));
+  setParamNoUpdate("C15", C(0, 4));
+  setParamNoUpdate("C16", C(0, 5));
+  setParamNoUpdate("C22", C(1, 1));
+  setParamNoUpdate("C23", C(1, 2));
+  setParamNoUpdate("C24", C(1, 3));
+  setParamNoUpdate("C25", C(1, 4));
+  setParamNoUpdate("C26", C(1, 5));
+  setParamNoUpdate("C33", C(2, 2));
+  setParamNoUpdate("C34", C(2, 3));
+  setParamNoUpdate("C35", C(2, 4));
+  setParamNoUpdate("C36", C(2, 5));
+  setParamNoUpdate("C44", C(3, 3));
+  setParamNoUpdate("C45", C(3, 4));
+  setParamNoUpdate("C46", C(3, 5));
+  setParamNoUpdate("C55", C(4, 4));
+  setParamNoUpdate("C56", C(4, 5));
+  setParamNoUpdate("C66", C(5, 5));
+  setParamNoUpdate("rho", rho);
+
+  // set internal Cijkl matrix expressed in the canonical frame of reference
+  this->updateInternalParameters();
+
+  Vector<Real> eig_expected(6);
+  C.eig(eig_expected);
+
+  auto celerity_expected = std::sqrt(eig_expected(0) / rho);
+
+  auto celerity = this->getCelerity(Element());
+
+  ASSERT_NEAR(celerity_expected, celerity, 1e-14);
+}
+
+/* -------------------------------------------------------------------------- */
+
 namespace {
 
 template <typename T>
 class TestElasticMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestElasticMaterialFixture, types);
 
 TYPED_TEST(TestElasticMaterialFixture, ElasticComputeStress) {
   this->material->testComputeStress();
 }
 
 TYPED_TEST(TestElasticMaterialFixture, ElasticEnergyDensity) {
   this->material->testEnergyDensity();
 }
 
 TYPED_TEST(TestElasticMaterialFixture, ElasticComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
 
-TYPED_TEST(TestElasticMaterialFixture, ElasticComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
+TYPED_TEST(TestElasticMaterialFixture, ElasticComputeCelerity) {
+  this->material->testCelerity();
 }
 
-TYPED_TEST(TestElasticMaterialFixture, ElasticComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
-}
 } // namespace
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc
index b1f0219b8..570314f6a 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_finite_def_materials.cc
@@ -1,61 +1,57 @@
 /* -------------------------------------------------------------------------- */
 #include "material_neohookean.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types = ::testing::Types<
 
     Traits<MaterialNeohookean, 1>, Traits<MaterialNeohookean, 2>,
     Traits<MaterialNeohookean, 3>>;
 
 /*****************************************************************/
 
 template <> void FriendMaterial<MaterialNeohookean<3>>::testComputeStress() {
   TO_IMPLEMENT;
 }
 
 /*****************************************************************/
 template <>
 void FriendMaterial<MaterialNeohookean<3>>::testComputeTangentModuli() {
   TO_IMPLEMENT;
 }
 
 /*****************************************************************/
 
 template <> void FriendMaterial<MaterialNeohookean<3>>::testEnergyDensity() {
   TO_IMPLEMENT;
 }
 
 /*****************************************************************/
 
 namespace {
 
 template <typename T>
 class TestFiniteDefMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestFiniteDefMaterialFixture, types);
 
 TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeStress) {
   this->material->testComputeStress();
 }
 TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefEnergyDensity) {
   this->material->testEnergyDensity();
 }
 TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
 
-TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
-}
-
-TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
+TYPED_TEST(TestFiniteDefMaterialFixture, FiniteDefComputeCelerity) {
+  this->material->testCelerity();
 }
 }
 /*****************************************************************/
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh
index eb4d93b77..97d814c89 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_material_fixtures.hh
@@ -1,171 +1,190 @@
 /* -------------------------------------------------------------------------- */
 #include "material_elastic.hh"
 #include "solid_mechanics_model.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <random>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 #define TO_IMPLEMENT AKANTU_EXCEPTION("TEST TO IMPLEMENT")
 
 using namespace akantu;
 
 /* -------------------------------------------------------------------------- */
 template <typename T> class FriendMaterial : public T {
 public:
   ~FriendMaterial() = default;
-  
+
   virtual void testComputeStress() { TO_IMPLEMENT; };
   virtual void testComputeTangentModuli() { TO_IMPLEMENT; };
   virtual void testEnergyDensity() { TO_IMPLEMENT; };
-  virtual void testPushWaveSpeed() { TO_IMPLEMENT; }
-  virtual void testShearWaveSpeed() { TO_IMPLEMENT; }
+  virtual void testCelerity() { TO_IMPLEMENT; }
 
   static inline Matrix<Real> getDeviatoricStrain(Real intensity);
-
   static inline Matrix<Real> getHydrostaticStrain(Real intensity);
+  static inline Matrix<Real> getComposedStrain(Real intensity);
 
   static inline const Matrix<Real>
   reverseRotation(Matrix<Real> mat, Matrix<Real> rotation_matrix) {
     Matrix<Real> R = rotation_matrix;
     Matrix<Real> m2 = mat * R;
     Matrix<Real> m1 = R.transpose();
     return m1 * m2;
   };
 
   static inline const Matrix<Real>
   applyRotation(Matrix<Real> mat, const Matrix<Real> rotation_matrix) {
     Matrix<Real> R = rotation_matrix;
     Matrix<Real> m2 = mat * R.transpose();
     Matrix<Real> m1 = R;
     return m1 * m2;
   };
 
   static inline Matrix<Real> getRandomRotation3d();
   static inline Matrix<Real> getRandomRotation2d();
 
   using T::T;
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Matrix<Real> FriendMaterial<T>::getDeviatoricStrain(Real intensity) {
   Matrix<Real> dev = {{0, 1, 2}, {1, 0, 3}, {2, 3, 0}};
   dev *= intensity;
   return dev;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Matrix<Real> FriendMaterial<T>::getHydrostaticStrain(Real intensity) {
-  Matrix<Real> dev = {{1, 0, 0}, {0, 2, 0}, {0, 0, 3}};
+  Matrix<Real> dev = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
   dev *= intensity;
   return dev;
 }
 
+/* -------------------------------------------------------------------------- */
+
+template <typename T>
+Matrix<Real> FriendMaterial<T>::getComposedStrain(Real intensity) {
+  Matrix<Real> s = FriendMaterial<T>::getHydrostaticStrain(intensity) +
+                   FriendMaterial<T>::getDeviatoricStrain(intensity);
+  s *= intensity;
+  return s;
+}
+
 /* -------------------------------------------------------------------------- */
 template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation3d() {
   constexpr UInt Dim = 3;
   // Seed with a real random value, if available
   std::random_device rd;
   std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
   std::uniform_real_distribution<> dis;
 
   Vector<Real> v1(Dim);
   Vector<Real> v2(Dim);
   Vector<Real> v3(Dim);
 
   for (UInt i = 0; i < Dim; ++i) {
     v1(i) = dis(gen);
     v2(i) = dis(gen);
   }
 
   v1.normalize();
   v2.normalize();
 
   auto d = v1.dot(v2);
   v2 -= v1 * d;
   v2.normalize();
 
   d = v1.dot(v2);
   v2 -= v1 * d;
   v2.normalize();
 
-  v3.crossProduct(v2, v1);
+  v3.crossProduct(v1, v2);
+
+  Vector<Real> test_axis(3);
+  test_axis.crossProduct(v1, v2);
+  test_axis -= v3;
+  if (test_axis.norm() > 8 * std::numeric_limits<Real>::epsilon()) {
+    AKANTU_DEBUG_ERROR("The axis vectors do not form a right-handed coordinate "
+                       << "system. I. e., ||n1 x n2 - n3|| should be zero, but "
+                       << "it is " << test_axis.norm() << ".");
+  }
 
   Matrix<Real> mat(Dim, Dim);
   for (UInt i = 0; i < Dim; ++i) {
     mat(0, i) = v1[i];
     mat(1, i) = v2[i];
     mat(2, i) = v3[i];
   }
 
   return mat;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T> Matrix<Real> FriendMaterial<T>::getRandomRotation2d() {
   constexpr UInt Dim = 2;
   // Seed with a real random value, if available
   std::random_device rd;
   std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
   std::uniform_real_distribution<> dis;
 
-  Vector<Real> v1(Dim);
-  Vector<Real> v2(Dim);
+  // v1 and v2 are such that they form a right-hand basis with prescribed v3,
+  // it's need (at least) for 2d linear elastic anisotropic and (orthotropic)
+  // materials to rotate the tangent stiffness
+
+  Vector<Real> v1(3);
+  Vector<Real> v2(3);
+  Vector<Real> v3 = {0, 0, 1};
 
   for (UInt i = 0; i < Dim; ++i) {
     v1(i) = dis(gen);
-    v2(i) = dis(gen);
+    // v2(i) = dis(gen);
   }
 
   v1.normalize();
-  v2.normalize();
-
-  auto d = v1.dot(v2);
-  v2 -= v1 * d;
-  v2.normalize();
+  v2.crossProduct(v3, v1);
 
   Matrix<Real> mat(Dim, Dim);
   for (UInt i = 0; i < Dim; ++i) {
     mat(0, i) = v1[i];
     mat(1, i) = v2[i];
   }
 
   return mat;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T> class TestMaterialFixture : public ::testing::Test {
 public:
   using mat_class = typename T::mat_class;
 
   void SetUp() override {
     constexpr auto spatial_dimension = T::Dim;
     mesh = std::make_unique<Mesh>(spatial_dimension);
     model = std::make_unique<SolidMechanicsModel>(*mesh);
     material = std::make_unique<friend_class>(*model);
   }
 
   void TearDown() override {
     material.reset(nullptr);
     model.reset(nullptr);
     mesh.reset(nullptr);
   }
 
   using friend_class = FriendMaterial<mat_class>;
 
 protected:
   std::unique_ptr<Mesh> mesh;
   std::unique_ptr<SolidMechanicsModel> model;
   std::unique_ptr<friend_class> material;
 };
 
 /* -------------------------------------------------------------------------- */
 template <template <UInt> class T, UInt _Dim> struct Traits {
   using mat_class = T<_Dim>;
   static constexpr UInt Dim = _Dim;
 };
 
 /* -------------------------------------------------------------------------- */
diff --git a/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc b/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc
index aef6ce6da..0c89bc0cc 100644
--- a/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc
+++ b/test/test_model/test_solid_mechanics_model/test_materials/test_plastic_materials.cc
@@ -1,43 +1,161 @@
 /* -------------------------------------------------------------------------- */
 #include "material_linear_isotropic_hardening.hh"
 #include "solid_mechanics_model.hh"
 #include "test_material_fixtures.hh"
 #include <gtest/gtest.h>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 using types = ::testing::Types<Traits<MaterialLinearIsotropicHardening, 1>,
                                Traits<MaterialLinearIsotropicHardening, 2>,
                                Traits<MaterialLinearIsotropicHardening, 3>>;
 
-/*****************************************************************/
+/* -------------------------------------------------------------------------- */
+
+template <>
+void FriendMaterial<MaterialLinearIsotropicHardening<3>>::testComputeStress() {
+
+  Real E = 1.;
+  // Real nu = .3;
+  Real nu = 0.;
+  Real rho = 1.;
+  Real sigma_0 = 1.;
+  Real h = 0.;
+  Real bulk_modulus_K = E / 3. / (1 - 2. * nu);
+  Real shear_modulus_mu = 0.5 * E / (1 + nu);
+
+  setParam("E", E);
+  setParam("nu", nu);
+  setParam("rho", rho);
+  setParam("sigma_y", sigma_0);
+  setParam("h", h);
+
+  Matrix<Real> rotation_matrix = getRandomRotation3d();
+
+  Real max_strain = 10.;
+  Real strain_steps = 100;
+  Real dt = max_strain / strain_steps;
+  std::vector<double> steps(strain_steps);
+  std::iota(steps.begin(), steps.end(), 0.);
+
+  Matrix<Real> previous_grad_u_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_sigma = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_sigma_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> inelastic_strain_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> inelastic_strain = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_inelastic_strain = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> previous_inelastic_strain_rot = Matrix<Real>(3, 3, 0.);
+  Matrix<Real> sigma_rot(3, 3, 0.);
+  Real iso_hardening = 0.;
+  Real previous_iso_hardening = 0.;
+
+  // hydrostatic loading (should not plastify)
+  for (auto && i : steps) {
+    auto t = i * dt;
+
+    auto grad_u = this->getHydrostaticStrain(t);
+    auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
+
+    this->computeStressOnQuad(grad_u_rot, previous_grad_u_rot, sigma_rot,
+                              previous_sigma_rot, inelastic_strain_rot,
+                              previous_inelastic_strain_rot, iso_hardening,
+                              previous_iso_hardening, 0., 0.);
+
+    auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
+
+    Matrix<Real> sigma_expected =
+        t * 3. * bulk_modulus_K * Matrix<Real>::eye(3, 1.);
+
+    Real stress_error = (sigma - sigma_expected).norm<L_inf>();
+
+    ASSERT_NEAR(stress_error, 0., 1e-13);
+    ASSERT_NEAR(inelastic_strain_rot.norm<L_inf>(), 0., 1e-13);
+
+    previous_grad_u_rot = grad_u_rot;
+    previous_sigma_rot = sigma_rot;
+    previous_inelastic_strain_rot = inelastic_strain_rot;
+    previous_iso_hardening = iso_hardening;
+  }
+
+  // deviatoric loading (should plastify)
+  // stress at onset of plastication
+  Real beta = sqrt(42);
+  Real t_P = sigma_0 / 2. / shear_modulus_mu / beta;
+  Matrix<Real> sigma_P = sigma_0 / beta * this->getDeviatoricStrain(1.);
+
+  for (auto && i : steps) {
+
+    auto t = i * dt;
+    auto grad_u = this->getDeviatoricStrain(t);
+    auto grad_u_rot = this->applyRotation(grad_u, rotation_matrix);
+    Real iso_hardening, previous_iso_hardening;
+
+    this->computeStressOnQuad(grad_u_rot, previous_grad_u_rot, sigma_rot,
+                              previous_sigma_rot, inelastic_strain_rot,
+                              previous_inelastic_strain_rot, iso_hardening,
+                              previous_iso_hardening, 0., 0.);
+
+    auto sigma = this->reverseRotation(sigma_rot, rotation_matrix);
+    auto inelastic_strain =
+        this->reverseRotation(inelastic_strain_rot, rotation_matrix);
+
+    if (t < t_P) {
+
+      Matrix<Real> sigma_expected =
+          shear_modulus_mu * (grad_u + grad_u.transpose());
+
+      Real stress_error = (sigma - sigma_expected).norm<L_inf>();
+      ASSERT_NEAR(stress_error, 0., 1e-13);
+      ASSERT_NEAR(inelastic_strain_rot.norm<L_inf>(), 0., 1e-13);
+    } else if (t > t_P + dt) {
+      // skip the transition from non plastic to plastic
+
+      auto delta_lambda_expected =
+          dt / t * previous_sigma.doubleDot(grad_u + grad_u.transpose()) / 2.;
+      auto delta_inelastic_strain_expected =
+          delta_lambda_expected * 3. / 2. / sigma_0 * previous_sigma;
+      auto inelastic_strain_expected =
+          delta_inelastic_strain_expected + previous_inelastic_strain;
+      ASSERT_NEAR((inelastic_strain - inelastic_strain_expected).norm<L_inf>(),
+                  0., 1e-13);
+      auto delta_sigma_expected =
+          2. * shear_modulus_mu *
+          (0.5 * dt / t * (grad_u + grad_u.transpose()) -
+           delta_inelastic_strain_expected);
+
+      auto delta_sigma = sigma - previous_sigma;
+      ASSERT_NEAR((delta_sigma_expected - delta_sigma).norm<L_inf>(), 0.,
+                  1e-13);
+    }
+    previous_sigma = sigma;
+    previous_sigma_rot = sigma_rot;
+    previous_grad_u_rot = grad_u_rot;
+    previous_inelastic_strain = inelastic_strain;
+    previous_inelastic_strain_rot = inelastic_strain_rot;
+  }
+}
 
 namespace {
 
 template <typename T>
 class TestPlasticMaterialFixture : public ::TestMaterialFixture<T> {};
 
 TYPED_TEST_CASE(TestPlasticMaterialFixture, types);
 
 TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeStress) {
   this->material->testComputeStress();
 }
 TYPED_TEST(TestPlasticMaterialFixture, PlasticEnergyDensity) {
   this->material->testEnergyDensity();
 }
 TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeTangentModuli) {
   this->material->testComputeTangentModuli();
 }
-
-TYPED_TEST(TestPlasticMaterialFixture, PlasticComputePushWaveSpeed) {
-  this->material->testPushWaveSpeed();
-}
-
-TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeShearWaveSpeed) {
-  this->material->testShearWaveSpeed();
+TYPED_TEST(TestPlasticMaterialFixture, PlasticComputeCelerity) {
+  this->material->testCelerity();
 }
 }
 
 /*****************************************************************/
diff --git a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc
index df4124325..fb0bfad88 100644
--- a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc
+++ b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_dynamics.cc
@@ -1,314 +1,314 @@
 /**
  * @file   test_solid_mechanics_model_cube3d.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  *
  * @date creation: Wed Aug 04 2010
  * @date last modification: Thu Aug 06 2015
  *
  * @brief  test of the class SolidMechanicsModel on the 3d cube
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "boundary_condition_functor.hh"
 #include "test_solid_mechanics_model_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 namespace {
 
 const Real A = 1e-1;
 const Real E = 1.;
 const Real poisson = 3. / 10;
 const Real lambda = E * poisson / (1 + poisson) / (1 - 2 * poisson);
 const Real mu = E / 2 / (1. + poisson);
 const Real rho = 1.;
 const Real cp = std::sqrt((lambda + 2 * mu) / rho);
 const Real cs = std::sqrt(mu / rho);
 const Real c = std::sqrt(E / rho);
 
 const Vector<Real> k = {.5, 0., 0.};
 const Vector<Real> psi1 = {0., 0., 1.};
 const Vector<Real> psi2 = {0., 1., 0.};
 const Real knorm = k.norm();
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim> struct Verification {};
 
 /* -------------------------------------------------------------------------- */
 template <> struct Verification<1> {
   void displacement(Vector<Real> & disp, const Vector<Real> & coord,
                     Real current_time) {
     const auto & x = coord(_x);
     const Real omega = c * k[0];
     disp(_x) = A * cos(k[0] * x - omega * current_time);
   }
 
   void velocity(Vector<Real> & vel, const Vector<Real> & coord,
                 Real current_time) {
     const auto & x = coord(_x);
     const Real omega = c * k[0];
     vel(_x) = omega * A * sin(k[0] * x - omega * current_time);
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct Verification<2> {
   void displacement(Vector<Real> & disp, const Vector<Real> & X,
                     Real current_time) {
     Vector<Real> kshear = {k[1], k[0]};
     Vector<Real> kpush = {k[0], k[1]};
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     disp = A * (kpush * cos(phase_p) + kshear * cos(phase_s));
   }
 
   void velocity(Vector<Real> & vel, const Vector<Real> & X, Real current_time) {
     Vector<Real> kshear = {k[1], k[0]};
     Vector<Real> kpush = {k[0], k[1]};
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     vel =
         A * (kpush * omega_p * cos(phase_p) + kshear * omega_s * cos(phase_s));
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct Verification<3> {
   void displacement(Vector<Real> & disp, const Vector<Real> & coord,
                     Real current_time) {
     const auto & X = coord;
     Vector<Real> kpush = k;
     Vector<Real> kshear1(3);
     Vector<Real> kshear2(3);
     kshear1.crossProduct(k, psi1);
     kshear2.crossProduct(k, psi2);
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     disp = A * (kpush * cos(phase_p) + kshear1 * cos(phase_s) +
                 kshear2 * cos(phase_s));
   }
 
   void velocity(Vector<Real> & vel, const Vector<Real> & coord,
                 Real current_time) {
     const auto & X = coord;
     Vector<Real> kpush = k;
     Vector<Real> kshear1(3);
     Vector<Real> kshear2(3);
     kshear1.crossProduct(k, psi1);
     kshear2.crossProduct(k, psi2);
 
     const Real omega_p = knorm * cp;
     const Real omega_s = knorm * cs;
 
     Real phase_p = X.dot(kpush) - omega_p * current_time;
     Real phase_s = X.dot(kpush) - omega_s * current_time;
 
     vel =
         A * (kpush * omega_p * cos(phase_p) + kshear1 * omega_s * cos(phase_s) +
              kshear2 * omega_s * cos(phase_s));
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <ElementType _type>
 class SolutionFunctor : public BC::Dirichlet::DirichletFunctor {
 public:
   SolutionFunctor(Real current_time, SolidMechanicsModel & model)
       : current_time(current_time), model(model) {}
 
 public:
   static constexpr UInt dim = ElementClass<_type>::getSpatialDimension();
 
   inline void operator()(UInt node, Vector<bool> & flags, Vector<Real> & primal,
                          const Vector<Real> & coord) const {
     flags(0) = true;
     auto & vel = model.getVelocity();
     auto it = vel.begin(model.getSpatialDimension());
     Vector<Real> v = it[node];
 
     Verification<dim> verif;
     verif.displacement(primal, coord, current_time);
     verif.velocity(v, coord, current_time);
   }
 
 private:
   Real current_time;
   SolidMechanicsModel & model;
 };
 
 /* -------------------------------------------------------------------------- */
 // This fixture uses somewhat finer meshes representing bars.
 template <typename type_>
 class TestSMMFixtureBar
     : public TestSMMFixture<std::tuple_element_t<0, type_>> {
   using parent = TestSMMFixture<std::tuple_element_t<0, type_>>;
 
 public:
   void SetUp() override {
-    this->mesh_file = "bar" + aka::to_string(this->type) + ".msh";
+    this->mesh_file = "../patch_tests/data/bar" + aka::to_string(this->type) + ".msh";
     parent::SetUp();
 
     getStaticParser().parse("test_solid_mechanics_model_"
                             "dynamics_material.dat");
 
     auto analysis_method = std::tuple_element_t<1, type_>::value;
     this->model->initFull(_analysis_method = analysis_method);
 
     if (this->dump_paraview) {
       std::stringstream base_name;
       base_name << "bar" << analysis_method << this->type;
       this->model->setBaseName(base_name.str());
       this->model->addDumpFieldVector("displacement");
       this->model->addDumpField("mass");
       this->model->addDumpField("velocity");
       this->model->addDumpField("acceleration");
       this->model->addDumpFieldVector("external_force");
       this->model->addDumpFieldVector("internal_force");
       this->model->addDumpField("stress");
       this->model->addDumpField("strain");
     }
 
     time_step = this->model->getStableTimeStep() / 10.;
     this->model->setTimeStep(time_step);
     // std::cout << "timestep: " << time_step << std::endl;
 
     const auto & position = this->mesh->getNodes();
     auto & displacement = this->model->getDisplacement();
     auto & velocity = this->model->getVelocity();
 
     constexpr auto dim = parent::spatial_dimension;
 
     Verification<dim> verif;
 
     for (auto && tuple :
          zip(make_view(position, dim), make_view(displacement, dim),
              make_view(velocity, dim))) {
       verif.displacement(std::get<1>(tuple), std::get<0>(tuple), 0.);
       verif.velocity(std::get<2>(tuple), std::get<0>(tuple), 0.);
     }
 
     if (dump_paraview)
       this->model->dump();
 
     /// boundary conditions
     this->model->applyBC(SolutionFunctor<parent::type>(0., *this->model), "BC");
 
     wave_velocity = 1.; // sqrt(E/rho) = sqrt(1/1) = 1
     simulation_time = 5 / wave_velocity;
 
     max_steps = simulation_time / time_step; // 100
     auto ndump = 50;
     dump_freq = max_steps / ndump;
   }
 
 protected:
   Real time_step;
   Real wave_velocity;
   Real simulation_time;
   UInt max_steps;
   UInt dump_freq;
   bool dump_paraview{false};
 };
 
 template <AnalysisMethod t>
 using analysis_method_t = std::integral_constant<AnalysisMethod, t>;
 
 #ifdef AKANTU_IMPLICIT
 using TestAnalysisTypes =
     std::tuple<analysis_method_t<_implicit_dynamic>, analysis_method_t<_explicit_lumped_mass>>;
 #else
 using TestAnalysisTypes = std::tuple<analysis_method_t<_explicit_lumped_mass>>;
 #endif
 
 using TestTypes =
     gtest_list_t<cross_product_t<TestElementTypes, TestAnalysisTypes>>;
 
 TYPED_TEST_CASE(TestSMMFixtureBar, TestTypes);
 
 /* -------------------------------------------------------------------------- */
 
 TYPED_TEST(TestSMMFixtureBar, DynamicsExplicit) {
   constexpr auto dim = TestFixture::spatial_dimension;
   Real current_time = 0.;
   const auto & position = this->mesh->getNodes();
   const auto & displacement = this->model->getDisplacement();
   UInt nb_nodes = this->mesh->getNbNodes();
   UInt nb_global_nodes = this->mesh->getNbGlobalNodes();
   Real max_error{0.};
 
   Array<Real> displacement_solution(nb_nodes, dim);
 
   Verification<dim> verif;
 
   for (UInt s = 0; s < this->max_steps; ++s, current_time += this->time_step) {
     if (s % this->dump_freq == 0 && this->dump_paraview)
       this->model->dump();
 
     /// boundary conditions
     this->model->applyBC(
         SolutionFunctor<TestFixture::type>(current_time, *this->model), "BC");
 
     // compute the disp solution
     for (auto && tuple :
          zip(make_view(position, dim), make_view(displacement_solution, dim))) {
       verif.displacement(std::get<1>(tuple), std::get<0>(tuple), current_time);
     }
 
     // compute the error solution
     Real disp_error = 0.;
     for (auto && tuple : zip(make_view(displacement, dim),
                              make_view(displacement_solution, dim))) {
       auto diff = std::get<1>(tuple) - std::get<0>(tuple);
       disp_error += diff.dot(diff);
     }
 
     this->mesh->getCommunicator().allReduce(disp_error,
                                             SynchronizerOperation::_sum);
 
     disp_error = sqrt(disp_error) / nb_global_nodes;
     max_error = std::max(disp_error, max_error);
 
-    ASSERT_NEAR(disp_error, 0., 1e-3);
+    ASSERT_NEAR(disp_error, 0., 2e-3);
 
     this->model->solveStep();
   }
   // std::cout << "max error: " << max_error << std::endl;
 }
 }
diff --git a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh
index 57400aa38..ff2979628 100644
--- a/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh
+++ b/test/test_model/test_solid_mechanics_model/test_solid_mechanics_model_fixture.hh
@@ -1,61 +1,55 @@
 /* -------------------------------------------------------------------------- */
 #include "solid_mechanics_model.hh"
 #include "test_gtest_utils.hh"
 #include "communicator.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <vector>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_TEST_SOLID_MECHANICS_MODEL_FIXTURE_HH__
 #define __AKANTU_TEST_SOLID_MECHANICS_MODEL_FIXTURE_HH__
 
 using namespace akantu;
 
 // This fixture uses very small meshes with a volume of 1.
 template <typename type_> class TestSMMFixture : public ::testing::Test {
 public:
   static constexpr ElementType type = type_::value;
   static constexpr size_t spatial_dimension =
       ElementClass<type>::getSpatialDimension();
 
   void SetUp() override {
     this->mesh = std::make_unique<Mesh>(this->spatial_dimension);
 
-#if defined(AKANTU_PARALLEL)
     if(Communicator::getStaticCommunicator().whoAmI() == 0) {
-#endif
-
       this->mesh->read(this->mesh_file);
-
-#if defined(AKANTU_PARALLEL)
     }
 
     mesh->distribute();
-#endif
 
     SCOPED_TRACE(aka::to_string(this->type).c_str());
 
     model = std::make_unique<SolidMechanicsModel>(*mesh, _all_dimensions,
                                                   aka::to_string(this->type));
   }
 
   void TearDown() override {
     model.reset(nullptr);
     mesh.reset(nullptr);
   }
 
 protected:
   std::string mesh_file{aka::to_string(this->type) + ".msh"};
   std::unique_ptr<Mesh> mesh;
   std::unique_ptr<SolidMechanicsModel> model;
 };
 
 template <typename type_> constexpr ElementType TestSMMFixture<type_>::type;
 template <typename type_> constexpr size_t TestSMMFixture<type_>::spatial_dimension;
 
 using gtest_element_types = gtest_list_t<TestElementTypes>;
 
 TYPED_TEST_CASE(TestSMMFixture, gtest_element_types);
 
 #endif /* __AKANTU_TEST_SOLID_MECHANICS_MODEL_FIXTURE_HH__ */
diff --git a/test/test_model/test_structural_mechanics_model/CMakeLists.txt b/test/test_model/test_structural_mechanics_model/CMakeLists.txt
index 46000bf54..856cd66ea 100644
--- a/test/test_model/test_structural_mechanics_model/CMakeLists.txt
+++ b/test/test_model/test_structural_mechanics_model/CMakeLists.txt
@@ -1,63 +1,68 @@
 #===============================================================================
 # @file   CMakeLists.txt
 #
 # @author Fabian Barras <fabian.barras@epfl.ch>
 #
 # @date creation: Fri Sep 03 2010
 # @date last modification: Mon Dec 07 2015
 #
 # @brief  Structural Mechanics Model Tests
 #
 # @section LICENSE
 #
 # Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
 # Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
 # Solides)
 #
 # Akantu is free  software: you can redistribute it and/or  modify it under the
 # terms  of the  GNU Lesser  General Public  License as  published by  the Free
 # Software Foundation, either version 3 of the License, or (at your option) any
 # later version.
 #
 # Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 # A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
 # details.
 #
 # You should  have received  a copy  of the GNU  Lesser General  Public License
 # along with Akantu. If not, see <http://www.gnu.org/licenses/>.
 #
 #===============================================================================
 
 # Adding sources
 register_gtest_sources(
   SOURCES test_structural_mechanics_model_bernoulli_beam_2.cc
   PACKAGE implicit structural_mechanics
 )
 
 register_gtest_sources(
   SOURCES test_structural_mechanics_model_bernoulli_beam_3.cc
   PACKAGE implicit structural_mechanics
 )
 
+register_gtest_sources(
+  SOURCES test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc
+  PACKAGE implicit structural_mechanics
+)
+
 #===============================================================================
 
 # Adding meshes for element types
 package_get_element_types(structural_mechanics _types)
 
 foreach(_type ${_types})
   if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_type}.msh)
     list(APPEND _meshes ${_type}.msh)
     #register_fem_test(fe_engine_precomputation ${_type })
   else()
     if(NOT ${_type} STREQUAL _point_1)
       message("The mesh ${_type}.msh is missing, the fe_engine test cannot be activated without it")
     endif()
   endif()
 endforeach()
 
 #===============================================================================
 # Registering google test
 register_gtest_test(test_structural_mechanics
   FILES_TO_COPY ${_meshes})
 
diff --git a/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh b/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh
index 741047074..03e36a496 100644
--- a/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh
+++ b/test/test_model/test_structural_mechanics_model/_discrete_kirchhoff_triangle_18.msh
@@ -1,50 +1,18 @@
 $MeshFormat
 2.2 0 8
 $EndMeshFormat
 $Nodes
-13
+5
 1 0 0 0
-2 1 0 0
-3 1 1 0
-4 0 1 0
-5 0.4999999999990217 0 0
-6 1 0.4999999999990217 0
-7 0.5000000000013878 1 0
-8 0 0.5000000000013878 0
-9 0.5000000000000262 0.5000000000000762 0
-10 0.2500000000004626 0.7500000000004626 0
-11 0.7500000000004626 0.7499999999996739 0
-12 0.7499999999996739 0.2499999999996739 0
-13 0.24999999999961 0.2500000000004752 0
+2 40 0 0
+3 40 20 0
+4 0 20 0
+5 15 15 0
 $EndNodes
 $Elements
-28
-1 15 2 0 101 1
-2 15 2 0 102 2
-3 15 2 0 103 3
-4 15 2 0 104 4
-5 1 2 0 101 1 5
-6 1 2 0 101 5 2
-7 1 2 0 102 2 6
-8 1 2 0 102 6 3
-9 1 2 0 103 3 7
-10 1 2 0 103 7 4
-11 1 2 0 104 4 8
-12 1 2 0 104 8 1
-13 2 2 0 101 4 10 7
-14 2 2 0 101 1 13 8
-15 2 2 0 101 3 11 6
-16 2 2 0 101 2 12 5
-17 2 2 0 101 8 9 10
-18 2 2 0 101 7 10 9
-19 2 2 0 101 7 9 11
-20 2 2 0 101 8 13 9
-21 2 2 0 101 6 11 9
-22 2 2 0 101 5 9 13
-23 2 2 0 101 5 12 9
-24 2 2 0 101 6 9 12
-25 2 2 0 101 1 5 13
-26 2 2 0 101 4 8 10
-27 2 2 0 101 2 6 12
-28 2 2 0 101 3 7 11
+4
+1 2 2 1 1 1 5 2
+2 2 2 1 2 2 5 3
+3 2 2 1 3 3 4 5
+4 2 2 1 4 1 4 5
 $EndElements
diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc
index 0883df322..8337bb9c2 100644
--- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc
+++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc
@@ -1,113 +1,114 @@
 /**
  * @file   test_structural_mechanics_model_bernoulli_beam_2.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Computation of the analytical exemple 1.1 in the TGC vol 6
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "test_structural_mechanics_model_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 
 using namespace akantu;
 
 /* -------------------------------------------------------------------------- */
 class TestStructBernoulli2
     : public TestStructuralFixture<element_type_t<_bernoulli_beam_2>> {
   using parent = TestStructuralFixture<element_type_t<_bernoulli_beam_2>>;
 
 public:
   void addMaterials() override {
     mat.E = 3e10;
     mat.I = 0.0025;
     mat.A = 0.01;
 
     this->model->addMaterial(mat);
 
     mat.E = 3e10;
     mat.I = 0.00128;
     mat.A = 0.01;
 
     this->model->addMaterial(mat);
   }
 
   void assignMaterials() override {
     auto & materials = this->model->getElementMaterial(parent::type);
     materials(0) = 0;
     materials(1) = 1;
   }
 
   void setDirichlets() override {
     auto boundary = this->model->getBlockedDOFs().begin(parent::ndof);
     // clang-format off
     *boundary = {true, true, true}; ++boundary;
     *boundary = {false, true, false}; ++boundary;
     *boundary = {false, true, false}; ++boundary;
     // clang-format on
   }
 
   void setNeumanns() override {
     Real M = 3600;  // Nm
     Real q = -6000; // kN/m
     Real L = 10;    // m
     auto & forces = this->model->getExternalForce();
     forces(2, 2) = -M; // moment on last node
 #if 1 // as long as integration is not available
     forces(0, 1) = q * L / 2;
     forces(0, 2) = q * L * L / 12;
     forces(1, 1) = q * L / 2;
     forces(1, 2) = -q * L * L / 12;
 #else
     auto & group = mesh.createElementGroup("lin_force");
     group.add({type, 0, _not_ghost});
     Vector<Real> lin_force = {0, q, 0};
     // a linear force is not actually a *boundary* condition
     // it is equivalent to a volume force
     model.applyBC(BC::Neumann::FromSameDim(lin_force), group);
 #endif
     forces(2, 0) = mat.E * mat.A / 18;
   }
 
 protected:
   StructuralMaterial mat;
 };
 
 /* -------------------------------------------------------------------------- */
 
 TEST_F(TestStructBernoulli2, TestDisplacements) {
+  model->solveStep();
   auto d1 = model->getDisplacement()(1, 2);
   auto d2 = model->getDisplacement()(2, 2);
   auto d3 = model->getDisplacement()(1, 0);
 
   Real tol = Math::getTolerance();
 
   EXPECT_NEAR(d1, 5.6 / 4800, tol);  // first rotation
   EXPECT_NEAR(d2, -3.7 / 4800, tol); // second rotation
   EXPECT_NEAR(d3, 10. / 18, tol);    // axial deformation
 }
diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc
index 7e522852a..b3e649e5e 100644
--- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc
+++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_3.cc
@@ -1,99 +1,100 @@
 /**
  * @file   test_structural_mechanics_model_bernoulli_beam_3.cc
  *
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @date creation: Mon Jan 22 2018
  *
  * @brief  Computation of the analytical exemple 1.1 in the TGC vol 6
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "test_structural_mechanics_model_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
 class TestStructBernoulli3
     : public TestStructuralFixture<element_type_t<_bernoulli_beam_3>> {
   using parent = TestStructuralFixture<element_type_t<_bernoulli_beam_3>>;
 
 public:
   void readMesh(std::string filename) override {
     parent::readMesh(filename);
     auto & normals =
         this->mesh->registerData<Real>("extra_normal")
             .alloc(0, parent::spatial_dimension, parent::type, _not_ghost);
     Vector<Real> normal = {0, 0, 1};
     normals.push_back(normal);
     normal = {0, 0, 1};
     normals.push_back(normal);
   }
 
   void addMaterials() override {
     StructuralMaterial mat;
     mat.E = 1;
     mat.Iz = 1;
     mat.Iy = 1;
     mat.A = 1;
     mat.GJ = 1;
     this->model->addMaterial(mat);
   }
 
   void setDirichlets() {
     // Boundary conditions (blocking all DOFs of nodes 2 & 3)
     auto boundary = ++this->model->getBlockedDOFs().begin(parent::ndof);
     // clang-format off
     *boundary = {true, true, true, true, true, true}; ++boundary;
     *boundary = {true, true, true, true, true, true}; ++boundary;
     // clang-format on
   }
 
   void setNeumanns() override {
     // Forces
     Real P = 1; // N
     auto & forces = this->model->getExternalForce();
     forces.clear();
     forces(0, 2) = -P; // vertical force on first node
   }
 
   void assignMaterials() override { model->getElementMaterial(parent::type).set(0); }
 };
 
 /* -------------------------------------------------------------------------- */
 
 TEST_F(TestStructBernoulli3, TestDisplacements) {
+  model->solveStep();
   auto vz = model->getDisplacement()(0, 2);
   auto thy = model->getDisplacement()(0, 4);
   auto thx = model->getDisplacement()(0, 3);
   auto thz = model->getDisplacement()(0, 5);
 
   Real tol = Math::getTolerance();
 
   EXPECT_NEAR(vz, -5. / 48, tol);
   EXPECT_NEAR(thy, -std::sqrt(2) / 8, tol);
   EXPECT_NEAR(thz, 0, tol);
   EXPECT_NEAR(thx, 0, tol);
 }
diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc
similarity index 53%
copy from test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc
copy to test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc
index 0883df322..f33fd4e01 100644
--- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_bernoulli_beam_2.cc
+++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_discrete_kirchhoff_triangle_18.cc
@@ -1,113 +1,107 @@
 /**
  * @file   test_structural_mechanics_model_bernoulli_beam_2.cc
  *
  * @author Fabian Barras <fabian.barras@epfl.ch>
  * @author Lucas Frérot <lucas.frerot@epfl.ch>
  *
  * @date creation: Fri Jul 15 2011
  * @date last modification: Sun Oct 19 2014
  *
  * @brief  Computation of the analytical exemple 1.1 in the TGC vol 6
  *
  * @section LICENSE
  *
  * Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
  * Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
  * Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "test_structural_mechanics_model_fixture.hh"
+#include "sparse_matrix.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 
 using namespace akantu;
 
 /* -------------------------------------------------------------------------- */
-class TestStructBernoulli2
-    : public TestStructuralFixture<element_type_t<_bernoulli_beam_2>> {
-  using parent = TestStructuralFixture<element_type_t<_bernoulli_beam_2>>;
+class TestStructDKT18
+    : public TestStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>> {
+  using parent = TestStructuralFixture<element_type_t<_discrete_kirchhoff_triangle_18>>;
 
 public:
   void addMaterials() override {
-    mat.E = 3e10;
-    mat.I = 0.0025;
-    mat.A = 0.01;
-
-    this->model->addMaterial(mat);
-
-    mat.E = 3e10;
-    mat.I = 0.00128;
-    mat.A = 0.01;
+    mat.E = 1;
+    mat.t = 1;
+    mat.nu = 0.3;
 
     this->model->addMaterial(mat);
   }
 
   void assignMaterials() override {
     auto & materials = this->model->getElementMaterial(parent::type);
-    materials(0) = 0;
-    materials(1) = 1;
+    std::fill(materials.begin(), materials.end(), 0);
   }
 
   void setDirichlets() override {
-    auto boundary = this->model->getBlockedDOFs().begin(parent::ndof);
+    this->model->getBlockedDOFs().set(true);
+    auto center_node = this->model->getBlockedDOFs().end(parent::ndof) - 1;
+    *center_node = {false, false, false, false, false, true};
+
+    this->model->getDisplacement().clear();
+    auto disp = ++this->model->getDisplacement().begin(parent::ndof);
+
+    // Displacement field from Batoz Vol. 2 p. 392
+    // with theta to beta correction from discrete Kirchhoff condition
+    // see also the master thesis of Michael Lozano
     // clang-format off
-    *boundary = {true, true, true}; ++boundary;
-    *boundary = {false, true, false}; ++boundary;
-    *boundary = {false, true, false}; ++boundary;
+    // *disp = {40, 20, -800 , -20, 40, 0}; ++disp;
+    // *disp = {50, 40, -1400, -40, 50, 0}; ++disp;
+    // *disp = {10, 20, -200 , -20, 10, 0}; ++disp;
+    *disp = {0, 0, -800 , -20, 40, 0}; ++disp;
+    *disp = {0, 0, -1400, -40, 50, 0}; ++disp;
+    *disp = {0, 0, -200 , -20, 10, 0}; ++disp;
     // clang-format on
   }
 
-  void setNeumanns() override {
-    Real M = 3600;  // Nm
-    Real q = -6000; // kN/m
-    Real L = 10;    // m
-    auto & forces = this->model->getExternalForce();
-    forces(2, 2) = -M; // moment on last node
-#if 1 // as long as integration is not available
-    forces(0, 1) = q * L / 2;
-    forces(0, 2) = q * L * L / 12;
-    forces(1, 1) = q * L / 2;
-    forces(1, 2) = -q * L * L / 12;
-#else
-    auto & group = mesh.createElementGroup("lin_force");
-    group.add({type, 0, _not_ghost});
-    Vector<Real> lin_force = {0, q, 0};
-    // a linear force is not actually a *boundary* condition
-    // it is equivalent to a volume force
-    model.applyBC(BC::Neumann::FromSameDim(lin_force), group);
-#endif
-    forces(2, 0) = mat.E * mat.A / 18;
-  }
+  void setNeumanns() override {}
 
 protected:
   StructuralMaterial mat;
 };
 
 /* -------------------------------------------------------------------------- */
 
-TEST_F(TestStructBernoulli2, TestDisplacements) {
-  auto d1 = model->getDisplacement()(1, 2);
-  auto d2 = model->getDisplacement()(2, 2);
-  auto d3 = model->getDisplacement()(1, 0);
+// Batoz Vol 2. patch test, ISBN 2-86601-259-3
+TEST_F(TestStructDKT18, TestDisplacements) {
+  model->solveStep();
+  model->getDOFManager().getMatrix("K").saveMatrix("K.mtx");
+  model->getDOFManager().getMatrix("J").saveMatrix("J.mtx");
+  Vector<Real> solution = {22.5, 22.5, -337.5, -22.5, 22.5, 0};
+  auto nb_nodes = this->model->getDisplacement().size();
+
+  Vector<Real> center_node_disp =
+      model->getDisplacement().begin(solution.size())[nb_nodes - 1];
+
+  std::cout << center_node_disp << std::endl;
+
+  auto error = solution - center_node_disp;
 
   Real tol = Math::getTolerance();
 
-  EXPECT_NEAR(d1, 5.6 / 4800, tol);  // first rotation
-  EXPECT_NEAR(d2, -3.7 / 4800, tol); // second rotation
-  EXPECT_NEAR(d3, 10. / 18, tol);    // axial deformation
+  EXPECT_NEAR(error.norm<L_2>(), 0., tol);
 }
diff --git a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh
index cd92c3e5d..a1f5f221e 100644
--- a/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh
+++ b/test/test_model/test_structural_mechanics_model/test_structural_mechanics_model_fixture.hh
@@ -1,76 +1,75 @@
 /* -------------------------------------------------------------------------- */
 #include "element_class_structural.hh"
 #include "structural_mechanics_model.hh"
 #include "test_gtest_utils.hh"
 /* -------------------------------------------------------------------------- */
 #include <gtest/gtest.h>
 #include <vector>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_TEST_STRUCTURAL_MECHANICS_MODEL_FIXTURE_HH__
 #define __AKANTU_TEST_STRUCTURAL_MECHANICS_MODEL_FIXTURE_HH__
 
 using namespace akantu;
 
 template <typename type_> class TestStructuralFixture : public ::testing::Test {
 public:
   static constexpr const ElementType type = type_::value;
   static constexpr const size_t spatial_dimension =
       ElementClass<type>::getSpatialDimension();
   static const UInt ndof = ElementClass<type>::getNbDegreeOfFreedom();
 
   void SetUp() override {
     const auto spatial_dimension = this->spatial_dimension;
     mesh = std::make_unique<Mesh>(spatial_dimension);
     readMesh(makeMeshName());
 
     std::stringstream element_type;
     element_type << this->type;
     model = std::make_unique<StructuralMechanicsModel>(*mesh, _all_dimensions,
                                                        element_type.str());
 
     addMaterials();
     model->initFull();
     assignMaterials();
     setDirichlets();
     setNeumanns();
-    model->solveStep();
   }
 
   virtual void readMesh(std::string filename) {
     mesh->read(filename, _miot_gmsh_struct);
   }
 
   virtual std::string makeMeshName() {
     std::stringstream element_type;
     element_type << type;
     SCOPED_TRACE(element_type.str().c_str());
     return element_type.str() + ".msh";
   }
 
   void TearDown() override {
     model.reset(nullptr);
     mesh.reset(nullptr);
   }
 
   virtual void addMaterials() = 0;
   virtual void assignMaterials() = 0;
   virtual void setDirichlets() = 0;
   virtual void setNeumanns() = 0;
 
 protected:
   std::unique_ptr<Mesh> mesh;
   std::unique_ptr<StructuralMechanicsModel> model;
 };
 
 template <typename type_>
 constexpr ElementType TestStructuralFixture<type_>::type;
 template <typename type_>
 constexpr size_t TestStructuralFixture<type_>::spatial_dimension;
 template <typename type_> const UInt TestStructuralFixture<type_>::ndof;
 
 // using types = gtest_list_t<StructuralTestElementTypes>;
 
 // TYPED_TEST_CASE(TestStructuralFixture, types);
 
 #endif /* __AKANTU_TEST_STRUCTURAL_MECHANICS_MODEL_FIXTURE_HH__ */
diff --git a/third-party/iohelper/src/iohelper_common.hh b/third-party/iohelper/src/iohelper_common.hh
index 7acab3a40..f12affbad 100644
--- a/third-party/iohelper/src/iohelper_common.hh
+++ b/third-party/iohelper/src/iohelper_common.hh
@@ -1,295 +1,298 @@
 /**
  * @file   iohelper_common.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Thu Mar 11 2010
  * @date last modification: Thu Oct 10 2013
  *
  * @brief  header for common types
  *
  * @section LICENSE
  *
  * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * IOHelper 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.
  *
  * IOHelper 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 IOHelper. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #ifndef __IOHELPER_COMMON_H__
 #define __IOHELPER_COMMON_H__
 /* -------------------------------------------------------------------------- */
 
 #define USING_ZLIB
 #include <iostream>
 #include <string>
 #include <sstream>
 
 #define __BEGIN_IOHELPER__ namespace iohelper {
 #define __END_IOHELPER__ }
 
 #include <string.h>
 #include <stdlib.h>
 
 
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_IOHELPER__
 
 using UInt = unsigned int;
 using Int = int;
 using Real = double;
 
 /* -------------------------------------------------------------------------- */
 enum DataType {
   _bool,
   _uint,
   _int,
   _float,
   _double,
   _int64,
   _uint64
 };
 
 enum IndexingMode{
   C_MODE       = 0,
   FORTRAN_MODE = 1
 };
 
 /* -------------------------------------------------------------------------- */
 
 #if __cplusplus <= 199711L
 enum ElemType {
 #else
 enum ElemType : unsigned int {
 #endif
   TRIANGLE1 ,
   TRIANGLE2 ,
   TETRA1    ,
   TETRA2    ,
   POINT_SET ,
   LINE1     ,
   LINE2     ,
   QUAD1     ,
   QUAD2     ,
   HEX1      ,
   HEX2      ,
   BEAM2     ,
   BEAM3     ,
   PRISM1    ,
   PRISM2    ,
+  COH1D2    ,
   COH2D4    ,
   COH2D6    ,
   COH3D6    ,
   COH3D12   ,
   COH3D8    ,
   MAX_ELEM_TYPE
 };
 
 /* -------------------------------------------------------------------------- */
 
 enum FileStorageMode{
   TEXT       = 0,
   BASE64     = 1,
   COMPRESSED = 2
 };
 
 enum TextDumpMode {
   _tdm_space,
   _tdm_csv
 };
 
 /* -------------------------------------------------------------------------- */
 static UInt nb_node_per_elem[MAX_ELEM_TYPE] __attribute__((unused)) = {
   3,   // TRIANGLE1
   6,   // TRIANGLE2
   4,   // TETRA1
  10,   // TETRA2
   1,   // POINT_SET
   2,   // LINE1
   3,   // LINE2
   4,   // QUAD1
   8,   // QUAD2
   8,   // HEX1
  20,   // HEX2
   2,   // BEAM2
   2,   // BEAM3
   6,   // PRISM1
  15,   // PRISM2
+  2,   // COH1D2
   4,   // COH2D4
   6,   // COH2D6
   6,   // COH3D6
  12,   // COH3D12
   8,   // COH3D8
 };
 
 /* -------------------------------------------------------------------------- */
 static UInt nb_quad_points[MAX_ELEM_TYPE] __attribute__((unused)) = {
   1,   // TRIANGLE1
   3,   // TRIANGLE2
   1,   // TETRA1
   4,   // TETRA2
   0,   // POINT_SET
   1,   // LINE1
   2,   // LINE2
   4,   // QUAD1
   9,   // QUAD2
   8,   // HEX1
  27,   // HEX2
   2,   // BEAM2
   3,   // BEAM3
   6,   // PRISM1
   8,   // PRISM2
+  1,   // COH1D2
   1,   // COH2D4
   2,   // COH2D6
   1,   // COH3D6
   3,   // COH3D12
   1,   // COH3D8
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 class IOHelperVector {
 public:
   virtual ~IOHelperVector() = default;
 
   inline IOHelperVector(T * ptr, UInt size){
     this->ptr = ptr;
     this->_size = size;
   };
 
   inline UInt size() const {return _size;};
 
   inline const T & operator[] (UInt i) const {
     return ptr[i];
   };
 
   inline const T * getPtr() const {
     return ptr;
   };
 
 private:
   T* ptr;
   UInt _size;
 };
 
 /* -------------------------------------------------------------------------- */
 /* Iterator interface                                                         */
 /* -------------------------------------------------------------------------- */
 template< typename T, class daughter, class ret_cont = IOHelperVector<T> > class iterator {
 public:
   using type = ret_cont;
 
   virtual ~iterator() = default;
   virtual bool operator!=(const daughter & it) const = 0;
   virtual daughter & operator++() = 0;
   virtual ret_cont operator*() = 0;
   //! This function is only for the element iterators
   virtual ElemType element_type() { return MAX_ELEM_TYPE; }
 };
 
 /* -------------------------------------------------------------------------- */
 
 class IOHelperException : public std::exception {
 
 public:
   enum ErrorType {
     _et_non_homogeneous_data,
     _et_unknown_visitor_stage,
     _et_file_error,
     _et_missing_field,
     _et_data_type,
     _et_options_error
 };
 
 public:
   IOHelperException(const std::string & message,
                     const ErrorType type) noexcept {
     this->message = message;
     this->type    = type;
   };
 
   ~IOHelperException() noexcept override = default;
 
   const char * what() const noexcept override { return message.c_str(); };
 
 private:
 
   std::string message;
   ErrorType type;
 };
 
 /* -------------------------------------------------------------------------- */
 
 #define IOHELPER_THROW(x,type) {					\
     std::stringstream ioh_throw_sstr;					\
     ioh_throw_sstr << __FILE__ << ":" << __LINE__ << ":"		\
 		   << __PRETTY_FUNCTION__ << ": " << x;			\
     std::string ioh_message(ioh_throw_sstr.str());			\
     throw ::iohelper::IOHelperException(ioh_message,			\
 					::iohelper::IOHelperException::type); \
   }
 
 /* -------------------------------------------------------------------------- */
 
 
 template <typename T> DataType getDataType();
 
 #define DEFINE_GET_DATA_TYPE(type, data_type )				\
   template <> inline DataType getDataType<type>() { return data_type; }
 
 DEFINE_GET_DATA_TYPE(bool, _bool)
 DEFINE_GET_DATA_TYPE(ElemType, _int)
 DEFINE_GET_DATA_TYPE(int, _int)
 DEFINE_GET_DATA_TYPE(unsigned int, _uint)
 DEFINE_GET_DATA_TYPE(float, _float)
 DEFINE_GET_DATA_TYPE(double, _double)
 DEFINE_GET_DATA_TYPE(long int, _int64)
 DEFINE_GET_DATA_TYPE(unsigned long int, _uint64)
 
 #undef DEFINE_GET_DATA_TYPE
 
 inline std::ostream & operator <<(std::ostream & stream,  DataType type)
 {
   switch(type)
     {
     case _bool   : stream << "bool"    ; break;
     case _uint   : stream << "uint32"  ; break;
     case _int	 : stream << "int32"   ; break;
     case _float  : stream << "float32" ; break;
     case _double : stream << "float64" ; break;
     case _uint64 : stream << "uint64"  ; break;
     case _int64	 : stream << "int64"   ; break;
     }
   return stream;
 }
 
 inline std::ostream & operator <<(std::ostream & stream,  TextDumpMode mode)
 {
   switch(mode)
     {
     case _tdm_space : stream << "space" ; break;
     case _tdm_csv   : stream << "csv"   ; break;
     }
   return stream;
 }
 
 
 __END_IOHELPER__
 
 #endif /* __IOHELPER_COMMON_H__ */
diff --git a/third-party/iohelper/src/paraview_helper.cc b/third-party/iohelper/src/paraview_helper.cc
index 7f2447257..2d6840453 100644
--- a/third-party/iohelper/src/paraview_helper.cc
+++ b/third-party/iohelper/src/paraview_helper.cc
@@ -1,312 +1,313 @@
 /**
  * @file   paraview_helper.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Oct 12 2012
  * @date last modification: Wed Jun 05 2013
  *
  * @brief  implementation of paraview helper
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * IOHelper 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.
  *
  * IOHelper 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 IOHelper. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 #include "paraview_helper.hh"
 #include <fstream>
 
 
 /* -------------------------------------------------------------------------- */
 #if defined(__INTEL_COMPILER)
 /// remark #981: operands are evaluated in unspecified order
 #pragma warning ( disable : 981 )
 /// remark #383: value copied to temporary, reference to temporary used
 #pragma warning ( disable : 383 )
 #endif //defined(__INTEL_COMPILER)
 
 __BEGIN_IOHELPER__
 
 /* -------------------------------------------------------------------------- */
 ParaviewHelper::ParaviewHelper(File & f, UInt mode):
   b64(f), file(f), position_flag(false) {
   bflag = BASE64;
   compteur = 0;
   setMode(mode);
 
   this->paraview_code_type[TRIANGLE1] = VTK_TRIANGLE;
   this->paraview_code_type[TRIANGLE2] = VTK_QUADRATIC_TRIANGLE;
   this->paraview_code_type[TETRA1   ] = VTK_TETRA;
   this->paraview_code_type[TETRA2   ] = VTK_QUADRATIC_TETRA;
   this->paraview_code_type[POINT_SET] = VTK_POLY_VERTEX;
   this->paraview_code_type[LINE1    ] = VTK_LINE;
   this->paraview_code_type[LINE2    ] = VTK_QUADRATIC_EDGE;
   this->paraview_code_type[QUAD1    ] = VTK_QUAD;
   this->paraview_code_type[QUAD2    ] = VTK_QUADRATIC_QUAD;
   this->paraview_code_type[HEX1     ] = VTK_HEXAHEDRON;
   this->paraview_code_type[HEX2     ] = VTK_QUADRATIC_HEXAHEDRON;
   this->paraview_code_type[BEAM2    ] = VTK_LINE;
   this->paraview_code_type[BEAM3    ] = VTK_LINE;
   this->paraview_code_type[PRISM1   ] = VTK_WEDGE;
   this->paraview_code_type[PRISM2   ] = VTK_QUADRATIC_WEDGE;
+  this->paraview_code_type[COH1D2   ] = VTK_LINE;
   this->paraview_code_type[COH2D4   ] = VTK_POLYGON;
   this->paraview_code_type[COH2D6   ] = VTK_POLYGON;
   this->paraview_code_type[COH3D6   ] = VTK_WEDGE;
   this->paraview_code_type[COH3D12  ] = VTK_QUADRATIC_LINEAR_WEDGE;
   this->paraview_code_type[COH3D8   ] = VTK_HEXAHEDRON;
 
 
   std::map<ElemType, VTKCellType>::iterator it;
   for(it = paraview_code_type.begin();
       it != paraview_code_type.end(); ++it) {
     UInt nb_nodes = nb_node_per_elem[it->first];
 
     UInt * tmp = new UInt[nb_nodes];
     for (UInt i = 0; i < nb_nodes; ++i) {
       tmp[i] = i;
     }
 
     switch(it->first) {
     case COH3D12:
       tmp[ 0] = 0;
       tmp[ 1] = 1;
       tmp[ 2] = 2;
       tmp[ 3] = 6;
       tmp[ 4] = 7;
       tmp[ 5] = 8;
       tmp[ 6] = 3;
       tmp[ 7] = 4;
       tmp[ 8] = 5;
       tmp[ 9] = 9;
       tmp[10] = 10;
       tmp[11] = 11;
       break;
     case COH2D6:
       tmp[0] = 0;
       tmp[1] = 2;
       tmp[2] = 1;
       tmp[3] = 4;
       tmp[4] = 5;
       tmp[5] = 3;
       break;
     case COH2D4:
       tmp[0] = 0;
       tmp[1] = 1;
       tmp[2] = 3;
       tmp[3] = 2;
       break;
     case HEX2:
       tmp[12] = 16;
       tmp[13] = 17;
       tmp[14] = 18;
       tmp[15] = 19;
       tmp[16] = 12;
       tmp[17] = 13;
       tmp[18] = 14;
       tmp[19] = 15;
       break;
     case PRISM2:
       tmp[ 0] =  0;
       tmp[ 1] =  1;
       tmp[ 2] =  2;
       
       tmp[ 3] =  3;
       tmp[ 4] =  4;
       tmp[ 5] =  5;
       
       tmp[ 6] =  6;
       tmp[ 7] =  7;
       tmp[ 8] =  8;
 
       tmp[ 9] = 12;
       tmp[10] = 13;
       tmp[11] = 14;
       
       tmp[12] = 9;
       tmp[13] = 10;
       tmp[14] = 11;
       
       break;
     default:
       //nothing to change
       break;
     }
     this->write_reorder[it->first] = tmp;
   }
 
 }
 
 /* -------------------------------------------------------------------------- */
 ParaviewHelper::~ParaviewHelper(){
   std::map<ElemType, VTKCellType>::iterator it;
   for(it = this->paraview_code_type.begin();
       it != this->paraview_code_type.end(); ++it) {
     delete [] this->write_reorder[it->first];
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::writeTimePVD(const std::string & filename,
 				  const std::vector< std::pair<Real, std::string> > & pvtus) {
   std::ofstream pvd_file;
   pvd_file.open(filename.c_str());
 
   if(!pvd_file.good()) {
     IOHELPER_THROW("DumperParaview was not able to open the file \"" << filename, _et_file_error);
   }
 
   pvd_file << "<?xml version=\"1.0\"?>" << std::endl
 	   << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl
 	   << "  <Collection>" << std::endl;
 
   std::vector< std::pair<Real, std::string> >::const_iterator it  = pvtus.begin();
   std::vector< std::pair<Real, std::string> >::const_iterator end = pvtus.end();
   for (;it != end; ++it) {
     pvd_file << "    <DataSet timestep=\"" << it->first << "\" group=\"\" part=\"0\" file=\""
 	     << it->second << "\"/>" << std::endl;
   }
 
   pvd_file << "  </Collection>" << std::endl
 	   << "</VTKFile>" << std::endl;
   pvd_file.close();
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::writeHeader(int nb_nodes,int nb_elems){
   file << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" " ;
   file << "byte_order=\"LittleEndian\">" << std::endl;
   file << " <UnstructuredGrid>" << std::endl
        << "  <Piece NumberOfPoints= \""
        << nb_nodes << "\" NumberOfCells=\""
        << nb_elems << "\">" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::PDataArray(const std::string & name, int nb_components, const std::string & type){
   file << "   <PDataArray type=\"" << type << "\" NumberOfComponents=\""
        << nb_components << "\" Name=\"" << name << "\" format=\"";
   if (bflag == BASE64) file << "binary";
   else file << "ascii";
 
   file << "\"></PDataArray>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::write_conclusion(){
   file << "  </Piece>" << std::endl;
   file << " </UnstructuredGrid>" << std::endl;
   file << "</VTKFile>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startData(const std::string & name,
 			       int nb_components,
 			       const std::string & type){
 
   file << "    <DataArray type=\"" << type << "\" ";
   if (nb_components) file << "NumberOfComponents=\"" << nb_components << "\" ";
 
   file << "Name=\"" << name << "\" format=\"";
   if (bflag == BASE64) file << "binary";
   else file << "ascii";
   file << "\">" << std::endl;
   if (bflag == BASE64) b64.CreateHeader();
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endData(){
   if (bflag == BASE64) b64.WriteHeader();
   file << std::endl << "    </DataArray>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startDofList(int dimension){
   file << "   <Points>" << std::endl;
   startData("positions", dimension, "Float64");
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endDofList(){
   endData();
   file << "   </Points>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startCells(){
   file << "   <Cells>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endCells(){
   file << "   </Cells>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startCellsConnectivityList(){
   startData("connectivity",0,"Int32");
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endCellsConnectivityList(){
   endData();
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startCellsoffsetsList(){
   startData("offsets",0,"Int32");
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endCellsoffsetsList(){
   endData();
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startCellstypesList(){
   startData("types",0,"UInt32");
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endCellstypesList(){
   endData();
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startPointDataList(){
   file << "   <PointData>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endPointDataList(){
   file << "   </PointData>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::startCellDataList(){
   file << "   <CellData>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 void ParaviewHelper::endCellDataList(){
   file << "   </CellData>" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 
 __END_IOHELPER__