diff --git a/cmake/AkantuTestsMacros.cmake b/cmake/AkantuTestsMacros.cmake
index 27e4e1be0..85bc9cdea 100644
--- a/cmake/AkantuTestsMacros.cmake
+++ b/cmake/AkantuTestsMacros.cmake
@@ -1,473 +1,474 @@
 #===============================================================================
 # @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>...]
       [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()
 
 # ==============================================================================
 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})
 
   set(AKANTU_${_u_dir}_GTEST_SOURCE "" CACHE INTERNAL "")
 
   # add the sub-directory
   add_subdirectory(${dir})
 
   if(AKANTU_${_u_dir}_GTEST_SOURCE)
     set(_srcs)
     foreach(_src ${AKANTU_${_u_dir}_GTEST_SOURCE})
       list(APPEND _srcs ${dir}/${_src})
     endforeach()
 
     add_executable(${dir}_gtest_all ${PROJECT_SOURCE_DIR}/test/test_gtest_main.cc ${_srcs})
     target_link_libraries(${dir}_gtest_all akantu GTest::GTest GTest::Main)
+    target_include_directories(${dir}_gtest_all PRIVATE ${PROJECT_SOURCE_DIR}/test)
     set_property(TARGET ${dir}_gtest_all PROPERTY OUTPUT_NAME ${dir}/gtest_all)
 
     add_test(NAME ${dir}_gtest COMMAND ${AKANTU_DRIVER_SCRIPT}  -n "${dir}" -e "gtest_all" -w "${CMAKE_CURRENT_BINARY_DIR}/${dir}")
   endif()
   
   # 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(register_test test_name)
   set(flags
     GTEST
     UNSTABLE
     PARALLEL
     )
   set(one_variables
     POSTPROCESS
     SCRIPT
     )
   set(multi_variables
     SOURCES
     FILES_TO_COPY
     DEPENDS
     DIRECTORIES_TO_CREATE
     COMPILE_OPTIONS
     EXTRA_FILES
     LINK_LIBRARIES
     PACKAGE
     PARALLEL_LEVEL
     )
 
   cmake_parse_arguments(_register_test
     "${flags}"
     "${one_variables}"
     "${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()
 
   # 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()
 
   # todo this should be checked for the build package_sources since the file will not be listed.
   if(_test_act)
     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)
 
     string(TOUPPER ${_akantu_current_parent_test} _u_parent)
 
     if(AKANTU_BUILD_${_u_parent} OR AKANTU_BUILD_ALL_TESTS)
       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(
           AKANTU_EXTERNAL_INCLUDE_DIR
           AKANTU_EXTERNAL_LIBRARIES
           )
 
 
         if(NOT _register_test_GTEST)
           # 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)
           target_link_libraries(${test_name} akantu ${_register_test_LINK_LIBRARIES})
 
           if(_register_test_DEPENDS)
             add_dependencies(${test_name} ${_register_test_DEPENDS})
           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(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND  CMAKE_BUILD_TYPE STREQUAL "Debug")
             set(AKANTU_EXTRA_CXX_FLAGS "${AKANTU_EXTRA_CXX_FLAGS} -no-pie")
           endif()
           if(AKANTU_EXTRA_CXX_FLAGS)
             set_target_properties(${test_name}
               PROPERTIES COMPILE_FLAGS "${AKANTU_EXTRA_CXX_FLAGS}")
           endif()
         else()
           set(_list ${AKANTU_${_u_parent}_GTEST_SOURCE})
           list(APPEND _list ${_compile_source})
           set(AKANTU_${_u_parent}_GTEST_SOURCE ${_list} CACHE INTERNAL "")
         endif()
       else()
         if(_register_test_UNPARSED_ARGUMENTS AND NOT _register_test_SCRIPT)
           set(_register_test_SCRIPT ${_register_test_UNPARSED_ARGUMENTS})
         endif()
       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 .)
         list(APPEND _arguments -e "${_register_test_SCRIPT}")
       elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.sh")
         file(COPY ${test_name}.sh DESTINATION .)
         list(APPEND _arguments -e "${test_name}.sh")
       else()
         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_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}")
 
       if(NOT _register_test_GTEST)
         
         # register them test
         if(_procs)
           foreach(p ${_procs})
             add_test(NAME ${test_name}_${p} COMMAND ${AKANTU_DRIVER_SCRIPT} ${_arguments} -N ${p})
           endforeach()
         else()
           add_test(NAME ${test_name} COMMAND ${AKANTU_DRIVER_SCRIPT} ${_arguments})
         endif()
       endif()
     endif()
   endif()
 
   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})
       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 estra 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/src/common/aka_compatibilty_with_cpp_standard.hh b/src/common/aka_compatibilty_with_cpp_standard.hh
index 154f339f1..9aa4fb8af 100644
--- a/src/common/aka_compatibilty_with_cpp_standard.hh
+++ b/src/common/aka_compatibilty_with_cpp_standard.hh
@@ -1,132 +1,143 @@
 /**
  * @file   aka_compatibilty_with_cpp_standard.hh
  *
  * @author Nicolas Richart
  *
  * @date creation  Wed Oct 25 2017
  *
  * @brief The content of this file is taken from the possible implementations on
  * http://en.cppreference.com
  *
  * @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 <type_traits>
 #include <utility>
 #include <tuple>
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH__
 #define __AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH__
 
 namespace aka {
 
 // Part taken from C++14
 #if __cplusplus < 201402L
 template <bool B, class T = void>
 using enable_if_t = typename enable_if<B, T>::type;
 #else
 template <bool B, class T = void>
 using enable_if_t = std::enable_if_t<B, T>;
 #endif
 
 // Part taken from C++17
 #if __cplusplus < 201703L
 // bool_constant
 template <bool B> using bool_constant = std::integral_constant<bool, B>;
 namespace {
   template <bool B> constexpr bool bool_constant_v = bool_constant<B>::value;
 }
+/* -------------------------------------------------------------------------- */
 
 // conjunction
 template <class...> struct conjunction : std::true_type {};
 template <class B1> struct conjunction<B1> : B1 {};
 template <class B1, class... Bn>
 struct conjunction<B1, Bn...>
     : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
 
+/* -------------------------------------------------------------------------- */
+
+// negations
+template<class B>
+struct negation : bool_constant<!bool(B::value)> { };
+
+
+/* -------------------------------------------------------------------------- */
+
+
 namespace detail {
   // template <class T>
   // struct is_reference_wrapper : std::false_type {};
   // template <class U>
   // struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {};
   // template <class T>
   // constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value;
 
   template <class T, class Type, class T1, class... Args>
   decltype(auto) INVOKE(Type T::*f, T1 && t1, Args &&... args) {
     static_assert(std::is_member_function_pointer<decltype(f)>{} and
                       std::is_base_of<T, std::decay_t<T1>>{},
                   "Does not know what to do with this types");
     return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
   }
 
   // template <class T, class Type, class T1, class... Args>
   // decltype(auto) INVOKE(Type T::*f, T1 && t1, Args &&... args) {
   //   if constexpr (std::is_member_function_pointer_v<decltype(f)>) {
   //     if constexpr (std::is_base_of_v<T, std::decay_t<T1>>)
   //       return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
   //     else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
   //       return (t1.get().*f)(std::forward<Args>(args)...);
   //     else
   //       return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
   //   } else {
   //     static_assert(std::is_member_object_pointer_v<decltype(f)>);
   //     static_assert(sizeof...(args) == 0);
   //     if constexpr (std::is_base_of_v<T, std::decay_t<T1>>)
   //       return std::forward<T1>(t1).*f;
   //     else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
   //       return t1.get().*f;
   //     else
   //       return (*std::forward<T1>(t1)).*f;
   //   }
   // }
 
   template <class F, class... Args>
   decltype(auto) INVOKE(F && f, Args &&... args) {
     return std::forward<F>(f)(std::forward<Args>(args)...);
   }
 } // namespace detail
 
 template <class F, class... Args>
 decltype(auto) invoke(F && f, Args &&... args) {
   return detail::INVOKE(std::forward<F>(f), std::forward<Args>(args)...);
 }
 
 namespace detail {
   template <class F, class Tuple, std::size_t... Is>
   constexpr decltype(auto) apply_impl(F && f, Tuple && t,
                                       std::index_sequence<Is...>) {
     return invoke(std::forward<F>(f),
                   std::get<Is>(std::forward<Tuple>(t))...);
   }
 } // namespace detail
 
 template <class F, class Tuple>
 constexpr decltype(auto) apply(F && f, Tuple && t) {
   return detail::apply_impl(
       std::forward<F>(f), std::forward<Tuple>(t),
       std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{});
 }
 
 #endif
 } // namespace aka
 
 #endif /* __AKANTU_AKA_COMPATIBILTY_WITH_CPP_STANDARD_HH__ */
diff --git a/test/test_fe_engine/CMakeLists.txt b/test/test_fe_engine/CMakeLists.txt
index 8c53658bb..57a63303a 100644
--- a/test/test_fe_engine/CMakeLists.txt
+++ b/test/test_fe_engine/CMakeLists.txt
@@ -1,94 +1,113 @@
 #===============================================================================
 # @file   CMakeLists.txt
 #
 # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
 #
 # @date creation: Fri Sep 03 2010
 # @date last modification: Mon Dec 07 2015
 #
 # @brief  configuration for FEM 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
 #
 #===============================================================================
 
 #===============================================================================
 function(register_fem_test operation type)
   set(_target test_${operation}${type})
 
   register_test(${_target}
     SOURCES test_${operation}.cc
     FILES_TO_COPY ${type}.msh
     COMPILE_OPTIONS TYPE=${type}
     PACKAGE core
     )
 endfunction()
 
 #===============================================================================
 package_get_element_types(core _types)
 
 foreach(_type ${_types})
   if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_type}.msh)
     register_fem_test(fe_engine_precomputation ${_type})
-    register_fem_test(fe_engine_gauss_integration ${_type})
-    register_fem_test(interpolate ${_type})
-    register_fem_test(gradient    ${_type})
-    register_fem_test(integrate   ${_type})
-    register_fem_test(inverse_map ${_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()
 
 
 #register_test(test_interpolate_bernoulli_beam_2 test_interpolate_bernoulli_beam_2.cc)
 #add_mesh(test_fem_circle_1_mesh circle.geo 2 1 OUTPUT circle1.msh)
 #add_mesh(test_fem_circle_2_mesh circle.geo 2 2 OUTPUT circle2.msh)
 
 # Tests for class MeshData
 macro(register_typed_test test_name type value1 value2)
   set(target test_${test_name}_${type})
   register_test(${target}
     SOURCES test_${test_name}.cc
     COMPILE_OPTIONS "TYPE=${type};VALUE1=${value1};VALUE2=${value2}"
     PACKAGE core
     )
 endmacro()
 
 register_typed_test(mesh_data string \"5\" \"10\")
 register_typed_test(mesh_data UInt 5 10)
 
 add_mesh(test_boundary_msh cube.geo 3 1)
 add_mesh(test_boundary_msh_physical_names cube_physical_names.geo 3 1)
 
 register_test(test_mesh_boundary
   SOURCES test_mesh_boundary.cc
   DEPENDS test_boundary_msh test_boundary_msh_physical_names
   PACKAGE core)
 
 register_test(test_facet_element_mapping
   SOURCES test_facet_element_mapping.cc
   DEPENDS test_boundary_msh_physical_names
   PACKAGE core)
 
+
+register_test(test_fe_engine_gauss_integration
+  SOURCES test_fe_engine_gauss_integration.cc
+  PACKAGE core
+  GTEST
+  )
+
+register_test(test_gradient
+  SOURCES test_gradient.cc
+  PACKAGE core
+  GTEST
+  )
+
+register_test(test_integrate
+  SOURCES test_integrate.cc
+  PACKAGE core
+  GTEST
+  )
+
+register_test(test_inverse_map
+  SOURCES test_inverse_map.cc
+  PACKAGE core
+  GTEST
+  )
diff --git a/test/test_fe_engine/test_fe_engine_fixture.hh b/test/test_fe_engine/test_fe_engine_fixture.hh
new file mode 100644
index 000000000..78d18a7c2
--- /dev/null
+++ b/test/test_fe_engine/test_fe_engine_fixture.hh
@@ -0,0 +1,59 @@
+/* -------------------------------------------------------------------------- */
+#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>
+/* -------------------------------------------------------------------------- */
+
+using namespace akantu;
+
+template <typename type_> class TestFEMFixture : public ::testing::Test {
+public:
+  static constexpr const ElementType type = type_::value;
+  static constexpr const size_t dim = ElementClass<type>::getSpatialDimension();
+  using FEM = FEEngineTemplate<IntegratorGauss, ShapeLagrange>;
+
+  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";
+    mesh->read(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;
+
+    std::stringstream sstr;
+    sstr << type;
+    SCOPED_TRACE(sstr.str().c_str());
+  }
+
+  void TearDown() override {
+    fem.reset(nullptr);
+    mesh.reset(nullptr);
+  }
+
+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;
+};
+
+using types = gtest_list_t<TestElementTypes>;
+
+TYPED_TEST_CASE(TestFEMFixture, types);
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 815cc9ae8..4edf29f8e 100644
--- a/test/test_fe_engine/test_fe_engine_gauss_integration.cc
+++ b/test/test_fe_engine/test_fe_engine_gauss_integration.cc
@@ -1,203 +1,215 @@
 /**
  * @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 "fe_engine.hh"
-#include "shape_lagrange.hh"
-#include "integrator_gauss.hh"
+#include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
+#include <gtest/gtest.h>
 #include <iostream>
 /* -------------------------------------------------------------------------- */
 using namespace akantu;
 
-typedef FEEngineTemplate<IntegratorGauss, ShapeLagrange> FEM;
-const ElementType type = TYPE;
-
-//                        cst           x           x^2           x^3
-//                        x^4          x^5
-Real alpha[3][6] = {{0.40062394, 0.13703225, 0.51731446, 0.87830084, 0.5410543,
-                     0.71842292}, // x
-                    {0.41861835, 0.11080576, 0.49874043, 0.49077504, 0.85073835,
-                     0.66259755}, // y
-                    {0.92620845, 0.7503478, 0.62962232, 0.31662719, 0.64069644,
-                     0.30878135}}; // z
-
-static Vector<Real> eval_poly(UInt degree, const Vector<Real> & x) {
-  Vector<Real> res(x.size());
-  for (UInt i = 0; i < degree + 1; ++i) {
-    for (UInt d = 0; d < x.size(); ++d) {
-      res(d) += std::pow(x(d), i) * alpha[d][i];
-    }
+namespace {
+/* -------------------------------------------------------------------------- */
+template <size_t t> using degree_t = std::integral_constant<size_t, t>;
+
+/* -------------------------------------------------------------------------- */
+
+template <size_t degree> class Polynomial {
+public:
+  Polynomial() = default;
+
+  Polynomial(std::initializer_list<double> && init) {
+    for (auto && pair : zip(init, constants))
+      std::get<1>(pair) = std::get<0>(pair);
   }
-  return res;
-}
 
-static Vector<Real> eval_int(UInt degree, const Vector<Real> & a,
-                             const Vector<Real> & b) {
-  Vector<Real> res(a.size());
-  for (UInt i = 0; i < degree + 1; ++i) {
-    for (UInt d = 0; d < a.size(); ++d) {
-      res(d) += (std::pow(b(d), i + 1) - std::pow(a(d), i + 1)) * alpha[d][i] / Real(i + 1);
+  double operator()(double x) {
+    double res = 0.;
+    for (auto && vals : enumerate(constants)) {
+      double a;
+      int k;
+      std::tie(k, a) = vals;
+      res += a * std::pow(x, k);
     }
+    return res;
   }
 
-  if (a.size() == 3) {
-    res(_x) *= std::abs(b(_y) - a(_y)) * std::abs(b(_z) - a(_z));
-    res(_y) *= std::abs(b(_x) - a(_x)) * std::abs(b(_z) - a(_z));
-    res(_z) *= std::abs(b(_y) - a(_y)) * std::abs(b(_x) - a(_x));
-  } else if (a.size() == 2) {
-    res(_x) *= std::abs(b(_y) - a(_y));
-    res(_y) *= std::abs(b(_x) - a(_x));
+  Polynomial extract(size_t pdegree) {
+    Polynomial<degree> extract(*this);
+    for (size_t d = pdegree + 1; d < degree + 1; ++d)
+      extract.constants[d] = 0;
+    return extract;
   }
 
-  return res;
-}
-
-template <UInt degree>
-static Vector<Real> integrate_poly(UInt poly_degree, FEM & fem) {
-  Mesh & mesh = fem.getMesh();
-  UInt dim = mesh.getSpatialDimension();
-
-  Matrix<Real> integration_points =
-      fem.getIntegrator().getIntegrationPoints<type, degree>();
-
-  // Vector<Real> integration_weights =
-  //     fem.getIntegrator().getIntegrationWeights<type, degree>();
-
-  // for (UInt i = 0; i < integration_points.cols(); ++i) {
-  //   std::cout << "q(" << i << ") = " << Vector<Real>(integration_points(i))
-  //   << " - w(" << i << ") = "<< integration_weights[i] << std::endl;
-  // }
+  auto integral() {
+    Polynomial<degree + 1> integral_;
+    integral_.set(0, 0.);
+    ;
+    for (size_t d = 0; d < degree + 1; ++d) {
+      integral_.set(1 + d, get(d) / double(d + 1));
+    }
+    return integral_;
+  }
 
-  UInt nb_integration_points = integration_points.cols();
-  UInt nb_element = mesh.getNbElement(type);
+  auto integrate(double a, double b) {
+    auto primitive = integral();
+    return (primitive(b) - primitive(a));
+  }
 
-  UInt shapes_size = ElementClass<type>::getShapeSize();
-  Array<Real> shapes(0, shapes_size);
-  fem.getShapeFunctions().computeShapesOnIntegrationPoints<type>(
-      mesh.getNodes(), integration_points, shapes, _not_ghost);
+  double get(int i) const { return constants[i]; }
 
-  UInt vect_size = nb_integration_points * nb_element;
-  Array<Real> integration_points_pos(vect_size, dim);
-  fem.getShapeFunctions().interpolateOnIntegrationPoints<type>(
-      mesh.getNodes(), integration_points_pos, dim, shapes);
+  void set(int i, double a) { constants[i] = a; }
 
-  Array<Real> polynomial(vect_size, dim);
+protected:
+  std::array<double, degree + 1> constants;
+};
 
-  Array<Real>::vector_iterator P_it = polynomial.begin(dim);
-  Array<Real>::vector_iterator P_end = polynomial.end(dim);
-  Array<Real>::const_vector_iterator x_it = integration_points_pos.begin(dim);
+template <size_t degree>
+std::ostream & operator<<(std::ostream & stream, const Polynomial<degree> & p) {
+  for (size_t d = 0; d < degree + 1; ++d) {
+    if (d != 0)
+      stream << " + ";
 
-  for (; P_it != P_end; ++P_it, ++x_it) {
-    *P_it = eval_poly(poly_degree, *x_it);
-     //   std::cout << "Q = " << *x_it << std::endl;
-     //   std::cout << "P(Q) = " << *P_it << std::endl;
+    stream << p.get(degree - d);
+    if (d != degree)
+      stream << "x ^ " << degree - d;
   }
+  return stream;
+}
 
-  Vector<Real> res(dim);
+/* -------------------------------------------------------------------------- */
+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>{}};
+
+public:
+  TestGaussIntegrationFixture() : integration_points_pos(0, parent::dim) {}
+
+  void SetUp() override {
+    parent::SetUp();
+    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);
+    }
+  }
 
-  Array<Real> polynomial_1d(vect_size, 1);
-  for (UInt d = 0; d < dim; ++d) {
-    Array<Real>::const_vector_iterator P_it = polynomial.begin(dim);
-    Array<Real>::const_vector_iterator P_end = polynomial.end(dim);
-    Array<Real>::scalar_iterator P1_it = polynomial_1d.begin();
-    for (; P_it != P_end; ++P_it, ++P1_it) {
-      *P1_it = (*P_it)(d);
-      // std::cout << "P(Q, d) = " << *P1_it << std::endl;
+  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, this->degree == 0 ? 1 : this->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);
     }
-    res(d) = fem.getIntegrator().integrate<type, degree>(polynomial_1d);
   }
 
-  return res;
+protected:
+  UInt nb_integration_points;
+  std::array<Array<Real>, parent::dim> polynomial;
+  Array<Real> integration_points_pos;
+  std::array<Polynomial<5>, 3> polys;
+};
+
+/* -------------------------------------------------------------------------- */
+/* Tests                                                                      */
+/* -------------------------------------------------------------------------- */
+TYPED_TEST_CASE_P(TestGaussIntegrationFixture);
+
+TYPED_TEST_P(TestGaussIntegrationFixture, ArbitraryOrder) {
+  this->testIntegrate();
 }
 
-int main(int argc, char * argv[]) {
-  akantu::initialize(argc, argv);
-
-  const UInt dim = ElementClass<type>::getSpatialDimension();
-  Mesh mesh(dim);
-
-  std::stringstream meshfilename;
-  meshfilename << type << ".msh";
-  mesh.read(meshfilename.str());
-
-  FEM fem(mesh, dim, "my_fem");
-
-  const Vector<Real> & lower = mesh.getLowerBounds();
-  const Vector<Real> & upper = mesh.getUpperBounds();
-
-  bool ok = true;
-
-  for (UInt d = 0; d < 6; ++d) {
-    Vector<Real> res(dim);
-    switch (d) {
-    case 0:
-      res = integrate_poly<1>(d, fem);
-      break;
-    case 1:
-      res = integrate_poly<1>(d, fem);
-      break;
-    case 2:
-      res = integrate_poly<2>(d, fem);
-      break;
-    case 3:
-      res = integrate_poly<3>(d, fem);
-      break;
-    case 4:
-      res = integrate_poly<4>(d, fem);
-      break;
-    case 5:
-      res = integrate_poly<5>(d, fem);
-      break;
-    }
+REGISTER_TYPED_TEST_CASE_P(TestGaussIntegrationFixture, ArbitraryOrder);
 
-    Vector<Real> exact(dim);
-    exact = eval_int(d, lower, upper);
 
-    Vector<Real> error(dim);
-    error = exact - res;
+using TestTypes =
+    gtest_list_t<tuple_split_t<50, cross_product_t<TestElementTypes, TestDegreeTypes>>>;
 
-    Real error_n = error.norm<L_inf>();
-    if (error_n > 5e-14) {
-      std::cout << d << " -> Resultat " << res << " - ";
-      std::cout << "Exact" << exact << " -- ";
-      std::cout << error << " {" << error_n << "}" << std::endl;
-      ok = false;
-    }
-  }
+INSTANTIATE_TYPED_TEST_CASE_P(Split1, TestGaussIntegrationFixture, TestTypes);
+
+using TestTypesTail =
+    gtest_list_t<tuple_split_tail_t<50, cross_product_t<TestElementTypes, TestDegreeTypes>>>;
 
-  finalize();
+INSTANTIATE_TYPED_TEST_CASE_P(Split2, TestGaussIntegrationFixture, TestTypesTail);
 
-  if (ok)
-    return 0;
-  else
-    return 1;
 }
diff --git a/test/test_fe_engine/test_gradient.cc b/test/test_fe_engine/test_gradient.cc
index bba6656c4..edd30e6a9 100644
--- a/test/test_fe_engine/test_gradient.cc
+++ b/test/test_fe_engine/test_gradient.cc
@@ -1,144 +1,103 @@
 /**
  * @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 "fe_engine.hh"
-#include "shape_lagrange.hh"
-#include "integrator_gauss.hh"
+#include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <cstdlib>
 #include <iostream>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
-int main(int argc, char * argv[]) {
-  akantu::initialize(argc, argv);
-  debug::setDebugLevel(dblTest);
-
-  const ElementType type = TYPE;
-  UInt dim = ElementClass<type>::getSpatialDimension();
-
-  Real eps = 1e-12;
-  std::cout << "Epsilon : " << eps << std::endl;
-
-  Mesh my_mesh(dim);
-
-  std::stringstream meshfilename;
-  meshfilename << type << ".msh";
-  my_mesh.read(meshfilename.str());
-
-  FEEngine * fem = new FEEngineTemplate<IntegratorGauss, ShapeLagrange>(
-      my_mesh, dim, "my_fem");
-
-  fem->initShapeFunctions();
+namespace {
 
+TYPED_TEST(TestFEMFixture, GradientPoly) {
   Real alpha[2][3] = {{13, 23, 31}, {11, 7, 5}};
 
-  /// create the 2 component field
-  const Array<Real> & position = fem->getMesh().getNodes();
-  Array<Real> const_val(fem->getMesh().getNbNodes(), 2, "const_val");
+  const auto dim = this->dim;
+  const auto type = this->type;
 
-  UInt nb_element = my_mesh.getNbElement(type);
-  UInt nb_quadrature_points = fem->getNbIntegrationPoints(type) * nb_element;
+  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);
 
-  Array<Real> grad_on_quad(nb_quadrature_points, 2 * dim, "grad_on_quad");
-  for (UInt i = 0; i < const_val.size(); ++i) {
-    const_val(i, 0) = 0;
-    const_val(i, 1) = 0;
+    const_.set(0.);
 
     for (UInt d = 0; d < dim; ++d) {
-      const_val(i, 0) += alpha[0][d] * position(i, d);
-      const_val(i, 1) += alpha[1][d] * position(i, d);
+      const_(0) += alpha[0][d] * pos(d);
+      const_(1) += alpha[1][d] * pos(d);
     }
   }
 
   /// compute the gradient
-  fem->gradientOnIntegrationPoints(const_val, grad_on_quad, 2, type);
-
-  // std::cout << "Linear array on nodes : " << const_val << std::endl;
-  // std::cout << "Gradient on quad : " << grad_on_quad << std::endl;
+  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
-  Array<Real>::matrix_iterator it = grad_on_quad.begin(2, dim);
-  Array<Real>::matrix_iterator it_end = grad_on_quad.end(2, dim);
-  for (; it != it_end; ++it) {
+  for(auto && grad : make_view(grad_on_quad, 2, dim)) {
     for (UInt d = 0; d < dim; ++d) {
-      Matrix<Real> & grad = *it;
-      if (!(std::abs(grad(0, d) - alpha[0][d]) < eps) ||
-          !(std::abs(grad(1, d) - alpha[1][d]) < eps)) {
-        std::cout << "Error gradient is not correct " << (*it)(0, d) << " "
-                  << alpha[0][d] << " (" << std::abs((*it)(0, d) - alpha[0][d])
-                  << ")"
-                  << " - " << (*it)(1, d) << " " << alpha[1][d] << " ("
-                  << std::abs((*it)(1, d) - alpha[1][d]) << ")"
-                  << " - " << d << std::endl;
-        std::cout << *it << std::endl;
-        exit(EXIT_FAILURE);
-      }
+      EXPECT_NEAR(grad(0, d), alpha[0][d], 5e-13);
+      EXPECT_NEAR(grad(1, d), alpha[1][d], 5e-13);
     }
   }
+}
+
+TYPED_TEST(TestFEMFixture, GradientPositions) {
+  const auto dim = this->dim;
+  const auto type = this->type;
 
-  // compute gradient of coordinates
+  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");
-  fem->gradientOnIntegrationPoints(my_mesh.getNodes(), grad_coord_on_quad,
-                                   my_mesh.getSpatialDimension(), type);
-
-  // std::cout << "Node positions : " << my_mesh.getNodes() << std::endl;
-  // std::cout << "Gradient of nodes : " << grad_coord_on_quad << std::endl;
-
-  Array<Real>::matrix_iterator itp = grad_coord_on_quad.begin(dim, dim);
-  Array<Real>::matrix_iterator itp_end = grad_coord_on_quad.end(dim, dim);
-
-  for (; itp != itp_end; ++itp) {
-    for (UInt i = 0; i < dim; ++i) {
-      for (UInt j = 0; j < dim; ++j) {
-        if (!(std::abs((*itp)(i, j) - (i == j)) < eps)) {
-          std::cout << *itp << std::endl;
-          exit(EXIT_FAILURE);
-        }
-      }
-    }
-  }
 
-  delete fem;
-  finalize();
+  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);
+   }
+}
 
-  return EXIT_SUCCESS;
 }
diff --git a/test/test_fe_engine/test_integrate.cc b/test/test_fe_engine/test_integrate.cc
index f9ca9251d..40200579e 100644
--- a/test/test_fe_engine/test_integrate.cc
+++ b/test/test_fe_engine/test_integrate.cc
@@ -1,105 +1,75 @@
 /**
  * @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 "fe_engine.hh"
-#include "shape_lagrange.hh"
-#include "integrator_gauss.hh"
+#include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 #include <cstdlib>
 #include <iostream>
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
-int main(int argc, char *argv[]) {
-  akantu::initialize(argc, argv);
-
-  debug::setDebugLevel(dblTest);
-
-  const ElementType type = TYPE;
-  UInt dim = ElementClass<type>::getSpatialDimension();
-
-  Real eps = 3e-13;
-  std::cout << "Epsilon : " << eps << std::endl;
-
-  Mesh my_mesh(dim);
-
-  std::stringstream meshfilename; meshfilename << type << ".msh";
-  my_mesh.read(meshfilename.str());
+namespace {
 
-  FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange>(my_mesh, dim, "my_fem");
+TYPED_TEST(TestFEMFixture, IntegrateConstant) {
+  const auto type = this->type;
 
-  fem->initShapeFunctions();
+  const auto & position = this->fem->getMesh().getNodes();
 
-  UInt nb_element = my_mesh.getNbElement(type);
-  UInt nb_quadrature_points = fem->getNbIntegrationPoints(type) * nb_element;
+  Array<Real> const_val(position.size(), 2, "const_val");
+  Array<Real> val_on_quad(this->nb_quadrature_points_total, 2, "val_on_quad");
 
-  Array<Real> const_val(fem->getMesh().getNbNodes(), 2, "const_val");
-  Array<Real> val_on_quad(nb_quadrature_points, 2 , "val_on_quad");
-
-  for (UInt i = 0; i < const_val.size(); ++i) {
-    const_val.storage()[i * 2 + 0] = 1.;
-    const_val.storage()[i * 2 + 1] = 2.;
+  Vector<Real> value{1, 2};
+  for (auto && const_ : make_view(const_val, 2)) {
+    const_ = value;
   }
 
-  //interpolate function on quadrature points
-  fem->interpolateOnIntegrationPoints(const_val, val_on_quad, 2, type);
+  // interpolate function on quadrature points
+  this->fem->interpolateOnIntegrationPoints(const_val, val_on_quad, 2, type);
 
-  //integrate function on elements
-  akantu::Array<akantu::Real> int_val_on_elem(nb_element, 2, "int_val_on_elem");
-  fem->integrate(val_on_quad, int_val_on_elem, 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
-  Real value[2] = {0,0};
-  std::cout << "Val on quads : " << val_on_quad << std::endl;
-  std::cout << "Integral on elements : " << int_val_on_elem << std::endl;
-
-  for (UInt i = 0; i < fem->getMesh().getNbElement(type); ++i) {
-    value[0] += int_val_on_elem.storage()[2*i];
-    value[1] += int_val_on_elem.storage()[2*i+1];
-  }
+  Vector<Real> sum{0., 0.};
 
-  std::cout << "integral on the mesh of 1 is " << value[0] << " and of 2 is " << value[1] << std::endl;
-
-  delete fem;
-  finalize();
-
-  if(!(std::abs(value[0] - 1.) < eps && std::abs(value[1] - 2.) < eps)) {
-    std::cout << "|1 - " << value[0] << "| = " << std::abs(value[0] - 1.) << std::endl
-	      << "|2 - " << value[1] << "| = " << std::abs(value[1] - 2.) << std::endl;
-    return EXIT_FAILURE;
+  for (auto && int_ : make_view(int_val_on_elem, 2)) {
+    sum += int_;
   }
 
-  return EXIT_SUCCESS;
+  auto diff = (value - sum).template norm<L_inf>();
+  EXPECT_NEAR(0, diff, 1e-14);
 }
+
+} // namespace
diff --git a/test/test_fe_engine/test_interpolate.cc b/test/test_fe_engine/test_interpolate.cc
index 9b8d626fd..e01b59ec9 100644
--- a/test/test_fe_engine/test_interpolate.cc
+++ b/test/test_fe_engine/test_interpolate.cc
@@ -1,92 +1,72 @@
 /**
  * @file   test_interpolate.cc
  *
  * @author Nicolas Richart <nicolas.richart@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 "fe_engine.hh"
-#include "shape_lagrange.hh"
-#include "integrator_gauss.hh"
-/* -------------------------------------------------------------------------- */
-#include <cstdlib>
-#include <iostream>
+#include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 using namespace akantu;
 
-int main(int argc, char *argv[]) {
-  akantu::initialize(argc, argv);
-
-  debug::setDebugLevel(dblTest);
-  const ElementType type = TYPE;
-  UInt dim = ElementClass<type>::getSpatialDimension();
-
-  Real eps = 3e-13;
-  std::cout << "Epsilon : " << eps << std::endl;
-
-  Mesh my_mesh(dim);
-
-  std::stringstream meshfilename; meshfilename << type << ".msh";
-  my_mesh.read(meshfilename.str());
+namespace {
 
-  FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange>(my_mesh, dim, "my_fem");
+TYPED_TEST(TestFEMFixture, InterpolateConstant) {
+  const auto type = this->type;
 
-  fem->initShapeFunctions();
+  const auto & position = this->fem->getMesh().getNodes();
 
-  Array<Real> const_val(fem->getMesh().getNbNodes(), 2, "const_val");
+  Array<Real> const_val(position.size(), 2, "const_val");
+  Array<Real> val_on_quad(this->nb_quadrature_points_total, 2, "val_on_quad");
 
-  UInt nb_element = my_mesh.getNbElement(type);
-  UInt nb_quadrature_points = fem->getNbIntegrationPoints(type) * nb_element;
-
-  Array<Real> val_on_quad(nb_quadrature_points, 2, "val_on_quad");
-
-  for (UInt i = 0; i < const_val.size(); ++i) {
-    const_val.storage()[i * 2 + 0] = 1.;
-    const_val.storage()[i * 2 + 1] = 2.;
+  Vector<Real> value{1, 2};
+  for (auto && const_ : make_view(const_val, 2)) {
+    const_ = value;
   }
 
-  fem->interpolateOnIntegrationPoints(const_val, val_on_quad, 2, type);
+  // interpolate function on quadrature points
+  this->fem->interpolateOnIntegrationPoints(const_val, val_on_quad, 2, type);
 
-  std::cout << "Interpolation of array : " << const_val << std::endl;
-  std::cout << "Gives on quads : " << val_on_quad << std::endl;
+  for (auto && int_ : make_view(val_on_quad, 2)) {
+    auto diff = (value - int_).template norm<L_inf>();
+    EXPECT_NEAR(0, diff, 1e-14);
+  }
+}
 
-  // interpolate coordinates
-  Array<Real> coord_on_quad(nb_quadrature_points, my_mesh.getSpatialDimension(), "coord_on_quad");
+// TYPED_TEST(TestFEMFixture, InterpolatePosition) {
+//   const auto dim = this->dim;
+//   const auto type = this->type;
+//   const auto & position = this->fem->getMesh().getNodes();
 
-  fem->interpolateOnIntegrationPoints(my_mesh.getNodes(),
-				     coord_on_quad,
-				     my_mesh.getSpatialDimension(),
-				     type);
-  std::cout << "Interpolations of node coordinates : " << my_mesh.getNodes() << std::endl;
-  std::cout << "Gives : " << coord_on_quad << std::endl;
+//   Array<Real> coord_on_quad(this->nb_quadrature_points_total, dim,
+//                             "coord_on_quad");
 
-  delete fem;
-  finalize();
+//   this->fem->interpolateOnIntegrationPoints(position, coord_on_quad, dim, type);
+// }
 
-  return EXIT_SUCCESS;
-}
+} // namespace
diff --git a/test/test_fe_engine/test_inverse_map.cc b/test/test_fe_engine/test_inverse_map.cc
index daeac8134..34b2496c3 100644
--- a/test/test_fe_engine/test_inverse_map.cc
+++ b/test/test_fe_engine/test_inverse_map.cc
@@ -1,110 +1,72 @@
 /**
  * @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 "aka_common.hh"
-#include "aka_iterators.hh"
-#include "fe_engine.hh"
-#include "integrator_gauss.hh"
-#include "shape_lagrange.hh"
 /* -------------------------------------------------------------------------- */
-#include <iostream>
+#include "test_fe_engine_fixture.hh"
 /* -------------------------------------------------------------------------- */
 
 using namespace akantu;
 
-int main(int argc, char * argv[]) {
-  akantu::initialize(argc, argv);
-
-  const auto type = TYPE;
-  auto dim = ElementClass<type>::getSpatialDimension();
-
-  Mesh my_mesh(dim);
-  std::stringstream meshfilename;
-  meshfilename << type << ".msh";
-
-  my_mesh.read(meshfilename.str());
-
-  const auto & lower = my_mesh.getLowerBounds();
-  const auto & upper = my_mesh.getUpperBounds();
-  UInt nb_elements = my_mesh.getNbElement(type);
+namespace {
 
-  auto fem = std::make_unique<FEEngineTemplate<IntegratorGauss, ShapeLagrange>>(
-      my_mesh, dim, "my_fem");
+TYPED_TEST(TestFEMFixture, InverseMap) {
+  const auto type = this->type;
+  const auto dim = this->dim;
 
-  fem->initShapeFunctions();
   Matrix<Real> quad = GaussIntegrationElement<type>::getQuadraturePoints();
 
+  const auto & position = this->fem->getMesh().getNodes();
+
   /// get the quadrature points coordinates
-  Array<Real> coord_on_quad(quad.cols() * nb_elements,
-                            my_mesh.getSpatialDimension(), "coord_on_quad");
+  Array<Real> coord_on_quad(quad.cols() * this->nb_element, dim,
+                            "coord_on_quad");
 
-  fem->interpolateOnIntegrationPoints(my_mesh.getNodes(), coord_on_quad,
-                                      my_mesh.getSpatialDimension(), type);
+  this->fem->interpolateOnIntegrationPoints(position, coord_on_quad, dim, type);
 
   Vector<Real> natural_coords(dim);
 
-  /// loop over the quadrature points
-  auto it = coord_on_quad.begin_reinterpret(dim, quad.cols(), nb_elements);
-  auto end = coord_on_quad.end_reinterpret(dim, quad.cols(), nb_elements);
+  auto length = (this->upper - this->lower).template norm<L_inf>();
 
-  auto length = (upper - lower).norm<L_inf>();
+  for(auto && enum_ : enumerate(make_view(coord_on_quad, dim, quad.cols()))) {
+    auto el = std::get<0>(enum_);
+    const auto & quads_coords = std::get<1>(enum_);
 
-  auto eps = 5e-12;
-  UInt el = 0;
-  for (; it != end; ++it, ++el) {
-    const auto & quads_coords = *it;
     for (auto q : arange(quad.cols())) {
       Vector<Real> quad_coord = quads_coords(q);
       Vector<Real> ref_quad_coord = quad(q);
-      fem->inverseMap(quad_coord, el, type, natural_coords);
+      this->fem->inverseMap(quad_coord, el, type, natural_coords);
 
       auto dis_normalized = ref_quad_coord.distance(natural_coords) / length;
-      if (not(dis_normalized < eps)) {
-        std::cout << "Real coordinates inversion test failed : "
-                  << std::scientific << natural_coords << " - "
-                  << ref_quad_coord << " / " << length << " = " << dis_normalized << std::endl;
-        return 1;
-      }
-
-      // std::cout << "Real coordinates inversion : " << std::scientific
-      //           << natural_coords << " = " << ref_quad_coord << " ("
-      //           << dis_normalized << ")" << std::endl;
+      EXPECT_NEAR(0., dis_normalized, 5e-12);
     }
   }
-
-  std::cout << "inverse completed over " << nb_elements << " elements"
-            << std::endl;
-
-  finalize();
-
-  return 0;
 }
+
+} // namespace
diff --git a/test/test_gtest_utils.hh b/test/test_gtest_utils.hh
new file mode 100644
index 000000000..c2cbe0de6
--- /dev/null
+++ b/test/test_gtest_utils.hh
@@ -0,0 +1,110 @@
+/* -------------------------------------------------------------------------- */
+#include "aka_common.hh"
+/* -------------------------------------------------------------------------- */
+#include <boost/preprocessor.hpp>
+#include <gtest/gtest.h>
+#include <tuple>
+/* -------------------------------------------------------------------------- */
+
+namespace {
+
+/* -------------------------------------------------------------------------- */
+template <::akantu::ElementType t>
+using element_type_t = std::integral_constant<::akantu::ElementType, t>;
+
+/* -------------------------------------------------------------------------- */
+template <typename... T> struct gtest_list {};
+
+template <typename... Ts> struct gtest_list<std::tuple<Ts...>> {
+  using type = ::testing::Types<Ts...>;
+};
+
+template <typename... T> using gtest_list_t = typename gtest_list<T...>::type;
+
+/* -------------------------------------------------------------------------- */
+template <typename... T> struct tuple_concat {};
+
+template <typename... T1s, typename... T2s>
+struct tuple_concat<std::tuple<T1s...>, std::tuple<T2s...>> {
+  using type = std::tuple<T1s..., T2s...>;
+};
+
+template <typename... T>
+using tuple_concat_t = typename tuple_concat<T...>::type;
+
+/* -------------------------------------------------------------------------- */
+template <template <typename> class Pred, typename... Ts> struct tuple_filter {};
+
+template <template <typename> class Pred, typename T>
+struct tuple_filter<Pred, std::tuple<T>> {
+  using type = std::conditional_t<Pred<T>::value, std::tuple<T>, std::tuple<>>;
+};
+
+template <template <typename> class Pred, typename T, typename... Ts>
+struct tuple_filter<Pred, std::tuple<T, Ts...>> {
+  using type = tuple_concat_t<
+    typename tuple_filter<Pred, std::tuple<T>>::type,
+    typename tuple_filter<Pred, std::tuple<Ts...>>::type>;
+};
+
+template <template <typename> class Pred, typename... Ts>
+using tuple_filter_t = typename tuple_filter<Pred, Ts...>::type;
+
+/* -------------------------------------------------------------------------- */
+template <size_t N, typename... Ts> struct tuple_split {};
+
+template <size_t N, typename T, typename... Ts>
+struct tuple_split<N, std::tuple<T, Ts...>> {
+protected:
+  using split = tuple_split<N - 1, std::tuple<Ts...>>;
+
+public:
+  using type = tuple_concat_t<std::tuple<T>, typename split::type>;
+  using type_tail = typename split::type_tail;
+};
+
+template <typename T, typename... Ts>
+struct tuple_split<1, std::tuple<T, Ts...>> {
+  using type = std::tuple<T>;
+  using type_tail = std::tuple<Ts...>;
+};
+
+template <size_t N, typename... T>
+using tuple_split_t = typename tuple_split<N, T...>::type;
+
+template <size_t N, typename... T>
+using tuple_split_tail_t = typename tuple_split<N, T...>::type_tail;
+
+/* -------------------------------------------------------------------------- */
+template <typename... T> struct cross_product {};
+
+template <typename... T2s>
+struct cross_product<std::tuple<>, std::tuple<T2s...>> {
+  using type = std::tuple<>;
+};
+
+template <typename T1, typename... T1s, typename... T2s>
+struct cross_product<std::tuple<T1, T1s...>, std::tuple<T2s...>> {
+  using type = tuple_concat_t<
+      std::tuple<std::tuple<T1, T2s>...>,
+      typename cross_product<std::tuple<T1s...>, std::tuple<T2s...>>::type>;
+};
+
+template <typename... T>
+using cross_product_t = typename cross_product<T...>::type;
+/* -------------------------------------------------------------------------- */
+
+#define OP_CAT(s, data, elem) element_type_t<::akantu::elem>
+
+using TestElementTypesAll = std::tuple<BOOST_PP_SEQ_ENUM(
+    BOOST_PP_SEQ_TRANSFORM(OP_CAT, _, AKANTU_ek_regular_ELEMENT_TYPE))>;
+} // namespace
+
+template <typename T>
+using is_point_1 = std::is_same<T, element_type_t<::akantu::_point_1>>;
+
+template <typename T>
+using not_is_point_1 =
+    aka::negation<std::is_same<T, element_type_t<::akantu::_point_1>>>;
+
+using TestElementTypes = tuple_filter_t<not_is_point_1, TestElementTypesAll>;