diff --git a/packages/00_core.cmake b/packages/00_core.cmake
index b8e823857..8dc96d9a1 100644
--- a/packages/00_core.cmake
+++ b/packages/00_core.cmake
@@ -1,434 +1,435 @@
 #===============================================================================
 # @file   00_core.cmake
 #
 # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Mon Nov 21 2011
 # @date last modification: Fri Sep 19 2014
 #
 # @brief  package description for core
 #
 # @section LICENSE
 #
 # Copyright (©) 2010-2012, 2014 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/>.
 #
 #===============================================================================
 
 set(AKANTU_CORE ON CACHE INTERNAL "core package for Akantu" FORCE)
 
 set(AKANTU_CORE_FILES
   common/aka_array.cc
   common/aka_array.hh
   common/aka_array_tmpl.hh
   common/aka_blas_lapack.hh
   common/aka_circular_array.hh
   common/aka_circular_array_inline_impl.cc
   common/aka_common.cc
   common/aka_common.hh
   common/aka_common_inline_impl.cc
   common/aka_csr.hh
   common/aka_error.cc
   common/aka_error.hh
   common/aka_event_handler_manager.hh
   common/aka_extern.cc
   common/aka_fwd.hh
   common/aka_grid_dynamic.hh
   common/aka_math.cc
   common/aka_math.hh
   common/aka_math_tmpl.hh
   common/aka_memory.cc
   common/aka_memory.hh
   common/aka_memory_inline_impl.cc
   common/aka_random_generator.hh
   common/aka_safe_enum.hh
   common/aka_static_memory.cc
   common/aka_static_memory.hh
   common/aka_static_memory_inline_impl.cc
   common/aka_static_memory_tmpl.hh
   common/aka_typelist.hh
   common/aka_types.hh
   common/aka_visitor.hh
   common/aka_voigthelper.hh
   common/aka_voigthelper.cc
 
   fe_engine/element_class.cc
   fe_engine/element_class.hh
   fe_engine/element_class_tmpl.hh
   fe_engine/element_classes/element_class_hexahedron_8_inline_impl.cc
   fe_engine/element_classes/element_class_pentahedron_6_inline_impl.cc
   fe_engine/element_classes/element_class_point_1_inline_impl.cc
   fe_engine/element_classes/element_class_quadrangle_4_inline_impl.cc
   fe_engine/element_classes/element_class_quadrangle_8_inline_impl.cc
   fe_engine/element_classes/element_class_segment_2_inline_impl.cc
   fe_engine/element_classes/element_class_segment_3_inline_impl.cc
   fe_engine/element_classes/element_class_tetrahedron_10_inline_impl.cc
   fe_engine/element_classes/element_class_tetrahedron_4_inline_impl.cc
   fe_engine/element_classes/element_class_triangle_3_inline_impl.cc
   fe_engine/element_classes/element_class_triangle_6_inline_impl.cc
 
   fe_engine/fe_engine.cc
   fe_engine/fe_engine.hh
   fe_engine/fe_engine_inline_impl.cc
   fe_engine/fe_engine_template.hh
   fe_engine/fe_engine_template_tmpl.hh
   fe_engine/geometrical_data_tmpl.hh
   fe_engine/geometrical_element.cc
   fe_engine/integration_element.cc
   fe_engine/integrator.hh
   fe_engine/integrator_gauss.hh
   fe_engine/integrator_gauss_inline_impl.cc
   fe_engine/interpolation_element.cc
   fe_engine/interpolation_element_tmpl.hh
   fe_engine/shape_functions.hh
   fe_engine/shape_functions_inline_impl.cc
   fe_engine/shape_lagrange.cc
   fe_engine/shape_lagrange.hh
   fe_engine/shape_lagrange_inline_impl.cc
   fe_engine/shape_linked.cc
   fe_engine/shape_linked.hh
   fe_engine/shape_linked_inline_impl.cc
   fe_engine/element.hh
 
   io/dumper/dumpable.hh
   io/dumper/dumpable.cc
   io/dumper/dumpable_inline_impl.hh
   io/dumper/dumper_field.hh
   io/dumper/dumper_material_padders.hh
   io/dumper/dumper_filtered_connectivity.hh
   io/dumper/dumper_element_type.hh
   io/dumper/dumper_element_partition.hh
 
   io/mesh_io.cc
   io/mesh_io.hh
   io/mesh_io/mesh_io_abaqus.cc
   io/mesh_io/mesh_io_abaqus.hh
   io/mesh_io/mesh_io_diana.cc
   io/mesh_io/mesh_io_diana.hh
   io/mesh_io/mesh_io_msh.cc
   io/mesh_io/mesh_io_msh.hh
   io/model_io.cc
   io/model_io.hh
 
   io/parser/algebraic_parser.hh
   io/parser/input_file_parser.hh
   io/parser/parsable.cc
   io/parser/parsable.hh
   io/parser/parsable_tmpl.hh
   io/parser/parser.cc
   io/parser/parser.hh
   io/parser/parser_tmpl.hh
   io/parser/cppargparse/cppargparse.hh
   io/parser/cppargparse/cppargparse.cc
   io/parser/cppargparse/cppargparse_tmpl.hh
 
   mesh/element_group.cc
   mesh/element_group.hh
   mesh/element_group_inline_impl.cc
   mesh/element_type_map.hh
   mesh/element_type_map_tmpl.hh
   mesh/element_type_map_filter.hh
   mesh/group_manager.cc
   mesh/group_manager.hh
   mesh/group_manager_inline_impl.cc
   mesh/mesh.cc
   mesh/mesh.hh
   mesh/mesh_filter.hh
   mesh/mesh_data.cc
   mesh/mesh_data.hh
   mesh/mesh_data_tmpl.hh
   mesh/mesh_inline_impl.cc
   mesh/node_group.cc
   mesh/node_group.hh
   mesh/node_group_inline_impl.cc
 
   mesh_utils/mesh_partition.cc
   mesh_utils/mesh_partition.hh
   mesh_utils/mesh_partition/mesh_partition_mesh_data.cc
   mesh_utils/mesh_partition/mesh_partition_mesh_data.hh
   mesh_utils/mesh_partition/mesh_partition_scotch.hh
   mesh_utils/mesh_pbc.cc
   mesh_utils/mesh_utils.cc
   mesh_utils/mesh_utils.hh
   mesh_utils/mesh_utils_inline_impl.cc
 
   model/boundary_condition.hh
   model/boundary_condition_functor.hh
   model/boundary_condition_functor_inline_impl.cc
   model/boundary_condition_tmpl.hh
   model/integration_scheme/generalized_trapezoidal.hh
   model/integration_scheme/generalized_trapezoidal_inline_impl.cc
   model/integration_scheme/integration_scheme_1st_order.hh
   model/integration_scheme/integration_scheme_2nd_order.hh
   model/integration_scheme/newmark-beta.hh
   model/integration_scheme/newmark-beta_inline_impl.cc
   model/model.cc
   model/model.hh
   model/model_inline_impl.cc
 
   model/solid_mechanics/material.cc
   model/solid_mechanics/material.hh
   model/solid_mechanics/material_inline_impl.cc
   model/solid_mechanics/material_list.hh
   model/solid_mechanics/material_random_internal.hh
   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_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_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_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
 
 
 
   solver/solver.cc
   solver/solver.hh
+  solver/solver_inline_impl.cc
   solver/sparse_matrix.cc
   solver/sparse_matrix.hh
   solver/sparse_matrix_inline_impl.cc
   solver/static_solver.hh
   solver/static_solver.cc
 
   synchronizer/communication_buffer.hh
   synchronizer/communication_buffer_inline_impl.cc
   synchronizer/data_accessor.cc
   synchronizer/data_accessor.hh
   synchronizer/data_accessor_inline_impl.cc
   synchronizer/distributed_synchronizer.cc
   synchronizer/distributed_synchronizer.hh
   synchronizer/distributed_synchronizer_tmpl.hh
   synchronizer/dof_synchronizer.cc
   synchronizer/dof_synchronizer.hh
   synchronizer/dof_synchronizer_inline_impl.cc
   synchronizer/filtered_synchronizer.cc
   synchronizer/filtered_synchronizer.hh
   synchronizer/mpi_type_wrapper.hh
   synchronizer/pbc_synchronizer.cc
   synchronizer/pbc_synchronizer.hh
   synchronizer/real_static_communicator.hh
   synchronizer/static_communicator.cc
   synchronizer/static_communicator.hh
   synchronizer/static_communicator_dummy.hh
   synchronizer/static_communicator_inline_impl.hh
   synchronizer/synchronizer.cc
   synchronizer/synchronizer.hh
   synchronizer/synchronizer_registry.cc
   synchronizer/synchronizer_registry.hh
   )
 
 
 set(AKANTU_CORE_DEB_DEPEND
   libboost-dev
   )
 
 set(AKANTU_CORE_TESTS
   test_csr
   test_facet_element_mapping
   test_facet_extraction_tetrahedron_4
   test_facet_extraction_triangle_3
   test_grid
   test_interpolate_stress
   test_local_material
   test_material_damage_non_local
   test_material_thermal
   test_matrix
   test_mesh_boundary
   test_mesh_data
   test_mesh_io_msh
   test_mesh_io_msh_physical_names
   test_mesh_partitionate_mesh_data
   test_parser
   test_dumper
   test_pbc_tweak
   test_purify_mesh
   test_solid_mechanics_model_bar_traction2d
   test_solid_mechanics_model_bar_traction2d_structured
   test_solid_mechanics_model_bar_traction2d_structured_pbc
   test_solid_mechanics_model_boundary_condition
   test_solid_mechanics_model_circle_2
   test_solid_mechanics_model_cube3d
   test_solid_mechanics_model_cube3d_pbc
   test_solid_mechanics_model_cube3d_tetra10
   test_solid_mechanics_model_square
   test_solid_mechanics_model_material_eigenstrain
   test_static_memory
   test_surface_extraction_tetrahedron_4
   test_surface_extraction_triangle_3
   test_vector
   test_vector_iterator
   test_weight
   test_math
   test_material_standard_linear_solid_deviatoric_relaxation
   test_material_standard_linear_solid_deviatoric_relaxation_tension
   test_material_plasticity
   )
 
 set(AKANTU_CORE_MANUAL_FILES
   manual.sty
   manual.cls
   manual.tex
   manual-macros.sty
   manual-titlepages.tex
   manual-introduction.tex
   manual-gettingstarted.tex
   manual-io.tex
   manual-solidmechanicsmodel.tex
   manual-constitutive-laws.tex
   manual-lumping.tex
   manual-elements.tex
   manual-appendix-elements.tex
   manual-appendix-materials.tex
   manual-appendix-packages.tex
   manual-backmatter.tex
   manual-bibliography.bib
   manual-bibliographystyle.bst
 
   figures/bc_and_ic_example.pdf
   figures/boundary.pdf
   figures/boundary.svg
   figures/dirichlet.pdf
   figures/dirichlet.svg
   figures/doc_wheel.pdf
   figures/doc_wheel.svg
   figures/dynamic_analysis.png
   figures/explicit_dynamic.pdf
   figures/explicit_dynamic.svg
   figures/static.pdf
   figures/static.svg
   figures/hooke_law.pdf
   figures/hot-point-1.png
   figures/hot-point-2.png
   figures/implicit_dynamic.pdf
   figures/implicit_dynamic.svg
   figures/insertion.pdf
   figures/interpolate.pdf
   figures/interpolate.svg
   figures/problemDomain.pdf_tex
   figures/problemDomain.pdf
   figures/static_analysis.png
   figures/stress_strain_el.pdf
   figures/tangent.pdf
   figures/tangent.svg
   figures/vectors.pdf
   figures/vectors.svg
 
   figures/stress_strain_neo.pdf
   figures/visco_elastic_law.pdf
   figures/isotropic_hardening_plasticity.pdf
   figures/stress_strain_visco.pdf
 
   figures/elements/hexahedron_8.pdf
   figures/elements/hexahedron_8.svg
   figures/elements/quadrangle_4.pdf
   figures/elements/quadrangle_4.svg
   figures/elements/quadrangle_8.pdf
   figures/elements/quadrangle_8.svg
   figures/elements/segment_2.pdf
   figures/elements/segment_2.svg
   figures/elements/segment_3.pdf
   figures/elements/segment_3.svg
   figures/elements/tetrahedron_10.pdf
   figures/elements/tetrahedron_10.svg
   figures/elements/tetrahedron_4.pdf
   figures/elements/tetrahedron_4.svg
   figures/elements/triangle_3.pdf
   figures/elements/triangle_3.svg
   figures/elements/triangle_6.pdf
   figures/elements/triangle_6.svg
   figures/elements/xtemp.pdf
   )
 
 find_program(READLINK_COMMAND readlink)
 find_program(ADDR2LINE_COMMAND addr2line)
 mark_as_advanced(READLINK_COMMAND)
 mark_as_advanced(ADDR2LINE_COMMAND)
 
 include(CheckFunctionExists)
 
 check_function_exists(clock_gettime _clock_gettime)
 
 if(NOT _clock_gettime)
   set(AKANTU_USE_OBSOLETE_GETTIMEOFDAY ON)
 else()
   set(AKANTU_USE_OBSOLETE_GETTIMEOFDAY OFF)
 endif()
 
 set(AKANTU_CORE_DOCUMENTATION
 "
 This package is the core engine of \\akantu. It depends on:
 \\begin{itemize}
 \\item A C++ compiler (\\href{http://gcc.gnu.org/}{GCC} >= 4, or \\href{https://software.intel.com/en-us/intel-compilers}{Intel}).
 \\item The cross-platform, open-source \\href{http://www.cmake.org/}{CMake} build system.
 \\item The \\href{http://www.boost.org/}{Boost} C++ portable libraries.
 \\item The \\href{http://www.zlib.net/}{zlib} compression library.
 \\end{itemize}
 
 Under Ubuntu (14.04 LTS) the installation can be performed using the commands:
 \\begin{command}
   > sudo apt-get install build-essential cmake-curses-gui libboost-dev zlib1g-dev
 \\end{command}
 
 Under Mac OS X the installation requires the following steps:
 \\begin{itemize}
 \\item Install Xcode
 \\item Install the command line tools.
 \\item Install the MacPorts project which allows to automatically 
 download and install opensource packages. 
 \\end{itemize}
 Then the following commands should be typed in a terminal:
 \\begin{command}
   > sudo port install cmake gcc48 boost
 \\end{command}
 ")
\ No newline at end of file
diff --git a/packages/50_parallel.cmake b/packages/50_parallel.cmake
index 2a91df104..173a943d8 100644
--- a/packages/50_parallel.cmake
+++ b/packages/50_parallel.cmake
@@ -1,48 +1,49 @@
 #===============================================================================
 # @file   50_parallel.cmake
 #
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Tue Oct 16 2012
 # @date last modification: Wed Jun 11 2014
 #
 # @brief  meta package description for parallelization
 #
 # @section LICENSE
 #
 # Copyright (©) 2010-2012, 2014 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/>.
 #
 #===============================================================================
 
 add_meta_package(PARALLEL "Add parallel support in Akantu" OFF MPI SCOTCH)
 
 set(AKANTU_PARALLEL_TESTS
   test_solid_mechanics_model_bar_traction2d_parallel
   test_solid_mechanics_model_segment_parallel
   test_solid_mechanics_model_pbc_parallel
   test_synchronizer_communication
   test_dof_synchronizer
+  test_dof_synchronizer_communication
   test_solid_mechanics_model_reassign_material
   )
 
 set(AKANTU_PARALLEL_MANUAL_FILES
   manual-parallel.tex
   )
 
 set(AKANTU_PARALLEL_DOCUMENTATION "
 This option activates the parallel features of AKANTU.
 " )
diff --git a/packages/84_petsc.cmake b/packages/84_petsc.cmake
index dceacb9ba..ddbec6201 100644
--- a/packages/84_petsc.cmake
+++ b/packages/84_petsc.cmake
@@ -1,45 +1,48 @@
 #===============================================================================
 # @file   petsc.cmake
 #
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 # @author Alejandro M. Aragón <alejandro.aragon@epfl.ch>
 # @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
 #
 # @date   Mon Nov 21 18:19:15 2011
 #
 # @brief  package description for PETSc support
 #
 # @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/>.
 #
 #===============================================================================
 
 add_optional_external_package(PETSc "Add PETSc support in akantu" OFF ARGS COMPONENT ARGS CXX)
 add_internal_package_dependencies(petsc parallel)
 
 set(AKANTU_PETSC_FILES
   solver/petsc_matrix.hh
   solver/petsc_matrix.cc
   solver/petsc_matrix_inline_impl.cc
   solver/solver_petsc.hh
   solver/solver_petsc.cc
+  solver/petsc_wrapper.hh
   )
 
 set(AKANTU_PETSC_TESTS
   test_petsc_matrix_profile
+  test_petsc_matrix_apply_boundary
+  test_solver_petsc
   )
diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh
index 0f5da70bc..bb4076853 100644
--- a/src/common/aka_common.hh
+++ b/src/common/aka_common.hh
@@ -1,697 +1,699 @@
 /**
  * @file   aka_common.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Jun 14 2010
  * @date last modification: Mon Sep 15 2014
  *
  * @brief  common type descriptions for akantu
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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
  *
  * All common things to be included in the projects files
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_COMMON_HH__
 #define __AKANTU_COMMON_HH__
 
 /* -------------------------------------------------------------------------- */
 #include <list>
 #include <limits>
 #include <boost/preprocessor.hpp>
 
 /* -------------------------------------------------------------------------- */
 #define __BEGIN_AKANTU__ namespace akantu {
 #define __END_AKANTU__ };
 /* -------------------------------------------------------------------------- */
 #define __BEGIN_AKANTU_DUMPER__ namespace dumper {
 #define __END_AKANTU_DUMPER__ }
 /* -------------------------------------------------------------------------- */
 #if defined(WIN32)
 #  define __attribute__(x)
 #endif
 
 /* -------------------------------------------------------------------------- */
 #include "aka_config.hh"
 #include "aka_error.hh"
 #include "aka_safe_enum.hh"
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 /* Common types                                                               */
 /* -------------------------------------------------------------------------- */
 
 typedef double Real;
 typedef unsigned int UInt;
 typedef unsigned long long UInt64;
 typedef signed int Int;
 
 typedef std::string ID;
 
 static const Real UINT_INIT_VALUE = 0;
 #ifdef AKANTU_NDEBUG
   static const Real REAL_INIT_VALUE = 0;
 #else
   static const Real REAL_INIT_VALUE = std::numeric_limits<Real>::quiet_NaN();
 #endif
 
 /* -------------------------------------------------------------------------- */
 /* Memory types                                                               */
 /* -------------------------------------------------------------------------- */
 
 typedef UInt MemoryID;
 
 /* -------------------------------------------------------------------------- */
 /* Mesh/FEM/Model types                                                       */
 /* -------------------------------------------------------------------------- */
 
 typedef std::string Surface;
 typedef std::pair<Surface, Surface> SurfacePair;
 typedef std::list< SurfacePair > SurfacePairList;
 
 /* -------------------------------------------------------------------------- */
 
 extern const UInt _all_dimensions;
 
 /// @boost sequence of element to loop on in global tasks
 #define AKANTU_ek_regular_ELEMENT_TYPE		\
   (_point_1)					\
   (_segment_2)					\
   (_segment_3)					\
   (_triangle_3)					\
   (_triangle_6)					\
   (_quadrangle_4)				\
   (_quadrangle_8)				\
   (_tetrahedron_4)				\
   (_tetrahedron_10)				\
   (_pentahedron_6)				\
   (_hexahedron_8)
 
 #if defined(AKANTU_STRUCTURAL_MECHANICS)
 #define AKANTU_ek_structural_ELEMENT_TYPE	\
   (_bernoulli_beam_2)				\
   (_bernoulli_beam_3)  				\
   (_kirchhoff_shell)
 #else
 #define AKANTU_ek_structural_ELEMENT_TYPE
 #endif
 
 #if defined(AKANTU_COHESIVE_ELEMENT)
 #  define AKANTU_ek_cohesive_ELEMENT_TYPE	\
    (_cohesive_2d_4)				\
    (_cohesive_2d_6)				\
    (_cohesive_1d_2)				\
    (_cohesive_3d_6)				\
    (_cohesive_3d_12)
 #else
 #  define AKANTU_ek_cohesive_ELEMENT_TYPE
 #endif
 
 #if defined(AKANTU_IGFEM)
 #define AKANTU_ek_igfem_ELEMENT_TYPE		\
    (_igfem_triangle_3)
 #else
 #define AKANTU_ek_igfem_ELEMENT_TYPE
 #endif
 
 #define AKANTU_ALL_ELEMENT_TYPE			\
   AKANTU_ek_regular_ELEMENT_TYPE		\
   AKANTU_ek_cohesive_ELEMENT_TYPE		\
   AKANTU_ek_structural_ELEMENT_TYPE		\
   AKANTU_ek_igfem_ELEMENT_TYPE
 
 #define AKANTU_NOT_STRUCTURAL_ELEMENT_TYPE	\
   AKANTU_ek_regular_ELEMENT_TYPE		\
   AKANTU_ek_cohesive_ELEMENT_TYPE		\
   AKANTU_ek_igfem_ELEMENT_TYPE
 
 /// @enum ElementType type of elements
 enum ElementType {
   _not_defined,
   _point_1,
   _segment_2,         ///< first order segment
   _segment_3,         ///< second order segment
   _triangle_3,        ///< first order triangle
   _triangle_6,        ///< second order triangle
   _tetrahedron_4,     ///< first order tetrahedron
   _tetrahedron_10,    ///< second order tetrahedron
   _quadrangle_4,      ///< first order quadrangle
   _quadrangle_8,      ///< second order quadrangle
   _hexahedron_8,      ///< first order hexahedron
   _pentahedron_6,     ///< first order pentahedron
 #if defined (AKANTU_STRUCTURAL_MECHANICS)
   _bernoulli_beam_2,  ///< Bernoulli beam 2D
   _bernoulli_beam_3,  ///< Bernoulli beam 3D
   _kirchhoff_shell,   ///< Kirchhoff shell
 #endif
 
 #if defined(AKANTU_COHESIVE_ELEMENT)
   _cohesive_2d_4,     ///< first order 2D cohesive
   _cohesive_2d_6,     ///< second order 2D cohesive
   _cohesive_1d_2,     ///< first order 1D cohesive
   _cohesive_3d_6,     ///< first order 3D cohesive
   _cohesive_3d_12,     ///< second order 3D cohesive
 #endif
 #if defined(AKANTU_IGFEM)
   _igfem_triangle_3,  ///< first order triangle for IGFEM
 #endif
   _max_element_type
 };
 
 /// @enum GeometricalType type of element potentially contained in a Mesh
 enum GeometricalType {
   _gt_point,             ///< point @remark only for some algorithm to be generic like mesh partitioning */
   _gt_segment_2,         ///< 2 nodes segment
   _gt_segment_3,         ///< 3 nodes segment
   _gt_triangle_3,        ///< 3 nodes triangle
   _gt_triangle_6,        ///< 6 nodes triangle
   _gt_quadrangle_4,      ///< 4 nodes quadrangle
   _gt_quadrangle_8,      ///< 8 nodes quadrangle
   _gt_tetrahedron_4,     ///< 4 nodes tetrahedron
   _gt_tetrahedron_10,    ///< 10 nodes tetrahedron
   _gt_hexahedron_8,      ///< 8 nodes hexahedron
   _gt_pentahedron_6,     ///< 6 nodes pentahedron
 #if defined(AKANTU_COHESIVE_ELEMENT)
   _gt_cohesive_2d_4,     ///< 4 nodes 2D cohesive
   _gt_cohesive_2d_6,     ///< 6 nodes 2D cohesive
   _gt_cohesive_1d_2,     ///< 2 nodes 1D cohesive
   _gt_cohesive_3d_6,     ///< 6 nodes 3D cohesive
   _gt_cohesive_3d_12,     ///< 12 nodes 3D cohesive
 #endif
   _gt_not_defined
 };
 
 /// @enum InterpolationType type of elements
 enum InterpolationType {
   _itp_lagrange_point_1,           ///< zeroth (!) order lagrangian point (for compatibility purposes)
   _itp_lagrange_segment_2,         ///< first order lagrangian segment
   _itp_lagrange_segment_3,         ///< second order lagrangian segment
   _itp_lagrange_triangle_3,        ///< first order lagrangian triangle
   _itp_lagrange_triangle_6,        ///< second order lagrangian triangle
   _itp_lagrange_quadrangle_4,      ///< first order lagrangian quadrangle
   _itp_serendip_quadrangle_8,      /**< second order serendipian quadrangle
 				      @remark used insted of the 9 node
 				      lagrangian element */
   _itp_lagrange_tetrahedron_4,     ///< first order lagrangian tetrahedron
   _itp_lagrange_tetrahedron_10,    ///< second order lagrangian tetrahedron
   _itp_lagrange_hexahedron_8,      ///< first order lagrangian hexahedron
   _itp_lagrange_pentahedron_6,      ///< first order lagrangian pentahedron
 #if defined(AKANTU_STRUCTURAL_MECHANICS)
   _itp_bernoulli_beam,             ///< Bernoulli beam
   _itp_kirchhoff_shell,            ///< Kirchhoff shell
 #endif
 
   _itp_not_defined
 };
 
 //! standard output stream operator for ElementType
 inline std::ostream & operator <<(std::ostream & stream, ElementType type);
 
 
 #define AKANTU_REGULAR_KIND      (_ek_regular)
 
 #ifdef AKANTU_COHESIVE_ELEMENT
 #  define AKANTU_COHESIVE_KIND   (_ek_cohesive)
 #else
 #  define AKANTU_COHESIVE_KIND
 #endif
 
 #ifdef AKANTU_STRUCTURAL_MECHANICS
 #  define AKANTU_STRUCTURAL_KIND (_ek_structural)
 #else
 #  define AKANTU_STRUCTURAL_KIND
 #endif
 
 #ifdef AKANTU_IGFEM
 #  define AKANTU_IGFEM_KIND      (_ek_igfem)
 #else
 #  define AKANTU_IGFEM_KIND
 #endif
 
 #define AKANTU_ELEMENT_KIND			\
   AKANTU_REGULAR_KIND                           \
   AKANTU_COHESIVE_KIND				\
   AKANTU_STRUCTURAL_KIND			\
   AKANTU_IGFEM_KIND
 
 enum ElementKind {
   BOOST_PP_SEQ_ENUM(AKANTU_ELEMENT_KIND),
   _ek_not_defined
 };
 
 /// small help to use names for directions
 enum SpacialDirection {
   _x = 0,
   _y = 1,
   _z = 2
 };
 
 /// enum MeshIOType type of mesh reader/writer
 enum MeshIOType {
   _miot_auto,        ///< Auto guess of the reader to use based on the extension
   _miot_gmsh,        ///< Gmsh files
   _miot_gmsh_struct, ///< Gsmh reader with reintpretation of elements has structures elements
   _miot_diana,       ///< TNO Diana mesh format
   _miot_abaqus       ///< Abaqus mesh format
 };
 
 /// enum AnalysisMethod type of solving method used to solve the equation of motion
 enum AnalysisMethod {
   _static,
   _implicit_dynamic,
   _explicit_lumped_mass,
   _explicit_lumped_capacity,
   _explicit_consistent_mass
 };
 
 //! enum ContactResolutionMethod types of solving for the contact
 enum ContactResolutionMethod {
   _penalty,
   _lagrangian,
   _augmented_lagrangian,
   _nitsche,
   _mortar
 };
 
 //! enum ContactImplementationMethod types for different contact implementations
 enum ContactImplementationMethod {
   _none,
   _uzawa,
   _generalized_newton
 };
 
 
 
 
 /// enum SolveConvergenceMethod different resolution algorithms
 enum SolveConvergenceMethod {
   _scm_newton_raphson_tangent,             ///< Newton-Raphson with tangent matrix
   _scm_newton_raphson_tangent_modified,    ///< Newton-Raphson with constant tangent matrix
   _scm_newton_raphson_tangent_not_computed ///< Newton-Raphson with constant tangent matrix (user has to assemble it)
 };
 
 /// enum SolveConvergenceCriteria different convergence criteria
 enum SolveConvergenceCriteria {
   _scc_residual, ///< Use residual to test the convergence
   _scc_increment, ///< Use increment to test the convergence
   _scc_residual_mass_wgh ///< Use residual weighted by inv. nodal mass to testb
 };
 
 /// enum CohesiveMethod type of insertion of cohesive elements
 enum CohesiveMethod {
   _intrinsic,
   _extrinsic
 };
 
 /// myfunction(double * position, double * stress/force, double * normal, unsigned int material_id)
 typedef void (*BoundaryFunction)(double *,double *, double*, unsigned int);
 
 /// @enum BoundaryFunctionType type of function passed for boundary conditions
 enum BoundaryFunctionType {
   _bft_stress,
   _bft_traction,
   _bft_traction_local
 };
 
 /// @enum SparseMatrixType type of sparse matrix used
 enum SparseMatrixType {
   _unsymmetric,
   _symmetric
 };
 
 /* -------------------------------------------------------------------------- */
 /* Contact                                                                    */
 /* -------------------------------------------------------------------------- */
 typedef ID ContactID;
 typedef ID ContactSearchID;
 typedef ID ContactNeighborStructureID;
 
 enum ContactType {
   _ct_not_defined = 0,
   _ct_2d_expli    = 1,
   _ct_3d_expli    = 2,
   _ct_rigid       = 3
 };
 
 enum ContactSearchType {
   _cst_not_defined = 0,
   _cst_2d_expli    = 1,
   _cst_expli       = 2
 };
 
 enum ContactNeighborStructureType {
   _cnst_not_defined  = 0,
   _cnst_regular_grid = 1,
   _cnst_2d_grid      = 2
 };
 
 /* -------------------------------------------------------------------------- */
 /* Friction                                                                   */
 /* -------------------------------------------------------------------------- */
 typedef ID FrictionID;
 
 /* -------------------------------------------------------------------------- */
 /* Ghosts handling                                                            */
 /* -------------------------------------------------------------------------- */
 
 typedef ID SynchronizerID;
 
 /// @enum CommunicatorType type of communication method to use
 enum CommunicatorType {
   _communicator_mpi,
   _communicator_dummy
 };
 
 /// @enum SynchronizationTag type of synchronizations
 enum SynchronizationTag {
   //--- SolidMechanicsModel tags ---
   _gst_smm_mass,         //< synchronization of the SolidMechanicsModel.mass
   _gst_smm_for_gradu,    //< synchronization of the SolidMechanicsModel.displacement
   _gst_smm_boundary,     //< synchronization of the boundary, forces, velocities and displacement
   _gst_smm_uv,           //< synchronization of the nodal velocities and displacement
   _gst_smm_res,          //< synchronization of the nodal residual
   _gst_smm_init_mat,     //< synchronization of the data to initialize materials
   _gst_smm_stress,       //< synchronization of the stresses to compute the internal forces
   _gst_smmc_facets,      //< synchronization of facet data to setup facet synch
   _gst_smmc_facets_conn, //< synchronization of facet global connectivity
   _gst_smmc_facets_stress, //< synchronization of facets' stress to setup facet synch
   _gst_smmc_damage,      //< synchronization of damage
   //--- CohesiveElementInserter tags ---
   _gst_ce_inserter,      //< synchronization of global nodes id of newly inserted cohesive elements
   //--- GroupManager tags ---
   _gst_gm_clusters,      //< synchronization of clusters
   //--- HeatTransfer tags ---
   _gst_htm_capacity,     //< synchronization of the nodal heat capacity
   _gst_htm_temperature,  //< synchronization of the nodal temperature
   _gst_htm_gradient_temperature,  //< synchronization of the element gradient temperature
   //--- LevelSet tags ---
   /// synchronization of the nodal level set value phi
   _gst_htm_phi,
   /// synchronization of the element gradient phi
   _gst_htm_gradient_phi,
   //--- Material non local ---
   _gst_mnl_for_average,  //< synchronization of data to average in non local material
   _gst_mnl_weight,       //< synchronization of data for the weight computations
   //--- General tags ---
   _gst_test,             //< Test tag
   _gst_material_id,      //< synchronization of the material ids
   _gst_for_dump,         //< everything that needs to be synch before dump
   //--- Contact & Friction ---
   _gst_cf_nodal,         //< synchronization of disp, velo, and current position
-  _gst_cf_incr           //< synchronization of increment
+  _gst_cf_incr,           //< synchronization of increment
+  ///--- Solver tags ---
+  _gst_solver_solution     //< synchronization of the solution obained with the PETSc solver
 };
 
 /// standard output stream operator for SynchronizationTag
 inline std::ostream & operator <<(std::ostream & stream, SynchronizationTag type);
 
 /// @enum GhostType type of ghost
 enum GhostType {
   _not_ghost,
   _ghost,
   _casper  // not used but a real cute ghost
 };
 
 /* -------------------------------------------------------------------------- */
 struct GhostType_def {
   typedef GhostType type;
   static const type _begin_ = _not_ghost;
   static const type _end_   = _casper;
 };
 
 typedef safe_enum<GhostType_def> ghost_type_t;
 
 /// standard output stream operator for GhostType
 inline std::ostream & operator <<(std::ostream & stream, GhostType type);
 
 
 /// @enum SynchronizerOperation reduce operation that the synchronizer can perform
 enum SynchronizerOperation {
   _so_sum,
   _so_min,
   _so_max,
   _so_null
 };
 
 
 /* -------------------------------------------------------------------------- */
 /* Global defines                                                             */
 /* -------------------------------------------------------------------------- */
 #define AKANTU_MIN_ALLOCATION 2000
 
 #define AKANTU_INDENT " "
 #define AKANTU_INCLUDE_INLINE_IMPL
 
 /* -------------------------------------------------------------------------- */
 // int 2 type construct
 template <int d>
 struct Int2Type {
   enum { result = d };
 };
 
 // type 2 type construct
 template <class T>
 class Type2Type {
   typedef T OriginalType;
 };
 
 /* -------------------------------------------------------------------------- */
 template<class T>
 struct is_scalar {
   enum{ value = false };
 };
 
 #define AKANTU_SPECIFY_IS_SCALAR(type)		\
   template<>					\
   struct is_scalar<type> {			\
     enum { value = true };			\
   }
 
 
 AKANTU_SPECIFY_IS_SCALAR(Real);
 AKANTU_SPECIFY_IS_SCALAR(UInt);
 AKANTU_SPECIFY_IS_SCALAR(Int);
 AKANTU_SPECIFY_IS_SCALAR(bool);
 
 template < typename T1, typename T2 >
 struct is_same {
   enum { value = false };      // is_same represents a bool.
 };
 
 template < typename T >
 struct is_same<T, T> {
   enum { value = true };
 };
 
 /* -------------------------------------------------------------------------- */
 #define AKANTU_SET_MACRO(name, variable, type)	\
   inline void set##name (type variable) {	\
     this->variable = variable;			\
   }
 
 #define AKANTU_GET_MACRO(name, variable, type)	\
   inline type get##name () const {		\
     return variable;				\
   }
 
 #define AKANTU_GET_MACRO_NOT_CONST(name, variable, type)	\
   inline type get##name () {					\
     return variable;						\
   }
 
 #define AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type,		\
 					 support, con)			\
   inline con Array<type> &						\
   get##name (const support & el_type,					\
 	     const GhostType & ghost_type = _not_ghost) con {		\
     return variable(el_type, ghost_type);				\
   }
 
 #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE(name, variable, type)		\
   AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType,)
 #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(name, variable, type)	\
   AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType, const)
 
 #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE(name, variable, type)	\
   AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType,)
 #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE_CONST(name, variable, type)	\
   AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType, const)
 
 /* -------------------------------------------------------------------------- */
 /// initialize the static part of akantu
 void initialize(int & argc, char ** & argv);
 /// initialize the static part of akantu and read the global input_file
 void initialize(const std::string & input_file, int & argc, char ** & argv);
 /* -------------------------------------------------------------------------- */
 /// finilize correctly akantu and clean the memory
 void finalize ();
 /* -------------------------------------------------------------------------- */
 
 /*
  * For intel compiler annoying remark
  */
 #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)
 
 /* -------------------------------------------------------------------------- */
 /* string manipulation                                                        */
 /* -------------------------------------------------------------------------- */
 inline std::string to_lower(const std::string & str);
 /* -------------------------------------------------------------------------- */
 inline std::string trim(const std::string & to_trim);
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 /// give a string representation of the a human readable size in bit
 template<typename T>
 std::string printMemorySize(UInt size);
 /* -------------------------------------------------------------------------- */
 
 
 __END_AKANTU__
 
 #include "aka_fwd.hh"
 
 __BEGIN_AKANTU__
 
 /// get access to the internal argument parser
 cppargparse::ArgumentParser & getStaticArgumentParser();
 
 /// get access to the internal input file parser
 Parser & getStaticParser();
 
 /// get access to the user part of the internal input file parser
 const ParserSection & getUserParser();
 
 __END_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 // BOOST PART: TOUCH ONLY IF YOU KNOW WHAT YOU ARE DOING
 
 #define AKANTU_BOOST_CASE_MACRO(r,macro,type)				\
   case type : { macro(type); break; }
 
 #define AKANTU_BOOST_LIST_SWITCH(macro1, list1, var)			\
   do {									\
     switch(var) {							\
       BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, macro1, list1)	\
     default: {								\
       AKANTU_DEBUG_ERROR("Type (" << var << ") not handled by this function"); \
     }									\
     }									\
   } while(0)
 
 #define AKANTU_BOOST_ELEMENT_SWITCH(macro1, list1)			\
   AKANTU_BOOST_LIST_SWITCH(macro1, list1, type)
 
 #define AKANTU_BOOST_ALL_ELEMENT_SWITCH(macro)				\
   AKANTU_BOOST_ELEMENT_SWITCH(macro,					\
 			      AKANTU_ALL_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(macro)			\
   AKANTU_BOOST_ELEMENT_SWITCH(macro,					\
 			      AKANTU_ek_regular_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(macro)			\
   AKANTU_BOOST_ELEMENT_SWITCH(macro,					\
 			      AKANTU_ek_cohesive_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(macro)			\
   AKANTU_BOOST_ELEMENT_SWITCH(macro,					\
 			      AKANTU_ek_structural_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_IGFEM_ELEMENT_SWITCH(macro)			\
   AKANTU_BOOST_ELEMENT_SWITCH(macro,					\
 			      AKANTU_ek_igfem_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_LIST_MACRO(r, macro, type)	                        \
   macro(type)
 
 #define AKANTU_BOOST_APPLY_ON_LIST(macro, list)			        \
   BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_LIST_MACRO, macro, list)
 
 #define AKANTU_BOOST_ALL_ELEMENT_LIST(macro)				\
   AKANTU_BOOST_APPLY_ON_LIST(macro,					\
 			     AKANTU_ALL_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_REGULAR_ELEMENT_LIST(macro)		        \
   AKANTU_BOOST_APPLY_ON_LIST(macro,				        \
 			     AKANTU_ek_regular_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_STRUCTURAL_ELEMENT_LIST(macro)			\
   AKANTU_BOOST_APPLY_ON_LIST(macro,					\
 			     AKANTU_ek_structural_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_COHESIVE_ELEMENT_LIST(macro)			\
   AKANTU_BOOST_APPLY_ON_LIST(macro,					\
 			     AKANTU_ek_cohesive_ELEMENT_TYPE)
 
 #define AKANTU_BOOST_IGFEM_ELEMENT_LIST(macro)				\
   AKANTU_BOOST_APPLY_ON_LIST(macro,					\
 			     AKANTU_ek_igfem_ELEMENT_TYPE)
 
 #define AKANTU_GET_ELEMENT_LIST(kind)	                                \
   AKANTU##kind##_ELEMENT_TYPE
 
 #define AKANTU_BOOST_KIND_ELEMENT_SWITCH(macro, kind)			\
   AKANTU_BOOST_ELEMENT_SWITCH(macro,					\
 			      AKANTU_GET_ELEMENT_LIST(kind))
 
 // BOOST_PP_SEQ_TO_LIST does not exists in Boost < 1.49
 #define AKANTU_GENERATE_KIND_LIST(seq)                                  \
   BOOST_PP_TUPLE_TO_LIST(BOOST_PP_SEQ_SIZE(seq),                        \
                          BOOST_PP_SEQ_TO_TUPLE(seq))
 
 #define AKANTU_ELEMENT_KIND_BOOST_LIST AKANTU_GENERATE_KIND_LIST(AKANTU_ELEMENT_KIND)
 
 #define AKANTU_BOOST_ALL_KIND_LIST(macro, list)			        \
   BOOST_PP_LIST_FOR_EACH(AKANTU_BOOST_LIST_MACRO, macro, list)
 
 #define AKANTU_BOOST_ALL_KIND(macro)					\
   AKANTU_BOOST_ALL_KIND_LIST(macro, AKANTU_ELEMENT_KIND_BOOST_LIST)
 
 #define AKANTU_BOOST_ALL_KIND_SWITCH(macro)			        \
   AKANTU_BOOST_LIST_SWITCH(macro,				        \
 			   AKANTU_ELEMENT_KIND,			        \
 			   kind)
 
 /// define kept for compatibility reasons (they are most probably not needed
 /// anymore) \todo check if they can be removed
 #define AKANTU_REGULAR_ELEMENT_TYPE	AKANTU_ek_regular_ELEMENT_TYPE
 #define AKANTU_COHESIVE_ELEMENT_TYPE	AKANTU_ek_cohesive_ELEMENT_TYPE
 #define AKANTU_STRUCTURAL_ELEMENT_TYPE  AKANTU_ek_structural_ELEMENT_TYPE
 #define AKANTU_IGFEM_ELEMENT_TYPE       AKANTU_ek_igfem_ELEMENT_TYPE
 
 
 #include "aka_common_inline_impl.cc"
 
 #endif /* __AKANTU_COMMON_HH__ */
diff --git a/src/common/aka_common_inline_impl.cc b/src/common/aka_common_inline_impl.cc
index 98f333536..f7da7198f 100644
--- a/src/common/aka_common_inline_impl.cc
+++ b/src/common/aka_common_inline_impl.cc
@@ -1,233 +1,234 @@
 /**
  * @file   aka_common_inline_impl.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Thu Dec 01 2011
  * @date last modification: Wed Jul 23 2014
  *
  * @brief  inline implementations of common akantu type descriptions
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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
  *
  * All common things to be included in the projects files
  *
  */
 
 #include <algorithm>
 #include <iomanip>
 
 #include <cctype>
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 //! standard output stream operator for ElementType
 inline std::ostream & operator <<(std::ostream & stream, ElementType type)
 {
 #define STRINGIFY(type)				\
   stream << BOOST_PP_STRINGIZE(type)
 
   switch(type) {
     BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, \
                           STRINGIFY,               \
                           AKANTU_ALL_ELEMENT_TYPE)
     case _not_defined:       stream << "_not_defined"; break;
     case _max_element_type:  stream << "_max_element_type"; break;
   }
 
 
 
 #undef STRINGIFY
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 //! standard output stream operator for ElementType
 inline std::ostream & operator <<(std::ostream & stream, ElementKind kind )
 {
 #define STRINGIFY(kind)				\
   stream << BOOST_PP_STRINGIZE(kind)
 
   AKANTU_BOOST_ALL_KIND_SWITCH(STRINGIFY);
 #undef STRINGIFY
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 /// standard output stream operator for InterpolationType
 inline std::ostream & operator <<(std::ostream & stream, InterpolationType type)
 {
   switch(type)
     {
     case _itp_lagrange_point_1        : stream << "_itp_lagrange_point_1"       ; break;
     case _itp_lagrange_segment_2      : stream << "_itp_lagrange_segment_2"     ; break;
     case _itp_lagrange_segment_3      : stream << "_itp_lagrange_segment_3"     ; break;
     case _itp_lagrange_triangle_3     : stream << "_itp_lagrange_triangle_3"    ; break;
     case _itp_lagrange_triangle_6     : stream << "_itp_lagrange_triangle_6"    ; break;
     case _itp_lagrange_quadrangle_4   : stream << "_itp_lagrange_quadrangle_4"  ; break;
     case _itp_serendip_quadrangle_8   : stream << "_itp_serendip_quadrangle_8"  ; break;
     case _itp_lagrange_tetrahedron_4  : stream << "_itp_lagrange_tetrahedron_4" ; break;
     case _itp_lagrange_tetrahedron_10 : stream << "_itp_lagrange_tetrahedron_10"; break;
     case _itp_lagrange_hexahedron_8   : stream << "_itp_lagrange_hexahedron_8"  ; break;
     case _itp_lagrange_pentahedron_6  : stream << "_itp_lagrange_pentahedron_6" ; break;
 #if defined(AKANTU_STRUCTURAL_MECHANICS)
     case _itp_bernoulli_beam          : stream << "_itp_bernoulli_beam"         ; break;
     case _itp_kirchhoff_shell         : stream << "_itp_kirchhoff_shell"        ; break;
 #endif
     case _itp_not_defined             : stream << "_itp_not_defined"            ; break;
     }
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 /// standard output stream operator for GhostType
 inline std::ostream & operator <<(std::ostream & stream, GhostType type)
 {
   switch(type)
     {
     case _not_ghost : stream << "not_ghost"; break;
     case _ghost     : stream << "ghost"    ; break;
     case _casper    : stream << "Casper the friendly ghost"; break;
     }
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 /// standard output stream operator for SynchronizationTag
 inline std::ostream & operator <<(std::ostream & stream, SynchronizationTag type)
 {
   switch(type)
     {
     case _gst_smm_mass                 : stream << "_gst_smm_mass"                ; break;
     case _gst_smm_for_gradu            : stream << "_gst_smm_for_gradu"           ; break;
     case _gst_smm_boundary             : stream << "_gst_smm_boundary"            ; break;
     case _gst_smm_uv                   : stream << "_gst_smm_uv"                  ; break;
     case _gst_smm_res                  : stream << "_gst_smm_res"                 ; break;
     case _gst_smm_init_mat             : stream << "_gst_smm_init_mat"            ; break;
     case _gst_smm_stress               : stream << "_gst_smm_stress"              ; break;
     case _gst_smmc_facets              : stream << "_gst_smmc_facets"             ; break;
     case _gst_smmc_facets_conn         : stream << "_gst_smmc_facets_conn"        ; break;
     case _gst_smmc_facets_stress       : stream << "_gst_smmc_facets_stress"      ; break;
     case _gst_smmc_damage              : stream << "_gst_smmc_damage"             ; break;
     case _gst_ce_inserter              : stream << "_gst_ce_inserter"             ; break;
     case _gst_gm_clusters              : stream << "_gst_gm_clusters"             ; break;
     case _gst_htm_capacity             : stream << "_gst_htm_capacity"            ; break;
     case _gst_htm_temperature          : stream << "_gst_htm_temperature"         ; break;
     case _gst_htm_gradient_temperature : stream << "_gst_htm_gradient_temperature"; break;
     case _gst_htm_phi                  : stream << "_gst_htm_phi"                 ; break;
     case _gst_htm_gradient_phi         : stream << "_gst_htm_gradient_phi"        ; break;
     case _gst_mnl_for_average          : stream << "_gst_mnl_for_average"         ; break;
     case _gst_mnl_weight               : stream << "_gst_mnl_weight"              ; break;
     case _gst_test                     : stream << "_gst_test"                    ; break;
     case _gst_material_id              : stream << "_gst_material_id"             ; break;
     case _gst_for_dump                 : stream << "_gst_for_dump"                ; break;
     case _gst_cf_nodal                 : stream << "_gst_cf_nodal"                ; break;
     case _gst_cf_incr                  : stream << "_gst_cf_incr"                 ; break;
+    case _gst_solver_solution          : stream << "_gst_solver_solution"         ; break;
     }
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 /// standard output stream operator for SolveConvergenceCriteria
 inline std::ostream & operator <<(std::ostream & stream, SolveConvergenceCriteria criteria)
 {
   switch(criteria) {
   case _scc_residual : stream << "_scc_residual" ; break;
   case _scc_increment: stream << "_scc_increment"; break;
   case _scc_residual_mass_wgh: stream << "_scc_residual_mass_wgh"; break;
   }
   return stream;
 }
 
 
 /* -------------------------------------------------------------------------- */
 inline std::string to_lower(const std::string & str) {
   std::string lstr = str;
   std::transform(lstr.begin(),
                  lstr.end(),
                  lstr.begin(),
                  (int(*)(int))tolower);
   return lstr;
 }
 
 /* -------------------------------------------------------------------------- */
 inline std::string trim(const std::string & to_trim) {
   std::string trimed = to_trim;
   //left trim
   trimed.erase(trimed.begin(),
                std::find_if(trimed.begin(),
                             trimed.end(),
                             std::not1(std::ptr_fun<int, int>(isspace))));
   // right trim
   trimed.erase(std::find_if(trimed.rbegin(),
                             trimed.rend(),
                             std::not1(std::ptr_fun<int, int>(isspace))).base(),
                trimed.end());
   return trimed;
 }
 
 __END_AKANTU__
 
 #include <cmath>
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 template<typename T>
 std::string printMemorySize(UInt size) {
   Real real_size = size * sizeof(T);
 
   UInt mult = (std::log(real_size) / std::log(2)) / 10;
 
   std::stringstream sstr;
 
   real_size /= Real(1 << (10 * mult));
   sstr << std::setprecision(2) << std::fixed << real_size;
 
   std::string size_prefix;
   switch(mult) {
   case 0: sstr << "";   break;
   case 1: sstr << "Ki"; break;
   case 2: sstr << "Mi"; break;
   case 3: sstr << "Gi"; break; // I started on this type of machines
                                // (32bit computers) (Nicolas)
   case 4: sstr << "Ti"; break;
   case 5: sstr << "Pi"; break;
   case 6: sstr << "Ei"; break; // theoritical limit of RAM of the current
                                // computers in 2014 (64bit computers) (Nicolas)
   case 7: sstr << "Zi"; break;
   case 8: sstr << "Yi"; break;
   default:
     AKANTU_DEBUG_ERROR("The programmer in 2014 didn't thought so far (even wikipedia does not go further)."
                        << " You have at least 1024 times more than a yobibit of RAM!!!"
                        << " Just add the prefix corresponding in this switch case.");
   }
 
   sstr << "Byte";
 
   return sstr.str();
 }
 
 
 
 __END_AKANTU__
diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc
index ce40bc72f..f25f0280f 100644
--- a/src/model/solid_mechanics/solid_mechanics_model.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model.cc
@@ -1,1830 +1,1840 @@
 /**
  * @file   solid_mechanics_model.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @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>
  *
  * @date creation: Tue Jul 27 2010
  * @date last modification: Fri Sep 19 2014
  *
  * @brief  Implementation of the SolidMechanicsModel class
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_math.hh"
 #include "aka_common.hh"
 #include "solid_mechanics_model.hh"
 #include "group_manager_inline_impl.cc"
 #include "dumpable_inline_impl.hh"
 #include "integration_scheme_2nd_order.hh"
 #include "element_group.hh"
 
 #include "static_communicator.hh"
 
 #include "dof_synchronizer.hh"
 #include "element_group.hh"
 
 #include <cmath>
 
 #ifdef AKANTU_USE_MUMPS
 #include "solver_mumps.hh"
 #endif
 
 #ifdef AKANTU_USE_IOHELPER
 #  include "dumper_field.hh"
 #  include "dumper_paraview.hh"
 #  include "dumper_homogenizing_field.hh"
 #  include "dumper_material_internal_field.hh"
 #  include "dumper_elemental_field.hh"
 #  include "dumper_material_padders.hh"
 #  include "dumper_element_partition.hh"
 #  include "dumper_iohelper.hh"
 #endif
 
 /* -------------------------------------------------------------------------- */
 __BEGIN_AKANTU__
 
 const SolidMechanicsModelOptions default_solid_mechanics_model_options(_explicit_lumped_mass, false);
 
 /* -------------------------------------------------------------------------- */
 /**
  * A solid mechanics model need a mesh  and a dimension to be created. the model
  * by it  self can not  do a lot,  the good init  functions should be  called in
  * order to configure the model depending on what we want to do.
  *
  * @param  mesh mesh  representing  the model  we  want to  simulate
  * @param dim spatial  dimension of the problem, if dim =  0 (default value) the
  * dimension of the problem is assumed to be the on of the mesh
  * @param id an id to identify the model
  */
 SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh,
                                          UInt dim,
                                          const ID & id,
                                          const MemoryID & memory_id) :
   Model(mesh, dim, id, memory_id), 
   BoundaryCondition<SolidMechanicsModel>(),
   time_step(NAN), f_m2a(1.0),
   mass_matrix(NULL),
   velocity_damping_matrix(NULL),
   stiffness_matrix(NULL),
   jacobian_matrix(NULL),
   element_index_by_material("element index by material", id),
   material_selector(new DefaultMaterialSelector(element_index_by_material)),
   is_default_material_selector(true),
   integrator(NULL),
   increment_flag(false), solver(NULL),
   synch_parallel(NULL),
   are_materials_instantiated(false) {
 
   AKANTU_DEBUG_IN();
 
   createSynchronizerRegistry(this);
 
   registerFEEngineObject<MyFEEngineType>("SolidMechanicsFEEngine", mesh, spatial_dimension);
 
   this->displacement = NULL;
   this->mass         = NULL;
   this->velocity     = NULL;
   this->acceleration = NULL;
   this->force        = NULL;
   this->residual     = NULL;
   this->blocked_dofs = NULL;
 
   this->increment    = NULL;
   this->increment_acceleration = NULL;
 
   this->dof_synchronizer = NULL;
 
   this->previous_displacement = NULL;
 
   materials.clear();
 
   mesh.registerEventHandler(*this);
 
 #if defined(AKANTU_USE_IOHELPER)
   this->mesh.registerDumper<DumperParaview>("paraview_all", id, true);
   this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular);
 #endif
   AKANTU_DEBUG_OUT();
 }
 
 
 
 /* -------------------------------------------------------------------------- */
 SolidMechanicsModel::~SolidMechanicsModel() {
   AKANTU_DEBUG_IN();
 
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     delete *mat_it;
   }
 
   materials.clear();
 
   delete integrator;
 
   delete solver;
   delete mass_matrix;
   delete velocity_damping_matrix;
 
   if(stiffness_matrix && stiffness_matrix != jacobian_matrix)
     delete stiffness_matrix;
 
   delete jacobian_matrix;
 
   delete synch_parallel;
 
   if(is_default_material_selector) {
     delete material_selector;
     material_selector = NULL;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 void SolidMechanicsModel::setTimeStep(Real time_step) {
   this->time_step = time_step;
 
 #if defined(AKANTU_USE_IOHELPER)
   this->mesh.getDumper().setTimeStep(time_step);
 #endif
 }
 
 /* -------------------------------------------------------------------------- */
 /* Initialisation                                                             */
 /* -------------------------------------------------------------------------- */
 /**
  * This function groups  many of the initialization in on  function. For most of
  * basics  case the  function should  be  enough. The  functions initialize  the
  * model, the internal  vectors, set them to 0, and  depending on the parameters
  * it also initialize the explicit or implicit solver.
  *
  * @param material_file the  file containing the materials to  use
  * @param method the analysis method wanted.  See the akantu::AnalysisMethod for
  * the different possibilities
  */
 void SolidMechanicsModel::initFull(const ModelOptions & options) {
   Model::initFull(options);
 
   const SolidMechanicsModelOptions & smm_options =
     dynamic_cast<const SolidMechanicsModelOptions &>(options);
 
   method = smm_options.analysis_method;
 
   // initialize the vectors
   initArrays();
 
   // set the initial condition to 0
   force->clear();
   velocity->clear();
   acceleration->clear();
   displacement->clear();
 
   // initialize pcb
   if(pbc_pair.size()!=0)
     initPBC();
 
   // initialize the time integration schemes
   switch(method) {
   case _explicit_lumped_mass:
     initExplicit();
     break;
   case _explicit_consistent_mass:
     initSolver();
     initExplicit();
     break;
   case _implicit_dynamic:
     initImplicit(true);
     break;
   case _static:
     initImplicit(false);
     break;
   default:
     AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel");
     break;
   }
 
   // initialize the materials
   if(this->parser->getLastParsedFile() != "") {
     instantiateMaterials();
   }
 
   if(!smm_options.no_init_materials) {
     initMaterials();
   }
 
   if(increment_flag)
     initBC(*this, *displacement, *increment, *force);
   else
     initBC(*this, *displacement, *force);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initParallel(MeshPartition * partition,
                                        DataAccessor * data_accessor) {
   AKANTU_DEBUG_IN();
 
   if (data_accessor == NULL) data_accessor = this;
   synch_parallel = &createParallelSynch(partition,data_accessor);
 
   synch_registry->registerSynchronizer(*synch_parallel, _gst_material_id);
   synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_mass);
   synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_stress);
   synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_boundary);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initFEEngineBoundary() {
   FEEngine & fem_boundary = getFEEngineBoundary();
   fem_boundary.initShapeFunctions(_not_ghost);
   fem_boundary.initShapeFunctions(_ghost);
 
   fem_boundary.computeNormalsOnControlPoints(_not_ghost);
   fem_boundary.computeNormalsOnControlPoints(_ghost);
 }
 
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initExplicit(AnalysisMethod analysis_method) {
   AKANTU_DEBUG_IN();
 
   //in case of switch from implicit to explicit
   if(!this->isExplicit())
     method = analysis_method;
 
   if (integrator) delete integrator;
   integrator = new CentralDifference();
 
   UInt nb_nodes = acceleration->getSize();
   UInt nb_degree_of_freedom = acceleration->getNbComponent();
 
   std::stringstream sstr; sstr << id << ":increment_acceleration";
   increment_acceleration = &(alloc<Real>(sstr.str(), nb_nodes, nb_degree_of_freedom, Real()));
 
   AKANTU_DEBUG_OUT();
 }
 
 void SolidMechanicsModel::initArraysPreviousDisplacment() {
   AKANTU_DEBUG_IN();
 
   SolidMechanicsModel::setIncrementFlagOn();
   UInt nb_nodes = mesh.getNbNodes();
   std::stringstream sstr_disp_t;
   sstr_disp_t << id << ":previous_displacement";
   previous_displacement = &(alloc<Real > (sstr_disp_t.str(), nb_nodes, spatial_dimension, 0.));
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Allocate all the needed vectors. By  default their are not necessarily set to
  * 0
  *
  */
 void SolidMechanicsModel::initArrays() {
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes = mesh.getNbNodes();
   std::stringstream sstr_disp; sstr_disp << id << ":displacement";
   //  std::stringstream sstr_mass; sstr_mass << id << ":mass";
   std::stringstream sstr_velo; sstr_velo << id << ":velocity";
   std::stringstream sstr_acce; sstr_acce << id << ":acceleration";
   std::stringstream sstr_forc; sstr_forc << id << ":force";
   std::stringstream sstr_resi; sstr_resi << id << ":residual";
   std::stringstream sstr_boun; sstr_boun << id << ":blocked_dofs";
 
   displacement = &(alloc<Real>(sstr_disp.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE));
   //  mass         = &(alloc<Real>(sstr_mass.str(), nb_nodes, spatial_dimension, 0));
   velocity     = &(alloc<Real>(sstr_velo.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE));
   acceleration = &(alloc<Real>(sstr_acce.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE));
   force        = &(alloc<Real>(sstr_forc.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE));
   residual     = &(alloc<Real>(sstr_resi.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE));
   blocked_dofs = &(alloc<bool>(sstr_boun.str(), nb_nodes, spatial_dimension, false));
 
   std::stringstream sstr_curp; sstr_curp << id << ":current_position";
   current_position = &(alloc<Real>(sstr_curp.str(), 0, spatial_dimension, REAL_INIT_VALUE));
 
   for(UInt g = _not_ghost; g <= _ghost; ++g) {
     GhostType gt = (GhostType) g;
     Mesh::type_iterator it  = mesh.firstType(spatial_dimension, gt, _ek_not_defined);
     Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, _ek_not_defined);
     for(; it != end; ++it) {
       UInt nb_element = mesh.getNbElement(*it, gt);
       element_index_by_material.alloc(nb_element, 2, *it, gt);
     }
   }
 
   dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension);
   dof_synchronizer->initLocalDOFEquationNumbers();
   dof_synchronizer->initGlobalDOFEquationNumbers();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Initialize the model,basically it  pre-compute the shapes, shapes derivatives
  * and jacobian
  *
  */
 void SolidMechanicsModel::initModel() {
   /// \todo add  the current position  as a parameter to  initShapeFunctions for
   /// large deformation
   getFEEngine().initShapeFunctions(_not_ghost);
   getFEEngine().initShapeFunctions(_ghost);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initPBC() {
   Model::initPBC();
   registerPBCSynchronizer();
 
   // as long as there are ones on the diagonal of the matrix, we can put boudandary true for slaves
   std::map<UInt, UInt>::iterator it = pbc_pair.begin();
   std::map<UInt, UInt>::iterator end = pbc_pair.end();
   UInt dim = mesh.getSpatialDimension();
   while(it != end) {
     for (UInt i=0; i<dim; ++i)
       (*blocked_dofs)((*it).first,i) = true;
     ++it;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::registerPBCSynchronizer(){
   PBCSynchronizer * synch = new PBCSynchronizer(pbc_pair);
   synch_registry->registerSynchronizer(*synch, _gst_smm_uv);
   synch_registry->registerSynchronizer(*synch, _gst_smm_mass);
   synch_registry->registerSynchronizer(*synch, _gst_smm_res);
   synch_registry->registerSynchronizer(*synch, _gst_for_dump);
   changeLocalEquationNumberForPBC(pbc_pair, mesh.getSpatialDimension());
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateCurrentPosition() {
   AKANTU_DEBUG_IN();
   UInt nb_nodes = mesh.getNbNodes();
 
   current_position->resize(nb_nodes);
   Real * current_position_val = current_position->storage();
   Real * position_val         = mesh.getNodes().storage();
   Real * displacement_val     = displacement->storage();
 
   /// compute current_position = initial_position + displacement
   memcpy(current_position_val, position_val, nb_nodes*spatial_dimension*sizeof(Real));
   for (UInt n = 0; n < nb_nodes*spatial_dimension; ++n) {
     *current_position_val++ += *displacement_val++;
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initializeUpdateResidualData() {
   AKANTU_DEBUG_IN();
   UInt nb_nodes = mesh.getNbNodes();
   residual->resize(nb_nodes);
 
   /// copy the forces in residual for boundary conditions
   memcpy(residual->storage(), force->storage(), nb_nodes*spatial_dimension*sizeof(Real));
 
   // start synchronization
   synch_registry->asynchronousSynchronize(_gst_smm_uv);
   synch_registry->waitEndSynchronize(_gst_smm_uv);
 
   updateCurrentPosition();
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 /* Explicit scheme                                                            */
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 /**
  * This function compute  the second member of the motion  equation.  That is to
  * say the sum of forces @f$ r = F_{ext} - F_{int} @f$. @f$ F_{ext} @f$ is given
  * by the  user in  the force  vector, and @f$  F_{int} @f$  is computed  as @f$
  * F_{int} = \int_{\Omega} N \sigma d\Omega@f$
  *
  */
 void SolidMechanicsModel::updateResidual(bool need_initialize) {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_INFO("Assemble the internal forces");
   // f = f_ext - f_int
 
   // f = f_ext
   if(need_initialize) initializeUpdateResidualData();
 
   AKANTU_DEBUG_INFO("Compute local stresses");
 
   std::vector<Material *>::iterator mat_it;
   for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     Material & mat = **mat_it;
     mat.computeAllStresses(_not_ghost);
   }
 
 #ifdef AKANTU_DAMAGE_NON_LOCAL
   /* ------------------------------------------------------------------------ */
   /* Computation of the non local part */
   synch_registry->asynchronousSynchronize(_gst_mnl_for_average);
   AKANTU_DEBUG_INFO("Compute non local stresses for local elements");
 
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     Material & mat = **mat_it;
     mat.computeAllNonLocalStresses(_not_ghost);
   }
 
 
   AKANTU_DEBUG_INFO("Wait distant non local stresses");
   synch_registry->waitEndSynchronize(_gst_mnl_for_average);
 
   AKANTU_DEBUG_INFO("Compute non local stresses for ghosts elements");
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     Material & mat = **mat_it;
     mat.computeAllNonLocalStresses(_ghost);
   }
 #endif
 
   /* ------------------------------------------------------------------------ */
   /* assembling the forces internal */
   // communicate the stress
   AKANTU_DEBUG_INFO("Send data for residual assembly");
   synch_registry->asynchronousSynchronize(_gst_smm_stress);
 
   AKANTU_DEBUG_INFO("Assemble residual for local elements");
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     Material & mat = **mat_it;
     mat.assembleResidual(_not_ghost);
   }
 
 
   AKANTU_DEBUG_INFO("Wait distant stresses");
   // finalize communications
   synch_registry->waitEndSynchronize(_gst_smm_stress);
 
   AKANTU_DEBUG_INFO("Assemble residual for ghost elements");
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     Material & mat = **mat_it;
     mat.assembleResidual(_ghost);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::computeStresses() {
   if (isExplicit()) {
     // start synchronization
     synch_registry->asynchronousSynchronize(_gst_smm_uv);
     synch_registry->waitEndSynchronize(_gst_smm_uv);
 
     // compute stresses on all local elements for each materials
     std::vector<Material *>::iterator mat_it;
     for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
       Material & mat = **mat_it;
       mat.computeAllStresses(_not_ghost);
     }
 
     /* ------------------------------------------------------------------------ */
 #ifdef AKANTU_DAMAGE_NON_LOCAL
     /* Computation of the non local part */
     synch_registry->asynchronousSynchronize(_gst_mnl_for_average);
 
     for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
       Material & mat = **mat_it;
       mat.computeAllNonLocalStresses(_not_ghost);
     }
 
     synch_registry->waitEndSynchronize(_gst_mnl_for_average);
 
     for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
       Material & mat = **mat_it;
       mat.computeAllNonLocalStresses(_ghost);
     }
 #endif
   } else {
     std::vector<Material *>::iterator mat_it;
     for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
       Material & mat = **mat_it;
       mat.computeAllStressesFromTangentModuli(_not_ghost);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateResidualInternal() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_INFO("Update the residual");
   // f = f_ext - f_int - Ma - Cv = r - Ma - Cv;
 
   if(method != _static) {
     // f -= Ma
     if(mass_matrix) {
       // if full mass_matrix
       Array<Real> * Ma = new Array<Real>(*acceleration, true, "Ma");
       *Ma *= *mass_matrix;
       /// \todo check unit conversion for implicit dynamics
       //      *Ma /= f_m2a
       *residual -= *Ma;
       delete Ma;
     } else if (mass) {
 
       // else lumped mass
       UInt nb_nodes = acceleration->getSize();
       UInt nb_degree_of_freedom = acceleration->getNbComponent();
 
       Real * mass_val     = mass->storage();
       Real * accel_val    = acceleration->storage();
       Real * res_val      = residual->storage();
       bool * blocked_dofs_val = blocked_dofs->storage();
 
       for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) {
         if(!(*blocked_dofs_val)) {
           *res_val -= *accel_val * *mass_val /f_m2a;
         }
         blocked_dofs_val++;
         res_val++;
         mass_val++;
         accel_val++;
       }
     } else {
       AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix.");
     }
 
     // f -= Cv
     if(velocity_damping_matrix) {
       Array<Real> * Cv = new Array<Real>(*velocity);
       *Cv *= *velocity_damping_matrix;
       *residual -= *Cv;
       delete Cv;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateAcceleration() {
   AKANTU_DEBUG_IN();
 
   updateResidualInternal();
 
   if(method == _explicit_lumped_mass) {
     /* residual = residual_{n+1} - M * acceleration_n therefore
        solution = increment acceleration not acceleration */
     solveLumped(*increment_acceleration,
                 *mass,
                 *residual,
                 *blocked_dofs,
                 f_m2a);
   } else if (method == _explicit_consistent_mass) {
     solve<NewmarkBeta::_acceleration_corrector>(*increment_acceleration);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::solveLumped(Array<Real> & x,
                                       const Array<Real> & A,
                                       const Array<Real> & b,
                                       const Array<bool> & blocked_dofs,
                                       Real alpha) {
 
   Real * A_val = A.storage();
   Real * b_val = b.storage();
   Real * x_val = x.storage();
   bool * blocked_dofs_val = blocked_dofs.storage();
 
   UInt nb_degrees_of_freedom = x.getSize() * x.getNbComponent();
 
   for (UInt n = 0; n < nb_degrees_of_freedom; ++n) {
     if(!(*blocked_dofs_val)) {
       *x_val = alpha * (*b_val / *A_val);
     }
     x_val++;
     A_val++;
     b_val++;
     blocked_dofs_val++;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::explicitPred() {
   AKANTU_DEBUG_IN();
 
   if(increment_flag) {
     if(previous_displacement) increment->copy(*previous_displacement);
     else increment->copy(*displacement);
   }
 
   AKANTU_DEBUG_ASSERT(integrator,"itegrator should have been allocated: "
                       << "have called initExplicit ? "
                       << "or initImplicit ?");
 
   integrator->integrationSchemePred(time_step,
                                     *displacement,
                                     *velocity,
                                     *acceleration,
                                     *blocked_dofs);
 
   if(increment_flag) {
     Real * inc_val = increment->storage();
     Real * dis_val = displacement->storage();
     UInt nb_degree_of_freedom = displacement->getSize() * displacement->getNbComponent();
 
     for (UInt n = 0; n < nb_degree_of_freedom; ++n) {
       *inc_val = *dis_val - *inc_val;
       inc_val++;
       dis_val++;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::explicitCorr() {
   AKANTU_DEBUG_IN();
 
   integrator->integrationSchemeCorrAccel(time_step,
                                          *displacement,
                                          *velocity,
                                          *acceleration,
                                          *blocked_dofs,
                                          *increment_acceleration);
 
   if(previous_displacement) previous_displacement->copy(*displacement);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::solveStep() {
   AKANTU_DEBUG_IN();
 
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method));
 
   this->explicitPred();
   this->updateResidual();
   this->updateAcceleration();
   this->explicitCorr();
 
   EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method));
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 /* Implicit scheme                                                            */
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 /**
  * Initialize the solver and create the sparse matrices needed.
  *
  */
 void SolidMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) {
-#if !defined(AKANTU_USE_MUMPS) // or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake
+#if !defined(AKANTU_USE_MUMPS) && !defined(AKANTU_USE_PETSC)// or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake
   AKANTU_DEBUG_ERROR("You should at least activate one solver.");
 #else
   UInt nb_global_nodes = mesh.getNbGlobalNodes();
 
   delete jacobian_matrix;
   std::stringstream sstr; sstr << id << ":jacobian_matrix";
-  jacobian_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id);
 
+#ifdef AKANTU_USE_PETSC
+  jacobian_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id);
+#else
+  jacobian_matrix = new PETScMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id);
+#endif //AKANTU_USE PETSC
   jacobian_matrix->buildProfile(mesh, *dof_synchronizer, spatial_dimension);
 
   if (!isExplicit()) {
     delete stiffness_matrix;
     std::stringstream sstr_sti; sstr_sti << id << ":stiffness_matrix";
+#ifdef AKANTU_USE_PETSC
     stiffness_matrix = new SparseMatrix(*jacobian_matrix, sstr_sti.str(), memory_id);
+#else
+    stiffness_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id);
+    stiffness_matrix->buildProfile();
+#endif //AKANTU_USE_PETSC
   }
 
-#ifdef AKANTU_USE_MUMPS
   std::stringstream sstr_solv; sstr_solv << id << ":solver";
+#ifdef AKANTU_USE_MUMPS
   solver = new SolverMumps(*jacobian_matrix, sstr_solv.str());
-
   dof_synchronizer->initScatterGatherCommunicationScheme();
+#elif defined(AKANTU_USE_PETSC)
+  solver = new SolverPETSc(*jacobian_matrix, sstr_solv.str());
 #else
   AKANTU_DEBUG_ERROR("You should at least activate one solver.");
 #endif //AKANTU_USE_MUMPS
 
   if(solver)
     solver->initialize(options);
 #endif //AKANTU_HAS_SOLVER
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initJacobianMatrix() {
 #ifdef AKANTU_USE_MUMPS
   
   // @todo make it more flexible: this is an ugly patch to treat the case of non
   // fix profile of the K matrix
   delete jacobian_matrix;
   std::stringstream sstr_sti; sstr_sti << id << ":jacobian_matrix";
   jacobian_matrix = new SparseMatrix(*stiffness_matrix, sstr_sti.str(), memory_id);
 
   std::stringstream sstr_solv; sstr_solv << id << ":solver";
   delete solver;
   solver = new SolverMumps(*jacobian_matrix, sstr_solv.str());
   if(solver)
     solver->initialize(_solver_no_options);
 #else
-  AKANTU_DEBUG_ERROR("You should at least activate one solver.");
+  AKANTU_DEBUG_ERROR("You need to activate the solver mumps.");
 #endif
 }
 
 /* -------------------------------------------------------------------------- */
 /**
  * Initialize the implicit solver, either for dynamic or static cases,
  *
  * @param dynamic
  */
 void SolidMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) {
   AKANTU_DEBUG_IN();
 
   method = dynamic ? _implicit_dynamic : _static;
 
   if (!increment) setIncrementFlagOn();
 
   initSolver(solver_options);
 
   if(method == _implicit_dynamic) {
     if(integrator) delete integrator;
     integrator = new TrapezoidalRule2();
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::initialAcceleration() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_INFO("Solving Ma = f");
 
   Solver * acc_solver = NULL;
 
   std::stringstream sstr; sstr << id << ":tmp_mass_matrix";
   SparseMatrix * tmp_mass = new SparseMatrix(*mass_matrix, sstr.str(), memory_id);
 
 #ifdef AKANTU_USE_MUMPS
   std::stringstream sstr_solver; sstr << id << ":solver_mass_matrix";
   acc_solver = new SolverMumps(*mass_matrix, sstr_solver.str());
 
   dof_synchronizer->initScatterGatherCommunicationScheme();
 #else
   AKANTU_DEBUG_ERROR("You should at least activate one solver.");
 #endif //AKANTU_USE_MUMPS
 
   acc_solver->initialize();
 
   tmp_mass->applyBoundary(*blocked_dofs);
 
   acc_solver->setRHS(*residual);
   acc_solver->solve(*acceleration);
 
   delete acc_solver;
   delete tmp_mass;
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::assembleStiffnessMatrix() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_INFO("Assemble the new stiffness matrix.");
 
   stiffness_matrix->clear();
 
   // call compute stiffness matrix on each local elements
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     (*mat_it)->assembleStiffnessMatrix(_not_ghost);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 SparseMatrix & SolidMechanicsModel::initVelocityDampingMatrix() {
   if(!velocity_damping_matrix)
     velocity_damping_matrix =
       new SparseMatrix(*jacobian_matrix, id + ":velocity_damping_matrix", memory_id);
 
   return *velocity_damping_matrix;
 }
 
 /* -------------------------------------------------------------------------- */
 template<>
 bool SolidMechanicsModel::testConvergence<_scc_increment>(Real tolerance, Real & error){
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes = displacement->getSize();
   UInt nb_degree_of_freedom = displacement->getNbComponent();
 
   error = 0;
   Real norm[2] = {0., 0.};
   Real * increment_val    = increment->storage();
   bool * blocked_dofs_val     = blocked_dofs->storage();
   Real * displacement_val = displacement->storage();
 
   for (UInt n = 0; n < nb_nodes; ++n) {
     bool is_local_node = mesh.isLocalOrMasterNode(n);
     for (UInt d = 0; d < nb_degree_of_freedom; ++d) {
       if(!(*blocked_dofs_val) && is_local_node) {
         norm[0] += *increment_val * *increment_val;
         norm[1] += *displacement_val * *displacement_val;
       }
       blocked_dofs_val++;
       increment_val++;
       displacement_val++;
     }
   }
 
   StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum);
 
   norm[0] = sqrt(norm[0]);
   norm[1] = sqrt(norm[1]);
 
   AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something goes wrong in the solve phase");
 
   if (norm[1] < Math::getTolerance()) {
     error = norm[0];
     AKANTU_DEBUG_OUT();
     //    cout<<"Error 1: "<<error<<endl;
     return error < tolerance;
   }
 
 
   AKANTU_DEBUG_OUT();
   if(norm[1] > Math::getTolerance())
     error = norm[0] / norm[1];
   else
     error = norm[0]; //In case the total displacement is zero!
 
   //  cout<<"Error 2: "<<error<<endl;
 
   return (error < tolerance);
 }
 
 
 /* -------------------------------------------------------------------------- */
 template<>
 bool SolidMechanicsModel::testConvergence<_scc_residual>(Real tolerance, Real & norm) {
   AKANTU_DEBUG_IN();
 
 
 
   UInt nb_nodes = residual->getSize();
 
   norm = 0;
   Real * residual_val = residual->storage();
   bool * blocked_dofs_val = blocked_dofs->storage();
 
   for (UInt n = 0; n < nb_nodes; ++n) {
     bool is_local_node = mesh.isLocalOrMasterNode(n);
     if(is_local_node) {
       for (UInt d = 0; d < spatial_dimension; ++d) {
         if(!(*blocked_dofs_val)) {
           norm += *residual_val * *residual_val;
         }
         blocked_dofs_val++;
         residual_val++;
       }
     } else {
       blocked_dofs_val += spatial_dimension;
       residual_val += spatial_dimension;
     }
   }
 
   StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum);
 
   norm = sqrt(norm);
 
   AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase");
 
   AKANTU_DEBUG_OUT();
   return (norm < tolerance);
 }
 
 /* -------------------------------------------------------------------------- */
 template<>
 bool SolidMechanicsModel::testConvergence<_scc_residual_mass_wgh>(Real tolerance,
                                                                   Real & norm) {
   AKANTU_DEBUG_IN();
 
 
 
   UInt nb_nodes = residual->getSize();
 
   norm = 0;
   Real * residual_val = residual->storage();
   Real * mass_val = this->mass->storage();
   bool * blocked_dofs_val = blocked_dofs->storage();
 
   for (UInt n = 0; n < nb_nodes; ++n) {
     bool is_local_node = mesh.isLocalOrMasterNode(n);
     if(is_local_node) {
       for (UInt d = 0; d < spatial_dimension; ++d) {
         if(!(*blocked_dofs_val)) {
           norm += *residual_val * *residual_val/(*mass_val * *mass_val);
         }
         blocked_dofs_val++;
         residual_val++;
         mass_val++;
       }
     } else {
       blocked_dofs_val += spatial_dimension;
       residual_val += spatial_dimension;
       mass_val += spatial_dimension;
     }
   }
 
   StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum);
 
   norm = sqrt(norm);
 
   AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase");
 
   AKANTU_DEBUG_OUT();
   return (norm < tolerance);
 }
 
 /* -------------------------------------------------------------------------- */
 bool SolidMechanicsModel::testConvergenceResidual(Real tolerance){
   AKANTU_DEBUG_IN();
 
   Real error=0;
   bool res = this->testConvergence<_scc_residual>(tolerance, error);
   AKANTU_DEBUG_OUT();
   return res;
 }
 
 /* -------------------------------------------------------------------------- */
 bool SolidMechanicsModel::testConvergenceResidual(Real tolerance, Real & error){
   AKANTU_DEBUG_IN();
 
   bool res = this->testConvergence<_scc_residual>(tolerance, error);
 
   AKANTU_DEBUG_OUT();
   return res;
 }
 
 /* -------------------------------------------------------------------------- */
 bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance){
   AKANTU_DEBUG_IN();
 
   Real error=0;
   bool res = this->testConvergence<_scc_increment>(tolerance, error);
 
   AKANTU_DEBUG_OUT();
   return res;
 }
 
 /* -------------------------------------------------------------------------- */
 bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error){
   AKANTU_DEBUG_IN();
 
   bool res = this->testConvergence<_scc_increment>(tolerance, error);
 
   AKANTU_DEBUG_OUT();
   return res;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::implicitPred() {
   AKANTU_DEBUG_IN();
 
   if(previous_displacement) previous_displacement->copy(*displacement);
 
   if(method == _implicit_dynamic)
     integrator->integrationSchemePred(time_step,
                                       *displacement,
                                       *velocity,
                                       *acceleration,
                                       *blocked_dofs);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::implicitCorr() {
   AKANTU_DEBUG_IN();
 
   if(method == _implicit_dynamic) {
     integrator->integrationSchemeCorrDispl(time_step,
                                            *displacement,
                                            *velocity,
                                            *acceleration,
                                            *blocked_dofs,
                                            *increment);
   } else {
     UInt nb_nodes = displacement->getSize();
     UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes;
 
     Real * incr_val = increment->storage();
     Real * disp_val = displacement->storage();
     bool * boun_val = blocked_dofs->storage();
 
     for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++boun_val){
       *incr_val *= (1. - *boun_val);
       *disp_val += *incr_val;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateIncrement() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized."
                       << " Are you working with Finite or Ineslactic deformations?");
 
   UInt nb_nodes = displacement->getSize();
   UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes;
 
   Real * incr_val = increment->storage();
   Real * disp_val = displacement->storage();
   Real * prev_disp_val = previous_displacement->storage();
 
   for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++prev_disp_val)
     *incr_val = (*disp_val - *prev_disp_val);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updatePreviousDisplacement() {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized."
                       << " Are you working with Finite or Ineslactic deformations?");
 
   previous_displacement->copy(*displacement);
 
   AKANTU_DEBUG_OUT();
 }
 /* -------------------------------------------------------------------------- */
 /* Information                                                                */
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::synchronizeBoundaries() {
   AKANTU_DEBUG_IN();
   AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized."
                       << " Did you call initParallel?");
   synch_registry->synchronize(_gst_smm_boundary);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::synchronizeResidual() {
   AKANTU_DEBUG_IN();
   AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized."
                       << " Did you call initPBC?");
   synch_registry->synchronize(_gst_smm_res);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::setIncrementFlagOn() {
   AKANTU_DEBUG_IN();
 
   if(!increment) {
     UInt nb_nodes = mesh.getNbNodes();
     std::stringstream sstr_inc; sstr_inc << id << ":increment";
     increment = &(alloc<Real>(sstr_inc.str(), nb_nodes, spatial_dimension, 0.));
   }
 
   increment_flag = true;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getStableTimeStep() {
   AKANTU_DEBUG_IN();
 
   Real min_dt = getStableTimeStep(_not_ghost);
 
   /// reduction min over all processors
   StaticCommunicator::getStaticCommunicator().allReduce(&min_dt, 1, _so_min);
 
   AKANTU_DEBUG_OUT();
   return min_dt;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) {
   AKANTU_DEBUG_IN();
 
   Material ** mat_val = &(materials.at(0));
   Real min_dt = std::numeric_limits<Real>::max();
 
   updateCurrentPosition();
 
   Element elem;
   elem.ghost_type = ghost_type;
   elem.kind = _ek_regular;
 
   Mesh::type_iterator it  = mesh.firstType(spatial_dimension, ghost_type);
   Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type);
   for(; it != end; ++it) {
     elem.type = *it;
     UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it);
     UInt nb_element           = mesh.getNbElement(*it);
 
     Array<UInt>::iterator< Vector<UInt> > eibm =
       element_index_by_material(*it, ghost_type).begin(2);
 
     Array<Real> X(0, nb_nodes_per_element*spatial_dimension);
     FEEngine::extractNodalToElementField(mesh, *current_position,
                                          X, *it, _not_ghost);
 
     Array<Real>::matrix_iterator X_el =
       X.begin(spatial_dimension, nb_nodes_per_element);
 
     for (UInt el = 0; el < nb_element; ++el, ++X_el, ++eibm) {
       elem.element = (*eibm)(1);
       Real el_h  = getFEEngine().getElementInradius(*X_el, *it);
       Real el_c  = mat_val[(*eibm)(0)]->getCelerity(elem);
       Real el_dt = el_h / el_c;
 
       min_dt = std::min(min_dt, el_dt);
     }
   }
 
   AKANTU_DEBUG_OUT();
   return min_dt;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getPotentialEnergy() {
   AKANTU_DEBUG_IN();
   Real energy = 0.;
 
   /// call update residual on each local elements
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     energy += (*mat_it)->getPotentialEnergy();
   }
 
   /// reduction sum over all processors
   StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum);
 
   AKANTU_DEBUG_OUT();
   return energy;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getKineticEnergy() {
   AKANTU_DEBUG_IN();
 
   if (!mass && !mass_matrix)
     AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix.");
 
 
   Real ekin = 0.;
 
   UInt nb_nodes = mesh.getNbNodes();
 
   Real * vel_val  = velocity->storage();
   Real * mass_val = mass->storage();
 
   for (UInt n = 0; n < nb_nodes; ++n) {
     Real mv2 = 0;
     bool is_local_node = mesh.isLocalOrMasterNode(n);
     bool is_not_pbc_slave_node = !isPBCSlaveNode(n);
     bool count_node = is_local_node && is_not_pbc_slave_node;
     for (UInt i = 0; i < spatial_dimension; ++i) {
       if (count_node)
         mv2 += *vel_val * *vel_val * *mass_val;
 
       vel_val++;
       mass_val++;
     }
     ekin += mv2;
   }
 
   StaticCommunicator::getStaticCommunicator().allReduce(&ekin, 1, _so_sum);
 
   AKANTU_DEBUG_OUT();
   return ekin * .5;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) {
   AKANTU_DEBUG_IN();
 
   UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(type);
 
   Array<Real> vel_on_quad(nb_quadrature_points, spatial_dimension);
   Array<UInt> filter_element(1, 1, index);
 
   getFEEngine().interpolateOnQuadraturePoints(*velocity, vel_on_quad,
                                               spatial_dimension,
                                               type, _not_ghost,
                                               filter_element);
 
   Array<Real>::vector_iterator vit   = vel_on_quad.begin(spatial_dimension);
   Array<Real>::vector_iterator vend  = vel_on_quad.end(spatial_dimension);
 
   Vector<Real> rho_v2(nb_quadrature_points);
 
   Real rho = materials[element_index_by_material(type)(index, 0)]->getRho();
 
   for (UInt q = 0; vit != vend; ++vit, ++q) {
     rho_v2(q) = rho * vit->dot(*vit);
   }
 
   AKANTU_DEBUG_OUT();
 
   return .5*getFEEngine().integrate(rho_v2, type, index);
 }
 
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getExternalWork() {
   AKANTU_DEBUG_IN();
 
   Real * velo = velocity->storage();
   Real * forc = force->storage();
   Real * resi = residual->storage();
   bool * boun = blocked_dofs->storage();
 
   Real work = 0.;
 
   UInt nb_nodes = mesh.getNbNodes();
 
   for (UInt n = 0; n < nb_nodes; ++n) {
     bool is_local_node = mesh.isLocalOrMasterNode(n);
     bool is_not_pbc_slave_node = !isPBCSlaveNode(n);
     bool count_node = is_local_node && is_not_pbc_slave_node;
 
     for (UInt i = 0; i < spatial_dimension; ++i) {
       if (count_node) {
         if(*boun)
           work -= *resi * *velo * time_step;
         else
           work += *forc * *velo * time_step;
       }
 
       ++velo;
       ++forc;
       ++resi;
       ++boun;
     }
   }
 
   StaticCommunicator::getStaticCommunicator().allReduce(&work, 1, _so_sum);
 
   AKANTU_DEBUG_OUT();
   return work;
 }
 
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getEnergy(const std::string & energy_id) {
   AKANTU_DEBUG_IN();
 
   if (energy_id == "kinetic") {
     return getKineticEnergy();
   } else if (energy_id == "external work"){
     return getExternalWork();
   }
 
   Real energy = 0.;
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     energy += (*mat_it)->getEnergy(energy_id);
   }
 
   /// reduction sum over all processors
   StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum);
 
   AKANTU_DEBUG_OUT();
   return energy;
 }
 /* -------------------------------------------------------------------------- */
 Real SolidMechanicsModel::getEnergy(const std::string & energy_id,
                                     const ElementType & type,
                                     UInt index){
   AKANTU_DEBUG_IN();
 
   if (energy_id == "kinetic") {
     return getKineticEnergy(type, index);
   }
 
   std::vector<Material *>::iterator mat_it;
   Vector<UInt> mat = element_index_by_material(type, _not_ghost).begin(2)[index];
   Real energy = materials[mat(0)]->getEnergy(energy_id, type, mat(1));
 
   AKANTU_DEBUG_OUT();
   return energy;
 }
 
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onNodesAdded(const Array<UInt> & nodes_list,
                                        __attribute__((unused)) const NewNodesEvent & event) {
   AKANTU_DEBUG_IN();
   UInt nb_nodes = mesh.getNbNodes();
 
   if(displacement) displacement->resize(nb_nodes);
   if(mass        ) mass        ->resize(nb_nodes);
   if(velocity    ) velocity    ->resize(nb_nodes);
   if(acceleration) acceleration->resize(nb_nodes);
   if(force       ) force       ->resize(nb_nodes);
   if(residual    ) residual    ->resize(nb_nodes);
   if(blocked_dofs) blocked_dofs->resize(nb_nodes);
 
   if(previous_displacement) previous_displacement->resize(nb_nodes);
   if(increment_acceleration) increment_acceleration->resize(nb_nodes);
   if(increment) increment->resize(nb_nodes);
 
   if(current_position) current_position->resize(nb_nodes);
 
   delete dof_synchronizer;
   dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension);
   dof_synchronizer->initLocalDOFEquationNumbers();
   dof_synchronizer->initGlobalDOFEquationNumbers();
 
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     (*mat_it)->onNodesAdded(nodes_list, event);
   }
 
   if (method != _explicit_lumped_mass) {
     delete stiffness_matrix;
     delete jacobian_matrix;
     delete solver;
     SolverOptions  solver_options;
     initImplicit((method == _implicit_dynamic), solver_options);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onElementsAdded(const Array<Element> & element_list,
                                           const NewElementsEvent & event) {
   AKANTU_DEBUG_IN();
 
   getFEEngine().initShapeFunctions(_not_ghost);
   getFEEngine().initShapeFunctions(_ghost);
 
   Array<Element>::const_iterator<Element> it  = element_list.begin();
   Array<Element>::const_iterator<Element> end = element_list.end();
 
   /// \todo have rules to choose the correct material
   UInt mat_id = 0;
 
   UInt * mat_id_vect = NULL;
   try {
     const NewMaterialElementsEvent & event_mat = dynamic_cast<const NewMaterialElementsEvent &>(event);
     mat_id_vect = event_mat.getMaterialList().storage();
   } catch(...) {  }
 
   for (UInt el = 0; it != end; ++it, ++el) {
     const Element & elem = *it;
 
     if(mat_id_vect) mat_id = mat_id_vect[el];
     else mat_id = (*material_selector)(elem);
 
     Material & mat = *materials[mat_id];
 
     UInt mat_index = mat.addElement(elem.type, elem.element, elem.ghost_type);
     Vector<UInt> id(2);
     id[0] = mat_id; id[1] = mat_index;
     if(!element_index_by_material.exists(elem.type, elem.ghost_type))
       element_index_by_material.alloc(0, 2, elem.type, elem.ghost_type);
 
     element_index_by_material(elem.type, elem.ghost_type).push_back(id);
   }
 
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     (*mat_it)->onElementsAdded(element_list, event);
   }
 
   if(method != _explicit_lumped_mass) AKANTU_DEBUG_TO_IMPLEMENT();
 
   assembleMassLumped();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onElementsRemoved(__attribute__((unused)) const Array<Element> & element_list,
                                             const ElementTypeMapArray<UInt> & new_numbering,
                                             const RemovedElementsEvent & event) {
   //  MeshUtils::purifyMesh(mesh);
 
   getFEEngine().initShapeFunctions(_not_ghost);
   getFEEngine().initShapeFunctions(_ghost);
 
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     (*mat_it)->onElementsRemoved(element_list, new_numbering, event);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::onNodesRemoved(__attribute__((unused)) const Array<UInt> & element_list,
                                          const Array<UInt> & new_numbering,
                                          __attribute__((unused)) const RemovedNodesEvent & event) {
   if(displacement) mesh.removeNodesFromArray(*displacement, new_numbering);
   if(mass        ) mesh.removeNodesFromArray(*mass        , new_numbering);
   if(velocity    ) mesh.removeNodesFromArray(*velocity    , new_numbering);
   if(acceleration) mesh.removeNodesFromArray(*acceleration, new_numbering);
   if(force       ) mesh.removeNodesFromArray(*force       , new_numbering);
   if(residual    ) mesh.removeNodesFromArray(*residual    , new_numbering);
   if(blocked_dofs) mesh.removeNodesFromArray(*blocked_dofs, new_numbering);
 
   if(increment_acceleration) mesh.removeNodesFromArray(*increment_acceleration, new_numbering);
   if(increment)              mesh.removeNodesFromArray(*increment             , new_numbering);
 
   delete dof_synchronizer;
   dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension);
   dof_synchronizer->initLocalDOFEquationNumbers();
   dof_synchronizer->initGlobalDOFEquationNumbers();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::reassignMaterial() {
   AKANTU_DEBUG_IN();
 
   std::vector< Array<Element> > element_to_add   (materials.size());
   std::vector< Array<Element> > element_to_remove(materials.size());
 
   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;
 
     Mesh::type_iterator it  = mesh.firstType(spatial_dimension, ghost_type, _ek_regular);
     Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type, _ek_regular);
     for(; it != end; ++it) {
       ElementType type = *it;
       element.type = type;
       element.kind = Mesh::getKind(type);
 
       UInt nb_element = mesh.getNbElement(type, ghost_type);
       Array<UInt> & el_index_by_mat = element_index_by_material(type, ghost_type);
 
       for (UInt el = 0; el < nb_element; ++el) {
         element.element = el;
 
         UInt old_material = el_index_by_mat(el, 0);
         UInt new_material = (*material_selector)(element);
 
         if(old_material != new_material) {
           element_to_add   [new_material].push_back(element);
           element_to_remove[old_material].push_back(element);
         }
       }
     }
   }
 
   std::vector<Material *>::iterator mat_it;
   UInt mat_index = 0;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it, ++mat_index) {
     (*mat_it)->removeElements(element_to_remove[mat_index]);
     (*mat_it)->addElements   (element_to_add[mat_index]);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 bool SolidMechanicsModel::isInternal(const std::string & field_name,
 				     const ElementKind & element_kind){
 
   bool is_internal = false;
   
   /// check if at least one material contains field_id as an internal
   for (UInt m = 0; m < materials.size() && !is_internal; ++m) {
     is_internal |= materials[m]->isInternal(field_name, element_kind);
   }
   
   return is_internal;
 }
 /* -------------------------------------------------------------------------- */
 
 ElementTypeMap<UInt> SolidMechanicsModel::getInternalDataPerElem(const std::string & field_name,
 								const ElementKind & element_kind){
 
 
   if (!(this->isInternal(field_name,element_kind))) AKANTU_EXCEPTION("unknown internal " << field_name);
 
   for (UInt m = 0; m < materials.size() ; ++m) {
     if (materials[m]->isInternal(field_name, element_kind))
       return materials[m]->getInternalDataPerElem(field_name,element_kind);
   }
   
   return ElementTypeMap<UInt>();
 }
 
 
 /* -------------------------------------------------------------------------- */
 ElementTypeMapArray<Real> & SolidMechanicsModel::flattenInternal(const std::string & field_name,
 								const ElementKind & kind){
 
   std::pair<std::string,ElementKind> key(field_name,kind);
   if (this->registered_internals.count(key) == 0){
     this->registered_internals[key] =
       new ElementTypeMapArray<Real>(field_name,this->id);
   }
 
   ElementTypeMapArray<Real> * internal_flat = this->registered_internals[key];
   for (UInt m = 0; m < materials.size(); ++m)
     materials[m]->flattenInternal(field_name,*internal_flat,_not_ghost,kind);
   
   return  *internal_flat;
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::flattenAllRegisteredInternals(const ElementKind & kind){
 
   std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *> ::iterator it = this->registered_internals.begin();
   std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *>::iterator end = this->registered_internals.end();
 
   while (it != end){
     if (kind == it->first.second)
       this->flattenInternal(it->first.first,kind);
     ++it;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 
 void SolidMechanicsModel::onDump(){
   this->flattenAllRegisteredInternals(_ek_regular);
 }
 /* -------------------------------------------------------------------------- */
 
 #ifdef AKANTU_USE_IOHELPER
 
 dumper::Field * SolidMechanicsModel
 ::createElementalField(const std::string & field_name, 
 		       const std::string & group_name,
 		       bool padding_flag,
 		       const ElementKind & kind){
   
   dumper::Field * field = NULL;
 
   if(field_name == "partitions") 
     field = mesh.createElementalField<UInt, dumper::ElementPartitionField>(mesh.getConnectivities(),group_name,this->spatial_dimension,kind);
   else if(field_name == "element_index_by_material") 
     field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(element_index_by_material,group_name,this->spatial_dimension,kind);
   else {
 
     bool is_internal = this->isInternal(field_name,kind);
 
     if (is_internal) {
 
       ElementTypeMap<UInt> nb_data_per_elem = this->getInternalDataPerElem(field_name,kind);
       ElementTypeMapArray<Real> & internal_flat = this->flattenInternal(field_name,kind);
       field = mesh.createElementalField<Real, dumper::InternalMaterialField>(internal_flat,
 									     group_name,
 									     this->spatial_dimension,kind,nb_data_per_elem);
       
       //treat the paddings
       if (padding_flag){
 	if (field_name == "stress"){
 	  if (this->spatial_dimension == 2) {
 	    dumper::StressPadder<2> * foo = new dumper::StressPadder<2>(*this);
 	    field = dumper::FieldComputeProxy::createFieldCompute(field,*foo);
 	  }
 	}
 	// else if (field_name == "strain"){
 	//   if (this->spatial_dimension == 2) {
 	//     dumper::StrainPadder<2> * foo = new dumper::StrainPadder<2>(*this);
 	//     field = dumper::FieldComputeProxy::createFieldCompute(field,*foo);
 	//   }
 	// }
       }
 
       // homogenize the field
       dumper::ComputeFunctorInterface * foo = 
 	dumper::HomogenizerProxy::createHomogenizer(*field);
 
       field = dumper::FieldComputeProxy::createFieldCompute(field,*foo);
 
     } 
   }
   return field;
 }
 
 /* -------------------------------------------------------------------------- */
 
 dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name,
 							  const std::string & group_name,
 							  bool padding_flag) {
   
   std::map<std::string,Array<Real>* > real_nodal_fields;
   real_nodal_fields["displacement"             ] = displacement;
   real_nodal_fields["mass"                     ] = mass;
   real_nodal_fields["velocity"                 ] = velocity;
   real_nodal_fields["acceleration"             ] = acceleration;
   real_nodal_fields["force"                    ] = force;
   real_nodal_fields["residual"                 ] = residual;
   real_nodal_fields["increment"                ] = increment;
 
   dumper::Field * field = NULL;
   if (padding_flag)
     field = mesh.createNodalField(real_nodal_fields[field_name],group_name, 3);
   else
     field = mesh.createNodalField(real_nodal_fields[field_name],group_name);
   
   return field;
 }
 /* -------------------------------------------------------------------------- */
 
 dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name,
 							  const std::string & group_name,
 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;
 
 }
 /* -------------------------------------------------------------------------- */
 #else
 /* -------------------------------------------------------------------------- */
 
 dumper::Field * SolidMechanicsModel
 ::createElementalField(const std::string & field_name, 
 		       const std::string & group_name,
 		       bool padding_flag,
 		       const ElementKind & kind){
   return NULL;
 }
 
 /* -------------------------------------------------------------------------- */
 
 dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name,
 							  const std::string & group_name,
 							  bool padding_flag) {
   return NULL;
 }
 
 /* -------------------------------------------------------------------------- */
 
 dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name,
 							  const std::string & group_name,
 bool padding_flag) {
   return NULL;
 }
 
 #endif
 /* -------------------------------------------------------------------------- */
 
 void SolidMechanicsModel::dump(const std::string & dumper_name) {
   this->onDump();
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent());
   synch_registry->synchronize(_gst_for_dump);
   mesh.dump(dumper_name);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::dump(const std::string & dumper_name, UInt step) {
   this->onDump();
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent());
   synch_registry->synchronize(_gst_for_dump);
   mesh.dump(dumper_name, step);
 }
 
 /* ------------------------------------------------------------------------- */
 void SolidMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) {
   this->onDump();
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent());
   synch_registry->synchronize(_gst_for_dump);
   mesh.dump(dumper_name, time, step);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::dump() {
   this->onDump();
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent());
   mesh.dump();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::dump(UInt step) {
   this->onDump();
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent());
   mesh.dump(step);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::dump(Real time, UInt step) {
   this->onDump();
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent());
   mesh.dump(time, step);
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::computeCauchyStresses() {
   AKANTU_DEBUG_IN();
 
   // call compute stiffness matrix on each local elements
   std::vector<Material *>::iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     Material & mat = **mat_it;
     if(mat.isFiniteDeformation())
       mat.computeAllCauchyStresses(_not_ghost);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::saveStressAndStrainBeforeDamage() {
   EventManager::sendEvent(SolidMechanicsModelEvent::BeginningOfDamageIterationEvent());
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::updateEnergiesAfterDamage() {
   EventManager::sendEvent(SolidMechanicsModelEvent::AfterDamageEvent());
 }
 
 /* -------------------------------------------------------------------------- */
 void SolidMechanicsModel::printself(std::ostream & stream, int indent) const {
   std::string space;
   for(Int i = 0; i < indent; i++, space += AKANTU_INDENT);
 
   stream << space << "Solid Mechanics Model [" << std::endl;
   stream << space << " + id                : " << id << std::endl;
   stream << space << " + spatial dimension : " << spatial_dimension << std::endl;
   stream << space << " + fem [" << std::endl;
   getFEEngine().printself(stream, indent + 2);
   stream << space << AKANTU_INDENT << "]" << std::endl;
   stream << space << " + nodals information [" << std::endl;
   displacement->printself(stream, indent + 2);
   mass        ->printself(stream, indent + 2);
   velocity    ->printself(stream, indent + 2);
   acceleration->printself(stream, indent + 2);
   force       ->printself(stream, indent + 2);
   residual    ->printself(stream, indent + 2);
   blocked_dofs->printself(stream, indent + 2);
   stream << space << AKANTU_INDENT << "]" << std::endl;
 
   stream << space << " + connectivity type information [" << std::endl;
   element_index_by_material.printself(stream, indent + 2);
   stream << space << AKANTU_INDENT << "]" << std::endl;
 
   stream << space << " + materials [" << std::endl;
   std::vector<Material *>::const_iterator mat_it;
   for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) {
     const Material & mat = *(*mat_it);
     mat.printself(stream, indent + 1);
   }
   stream << space << AKANTU_INDENT << "]" << std::endl;
 
   stream << space << "]" << std::endl;
 }
 
 /* -------------------------------------------------------------------------- */
 
 __END_AKANTU__
diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh
index 5209ed661..9a6b33463 100644
--- a/src/model/solid_mechanics/solid_mechanics_model.hh
+++ b/src/model/solid_mechanics/solid_mechanics_model.hh
@@ -1,737 +1,736 @@
 /**
  * @file   solid_mechanics_model.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Tue Jul 27 2010
  * @date last modification: Tue Sep 16 2014
  *
  * @brief  Model of Solid Mechanics
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__
 #define __AKANTU_SOLID_MECHANICS_MODEL_HH__
 
 
 /* -------------------------------------------------------------------------- */
 #include <fstream>
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "aka_types.hh"
 #include "model.hh"
 #include "data_accessor.hh"
 #include "mesh.hh"
 #include "dumpable.hh"
 #include "boundary_condition.hh"
 #include "integrator_gauss.hh"
 #include "shape_lagrange.hh"
 #include "integration_scheme_2nd_order.hh"
 #include "solver.hh"
 #include "material_selector.hh"
 #include "solid_mechanics_model_event_handler.hh"
 /* -------------------------------------------------------------------------- */
 namespace akantu {
   class Material;
   class IntegrationScheme2ndOrder;
   class SparseMatrix;
   class DumperIOHelper;
 }
 /* -------------------------------------------------------------------------- */
 
 
 __BEGIN_AKANTU__
 
 struct SolidMechanicsModelOptions : public ModelOptions {
   SolidMechanicsModelOptions(AnalysisMethod analysis_method = _explicit_lumped_mass,
 			     bool no_init_materials = false) :
     analysis_method(analysis_method),
     no_init_materials(no_init_materials)  {  }
   AnalysisMethod analysis_method;
   bool no_init_materials;
 };
 
 extern const SolidMechanicsModelOptions default_solid_mechanics_model_options;
 
 
 class SolidMechanicsModel : public Model,
 			    public DataAccessor,
 			    public MeshEventHandler,
 			    public BoundaryCondition<SolidMechanicsModel>,
                             public EventHandlerManager<SolidMechanicsModelEventHandler> {
 
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   class NewMaterialElementsEvent : public NewElementsEvent {
   public:
     AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array <UInt> &);
     AKANTU_GET_MACRO(MaterialList, material, const Array <UInt> &);
   protected:
     Array <UInt> material;
   };
 
   typedef FEEngineTemplate <IntegratorGauss, ShapeLagrange> MyFEEngineType;
 
 protected:
   typedef EventHandlerManager <SolidMechanicsModelEventHandler> EventManager;
 
 public:
   SolidMechanicsModel(Mesh & mesh,
 		      UInt spatial_dimension = _all_dimensions,
 		      const ID & id = "solid_mechanics_model",
 		      const MemoryID & memory_id = 0);
 
   virtual ~SolidMechanicsModel();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// initialize completely the model
   virtual void initFull(const ModelOptions & options = default_solid_mechanics_model_options);
 
   /// initialize the fem object needed for boundary conditions
   void initFEEngineBoundary();
 
   /// register the tags associated with the parallel synchronizer
   void initParallel(MeshPartition *partition, DataAccessor *data_accessor = NULL);
 
   /// allocate all vectors
   void initArrays();
 
   /// allocate all vectors
   void initArraysPreviousDisplacment();
 
   /// initialize all internal arrays for materials
   virtual void initMaterials();
 
   /// initialize the model
   virtual void initModel();
 
   /// init PBC synchronizer
   void initPBC();
 
   /// function to print the containt of the class
   virtual void printself(std::ostream & stream, int indent = 0) const;
 
   /* ------------------------------------------------------------------------ */
   /* PBC                                                                      */
   /* ------------------------------------------------------------------------ */
 public:
   /// change the equation number for proper assembly when using PBC
   void changeEquationNumberforPBC(std::map <UInt, UInt> & pbc_pair);
 
   /// synchronize Residual for output
   void synchronizeResidual();
 
 protected:
   /// register PBC synchronizer
   void registerPBCSynchronizer();
 
   /* ------------------------------------------------------------------------ */
   /* Explicit                                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   /// initialize the stuff for the explicit scheme
   void initExplicit(AnalysisMethod analysis_method = _explicit_lumped_mass);
 
   bool isExplicit() {
     return method == _explicit_lumped_mass || method == _explicit_consistent_mass;
   }
 
   /// initialize the array needed by updateResidual (residual, current_position)
   void initializeUpdateResidualData();
 
   /// update the current position vector
   void updateCurrentPosition();
 
   /// assemble the residual for the explicit scheme
   virtual void updateResidual(bool need_initialize = true);
 
   /**
    * \brief compute the acceleration from the residual
    * this function is the explicit equivalent to solveDynamic in implicit
    * In the case of lumped mass just divide the residual by the mass
    * In the case of not lumped mass call solveDynamic<_acceleration_corrector>
    */
   void updateAcceleration();
 
   void updateIncrement();
   void updatePreviousDisplacement();
   void saveStressAndStrainBeforeDamage();
   void updateEnergiesAfterDamage();
 
   /// Solve the system @f[ A x = \alpha b @f] with A a lumped matrix
   void solveLumped(Array <Real> &       x,
 		   const Array <Real> & A,
 		   const Array <Real> & b,
 		   const Array <bool> & blocked_dofs,
 		   Real                 alpha);
 
   /// explicit integration predictor
   void explicitPred();
 
   /// explicit integration corrector
   void explicitCorr();
 
 public:
   void solveStep();
 
   /* ------------------------------------------------------------------------ */
   /* Implicit                                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   /// initialize the solver and the jacobian_matrix (called by initImplicit)
   void initSolver(SolverOptions & options = _solver_no_options);
 
   /// initialize the stuff for the implicit solver
   void initImplicit(bool            dynamic = false,
 		    SolverOptions & solver_options = _solver_no_options);
 
   /// solve Ma = f to get the initial acceleration
   void initialAcceleration();
 
   /// assemble the stiffness matrix
   void assembleStiffnessMatrix();
 
 public:
   /**
    * solve a step (predictor + convergence loop + corrector) using the
    * the given convergence method (see akantu::SolveConvergenceMethod)
    * and the given convergence criteria (see
    * akantu::SolveConvergenceCriteria)
    **/
   template <SolveConvergenceMethod method, SolveConvergenceCriteria criteria>
   bool solveStep(Real tolerance, UInt max_iteration = 100);
 
   template <SolveConvergenceMethod method, SolveConvergenceCriteria criteria>
   bool solveStep(Real   tolerance,
 		 Real & error,
 		 UInt   max_iteration = 100,
 		 bool   do_not_factorize = false);
 
 public:
   /**
    * solve Ku = f using the the given convergence method (see
    * akantu::SolveConvergenceMethod) and the given convergence
    * criteria (see akantu::SolveConvergenceCriteria)
    **/
   template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria>
   bool solveStatic(Real tolerance, UInt max_iteration,
 		   bool do_not_factorize = false);
 
   /// test if the system is converged
   template <SolveConvergenceCriteria criteria>
   bool testConvergence(Real tolerance, Real & error);
 
   /// test the convergence (norm of increment)
   bool testConvergenceIncrement(Real tolerance) __attribute__((deprecated));
   bool testConvergenceIncrement(Real tolerance, Real & error) __attribute__((deprecated));
 
   /// test the convergence (norm of residual)
   bool testConvergenceResidual(Real tolerance) __attribute__((deprecated));
   bool testConvergenceResidual(Real tolerance, Real & error) __attribute__((deprecated));
 
   /// create and return the velocity damping matrix
   SparseMatrix & initVelocityDampingMatrix();
 
   /// implicit time integration predictor
   void implicitPred();
 
   /// implicit time integration corrector
   void implicitCorr();
 
   /// compute the Cauchy stress on user demand.
   void computeCauchyStresses();
 
 protected:
   /// finish the computation of residual to solve in increment
   void updateResidualInternal();
 
   /// compute the support reaction and store it in force
   void updateSupportReaction();
 
 
 public:
 
   //protected: Daniel changed it just for a test
   /// compute A and solve @f[ A\delta u = f_ext - f_int @f]
   template <NewmarkBeta::IntegrationSchemeCorrectorType type>
   void solve(Array<Real> &increment, Real block_val = 1.,
-             bool need_factorize = true, bool has_profile_changed = false,
-             const Array<Real> &rhs = Array<Real>());
+             bool need_factorize = true, bool has_profile_changed = false);
 
 private:
   /// re-initialize the J matrix (to use if the profile of K changed)
   void initJacobianMatrix();
 
   /* ------------------------------------------------------------------------ */
   /* Explicit/Implicit                                                        */
   /* ------------------------------------------------------------------------ */
 
 public:
   /// Update the stresses for the computation of the residual of the Stiffness
   /// matrix in the case of finite deformation
   void computeStresses();
 
   /// synchronize the ghost element boundaries values
   void synchronizeBoundaries();
 
   /* ------------------------------------------------------------------------ */
   /* Materials (solid_mechanics_model_material.cc)                            */
   /* ------------------------------------------------------------------------ */
 public:
   /// registers all the custom materials of a given type present in the input file
   template <typename M>
   void registerNewCustomMaterials(const ID & mat_type);
 
   /// register an empty material of a given type
   template <typename M>
   Material & registerNewEmptyMaterial(const std::string & name);
 
   // /// Use a UIntData in the mesh to specify the material to use per element
   // void setMaterialIDsFromIntData(const std::string & data_name);
 
   /// reassigns materials depending on the material selector
   virtual void reassignMaterial();
 
 protected:
   /// register a material in the dynamic database
   template <typename M>
   Material & registerNewMaterial(const ParserSection & mat_section);
 
   /// read the material files to instantiate all the materials
   void instantiateMaterials();
 
   /* ------------------------------------------------------------------------ */
   /* Mass (solid_mechanics_model_mass.cc)                                     */
   /* ------------------------------------------------------------------------ */
 public:
   /// assemble the lumped mass matrix
   void assembleMassLumped();
 
   /// assemble the mass matrix for consistent mass resolutions
   void assembleMass();
 
 
 protected:
   /// assemble the lumped mass matrix for local and ghost elements
   void assembleMassLumped(GhostType ghost_type);
 
   /// assemble the mass matrix for either _ghost or _not_ghost elements
   void assembleMass(GhostType ghost_type);
 
   /// fill a vector of rho
   void computeRho(Array <Real> & rho,
 		  ElementType    type,
 		  GhostType      ghost_type);
 
 
   /* ------------------------------------------------------------------------ */
   /* Data Accessor inherited members                                          */
   /* ------------------------------------------------------------------------ */
 public:
   inline virtual UInt getNbDataForElements(const Array <Element> & elements,
-					   SynchronizationTag      tag) const;
+					   SynchronizationTag tag) const;
 
   inline virtual void packElementData(CommunicationBuffer &   buffer,
 				      const Array <Element> & elements,
 				      SynchronizationTag      tag) const;
 
   inline virtual void unpackElementData(CommunicationBuffer &   buffer,
 					const Array <Element> & elements,
 					SynchronizationTag      tag);
 
   inline virtual UInt getNbDataToPack(SynchronizationTag tag) const;
   inline virtual UInt getNbDataToUnpack(SynchronizationTag tag) const;
 
   inline virtual void packData(CommunicationBuffer & buffer,
 			       const UInt            index,
 			       SynchronizationTag    tag) const;
 
   inline virtual void unpackData(CommunicationBuffer & buffer,
 				 const UInt            index,
 				 SynchronizationTag    tag);
 
 protected:
   inline void splitElementByMaterial(const Array <Element> & elements,
 				     Array <Element> *       elements_per_mat) const;
 
   /* ------------------------------------------------------------------------ */
   /* Mesh Event Handler inherited members                                     */
   /* ------------------------------------------------------------------------ */
 protected:
   virtual void onNodesAdded(const Array <UInt> &  nodes_list,
 			    const NewNodesEvent & event);
   virtual void onNodesRemoved(const Array <UInt> &      element_list,
 			      const Array <UInt> &      new_numbering,
 			      const RemovedNodesEvent & event);
   virtual void onElementsAdded(const Array <Element> &  nodes_list,
 			       const NewElementsEvent & event);
   virtual void onElementsRemoved(const Array <Element> &      element_list,
 				 const ElementTypeMapArray<UInt> &    new_numbering,
 				 const RemovedElementsEvent & event);
 
   /* ------------------------------------------------------------------------ */
   /* Dumpable interface (kept for convenience) and dumper relative functions  */
   /* ------------------------------------------------------------------------ */
 public:
 
 
   virtual void onDump();
 
   //! decide wether a field is a material internal or not
   bool isInternal(const std::string & field_name, const ElementKind & element_kind);
   //! give the amount of data per element
   ElementTypeMap<UInt> getInternalDataPerElem(const std::string & field_name,
 					     const ElementKind & kind);
 
   //! flatten a given material internal field 
   ElementTypeMapArray<Real> & flattenInternal(const std::string & field_name,
 					     const ElementKind & kind);
   //! flatten all the registered material internals
   void flattenAllRegisteredInternals(const ElementKind & kind);
 
 
   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);
 
 
 
   virtual void dump(const std::string & dumper_name);
 
   virtual void dump(const std::string & dumper_name, UInt step);
 
   virtual void dump(const std::string & dumper_name, Real time, UInt step);
 
   virtual void dump();
 
   virtual void dump(UInt step);
 
   virtual void dump(Real time, UInt step);
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// return the dimension of the system space
   AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt);
 
   /// get the current value of the time step
   AKANTU_GET_MACRO(TimeStep, time_step, Real);
   /// set the value of the time step
   void setTimeStep(Real time_step);
 
   /// get the value of the conversion from forces/ mass to acceleration
   AKANTU_GET_MACRO(F_M2A, f_m2a, Real);
 
   /// set the value of the conversion from forces/ mass to acceleration
   AKANTU_SET_MACRO(F_M2A, f_m2a, Real);
 
   /// get the SolidMechanicsModel::displacement vector
   AKANTU_GET_MACRO(Displacement,    *displacement,           Array <Real> &);
 
   /// get the SolidMechanicsModel::previous_displacement vector
   AKANTU_GET_MACRO(PreviousDisplacement, *previous_displacement, Array <Real> &);
 
   /// get the SolidMechanicsModel::current_position vector \warn only consistent
   /// after a call to SolidMechanicsModel::updateCurrentPosition
   AKANTU_GET_MACRO(CurrentPosition, *current_position, const Array <Real> &);
 
   /// get  the SolidMechanicsModel::increment  vector \warn  only  consistent if
   /// SolidMechanicsModel::setIncrementFlagOn has been called before
   AKANTU_GET_MACRO(Increment,       *increment,              Array <Real> &);
 
   /// get the lumped SolidMechanicsModel::mass vector
   AKANTU_GET_MACRO(Mass,            *mass,                   Array <Real> &);
 
   /// get the SolidMechanicsModel::velocity vector
   AKANTU_GET_MACRO(Velocity,        *velocity,               Array <Real> &);
 
   /// get    the    SolidMechanicsModel::acceleration    vector,   updated    by
   /// SolidMechanicsModel::updateAcceleration
   AKANTU_GET_MACRO(Acceleration,    *acceleration,           Array <Real> &);
 
   /// get the SolidMechanicsModel::force vector (boundary forces)
   AKANTU_GET_MACRO(Force,           *force,                  Array <Real> &);
 
   /// get     the    SolidMechanicsModel::residual    vector,     computed    by
   /// SolidMechanicsModel::updateResidual
   AKANTU_GET_MACRO(Residual,        *residual,               Array <Real> &);
 
   /// get the SolidMechanicsModel::blocked_dofs vector
   AKANTU_GET_MACRO(BlockedDOFs,     *blocked_dofs,           Array <bool> &);
 
   /// get the SolidMechnicsModel::incrementAcceleration vector
   AKANTU_GET_MACRO(IncrementAcceleration, *increment_acceleration, Array <Real> &);
 
   /// get the value of the SolidMechanicsModel::increment_flag
   AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool);
 
   /// get a particular material (by material index)
   inline Material & getMaterial(UInt mat_index);
 
   /// get a particular material (by material index)
   inline const Material & getMaterial(UInt mat_index) const;
 
   /// get a particular material (by material name)
   inline Material & getMaterial(const std::string & name);
 
   /// get a particular material (by material name)
   inline const Material & getMaterial(const std::string & name) const;
 
   /// get a particular material id from is name
   inline UInt getMaterialIndex(const std::string & name) const;
 
   /// give the number of materials
   inline UInt getNbMaterials() const {
     return materials.size();
   }
 
   inline void setMaterialSelector(MaterialSelector & selector);
 
   /// give the material internal index from its id
   Int getInternalIndexFromID(const ID & id) const;
 
   /// compute the stable time step
   Real getStableTimeStep();
 
   /// compute the potential energy
   Real getPotentialEnergy();
 
   /// compute the kinetic energy
   Real getKineticEnergy();
   Real getKineticEnergy(const ElementType & type, UInt index);
 
   /// compute the external work (for impose displacement, the velocity should be given too)
   Real getExternalWork();
 
   /// get the energies
   Real getEnergy(const std::string & energy_id);
 
   /// compute the energy for energy
   Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index);
 
   /**
    * @brief set the SolidMechanicsModel::increment_flag  to on, the activate the
    * update of the SolidMechanicsModel::increment vector
    */
   void setIncrementFlagOn();
 
   /// get the stiffness matrix
   AKANTU_GET_MACRO(StiffnessMatrix, *stiffness_matrix, SparseMatrix &);
 
   /// get the global jacobian matrix of the system
   AKANTU_GET_MACRO(GlobalJacobianMatrix, *jacobian_matrix, const SparseMatrix &);
 
   /// get the mass matrix
   AKANTU_GET_MACRO(MassMatrix, *mass_matrix, SparseMatrix &);
 
   /// get the velocity damping matrix
   AKANTU_GET_MACRO(VelocityDampingMatrix, *velocity_damping_matrix, SparseMatrix &);
 
   /// get the FEEngine object to integrate or interpolate on the boundary
   inline FEEngine & getFEEngineBoundary(const ID & name = "");
 
   /// get integrator
   AKANTU_GET_MACRO(Integrator, *integrator, const IntegrationScheme2ndOrder &);
 
   /// get access to the internal solver
   AKANTU_GET_MACRO(Solver, *solver, Solver &);
 
   /// get synchronizer
   AKANTU_GET_MACRO(Synchronizer, *synch_parallel, const DistributedSynchronizer &);
 
   AKANTU_GET_MACRO(ElementIndexByMaterial, element_index_by_material, const ElementTypeMapArray <UInt> &);
 
   /// vectors containing local material element index for each global element index
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementIndexByMaterial, element_index_by_material, UInt);
   AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementIndexByMaterial, element_index_by_material, UInt);
 
   /// Get the type of analysis method used
   AKANTU_GET_MACRO(AnalysisMethod, method, AnalysisMethod);
 
 
   template <int dim, class model_type>
   friend struct ContactData;
 
   template <int Dim, AnalysisMethod s, ContactResolutionMethod r>
   friend class ContactResolution;
             
 
 protected:
   friend class Material;
 
   template <UInt DIM, template <UInt> class WeightFunction>
   friend class MaterialNonLocal;
 protected:
   /// compute the stable time step
   Real getStableTimeStep(const GhostType & ghost_type);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// time step
   Real time_step;
 
   /// conversion coefficient form force/mass to acceleration
   Real f_m2a;
 
   /// displacements array
   Array <Real> *displacement;
 
   /// displacements array at the previous time step (used in finite deformation)
   Array <Real> *previous_displacement;
 
   /// lumped mass array
   Array <Real> *mass;
 
   /// velocities array
   Array <Real> *velocity;
 
   /// accelerations array
   Array <Real> *acceleration;
 
   /// accelerations array
   Array <Real> *increment_acceleration;
 
   /// forces array
   Array <Real> *force;
 
   /// residuals array
   Array <Real> *residual;
 
   /// array specifing if a degree of freedom is blocked or not
   Array <bool> *blocked_dofs;
 
   /// array of current position used during update residual
   Array <Real> *current_position;
 
   /// mass matrix
   SparseMatrix *mass_matrix;
 
   /// velocity damping matrix
   SparseMatrix *velocity_damping_matrix;
 
   /// stiffness matrix
   SparseMatrix *stiffness_matrix;
 
   /// jacobian matrix @f[A = cM + dD + K@f] with @f[c = \frac{1}{\beta \Delta
   /// t^2}, d = \frac{\gamma}{\beta \Delta t} @f]
   SparseMatrix *jacobian_matrix;
 
   /// vectors containing local material element index for each global element index
   ElementTypeMapArray<UInt> element_index_by_material;
 
   /// list of used materials
   std::vector <Material *> materials;
 
   /// mapping between material name and material internal id
   std::map <std::string, UInt> materials_names_to_id;
 
   /// class defining of to choose a material
   MaterialSelector *material_selector;
 
   /// define if it is the default selector or not
   bool is_default_material_selector;
 
   /// integration scheme of second order used
   IntegrationScheme2ndOrder *integrator;
 
   /// increment of displacement
   Array <Real> *increment;
 
   /// flag defining if the increment must be computed or not
   bool increment_flag;
 
   /// solver for implicit
   Solver *solver;
 
   /// analysis method check the list in akantu::AnalysisMethod
   AnalysisMethod method;
 
   /// internal synchronizer for parallel computations
   DistributedSynchronizer *synch_parallel;
 
   /// tells if the material are instantiated
   bool are_materials_instantiated;
 
   /// map a registered internals to be flattened for dump purposes
   std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *> registered_internals;
 };
 
 
 /* -------------------------------------------------------------------------- */
 namespace BC {
   namespace Neumann {
     typedef FromHigherDim FromStress;
     typedef FromSameDim FromTraction;
   }
 }
 
 __END_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 #include "parser.hh"
 #include "material.hh"
 
 __BEGIN_AKANTU__
 
 #include "solid_mechanics_model_tmpl.hh"
 
 #if defined (AKANTU_INCLUDE_INLINE_IMPL)
 #  include "solid_mechanics_model_inline_impl.cc"
 #endif
 
 /// standard output stream operator
 inline std::ostream & operator << (std::ostream & stream, const SolidMechanicsModel &_this) {
   _this.printself(stream);
   return stream;
 }
 
 __END_AKANTU__
 
 	#include "material_selector_tmpl.hh"
 
 
 	#endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */
diff --git a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc
index d4aece91b..48d6b26f6 100644
--- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc
+++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc
@@ -1,609 +1,608 @@
 /**
  * @file   solid_mechanics_model_inline_impl.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Aug 04 2010
  * @date last modification: Mon Sep 15 2014
  *
  * @brief  Implementation of the inline functions of the SolidMechanicsModel class
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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 Material & SolidMechanicsModel::getMaterial(UInt mat_index) {
   AKANTU_DEBUG_IN();
   AKANTU_DEBUG_ASSERT(mat_index < materials.size(),
                      "The model " << id << " has no material no "<< mat_index);
   AKANTU_DEBUG_OUT();
   return *materials[mat_index];
 }
 
 /* -------------------------------------------------------------------------- */
 inline const Material & SolidMechanicsModel::getMaterial(UInt mat_index) const {
   AKANTU_DEBUG_IN();
   AKANTU_DEBUG_ASSERT(mat_index < materials.size(),
                      "The model " << id << " has no material no "<< mat_index);
   AKANTU_DEBUG_OUT();
   return *materials[mat_index];
 }
 
 /* -------------------------------------------------------------------------- */
 inline Material & SolidMechanicsModel::getMaterial(const std::string & name) {
   AKANTU_DEBUG_IN();
   std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name);
   AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(),
                      "The model " << id << " has no material named "<< name);
   AKANTU_DEBUG_OUT();
   return *materials[it->second];
 }
 
 /* -------------------------------------------------------------------------- */
 inline UInt SolidMechanicsModel::getMaterialIndex(const std::string & name) const {
   AKANTU_DEBUG_IN();
   std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name);
   AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(),
                       "The model " << id << " has no material named "<< name);
   AKANTU_DEBUG_OUT();
   return it->second;
 }
 
 /* -------------------------------------------------------------------------- */
 inline const Material & SolidMechanicsModel::getMaterial(const std::string & name) const {
   AKANTU_DEBUG_IN();
   std::map<std::string, UInt>::const_iterator it = materials_names_to_id.find(name);
   AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(),
                       "The model " << id << " has no material named "<< name);
   AKANTU_DEBUG_OUT();
   return *materials[it->second];
 }
 
 /* -------------------------------------------------------------------------- */
 inline void SolidMechanicsModel::setMaterialSelector(MaterialSelector & selector) {
   if(is_default_material_selector) delete material_selector;
   material_selector = &selector;
   is_default_material_selector = false;
 }
 
 /* -------------------------------------------------------------------------- */
 inline FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) {
   return dynamic_cast<FEEngine &>(getFEEngineClassBoundary<MyFEEngineType>(name));
 }
 
 /* -------------------------------------------------------------------------- */
 inline void SolidMechanicsModel::splitElementByMaterial(const Array<Element> & elements,
                                                        Array<Element> * elements_per_mat) const {
   ElementType current_element_type = _not_defined;
   GhostType current_ghost_type = _casper;
   const Array<UInt> * elem_mat = NULL;
 
   Array<Element>::const_iterator<Element> it  = elements.begin();
   Array<Element>::const_iterator<Element> end = elements.end();
   for (; it != end; ++it) {
     Element el = *it;
 
     if(el.type != current_element_type || el.ghost_type != current_ghost_type) {
       current_element_type = el.type;
       current_ghost_type   = el.ghost_type;
       elem_mat = &element_index_by_material(el.type, el.ghost_type);
     }
 
     UInt old_id = el.element;
     el.element = (*elem_mat)(old_id, 1);
     elements_per_mat[(*elem_mat)(old_id, 0)].push_back(el);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 inline UInt SolidMechanicsModel::getNbDataForElements(const Array<Element> & elements,
                                                      SynchronizationTag tag) const {
   AKANTU_DEBUG_IN();
 
   UInt size = 0;
   UInt nb_nodes_per_element = 0;
 
   Array<Element>::const_iterator<Element> it  = elements.begin();
   Array<Element>::const_iterator<Element> end = elements.end();
   for (; it != end; ++it) {
     const Element & el = *it;
     nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type);
   }
 
   switch(tag) {
   case _gst_material_id: {
     size += elements.getSize() * 2 * sizeof(UInt);
     break;
   }
   case _gst_smm_mass: {
     size += nb_nodes_per_element * sizeof(Real) * spatial_dimension; // mass vector
     break;
   }
   case _gst_smm_for_gradu: {
     size += nb_nodes_per_element * spatial_dimension * sizeof(Real); // displacement
    break;
   }
   case _gst_smm_boundary: {
     // force, displacement, boundary
     size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool));
     break;
   }
   default: {  }
   }
 
   if(tag != _gst_material_id) {
     Array<Element> * elements_per_mat = new Array<Element>[materials.size()];
     this->splitElementByMaterial(elements, elements_per_mat);
 
     for (UInt i = 0; i < materials.size(); ++i) {
       size += materials[i]->getNbDataForElements(elements_per_mat[i], tag);
     }
     delete [] elements_per_mat;
   }
 
   AKANTU_DEBUG_OUT();
   return size;
 }
 
 /* -------------------------------------------------------------------------- */
 inline void SolidMechanicsModel::packElementData(CommunicationBuffer & buffer,
                                                 const Array<Element> & elements,
                                                 SynchronizationTag tag) const {
   AKANTU_DEBUG_IN();
 
   switch(tag) {
   case _gst_material_id: {
     packElementalDataHelper(element_index_by_material, buffer, elements, false, getFEEngine());
     break;
   }
   case _gst_smm_mass: {
     packNodalDataHelper(*mass, buffer, elements, mesh);
     break;
   }
   case _gst_smm_for_gradu: {
     packNodalDataHelper(*displacement, buffer, elements, mesh);
     break;
   }
   case _gst_smm_boundary: {
     packNodalDataHelper(*force, buffer, elements, mesh);
     packNodalDataHelper(*velocity, buffer, elements, mesh);
     packNodalDataHelper(*blocked_dofs, buffer, elements, mesh);
     break;
   }
   default: {
   }
   }
 
   if(tag != _gst_material_id) {
     Array<Element> * elements_per_mat = new Array<Element>[materials.size()];
     splitElementByMaterial(elements, elements_per_mat);
 
     for (UInt i = 0; i < materials.size(); ++i) {
       materials[i]->packElementData(buffer, elements_per_mat[i], tag);
     }
 
     delete [] elements_per_mat;
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 inline void SolidMechanicsModel::unpackElementData(CommunicationBuffer & buffer,
                                                   const Array<Element> & elements,
                                                   SynchronizationTag tag) {
   AKANTU_DEBUG_IN();
 
   switch(tag) {
   case _gst_material_id: {
     unpackElementalDataHelper(element_index_by_material, buffer, elements,
                              false, getFEEngine());
     break;
   }
   case _gst_smm_mass: {
     unpackNodalDataHelper(*mass, buffer, elements, mesh);
     break;
   }
   case _gst_smm_for_gradu: {
     unpackNodalDataHelper(*displacement, buffer, elements, mesh);
     break;
   }
   case _gst_smm_boundary: {
     unpackNodalDataHelper(*force, buffer, elements, mesh);
     unpackNodalDataHelper(*velocity, buffer, elements, mesh);
     unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh);
     break;
   }
   default: {
   }
   }
 
   if(tag != _gst_material_id) {
     Array<Element> * elements_per_mat = new Array<Element>[materials.size()];
     splitElementByMaterial(elements, elements_per_mat);
 
     for (UInt i = 0; i < materials.size(); ++i) {
       materials[i]->unpackElementData(buffer, elements_per_mat[i], tag);
     }
 
     delete [] elements_per_mat;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 inline UInt SolidMechanicsModel::getNbDataToPack(SynchronizationTag tag) const {
   AKANTU_DEBUG_IN();
 
   UInt size = 0;
   //  UInt nb_nodes = mesh.getNbNodes();
 
   switch(tag) {
   case _gst_smm_uv: {
     size += sizeof(Real) * spatial_dimension * 2;
     break;
   }
   case _gst_smm_res: {
     size += sizeof(Real) * spatial_dimension;
     break;
   }
   case _gst_smm_mass: {
     size += sizeof(Real) * spatial_dimension;
     break;
   }
   case _gst_for_dump: {
     size += sizeof(Real) * spatial_dimension * 5;
     break;
   }
   default: {
     AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag);
   }
   }
 
   AKANTU_DEBUG_OUT();
   return size;
 }
 
 /* -------------------------------------------------------------------------- */
 inline UInt SolidMechanicsModel::getNbDataToUnpack(SynchronizationTag tag) const {
   AKANTU_DEBUG_IN();
 
   UInt size = 0;
   //  UInt nb_nodes = mesh.getNbNodes();
 
   switch(tag) {
   case _gst_smm_uv: {
     size += sizeof(Real) * spatial_dimension * 2;
     break;
   }
   case _gst_smm_res: {
     size += sizeof(Real) * spatial_dimension;
     break;
   }
   case _gst_smm_mass: {
     size += sizeof(Real) * spatial_dimension;
     break;
   }
   case _gst_for_dump: {
     size += sizeof(Real) * spatial_dimension * 5;
     break;
   }
   default: {
     AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag);
   }
   }
 
   AKANTU_DEBUG_OUT();
   return size;
 }
 
 /* -------------------------------------------------------------------------- */
 inline void SolidMechanicsModel::packData(CommunicationBuffer & buffer,
                                          const UInt index,
                                          SynchronizationTag tag) const {
   AKANTU_DEBUG_IN();
 
   switch(tag) {
   case _gst_smm_uv: {
     Array<Real>::const_vector_iterator it_disp = displacement->begin(spatial_dimension);
     Array<Real>::const_vector_iterator it_velo = velocity->begin(spatial_dimension);
     buffer << it_disp[index];
     buffer << it_velo[index];
     break;
   }
   case _gst_smm_res: {
     Array<Real>::const_vector_iterator it_res = residual->begin(spatial_dimension);
     buffer << it_res[index];
     break;
   }
   case _gst_smm_mass: {
     AKANTU_DEBUG_INFO("pack mass of node " << index << " which is " << (*mass)(index,0));
     Array<Real>::const_vector_iterator it_mass = mass->begin(spatial_dimension);
     buffer << it_mass[index];
     break;
   }
   case _gst_for_dump: {
     Array<Real>::const_vector_iterator it_disp = displacement->begin(spatial_dimension);
     Array<Real>::const_vector_iterator it_velo = velocity->begin(spatial_dimension);
     Array<Real>::const_vector_iterator it_acce = acceleration->begin(spatial_dimension);
     Array<Real>::const_vector_iterator it_resi = residual->begin(spatial_dimension);
     Array<Real>::const_vector_iterator it_forc = force->begin(spatial_dimension);
     buffer << it_disp[index];
     buffer << it_velo[index];
     buffer << it_acce[index];
     buffer << it_resi[index];
     buffer << it_forc[index];
     break;
   }
   default: {
     AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag);
   }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer,
                                            const UInt index,
                                            SynchronizationTag tag) {
   AKANTU_DEBUG_IN();
 
   switch(tag) {
   case _gst_smm_uv: {
     Array<Real>::vector_iterator it_disp = displacement->begin(spatial_dimension);
     Array<Real>::vector_iterator it_velo = velocity->begin(spatial_dimension);
     buffer >> it_disp[index];
     buffer >> it_velo[index];
     break;
   }
   case _gst_smm_res: {
     Array<Real>::vector_iterator it_res = residual->begin(spatial_dimension);
     buffer >> it_res[index];
     break;
   }
   case _gst_smm_mass: {
     AKANTU_DEBUG_INFO("mass of node " << index << " was " << (*mass)(index,0));
     Array<Real>::vector_iterator it_mass = mass->begin(spatial_dimension);
     buffer >> it_mass[index];
     AKANTU_DEBUG_INFO("mass of node " << index << " is now " << (*mass)(index,0));
     break;
   }
   case _gst_for_dump: {
     Array<Real>::vector_iterator it_disp = displacement->begin(spatial_dimension);
     Array<Real>::vector_iterator it_velo = velocity->begin(spatial_dimension);
     Array<Real>::vector_iterator it_acce = acceleration->begin(spatial_dimension);
     Array<Real>::vector_iterator it_resi = residual->begin(spatial_dimension);
     Array<Real>::vector_iterator it_forc = force->begin(spatial_dimension);
     buffer >> it_disp[index];
     buffer >> it_velo[index];
     buffer >> it_acce[index];
     buffer >> it_resi[index];
     buffer >> it_forc[index];
     break;
   }
   default: {
     AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag);
   }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 __END_AKANTU__
 
 #include "sparse_matrix.hh"
 #include "solver.hh"
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 template <NewmarkBeta::IntegrationSchemeCorrectorType type>
 void SolidMechanicsModel::solve(Array<Real> &increment, Real block_val,
-                                bool need_factorize, bool has_profile_changed,
-                                const Array<Real> &rhs) {
+                                bool need_factorize, bool has_profile_changed) {
   
   if(has_profile_changed) {
     this->initJacobianMatrix();
     need_factorize = true;
   }
 
   updateResidualInternal(); //doesn't do anything for static
 
   if(need_factorize) {
     Real c = 0.,d = 0.,e = 0.;
 
     if(method == _static) {
       AKANTU_DEBUG_INFO("Solving K inc = r");
       e = 1.;
     } else {
       AKANTU_DEBUG_INFO("Solving (c M + d C + e K) inc = r");
 
       NewmarkBeta * nmb_int = dynamic_cast<NewmarkBeta *>(integrator);
       c = nmb_int->getAccelerationCoefficient<type>(time_step);
       d = nmb_int->getVelocityCoefficient<type>(time_step);
       e = nmb_int->getDisplacementCoefficient<type>(time_step);
     }
 
 
     jacobian_matrix->clear();
     // J = c M + d C + e K
     if(stiffness_matrix)
       jacobian_matrix->add(*stiffness_matrix, e);
 
     if(mass_matrix)
       jacobian_matrix->add(*mass_matrix, c);
 
 #if !defined(AKANTU_NDEBUG)
     if(mass_matrix && AKANTU_DEBUG_TEST(dblDump))
       mass_matrix->saveMatrix("M.mtx");
 #endif
 
     if(velocity_damping_matrix)
       jacobian_matrix->add(*velocity_damping_matrix, d);
 
     jacobian_matrix->applyBoundary(*blocked_dofs, block_val);
 
 #if !defined(AKANTU_NDEBUG)
     if(AKANTU_DEBUG_TEST(dblDump))
       jacobian_matrix->saveMatrix("J.mtx");
 #endif
     solver->factorize();
   }
 
-  if (rhs.getSize() != 0)
-    solver->setRHS(rhs);
-  else
+  // if (rhs.getSize() != 0)
+  //  solver->setRHS(rhs);
+  // else
     solver->setRHS(*residual);
 
   // solve @f[ J \delta w = r @f]
   solver->solve(increment);
 
   UInt nb_nodes = displacement-> getSize();
   UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes;
 
   bool * blocked_dofs_val = blocked_dofs->storage();
   Real * increment_val = increment.storage();
 
   for (UInt j = 0; j < nb_degree_of_freedom;
        ++j,++increment_val, ++blocked_dofs_val) {
     if ((*blocked_dofs_val))
       *increment_val = 0.0;
     }
 
 }
 
 
 /* -------------------------------------------------------------------------- */
 template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria>
 bool SolidMechanicsModel::solveStatic(Real tolerance, UInt max_iteration,
 				      bool do_not_factorize) {
 
   AKANTU_DEBUG_INFO("Solving Ku = f");
   AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL,
                       "You should first initialize the implicit solver and assemble the stiffness matrix by calling initImplicit");
 
   AnalysisMethod analysis_method=method;
   Real error = 0.;
   method=_static;
   bool converged = this->template solveStep<cmethod, criteria>(tolerance, error, max_iteration, do_not_factorize);
   method=analysis_method;
   return converged;
 
 }
 
 /* -------------------------------------------------------------------------- */
 template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria>
 bool SolidMechanicsModel::solveStep(Real tolerance,
                                     UInt max_iteration) {
   Real error = 0.;
   return this->template solveStep<cmethod,criteria>(tolerance,
                                                     error,
                                                     max_iteration);
 }
 
 /* -------------------------------------------------------------------------- */
 template<SolveConvergenceMethod cmethod, SolveConvergenceCriteria criteria>
 bool SolidMechanicsModel::solveStep(Real tolerance, Real & error, UInt max_iteration,
 				    bool do_not_factorize) {
   EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method));
   this->implicitPred();
   this->updateResidual();
 
   AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL,
                       "You should first initialize the implicit solver and assemble the stiffness matrix");
 
   bool need_factorize = !do_not_factorize;
 
   if (method==_implicit_dynamic) {
     AKANTU_DEBUG_ASSERT(mass_matrix != NULL,
                         "You should first initialize the implicit solver and assemble the mass matrix");
   }
 
   switch (cmethod) {
   case _scm_newton_raphson_tangent:
   case _scm_newton_raphson_tangent_not_computed:
     break;
   case _scm_newton_raphson_tangent_modified:
     this->assembleStiffnessMatrix();
     break;
   default:
     AKANTU_DEBUG_ERROR("The resolution method " << cmethod << " has not been implemented!");
   }
 
   UInt iter = 0;
   bool converged = false;
   error = 0.;
   if(criteria == _scc_residual) {
     converged = this->testConvergence<criteria> (tolerance, error);
     if(converged) return converged;
   }
 
   do {
     if (cmethod == _scm_newton_raphson_tangent)
       this->assembleStiffnessMatrix();
 
     solve<NewmarkBeta::_displacement_corrector> (*increment, 1., need_factorize);
 
     this->implicitCorr();
 
     if(criteria == _scc_residual) this->updateResidual();
 
     converged = this->testConvergence<criteria> (tolerance, error);
 
     if(criteria == _scc_increment && !converged) this->updateResidual();
     //this->dump();
 
     iter++;
     AKANTU_DEBUG_INFO("[" << criteria << "] Convergence iteration "
                       << std::setw(std::log10(max_iteration)) << iter
                       << ": error " << error << (converged ? " < " : " > ") << tolerance);
 
     switch (cmethod) {
     case _scm_newton_raphson_tangent:
       need_factorize = true;
       break;
     case _scm_newton_raphson_tangent_not_computed:
     case _scm_newton_raphson_tangent_modified:
       need_factorize = false;
       break;
     default:
       AKANTU_DEBUG_ERROR("The resolution method " << cmethod << " has not been implemented!");
     }
 
 
   } while (!converged && iter < max_iteration);
 
   // this makes sure that you have correct strains and stresses after the solveStep function (e.g., for dumping)
   if(criteria == _scc_increment) this->updateResidual();
 
   if (converged) {
     EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method));
   } else if(iter == max_iteration) {
     AKANTU_DEBUG_WARNING("[" << criteria << "] Convergence not reached after "
                          << std::setw(std::log10(max_iteration)) << iter <<
                          " iteration" << (iter == 1 ? "" : "s") << "!" << std::endl);
   }
 
   return converged;
 }
diff --git a/src/solver/petsc_matrix.cc b/src/solver/petsc_matrix.cc
index 793f8a196..e64367c3f 100644
--- a/src/solver/petsc_matrix.cc
+++ b/src/solver/petsc_matrix.cc
@@ -1,534 +1,625 @@
 /**
  * @file   petsc_matrix.cc
  * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @date   Mon Jul 21 17:40:41 2014
  *
  * @brief  Implementation of PETSc matrix class
  *
  * @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 "petsc_matrix.hh"
 #include "static_communicator.hh"
 #include "static_communicator_mpi.hh"
 #include "mpi_type_wrapper.hh"
 #include "dof_synchronizer.hh"
+#include "petsc_wrapper.hh"
 /* -------------------------------------------------------------------------- */
 #include <cstring>
-#include <mpi.h>
-#include <petscmat.h>
-#include <petscao.h>
-#include <petscis.h>
 #include <petscsys.h>  
 
-
 __BEGIN_AKANTU__
 
-struct PETScWrapper {
-  Mat mat;
-  AO ao;
-  ISLocalToGlobalMapping mapping;
-  /// pointer to the MPI communicator for PETSc commands
-  MPI_Comm communicator;
-};
+// struct PETScWrapper {
+//   Mat mat;
+//   AO ao;
+//   ISLocalToGlobalMapping mapping;
+//   /// pointer to the MPI communicator for PETSc commands
+//   MPI_Comm communicator;
+// };
 
 /* -------------------------------------------------------------------------- */
 PETScMatrix::PETScMatrix(UInt size,
 			 const SparseMatrixType & sparse_matrix_type,
 			 const ID & id,
 			 const MemoryID & memory_id) :
   SparseMatrix(size, sparse_matrix_type, id, memory_id), 
-  petsc_wrapper(new PETScWrapper),
- d_nnz(0,1,"dnnz"),
- o_nnz(0,1,"onnz"),
+  petsc_matrix_wrapper(new PETScMatrixWrapper),
+  d_nnz(0,1,"dnnz"),
+  o_nnz(0,1,"onnz"),
   first_global_index(0),
- is_petsc_matrix_initialized(false) {
+  is_petsc_matrix_initialized(false) {
   AKANTU_DEBUG_IN();
   StaticSolver::getStaticSolver().registerEventHandler(*this);
   this->offset = 0;
   this->init();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 PETScMatrix::PETScMatrix(const SparseMatrix & matrix,
 			 const ID & id,
 			 const MemoryID & memory_id) :
   SparseMatrix(matrix, id, memory_id),
-  petsc_wrapper(new PETScWrapper), 
+  petsc_matrix_wrapper(new PETScMatrixWrapper), 
   d_nnz(0,1,"dnnz"), 
   o_nnz(0,1,"onnz"), 
   first_global_index(0),
   is_petsc_matrix_initialized(false) {
-  AKANTU_DEBUG_IN();
-  StaticSolver::getStaticSolver().registerEventHandler(*this);
-  this->offset = 0;
-  this->init();
+  // AKANTU_DEBUG_IN();
+  // StaticSolver::getStaticSolver().registerEventHandler(*this);
+  // this->offset = 0;
+  // this->init();
 
-  AKANTU_DEBUG_OUT();
+  // AKANTU_DEBUG_OUT();
+  AKANTU_DEBUG_TO_IMPLEMENT();
 }
 
 /* -------------------------------------------------------------------------- */
 PETScMatrix::~PETScMatrix() {
   AKANTU_DEBUG_IN();
 
+  /// destroy all the PETSc data structures used for this matrix
   this->destroyInternalData();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void PETScMatrix::init() {
   AKANTU_DEBUG_IN();
 
+  /// set the communicator that should be used by PETSc
 #if defined(AKANTU_USE_MPI)
     StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
     const StaticCommunicatorMPI & mpi_st_comm =
       dynamic_cast<const StaticCommunicatorMPI &>(comm.getRealStaticCommunicator());
-    this->petsc_wrapper->communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator();
+    this->petsc_matrix_wrapper->communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator();
 #else
-    this->petsc_wrapper->communicator = PETSC_COMM_SELF;
+    this->petsc_matrix_wrapper->communicator = PETSC_COMM_SELF;
 #endif
  
   PetscErrorCode ierr;
-
-  ierr = MatCreate(this->petsc_wrapper->communicator, &(this->petsc_wrapper->mat)); CHKERRXX(ierr);
-  /// set matrix type
-  ierr = MatSetType(this->petsc_wrapper->mat,  MATAIJ); CHKERRXX(ierr);
+  
+  /// create the PETSc matrix object
+  ierr = MatCreate(this->petsc_matrix_wrapper->communicator, &(this->petsc_matrix_wrapper->mat)); CHKERRXX(ierr);
 
 
-  //if (this->sparse_matrix_type==_symmetric)
-    /// set flag for symmetry to enable ICC/Cholesky preconditioner
-    //    ierr = MatSetOption(this->petsc_wrapper->mat, MAT_SYMMETRIC, PETSC_TRUE); CHKERRXX(ierr);
+  /**
+   * Set the matrix type
+   * @todo PETSc does currently not support a straightforward way to
+   * apply Dirichlet boundary conditions for MPISBAIJ
+   * matrices. Therefore always the entire matrix is allocated. It
+   * would be possible to use MATSBAIJ for sequential matrices in case
+   * memory becomes critical. Also, block matrices would give a much
+   * better performance. Modify this in the future!
+   */
 
+  ierr = MatSetType(this->petsc_matrix_wrapper->mat,  MATAIJ); CHKERRXX(ierr);
+ 
   this->is_petsc_matrix_initialized = true;
-    
+
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
-void PETScMatrix::resize(const DOFSynchronizer & dof_synchronizer) {
+/**
+ * With this method each processor computes the dimensions of the
+ * local matrix, i.e. the part of the global matrix it is storing.
+ * @param dof_synchronizer dof synchronizer that maps the local
+ * dofs to the global dofs and the equation numbers, i.e., the 
+ * position at which the dof is assembled in the matrix
+ */
+void PETScMatrix::setSize() {
   AKANTU_DEBUG_IN();
 
   PetscErrorCode ierr;
 
-  this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer);
-
   /// find the number of dofs corresponding to master or local nodes
-  UInt nb_dofs = dof_synchronizer.getNbDOFs();
+  UInt nb_dofs = this->dof_synchronizer->getNbDOFs();
   UInt nb_local_master_dofs = 0;
 
   /// create array to store the global equation number of all local and master dofs
   Array<Int> local_master_eq_nbs(nb_dofs);
   Array<Int>::scalar_iterator it_eq_nb = local_master_eq_nbs.begin();
 
-  /// get the pointer to the gloabl equation number array
-  Int * eq_nb_val = dof_synchronizer.getGlobalDOFEquationNumbers().storage();
+  /// get the pointer to the global equation number array
+  Int * eq_nb_val = this->dof_synchronizer->getGlobalDOFEquationNumbers().storage();
   
   for (UInt i = 0; i <nb_dofs; ++i) {
-    if (dof_synchronizer.isLocalOrMasterDOF(i) ) {
+    if (this->dof_synchronizer->isLocalOrMasterDOF(i) ) {
       *it_eq_nb = eq_nb_val[i];
       ++it_eq_nb;
       ++nb_local_master_dofs;
     }
   }
 
   local_master_eq_nbs.resize(nb_local_master_dofs);
 
   /// set the local size
   this->local_size = nb_local_master_dofs;
 
   /// resize PETSc matrix
 #if defined(AKANTU_USE_MPI)
-  ierr = MatSetSizes(this->petsc_wrapper->mat, this->local_size, this->local_size, this->size, this->size); CHKERRXX(ierr);
+  ierr = MatSetSizes(this->petsc_matrix_wrapper->mat, this->local_size, this->local_size, this->size, this->size); CHKERRXX(ierr);
 #else
-  ierr =  MatSetSizes(this->petsc_wrapper->mat, this->local_size, this->local_size); CHKERRXX(ierr);
+  ierr =  MatSetSizes(this->petsc_matrix_wrapper->mat, this->local_size, this->local_size); CHKERRXX(ierr);
 #endif
 
   /// create mapping from akantu global numbering to petsc global numbering
   this->createGlobalAkantuToPETScMap(local_master_eq_nbs.storage());
+
+
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * This method generates a mapping from the global Akantu equation
+ * numbering to the global PETSc dof ordering 
+ * @param local_master_eq_nbs_ptr Int pointer to the array of equation
+ * numbers of all local or master dofs, i.e. the row indices of the
+ * local matrix
+ */
 void PETScMatrix::createGlobalAkantuToPETScMap(Int* local_master_eq_nbs_ptr) {
   AKANTU_DEBUG_IN();
 
   PetscErrorCode ierr;
  
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); 
   UInt rank = comm.whoAmI();
 
   //initialize vector to store the number of local and master nodes that are assigned to each processor
   Vector<UInt> master_local_ndofs_per_proc(nb_proc);
 
   /// store the nb of master and local dofs on each processor
   master_local_ndofs_per_proc(rank) = this->local_size;
   
 
 
   /// exchange the information among all processors
   comm.allGather(master_local_ndofs_per_proc.storage(), 1);
 
   /// each processor creates a map for his akantu global dofs to the corresponding petsc global dofs
 
   /// determine the PETSc-index for the first dof on each processor
 	
   for (UInt i = 0; i < rank; ++i) {
     this->first_global_index +=  master_local_ndofs_per_proc(i);
   }
 
   /// create array for petsc ordering
   Array<Int> petsc_dofs(this->local_size);
   Array<Int>::scalar_iterator it_petsc_dofs = petsc_dofs.begin();
 	
   for (Int i = this->first_global_index; i < this->first_global_index + this->local_size; ++i, ++it_petsc_dofs) {
     *it_petsc_dofs = i; 
   }
 
-  ierr = AOCreateBasic(this->petsc_wrapper->communicator, this->local_size, local_master_eq_nbs_ptr, petsc_dofs.storage(), &(this->petsc_wrapper->ao)); CHKERRXX(ierr);
+  ierr = AOCreateBasic(this->petsc_matrix_wrapper->communicator, this->local_size, local_master_eq_nbs_ptr, petsc_dofs.storage(), &(this->petsc_matrix_wrapper->ao)); CHKERRXX(ierr);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 // void PETScMatrix::createLocalAkantuToPETScMap(const DOFSynchronizer & dof_synchronizer) {
 //   AKANTU_DEBUG_IN();
 
-//   AKANTU_DEBUG_ASSERT(this->petsc_wrapper->ao != NULL,
+//   AKANTU_DEBUG_ASSERT(this->petsc_matrix_wrapper->ao != NULL,
 //                       "You should first create a mapping from the global"
 // 		      << " Akantu numbering to the global PETSc numbering");
 
+//   PetscErrorCode ierr;
+
 //   this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer);
 
 //   /// get the number of dofs
 //   Int nb_dofs = dof_synchronizer.getNbDOFs();
 
 //   /// get the global equation numbers for each node
 //   Array<Int> global_dof_equation_numbers = dof_synchronizer.getGlobalDOFEquationNumbers();
 
 //   /// map the global dof equation numbers to the corresponding PETSc ordering
-//   AOApplicationToPETSc(this->petsc_wrapper->ao, nb_dofs,
-// 		       global_dof_equation_numbers.storage());
+//   ierr =  AOApplicationToPETSc(this->petsc_matrix_wrapper->ao, nb_dofs,
+// 		       global_dof_equation_numbers.storage()); CHKERRXX(ierr);
 
 //   /// create the mapping from the local Akantu ordering to the global PETSc ordering
-//   ISLocalToGlobalMappingCreate(this->petsc_wrapper->communicator,
+//   ierr = ISLocalToGlobalMappingCreate(this->petsc_matrix_wrapper->communicator,
 // 			       1, nb_dofs, global_dof_equation_numbers.storage(),
-// 			       PETSC_COPY_VALUES, mapping);
+// 			       PETSC_COPY_VALUES, &(this->petsc_matrix_wrapper-mapping)); CHKERRXX(ierr);
 
 //   AKANTU_DEBUG_OUT();
 // }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * This function creates the non-zero pattern of the PETSc matrix. In
+ * PETSc the parallel matrix is partitioned across processors such
+ * that the first m0 rows belong to process 0, the next m1 rows belong
+ * to process 1, the next m2 rows belong to process 2 etc.. where
+ * m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores
+ * values corresponding to [m x N] submatrix
+ * (http://www.mcs.anl.gov/petsc/).
+ * @param mesh mesh discretizing the domain we want to analyze
+ * @param dof_synchronizer dof synchronizer that maps the local 
+ * dofs to the global dofs and the equation numbers, i.e., the 
+ * position at which the dof is assembled in the matrix
+ */
+
 void PETScMatrix::buildProfile(const Mesh & mesh, const DOFSynchronizer & dof_synchronizer, UInt nb_degree_of_freedom) {
   AKANTU_DEBUG_IN();
 
   //clearProfile();
-
+  this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer);
+  this->setSize();
   PetscErrorCode ierr;
 
   /// resize arrays to store the number of nonzeros in each row
   this->d_nnz.resize(this->local_size);
   this->o_nnz.resize(this->local_size);
 
   /// set arrays to zero everywhere
   this->d_nnz.set(0);
   this->o_nnz.set(0); 
 
-  this->dof_synchronizer = &const_cast<DOFSynchronizer &>(dof_synchronizer);
 
   // if(irn_jcn_to_k) delete irn_jcn_to_k;
   // irn_jcn_to_k = new std::map<std::pair<UInt, UInt>, UInt>;
   
   coordinate_list_map::iterator irn_jcn_k_it;
 
   Int * eq_nb_val = dof_synchronizer.getGlobalDOFEquationNumbers().storage();
   UInt nb_global_dofs = dof_synchronizer.getNbGlobalDOFs();
 
   /// Loop over all the ghost types
   for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) {
     const GhostType & ghost_type = *gt;
     Mesh::type_iterator it  = mesh.firstType(mesh.getSpatialDimension(), ghost_type, _ek_not_defined);
     Mesh::type_iterator end = mesh.lastType (mesh.getSpatialDimension(), ghost_type, _ek_not_defined);
     for(; it != end; ++it) {
-      UInt nb_element = mesh.getNbElement(*it);
+      UInt nb_element = mesh.getNbElement(*it, ghost_type);
       UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it);
       UInt size_mat = nb_nodes_per_element * nb_degree_of_freedom;
 
       UInt * conn_val = mesh.getConnectivity(*it, ghost_type).storage();
       Int * local_eq_nb_val = new Int[nb_degree_of_freedom * nb_nodes_per_element];
 
 
       for (UInt e = 0; e < nb_element; ++e) {
 	Int * tmp_local_eq_nb_val = local_eq_nb_val;
 	for (UInt i = 0; i < nb_nodes_per_element; ++i) {
 	  UInt n = conn_val[i];
 	  for (UInt d = 0; d < nb_degree_of_freedom; ++d) {
+	    /**
+	     * !!!!!!Careful!!!!!! This is a ugly fix. @todo this is a
+	     * very ugly fix, because the offset for the global
+	     * equation number, where the dof will be assembled, is
+	     * hardcoded. In the future a class dof manager has to be
+	     * added to Akantu to handle the mapping between the dofs
+	     * and the equation numbers
+	     * 
+	     */
+
 	    *tmp_local_eq_nb_val++ = eq_nb_val[n * nb_degree_of_freedom + d] - (dof_synchronizer.isPureGhostDOF(n * nb_degree_of_freedom + d) ? nb_global_dofs : 0);
 	    
 	  }
-	  // memcpy(tmp_local_eq_nb_val, eq_nb_val + n * nb_degree_of_freedom, nb_degree_of_freedom * sizeof(Int));
-	  // tmp_local_eq_nb_val += nb_degree_of_freedom;
 	}
 	
 
 	for (UInt i = 0; i < size_mat; ++i) {
 	  Int c_irn = local_eq_nb_val[i];
-	  UInt j_start = (sparse_matrix_type == _symmetric) ? i : 0;
+	  UInt j_start = 0;
 	  for (UInt j = j_start; j < size_mat; ++j) {
 	    Int c_jcn = local_eq_nb_val[j];
 	    Array<Int> index_pair(2,1);
 	    index_pair(0) = c_irn;
 	    index_pair(1) = c_jcn;
-	    AOApplicationToPetsc(this->petsc_wrapper->ao, 2, index_pair.storage());
-	    if(sparse_matrix_type == _symmetric && (index_pair(0) > index_pair(1)))
-	      std::swap(index_pair(0), index_pair(1));
+	    AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index_pair.storage());
 	    if (index_pair(0) >= first_global_index && index_pair(0) < first_global_index + this->local_size)  {
-	      KeyCOO irn_jcn = key(c_irn, c_jcn);
+	      KeyCOO irn_jcn = keyPETSc(c_irn, c_jcn);
 	      irn_jcn_k_it = irn_jcn_k.find(irn_jcn);
 
 	      if (irn_jcn_k_it == irn_jcn_k.end()) {
 		irn_jcn_k[irn_jcn] = nb_non_zero;
 		
 		
 		// check if node is slave node
 		if (index_pair(1) >= first_global_index && index_pair(1) < first_global_index + this->local_size)
 		  this->d_nnz(index_pair(0) - first_global_index) += 1;
 		else
 		  this->o_nnz(index_pair(0) - first_global_index) += 1;
 		nb_non_zero++;
 		
 	      }
 	    }
 	    
 	  }
 	  
 	}
 	conn_val += nb_nodes_per_element;
       }
 
       delete [] local_eq_nb_val;
     }
   }
 
 
 
   // /// for pbc @todo correct it for parallel
   // if(StaticCommunicator::getStaticCommunicator().getNbProc() == 1) {
   //   for (UInt i = 0; i < size; ++i) {
   // 	KeyCOO irn_jcn = key(i, i);
   // 	irn_jcn_k_it = irn_jcn_k.find(irn_jcn);
   // 	if(irn_jcn_k_it == irn_jcn_k.end()) {
   // 	  irn_jcn_k[irn_jcn] = nb_non_zero;
   // 	  irn.push_back(i + 1);
   // 	  jcn.push_back(i + 1);
   // 	  nb_non_zero++;
   // 	}
   //   }
   // }
   
 
 
   // std::string mat_type;
   // mat_type.resize(20, 'a');
   // std::cout << "MatType: " << mat_type << std::endl;
   // const char * mat_type_ptr = mat_type.c_str();
-
   MatType type;
-  MatGetType(this->petsc_wrapper->mat, &type);
-
-  //  PetscTypeCompare((PetscObject)(this->petsc_wrapper->mat),MATSEQAIJ,&sametype);
-  //ierr = PetscTypeCompare(pet, MATSEQAIJ, &sametype); CHKERRXX(ierr);
-
+  MatGetType(this->petsc_matrix_wrapper->mat, &type);
+  std::cout << "the matrix type is: " << type << std::endl;
+  /**
+   * PETSc will use only one of the following preallocation commands
+   * depending on the matrix type and ignore the rest. Note that for
+   * the block matrix format a block size of 1 is used. This might
+   * result in bad performance. @todo For better results implement
+   * buildProfile() with larger block size.
+   * 
+   */
   /// build profile:
   if (strcmp(type, MATSEQAIJ) == 0) {
-    ierr = MatSeqAIJSetPreallocation(this->petsc_wrapper->mat,
-				     0, d_nnz.storage()); CHKERRXX(ierr);
+    ierr = MatSeqAIJSetPreallocation(this->petsc_matrix_wrapper->mat,
+				       0, d_nnz.storage()); CHKERRXX(ierr);
   } else if ((strcmp(type, MATMPIAIJ) == 0)) {
-    ierr = MatMPIAIJSetPreallocation(this->petsc_wrapper->mat,
-				     0, d_nnz.storage(), 0,
-				     o_nnz.storage()); CHKERRXX(ierr); 
+    ierr = MatMPIAIJSetPreallocation(this->petsc_matrix_wrapper->mat,
+                                     0, d_nnz.storage(), 0,
+                                     o_nnz.storage()); CHKERRXX(ierr);
   } else {
     AKANTU_DEBUG_ERROR("The type " << type << " of PETSc matrix is not handled by"
-		       << " akantu in the preallocation step");
+                       << " akantu in the preallocation step");
   }
 
+  //ierr =  MatSeqSBAIJSetPreallocation(this->petsc_matrix_wrapper->mat, 1,
+  //				      0, d_nnz.storage()); CHKERRXX(ierr);
+
+  if (this->sparse_matrix_type==_symmetric) {
+    /// set flag for symmetry to enable ICC/Cholesky preconditioner
+    ierr = MatSetOption(this->petsc_matrix_wrapper->mat, MAT_SYMMETRIC, PETSC_TRUE); CHKERRXX(ierr);
+  }
+  /// once the profile has been build ignore any new nonzero locations
+  ierr = MatSetOption(this->petsc_matrix_wrapper->mat, MAT_NEW_NONZERO_LOCATIONS, PETSC_TRUE); CHKERRXX(ierr);
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
-void PETScMatrix::saveMatrix(const std::string & filename) const {
+/**
+ * Method to save the nonzero pattern and the values stored at each position
+ * @param filename name of the file in which the information will be stored
+ */
+void PETScMatrix::saveMatrix(const std::string & filename) const{
   AKANTU_DEBUG_IN();
 
   PetscErrorCode ierr;
-  
+
   /// create Petsc viewer
   PetscViewer viewer; 
-  ierr = PetscViewerASCIIOpen(this->petsc_wrapper->communicator, filename.c_str(), &viewer); CHKERRXX(ierr);
+  ierr = PetscViewerASCIIOpen(this->petsc_matrix_wrapper->communicator, filename.c_str(), &viewer); CHKERRXX(ierr);
 
   /// set the format
   PetscViewerSetFormat(viewer, PETSC_VIEWER_DEFAULT); CHKERRXX(ierr);
   /// save the matrix
-  ierr =  MatView(this->petsc_wrapper->mat, viewer); CHKERRXX(ierr);
+  ierr =  MatView(this->petsc_matrix_wrapper->mat, viewer); CHKERRXX(ierr);
 
   /// destroy the viewer
   ierr =  PetscViewerDestroy(&viewer); CHKERRXX(ierr);
 
   AKANTU_DEBUG_OUT();
 }
 
-// /* -------------------------------------------------------------------------- */
-// Array<Real> & operator*=(Array<Real> & vect, const PETScMatrix & mat) {
-//   AKANTU_DEBUG_IN();
-
-//   Array<Real> result 
-//   MatMult(this->mat, vect, )
-
-//   // AKANTU_DEBUG_ASSERT((vect.getSize()*vect.getNbComponent() == mat.getSize()) &&
-//   // 		      (vect.getNbComponent() == mat.getNbDegreOfFreedom()),
-//   // 		      "The size of the matrix and the vector do not match");
-
-//   const PETScMatrixType & sparse_matrix_type = mat.getPETScMatrixType();
-//   DOFSynchronizer * dof_synchronizer = mat.getDOFSynchronizerPointer();
-
-//   UInt nb_non_zero = mat.getNbNonZero();
-//   Real * tmp = new Real [vect.getNbComponent() * vect.getSize()];
-//   std::fill_n(tmp, vect.getNbComponent() * vect.getSize(), 0);
-
-//   Int * i_val  = mat.getIRN().storage();
-//   Int * j_val  = mat.getJCN().storage();
-//   Real * a_val = mat.getA().storage();
-
-//   Real * vect_val = vect.storage();
-
-//   for (UInt k = 0; k < nb_non_zero; ++k) {
-//     UInt i = *(i_val++);
-//     UInt j = *(j_val++);
-//     Real a = *(a_val++);
-
-//     UInt local_i = i - 1;
-//     UInt local_j = j - 1;
-//     if(dof_synchronizer) {
-//       local_i = dof_synchronizer->getDOFLocalID(local_i);
-//       local_j = dof_synchronizer->getDOFLocalID(local_j);
-//     }
-
-//     tmp[local_i] += a * vect_val[local_j];
-//     if((sparse_matrix_type == _symmetric) && (local_i != local_j))
-//       tmp[local_j] += a * vect_val[local_i];
-//   }
-
-//   memcpy(vect_val, tmp, vect.getNbComponent() * vect.getSize() * sizeof(Real));
-//   delete [] tmp;
-
-//   if(dof_synchronizer)
-//     dof_synchronizer->reduceSynchronize<AddOperation>(vect);
-
-//   AKANTU_DEBUG_OUT();
-
-//   return vect;
-// }
-
-// /* -------------------------------------------------------------------------- */
-// void PETScMatrix::copyContent(const PETScMatrix & matrix) {
-//   AKANTU_DEBUG_IN();
-//   AKANTU_DEBUG_ASSERT(nb_non_zero == matrix.getNbNonZero(),
-// 		      "The two matrices don't have the same profiles");
-
-//   MatCopy(this->mat, matrix->mat, SAME_NONZERO_PATTERN);
-
-//   AKANTU_DEBUG_OUT();
-// }
-
-// ///* -------------------------------------------------------------------------- */
-// //void PETScMatrix::copyProfile(const PETScMatrix & matrix) {
-// //  AKANTU_DEBUG_IN();
-// //  irn = matrix.irn;
-// //  jcn = matrix.jcn;
-// //  nb_non_zero = matrix.nb_non_zero;
-// //  irn_jcn_k = matrix.irn_jcn_k;
-// //  a.resize(nb_non_zero);
-// //  AKANTU_DEBUG_OUT();
-// //}
-
 /* -------------------------------------------------------------------------- */
+/**
+ * Method to add an Akantu sparse matrix to the PETSc matrix
+ * @param matrix Akantu sparse matrix to be added
+ * @param alpha the factor specifying how many times the matrix should be added
+ */
 void PETScMatrix::add(const SparseMatrix & matrix, Real alpha) {
   PetscErrorCode ierr;
   //  AKANTU_DEBUG_ASSERT(nb_non_zero == matrix.getNbNonZero(),
   //		      "The two matrix don't have the same profiles");
 
   for (UInt n = 0; n < matrix.getNbNonZero(); ++n) {
     Array<Int> index(2,1);
     index(0) = matrix.getIRN()(n)-matrix.getOffset();
     index(1) =  matrix.getJCN()(n)-matrix.getOffset();
-    AOApplicationToPetsc(this->petsc_wrapper->ao, 2, index.storage());
-    if (_symmetric && index(0) > index(1))
+    AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index.storage());
+    if (this->sparse_matrix_type == _symmetric && index(0) > index(1))
       std::swap(index(0), index(1));
-    ierr = MatSetValue(this->petsc_wrapper->mat, index(0), index(1), matrix.getA()(n) * alpha, ADD_VALUES); CHKERRXX(ierr);
+    /// MatSetValue might be very slow for MATBAIJ, might need to use MatSetValuesBlocked
+    ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(0), index(1), matrix.getA()(n) * alpha, ADD_VALUES); CHKERRXX(ierr);
+    /// chek if sparse matrix to be added is symmetric. In this case
+    /// the value also needs to be added at the transposed location in
+    /// the matrix because PETSc is using the full profile, also for symmetric matrices
+    if (matrix.getSparseMatrixType() == _symmetric && index(0) != index(1))
+      ierr = MatSetValue(this->petsc_matrix_wrapper->mat, index(1), index(0), matrix.getA()(n) * alpha, ADD_VALUES); CHKERRXX(ierr);
   }
 
+  this->performAssembly();
+}
 
-  
+/* -------------------------------------------------------------------------- */
+/**
+ * Method to add another PETSc matrix to this PETSc matrix
+ * @param matrix PETSc matrix to be added
+ * @param alpha the factor specifying how many times the matrix should be added
+ */
+void PETScMatrix::add(const PETScMatrix & matrix, Real alpha) {
+  PetscErrorCode ierr;
 
+  ierr = MatAXPY(this->petsc_matrix_wrapper->mat, alpha, matrix.petsc_matrix_wrapper->mat, SAME_NONZERO_PATTERN); CHKERRXX(ierr);
 
 
+  this->performAssembly();
 }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * MatSetValues() generally caches the values. The matrix is ready to
+ * use only after MatAssemblyBegin() and MatAssemblyEnd() have been
+ * called. (http://www.mcs.anl.gov/petsc/)
+ */
 void PETScMatrix::performAssembly() {
   PetscErrorCode ierr;
-  ierr = MatAssemblyBegin(this->petsc_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr);
-  ierr = MatAssemblyEnd(this->petsc_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr);
+  ierr = MatAssemblyBegin(this->petsc_matrix_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr);
+  ierr = MatAssemblyEnd(this->petsc_matrix_wrapper->mat, MAT_FINAL_ASSEMBLY); CHKERRXX(ierr);
 }
 
 /* -------------------------------------------------------------------------- */
+/**
+ * Method is called when the static solver is destroyed, just before
+ * PETSc is finalized. So all PETSc objects need to be destroyed at
+ * this point.
+ */
 void PETScMatrix::beforeStaticSolverDestroy() {
   AKANTU_DEBUG_IN();
 
   try{
     this->destroyInternalData();
   } catch(...) {}
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
+ /// destroy all the PETSc data structures used for this matrix
 void PETScMatrix::destroyInternalData() {
   AKANTU_DEBUG_IN();
 
   if(this->is_petsc_matrix_initialized) {
   
     PetscErrorCode ierr;
 
-    ierr = MatDestroy(&(this->petsc_wrapper->mat)); CHKERRXX(ierr);
-    delete petsc_wrapper;
+    ierr = MatDestroy(&(this->petsc_matrix_wrapper->mat)); CHKERRXX(ierr);
+    delete petsc_matrix_wrapper;
 
     this->is_petsc_matrix_initialized = false;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
+
+/* -------------------------------------------------------------------------- */
+/// access K(i, j). Works only for dofs on this processor!!!! 
+Real PETScMatrix::operator()(UInt i, UInt j) const{
+  AKANTU_DEBUG_IN();
+
+  AKANTU_DEBUG_ASSERT(this->dof_synchronizer->isLocalOrMasterDOF(i) && this->dof_synchronizer->isLocalOrMasterDOF(j), "Operator works only for dofs on this processor");
+
+  Array<Int> index(2,1);
+  index(0) = this->dof_synchronizer->getDOFGlobalID(i);
+  index(1) = this->dof_synchronizer->getDOFGlobalID(j);
+  AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, 2, index.storage());
+
+  Real value = 0;
+
+  PetscErrorCode ierr;
+  /// @todo MatGetValue might be very slow for MATBAIJ, might need to use MatGetValuesBlocked
+  ierr = MatGetValues(this->petsc_matrix_wrapper->mat, 1, &index(0), 1, &index(1), &value); CHKERRXX(ierr);
+
+
+  AKANTU_DEBUG_OUT();
+
+
+  return value;
+
+}
+
+/* -------------------------------------------------------------------------- */
+/**
+ * Apply Dirichlet boundary conditions by zeroing the rows and columns which correspond to blocked dofs
+ * @param boundary array of booleans which are true if the dof at this position is blocked
+ * @param block_val the value in the diagonal entry of blocked rows
+ */
+void PETScMatrix::applyBoundary(const Array<bool> & boundary, Real block_val) {
+  AKANTU_DEBUG_IN();
+
+  PetscErrorCode ierr;
+
+  /// get the global equation numbers to find the rows that need to be zeroed for the blocked dofs
+  Int * eq_nb_val = dof_synchronizer->getGlobalDOFEquationNumbers().storage();
+
+  /// every processor calls the MatSetZero() only for his local or master dofs. This assures that not two processors or more try to zero the same row
+  Int nb_blocked_local_master_eq_nb = 0;
+  Array<Int> blocked_local_master_eq_nb(this->local_size / boundary.getNbComponent(), boundary.getNbComponent());
+  Int * blocked_lm_eq_nb_ptr  = blocked_local_master_eq_nb.storage();
+  for (UInt i = 0; i < boundary.getSize(); ++i) {
+    for (UInt j = 0; j < boundary.getNbComponent(); ++j) {
+      UInt local_dof = i * boundary.getNbComponent() + j;
+      if (boundary(i, j) == true && this->dof_synchronizer->isLocalOrMasterDOF(local_dof)) {
+	Int global_eq_nb = *eq_nb_val;
+	*blocked_lm_eq_nb_ptr = global_eq_nb;
+	++ nb_blocked_local_master_eq_nb;
+	++blocked_lm_eq_nb_ptr;
+	++eq_nb_val;
+      }
+    }
+  }
+  blocked_local_master_eq_nb.resize(nb_blocked_local_master_eq_nb/boundary.getNbComponent());
+
+
+  ierr = AOApplicationToPetsc(this->petsc_matrix_wrapper->ao, nb_blocked_local_master_eq_nb, blocked_local_master_eq_nb.storage() ); CHKERRXX(ierr);
+  ierr = MatZeroRowsColumns(this->petsc_matrix_wrapper->mat, nb_blocked_local_master_eq_nb, blocked_local_master_eq_nb.storage(), block_val, 0, 0); CHKERRXX(ierr);
+
+  this->performAssembly();
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+/// set all entries to zero while keeping the same nonzero pattern
+void PETScMatrix::clear() {
+  MatZeroEntries(this->petsc_matrix_wrapper->mat);
+}
+
 __END_AKANTU__
diff --git a/src/solver/petsc_matrix.hh b/src/solver/petsc_matrix.hh
index ea1369539..d09eae806 100644
--- a/src/solver/petsc_matrix.hh
+++ b/src/solver/petsc_matrix.hh
@@ -1,158 +1,146 @@
 /**
  * @file   petsc_matrix.hh
  * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @date   Mon Jul 21 14:49:49 2014
  *
  * @brief  Interface for PETSc matrices
  *
  * @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_PETSC_MATRIX_HH__
 #define __AKANTU_PETSC_MATRIX_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "sparse_matrix.hh"
 #include "static_communicator.hh"
 #include "static_solver.hh"
 
 /* -------------------------------------------------------------------------- */
 __BEGIN_AKANTU__
 
-class PETScWrapper;
+class PETScMatrixWrapper;
 
 class PETScMatrix : public SparseMatrix, StaticSolverEventHandler {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   PETScMatrix(UInt size,
 	      const SparseMatrixType & sparse_matrix_type,
 	      const ID & id = "petsc_matrix",
 	      const MemoryID & memory_id = 0);
 
   PETScMatrix(const SparseMatrix & matrix,
 	      const ID & id = "petsc_matrix",
 	      const MemoryID & memory_id = 0);
 
   virtual ~PETScMatrix();
 
 
 private:
   /// init internal PETSc matrix
   void init();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
-  /// resize PETSc matrix
-  void resize(const DOFSynchronizer & dof_synchronizer);
 
-  void createGlobalAkantuToPETScMap(Int* local_master_eq_nbs_ptr);
-
-  // /// remove the existing profile
-  // inline void clearProfile();
-
-  // /// add a non-zero element
-  // virtual UInt addToProfile(UInt i, UInt j);
-
-  // /// set the matrix to 0
-  // inline void clear();
-
-  // /// assemble a local matrix in the sparse one
-  // inline void addToMatrix(UInt i, UInt j, Real value);
+  /// set the matrix to 0
+  virtual void clear();
 
   /// fill the profil of the matrix
   virtual void buildProfile(const Mesh & mesh, const DOFSynchronizer & dof_synchronizer, UInt nb_degree_of_freedom);
 
-  // /// modify the matrix to "remove" the blocked dof
-  // virtual void applyBoundary(const Array<bool> & boundary, Real block_val = 1.);
-  
-  /// perform assembly so that matrix is ready for use
-  void performAssembly();
-
-  // /// restore the profile that was before removing the boundaries
-  // virtual void restoreProfile();
+  /// modify the matrix to "remove" the blocked dof
+  virtual void applyBoundary(const Array<bool> & boundary, Real block_val = 1.);
 
-  // /// save the profil in a file using the MatrixMarket file format
-  // virtual void saveProfile(const std::string & filename) const;
-
-  /// save the matrix in a file using the MatrixMarket file format
+  /// save the matrix in a ASCII file format
   virtual void saveMatrix(const std::string & filename) const;
 
-  // /// copy assuming the profile are the same
-  // virtual void copyContent(const SparseMatrix & matrix);
-
-  // /// copy profile
-  // //  void copyProfile(const SparseMatrix & matrix);
-
-  /// add matrix assuming the profile are the same
+  /// add a sparse matrix assuming the profile are the same
   virtual void add(const SparseMatrix & matrix, Real alpha);
+  /// add a petsc matrix assuming the profile are the same
+  virtual void add(const PETScMatrix & matrix, Real alpha);
 
-  // /// diagonal lumping
-  // virtual void lump(Array<Real> & lumped);
-
-  // /// function to print the contain of the class
-  // //virtual void printself(std::ostream & stream, int indent = 0) const;
 
   virtual void beforeStaticSolverDestroy();
 
+  Real operator()(UInt i, UInt j) const;
+
+protected:
+  inline KeyCOO keyPETSc(UInt i, UInt j) const {
+    return std::make_pair(i, j);
+  }
+
 private:
   virtual void destroyInternalData();
 
+  /// set the size of the PETSc matrix
+  void setSize();
+  void createGlobalAkantuToPETScMap(Int* local_master_eq_nbs_ptr);
+  void createLocalAkantuToPETScMap(const DOFSynchronizer & dof_synchronizer);
+  /// perform assembly so that matrix is ready for use
+  void performAssembly();
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
+public:
+  
+  AKANTU_GET_MACRO(PETScMatrixWrapper, petsc_matrix_wrapper, PETScMatrixWrapper*);
+  AKANTU_GET_MACRO(LocalSize, local_size, Int);
+  ///  AKANTU_GET_MACRO(LocalSize, local_size, Int);
+  
+
 public:
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 
 
 private:
   /// store the PETSc structures
-  PETScWrapper * petsc_wrapper;
+  PETScMatrixWrapper * petsc_matrix_wrapper;
 
   /// size of the diagonal part of the matrix partition
   Int local_size;
 
   /// number of nonzeros in every row of the diagonal part
   Array<Int> d_nnz;
 
   /// number of nonzeros in every row of the off-diagonal part
   Array<Int> o_nnz;
 
   /// the global index of the first local row 
   Int first_global_index;
 
   /// bool to indicate if the matrix data has been initialized by calling MatCreate
 
   bool is_petsc_matrix_initialized;
 
-
 };
 
 __END_AKANTU__
 
-#endif /* __AKANTU_PETSCI_MATRIX_HH__ */
+#endif /* __AKANTU_PETSC_MATRIX_HH__ */
diff --git a/src/solver/petsc_wrapper.hh b/src/solver/petsc_wrapper.hh
index af1704e44..14bd59b4e 100644
--- a/src/solver/petsc_wrapper.hh
+++ b/src/solver/petsc_wrapper.hh
@@ -1,61 +1,62 @@
 /**
  * @file   petsc_wrapper.hh
  * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @date   Mon Jul 21 17:40:41 2014
  *
  * @brief  Wrapper of PETSc structures
  *
  * @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_PETSC_WRAPPER_HH__
 #define __AKANTU_PETSC_WRAPPER_HH__
 
 /* -------------------------------------------------------------------------- */
 #include <mpi.h>
 #include <petscmat.h>
+#include <petscvec.h> 
 #include <petscao.h>
 #include <petscis.h>
 #include <petscksp.h>
 
 __BEGIN_AKANTU__
 
 struct PETScMatrixWrapper {
   Mat mat;
   AO ao;
   ISLocalToGlobalMapping mapping;
   /// pointer to the MPI communicator for PETSc commands
   MPI_Comm communicator;
 };
 
 struct PETScSolverWrapper {
   KSP ksp;
   Vec solution;
   Vec rhs;
   /// pointer to the MPI communicator for PETSc commands
   MPI_Comm communicator;
 };
 
 
 __END_AKANTU__
 
 #endif /* __AKANTU_PETSC_WRAPPER_HH__ */
diff --git a/src/solver/solver.cc b/src/solver/solver.cc
index ee6706eb4..7d9d4746e 100644
--- a/src/solver/solver.cc
+++ b/src/solver/solver.cc
@@ -1,76 +1,87 @@
 /**
  * @file   solver.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Dec 13 2010
  * @date last modification: Wed Nov 13 2013
  *
  * @brief  Solver interface class
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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 "solver.hh"
+#include "dof_synchronizer.hh"
 
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_AKANTU__
 
 SolverOptions _solver_no_options(true);
 
 /* -------------------------------------------------------------------------- */
 Solver::Solver(SparseMatrix & matrix,
 	       const ID & id,
 	       const MemoryID & memory_id) :
   Memory(id, memory_id), StaticSolverEventHandler(),
   matrix(&matrix),
   is_matrix_allocated(false),
   mesh(NULL),
-  communicator(StaticCommunicator::getStaticCommunicator()){
+  communicator(StaticCommunicator::getStaticCommunicator()),
+  solution(NULL),
+  synch_registry(NULL) {
   AKANTU_DEBUG_IN();
   StaticSolver::getStaticSolver().registerEventHandler(*this);
+  //createSynchronizerRegistry();
+  this->synch_registry = new SynchronizerRegistry(*this);
+  synch_registry->registerSynchronizer(this->matrix->getDOFSynchronizer(), _gst_solver_solution);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 Solver::~Solver() {
   AKANTU_DEBUG_IN();
 
   this->destroyInternalData();
-
+  delete synch_registry;
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void Solver::beforeStaticSolverDestroy() {
   AKANTU_DEBUG_IN();
 
   try{
     this->destroyInternalData();
   } catch(...) {}
 
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+void Solver::createSynchronizerRegistry() {
+  //this->synch_registry = new SynchronizerRegistry(this);
+}
+
 
 __END_AKANTU__
diff --git a/src/solver/solver.hh b/src/solver/solver.hh
index 99bb1bd4a..9377bd932 100644
--- a/src/solver/solver.hh
+++ b/src/solver/solver.hh
@@ -1,134 +1,165 @@
 /**
  * @file   solver.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @date creation: Mon Dec 13 2010
  * @date last modification: Mon Sep 15 2014
  *
  * @brief  interface for solvers
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_SOLVER_HH__
 #define __AKANTU_SOLVER_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "aka_memory.hh"
 #include "aka_array.hh"
 #include "sparse_matrix.hh"
 #include "mesh.hh"
 #include "static_communicator.hh"
 #include "static_solver.hh"
+#include "data_accessor.hh"
+#include "synchronizer_registry.hh"
 
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_AKANTU__
 
 class SolverOptions {
 public:
   SolverOptions(bool no_option = false) : no_option(no_option) { }
 
   virtual ~SolverOptions() {}
 
 private:
   bool no_option;
 };
 
 extern SolverOptions _solver_no_options;
 
 class Solver : protected Memory,
-               public StaticSolverEventHandler {
+               public StaticSolverEventHandler, 
+	       public DataAccessor {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
 
   Solver(SparseMatrix & matrix,
 	 const ID & id = "solver",
 	 const MemoryID & memory_id = 0);
 
   virtual ~Solver();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
 
   /// initialize the solver
   virtual void initialize(SolverOptions & options = _solver_no_options) = 0;
 
   virtual void analysis() {};
 
   virtual void factorize() {};
 
   /// solve
   virtual void solve(Array<Real> & solution) = 0;
   virtual void solve() = 0;
 
-  virtual void setRHS(const Array<Real> & rhs) = 0;
+  virtual void setRHS(Array<Real> & rhs) = 0;
 
   /// function to print the contain of the class
   //  virtual void printself(std::ostream & stream, int indent = 0) const;
 
 protected:
   virtual void destroyInternalData() {};
 
 public:
   virtual void beforeStaticSolverDestroy();
 
+  void createSynchronizerRegistry();
+  /* ------------------------------------------------------------------------ */
+  /* Data Accessor inherited members                                          */
+  /* ------------------------------------------------------------------------ */
+public:
+  inline virtual UInt getNbDataForDOFs(const Array <UInt> & dofs,
+					   SynchronizationTag tag) const;
+
+  inline virtual void packDOFData(CommunicationBuffer & buffer,
+			  const Array<UInt> & dofs,
+			  SynchronizationTag tag) const;
+
+  inline virtual void unpackDOFData(CommunicationBuffer & buffer,
+			    const Array<UInt> & dofs,
+			    SynchronizationTag tag);
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
 
   AKANTU_GET_MACRO(RHS, *rhs, Array<Real> &);
 
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
 
   /// the matrix
   SparseMatrix * matrix;
 
   /// is sparse matrix allocated
   bool is_matrix_allocated;
 
   /// the right hand side
   Array<Real> * rhs;
 
   /// mesh
   const Mesh * mesh;
 
   /// pointer to the communicator
   StaticCommunicator & communicator;
+
+  /// the solution obtained from the solve step
+  Array<Real> * solution;
+
+  /// synchronizer registry
+  SynchronizerRegistry * synch_registry;
+
 };
 
+/* -------------------------------------------------------------------------- */
+/* inline functions                                                           */
+/* -------------------------------------------------------------------------- */
+
+#include "solver_inline_impl.cc"
 
 __END_AKANTU__
 
 #endif /* __AKANTU_SOLVER_HH__ */
diff --git a/src/solver/solver_mumps.cc b/src/solver/solver_mumps.cc
index 526f034e3..68ba81c0d 100644
--- a/src/solver/solver_mumps.cc
+++ b/src/solver/solver_mumps.cc
@@ -1,374 +1,374 @@
 /**
  * @file   solver_mumps.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Dec 13 2010
  * @date last modification: Mon Sep 15 2014
  *
  * @brief  implem of SolverMumps class
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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
  *
  * @subsection Ctrl_param Control parameters
  *
  * ICNTL(1),
  * ICNTL(2),
  * ICNTL(3) : output streams for error, diagnostics, and global messages
  *
  * ICNTL(4) : verbose level : 0 no message - 4 all messages
  *
  * ICNTL(5) : type of matrix, 0 assembled, 1 elementary
  *
  * ICNTL(6) : control  the permutation and scaling(default 7)  see mumps doc for
  * more information
  *
  * ICNTL(7) : determine  the pivot  order (default  7) see  mumps doc  for more
  * information
  *
  * ICNTL(8) : describe the scaling method used
  *
  * ICNTL(9) : 1 solve A x = b, 0 solve At x = b
  *
  * ICNTL(10) : number of iterative refinement when NRHS = 1
  *
  * ICNTL(11) : > 0 return statistics
  *
  * ICNTL(12) : only used for SYM = 2, ordering strategy
  *
  * ICNTL(13) :
  *
  * ICNTL(14) : percentage of increase of the estimated working space
  *
  * ICNTL(15-17) : not used
  *
  * ICNTL(18) : only  used if ICNTL(5) = 0, 0 matrix  centralized, 1 structure on
  * host and mumps  give the mapping, 2 structure on  host and distributed matrix
  * for facto, 3 distributed matrix
  *
  * ICNTL(19) : > 0, Shur complement returned
  *
  * ICNTL(20) : 0 rhs dense, 1 rhs sparse
  *
  * ICNTL(21) : 0 solution in rhs, 1 solution distributed in ISOL_loc and SOL_loc
  * allocated by user
  *
  * ICNTL(22) : 0 in-core, 1 out-of-core
  *
  * ICNTL(23) : maximum memory allocatable by mumps pre proc
  *
  * ICNTL(24) : controls the detection of "null pivot rows"
  *
  * ICNTL(25) :
  *
  * ICNTL(26) :
  *
  * ICNTL(27) :
  *
  * ICNTL(28) : 0 automatic choice, 1 sequential analysis, 2 parallel analysis
  *
  * ICNTL(29) : 0 automatic choice, 1 PT-Scotch, 2 ParMetis
  */
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 
 #if defined(AKANTU_USE_MPI)
 #  include "static_communicator_mpi.hh"
 #  include "mpi_type_wrapper.hh"
 #endif
 
 #include "solver_mumps.hh"
 #include "dof_synchronizer.hh"
 
 
 /* -------------------------------------------------------------------------- */
 // static std::ostream & operator <<(std::ostream & stream, const DMUMPS_STRUC_C & _this) {
 //   stream << "DMUMPS Data [" << std::endl;
 //   stream << " + job          : " << _this.job          << std::endl;
 //   stream << " + par          : " << _this.par          << std::endl;
 //   stream << " + sym          : " << _this.sym          << std::endl;
 //   stream << " + comm_fortran : " << _this.comm_fortran << std::endl;
 //   stream << " + nz           : " << _this.nz           << std::endl;
 //   stream << " + irn          : " << _this.irn          << std::endl;
 //   stream << " + jcn          : " << _this.jcn          << std::endl;
 //   stream << " + nz_loc       : " << _this.nz_loc       << std::endl;
 //   stream << " + irn_loc      : " << _this.irn_loc      << std::endl;
 //   stream << " + jcn_loc      : " << _this.jcn_loc      << std::endl;
 //   stream << "]";
 //   return stream;
 // }
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 SolverMumps::SolverMumps(SparseMatrix & matrix,
                          const ID & id,
                          const MemoryID & memory_id) :
   Solver(matrix, id, memory_id), is_mumps_data_initialized(false), rhs_is_local(true) {
   AKANTU_DEBUG_IN();
 
 #ifdef AKANTU_USE_MPI
   parallel_method = SolverMumpsOptions::_fully_distributed;
 #else //AKANTU_USE_MPI
   parallel_method = SolverMumpsOptions::_not_parallel;
 #endif //AKANTU_USE_MPI
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 SolverMumps::~SolverMumps() { }
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::destroyInternalData() {
   AKANTU_DEBUG_IN();
 
   if(this->is_mumps_data_initialized) {
     this->mumps_data.job = _smj_destroy; // destroy
     dmumps_c(&this->mumps_data);
     this->is_mumps_data_initialized = false;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::initMumpsData() {
   // Default Scaling
   icntl(8) = 77;
 
   // Assembled matrix
   icntl(5) = 0;
 
   /// Default centralized dense second member
   icntl(20) = 0;
   icntl(21) = 0;
 
   icntl(28) = 0; //automatic choice for analysis analysis
 
   switch(this->parallel_method) {
   case SolverMumpsOptions::_fully_distributed:
       icntl(18) = 3; //fully distributed
 
       this->mumps_data.nz_loc  = matrix->getNbNonZero();
       this->mumps_data.irn_loc = matrix->getIRN().storage();
       this->mumps_data.jcn_loc = matrix->getJCN().storage();
       break;
   case SolverMumpsOptions::_not_parallel:
   case SolverMumpsOptions::_master_slave_distributed:
     icntl(18) = 0; //centralized
 
     if(prank == 0) {
       this->mumps_data.nz  = matrix->getNbNonZero();
       this->mumps_data.irn = matrix->getIRN().storage();
       this->mumps_data.jcn = matrix->getJCN().storage();
     } else {
       this->mumps_data.nz  = 0;
       this->mumps_data.irn = NULL;
       this->mumps_data.jcn = NULL;
     }
     break;
   default:
     AKANTU_DEBUG_ERROR("This case should not happen!!");
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::initialize(SolverOptions & options) {
   AKANTU_DEBUG_IN();
 
   if(SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions *>(&options)) {
     this->parallel_method = opt->parallel_method;
   }
 
   this->mumps_data.par = 1; // The host is part of computations
 
   switch(this->parallel_method) {
   case SolverMumpsOptions::_not_parallel: break;
   case SolverMumpsOptions::_master_slave_distributed:
     this->mumps_data.par = 0; // The host is not part of the computations
   case SolverMumpsOptions::_fully_distributed:
 #ifdef AKANTU_USE_MPI
     const StaticCommunicatorMPI & mpi_st_comm = dynamic_cast<const StaticCommunicatorMPI &>(communicator.getRealStaticCommunicator());
     this->mumps_data.comm_fortran = MPI_Comm_c2f(mpi_st_comm.getMPITypeWrapper().getMPICommunicator());
 #endif
     break;
   }
 
 
   this->mumps_data.sym = 2 * (matrix->getSparseMatrixType() == _symmetric);
   this->prank = communicator.whoAmI();
 
   this->mumps_data.job = _smj_initialize; //initialize
   dmumps_c(&this->mumps_data);
 
   this->is_mumps_data_initialized = true;
 
   /* ------------------------------------------------------------------------ */
   UInt size = matrix->getSize();
 
   if(prank == 0) {
     std::stringstream sstr_rhs; sstr_rhs << id << ":rhs";
     this->rhs = &(alloc<Real>(sstr_rhs.str(), size, 1, 0.));
   } else {
     this->rhs = NULL;
   }
 
   this->mumps_data.nz_alloc = 0;
   this->mumps_data.n        = size;
   /* ------------------------------------------------------------------------ */
   // Output setup
   if(AKANTU_DEBUG_TEST(dblTrace)) {
     icntl(1) = 6;
     icntl(2) = 2;
     icntl(3) = 2;
     icntl(4) = 4;
   } else {
     /// No outputs
     icntl(1) = 6; // error output
     icntl(2) = 0; // dignostics output
     icntl(3) = 0; // informations
     icntl(4) = 0; // no outputs
   }
 
   if(AKANTU_DEBUG_TEST(dblDump)) {
     strcpy(this->mumps_data.write_problem, "mumps_matrix.mtx");
   }
 
   this->analysis();
 
 //  icntl(14) = 80;
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
-void SolverMumps::setRHS(const Array<Real> & rhs) {
+void SolverMumps::setRHS(Array<Real> & rhs) {
   if(prank == 0) {
 
-    std::copy(rhs.storage(), rhs.storage() + this->rhs->getSize(), this->rhs->storage());
+    //std::copy(rhs.storage(), rhs.storage() + this->rhs->getSize(), this->rhs->storage());
 
-    //    DebugLevel dbl = debug::getDebugLevel();
-//    debug::setDebugLevel(dblError);
-//    matrix->getDOFSynchronizer().gather(rhs, 0, this->rhs);
-//    debug::setDebugLevel(dbl);
+    DebugLevel dbl = debug::getDebugLevel();
+    debug::setDebugLevel(dblError);
+    matrix->getDOFSynchronizer().gather(rhs, 0, this->rhs);
+    debug::setDebugLevel(dbl);
 
   } else {
     this->matrix->getDOFSynchronizer().gather(rhs, 0);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::analysis() {
   AKANTU_DEBUG_IN();
 
   initMumpsData();
 
   this->mumps_data.job = _smj_analyze; //analyze
   dmumps_c(&this->mumps_data);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::factorize() {
   AKANTU_DEBUG_IN();
 
   if(parallel_method == SolverMumpsOptions::_fully_distributed)
     this->mumps_data.a_loc  = this->matrix->getA().storage();
   else {
     if(prank == 0)
       this->mumps_data.a  = this->matrix->getA().storage();
   }
 
   if(prank == 0) {
     this->mumps_data.rhs = this->rhs->storage();
   }
 
 
   this->mumps_data.job = _smj_factorize; // factorize
   dmumps_c(&this->mumps_data);
 
   this->printError();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::solve() {
   AKANTU_DEBUG_IN();
 
   if(prank == 0) {
     this->mumps_data.rhs = this->rhs->storage();
   }
 
   this->mumps_data.job = _smj_solve; // solve
   dmumps_c(&this->mumps_data);
 
   this->printError();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::solve(Array<Real> & solution) {
   AKANTU_DEBUG_IN();
 
   this->solve();
 
   if(prank == 0) {
-//    matrix->getDOFSynchronizer().scatter(solution, 0, this->rhs);
-    std::copy(this->rhs->storage(), this->rhs->storage() + this->rhs->getSize(), solution.storage());
+    matrix->getDOFSynchronizer().scatter(solution, 0, this->rhs);
+//    std::copy(this->rhs->storage(), this->rhs->storage() + this->rhs->getSize(), solution.storage());
 
   } else {
     this->matrix->getDOFSynchronizer().scatter(solution, 0);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void SolverMumps::printError() {
   if(info(1) != 0) {
     communicator.allReduce(&info(1), 1, _so_min);
     switch(info(1)) {     
     case -10: AKANTU_DEBUG_ERROR("The matrix is singular"); break;
     case  -9: {
       icntl(14) += 10;
       if(icntl(14) != 90) {
 	//std::cout << "Dynamic memory increase of 10%" << std::endl;
       	this->analysis();
       	this->factorize();
       	this->solve();
       } else {
 	AKANTU_DEBUG_ERROR("The MUMPS workarray is too small INFO(2)=" << info(2) << "No further increase possible"); break;
       }
     }
     default:
       AKANTU_DEBUG_ERROR("Error in mumps during solve process, check mumps user guide INFO(1) ="
                          << info(1));
     }
   }
 }
 
 
 __END_AKANTU__
diff --git a/src/solver/solver_mumps.hh b/src/solver/solver_mumps.hh
index 5bff7da6d..c843439d1 100644
--- a/src/solver/solver_mumps.hh
+++ b/src/solver/solver_mumps.hh
@@ -1,154 +1,154 @@
 /**
  * @file   solver_mumps.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Dec 13 2010
  * @date last modification: Mon Sep 15 2014
  *
  * @brief  Solver class implementation for the mumps solver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_SOLVER_MUMPS_HH__
 #define __AKANTU_SOLVER_MUMPS_HH__
 #include <dmumps_c.h>
 
 #include "solver.hh"
 #include "static_communicator.hh"
 
 __BEGIN_AKANTU__
 
 class SolverMumpsOptions : public SolverOptions {
 public:
   enum ParallelMethod {
     _not_parallel,
     _fully_distributed,
     _master_slave_distributed
   };
 
   SolverMumpsOptions(ParallelMethod parallel_method = _fully_distributed) :
     SolverOptions(),
     parallel_method(parallel_method) { }
 
 private:
   friend class SolverMumps;
   ParallelMethod parallel_method;
 };
 
 class SolverMumps : public Solver {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
 
   SolverMumps(SparseMatrix & sparse_matrix,
 	      const ID & id = "solver_mumps",
 	      const MemoryID & memory_id = 0);
 
   virtual ~SolverMumps();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
 
   /// build the profile and do the analysis part
-  void initialize(SolverOptions & options = _solver_no_options);
+  virtual void initialize(SolverOptions & options = _solver_no_options);
 
   void initializeSlave(SolverOptions & options = _solver_no_options);
 
   /// analysis (symbolic facto + permutations)
-  void analysis();
+  virtual void analysis();
 
   /// factorize the matrix
-  void factorize();
+  virtual void factorize();
 
   /// solve the system
-  void solve(Array<Real> & solution);
-  void solve();
+  virtual void solve(Array<Real> & solution);
+  virtual void solve();
 
   void solveSlave();
 
-  virtual void setRHS(const Array<Real> & rhs);
+  virtual void setRHS(Array<Real> & rhs);
 
 private:
   /// print the error if any happened in mumps
   void printError();
 
   /// clean the mumps info
-  void destroyInternalData();
+  virtual void destroyInternalData();
 
   /// set internal values;
   void initMumpsData();
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 private:
   /// access the control variable
   inline Int & icntl(UInt i) {
     return mumps_data.icntl[i - 1];
   }
 
   /// access the results info
   inline Int & info(UInt i) {
     return mumps_data.info[i - 1];
   }
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
 
   /// mumps data
   DMUMPS_STRUC_C mumps_data;
 
   /// specify if the mumps_data are initialized or not
   bool is_mumps_data_initialized;
 
   UInt prank;
 
   /* ------------------------------------------------------------------------ */
   /* Local types                                                              */
   /* ------------------------------------------------------------------------ */
 private:
   SolverMumpsOptions::ParallelMethod parallel_method;
 
   bool rhs_is_local;
 
   enum SolverMumpsJob {
     _smj_initialize = -1,
     _smj_analyze = 1,
     _smj_factorize = 2,
     _smj_solve = 3,
     _smj_analyze_factorize = 4,
     _smj_factorize_solve = 5,
     _smj_complete = 6, // analyze, factorize, solve
     _smj_destroy = -2
   };
 };
 
 
 __END_AKANTU__
 
 #endif /* __AKANTU_SOLVER_MUMPS_HH__ */
diff --git a/src/solver/solver_petsc.cc b/src/solver/solver_petsc.cc
index ce058bc87..09b3c0c74 100644
--- a/src/solver/solver_petsc.cc
+++ b/src/solver/solver_petsc.cc
@@ -1,954 +1,1082 @@
-// /**
-//  * @file   solver_petsc.cc
-//  *
-//  * @author Nicolas Richart <nicolas.richart@epfl.ch>
-//  # @author Alejandro M. Aragón <alejandro.aragon@epfl.ch>
-//  *
-//  * @date   Mon Dec 13 10:48:06 2010
-//  *
-//  * @brief  Solver class implementation for the petsc solver
-//  *
-//  * @section LICENSE
-//  *
-//  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
-//  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
-//  *
-//  * Akantu is free  software: you can redistribute it and/or  modify it under the
-//  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
-//  * Software Foundation, either version 3 of the License, or (at your option) any
-//  * later version.
-//  *
-//  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
-//  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-//  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
-//  * details.
-//  *
-//  * You should  have received  a copy  of the GNU  Lesser General  Public License
-//  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
-//  *
-//  */
-
-// /* -------------------------------------------------------------------------- */
-// #ifdef AKANTU_USE_MPI
-// #include "static_communicator_mpi.hh"
-// #endif
-
-// #include "solver_petsc.hh"
-// #include "dof_synchronizer.hh"
-
-// __BEGIN_AKANTU__
+/**
+ * @file   solver_petsc.cc
+ *
+ * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ # @author Alejandro M. Aragón <alejandro.aragon@epfl.ch>
+ * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
+ *
+ * @date   Mon Dec 13 10:48:06 2010
+ *
+ * @brief  Solver class implementation for the petsc solver
+ *
+ * @section LICENSE
+ *
+ * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * Akantu is free  software: you can redistribute it and/or  modify it under the
+ * terms  of the  GNU Lesser  General Public  License as  published by  the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
+ * details.
+ *
+ * You should  have received  a copy  of the GNU  Lesser General  Public License
+ * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
 
+/* -------------------------------------------------------------------------- */
+#include <petscksp.h>
+#include "solver_petsc.hh"
+#include "petsc_wrapper.hh"
+#include "petsc_matrix.hh"
+#include "static_communicator.hh"
+#include "static_communicator_mpi.hh"
+#include "mpi_type_wrapper.hh"
+#include "dof_synchronizer.hh"
 
+__BEGIN_AKANTU__
+
+/* -------------------------------------------------------------------------- */
+SolverPETSc::SolverPETSc(SparseMatrix & matrix,
+                         const ID & id,
+                         const MemoryID & memory_id) :
+  Solver(matrix, id, memory_id), is_petsc_data_initialized(false), 
+  petsc_solver_wrapper(new PETScSolverWrapper) {
+}
+
+/* -------------------------------------------------------------------------- */
+SolverPETSc::~SolverPETSc() {
+  AKANTU_DEBUG_IN();
+
+  this->destroyInternalData();
+
+  AKANTU_DEBUG_OUT();
+ }
+/* -------------------------------------------------------------------------- */
+void SolverPETSc::destroyInternalData() {
+  AKANTU_DEBUG_IN();
+
+  if(this->is_petsc_data_initialized) {
+    PetscErrorCode ierr;
+    ierr = KSPDestroy(&(this->petsc_solver_wrapper->ksp)); CHKERRXX(ierr);
+    ierr = VecDestroy(&(this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr);
+    ierr = VecDestroy(&(this->petsc_solver_wrapper->solution)); CHKERRXX(ierr);
+    delete petsc_solver_wrapper;
+
+    this->is_petsc_data_initialized = false;
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolverPETSc::initialize(SolverOptions & options) {
+  AKANTU_DEBUG_IN();
+
+#if defined(AKANTU_USE_MPI)
+    StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
+    const StaticCommunicatorMPI & mpi_st_comm =
+      dynamic_cast<const StaticCommunicatorMPI &>(comm.getRealStaticCommunicator());
+    this->petsc_solver_wrapper->communicator = mpi_st_comm.getMPITypeWrapper().getMPICommunicator();
+#else
+    this->petsc_solver_wrapper->communicator = PETSC_COMM_SELF;
+#endif
+
+  PetscErrorCode ierr;
+
+  /// create a solver context
+  ierr = KSPCreate(this->petsc_solver_wrapper->communicator, &(this->petsc_solver_wrapper->ksp)); CHKERRXX(ierr);
+ 
+ /// set the matrix that defines the linear system and the matrix for preconditioning (here they are the same)
+  PETScMatrix * petsc_matrix = static_cast<PETScMatrix*>(this->matrix);
+
+#if PETSC_VERSION_MAJOR >= 3 && PETSC_VERSION_MINOR >= 5  
+  ierr = KSPSetOperators(this->petsc_solver_wrapper->ksp, petsc_matrix->getPETScMatrixWrapper()->mat, petsc_matrix->getPETScMatrixWrapper()->mat); CHKERRXX(ierr);
+#else
+  ierr = KSPSetOperators(this->petsc_solver_wrapper->ksp, petsc_matrix->getPETScMatrixWrapper()->mat, petsc_matrix->getPETScMatrixWrapper()->mat, SAME_NONZERO_PATTERN); CHKERRXX(ierr);
+#endif
+
+  ierr = VecCreate(this->petsc_solver_wrapper->communicator, &(this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr);
+
+  this->is_petsc_data_initialized = true; 
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolverPETSc::setRHS(Array<Real> & rhs) {
+  PetscErrorCode ierr;
+  PETScMatrix * petsc_matrix = static_cast<PETScMatrix*>(this->matrix);
+  ierr = VecSetSizes((this->petsc_solver_wrapper->rhs), petsc_matrix->getLocalSize(), petsc_matrix->getSize()); CHKERRXX(ierr);
+  ierr = VecSetFromOptions((this->petsc_solver_wrapper->rhs)); CHKERRXX(ierr);
+
+  for (UInt i = 0; i < rhs.getSize(); ++i) {
+    if (matrix->getDOFSynchronizer().isLocalOrMasterDOF(i)) {
+      Int i_global = matrix->getDOFSynchronizer().getDOFGlobalID(i);
+      AOApplicationToPetsc(petsc_matrix->getPETScMatrixWrapper()->ao, 1, &(i_global) );
+      ierr = VecSetValue((this->petsc_solver_wrapper->rhs), i_global, rhs(i), INSERT_VALUES); CHKERRXX(ierr);
+    }
+  }
+  ierr = VecAssemblyBegin(this->petsc_solver_wrapper->rhs); CHKERRXX(ierr);
+  ierr = VecAssemblyEnd(this->petsc_solver_wrapper->rhs); CHKERRXX(ierr);
+  ierr = VecDuplicate((this->petsc_solver_wrapper->rhs), &(this->petsc_solver_wrapper->solution)); CHKERRXX(ierr);
+
+
+}
+
+/* -------------------------------------------------------------------------- */
+void SolverPETSc::solve() {
+  AKANTU_DEBUG_IN();
+
+  PetscErrorCode ierr;
+  ierr = KSPSolve(this->petsc_solver_wrapper->ksp, this->petsc_solver_wrapper->rhs, this->petsc_solver_wrapper->solution); CHKERRXX(ierr); 
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void SolverPETSc::solve(Array<Real> & solution) {
+  AKANTU_DEBUG_IN();
+
+  this->solution = &solution;
+  this->solve();
+
+  PetscErrorCode ierr;
+  PETScMatrix * petsc_matrix = static_cast<PETScMatrix*>(this->matrix);
+
+
+  // ierr = VecGetOwnershipRange(this->petsc_solver_wrapper->solution, solution_begin, solution_end); CHKERRXX(ierr);
+  // ierr = VecGetArray(this->petsc_solver_wrapper->solution, PetscScalar **array); CHKERRXX(ierr);
+
+  for (UInt i = 0; i < solution.getSize(); ++i) {
+    if (this->matrix->getDOFSynchronizer().isLocalOrMasterDOF(i)) {
+      Int i_global = this->matrix->getDOFSynchronizer().getDOFGlobalID(i);
+      ierr = AOApplicationToPetsc(petsc_matrix->getPETScMatrixWrapper()->ao, 1, &(i_global) ); CHKERRXX(ierr);
+      ierr = VecGetValues(this->petsc_solver_wrapper->solution, 1, &i_global, &solution(i)); CHKERRXX(ierr);
+      
+    }
+  }
+
+  synch_registry->synchronize(_gst_solver_solution);
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
 // void finalize_petsc() {
   
 //   static bool finalized = false;
 //   if (!finalized) {
     
 //     cout<<"*** INFO *** PETSc is finalizing..."<<endl;
 //     // finalize PETSc
 //     PetscErrorCode ierr = PetscFinalize();CHKERRCONTINUE(ierr);
 //     finalized = true;
 //   }
 // }
 
 
 // SolverPETSc::sparse_vector_type
 // SolverPETSc::operator()(const SolverPETSc::sparse_matrix_type& AA,
 //                          const SolverPETSc::sparse_vector_type& bb) {
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   // parallel output stream
 //   Output_stream out;
 //   // timer
 //   cpputils::ctimer timer;
 //   out<<"Inside PETSc solver: "<<timer<<endl;
 // #endif
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Inside operator()(const sparse_matrix_type&, const sparse_vector_type&)... "<<timer<<endl;
 // #endif
   
 //   assert(AA.rows() == bb.size());
   
 //   //  KSP ksp;            //!< linear solver context
   
 //   Vec            b;                /* RHS */
 //   PC             pc;               /* preconditioner context */
 //   PetscErrorCode ierr;
 //   PetscInt       nlocal;
 //   PetscInt       n = bb.size();
 //   VecScatter ctx;
   
 //   /*
 //    Create vectors.  Note that we form 1 vector from scratch and
 //    then duplicate as needed. For this simple case let PETSc decide how
 //    many elements of the vector are stored on each processor. The second
 //    argument to VecSetSizes() below causes PETSc to decide.
 //    */
 //   ierr = VecCreate(PETSC_COMM_WORLD,&b);CHKERRCONTINUE(ierr);
 //   ierr = VecSetSizes(b,PETSC_DECIDE,n);CHKERRCONTINUE(ierr);
 //   ierr = VecSetFromOptions(b);CHKERRCONTINUE(ierr);
 //   if (!allocated_) {
 //     ierr = VecDuplicate(b,&x_);CHKERRCONTINUE(ierr);
 //   } else
 //     VecZeroEntries(x_);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vectors created... "<<timer<<endl;
 // #endif
   
   
 //   /* Set hight-hand-side vector */
 //   for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) {
 //     int row = it->first;
 //     ierr = VecSetValues(b, 1, &row, &it->second, ADD_VALUES);
 //   }
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Right hand side set... "<<timer<<endl;
 // #endif
   
   
 //   /*
 //    Assemble vector, using the 2-step process:
 //    VecAssemblyBegin(), VecAssemblyEnd()
 //    Computations can be done while messages are in transition
 //    by placing code between these two statements.
 //    */
 //   ierr = VecAssemblyBegin(b);CHKERRCONTINUE(ierr);
 //   ierr = VecAssemblyEnd(b);CHKERRCONTINUE(ierr);
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Right-hand-side vector assembled... "<<timer<<endl;
   
 //   ierr = VecView(b,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr);
   
 //   Vec b_all;
 //   ierr = VecScatterCreateToAll(b, &ctx, &b_all);CHKERRCONTINUE(ierr);
 //   ierr = VecScatterBegin(ctx,b,b_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr);
 //   ierr = VecScatterEnd(ctx,b,b_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr);
   
 //   value_type nrm;
 //   VecNorm(b_all,NORM_2,&nrm);
 //   out<<"  Norm of right hand side... "<<nrm<<endl;
 // #endif
   
 //   /* Identify the starting and ending mesh points on each
 //    processor for the interior part of the mesh. We let PETSc decide
 //    above. */
   
 //   //    PetscInt rstart,rend;
 //   //    ierr = VecGetOwnershipRange(x_,&rstart,&rend);CHKERRCONTINUE(ierr);
 //   ierr = VecGetLocalSize(x_,&nlocal);CHKERRCONTINUE(ierr);
   
   
 //   /*
 //    Create matrix.  When using MatCreate(), the matrix format can
 //    be specified at runtime.
    
 //    Performance tuning note:  For problems of substantial size,
 //    preallocation of matrix memory is crucial for attaining good
 //    performance. See the matrix chapter of the users manual for details.
    
 //    We pass in nlocal as the "local" size of the matrix to force it
 //    to have the same parallel layout as the vector created above.
 //    */
 //   if (!allocated_) {
     
 //     ierr = MatCreate(PETSC_COMM_WORLD,&A_);CHKERRCONTINUE(ierr);
 //     ierr = MatSetSizes(A_,nlocal,nlocal,n,n);CHKERRCONTINUE(ierr);
 //     ierr = MatSetFromOptions(A_);CHKERRCONTINUE(ierr);
 //     ierr = MatSetUp(A_);CHKERRCONTINUE(ierr);
 //   } else {
 //     // zero-out matrix
 //     MatZeroEntries(A_);
 //   }
   
   
 //   /*
 //    Assemble matrix.
    
 //    The linear system is distributed across the processors by
 //    chunks of contiguous rows, which correspond to contiguous
 //    sections of the mesh on which the problem is discretized.
 //    For matrix assembly, each processor contributes entries for
 //    the part that it owns locally.
 //    */
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Zeroed-out sparse matrix entries... "<<timer<<endl;
 // #endif
   
 //   for (sparse_matrix_type::const_hash_iterator it = AA.map_.begin(); it != AA.map_.end(); ++it) {
     
 //     // get subscripts
 //     std::pair<size_t,size_t> subs = AA.unhash(it->first);
 //     PetscInt row = subs.first;
 //     PetscInt col = subs.second;
 //     ierr = MatSetValues(A_, 1, &row, 1, &col, &it->second, ADD_VALUES);CHKERRCONTINUE(ierr);
 //   }
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Filled sparse matrix... "<<timer<<endl;
 // #endif
   
   
   
   
 //   /* Assemble the matrix */
 //   ierr = MatAssemblyBegin(A_,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
 //   ierr = MatAssemblyEnd(A_,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
   
   
 //   if (!allocated_) {
 //     // set after the first MatAssemblyEnd
 //     //        ierr = MatSetOption(A_, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);CHKERRCONTINUE(ierr);
 //     ierr = MatSetOption(A_, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);CHKERRCONTINUE(ierr);
 //   }
   
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Sparse matrix assembled... "<<timer<<endl;
 //   // view matrix
 //   MatView(A_, PETSC_VIEWER_STDOUT_WORLD);
   
 //   MatNorm(A_,NORM_FROBENIUS,&nrm);
 //   out<<"  Norm of stiffness matrix... "<<nrm<<endl;
 // #endif
   
 //   /*
 //    Set operators. Here the matrix that defines the linear system
 //    also serves as the preconditioning matrix.
 //    */
 //   //    ierr = KSPSetOperators(ksp,A_,A_,DIFFERENT_NONZERO_PATTERN);CHKERRCONTINUE(ierr);
 //   ierr = KSPSetOperators(ksp_,A_,A_,SAME_NONZERO_PATTERN);CHKERRCONTINUE(ierr);
   
   
 //   //
 //   //    /*
 //   //     Set runtime options, e.g.,
 //   //     -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol>
 //   //     These options will override those specified above as long as
 //   //     KSPSetFromOptions() is called _after_ any other customization
 //   //     routines.
 //   //     */
 //   //    ierr = KSPSetFromOptions(ksp);CHKERRCONTINUE(ierr);
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Solving system... "<<timer<<endl;
 // #endif
   
   
 //   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 //    Solve the linear system
 //    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 //   /*
 //    Solve linear system
 //    */
 //   ierr = KSPSolve(ksp_,b,x_);CHKERRCONTINUE(ierr);
   
   
 // #ifdef CPPUTILS_VERBOSE
   
 //   /*
 //    View solver info; we could instead use the option -ksp_view to
 //    print this info to the screen at the conclusion of KSPSolve().
 //    */
 //   ierr = KSPView(ksp_,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr);
   
 //   int iter;
 //   KSPGetIterationNumber(ksp_, &iter);
 //   out<<"  System solved in "<<iter<<" iterations... "<<timer<<endl;
 //   KSPConvergedReason reason;
 //   ierr = KSPGetConvergedReason(ksp_,&reason);CHKERRCONTINUE(ierr);
 //   if (reason < 0)
 //     out<<"*** WARNING *** PETSc solver diverged with flag ";
 //   else
 //     out<<"*** INFO *** PETSc solver converged with flag ";
   
 //   if (reason == KSP_CONVERGED_RTOL)
 //     out<<"KSP_CONVERGED_RTOL"<<endl;
 //   else if (reason == KSP_CONVERGED_ATOL)
 //     out<<"KSP_CONVERGED_ATOL"<<endl;
 //   else if (reason == KSP_CONVERGED_ITS)
 //     out<<"KSP_CONVERGED_ITS"<<endl;
 //   else if (reason == KSP_CONVERGED_CG_NEG_CURVE)
 //     out<<"KSP_CONVERGED_CG_NEG_CURVE"<<endl;
 //   else if (reason == KSP_CONVERGED_CG_CONSTRAINED)
 //     out<<"KSP_CONVERGED_CG_CONSTRAINED"<<endl;
 //   else if (reason == KSP_CONVERGED_STEP_LENGTH)
 //     out<<"KSP_CONVERGED_STEP_LENGTH"<<endl;
 //   else if (reason == KSP_CONVERGED_HAPPY_BREAKDOWN)
 //     out<<"KSP_CONVERGED_HAPPY_BREAKDOWN"<<endl;
 //   else if (reason == KSP_DIVERGED_NULL)
 //     out<<"KSP_DIVERGED_NULL"<<endl;
 //   else if (reason == KSP_DIVERGED_ITS)
 //     out<<"KSP_DIVERGED_ITS"<<endl;
 //   else if (reason == KSP_DIVERGED_DTOL)
 //     out<<"KSP_DIVERGED_DTOL"<<endl;
 //   else if (reason == KSP_DIVERGED_BREAKDOWN)
 //     out<<"KSP_DIVERGED_BREAKDOWN"<<endl;
 //   else if (reason == KSP_DIVERGED_BREAKDOWN_BICG)
 //     out<<"KSP_DIVERGED_BREAKDOWN_BICG"<<endl;
 //   else if (reason == KSP_DIVERGED_NONSYMMETRIC)
 //     out<<"KSP_DIVERGED_NONSYMMETRIC"<<endl;
 //   else if (reason == KSP_DIVERGED_INDEFINITE_PC)
 //     out<<"KSP_DIVERGED_INDEFINITE_PC"<<endl;
 //   else if (reason == KSP_DIVERGED_NAN)
 //     out<<"KSP_DIVERGED_NAN"<<endl;
 //   else if (reason == KSP_DIVERGED_INDEFINITE_MAT)
 //     out<<"KSP_DIVERGED_INDEFINITE_MAT"<<endl;
 //   else if (reason == KSP_CONVERGED_ITERATING)
 //     out<<"KSP_CONVERGED_ITERATING"<<endl;
   
 //   PetscReal rnorm;
 //   ierr = KSPGetResidualNorm(ksp_,&rnorm);CHKERRCONTINUE(ierr);
   
 //   out<<"PETSc last residual norm computed: "<<rnorm<<endl;
   
 //   ierr = VecView(x_,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr);
   
 //   VecNorm(x_,NORM_2,&nrm);
 //   out<<"  Norm of solution vector... "<<nrm<<endl;
   
 // #endif
   
   
   
 //   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 //    Check solution and clean up
 //    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
   
 //   Vec x_all;
   
 //   ierr = VecScatterCreateToAll(x_, &ctx, &x_all);CHKERRCONTINUE(ierr);
 //   ierr = VecScatterBegin(ctx,x_,x_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr);
 //   ierr = VecScatterEnd(ctx,x_,x_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr);
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Solution vector scattered... "<<timer<<endl;
 //   VecNorm(x_all,NORM_2,&nrm);
 //   out<<"  Norm of scattered vector... "<<nrm<<endl;
 //   //    ierr = VecView(x_all,PETSC_VIEWER_STDOUT_WORLD);CHKERRCONTINUE(ierr);
 // #endif
   
 //   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 //    Get values from solution and store them in the object that will be
 //    returned
 //    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
   
 //   sparse_vector_type xx(bb.size());
   
 //   /* Set solution vector */
 //   double zero = 0.;
 //   double val;
 //   for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) {
 //     int row = it->first;
 //     ierr = VecGetValues(x_all, 1, &row, &val);
 //     if (val != zero)
 //       xx[row] = val;
 //   }
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Solution vector copied... "<<timer<<endl;
 //   //    out<<"  Norm of copied solution vector... "<<norm(xx, Insert_t)<<endl;
 // #endif
   
   
 //   /*
 //    Free work space.  All PETSc objects should be destroyed when they
 //    are no longer needed.
 //    */
 //   ierr = VecDestroy(&b);CHKERRCONTINUE(ierr);
 //   //    ierr = KSPDestroy(&ksp);CHKERRCONTINUE(ierr);
   
 //   // set allocated flag
 //   if (!allocated_) {
 //     allocated_ = true;
 //   }
   
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Temporary data structures destroyed... "<<timer<<endl;
 // #endif
   
 //   return xx;
 // }
 
 // SolverPETSc::sparse_vector_type SolverPETSc::operator()(const SolverPETSc::sparse_matrix_type& KKpf, const SolverPETSc::sparse_matrix_type& KKpp, const SolverPETSc::sparse_vector_type& UUp) {
   
 // #ifdef CPPUTILS_VERBOSE
 //   // parallel output stream
 //   Output_stream out;
 //   // timer
 //   cpputils::ctimer timer;
 //   out<<"Inside SolverPETSc::operator()(const sparse_matrix&, const sparse_matrix&, const sparse_vector&). "<<timer<<endl;
 // #endif
   
 //   Mat Kpf, Kpp;
 //   Vec Up, Pf, Pp;
   
 //   PetscErrorCode ierr = MatCreate(PETSC_COMM_WORLD,&Kpf);CHKERRCONTINUE(ierr);
 //   ierr = MatCreate(PETSC_COMM_WORLD,&Kpp);CHKERRCONTINUE(ierr);
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Allocating memory... "<<timer<<endl;
 // #endif
   
 //   ierr = MatSetFromOptions(Kpf);CHKERRCONTINUE(ierr);
 //   ierr = MatSetFromOptions(Kpp);CHKERRCONTINUE(ierr);
   
 //   ierr = MatSetSizes(Kpf,PETSC_DECIDE,PETSC_DECIDE, KKpf.rows(), KKpf.columns());CHKERRCONTINUE(ierr);
 //   ierr = MatSetSizes(Kpp,PETSC_DECIDE,PETSC_DECIDE, KKpp.rows(), KKpp.columns());CHKERRCONTINUE(ierr);
   
 //   // get number of non-zeros in both diagonal and non-diagonal portions of the matrix
   
 //   std::pair<size_t,size_t> Kpf_nz = KKpf.non_zero_off_diagonal();
 //   std::pair<size_t,size_t> Kpp_nz = KKpp.non_zero_off_diagonal();
   
 //   ierr = MatMPIAIJSetPreallocation(Kpf, Kpf_nz.first, PETSC_NULL, Kpf_nz.second, PETSC_NULL); CHKERRCONTINUE(ierr);
 //   ierr = MatMPIAIJSetPreallocation(Kpp, Kpp_nz.first, PETSC_NULL, Kpp_nz.second, PETSC_NULL); CHKERRCONTINUE(ierr);
 //   ierr = MatSeqAIJSetPreallocation(Kpf, Kpf_nz.first, PETSC_NULL); CHKERRCONTINUE(ierr);
 //   ierr = MatSeqAIJSetPreallocation(Kpp, Kpp_nz.first, PETSC_NULL); CHKERRCONTINUE(ierr);
   
 //   for (sparse_matrix_type::const_hash_iterator it = KKpf.map_.begin(); it != KKpf.map_.end(); ++it) {
     
 //     // get subscripts
 //     std::pair<size_t,size_t> subs = KKpf.unhash(it->first);
 //     int row = subs.first;
 //     int col = subs.second;
 //     ierr = MatSetValues(Kpf, 1, &row, 1, &col, &it->second, ADD_VALUES);CHKERRCONTINUE(ierr);
 //   }
   
 //   for (sparse_matrix_type::const_hash_iterator it = KKpp.map_.begin(); it != KKpp.map_.end(); ++it) {
     
 //     // get subscripts
 //     std::pair<size_t,size_t> subs = KKpp.unhash(it->first);
 //     int row = subs.first;
 //     int col = subs.second;
 //     ierr = MatSetValues(Kpf, 1, &row, 1, &col, &it->second, ADD_VALUES);CHKERRCONTINUE(ierr);
 //   }
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Filled sparse matrices... "<<timer<<endl;
 // #endif
   
   
 //   /*
 //    Assemble matrix, using the 2-step process:
 //    MatAssemblyBegin(), MatAssemblyEnd()
 //    Computations can be done while messages are in transition
 //    by placing code between these two statements.
 //    */
 //   ierr = MatAssemblyBegin(Kpf,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
 //   ierr = MatAssemblyBegin(Kpp,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
 //   ierr = MatAssemblyEnd(Kpf,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
 //   ierr = MatAssemblyEnd(Kpp,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Sparse matrices assembled... "<<timer<<endl;
 // #endif
   
 //   ierr = VecCreate(PETSC_COMM_WORLD,&Up);CHKERRCONTINUE(ierr);
 //   ierr = VecSetSizes(Up,PETSC_DECIDE, UUp.size());CHKERRCONTINUE(ierr);
 //   ierr = VecSetFromOptions(Up);CHKERRCONTINUE(ierr);
   
 //   ierr = VecCreate(PETSC_COMM_WORLD,&Pf);CHKERRCONTINUE(ierr);
 //   ierr = VecSetSizes(Pf,PETSC_DECIDE, KKpf.rows());CHKERRCONTINUE(ierr);
 //   ierr = VecSetFromOptions(Pf);CHKERRCONTINUE(ierr);
 //   ierr = VecDuplicate(Pf,&Pp);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vectors created... "<<timer<<endl;
 // #endif
   
   
 //   /* Set hight-hand-side vector */
 //   for (sparse_vector_type::const_hash_iterator it = UUp.map_.begin(); it != UUp.map_.end(); ++it) {
 //     int row = it->first;
 //     ierr = VecSetValues(Up, 1, &row, &it->second, ADD_VALUES);
 //   }
   
 //   /*
 //    Assemble vector, using the 2-step process:
 //    VecAssemblyBegin(), VecAssemblyEnd()
 //    Computations can be done while messages are in transition
 //    by placing code between these two statements.
 //    */
 //   ierr = VecAssemblyBegin(Up);CHKERRCONTINUE(ierr);
 //   ierr = VecAssemblyEnd(Up);CHKERRCONTINUE(ierr);
   
 //   // add Kpf*Uf
 //   ierr = MatMult(Kpf, x_, Pf);
   
 //   // add Kpp*Up
 //   ierr = MatMultAdd(Kpp, Up, Pf, Pp);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Matrices multiplied... "<<timer<<endl;
 // #endif
   
   
 //   VecScatter ctx;
 //   Vec Pp_all;
   
 //   ierr = VecScatterCreateToAll(Pp, &ctx, &Pp_all);CHKERRCONTINUE(ierr);
 //   ierr = VecScatterBegin(ctx,Pp,Pp_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr);
 //   ierr = VecScatterEnd(ctx,Pp,Pp_all,INSERT_VALUES,SCATTER_FORWARD);CHKERRCONTINUE(ierr);
   
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vector scattered... "<<timer<<endl;
 // #endif
   
 //   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 //    Get values from solution and store them in the object that will be
 //    returned
 //    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
   
 //   sparse_vector_type pp(KKpf.rows());
   
 //   // get reaction vector
 //   for (int i=0; i<KKpf.rows(); ++i) {
     
 //     PetscScalar v;
 //     ierr = VecGetValues(Pp_all, 1, &i, &v);
 //     if (v != PetscScalar())
 //       pp[i] = v;
 //   }
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vector copied... "<<timer<<endl;
 // #endif
   
 //   ierr = MatDestroy(&Kpf);CHKERRCONTINUE(ierr);
 //   ierr = MatDestroy(&Kpp);CHKERRCONTINUE(ierr);
 //   ierr = VecDestroy(&Up);CHKERRCONTINUE(ierr);
 //   ierr = VecDestroy(&Pf);CHKERRCONTINUE(ierr);
 //   ierr = VecDestroy(&Pp);CHKERRCONTINUE(ierr);
 //   ierr = VecDestroy(&Pp_all);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Temporary data structures destroyed... "<<timer<<endl;
 // #endif
   
 //   return pp;
 // }
 
 
 
 // SolverPETSc::sparse_vector_type SolverPETSc::operator()(const SolverPETSc::sparse_vector_type& aa, const SolverPETSc::sparse_vector_type& bb) {
   
 //   assert(aa.size() == bb.size());
   
 // #ifdef CPPUTILS_VERBOSE
 //   // parallel output stream
 //   Output_stream out;
 //   // timer
 //   cpputils::ctimer timer;
 //   out<<"Inside SolverPETSc::operator()(const sparse_vector&, const sparse_vector&). "<<timer<<endl;
 // #endif
   
 //   Vec r;
   
 //   PetscErrorCode ierr = VecCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr);
 //   ierr = VecSetSizes(r,PETSC_DECIDE, aa.size());CHKERRCONTINUE(ierr);
 //   ierr = VecSetFromOptions(r);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vectors created... "<<timer<<endl;
 // #endif
   
 //   // set values
 //   for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) {
 //     int row = it->first;
 //     ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES);
 //   }
 //   for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) {
 //     int row = it->first;
 //     ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES);
 //   }
   
 //   /*
 //    Assemble vector, using the 2-step process:
 //    VecAssemblyBegin(), VecAssemblyEnd()
 //    Computations can be done while messages are in transition
 //    by placing code between these two statements.
 //    */
 //   ierr = VecAssemblyBegin(r);CHKERRCONTINUE(ierr);
 //   ierr = VecAssemblyEnd(r);CHKERRCONTINUE(ierr);
   
   
 //   sparse_vector_type rr(aa.size());
   
 //   for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) {
 //     int row = it->first;
 //     ierr = VecGetValues(r, 1, &row, &rr[row]);
 //   }
 //   for (sparse_vector_type::const_hash_iterator it = bb.map_.begin(); it != bb.map_.end(); ++it) {
 //     int row = it->first;
 //     ierr = VecGetValues(r, 1, &row, &rr[row]);
 //   }
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vector copied... "<<timer<<endl;
 // #endif
   
 //   ierr = VecDestroy(&r);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Temporary data structures destroyed... "<<timer<<endl;
 // #endif
   
 //   return rr;
 // }
 
 // SolverPETSc::value_type SolverPETSc::norm(const SolverPETSc::sparse_matrix_type& aa, Element_insertion_type flag) {
   
 // #ifdef CPPUTILS_VERBOSE
 //   // parallel output stream
 //   Output_stream out;
 //   // timer
 //   cpputils::ctimer timer;
 //   out<<"Inside SolverPETSc::norm(const sparse_matrix&). "<<timer<<endl;
 // #endif
   
 //   Mat r;
   
 //   PetscErrorCode ierr = MatCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr);
 //   ierr = MatSetSizes(r,PETSC_DECIDE,PETSC_DECIDE, aa.rows(), aa.columns());CHKERRCONTINUE(ierr);
 //   ierr = MatSetFromOptions(r);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Matrix created... "<<timer<<endl;
 // #endif
   
 //   // set values
 //   for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) {
 //     // get subscripts
 //     std::pair<size_t,size_t> subs = aa.unhash(it->first);
 //     int row = subs.first;
 //     int col = subs.second;
     
 //     if (flag == Add_t)
 //       ierr = MatSetValues(r, 1, &row, 1, &col, &it->second, ADD_VALUES);
 //     else if (flag == Insert_t)
 //       ierr = MatSetValues(r, 1, &row, 1, &col, &it->second, INSERT_VALUES);
 //     CHKERRCONTINUE(ierr);
 //   }
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Matrix filled..."<<timer<<endl;
 // #endif
   
 //   /*
 //    Assemble vector, using the 2-step process:
 //    VecAssemblyBegin(), VecAssemblyEnd()
 //    Computations can be done while messages are in transition
 //    by placing code between these two statements.
 //    */
 //   ierr = MatAssemblyBegin(r,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
 //   ierr = MatAssemblyEnd(r,MAT_FINAL_ASSEMBLY);CHKERRCONTINUE(ierr);
   
 //   value_type nrm;
   
 //   MatNorm(r,NORM_FROBENIUS,&nrm);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Norm computed... "<<timer<<endl;
 // #endif
   
 //   ierr = MatDestroy(&r);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Temporary data structures destroyed... "<<timer<<endl;
 // #endif
   
 //   return nrm;
 // }
 
 
 // SolverPETSc::value_type SolverPETSc::norm(const SolverPETSc::sparse_vector_type& aa, Element_insertion_type flag) {
   
 // #ifdef CPPUTILS_VERBOSE
 //   // parallel output stream
 //   Output_stream out;
 //   // timer
 //   cpputils::ctimer timer;
 //   out<<"Inside SolverPETSc::norm(const sparse_vector&). "<<timer<<endl;
 // #endif
   
 //   Vec r;
   
 //   PetscErrorCode ierr = VecCreate(PETSC_COMM_WORLD,&r);CHKERRCONTINUE(ierr);
 //   ierr = VecSetSizes(r,PETSC_DECIDE, aa.size());CHKERRCONTINUE(ierr);
 //   ierr = VecSetFromOptions(r);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vector created... "<<timer<<endl;
 // #endif
   
 //   // set values
 //   for (sparse_vector_type::const_hash_iterator it = aa.map_.begin(); it != aa.map_.end(); ++it) {
 //     int row = it->first;
 //     if (flag == Add_t)
 //       ierr = VecSetValues(r, 1, &row, &it->second, ADD_VALUES);
 //     else if (flag == Insert_t)
 //       ierr = VecSetValues(r, 1, &row, &it->second, INSERT_VALUES);
 //     CHKERRCONTINUE(ierr);
 //   }
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Vector filled..."<<timer<<endl;
 // #endif
   
 //   /*
 //    Assemble vector, using the 2-step process:
 //    VecAssemblyBegin(), VecAssemblyEnd()
 //    Computations can be done while messages are in transition
 //    by placing code between these two statements.
 //    */
 //   ierr = VecAssemblyBegin(r);CHKERRCONTINUE(ierr);
 //   ierr = VecAssemblyEnd(r);CHKERRCONTINUE(ierr);
   
 //   value_type nrm;
   
 //   VecNorm(r,NORM_2,&nrm);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Norm computed... "<<timer<<endl;
 // #endif
   
 //   ierr = VecDestroy(&r);CHKERRCONTINUE(ierr);
   
 // #ifdef CPPUTILS_VERBOSE
 //   out<<"  Temporary data structures destroyed... "<<timer<<endl;
 // #endif
   
 //   return nrm;
   
 // }
 
 
 
 // //
 // ///* -------------------------------------------------------------------------- */
 // //SolverMumps::SolverMumps(SparseMatrix & matrix,
 // //                         const ID & id,
 // //                         const MemoryID & memory_id) :
 // //Solver(matrix, id, memory_id), is_mumps_data_initialized(false), rhs_is_local(true) {
 // //  AKANTU_DEBUG_IN();
 // //  
 // //#ifdef AKANTU_USE_MPI
 // //  parallel_method = SolverMumpsOptions::_fully_distributed;
 // //#else //AKANTU_USE_MPI
 // //  parallel_method = SolverMumpsOptions::_master_slave_distributed;
 // //#endif //AKANTU_USE_MPI
 // //  
 // //  CommunicatorEventHandler & comm_event_handler = *this;
 // //  
 // //  communicator.registerEventHandler(comm_event_handler);
 // //  
 // //  AKANTU_DEBUG_OUT();
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //SolverMumps::~SolverMumps() {
 // //  AKANTU_DEBUG_IN();
 // //  
 // //  AKANTU_DEBUG_OUT();
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //void SolverMumps::destroyMumpsData() {
 // //  AKANTU_DEBUG_IN();
 // //  
 // //  if(is_mumps_data_initialized) {
 // //    mumps_data.job = _smj_destroy; // destroy
 // //    dmumps_c(&mumps_data);
 // //    is_mumps_data_initialized = false;
 // //  }
 // //  
 // //  AKANTU_DEBUG_OUT();
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //void SolverMumps::onCommunicatorFinalize(const StaticCommunicator & comm) {
 // //  AKANTU_DEBUG_IN();
 // //  
 // //  try{
 // //    const StaticCommunicatorMPI & comm_mpi =
 // //    dynamic_cast<const StaticCommunicatorMPI &>(comm.getRealStaticCommunicator());
 // //    if(mumps_data.comm_fortran == MPI_Comm_c2f(comm_mpi.getMPICommunicator()))
 // //      destroyMumpsData();
 // //  } catch(...) {}
 // //  
 // //  AKANTU_DEBUG_OUT();
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //void SolverMumps::initMumpsData(SolverMumpsOptions::ParallelMethod parallel_method) {
 // //  switch(parallel_method) {
 // //    case SolverMumpsOptions::_fully_distributed:
 // //      icntl(18) = 3; //fully distributed
 // //      icntl(28) = 0; //automatic choice
 // //      
 // //      mumps_data.nz_loc  = matrix->getNbNonZero();
 // //      mumps_data.irn_loc = matrix->getIRN().values;
 // //      mumps_data.jcn_loc = matrix->getJCN().values;
 // //      break;
 // //    case SolverMumpsOptions::_master_slave_distributed:
 // //      if(prank == 0) {
 // //        mumps_data.nz  = matrix->getNbNonZero();
 // //        mumps_data.irn = matrix->getIRN().values;
 // //        mumps_data.jcn = matrix->getJCN().values;
 // //      } else {
 // //        mumps_data.nz  = 0;
 // //        mumps_data.irn = NULL;
 // //        mumps_data.jcn = NULL;
 // //        
 // //        icntl(18) = 0; //centralized
 // //        icntl(28) = 0; //sequential analysis
 // //      }
 // //      break;
 // //  }
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //void SolverMumps::initialize(SolverOptions & options) {
 // //  AKANTU_DEBUG_IN();
 // //  
 // //  mumps_data.par = 1;
 // //  
 // //  if(SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions *>(&options)) {
 // //    if(opt->parallel_method == SolverMumpsOptions::_master_slave_distributed) {
 // //      mumps_data.par = 0;
 // //    }
 // //  }
 // //  
 // //  mumps_data.sym = 2 * (matrix->getSparseMatrixType() == _symmetric);
 // //  prank = communicator.whoAmI();
 // //#ifdef AKANTU_USE_MPI
 // //  mumps_data.comm_fortran = MPI_Comm_c2f(dynamic_cast<const StaticCommunicatorMPI &>(communicator.getRealStaticCommunicator()).getMPICommunicator());
 // //#endif
 // //  
 // //  if(AKANTU_DEBUG_TEST(dblTrace)) {
 // //    icntl(1) = 2;
 // //    icntl(2) = 2;
 // //    icntl(3) = 2;
 // //    icntl(4) = 4;
 // //  }
 // //  
 // //  mumps_data.job = _smj_initialize; //initialize
 // //  dmumps_c(&mumps_data);
 // //  is_mumps_data_initialized = true;
 // //  
 // //  /* ------------------------------------------------------------------------ */
 // //  UInt size = matrix->getSize();
 // //  
 // //  if(prank == 0) {
 // //    std::stringstream sstr_rhs; sstr_rhs << id << ":rhs";
 // //    rhs = &(alloc<Real>(sstr_rhs.str(), size, 1, REAL_INIT_VALUE));
 // //  } else {
 // //    rhs = NULL;
 // //  }
 // //  
 // //  /// No outputs
 // //  icntl(1) = 0;
 // //  icntl(2) = 0;
 // //  icntl(3) = 0;
 // //  icntl(4) = 0;
 // //  mumps_data.nz_alloc = 0;
 // //  
 // //  if (AKANTU_DEBUG_TEST(dblDump)) icntl(4) = 4;
 // //  
 // //  mumps_data.n   = size;
 // //  
 // //  if(AKANTU_DEBUG_TEST(dblDump)) {
 // //    strcpy(mumps_data.write_problem, "mumps_matrix.mtx");
 // //  }
 // //  
 // //  /* ------------------------------------------------------------------------ */
 // //  // Default Scaling
 // //  icntl(8) = 77;
 // //  
 // //  icntl(5) = 0; // Assembled matrix
 // //  
 // //  SolverMumpsOptions * opt = dynamic_cast<SolverMumpsOptions *>(&options);
 // //  if(opt)
 // //    parallel_method = opt->parallel_method;
 // //  
 // //  initMumpsData(parallel_method);
 // //  
 // //  mumps_data.job = _smj_analyze; //analyze
 // //  dmumps_c(&mumps_data);
 // //  
 // //  AKANTU_DEBUG_OUT();
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //void SolverMumps::setRHS(Array<Real> & rhs) {
 // //  if(prank == 0) {
 // //    matrix->getDOFSynchronizer().gather(rhs, 0, this->rhs);
 // //  } else {
 // //    matrix->getDOFSynchronizer().gather(rhs, 0);
 // //  }
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //void SolverMumps::solve() {
 // //  AKANTU_DEBUG_IN();
 // //  
 // //  if(parallel_method == SolverMumpsOptions::_fully_distributed)
 // //    mumps_data.a_loc  = matrix->getA().values;
 // //  else
 // //    if(prank == 0) {
 // //      mumps_data.a  = matrix->getA().values;
 // //    }
 // //  
 // //  if(prank == 0) {
 // //    mumps_data.rhs = rhs->values;
 // //  }
 // //  
 // //  /// Default centralized dense second member
 // //  icntl(20) = 0;
 // //  icntl(21) = 0;
 // //  
 // //  mumps_data.job = _smj_factorize_solve; //solve
 // //  dmumps_c(&mumps_data);
 // //  
 // //  AKANTU_DEBUG_ASSERT(info(1) != -10, "Singular matrix");
 // //  AKANTU_DEBUG_ASSERT(info(1) == 0,
 // //                      "Error in mumps during solve process, check mumps user guide INFO(1) ="
 // //                      << info(1));
 // //  
 // //  AKANTU_DEBUG_OUT();
 // //}
 // //
 // ///* -------------------------------------------------------------------------- */
 // //void SolverMumps::solve(Array<Real> & solution) {
 // //  AKANTU_DEBUG_IN();
 // //  
 // //  solve();
 // //  
 // //  if(prank == 0) {
 // //    matrix->getDOFSynchronizer().scatter(solution, 0, this->rhs);
 // //  } else {
 // //    matrix->getDOFSynchronizer().scatter(solution, 0);
 // //  }
 // //  
 // //  AKANTU_DEBUG_OUT();
 // //}
 
+__END_AKANTU__
 
-// __END_AKANTU__
diff --git a/src/solver/solver_petsc.hh b/src/solver/solver_petsc.hh
index 352a2db88..40c27c7d5 100644
--- a/src/solver/solver_petsc.hh
+++ b/src/solver/solver_petsc.hh
@@ -1,271 +1,165 @@
 /**
  * @file   solver_petsc.hh
  *
  # @author Alejandro M. Aragón <alejandro.aragon@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @date   Mon Dec 13 10:48:06 2010
  *
- * @brief  Solver class implementation for the petsc solver
+ * @brief  Solver class interface for the petsc solver
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
-// #ifndef __AKANTU_SOLVER_PETSC_HH__
-// #define __AKANTU_SOLVER_PETSC_HH__
+#ifndef __AKANTU_SOLVER_PETSC_HH__
+#define __AKANTU_SOLVER_PETSC_HH__
 
+/* -------------------------------------------------------------------------- */
+#include "solver.hh"
 
-// #include <petscksp.h>
 
+/* -------------------------------------------------------------------------- */
+__BEGIN_AKANTU__
 
-// #include "solver.hh"
-// #include "static_communicator.hh"
-// #include "sparse_matrix.hh"
+class PETScSolverWrapper;
 
-// __BEGIN_AKANTU__
+class SolverPETSc : public Solver {
 
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
 
+  SolverPETSc(SparseMatrix & sparse_matrix,
+	      const ID & id = "solver_petsc",
+	      const MemoryID & memory_id = 0);
 
-// struct SolverPETSc : public Solver, public CommunicatorEventHandler {
-  
-//   typedef double value_type;
-//   typedef sparse_vector<value_type> sparse_vector_type;
-//   typedef SparseMatrix sparse_matrix_type;
-  
-//   Mat A_;                //!< linear system matrix
-//   Vec x_;                //!< Solution vector
-//   KSP ksp_;              //!< linear solver context
-  
-//   bool allocated_;
+  virtual ~SolverPETSc();
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+public:
+  /// create the solver context and set the matrices
+  virtual void initialize(SolverOptions & options = _solver_no_options);
+  virtual void setRHS(Array<Real> & rhs);
+  virtual void solve();
+  virtual void solve(Array<Real> & solution);
+private:
+  /// clean the petsc data
+  virtual void destroyInternalData();  
+
+private:
+
+  /// specify if the petsc_data is initialized or not
+  bool is_petsc_data_initialized;
+
+  /// store the PETSc structures
+  PETScSolverWrapper * petsc_solver_wrapper;
+
+
+
+};
   
+
 //   SolverPETSc(int argc, char *argv[]) : allocated_(false) {
     
-    
-//     PetscInitialize(&argc, &argv,NULL,NULL);
-//     PetscErrorCode ierr;
-    
-//     // create linear solver context
-//     ierr = KSPCreate(PETSC_COMM_WORLD, &ksp_);CHKERRCONTINUE(ierr);
-    
-//     // initial nonzero guess
-//     ierr = KSPSetInitialGuessNonzero(ksp_,PETSC_TRUE); CHKERRCONTINUE(ierr);
-    
-//     // set runtime options
-//     ierr = KSPSetFromOptions(ksp_);CHKERRCONTINUE(ierr);
-    
 //     /*
 //      Set linear solver defaults for this problem (optional).
 //      - By extracting the KSP and PC contexts from the KSP context,
 //      we can then directly call any KSP and PC routines to set
 //      various options.
 //      - The following four statements are optional; all of these
 //      parameters could alternatively be specified at runtime via
 //      KSPSetFromOptions();
 //      */
 //     //      ierr = KSPGetPC(ksp_,&pc);CHKERRCONTINUE(ierr);
 //     //      ierr = PCSetType(pc,PCILU);CHKERRCONTINUE(ierr);
 //     //    ierr = PCSetType(pc,PCJACOBI);CHKERRCONTINUE(ierr);
 //     ierr = KSPSetTolerances(ksp_,1.e-5,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRCONTINUE(ierr);
 //   }
   
 //   //! Overload operator() to solve system of linear equations
 //   sparse_vector_type operator()(const sparse_matrix_type& AA, const sparse_vector_type& bb);
   
 //   //! Overload operator() to obtain reaction vector
 //   sparse_vector_type operator()(const sparse_matrix_type& Kpf, const sparse_matrix_type& Kpp, const sparse_vector_type& Up);
   
 //   //! Overload operator() to obtain the addition two vectors
 //   sparse_vector_type operator()(const sparse_vector_type& aa, const sparse_vector_type& bb);
   
 //   value_type norm(const sparse_matrix_type& aa, Element_insertion_type it = Add_t);
   
 //   value_type norm(const sparse_vector_type& aa, Element_insertion_type it = Add_t);
   
 //   // NOTE: the destructor will return an error if it is called after MPI_Finalize is
 //   // called because it uses collect communication to free-up allocated memory.
 //   ~SolverPETSc() {
     
 //     static bool exit = false;
 //     if (!exit) {
 //       // add finalize PETSc function at exit
 //       atexit(finalize);
 //       exit = true;
 //     }
     
 //     if (allocated_) {
 //       PetscErrorCode ierr = MatDestroy(&A_);CHKERRCONTINUE(ierr);
 //       ierr = VecDestroy(&x_);CHKERRCONTINUE(ierr);
 //       ierr = KSPDestroy(&ksp_);CHKERRCONTINUE(ierr);
 //     }
 //   }
   
 //   /* from the PETSc library, these are the options that can be passed
 //    to the command line
    
 //    Options Database Keys
    
 //    -options_table	                - Calls PetscOptionsView()
 //    -options_left	                - Prints unused options that remain in the database
 //    -objects_left                  - Prints list of all objects that have not been freed
 //    -mpidump	                    - Calls PetscMPIDump()
 //    -malloc_dump	                - Calls PetscMallocDump()
 //    -malloc_info	                - Prints total memory usage
 //    -malloc_log	                - Prints summary of memory usage
    
 //    Options Database Keys for Profiling
    
 //    -log_summary [filename]	    - Prints summary of flop and timing information to screen.
 //    If the filename is specified the summary is written to the file. See PetscLogView().
 //    -log_summary_python [filename]	- Prints data on of flop and timing usage to a file or screen.
 //    -log_all [filename]	        - Logs extensive profiling information See PetscLogDump().
 //    -log [filename]	            - Logs basic profiline information See PetscLogDump().
 //    -log_sync	                    - Log the synchronization in scatters, inner products and norms
 //    -log_mpe [filename]            - Creates a logfile viewable by the utility Upshot/Nupshot (in MPICH distribution)
-//    */
-//   static void finalize() {
-    
-//     static bool finalized = false;
-//     if (!finalized) {
-      
-//       cout<<"*** INFO *** PETSc is finalizing..."<<endl;
-      
-//       // finalize PETSc
-//       PetscErrorCode ierr = PetscFinalize();CHKERRCONTINUE(ierr);
-//       finalized = true;
-      
-//       cout<<"*** INFO *** Process "<<Parallel_base::rank_<<" is finalizing..."<<endl;
-      
-//       // finalize MPI
-//       MPI_Finalize();
 //     }
 //   }
 // };
 
 
 
 
-// class SolverPETSc : public Solver, public CommunicatorEventHandler {
-//   /* ------------------------------------------------------------------------ */
-//   /* Constructors/Destructors                                                 */
-//   /* ------------------------------------------------------------------------ */
-// public:
-  
-//   SolverPETSc(SparseMatrix & sparse_matrix,
-//               const ID & id = "solver_petsc",
-//               const MemoryID & memory_id = 0);
-  
-//   virtual SolverPETSc();
-  
-//   /* ------------------------------------------------------------------------ */
-//   /* Methods                                                                  */
-//   /* ------------------------------------------------------------------------ */
-// public:
-  
-//   /// build the profile and do the analysis part
-//   void initialize(SolverOptions & options = _solver_no_options);
-  
-//   void initializeSlave(SolverOptions & options = _solver_no_options);
-  
-  
-//   /// factorize and solve the system
-//   void solve(Array<Real> & solution);
-//   void solve();
-  
-//   void solveSlave();
-  
-//   virtual void setRHS(Array<Real> & rhs);
-  
-//   /// function to print the contain of the class
-//   //  virtual void printself(std::ostream & stream, int indent = 0) const;
-  
-//   virtual void onCommunicatorFinalize(const StaticCommunicator & communicator);
-  
-// private:
-  
-//   void destroyMumpsData();
-  
-//   inline Int & icntl(UInt i) {
-//     return mumps_data.icntl[i - 1];
-//   }
-  
-//   inline Int & info(UInt i) {
-//     return mumps_data.info[i - 1];
-//   }
-  
-//   void initMumpsData(SolverMumpsOptions::ParallelMethod parallel_method);
-  
-//   /* ------------------------------------------------------------------------ */
-//   /* Accessors                                                                */
-//   /* ------------------------------------------------------------------------ */
-// public:
-  
-//   /* ------------------------------------------------------------------------ */
-//   /* Class Members                                                            */
-//   /* ------------------------------------------------------------------------ */
-// private:
-  
-//   /// mumps data
-//   DMUMPS_STRUC_C mumps_data;
-  
-//   /// specify if the mumps_data are initialized or not
-//   bool is_mumps_data_initialized;
-  
-//   UInt prank;
-  
-//   /* ------------------------------------------------------------------------ */
-//   /* Local types                                                              */
-//   /* ------------------------------------------------------------------------ */
-
-// private:
-//   SolverMumpsOptions::ParallelMethod parallel_method;
-  
-//   bool rhs_is_local;
-  
-//   enum SolverMumpsJob {
-//     _smj_initialize = -1,
-//     _smj_analyze = 1,
-//     _smj_factorize = 2,
-//     _smj_solve = 3,
-//     _smj_analyze_factorize = 4,
-//     _smj_factorize_solve = 5,
-//     _smj_complete = 6, // analyze, factorize, solve
-//     _smj_destroy = -2
-//   };
-// };
-
-
-// /* -------------------------------------------------------------------------- */
-// /* inline functions                                                           */
-// /* -------------------------------------------------------------------------- */
-
-// //#include "solver_mumps_inline_impl.cc"
-
-// /// standard output stream operator
-// // inline std::ostream & operator <<(std::ostream & stream, const SolverMumps & _this)
-// // {
-// //   _this.printself(stream);
-// //   return stream;
-// // }
 
 
-// __END_AKANTU__
+__END_AKANTU__
 
-// #endif /* __AKANTU_SOLVER_PETSC_HH__ */
+#endif /* __AKANTU_SOLVER_PETSC_HH__ */
diff --git a/src/solver/sparse_matrix.hh b/src/solver/sparse_matrix.hh
index 60a03e966..fad877951 100644
--- a/src/solver/sparse_matrix.hh
+++ b/src/solver/sparse_matrix.hh
@@ -1,251 +1,259 @@
 /**
  * @file   sparse_matrix.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Dec 13 2010
  * @date last modification: Mon Sep 15 2014
  *
  * @brief  sparse matrix storage class (distributed assembled matrix)
  * This is a COO format (Coordinate List)
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_SPARSE_MATRIX_HH__
 #define __AKANTU_SPARSE_MATRIX_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "mesh.hh"
 
 /* -------------------------------------------------------------------------- */
 #ifndef __INTEL_COMPILER
 namespace std {
   namespace tr1 {
     template<typename a, typename b>
     struct hash< std::pair<a, b> > {
     private:
       const hash<a> ah;
       const hash<b> bh;
     public:
       hash() : ah(), bh() {}
       size_t operator()(const std::pair<a, b> &p) const {
 	size_t seed = ah(p.first);
 	return bh(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2);
       }
     };
   }
 } // namespaces
 #endif
 
 __BEGIN_AKANTU__
 
 class DOFSynchronizer;
 
-class SparseMatrix : private Memory {
+class SparseMatrix : protected Memory {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   SparseMatrix(UInt size,
 	       const SparseMatrixType & sparse_matrix_type,
 	       const ID & id = "sparse_matrix",
 	       const MemoryID & memory_id = 0);
 
   SparseMatrix(const SparseMatrix & matrix,
 	       const ID & id = "sparse_matrix",
 	       const MemoryID & memory_id = 0);
 
   virtual ~SparseMatrix();
 
   typedef std::pair<UInt, UInt> KeyCOO;
   typedef unordered_map<KeyCOO, UInt>::type coordinate_list_map;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// remove the existing profile
   inline void clearProfile();
   
   /// add a non-zero element
   virtual UInt addToProfile(UInt i, UInt j);
 
   /// set the matrix to 0
   inline void clear();
 
   /// assemble a local matrix in the sparse one
   inline void addToMatrix(UInt i, UInt j, Real value);
 
   /// set the size of the matrix
   void resize(UInt size)
   { this->size = size; }
   
   virtual void buildProfile(const Mesh & mesh, const DOFSynchronizer & dof_synchronizer, UInt nb_degree_of_freedom);
 
   /// modify the matrix to "remove" the blocked dof
   virtual void applyBoundary(const Array<bool> & boundary, Real block_val = 1.);
 
 //  /// modify the matrix to "remove" the blocked dof
 //  void applyBoundaryNormal(Array<bool> & boundary_normal, Array<Real> & EulerAngles, Array<Real> & rhs, const Array<Real> & matrix, Array<Real> & rhs_rotated);
 
   /// save the profil in a file using the MatrixMarket file format
   virtual void saveProfile(const std::string & filename) const;
 
   /// save the matrix in a file using the MatrixMarket file format
   virtual void saveMatrix(const std::string & filename) const;
 
   /// copy assuming the profile are the same
   virtual void copyContent(const SparseMatrix & matrix);
   
   /// copy profile
 //  void copyProfile(const SparseMatrix & matrix);
 
   /// add matrix assuming the profile are the same
   virtual void add(const SparseMatrix & matrix, Real alpha);
 
   /// diagonal lumping
   virtual void lump(Array<Real> & lumped);
 
   /// function to print the contain of the class
   //virtual void printself(std::ostream & stream, int indent = 0) const;
 
 protected:
   inline KeyCOO key(UInt i, UInt j) const {
     if(sparse_matrix_type == _symmetric && (i > j))
       return std::make_pair(j, i);
 
     return std::make_pair(i, j);
   }
 
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// return the values at potition i, j
   inline Real operator()(UInt i, UInt j) const;
   inline Real & operator()(UInt i, UInt j);
 
   AKANTU_GET_MACRO(IRN, irn, const Array<Int> &);
 
   AKANTU_GET_MACRO(JCN, jcn, const Array<Int> &);
 
   AKANTU_GET_MACRO(A, a, const Array<Real> &);
 
   AKANTU_GET_MACRO(NbNonZero, nb_non_zero, UInt);
 
   AKANTU_GET_MACRO(Size, size, UInt);
 
   AKANTU_GET_MACRO(SparseMatrixType, sparse_matrix_type, const SparseMatrixType &);
 
   AKANTU_GET_MACRO(Offset, offset, UInt);
 
   const DOFSynchronizer & getDOFSynchronizer() const {
     AKANTU_DEBUG_ASSERT(dof_synchronizer != NULL,
 			"DOFSynchronizer not initialized in the SparseMatrix!");
     return *dof_synchronizer;
   }
 
+  DOFSynchronizer & getDOFSynchronizer() {
+    AKANTU_DEBUG_ASSERT(dof_synchronizer != NULL,
+			"DOFSynchronizer not initialized in the SparseMatrix!");
+    return *dof_synchronizer;
+  }
+
 private:
   AKANTU_GET_MACRO(DOFSynchronizerPointer, dof_synchronizer, DOFSynchronizer *);
 
   friend Array<Real> & operator*=(Array<Real> & vect, const SparseMatrix & mat);
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// id  of the SparseMatrix
   ID id;
 
   /// sparce matrix type
   SparseMatrixType sparse_matrix_type;
 
   /// Mesh corresponding to the profile
   //  const Mesh * mesh;
 
   /// Size of the matrix
   UInt size;
 
   /// number of processors
   UInt nb_proc;
 
   /// number of non zero element
   UInt nb_non_zero;
 
   /// row indexes
   Array<Int> irn;
 
   /// column indexes
   Array<Int> jcn;
 
   /// values : A[k] = Matrix[irn[k]][jcn[k]]
   Array<Real> a;
 
 
   /// saved row indexes
   Array<Int> * irn_save;
 
   /// saved column indexes
   Array<Int> * jcn_save;
 
   /// saved size
   UInt size_save;
 
   /// information to know where to assemble an element in a global sparse matrix
   //  ElementTypeMapArray<UInt> element_to_sparse_profile;
 
   /* map for  (i,j) ->  k correspondence \warning std::map are slow
    *  \todo improve  with hash_map (non standard in stl) or unordered_map (boost or C++0x)
    */
   coordinate_list_map irn_jcn_k;
 
   DOFSynchronizer * dof_synchronizer;
   //  std::map<std::pair<UInt, UInt>, UInt> * irn_jcn_to_k;
 
   /// offset to inidcate whether row and column indices start at 0 (C/C++) or 1 (Fortran)
   UInt offset; 
+
+
 };
 
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 
 #if defined (AKANTU_INCLUDE_INLINE_IMPL)
 #  include "sparse_matrix_inline_impl.cc"
 #endif
 
 // /// standard output stream operator
 // inline std::ostream & operator <<(std::ostream & stream, const SparseMatrix & _this)
 // {
 //   _this.printself(stream);
 //   return stream;
 // }
 
 Array<Real> & operator*=(Array<Real> & vect, const SparseMatrix & mat);
 
 
 __END_AKANTU__
 
 #endif /* __AKANTU_SPARSE_MATRIX_HH__ */
diff --git a/src/synchronizer/data_accessor.hh b/src/synchronizer/data_accessor.hh
index 8324bdc8c..9d8001934 100644
--- a/src/synchronizer/data_accessor.hh
+++ b/src/synchronizer/data_accessor.hh
@@ -1,217 +1,268 @@
 /**
  * @file   data_accessor.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Thu Jun 16 2011
  * @date last modification: Thu Jun 05 2014
  *
  * @brief  Interface of accessors for pack_unpack system
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_DATA_ACCESSOR_HH__
 #define __AKANTU_DATA_ACCESSOR_HH__
 
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "mesh.hh"
 #include "fe_engine.hh"
 #include "communication_buffer.hh"
 /* -------------------------------------------------------------------------- */
 
 
 __BEGIN_AKANTU__
 
 class DataAccessor {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
 
   DataAccessor();
   virtual ~DataAccessor();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /**
    * @brief get  the number of  data to exchange  for a given akantu::Element  and a
    * given akantu::SynchronizationTag
    */
   virtual UInt getNbDataForElements(__attribute__((unused)) const Array<Element> & elements,
 				    __attribute__((unused)) SynchronizationTag tag) const {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
+  /**
+   * @brief get  the number of  data to exchange  for a given degree of freedom  and a
+   * given akantu::SynchronizationTag
+   */
+  virtual UInt getNbDataForDOFs(__attribute__((unused)) const Array<UInt> & dofs,
+				__attribute__((unused)) SynchronizationTag tag) const {
+    AKANTU_DEBUG_TO_IMPLEMENT();
+  }
+
   /**
    * @brief get  the number of  data to send  for a given
    * akantu::SynchronizationTag
    */
   virtual UInt getNbDataToPack(__attribute__((unused)) SynchronizationTag tag) const {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /**
    * @brief get the number of data  to receive for a given
    * akantu::SynchronizationTag
    */
   virtual UInt getNbDataToUnpack(__attribute__((unused)) SynchronizationTag tag) const {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /**
    * @brief   pack  the   data  for   a  given   akantu::Element  and   a  given
    * akantu::SynchronizationTag
    */
   virtual void packElementData(__attribute__((unused)) CommunicationBuffer & buffer,
 			       __attribute__((unused)) const Array<Element> & element,
 			       __attribute__((unused)) SynchronizationTag tag) const {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /**
    * @brief   pack  the   data  for   a  given  index  and   a  given
    * akantu::SynchronizationTag
    */
   virtual void packData(__attribute__((unused)) CommunicationBuffer & buffer,
 			__attribute__((unused)) const UInt index,
                         __attribute__((unused)) SynchronizationTag tag) const {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
+  /**
+   * @brief   pack  the   data  for the dofs  and   a  given
+   * akantu::SynchronizationTag
+   */
+  virtual void packDOFData(__attribute__((unused)) CommunicationBuffer & buffer,
+			   __attribute__((unused)) const Array<UInt> & dofs,
+			   __attribute__((unused)) SynchronizationTag tag) const {
+    AKANTU_DEBUG_TO_IMPLEMENT();
+  }
+
   /**
    * @brief   unpack  the   data  for   a  given   akantu::Element  and   a  given
    * akantu::SynchronizationTag
    */
   virtual void unpackElementData(__attribute__((unused)) CommunicationBuffer & buffer,
 				 __attribute__((unused)) const Array<Element> & element,
 				 __attribute__((unused)) SynchronizationTag tag) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
   /**
    * @brief   unpack  the   data  for   a  given  index  and   a  given
    * akantu::SynchronizationTag
    */
   virtual void unpackData(__attribute__((unused)) CommunicationBuffer & buffer,
                           __attribute__((unused)) const UInt index,
                           __attribute__((unused)) SynchronizationTag tag) {
     AKANTU_DEBUG_TO_IMPLEMENT();
   }
 
+  /**
+   * @brief   unpack  the   data  for the dofs  and   a  given
+   * akantu::SynchronizationTag
+   */
+  virtual void unpackDOFData(__attribute__((unused)) CommunicationBuffer & buffer,
+			     __attribute__((unused)) const Array<UInt> & dofs,
+			     __attribute__((unused)) SynchronizationTag tag) {
+    AKANTU_DEBUG_TO_IMPLEMENT();
+  }
+
 public:
   template<typename T>
   static inline void packNodalDataHelper(const Array<T> & data,
 					 CommunicationBuffer & buffer,
 					 const Array<Element> & elements,
 					 const Mesh & mesh) {
     packUnpackNodalDataHelper<T, true>(const_cast<Array<T> &>(data), 
 				       buffer, 
 				       elements, 
 				       mesh);
   }
 
   template<typename T>
   static inline void unpackNodalDataHelper(Array<T> & data,
 					   CommunicationBuffer & buffer,
 					   const Array<Element> & elements,
 					   const Mesh & mesh) {
     packUnpackNodalDataHelper<T, false>(data, 
 					buffer, 
 					elements, 
 					mesh);
   }
 
   template<typename T, bool pack_helper>
   static inline void packUnpackNodalDataHelper(Array<T> & data,
 					       CommunicationBuffer & buffer,
 					       const Array<Element> & elements,
 					       const Mesh & mesh);
 
   template<typename T, bool pack_helper>
   static inline void packUnpackElementalDataHelper(ElementTypeMapArray<T> & data_to_pack,
 						   CommunicationBuffer & buffer,
 						   const Array<Element> & element,
 						   bool per_quadrature_point_data,
 						   const FEEngine & fem);
-
   template<typename T>
   static inline void packElementalDataHelper(const ElementTypeMapArray<T> & data_to_pack,
 					     CommunicationBuffer & buffer,
 					     const Array<Element> & elements,
 					     bool per_quadrature_point,
 					     const FEEngine & fem) {
     packUnpackElementalDataHelper<T, true>(const_cast<ElementTypeMapArray<T> &>(data_to_pack),
 					   buffer,
 					   elements,
 					   per_quadrature_point,
 					   fem);
   }
   
   template<typename T>
-  inline void unpackElementalDataHelper(ElementTypeMapArray<T> & data_to_unpack,
+  static inline void unpackElementalDataHelper(ElementTypeMapArray<T> & data_to_unpack,
                                         CommunicationBuffer & buffer,
                                         const Array<Element> & elements,
                                         bool per_quadrature_point,
 					const FEEngine & fem) {
     packUnpackElementalDataHelper<T, false>(data_to_unpack,
 					    buffer,
 					    elements,
 					    per_quadrature_point,
 					    fem);
   }
 
+  template<typename T, bool pack_helper>
+  static inline void packUnpackDOFDataHelper(Array<T> & data,
+					     CommunicationBuffer & buffer,
+					     const Array<UInt> & dofs);
+
+  template<typename T>
+  static inline void packDOFDataHelper(const Array<T> & data_to_pack,
+				       CommunicationBuffer & buffer,
+				       const Array<UInt> & dofs) {
+    packUnpackDOFDataHelper<T, true>(const_cast<Array<T> &>(data_to_pack),
+				     buffer,
+				     dofs);
+  }
+  
+  template<typename T>
+  static inline void unpackDOFDataHelper(Array<T> & data_to_unpack,
+				  CommunicationBuffer & buffer,
+				  const Array<UInt> & dofs) {
+    packUnpackDOFDataHelper<T, false>(data_to_unpack,
+				      buffer,
+				      dofs);
+  }
+
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
 
 };
 
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 
 #include "data_accessor_inline_impl.cc"
 
 // /// standard output stream operator
 // inline std::ostream & operator <<(std::ostream & stream, const DataAccessor & _this)
 // {
 //   _this.printself(stream);
 //   return stream;
 // }
 
 __END_AKANTU__
 
 #endif /* __AKANTU_DATA_ACCESSOR_HH__ */
diff --git a/src/synchronizer/data_accessor_inline_impl.cc b/src/synchronizer/data_accessor_inline_impl.cc
index dc8c0b6dc..8bba84c11 100644
--- a/src/synchronizer/data_accessor_inline_impl.cc
+++ b/src/synchronizer/data_accessor_inline_impl.cc
@@ -1,107 +1,125 @@
 /**
  * @file   data_accessor_inline_impl.cc
  *
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Sep 18 2013
  * @date last modification: Thu Jun 05 2014
  *
  * @brief  Implementation of the inline functions of the DataAccessor class
  *
  * @section LICENSE
  *
  * Copyright (©) 2014 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/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 template<typename T, bool pack_helper>
 inline void DataAccessor::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 = NULL;
 
   Array<Element>::const_iterator<Element> it  = elements.begin();
   Array<Element>::const_iterator<Element> end = elements.end();
   for (; it != end; ++it) {
     const Element & el = *it;
     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>
 inline void DataAccessor::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 = NULL;
 
   Array<Element>::const_iterator<Element> it  = element.begin();
   Array<Element>::const_iterator<Element> end = element.end();
   for (; it != end; ++it) {
     const Element & el = *it;
     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.getNbQuadraturePoints(el.type,
 						     el.ghost_type);
       else nb_quad_per_elem = 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>
+inline void DataAccessor::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) {
+    if(pack_helper)
+      buffer << data_ptr[*it_dof];
+    else
+      buffer >> data_ptr[*it_dof];
+  }
+}
+
diff --git a/src/synchronizer/distributed_synchronizer.cc b/src/synchronizer/distributed_synchronizer.cc
index c497e7069..d698c9fea 100644
--- a/src/synchronizer/distributed_synchronizer.cc
+++ b/src/synchronizer/distributed_synchronizer.cc
@@ -1,1652 +1,1651 @@
 /**
  * @file   distributed_synchronizer.cc
  *
  * @author Dana Christen <dana.christen@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Thu Jun 16 2011
  * @date last modification: Fri Sep 05 2014
  *
  * @brief  implementation of a  communicator using a static_communicator for real
  * send/receive
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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 "distributed_synchronizer.hh"
 #include "static_communicator.hh"
 #include "mesh_utils.hh"
 #include "mesh_data.hh"
 #include "element_group.hh"
 /* -------------------------------------------------------------------------- */
 #include <map>
 #include <iostream>
 #include <algorithm>
 
 #if defined(AKANTU_DEBUG_TOOLS)
 #  include "aka_debug_tools.hh"
 #endif
 
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 DistributedSynchronizer::DistributedSynchronizer(Mesh & mesh,
 						 SynchronizerID id,
 						 MemoryID memory_id) :
   Synchronizer(id, memory_id),
   mesh(mesh),
-  static_communicator(&StaticCommunicator::getStaticCommunicator()),
   prank_to_element("prank_to_element", id)
 {
   AKANTU_DEBUG_IN();
 
   nb_proc = static_communicator->getNbProc();
   rank    = static_communicator->whoAmI();
 
   send_element = new Array<Element>[nb_proc];
   recv_element = new Array<Element>[nb_proc];
 
   mesh.registerEventHandler(*this);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 DistributedSynchronizer::~DistributedSynchronizer() {
   AKANTU_DEBUG_IN();
 
   for (UInt p = 0; p < nb_proc; ++p) {
     send_element[p].clear();
     recv_element[p].clear();
   }
 
   delete [] send_element;
   delete [] recv_element;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 DistributedSynchronizer * DistributedSynchronizer::
 createDistributedSynchronizerMesh(Mesh & mesh,
 				  const MeshPartition * partition,
 				  UInt root,
 				  SynchronizerID id,
 				  MemoryID memory_id) {
   AKANTU_DEBUG_IN();
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
   UInt nb_proc = comm.getNbProc();
   UInt my_rank = comm.whoAmI();
 
   DistributedSynchronizer & communicator = *(new DistributedSynchronizer(mesh, id, memory_id));
 
   if(nb_proc == 1) return &communicator;
 
   UInt * local_connectivity = NULL;
   UInt * local_partitions = NULL;
   Array<UInt> * old_nodes = mesh.getNodesGlobalIdsPointer();
   old_nodes->resize(0);
   Array<Real> * nodes = mesh.getNodesPointer();
 
 
   UInt spatial_dimension = nodes->getNbComponent();
 
   mesh.synchronizeGroupNames();
 
   /* ------------------------------------------------------------------------ */
   /*  Local (rank == root)                                                    */
   /* ------------------------------------------------------------------------ */
   if(my_rank == root) {
     AKANTU_DEBUG_ASSERT(partition->getNbPartition() == nb_proc,
 			"The number of partition does not match the number of processors: " <<
 			partition->getNbPartition() << " != " << nb_proc);
 
     /**
      * connectivity and communications scheme construction
      */
     Mesh::type_iterator it  = mesh.firstType(_all_dimensions,
 					     _not_ghost,
 					     _ek_not_defined);
     Mesh::type_iterator end = mesh.lastType(_all_dimensions,
 					    _not_ghost,
 					    _ek_not_defined);
     UInt count = 0;
     /* --- MAIN LOOP ON TYPES --- */
     for(; it != end; ++it) {
       ElementType type = *it;
 
       UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
       UInt nb_element = mesh.getNbElement(*it);
       UInt nb_local_element[nb_proc];
       UInt nb_ghost_element[nb_proc];
       UInt nb_element_to_send[nb_proc];
 
       memset(nb_local_element, 0, nb_proc*sizeof(UInt));
       memset(nb_ghost_element, 0, nb_proc*sizeof(UInt));
       memset(nb_element_to_send, 0, nb_proc*sizeof(UInt));
 
       /// \todo change this ugly way to avoid a problem if an element
       /// type is present in the mesh but not in the partitions
       const Array<UInt> * tmp_partition_num = NULL;
       try {
 	tmp_partition_num = &partition->getPartition(type, _not_ghost);
       } catch(...) {
 	continue;
       }
       const Array<UInt> & partition_num = *tmp_partition_num;
 
       const CSR<UInt> & ghost_partition = partition->getGhostPartitionCSR()(type, _not_ghost);
 
       /* -------------------------------------------------------------------- */
       /// constructing the reordering structures
       for (UInt el = 0; el < nb_element; ++el) {
 	nb_local_element[partition_num(el)]++;
 	for (CSR<UInt>::const_iterator part = ghost_partition.begin(el);
 	     part != ghost_partition.end(el);
 	     ++part) {
 	  nb_ghost_element[*part]++;
 	}
 	nb_element_to_send[partition_num(el)] += ghost_partition.getNbCols(el) + 1;
       }
 
       /// allocating buffers
       UInt * buffers[nb_proc];
       UInt * buffers_tmp[nb_proc];
       for (UInt p = 0; p < nb_proc; ++p) {
 	UInt size = nb_nodes_per_element * (nb_local_element[p] +
 					    nb_ghost_element[p]);
 	buffers[p] = new UInt[size];
 	buffers_tmp[p] = buffers[p];
       }
 
       /// copying the local connectivity
       UInt * conn_val = mesh.getConnectivity(type, _not_ghost).storage();
       for (UInt el = 0; el < nb_element; ++el) {
 	memcpy(buffers_tmp[partition_num(el)],
 	       conn_val + el * nb_nodes_per_element,
 	       nb_nodes_per_element * sizeof(UInt));
 	buffers_tmp[partition_num(el)] += nb_nodes_per_element;
       }
 
       /// copying the connectivity of ghost element
       for (UInt el = 0; el < nb_element; ++el) {
 	for (CSR<UInt>::const_iterator part = ghost_partition.begin(el);
 	     part != ghost_partition.end(el);
 	     ++part) {
 	  UInt proc = *part;
 	  memcpy(buffers_tmp[proc],
 		 conn_val + el * nb_nodes_per_element,
 		 nb_nodes_per_element * sizeof(UInt));
 	  buffers_tmp[proc] += nb_nodes_per_element;
 	}
       }
 
 
       /// tag info
       std::vector<std::string> tag_names;
       mesh.getMeshData().getTagNames(tag_names, type);
 
       UInt nb_tags = tag_names.size();
 
       /* -------->>>>-SIZE + CONNECTIVITY------------------------------------ */
       /// send all connectivity and ghost information to all processors
       std::vector<CommunicationRequest *> requests;
       for (UInt p = 0; p < nb_proc; ++p) {
 	if(p != root) {
 	  UInt size[5];
 	  size[0] = (UInt) type;
 	  size[1] = nb_local_element[p];
 	  size[2] = nb_ghost_element[p];
 	  size[3] = nb_element_to_send[p];
 	  size[4] = nb_tags;
 	  AKANTU_DEBUG_INFO("Sending connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")");
 	  comm.send(size, 5, p, Tag::genTag(my_rank, count, TAG_SIZES));
 
 	  AKANTU_DEBUG_INFO("Sending connectivities to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_CONNECTIVITY) <<")");
 	  requests.push_back(comm.asyncSend(buffers[p],
 					    nb_nodes_per_element * (nb_local_element[p] +
 								    nb_ghost_element[p]),
 					    p, Tag::genTag(my_rank, count, TAG_CONNECTIVITY)));
 	} else {
 	  local_connectivity = buffers[p];
 	}
       }
 
       /// create the renumbered connectivity
       AKANTU_DEBUG_INFO("Renumbering local connectivities");
       MeshUtils::renumberMeshNodes(mesh,
 				   local_connectivity,
 				   nb_local_element[root],
 				   nb_ghost_element[root],
 				   type,
 				   *old_nodes);
 
       comm.waitAll(requests);
       comm.freeCommunicationRequest(requests);
       requests.clear();
 
       for (UInt p = 0; p < nb_proc; ++p) {
 	delete [] buffers[p];
       }
 
       /* -------------------------------------------------------------------- */
       for (UInt p = 0; p < nb_proc; ++p) {
 	buffers[p] = new UInt[nb_ghost_element[p] + nb_element_to_send[p]];
 	buffers_tmp[p] = buffers[p];
       }
 
       /// splitting the partition information to send them to processors
       UInt count_by_proc[nb_proc];
       memset(count_by_proc, 0, nb_proc*sizeof(UInt));
       for (UInt el = 0; el < nb_element; ++el) {
 	*(buffers_tmp[partition_num(el)]++) = ghost_partition.getNbCols(el);
 	UInt i(0);
 	for (CSR<UInt>::const_iterator part = ghost_partition.begin(el);
 	     part != ghost_partition.end(el);
 	     ++part, ++i) {
 	  *(buffers_tmp[partition_num(el)]++) = *part;
 	}
       }
 
       for (UInt el = 0; el < nb_element; ++el) {
 	UInt i(0);
 	for (CSR<UInt>::const_iterator part = ghost_partition.begin(el);
 	     part != ghost_partition.end(el);
 	     ++part, ++i) {
 	  *(buffers_tmp[*part]++) = partition_num(el);
 	}
       }
 
       /* -------->>>>-PARTITIONS--------------------------------------------- */
       /// last data to compute the communication scheme
       for (UInt p = 0; p < nb_proc; ++p) {
 	if(p != root) {
 	  AKANTU_DEBUG_INFO("Sending partition informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_PARTITIONS) <<")");
 	  requests.push_back(comm.asyncSend(buffers[p],
 					     nb_element_to_send[p] + nb_ghost_element[p],
 					    p, Tag::genTag(my_rank, count, TAG_PARTITIONS)));
 	} else {
 	  local_partitions = buffers[p];
 	}
       }
 
       if(Mesh::getSpatialDimension(type) == mesh.getSpatialDimension()) {
 	AKANTU_DEBUG_INFO("Creating communications scheme");
 	communicator.fillCommunicationScheme(local_partitions,
 					     nb_local_element[root],
 					     nb_ghost_element[root],
 					     type);
       }
 
       comm.waitAll(requests);
       comm.freeCommunicationRequest(requests);
       requests.clear();
 
       for (UInt p = 0; p < nb_proc; ++p) {
 	delete [] buffers[p];
       }
 
       /* -------------------------------------------------------------------- */
       /// send  data assossiated to the mesh
       /* -------->>>>-TAGS--------------------------------------------------- */
       synchronizeTagsSend(communicator, root, mesh, nb_tags, type,
 			  partition_num,
 			  ghost_partition,
 			  nb_local_element[root],
 			  nb_ghost_element[root]);
 
 
       /* -------------------------------------------------------------------- */
       /// send  data assossiated to groups
       /* -------->>>>-GROUPS------------------------------------------------- */
       synchronizeElementGroups(communicator, root, mesh, type,
       			       partition_num,
       			       ghost_partition,
 			       nb_element);
 
       ++count;
     }
 
     /* -------->>>>-SIZE----------------------------------------------------- */
     for (UInt p = 0; p < nb_proc; ++p) {
       if(p != root) {
 	UInt size[5];
 	size[0] = (UInt) _not_defined;
 	size[1] = 0;
 	size[2] = 0;
 	size[3] = 0;
 	size[4] = 0;
 	AKANTU_DEBUG_INFO("Sending empty connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")");
 	comm.send(size, 5, p, Tag::genTag(my_rank, count, TAG_SIZES));
       }
     }
 
     /* ---------------------------------------------------------------------- */
     /* ---------------------------------------------------------------------- */
     /**
      * Nodes coordinate construction and synchronization
      */
     std::multimap< UInt, std::pair<UInt, UInt> > nodes_to_proc;
     /// get the list of nodes to send and send them
     Real * local_nodes = NULL;
     UInt nb_nodes_per_proc[nb_proc];
     UInt * nodes_per_proc[nb_proc];
 
     comm.broadcast(&(mesh.nb_global_nodes), 1, root);
 
     /* --------<<<<-NB_NODES + NODES----------------------------------------- */
     for (UInt p = 0; p < nb_proc; ++p) {
       UInt nb_nodes = 0;
       //      UInt * buffer;
       if(p != root) {
 	AKANTU_DEBUG_INFO("Receiving number of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NB_NODES) <<")");
 	comm.receive(&nb_nodes, 1, p, Tag::genTag(p, 0, TAG_NB_NODES));
 	nodes_per_proc[p] = new UInt[nb_nodes];
 	nb_nodes_per_proc[p] = nb_nodes;
 	AKANTU_DEBUG_INFO("Receiving list of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NODES) <<")");
 	comm.receive(nodes_per_proc[p], nb_nodes, p, Tag::genTag(p, 0, TAG_NODES));
       } else {
 	nb_nodes = old_nodes->getSize();
 	nb_nodes_per_proc[p] = nb_nodes;
 	nodes_per_proc[p] = old_nodes->storage();
       }
 
       /// get the coordinates for the selected nodes
       Real * nodes_to_send = new Real[nb_nodes * spatial_dimension];
       Real * nodes_to_send_tmp = nodes_to_send;
       for (UInt n = 0; n < nb_nodes; ++n) {
 	memcpy(nodes_to_send_tmp,
 	       nodes->storage() + spatial_dimension * nodes_per_proc[p][n],
 	       spatial_dimension * sizeof(Real));
 	// nodes_to_proc.insert(std::make_pair(buffer[n], std::make_pair(p, n)));
 	nodes_to_send_tmp += spatial_dimension;
       }
 
       /* -------->>>>-COORDINATES-------------------------------------------- */
       if(p != root) { /// send them for distant processors
 	AKANTU_DEBUG_INFO("Sending coordinates to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_COORDINATES) <<")");
 	comm.send(nodes_to_send, nb_nodes * spatial_dimension, p, Tag::genTag(my_rank, 0, TAG_COORDINATES));
 	delete [] nodes_to_send;
       } else { /// save them for local processor
 	local_nodes = nodes_to_send;
       }
     }
 
 
     /// construct the local nodes coordinates
     UInt nb_nodes = old_nodes->getSize();
     nodes->resize(nb_nodes);
     memcpy(nodes->storage(), local_nodes, nb_nodes * spatial_dimension * sizeof(Real));
     delete [] local_nodes;
 
     Array<Int> * nodes_type_per_proc[nb_proc];
     for (UInt p = 0; p < nb_proc; ++p) {
       nodes_type_per_proc[p] = new Array<Int>(nb_nodes_per_proc[p]);
     }
 
     communicator.fillNodesType(mesh);
 
     /* --------<<<<-NODES_TYPE-1--------------------------------------------- */
     for (UInt p = 0; p < nb_proc; ++p) {
       if(p != root) {
 	AKANTU_DEBUG_INFO("Receiving first nodes types from proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_NODES_TYPE) <<")");
 	comm.receive(nodes_type_per_proc[p]->storage(),
 		     nb_nodes_per_proc[p], p, Tag::genTag(p, 0, TAG_NODES_TYPE));
       } else {
 	nodes_type_per_proc[p]->copy(mesh.getNodesType());
       }
       for (UInt n = 0; n < nb_nodes_per_proc[p]; ++n) {
 	if((*nodes_type_per_proc[p])(n) == -2)
 	  nodes_to_proc.insert(std::make_pair(nodes_per_proc[p][n], std::make_pair(p, n)));
       }
     }
 
     std::multimap< UInt, std::pair<UInt, UInt> >::iterator it_node;
     std::pair< std::multimap< UInt, std::pair<UInt, UInt> >::iterator,
 	       std::multimap< UInt, std::pair<UInt, UInt> >::iterator > it_range;
     for (UInt i = 0; i < mesh.nb_global_nodes; ++i) {
       it_range = nodes_to_proc.equal_range(i);
       if(it_range.first == nodes_to_proc.end() || it_range.first->first != i) continue;
 
       UInt node_type = (it_range.first)->second.first;
       for (it_node = it_range.first; it_node != it_range.second; ++it_node) {
 	UInt proc = it_node->second.first;
 	UInt node = it_node->second.second;
 	if(proc != node_type)
 	  nodes_type_per_proc[proc]->storage()[node] = node_type;
       }
     }
 
     /* -------->>>>-NODES_TYPE-2--------------------------------------------- */
     std::vector<CommunicationRequest *> requests;
     for (UInt p = 0; p < nb_proc; ++p) {
       if(p != root) {
 	AKANTU_DEBUG_INFO("Sending nodes types to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_NODES_TYPE) <<")");
 	requests.push_back(comm.asyncSend(nodes_type_per_proc[p]->storage(),
 					  nb_nodes_per_proc[p], p, Tag::genTag(my_rank, 0, TAG_NODES_TYPE)));
       } else {
 	mesh.getNodesTypePointer()->copy(*nodes_type_per_proc[p]);
       }
     }
 
     comm.waitAll(requests);
     comm.freeCommunicationRequest(requests);
     requests.clear();
 
     for (UInt p = 0; p < nb_proc; ++p) {
       if(p != root) delete [] nodes_per_proc[p];
       delete nodes_type_per_proc[p];
     }
 
     /* -------->>>>-NODE GROUPS --------------------------------------------- */
     synchronizeNodeGroupsMaster(communicator, root, mesh);
 
     /* ---------------------------------------------------------------------- */
     /*  Distant (rank != root)                                                */
     /* ---------------------------------------------------------------------- */
   } else {
     /**
      * connectivity and communications scheme construction on distant processors
      */
     ElementType type = _not_defined;
     UInt count = 0;
     do {
       /* --------<<<<-SIZE--------------------------------------------------- */
       UInt size[5] = { 0 };
       comm.receive(size, 5, root, Tag::genTag(root, count, TAG_SIZES));
 
       type        = (ElementType) size[0];
       UInt nb_local_element     = size[1];
       UInt nb_ghost_element     = size[2];
       UInt nb_element_to_send   = size[3];
       UInt nb_tags              = size[4];
 
       if(type != _not_defined) {
 	UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
 	/* --------<<<<-CONNECTIVITY----------------------------------------- */
 	local_connectivity = new UInt[(nb_local_element + nb_ghost_element) *
 				      nb_nodes_per_element];
 	AKANTU_DEBUG_INFO("Receiving connectivities from proc " << root);
 	comm.receive(local_connectivity, nb_nodes_per_element * (nb_local_element +
 								  nb_ghost_element),
 		     root, Tag::genTag(root, count, TAG_CONNECTIVITY));
 
 	AKANTU_DEBUG_INFO("Renumbering local connectivities");
 	MeshUtils::renumberMeshNodes(mesh,
 				     local_connectivity,
 				     nb_local_element,
 				     nb_ghost_element,
 				     type,
 				     *old_nodes);
 
 	delete [] local_connectivity;
 
 	/* --------<<<<-PARTITIONS--------------------------------------------- */
 	local_partitions = new UInt[nb_element_to_send + nb_ghost_element * 2];
 	AKANTU_DEBUG_INFO("Receiving partition informations from proc " << root);
 	comm.receive(local_partitions,
 		     nb_element_to_send + nb_ghost_element * 2,
 		     root, Tag::genTag(root, count, TAG_PARTITIONS));
 
 	if(Mesh::getSpatialDimension(type) == mesh.getSpatialDimension()) {
 	  AKANTU_DEBUG_INFO("Creating communications scheme");
 	  communicator.fillCommunicationScheme(local_partitions,
 					       nb_local_element,
 					       nb_ghost_element,
 					       type);
 	}
 	delete [] local_partitions;
 
 	/* --------<<<<-TAGS------------------------------------------------- */
 	synchronizeTagsRecv(communicator, root, mesh, nb_tags, type,
 			    nb_local_element,
 			    nb_ghost_element);
 
 	/* --------<<<<-GROUPS----------------------------------------------- */
 	synchronizeElementGroups(communicator, root, mesh, type);
       }
       ++count;
     } while(type != _not_defined);
 
     /**
      * Nodes coordinate construction and synchronization on distant processors
      */
     comm.broadcast(&(mesh.nb_global_nodes), 1, root);
 
     /* -------->>>>-NB_NODES + NODES----------------------------------------- */
     AKANTU_DEBUG_INFO("Sending list of nodes to proc " << root);
     UInt nb_nodes = old_nodes->getSize();
     comm.send(&nb_nodes, 1, root, Tag::genTag(my_rank, 0, TAG_NB_NODES));
     comm.send(old_nodes->storage(), nb_nodes, root, Tag::genTag(my_rank, 0, TAG_NODES));
 
     /* --------<<<<-COORDINATES---------------------------------------------- */
     nodes->resize(nb_nodes);
     AKANTU_DEBUG_INFO("Receiving coordinates from proc " << root);
     comm.receive(nodes->storage(), nb_nodes * spatial_dimension, root, Tag::genTag(root, 0, TAG_COORDINATES));
 
     communicator.fillNodesType(mesh);
     /* -------->>>>-NODES_TYPE-1--------------------------------------------- */
     Int * nodes_types = mesh.getNodesTypePointer()->storage();
     AKANTU_DEBUG_INFO("Sending first nodes types to proc " << root);
     comm.send(nodes_types, nb_nodes,
 	      root, Tag::genTag(my_rank, 0, TAG_NODES_TYPE));
 
     /* --------<<<<-NODES_TYPE-2--------------------------------------------- */
     AKANTU_DEBUG_INFO("Receiving nodes types from proc " << root);
     comm.receive(nodes_types, nb_nodes,
 		 root, Tag::genTag(root, 0, TAG_NODES_TYPE));
 
     /* --------<<<<-NODE GROUPS --------------------------------------------- */
     synchronizeNodeGroupsSlaves(communicator, root, mesh);
   }
 
   MeshUtils::fillElementToSubElementsData(mesh);
 
   mesh.is_distributed = true;
 
   AKANTU_DEBUG_OUT();
   return &communicator;
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::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) {
   #define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem)	\
     case BOOST_PP_TUPLE_ELEM(2, 0, elem) : { \
       fillTagBufferTemplated<BOOST_PP_TUPLE_ELEM(2, 1, elem)>(mesh_data, buffers, tag_name, el_type, partition_num, ghost_partition); \
       break; \
     } \
 
   MeshDataTypeCode data_type_code = mesh_data.getTypeCode(tag_name);
   switch(data_type_code) {
     BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , AKANTU_MESH_DATA_TYPES)
   default : AKANTU_DEBUG_ERROR("Could not obtain the type of tag" << tag_name << "!"); break;
   }
   #undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::fillNodesType(Mesh & mesh) {
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes = mesh.getNbNodes();
   Int * nodes_type = mesh.getNodesTypePointer()->storage();
 
   UInt * nodes_set = new UInt[nb_nodes];
   std::fill_n(nodes_set, nb_nodes, 0);
 
   const UInt NORMAL_SET = 1;
   const UInt GHOST_SET  = 2;
 
   bool * already_seen = new bool[nb_nodes];
 
   for(UInt g = _not_ghost; g <= _ghost; ++g) {
     GhostType gt = (GhostType) g;
     UInt set = NORMAL_SET;
     if (gt == _ghost) set = GHOST_SET;
 
     std::fill_n(already_seen, nb_nodes, false);
     Mesh::type_iterator it  = mesh.firstType(_all_dimensions, gt, _ek_not_defined);
     Mesh::type_iterator end = mesh.lastType(_all_dimensions, gt, _ek_not_defined);
     for(; it != end; ++it) {
       ElementType type = *it;
 
       UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
       UInt nb_element = mesh.getNbElement(type, gt);
       Array<UInt>::iterator< Vector<UInt> > conn_it = mesh.getConnectivity(type, gt).begin(nb_nodes_per_element);
 
       for (UInt e = 0; e < nb_element; ++e, ++conn_it) {
 	Vector<UInt> & conn = *conn_it;
 	for (UInt n = 0; n < nb_nodes_per_element; ++n) {
 	  AKANTU_DEBUG_ASSERT(conn(n) < nb_nodes, "Node " << conn(n)
 			      << " bigger than number of nodes " << nb_nodes);
 	  if(!already_seen[conn(n)]) {
 	    nodes_set[conn(n)] += set;
 	    already_seen[conn(n)] = true;
 	  }
 	}
       }
     }
   }
 
   delete [] already_seen;
 
   for (UInt i = 0; i < nb_nodes; ++i) {
     if(nodes_set[i] == NORMAL_SET) nodes_type[i] = -1;
     else if(nodes_set[i] == GHOST_SET) nodes_type[i] = -3;
     else if(nodes_set[i] == (GHOST_SET + NORMAL_SET)) nodes_type[i] = -2;
   }
 
   delete [] nodes_set;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::fillCommunicationScheme(const UInt * partition,
 						      UInt nb_local_element,
 						      UInt nb_ghost_element,
 						      ElementType type) {
   AKANTU_DEBUG_IN();
 
   Element element;
   element.type = type;
   element.kind = Mesh::getKind(type);
 
   const UInt * part = partition;
 
   part = partition;
   for (UInt lel = 0; lel < nb_local_element; ++lel) {
     UInt nb_send = *part; part++;
     element.element = lel;
     element.ghost_type = _not_ghost;
     for (UInt p = 0; p < nb_send; ++p) {
       UInt proc = *part; part++;
 
       AKANTU_DEBUG(dblAccessory, "Must send : " << element << " to proc " << proc);
       (send_element[proc]).push_back(element);
     }
   }
 
   for (UInt gel = 0; gel < nb_ghost_element; ++gel) {
     UInt proc = *part; part++;
     element.element = gel;
     element.ghost_type = _ghost;
     AKANTU_DEBUG(dblAccessory, "Must recv : " << element << " from proc " << proc);
     recv_element[proc].push_back(element);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::asynchronousSynchronize(DataAccessor & data_accessor,
 						      SynchronizationTag tag) {
   AKANTU_DEBUG_IN();
 
   if (communications.find(tag) == communications.end())
     computeBufferSize(data_accessor, tag);
 
   Communication & communication = communications[tag];
 
   AKANTU_DEBUG_ASSERT(communication.send_requests.size() == 0,
 		      "There must be some pending sending communications. Tag is " << tag);
 
   std::map<SynchronizationTag, UInt>::iterator t_it = tag_counter.find(tag);
   UInt counter = 0;
   if(t_it == tag_counter.end()) {
     tag_counter[tag] = 0;
   } else {
     counter = ++(t_it->second);
   }
 
   for (UInt p = 0; p < nb_proc; ++p) {
     UInt ssize = communication.size_to_send[p];
     if(p == rank || ssize == 0) continue;
 
     CommunicationBuffer & buffer = communication.send_buffer[p];
     buffer.resize(ssize);
 #ifndef AKANTU_NDEBUG
     UInt nb_elements   =  send_element[p].getSize();
     AKANTU_DEBUG_INFO("Packing data for proc " << p
 		      << " (" << ssize << "/" << nb_elements
 		      <<" data to send/elements)");
 
     /// pack barycenters in debug mode
     Array<Element>::const_iterator<Element> bit  = send_element[p].begin();
     Array<Element>::const_iterator<Element> bend = send_element[p].end();
     for (; bit != bend; ++bit) {
       const Element & element = *bit;
       Vector<Real> barycenter(mesh.getSpatialDimension());
       mesh.getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type);
       buffer << barycenter;
     }
 #endif
 
     data_accessor.packElementData(buffer, send_element[p], tag);
 
     AKANTU_DEBUG_ASSERT(buffer.getPackedSize() == ssize,
 			"a problem have been introduced with "
 			<< "false sent sizes declaration "
 			<< buffer.getPackedSize() << " != " << ssize);
     AKANTU_DEBUG_INFO("Posting send to proc " << p
 		      << " (tag: " << tag << " - " << ssize << " data to send)"
 		      << " [" << Tag::genTag(rank, counter, tag) << "]");
     communication.send_requests.push_back(static_communicator->asyncSend(buffer.storage(),
 									 ssize,
 									 p,
 									 Tag::genTag(rank, counter, tag)));
   }
 
   AKANTU_DEBUG_ASSERT(communication.recv_requests.size() == 0,
 		      "There must be some pending receive communications");
 
   for (UInt p = 0; p < nb_proc; ++p) {
     UInt rsize = communication.size_to_receive[p];
     if(p == rank || rsize == 0) continue;
     CommunicationBuffer & buffer = communication.recv_buffer[p];
     buffer.resize(rsize);
 
     AKANTU_DEBUG_INFO("Posting receive from proc " << p
 		      << " (tag: " << tag << " - " << rsize << " data to receive) "
 		      << " [" << Tag::genTag(p, counter, tag) << "]");
     communication.recv_requests.push_back(static_communicator->asyncReceive(buffer.storage(),
 									    rsize,
 									    p,
 									    Tag::genTag(p, counter, tag)));
   }
 
 
 #if defined(AKANTU_DEBUG_TOOLS) && defined(AKANTU_CORE_CXX11)
   static std::set<SynchronizationTag> tags;
   if(tags.find(tag) == tags.end()) {
     debug::element_manager.print(debug::_dm_synch,
 				 [&send_element, rank, nb_proc, tag, id](const Element & el)->std::string {
 				   std::stringstream out;
 				   UInt elp = 0;
 				   for (UInt p = 0; p < nb_proc; ++p) {
 				     UInt pos = send_element[p].find(el);
 				     if(pos != UInt(-1)) {
 				       if(elp > 0) out << std::endl;
 				       out << id << " send (" << pos << "/" << send_element[p].getSize() << ") to proc " << p << " tag:" << tag;
 				       ++elp;
 				     }
 				   }
 				   return out.str();
 				 });
 
     debug::element_manager.print(debug::_dm_synch,
 				 [&recv_element, rank, nb_proc, tag, id](const Element & el)->std::string {
 				   std::stringstream out;
 				   UInt elp = 0;
 				   for (UInt p = 0; p < nb_proc; ++p) {
 				     if(p == rank) continue;
 				     UInt pos = recv_element[p].find(el);
 				     if(pos != UInt(-1)) {
 				       if(elp > 0) out << std::endl;
 				       out << id << " recv (" << pos << "/" << recv_element[p].getSize() << ") from proc " << p << " tag:" << tag;
 				       ++elp;
 				     }
 				   }
 				   return out.str();
 				 });
     tags.insert(tag);
   }
 #endif
 
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::waitEndSynchronize(DataAccessor & data_accessor,
 						 SynchronizationTag tag) {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(communications.find(tag) != communications.end(), "No communication with the tag \""
 		      << tag <<"\" started");
 
   Communication & communication = communications[tag];
 
   std::vector<CommunicationRequest *> req_not_finished;
   std::vector<CommunicationRequest *> * req_not_finished_tmp = &req_not_finished;
   std::vector<CommunicationRequest *> * recv_requests_tmp = &(communication.recv_requests);
 
   //  static_communicator->waitAll(recv_requests);
   while(!recv_requests_tmp->empty()) {
     for (std::vector<CommunicationRequest *>::iterator req_it = recv_requests_tmp->begin();
 	 req_it != recv_requests_tmp->end() ; ++req_it) {
       CommunicationRequest * req = *req_it;
 
       if(static_communicator->testRequest(req)) {
 	UInt proc = req->getSource();
 	AKANTU_DEBUG_INFO("Unpacking data coming from proc " << proc);
 	CommunicationBuffer & buffer = communication.recv_buffer[proc];
 
 #ifndef AKANTU_NDEBUG
 	Array<Element>::const_iterator<Element> bit  = recv_element[proc].begin();
 	Array<Element>::const_iterator<Element> bend = recv_element[proc].end();
 
 	UInt spatial_dimension = mesh.getSpatialDimension();
 
 	for (; bit != bend; ++bit) {
 	  const Element & element = *bit;
 
 	  Vector<Real> barycenter_loc(spatial_dimension);
 	  mesh.getBarycenter(element.element,
 			     element.type,
 			     barycenter_loc.storage(),
 			     element.ghost_type);
 	  Vector<Real> barycenter(spatial_dimension);
 	  buffer >> barycenter;
 	  Real tolerance = Math::getTolerance();
 	  Real bary_norm = barycenter.norm();
 	  for (UInt i = 0; i < spatial_dimension; ++i) {
 	    if((std::abs((barycenter(i) - barycenter_loc(i))/bary_norm) <= tolerance) ||
-	       (std::abs(barycenter_loc(i)) <= 0 && std::abs(barycenter(i)) <= tolerance)) continue;
+	       (std::abs(barycenter_loc(i)) <= tolerance && std::abs(barycenter(i)) <= tolerance)) continue;
 	    AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: "
 			       << element
 			       << "(barycenter[" << i << "] = " << barycenter_loc(i)
 			       << " and buffer[" << i << "] = " << barycenter(i) << ") ["
 			       << std::abs((barycenter(i) - barycenter_loc(i))/barycenter_loc(i))
 			       << "] - tag: " << tag);
 	  }
 	}
 #endif
 
 	data_accessor.unpackElementData(buffer, recv_element[proc], tag);
 	buffer.resize(0);
 
 	AKANTU_DEBUG_ASSERT(buffer.getLeftToUnpack() == 0,
 			    "all data have not been unpacked: "
 			    << buffer.getLeftToUnpack() << " bytes left");
 	static_communicator->freeCommunicationRequest(req);
       } else {
 	req_not_finished_tmp->push_back(req);
       }
     }
 
     std::vector<CommunicationRequest *> * swap = req_not_finished_tmp;
     req_not_finished_tmp = recv_requests_tmp;
     recv_requests_tmp = swap;
 
     req_not_finished_tmp->clear();
   }
 
 
   AKANTU_DEBUG_INFO("Waiting that every send requests are received");
   static_communicator->waitAll(communication.send_requests);
   for (std::vector<CommunicationRequest *>::iterator req_it = communication.send_requests.begin();
        req_it != communication.send_requests.end() ; ++req_it) {
     CommunicationRequest & req = *(*req_it);
 
     if(static_communicator->testRequest(&req)) {
       UInt proc = req.getDestination();
       CommunicationBuffer & buffer = communication.send_buffer[proc];
       buffer.resize(0);
       static_communicator->freeCommunicationRequest(&req);
     }
   }
   communication.send_requests.clear();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::computeBufferSize(DataAccessor & data_accessor,
 						SynchronizationTag tag) {
   AKANTU_DEBUG_IN();
 
   communications[tag].resize(nb_proc);
 
   for (UInt p = 0; p < nb_proc; ++p) {
     UInt ssend    = 0;
     UInt sreceive = 0;
     if(p != rank) {
       if(send_element[p].getSize() != 0) {
 #ifndef AKANTU_NDEBUG
 	ssend += send_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real);
 #endif
 	ssend += data_accessor.getNbDataForElements(send_element[p], tag);
 	AKANTU_DEBUG_INFO("I have " << ssend << "(" << ssend / 1024.
 			  << "kB - "<< send_element[p].getSize() <<" element(s)) data to send to " << p << " for tag "
 			  << tag);
       }
 
       if(recv_element[p].getSize() != 0) {
 #ifndef AKANTU_NDEBUG
 	sreceive += recv_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real);
 #endif
 	sreceive += data_accessor.getNbDataForElements(recv_element[p], tag);
 	AKANTU_DEBUG_INFO("I have " << sreceive << "(" << sreceive / 1024.
 			  << "kB - "<< recv_element[p].getSize() <<" element(s)) data to receive for tag "
 			  << tag);
       }
     }
 
     communications[tag].size_to_send   [p] = ssend;
     communications[tag].size_to_receive[p] = sreceive;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::printself(std::ostream & stream, int indent) const {
   std::string space;
   for(Int i = 0; i < indent; i++, space += AKANTU_INDENT);
 
   Int prank = StaticCommunicator::getStaticCommunicator().whoAmI();
   Int psize = StaticCommunicator::getStaticCommunicator().getNbProc();
   stream << "[" << prank << "/" << psize << "]" << space << "DistributedSynchronizer [" << std::endl;
   for (UInt p = 0; p < nb_proc; ++p) {
     if (p == UInt(prank)) continue;
     stream << "[" << prank << "/" << psize << "]" << space
 	   << " + Communication to proc " << p << " [" << std::endl;
     if(AKANTU_DEBUG_TEST(dblDump)) {
       stream << "[" << prank << "/" << psize << "]" << space
 	     << "    - Element to send to proc " << p << " [" << std::endl;
 
       Array<Element>::iterator<Element> it_el  = send_element[p].begin();
       Array<Element>::iterator<Element> end_el = send_element[p].end();
       for(;it_el != end_el; ++it_el)
 	stream << "[" << prank << "/" << psize << "]" << space << "       " << *it_el << std::endl;
       stream << "[" << prank << "/" << psize << "]" << space << "   ]" << std::endl;
 
       stream << "[" << prank << "/" << psize << "]" << space
 	     << "    - Element to recv from proc " << p << " [" << std::endl;
 
       it_el  = recv_element[p].begin();
       end_el = recv_element[p].end();
       for(;it_el != end_el; ++it_el)
 	stream << "[" << prank << "/" << psize << "]"
 	       << space << "       " << *it_el << std::endl;
 
       stream << "[" << prank << "/" << psize << "]" << space << "   ]" << std::endl;
     }
 
     std::map< SynchronizationTag, Communication>::const_iterator it = communications.begin();
     std::map< SynchronizationTag, Communication>::const_iterator end = communications.end();
     for (; it != end; ++it) {
       const SynchronizationTag & tag = it->first;
       const Communication & communication = it->second;
       UInt ssend    = communication.size_to_send[p];
       UInt sreceive = communication.size_to_receive[p];
       stream << "[" << prank << "/" << psize << "]" << space << "     - Tag " << tag << " -> " << ssend << "byte(s) -- <- " << sreceive << "byte(s)" << std::endl;
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::onElementsRemoved(const Array<Element> & element_to_remove,
 						const ElementTypeMapArray<UInt> & new_numbering,
 						__attribute__((unused)) const RemovedElementsEvent & event) {
   AKANTU_DEBUG_IN();
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
   UInt psize = comm.getNbProc();
   UInt prank = comm.whoAmI();
 
   std::vector<CommunicationRequest *> isend_requests;
   Array<UInt> * list_of_el = new Array<UInt>[nb_proc];
   // Handling ghost elements
   for (UInt p = 0; p < psize; ++p) {
     if (p == prank) continue;
 
     Array<Element> & recv = recv_element[p];
     if(recv.getSize() == 0) continue;
 
     Array<Element>::iterator<Element> recv_begin = recv.begin();
     Array<Element>::iterator<Element> recv_end   = recv.end();
 
     Array<Element>::const_iterator<Element> er_it  = element_to_remove.begin();
     Array<Element>::const_iterator<Element> er_end = element_to_remove.end();
 
     Array<UInt> & list = list_of_el[p];
     for (UInt i = 0; recv_begin != recv_end; ++i, ++recv_begin) {
       const Element & el = *recv_begin;
       Array<Element>::const_iterator<Element> pos = std::find(er_it, er_end, el);
       if(pos == er_end) {
 	list.push_back(i);
       }
     }
 
     if(list.getSize() == recv.getSize())
       list.push_back(UInt(0));
     else list.push_back(UInt(-1));
 
     AKANTU_DEBUG_INFO("Sending a message of size " << list.getSize() << " to proc " << p << " TAG(" << Tag::genTag(prank, 0, 0) << ")");
     isend_requests.push_back(comm.asyncSend(list.storage(), list.getSize(),
 					    p, Tag::genTag(prank, 0, 0)));
 
     list.erase(list.getSize() - 1);
     if(list.getSize() == recv.getSize()) continue;
 
     Array<Element> new_recv;
     for (UInt nr = 0; nr < list.getSize(); ++nr) {
       Element & el = recv(list(nr));
       el.element = new_numbering(el.type, el.ghost_type)(el.element);
       new_recv.push_back(el);
     }
 
     AKANTU_DEBUG_INFO("I had " << recv.getSize() << " elements to recv from proc " << p << " and "
 		      << list.getSize() << " elements to keep. I have "
 		      << new_recv.getSize() << " elements left.");
     recv.copy(new_recv);
   }
 
   for (UInt p = 0; p < psize; ++p) {
     if (p == prank) continue;
     Array<Element> & send = send_element[p];
 
     if(send.getSize() == 0) continue;
 
     CommunicationStatus status;
     AKANTU_DEBUG_INFO("Getting number of elements of proc " << p << " not needed anymore TAG("<< Tag::genTag(p, 0, 0) <<")");
     comm.probe<UInt>(p, Tag::genTag(p, 0, 0), status);
     Array<UInt> list(status.getSize());
 
     AKANTU_DEBUG_INFO("Receiving list of elements (" << status.getSize() - 1
 		      << " elements) no longer needed by proc " << p
 		      << " TAG("<< Tag::genTag(p, 0, 0) <<")");
     comm.receive(list.storage(), list.getSize(),
 		 p, Tag::genTag(p, 0, 0));
 
     if(list.getSize() == 1 && list(0) == 0) continue;
 
     list.erase(list.getSize() - 1);
 
     Array<Element> new_send;
     for (UInt ns = 0; ns < list.getSize(); ++ns) {
       new_send.push_back(send(list(ns)));
     }
 
     AKANTU_DEBUG_INFO("I had " << send.getSize() << " elements to send to proc " << p << " and "
 		      << list.getSize() << " elements to keep. I have "
 		      << new_send.getSize() << " elements left.");
     send.copy(new_send);
   }
 
   comm.waitAll(isend_requests);
   comm.freeCommunicationRequest(isend_requests);
 
   delete [] list_of_el;
   AKANTU_DEBUG_OUT();
 }
 
 
 // void DistributedSynchronizer::checkCommunicationScheme() {
 //   for (UInt p = 0; p < psize; ++p) {
 //     if (p == prank) continue;
 //     for(UInt e(0), e < recv_element.getSize())
 //   }
 // }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::buildPrankToElement() {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   mesh.initElementTypeMapArray(prank_to_element,
 			      1,
 			      spatial_dimension,
 			      false,
 			      _ek_not_defined,
 			      true);
 
   Mesh::type_iterator it  = mesh.firstType(spatial_dimension,
 					   _not_ghost,
 					   _ek_not_defined);
 
   Mesh::type_iterator end = mesh.lastType(spatial_dimension,
 					  _not_ghost,
 					  _ek_not_defined);
 
   /// assign prank to all not ghost elements
   for (; it != end; ++it) {
     UInt nb_element = mesh.getNbElement(*it);
     Array<UInt> & prank_to_el = prank_to_element(*it);
     for (UInt el = 0; el < nb_element; ++el) {
       prank_to_el(el) = rank;
     }
   }
 
   /// assign prank to all ghost elements
   for (UInt p = 0; p < nb_proc; ++p) {
     UInt nb_ghost_element = recv_element[p].getSize();
 
     for (UInt el = 0; el < nb_ghost_element; ++el) {
       UInt element = recv_element[p](el).element;
       ElementType type = recv_element[p](el).type;
       GhostType ghost_type = recv_element[p](el).ghost_type;
 
       Array<UInt> & prank_to_el = prank_to_element(type, ghost_type);
       prank_to_el(element) = p;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::filterElementsByKind(DistributedSynchronizer * new_synchronizer,
 						   ElementKind kind) {
   AKANTU_DEBUG_IN();
 
   Array<Element> * newsy_send_element = new_synchronizer->send_element;
   Array<Element> * newsy_recv_element = new_synchronizer->recv_element;
 
   Array<Element> * new_send_element = new Array<Element>[nb_proc];
   Array<Element> * new_recv_element = new Array<Element>[nb_proc];
 
   for (UInt p = 0; p < nb_proc; ++p) {
 
     /// send element copying part
     new_send_element[p].resize(0);
 
     for (UInt el = 0; el < send_element[p].getSize(); ++el) {
       Element & element = send_element[p](el);
 
       if (element.kind == kind)
 	newsy_send_element[p].push_back(element);
       else
 	new_send_element[p].push_back(element);
     }
 
     /// recv element copying part
     new_recv_element[p].resize(0);
 
     for (UInt el = 0; el < recv_element[p].getSize(); ++el) {
       Element & element = recv_element[p](el);
 
       if (element.kind == kind)
 	newsy_recv_element[p].push_back(element);
       else
 	new_recv_element[p].push_back(element);
     }
   }
 
   /// deleting and reassigning old pointers
   delete [] send_element;
   delete [] recv_element;
 
   send_element = new_send_element;
   recv_element = new_recv_element;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::reset() {
   AKANTU_DEBUG_IN();
 
   for (UInt p = 0; p < nb_proc; ++p) {
     send_element[p].resize(0);
     recv_element[p].resize(0);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::synchronizeTagsSend(DistributedSynchronizer & 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) {
   AKANTU_DEBUG_IN();
 
   static UInt count = 0;
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
   UInt nb_proc = comm.getNbProc();
   UInt my_rank = comm.whoAmI();
 
   if(nb_tags == 0) {
     AKANTU_DEBUG_OUT();
     return;
   }
 
   UInt mesh_data_sizes_buffer_length;
   MeshData & mesh_data = mesh.getMeshData();
 
   /// tag info
   std::vector<std::string> tag_names;
   mesh.getMeshData().getTagNames(tag_names, type);
   // Make sure the tags are sorted (or at least not in random order),
   // because they come from a map !!
   std::sort(tag_names.begin(), tag_names.end());
 
 
   // Sending information about the tags in mesh_data: name, data type and
   // number of components of the underlying array associated to the current type
   DynamicCommunicationBuffer mesh_data_sizes_buffer;
   std::vector<std::string>::const_iterator names_it  = tag_names.begin();
   std::vector<std::string>::const_iterator names_end = tag_names.end();
   for(;names_it != names_end; ++names_it) {
     mesh_data_sizes_buffer << *names_it;
     mesh_data_sizes_buffer << mesh_data.getTypeCode(*names_it);
     mesh_data_sizes_buffer << mesh_data.getNbComponent(*names_it, type);
   }
 
   mesh_data_sizes_buffer_length = mesh_data_sizes_buffer.getSize();
   AKANTU_DEBUG_INFO("Broadcasting the size of the information about the mesh data tags: (" << mesh_data_sizes_buffer_length << ")." );
   comm.broadcast(&mesh_data_sizes_buffer_length, 1, root);
   AKANTU_DEBUG_INFO("Broadcasting the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage());
 
   if(mesh_data_sizes_buffer_length !=0)
     comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer.getSize(), root);
 
 
   if(mesh_data_sizes_buffer_length !=0) {
     //Sending the actual data to each processor
     DynamicCommunicationBuffer buffers[nb_proc];
     std::vector<std::string>::const_iterator names_it  = tag_names.begin();
     std::vector<std::string>::const_iterator names_end = tag_names.end();
 
     // Loop over each tag for the current type
     for(;names_it != names_end; ++names_it) {
       // Type code of the current tag (i.e. the tag named *names_it)
       communicator.fillTagBuffer(mesh_data,
 				 buffers,
 				 *names_it,
 				 type,
 				 partition_num,
 				 ghost_partition);
     }
 
     std::vector<CommunicationRequest *> requests;
     for (UInt p = 0; p < nb_proc; ++p) {
       if(p != root) {
 	AKANTU_DEBUG_INFO("Sending " << buffers[p].getSize() << " bytes of mesh data to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_MESH_DATA) <<")");
 
 	requests.push_back(comm.asyncSend(buffers[p].storage(),
 					  buffers[p].getSize(), p, Tag::genTag(my_rank, count, TAG_MESH_DATA)));
       }
     }
 
     names_it  = tag_names.begin();
     // Loop over each tag for the current type
     for(;names_it != names_end; ++names_it) {
       // Reinitializing the mesh data on the master
       communicator.populateMeshData(mesh_data,
 				    buffers[root],
 				    *names_it,
 				    type,
 				    mesh_data.getTypeCode(*names_it),
 				    mesh_data.getNbComponent(*names_it, type),
 				    nb_local_element,
 				    nb_ghost_element);
     }
 
 
     comm.waitAll(requests);
     comm.freeCommunicationRequest(requests);
     requests.clear();
   }
 
   ++count;
 
   AKANTU_DEBUG_OUT();
 }
 
 
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::synchronizeTagsRecv(DistributedSynchronizer & communicator,
 						  UInt root,
 						  Mesh & mesh,
 						  UInt nb_tags,
 						  const ElementType & type,
 						  UInt nb_local_element,
 						  UInt nb_ghost_element) {
   AKANTU_DEBUG_IN();
 
   static UInt count = 0;
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
 
   if(nb_tags == 0) {
     AKANTU_DEBUG_OUT();
     return;
   }
 
   /* --------<<<<-TAGS------------------------------------------------- */
   UInt mesh_data_sizes_buffer_length = 0;
   CommunicationBuffer mesh_data_sizes_buffer;
   MeshData & mesh_data = mesh.getMeshData();
 
   AKANTU_DEBUG_INFO("Receiving the size of the information about the mesh data tags.");
   comm.broadcast(&mesh_data_sizes_buffer_length, 1, root);
 
   if(mesh_data_sizes_buffer_length != 0) {
     mesh_data_sizes_buffer.resize(mesh_data_sizes_buffer_length);
     AKANTU_DEBUG_INFO("Receiving the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage());
     comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer_length, root);
     AKANTU_DEBUG_INFO("Size of the information about the mesh data: " << mesh_data_sizes_buffer_length);
 
     std::vector<std::string> tag_names;
     std::vector<MeshDataTypeCode> tag_type_codes;
     std::vector<UInt> tag_nb_component;
     tag_names.resize(nb_tags);
     tag_type_codes.resize(nb_tags);
     tag_nb_component.resize(nb_tags);
     CommunicationBuffer mesh_data_buffer;
     UInt type_code_int;
     for(UInt i(0); i < nb_tags; ++i) {
       mesh_data_sizes_buffer >> tag_names[i];
       mesh_data_sizes_buffer >> type_code_int;
       tag_type_codes[i] = static_cast<MeshDataTypeCode>(type_code_int);
       mesh_data_sizes_buffer >> tag_nb_component[i];
     }
 
     std::vector<std::string>::const_iterator names_it  = tag_names.begin();
     std::vector<std::string>::const_iterator names_end = tag_names.end();
 
     CommunicationStatus mesh_data_comm_status;
     AKANTU_DEBUG_INFO("Checking size of data to receive for mesh data TAG("
 		      << Tag::genTag(root, count, TAG_MESH_DATA) << ")");
     comm.probe<char>(root, Tag::genTag(root, count, TAG_MESH_DATA), mesh_data_comm_status);
     UInt mesh_data_buffer_size(mesh_data_comm_status.getSize());
     AKANTU_DEBUG_INFO("Receiving " << mesh_data_buffer_size
 		      << " bytes of mesh data TAG("
 		      << Tag::genTag(root, count, TAG_MESH_DATA) << ")");
     mesh_data_buffer.resize(mesh_data_buffer_size);
     comm.receive(mesh_data_buffer.storage(),
 		 mesh_data_buffer_size,
 		 root,
 		 Tag::genTag(root, count, TAG_MESH_DATA));
 
     // Loop over each tag for the current type
     UInt k(0);
     for(; names_it != names_end; ++names_it, ++k) {
       communicator.populateMeshData(mesh_data, mesh_data_buffer,
 				    *names_it, type,
 				    tag_type_codes[k],
 				    tag_nb_component[k],
 				    nb_local_element, nb_ghost_element);
     }
   }
 
   ++count;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template<class CommunicationBuffer>
 void DistributedSynchronizer::fillElementGroupsFromBuffer(DistributedSynchronizer & communicator,
 							  Mesh & mesh,
 							  const ElementType & type,
 							  CommunicationBuffer & buffer) {
   AKANTU_DEBUG_IN();
 
   Element el;
   el.type = type;
 
   for (ghost_type_t::iterator gt = ghost_type_t::begin();  gt != ghost_type_t::end(); ++gt) {
     UInt nb_element = mesh.getNbElement(type, *gt);
     el.ghost_type = *gt;
 
     for (UInt e = 0; e < nb_element; ++e) {
       el.element = e;
 
       std::vector<std::string> element_to_group;
       buffer >> element_to_group;
 
       AKANTU_DEBUG_ASSERT(e < mesh.getNbElement(type, *gt), "The mesh does not have the element " << e);
 
       std::vector<std::string>::iterator it  = element_to_group.begin();
       std::vector<std::string>::iterator end = element_to_group.end();
       for (; it != end; ++it) {
 	mesh.getElementGroup(*it).add(el, false, false);
       }
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::synchronizeElementGroups(DistributedSynchronizer & communicator,
 						       UInt root,
 						       Mesh & mesh,
 						       const ElementType & type,
 						       const Array<UInt> & partition_num,
 						       const CSR<UInt> & ghost_partition,
 						       UInt nb_element) {
   AKANTU_DEBUG_IN();
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
 
   UInt nb_proc = comm.getNbProc();
   UInt my_rank = comm.whoAmI();
 
   DynamicCommunicationBuffer buffers[nb_proc];
 
   typedef std::vector< std::vector<std::string> > ElementToGroup;
   ElementToGroup element_to_group;
   element_to_group.resize(nb_element);
 
   GroupManager::const_element_group_iterator egi = mesh.element_group_begin();
   GroupManager::const_element_group_iterator ege = mesh.element_group_end();
   for (; egi != ege; ++egi) {
     ElementGroup & eg = *(egi->second);
 
     std::string name = egi->first;
 
     ElementGroup::const_element_iterator eit  = eg.element_begin(type, _not_ghost);
     ElementGroup::const_element_iterator eend = eg.element_end(type, _not_ghost);
     for (; eit != eend; ++eit) {
       element_to_group[*eit].push_back(name);
     }
 
     eit  = eg.element_begin(type, _not_ghost);
     if(eit != eend)
       const_cast<Array<UInt> &>(eg.getElements(type)).empty();
   }
 
   /// preparing the buffers
   const UInt * part = partition_num.storage();
 
   /// copying the data, element by element
   ElementToGroup::const_iterator data_it  = element_to_group.begin();
   ElementToGroup::const_iterator data_end = element_to_group.end();
   for (; data_it != data_end; ++part, ++data_it) {
     buffers[*part] << *data_it;
   }
 
   data_it = element_to_group.begin();
   /// copying the data for the ghost element
   for (UInt el(0); data_it != data_end; ++data_it, ++el) {
     CSR<UInt>::const_iterator it  = ghost_partition.begin(el);
     CSR<UInt>::const_iterator end = ghost_partition.end(el);
     for (;it != end; ++it) {
       UInt proc = *it;
       buffers[proc] << *data_it;
     }
   }
 
 
   std::vector<CommunicationRequest *> requests;
   for (UInt p = 0; p < nb_proc; ++p) {
     if(p == my_rank) continue;
     AKANTU_DEBUG_INFO("Sending element groups to proc " << p
 		      << " TAG("<< Tag::genTag(my_rank, p, TAG_ELEMENT_GROUP) <<")");
     requests.push_back(comm.asyncSend(buffers[p].storage(),
 				      buffers[p].getSize(),
 				      p,
 				      Tag::genTag(my_rank, p, TAG_ELEMENT_GROUP)));
   }
 
   fillElementGroupsFromBuffer(communicator, mesh, type, buffers[my_rank]);
 
   comm.waitAll(requests);
   comm.freeCommunicationRequest(requests);
   requests.clear();
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::synchronizeElementGroups(DistributedSynchronizer & communicator,
 						       UInt root,
 						       Mesh & mesh,
 						       const ElementType & type) {
   AKANTU_DEBUG_IN();
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
   UInt my_rank = comm.whoAmI();
 
 
   AKANTU_DEBUG_INFO("Receiving element groups from proc " << root
 		    << " TAG("<< Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP) <<")");
 
   CommunicationStatus status;
   comm.probe<char>(root, Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP), status);
 
   CommunicationBuffer buffer(status.getSize());
   comm.receive(buffer.storage(), buffer.getSize(), root, Tag::genTag(root, my_rank, TAG_ELEMENT_GROUP));
 
   fillElementGroupsFromBuffer(communicator, mesh, type, buffer);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template<class CommunicationBuffer>
 void DistributedSynchronizer::fillNodeGroupsFromBuffer(DistributedSynchronizer & communicator,
 						       Mesh & mesh,
 						       CommunicationBuffer & buffer) {
   AKANTU_DEBUG_IN();
 
   std::vector< std::vector<std::string> > node_to_group;
 
   buffer >> node_to_group;
 
   AKANTU_DEBUG_ASSERT(node_to_group.size() == mesh.getNbGlobalNodes(),
 		      "Not the good amount of nodes where transmitted");
 
   const Array<UInt> & global_nodes = mesh.getGlobalNodesIds();
 
   Array<UInt>::const_scalar_iterator nbegin = global_nodes.begin();
   Array<UInt>::const_scalar_iterator nit    = global_nodes.begin();
   Array<UInt>::const_scalar_iterator nend   = global_nodes.end();
 
   for (; nit != nend; ++nit) {
     std::vector<std::string>::iterator it    = node_to_group[*nit].begin();
     std::vector<std::string>::iterator end   = node_to_group[*nit].end();
 
     for (; it != end; ++it) {
       mesh.getNodeGroup(*it).add(nit - nbegin, false);
     }
   }
 
   GroupManager::const_node_group_iterator ngi = mesh.node_group_begin();
   GroupManager::const_node_group_iterator nge = mesh.node_group_end();
   for (; ngi != nge; ++ngi) {
     NodeGroup & ng = *(ngi->second);
     ng.optimize();
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::synchronizeNodeGroupsMaster(DistributedSynchronizer & communicator,
 							  UInt root,
 							  Mesh & mesh) {
   AKANTU_DEBUG_IN();
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
 
   UInt nb_proc = comm.getNbProc();
   UInt my_rank = comm.whoAmI();
 
   UInt nb_total_nodes = mesh.getNbGlobalNodes();
 
   DynamicCommunicationBuffer buffer;
 
   typedef std::vector< std::vector<std::string> > NodeToGroup;
   NodeToGroup node_to_group;
   node_to_group.resize(nb_total_nodes);
 
   GroupManager::const_node_group_iterator ngi = mesh.node_group_begin();
   GroupManager::const_node_group_iterator nge = mesh.node_group_end();
   for (; ngi != nge; ++ngi) {
     NodeGroup & ng = *(ngi->second);
 
     std::string name = ngi->first;
 
     NodeGroup::const_node_iterator nit  = ng.begin();
     NodeGroup::const_node_iterator nend = ng.end();
     for (; nit != nend; ++nit) {
       node_to_group[*nit].push_back(name);
     }
 
     nit  = ng.begin();
     if(nit != nend)
       ng.empty();
   }
 
   buffer << node_to_group;
 
   std::vector<CommunicationRequest *> requests;
   for (UInt p = 0; p < nb_proc; ++p) {
     if(p == my_rank) continue;
     AKANTU_DEBUG_INFO("Sending node groups to proc " << p
 		      << " TAG("<< Tag::genTag(my_rank, p, TAG_NODE_GROUP) <<")");
     requests.push_back(comm.asyncSend(buffer.storage(),
 				      buffer.getSize(),
 				      p,
 				      Tag::genTag(my_rank, p, TAG_NODE_GROUP)));
   }
 
   fillNodeGroupsFromBuffer(communicator, mesh, buffer);
 
   comm.waitAll(requests);
   comm.freeCommunicationRequest(requests);
   requests.clear();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DistributedSynchronizer::synchronizeNodeGroupsSlaves(DistributedSynchronizer & communicator,
 							  UInt root,
 							  Mesh & mesh) {
   AKANTU_DEBUG_IN();
 
   StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator();
   UInt my_rank = comm.whoAmI();
 
 
   AKANTU_DEBUG_INFO("Receiving node groups from proc " << root
 		    << " TAG("<< Tag::genTag(root, my_rank, TAG_NODE_GROUP) <<")");
 
   CommunicationStatus status;
   comm.probe<char>(root, Tag::genTag(root, my_rank, TAG_NODE_GROUP), status);
 
   CommunicationBuffer buffer(status.getSize());
   comm.receive(buffer.storage(), buffer.getSize(), root, Tag::genTag(root, my_rank, TAG_NODE_GROUP));
 
   fillNodeGroupsFromBuffer(communicator, mesh, buffer);
 
   AKANTU_DEBUG_OUT();
 }
 
 __END_AKANTU__
diff --git a/src/synchronizer/distributed_synchronizer.hh b/src/synchronizer/distributed_synchronizer.hh
index 64976adad..2edd12ab1 100644
--- a/src/synchronizer/distributed_synchronizer.hh
+++ b/src/synchronizer/distributed_synchronizer.hh
@@ -1,293 +1,268 @@
 /**
  * @file   distributed_synchronizer.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Dana Christen <dana.christen@epfl.ch>
  * @author Marco Vocialta <marco.vocialta@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Thu Jun 16 2011
  * @date last modification: Fri Sep 05 2014
  *
  * @brief  wrapper to the static communicator
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_DISTRIBUTED_SYNCHRONIZER_HH__
 #define __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "aka_array.hh"
-#include "static_communicator.hh"
 #include "synchronizer.hh"
 #include "mesh.hh"
 #include "mesh_partition.hh"
 #include "communication_buffer.hh"
 
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_AKANTU__
 
 class DistributedSynchronizer : public Synchronizer, public MeshEventHandler {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   DistributedSynchronizer(Mesh & mesh,
                           SynchronizerID id = "distributed_synchronizer",
                           MemoryID memory_id = 0);
 
 public:
   virtual ~DistributedSynchronizer();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// get a  mesh and a partition and  create the local mesh  and the associated
   /// DistributedSynchronizer
   static DistributedSynchronizer *
   createDistributedSynchronizerMesh(Mesh & mesh,
                                     const MeshPartition * partition,
                                     UInt root = 0,
                                     SynchronizerID id = "distributed_synchronizer",
                                     MemoryID memory_id = 0);
 
   /* ------------------------------------------------------------------------ */
   /* Inherited from Synchronizer                                              */
   /* ------------------------------------------------------------------------ */
 
   /// asynchronous synchronization of ghosts
   void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag);
 
   /// wait end of asynchronous synchronization of ghosts
   void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag);
 
   /// build processor to element corrispondance
   void buildPrankToElement();
 
   virtual void printself(std::ostream & stream, int indent = 0) const;
 
   /// mesh event handler onRemovedElement
   virtual void onElementsRemoved(const Array<Element> & element_list,
                                  const ElementTypeMapArray<UInt> & new_numbering,
                                  const RemovedElementsEvent & event);
 
   /// filter elements of a certain kind and copy them into a new synchronizer
   void filterElementsByKind(DistributedSynchronizer * new_synchronizer,
 			    ElementKind kind);
 
   /// reset send and recv element lists
   void reset();
 
   /// compute buffer size for a given tag and data accessor
   void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag);
 
 protected:
   /// fill the nodes type vector
   void fillNodesType(Mesh & mesh);
 
   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);
 
   template<typename T, typename BufferType>
   void populateMeshDataTemplated(MeshData & mesh_data,
                                  BufferType & buffer,
                                  const std::string & tag_name,
                                  const ElementType & el_type,
                                  UInt nb_component,
                                  UInt nb_local_element,
                                  UInt nb_ghost_element);
 
   template <typename BufferType>
   void populateMeshData(MeshData & mesh_data,
                         BufferType & buffer,
                         const std::string & tag_name,
                         const ElementType & el_type,
                         const MeshDataTypeCode & type_code,
                         UInt nb_component,
                         UInt nb_local_element,
                         UInt nb_ghost_element);
 
   /// fill the communications array of a distributedSynchronizer based on a partition array
   void fillCommunicationScheme(const UInt * partition,
                                UInt nb_local_element,
                                UInt nb_ghost_element,
                                ElementType type);
 
   /// function that handels the MeshData to be split (root side)
   static void synchronizeTagsSend(DistributedSynchronizer & 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(DistributedSynchronizer & 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(DistributedSynchronizer & 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(DistributedSynchronizer & communicator,
 				       UInt root,
 				       Mesh & mesh,
 				       const ElementType & type);
 
   template<class CommunicationBuffer>
   static void fillElementGroupsFromBuffer(DistributedSynchronizer & communicator,
 					  Mesh & mesh,
 					  const ElementType & type,
 					  CommunicationBuffer & buffer);
 
   /// function that handles the preexisting groups in the mesh
   static void synchronizeNodeGroupsMaster(DistributedSynchronizer & communicator,
 					  UInt root,
 					  Mesh & mesh);
 
 
   /// function that handles the preexisting groups in the mesh
   static void synchronizeNodeGroupsSlaves(DistributedSynchronizer & communicator,
 					  UInt root,
 					  Mesh & mesh);
 
   template<class CommunicationBuffer>
   static void fillNodeGroupsFromBuffer(DistributedSynchronizer & communicator,
 					  Mesh & mesh,
 					  CommunicationBuffer & buffer);
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
 
   AKANTU_GET_MACRO(PrankToElement, prank_to_element, const ElementTypeMapArray<UInt> &);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
   enum CommTags {
     TAG_SIZES        = 0,
     TAG_CONNECTIVITY = 1,
     TAG_DATA         = 2,
     TAG_PARTITIONS   = 3,
     TAG_NB_NODES     = 4,
     TAG_NODES        = 5,
     TAG_COORDINATES  = 6,
     TAG_NODES_TYPE   = 7,
     TAG_MESH_DATA    = 8,
     TAG_ELEMENT_GROUP = 9,
     TAG_NODE_GROUP = 10,
   };
 
 protected:
   /// reference to the underlying mesh
   Mesh & mesh;
 
-  /// the static memory instance
-  StaticCommunicator * static_communicator;
-
-  class Communication {
-  public:
-    void resize(UInt size) {
-      send_buffer.resize(size);
-      recv_buffer.resize(size);
-      size_to_send   .resize(size);
-      size_to_receive.resize(size);
-    }
-
-  public:
-    /// size of data to send to each processor
-    std::vector<UInt> size_to_send;
-    /// size of data to recv to each processor
-    std::vector<UInt> size_to_receive;
-    std::vector< CommunicationBuffer > send_buffer;
-    std::vector< CommunicationBuffer > recv_buffer;
-
-    std::vector<CommunicationRequest *> send_requests;
-    std::vector<CommunicationRequest *> recv_requests;
-  };
-
   std::map<SynchronizationTag, Communication> communications;
 
   /// list of element to send to proc p
   Array<Element> * send_element;
   /// list of element to receive from proc p
   Array<Element> * recv_element;
 
   UInt nb_proc;
   UInt rank;
 
   friend class FilteredSynchronizer;
   friend class FacetSynchronizer;
 
   ElementTypeMapArray<UInt> prank_to_element;
 
 };
 
 __END_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 #include "distributed_synchronizer_tmpl.hh"
 
 
 #endif /* __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ */
diff --git a/src/synchronizer/dof_synchronizer.cc b/src/synchronizer/dof_synchronizer.cc
index d15d02d0a..4b986fe97 100644
--- a/src/synchronizer/dof_synchronizer.cc
+++ b/src/synchronizer/dof_synchronizer.cc
@@ -1,258 +1,501 @@
 /**
  * @file   dof_synchronizer.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @date creation: Fri Jun 17 2011
  * @date last modification: Thu Mar 27 2014
  *
  * @brief  DOF synchronizing object implementation
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as  published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "dof_synchronizer.hh"
 #include "mesh.hh"
 
 /* -------------------------------------------------------------------------- */
 
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
+/**
+ * A DOFSynchronizer needs a mesh and the number of degrees of freedom
+ * per node to be created. In the constructor computes the local and global dof
+ * number for each dof. The member
+ * proc_informations (std vector) is resized with the number of mpi
+ * processes. Each entry in the vector is a PerProcInformations object
+ * that contains the interactions of the current mpi process (prank) with the
+ * mpi process corresponding to the position of that entry. Every
+ * ProcInformations object contains one array with the dofs that have
+ * to be sent to prank and a second one with dofs that willl be received form prank.
+ * This information is needed for the asychronous communications. The
+ * constructor sets up this information.   
+ * @param mesh mesh discretizing the domain we want to analyze 
+ * @param nb_degree_of_freedom number of degrees of freedom per node
+ */
 DOFSynchronizer::DOFSynchronizer(const Mesh & mesh, UInt nb_degree_of_freedom) :
   global_dof_equation_numbers(0, 1, "global_equation_number"),
   local_dof_equation_numbers(0, 1, "local_equation_number"),
   dof_global_ids(0, 1, "global_ids"),
   dof_types(0, 1, "types") {
-  gather_scatter_scheme_initialized = false;
 
-  communicator = &StaticCommunicator::getStaticCommunicator();
+  gather_scatter_scheme_initialized = false;
 
-  prank = communicator->whoAmI();
-  psize = communicator->getNbProc();
+  prank = static_communicator->whoAmI();
+  psize = static_communicator->getNbProc();
 
   proc_informations.resize(psize);
 
   UInt nb_nodes = mesh.getNbNodes();
 
   nb_dofs = nb_nodes * nb_degree_of_freedom;
 
   dof_global_ids.resize(nb_dofs);
   dof_types.resize(nb_dofs);
 
   nb_global_dofs = mesh.getNbGlobalNodes() * nb_degree_of_freedom;
 
+  /// compute the global id for each dof and store the dof type (pure ghost, slave, master or local)
   UInt * dof_global_id       = dof_global_ids.storage();
   Int  * dof_type            = dof_types.storage();
   for(UInt n = 0, ld = 0; n < nb_nodes; ++n) {
     UInt node_global_id = mesh.getNodeGlobalId(n);
     UInt node_type      = mesh.getNodeType(n);
     for (UInt d = 0; d < nb_degree_of_freedom; ++d, ++ld) {
       *dof_global_id = node_global_id * nb_degree_of_freedom + d;
       global_dof_to_local[*dof_global_id] = ld;
 
       *(dof_type++)  = node_type;
 
       dof_global_id++;
     }
   }
 
   if(psize == 1) return;
 
   /// creating communication scheme
   dof_global_id  = dof_global_ids.storage();
   dof_type       = dof_types.storage();
 
   for (UInt n = 0; n < nb_dofs; ++n) {
+    /// check if dof is slave. In that case the value stored in
+    /// dof_type corresponds to the process that has the corresponding
+    /// master dof
     if(*dof_type >= 0) {
+      /// has to receive n from proc[*dof_type]
       proc_informations[*dof_type].master_dofs.push_back(n);
     }
     dof_type++;
   }
 
+  /// at this point the master nodes in PerProcInfo are known
   /// exchanging information
   for (UInt p = 1; p < psize; ++p) {
     UInt sendto   = (psize + prank + p) % psize;
     UInt recvfrom = (psize + prank - p) % psize;
 
+    /// send the master nodes
     UInt nb_master_dofs = proc_informations[sendto].master_dofs.getSize();
     UInt * master_dofs = proc_informations[sendto].master_dofs.storage();
     UInt * send_buffer = new UInt[nb_master_dofs];
     for (UInt d = 0; d < nb_master_dofs; ++d) {
       send_buffer[d] = dof_global_id[master_dofs[d]];
     }
 
     UInt nb_slave_dofs = 0;
     UInt * recv_buffer;
     std::vector<CommunicationRequest *> requests;
-    requests.push_back(communicator->asyncSend(&nb_master_dofs, 1, sendto, 0));
+    requests.push_back(static_communicator->asyncSend(&nb_master_dofs, 1, sendto, 0));
     if(nb_master_dofs != 0) {
-      AKANTU_DEBUG(dblInfo, "Sending "<< nb_master_dofs << " nodes to " << sendto + 1);
-      requests.push_back(communicator->asyncSend(send_buffer, nb_master_dofs, sendto, 1));
+      AKANTU_DEBUG(dblInfo, "Sending "<< nb_master_dofs << " dofs to " << sendto + 1);
+      requests.push_back(static_communicator->asyncSend(send_buffer, nb_master_dofs, sendto, 1));
     }
-    communicator->receive(&nb_slave_dofs, 1, recvfrom, 0);
+
+    /// Receive the info and store them as slave nodes 
+    static_communicator->receive(&nb_slave_dofs, 1, recvfrom, 0);
     if(nb_slave_dofs != 0) {
-      AKANTU_DEBUG(dblInfo, "Receiving "<< nb_slave_dofs << " nodes from " << recvfrom + 1);
+      AKANTU_DEBUG(dblInfo, "Receiving "<< nb_slave_dofs << " dofs from " << recvfrom + 1);
       proc_informations[recvfrom].slave_dofs.resize(nb_slave_dofs);
       recv_buffer = proc_informations[recvfrom].slave_dofs.storage();
-      communicator->receive(recv_buffer, nb_slave_dofs, recvfrom, 1);
+      static_communicator->receive(recv_buffer, nb_slave_dofs, recvfrom, 1);
     }
 
     for (UInt d = 0; d < nb_slave_dofs; ++d) {
       recv_buffer[d] = global_dof_to_local[recv_buffer[d]];
     }
 
-    communicator->waitAll(requests);
-    communicator->freeCommunicationRequest(requests);
+    static_communicator->waitAll(requests);
+    static_communicator->freeCommunicationRequest(requests);
     requests.clear();
     delete [] send_buffer;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 DOFSynchronizer::~DOFSynchronizer() {
 
 }
 
 
 /* -------------------------------------------------------------------------- */
 void DOFSynchronizer::initLocalDOFEquationNumbers() {
   AKANTU_DEBUG_IN();
   local_dof_equation_numbers.resize(nb_dofs);
 
   Int  * dof_equation_number = local_dof_equation_numbers.storage();
   for (UInt d = 0; d < nb_dofs; ++d) {
     *(dof_equation_number++) = d;
   }
 
   //local_dof_equation_numbers.resize(nb_dofs);
   AKANTU_DEBUG_OUT();
 }
 
+/* -------------------------------------------------------------------------- */
+void DOFSynchronizer::asynchronousSynchronize(DataAccessor & data_accessor,
+					      SynchronizationTag tag) {
+  AKANTU_DEBUG_IN();
+
+  if (communications.find(tag) == communications.end())
+    computeBufferSize(data_accessor, tag);
+
+  Communication & communication = communications[tag];
+
+  AKANTU_DEBUG_ASSERT(communication.send_requests.size() == 0,
+		      "There must be some pending sending communications. Tag is " << tag);
+
+  std::map<SynchronizationTag, UInt>::iterator t_it = tag_counter.find(tag);
+  UInt counter = 0;
+  if(t_it == tag_counter.end()) {
+    tag_counter[tag] = 0;
+  } else {
+    counter = ++(t_it->second);
+  }
+
+  for (UInt p = 0; p < psize; ++p) {
+    UInt ssize = communication.size_to_send[p];
+    if(p == prank || ssize == 0) continue;
+
+    CommunicationBuffer & buffer = communication.send_buffer[p];
+    buffer.resize(ssize);
+#ifndef AKANTU_NDEBUG
+    UInt nb_dofs   =  proc_informations[p].slave_dofs.getSize();
+    AKANTU_DEBUG_INFO("Packing data for proc " << p
+		      << " (" << ssize << "/" << nb_dofs
+		      <<" data to send/dofs)");
+
+    /// pack global equation numbers in debug mode
+    Array<UInt>::const_iterator<UInt> bit  = proc_informations[p].slave_dofs.begin();
+    Array<UInt>::const_iterator<UInt> bend = proc_informations[p].slave_dofs.end();
+    for (; bit != bend; ++bit) {
+      buffer << global_dof_equation_numbers[*bit];
+    }
+#endif
+
+
+    /// dof synchronizer needs to send the data corresponding to the 
+    data_accessor.packDOFData(buffer, proc_informations[p].slave_dofs, tag);
+
+    AKANTU_DEBUG_ASSERT(buffer.getPackedSize() == ssize,
+			"a problem has been introduced with "
+			<< "false sent sizes declaration "
+			<< buffer.getPackedSize() << " != " << ssize);
+    AKANTU_DEBUG_INFO("Posting send to proc " << p
+		      << " (tag: " << tag << " - " << ssize << " data to send)"
+		      << " [" << Tag::genTag(prank, counter, tag) << "]");
+    communication.send_requests.push_back(static_communicator->asyncSend(buffer.storage(),
+									 ssize,
+									 p,
+									 Tag::genTag(prank, counter, tag)));
+  }
+
+  AKANTU_DEBUG_ASSERT(communication.recv_requests.size() == 0,
+		      "There must be some pending receive communications");
+
+  for (UInt p = 0; p < psize; ++p) {
+    UInt rsize = communication.size_to_receive[p];
+    if(p == prank || rsize == 0) continue;
+    CommunicationBuffer & buffer = communication.recv_buffer[p];
+    buffer.resize(rsize);
+
+    AKANTU_DEBUG_INFO("Posting receive from proc " << p
+		      << " (tag: " << tag << " - " << rsize << " data to receive) "
+		      << " [" << Tag::genTag(p, counter, tag) << "]");
+    communication.recv_requests.push_back(static_communicator->asyncReceive(buffer.storage(),
+									    rsize,
+									    p,
+									    Tag::genTag(p, counter, tag)));
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void DOFSynchronizer::waitEndSynchronize(DataAccessor & data_accessor,
+					 SynchronizationTag tag) {
+  AKANTU_DEBUG_IN();
+
+  AKANTU_DEBUG_ASSERT(communications.find(tag) != communications.end(), "No communication with the tag \""
+		      << tag <<"\" started");
+
+  Communication & communication = communications[tag];
+
+  std::vector<CommunicationRequest *> req_not_finished;
+  std::vector<CommunicationRequest *> * req_not_finished_tmp = &req_not_finished;
+  std::vector<CommunicationRequest *> * recv_requests_tmp = &(communication.recv_requests);
+
+  //  static_communicator->waitAll(recv_requests);
+  while(!recv_requests_tmp->empty()) {
+    for (std::vector<CommunicationRequest *>::iterator req_it = recv_requests_tmp->begin();
+	 req_it != recv_requests_tmp->end() ; ++req_it) {
+      CommunicationRequest * req = *req_it;
+
+      if(static_communicator->testRequest(req)) {
+	UInt proc = req->getSource();
+	AKANTU_DEBUG_INFO("Unpacking data coming from proc " << proc);
+	CommunicationBuffer & buffer = communication.recv_buffer[proc];
+
+#ifndef AKANTU_NDEBUG
+	Array<UInt>::const_iterator<UInt> bit  = proc_informations[proc].master_dofs.begin();
+	Array<UInt>::const_iterator<UInt> bend = proc_informations[proc].master_dofs.end();
+
+	for (; bit != bend; ++bit) {
+	  Int global_dof_eq_nb_loc = global_dof_equation_numbers[*bit];
+	  Int global_dof_eq_nb = 0;
+	  buffer >> global_dof_eq_nb;
+	  Real tolerance = Math::getTolerance();
+	  if(std::abs(global_dof_eq_nb - global_dof_eq_nb_loc) <= tolerance) continue;
+	  AKANTU_DEBUG_ERROR("Unpacking an unknown global dof equation number for dof: "
+			     << *bit
+			     << "(global dof equation number = " << global_dof_eq_nb
+			     << " and buffer = " << global_dof_eq_nb << ") ["
+			     << std::abs(global_dof_eq_nb - global_dof_eq_nb_loc)
+			     << "] - tag: " << tag);
+	}
+	
+#endif
+
+	data_accessor.unpackDOFData(buffer, proc_informations[proc].master_dofs, tag);
+	buffer.resize(0);
+
+	AKANTU_DEBUG_ASSERT(buffer.getLeftToUnpack() == 0,
+			    "all data have not been unpacked: "
+			    << buffer.getLeftToUnpack() << " bytes left");
+	static_communicator->freeCommunicationRequest(req);
+      } else {
+	req_not_finished_tmp->push_back(req);
+      }
+    }
+
+    std::vector<CommunicationRequest *> * swap = req_not_finished_tmp;
+    req_not_finished_tmp = recv_requests_tmp;
+    recv_requests_tmp = swap;
+
+    req_not_finished_tmp->clear();
+  }
+
+
+  AKANTU_DEBUG_INFO("Waiting that every send requests are received");
+  static_communicator->waitAll(communication.send_requests);
+  for (std::vector<CommunicationRequest *>::iterator req_it = communication.send_requests.begin();
+       req_it != communication.send_requests.end() ; ++req_it) {
+    CommunicationRequest & req = *(*req_it);
+
+    if(static_communicator->testRequest(&req)) {
+      UInt proc = req.getDestination();
+      CommunicationBuffer & buffer = communication.send_buffer[proc];
+      buffer.resize(0);
+      static_communicator->freeCommunicationRequest(&req);
+    }
+  }
+  communication.send_requests.clear();
+
+  AKANTU_DEBUG_OUT();				
+
+
+}
+
+/* -------------------------------------------------------------------------- */
+/**
+ * This function computes the buffer size needed for in order to send data or receive data. 
+ * @param data_accessor object of a class that needs to use the DOFSynchronizer. This class has to inherit from the  * DataAccessor interface.
+ * @param tag synchronization tag: indicates what variable should be sychronized, e.g. mass, nodal residual, etc. 
+ * for the SolidMechanicsModel
+ */
+void DOFSynchronizer::computeBufferSize(DataAccessor & data_accessor,
+					SynchronizationTag tag) {
+  AKANTU_DEBUG_IN();
+
+  communications[tag].resize(psize);
+
+  for (UInt p = 0; p < psize; ++p) {
+    /// initialize the size of data that we be sent and received
+    UInt ssend    = 0;
+    UInt sreceive = 0;
+    if(p != prank) {
+      /// check if processor prank has to send dof information to p
+      if(proc_informations[p].slave_dofs.getSize() != 0) {
+
+       
+#ifndef AKANTU_NDEBUG
+	/// in debug mode increase buffer size to send the positions
+	/// of nodes in the direction that correspond to the dofs
+	ssend += proc_informations[p].slave_dofs.getSize() * sizeof(Int);
+#endif
+	ssend += data_accessor.getNbDataForDOFs(proc_informations[p].slave_dofs, tag);
+	AKANTU_DEBUG_INFO("I have " << ssend << "(" << ssend / 1024.
+			  << "kB - "<< proc_informations[p].slave_dofs.getSize() <<" dof(s)) data to send to " << p << " for tag "
+			  << tag);
+      }
+
+      /// check if processor prank has to receive dof information from p
+      if(proc_informations[p].master_dofs.getSize() != 0) {
+#ifndef AKANTU_NDEBUG
+	/// in debug mode increase buffer size to receive the
+	/// positions of nodes in the direction that correspond to the
+	/// dofs
+	sreceive += proc_informations[p].master_dofs.getSize() * sizeof(Int);
+#endif
+	sreceive += data_accessor.getNbDataForDOFs(proc_informations[p].master_dofs, tag);
+	AKANTU_DEBUG_INFO("I have " << sreceive << "(" << sreceive / 1024.
+			  << "kB - "<< proc_informations[p].master_dofs.getSize() <<" dof(s)) data to receive for tag "
+			  << tag);
+      }
+    }
+
+    communications[tag].size_to_send   [p] = ssend;
+    communications[tag].size_to_receive[p] = sreceive;
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
 /* -------------------------------------------------------------------------- */
 void DOFSynchronizer::initGlobalDOFEquationNumbers() {
   AKANTU_DEBUG_IN();
   global_dof_equation_numbers.resize(nb_dofs);
 
   Int  * dof_type            = dof_types.storage();
   UInt * dof_global_id       = dof_global_ids.storage();
   Int  * dof_equation_number = global_dof_equation_numbers.storage();
   for(UInt d = 0; d < nb_dofs; ++d) {
     /// if ghost dof the equation_number is greater than nb_global_dofs
     Int global_eq_num = *dof_global_id + (*dof_type > -3 ? 0 : nb_global_dofs);
     *(dof_equation_number)  = global_eq_num;
     global_dof_equation_number_to_local[global_eq_num] = d;
 
     dof_equation_number++;
     dof_global_id++;
     dof_type++;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 void DOFSynchronizer::initScatterGatherCommunicationScheme() {
   AKANTU_DEBUG_IN();
 
   if(psize == 1 || gather_scatter_scheme_initialized) {
     if(psize == 1) gather_scatter_scheme_initialized = true;
     AKANTU_DEBUG_OUT();
     return;
   }
 
   /// creating communication scheme
   UInt * dof_global_id = dof_global_ids.storage();
   Int * dof_type       = dof_types.storage();
 
   Array<UInt> * local_dofs = new Array<UInt>(0,2);
   UInt local_dof_val[2];
   nb_needed_dofs = 0;
   nb_local_dofs = 0;
 
   for (UInt n = 0; n < nb_dofs; ++n) {
     if(*dof_type != -3) {
       local_dof_val[0] = *dof_global_id;
 
       if(*dof_type == -1 || *dof_type == -2) {
         local_dof_val[1] = 0; // master for this node, shared or not
         nb_local_dofs++;
       } else if (*dof_type >= 0) {
         nb_needed_dofs++;
         local_dof_val[1] = 1; // slave node
       }
       local_dofs->push_back(local_dof_val);
     }
     dof_type++;
     dof_global_id++;
   }
 
   Int * nb_dof_per_proc = new Int[psize];
   nb_dof_per_proc[prank] = local_dofs->getSize();
-  communicator->allGather(nb_dof_per_proc, 1);
+  static_communicator->allGather(nb_dof_per_proc, 1);
   AKANTU_DEBUG(dblDebug, "I have " << local_dofs->getSize() << " not ghost dofs ("
                << nb_local_dofs << " local and " << nb_needed_dofs << " slave)");
 
   UInt pos = 0;
   for (UInt p = 0; p < prank; ++p)  pos += nb_dof_per_proc[p];
   UInt nb_total_dofs = pos;
   for (UInt p = prank; p < psize; ++p)  nb_total_dofs += nb_dof_per_proc[p];
 
   Int * nb_values = new Int[psize];
   for (UInt p = 0; p < psize; ++p) nb_values[p] = nb_dof_per_proc[p] * 2;
 
   UInt * buffer = new UInt[2*nb_total_dofs];
   memcpy(buffer + 2 * pos, local_dofs->storage(), local_dofs->getSize() * 2 * sizeof(UInt));
   delete local_dofs;
 
-  communicator->allGatherV(buffer, nb_values);
+  static_communicator->allGatherV(buffer, nb_values);
 
   UInt * tmp_buffer = buffer;
 
   for (UInt p = 0; p < psize; ++p) {
     UInt proc_p_nb_dof = nb_dof_per_proc[p];
     if (p != prank){
       AKANTU_DEBUG(dblDebug, "I get " << proc_p_nb_dof << "(" << nb_values[p] << ") dofs from " << p + 1);
       proc_informations[p].dofs.resize(0);
       for (UInt dd = 0; dd < proc_p_nb_dof; ++dd) {
         UInt dof = tmp_buffer[2*dd];
         if(tmp_buffer[2*dd + 1] == 0)
           proc_informations[p].dofs.push_back(dof);
         else
           proc_informations[p].needed_dofs.push_back(dof);
       }
 
       AKANTU_DEBUG(dblDebug, "Proc " << p + 1 << " sends me "
                    << proc_informations[p].dofs.getSize()	<< " local dofs, and "
                    << proc_informations[p].needed_dofs.getSize() << " slave dofs");
     }
     tmp_buffer += 2*proc_p_nb_dof;
   }
   delete [] nb_dof_per_proc;
   delete [] buffer;
   delete [] nb_values;
   gather_scatter_scheme_initialized = true;
 
   AKANTU_DEBUG_OUT();
 }
 
 __END_AKANTU__
diff --git a/src/synchronizer/dof_synchronizer.hh b/src/synchronizer/dof_synchronizer.hh
index 731820c60..16f2f9a77 100644
--- a/src/synchronizer/dof_synchronizer.hh
+++ b/src/synchronizer/dof_synchronizer.hh
@@ -1,224 +1,237 @@
 /**
  * @file   dof_synchronizer.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @date creation: Fri Jun 17 2011
  * @date last modification: Fri Mar 21 2014
  *
  * @brief  Synchronize Array of DOFs
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_array.hh"
 #include "static_communicator.hh"
+#include "synchronizer.hh"
 
 /* -------------------------------------------------------------------------- */
 
 
 
 #ifndef __AKANTU_DOF_SYNCHRONIZER_HH__
 #define __AKANTU_DOF_SYNCHRONIZER_HH__
 
 __BEGIN_AKANTU__
 
 class Mesh;
 
 template<typename T>
 class AddOperation {
 public:
   inline T operator()(T & b, T & a) { return a + b; };
 };
 
 
-class DOFSynchronizer {
+class DOFSynchronizer : public Synchronizer {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
 
   DOFSynchronizer(const Mesh & mesh, UInt nb_degree_of_freedom);
   virtual ~DOFSynchronizer();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
 
+  /// asynchronous synchronization of ghosts
+  virtual void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag);
+
+  /// wait end of asynchronous synchronization of ghosts
+  virtual void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag);
+
+  /// compute buffer size for a given tag and data accessor
+  virtual void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag);
+
   /// init the scheme for scatter and gather operation, need extra memory
   void initScatterGatherCommunicationScheme();
 
   /// initialize the equation number with local ids
   void initLocalDOFEquationNumbers();
 
   /// initialize the equation number with local ids
   void initGlobalDOFEquationNumbers();
 
   /**
    * Gather the DOF value on the root proccessor
    *
    * @param to_gather data to gather
    * @param root processor on which data are gathered
    * @param gathered Array containing the gathered data, only valid on root processor
    */
   template<typename T>
   void gather(const Array<T> & to_gather, UInt root,
 	      Array<T> * gathered = NULL) const;
 
   /**
    * Scatter a DOF Array form root to all processors
    *
    * @param scattered data to scatter, only valid on root processor
    * @param root processor scattering data
    * @param to_scatter result of scattered data
    */
   template<typename T>
   void scatter(Array<T> & scattered, UInt root,
 	       const Array<T> * to_scatter = NULL) const;
 
 
   template<typename T> void synchronize(Array<T> & vector) const ;
   template<template <class> class Op, typename T> void reduceSynchronize(Array<T> & vector) const;
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// get the equation_number Array
   AKANTU_GET_MACRO(LocalDOFEquationNumbers, local_dof_equation_numbers, const Array<Int> &);
   AKANTU_GET_MACRO(GlobalDOFEquationNumbers, global_dof_equation_numbers, const Array<Int> &);
 
   Array<Int> * getLocalDOFEquationNumbersPointer(){return &local_dof_equation_numbers;};
   Array<Int> * getGlobalDOFEquationNumbersPointer(){return &global_dof_equation_numbers;};
 
   typedef unordered_map<Int, UInt>::type GlobalEquationNumberMap;
 
   AKANTU_GET_MACRO(GlobalEquationNumberToLocal, global_dof_equation_number_to_local, const GlobalEquationNumberMap &)
 
   /// get the Array of global ids of the dofs
   AKANTU_GET_MACRO(DOFGlobalIDs, dof_global_ids, const Array<UInt> &);
 
   /// get the global id of a dof
   inline UInt getDOFGlobalID(UInt local_id) const {
     return dof_global_ids(local_id);
   }
 
   /// get the local id of a global dof
   inline UInt getDOFLocalID(UInt global_id) const {
     return global_dof_to_local.find(global_id)->second;
   }
 
   /// get the DOF type Array
   AKANTU_GET_MACRO(DOFTypes, dof_types, const Array<Int> &);
 
   AKANTU_GET_MACRO(NbDOFs, nb_dofs, UInt);
 
   AKANTU_GET_MACRO(NbGlobalDOFs, nb_global_dofs, UInt);
 
   /// say if a node is a pure ghost node
   inline bool isPureGhostDOF(UInt n) const;
 
   /// say if a node is pure local or master node
   inline bool isLocalOrMasterDOF(UInt n) const;
 
   inline bool isLocalDOF(UInt n) const;
   inline bool isMasterDOF(UInt n) const;
   inline bool isSlaveDOF(UInt n) const;
 
 
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
 
   /// equation number position where a dof is synchronized in the matrix (by default = global id)
   Array<Int> global_dof_equation_numbers;
   Array<Int> local_dof_equation_numbers;
   GlobalEquationNumberMap global_dof_equation_number_to_local;
 
   /// DOF global id
   Array<UInt> dof_global_ids;
 
   /*
    * DOF type  -3 pure ghost, -2  master for the dof, -1 normal dof,  i in
    * [0-N] slave dof and master is proc i
    */
   Array<Int> dof_types;
 
   /// number of dofs
   UInt nb_dofs;
 
   UInt nb_global_dofs;
 
   unordered_map<UInt, UInt>::type global_dof_to_local;
 
   UInt prank;
   UInt psize;
-  StaticCommunicator * communicator;
 
   struct PerProcInformations {
     /// dofs to send to the proc
     Array<UInt> slave_dofs;
     /// dofs to recvs from the proc
     Array<UInt> master_dofs;
 
     /* ---------------------------------------------------------------------- */
     /* Data for gather/scatter                                                */
     /* ---------------------------------------------------------------------- */
     /// the dof that the node handle
     Array<UInt> dofs;
     /// the dof that the proc need
     Array<UInt> needed_dofs;
   };
 
   std::vector<PerProcInformations> proc_informations;
 
   /// nb dofs with type -1 or -2
   UInt nb_local_dofs;
   /// nb dof with type >= 0
   UInt nb_needed_dofs;
 
   bool gather_scatter_scheme_initialized;
+
+
+  std::map<SynchronizationTag, Communication> communications; 
 };
 
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 
 #if defined (AKANTU_INCLUDE_INLINE_IMPL)
 #  include "dof_synchronizer_inline_impl.cc"
 #endif
 
 /// standard output stream operator
 // inline std::ostream & operator <<(std::ostream & stream, const DOFSynchronizer & _this)
 // {
 //   _this.printself(stream);
 //   return stream;
 // }
 
 
 __END_AKANTU__
 
 #endif /* __AKANTU_DOF_SYNCHRONIZER_HH__ */
diff --git a/src/synchronizer/dof_synchronizer_inline_impl.cc b/src/synchronizer/dof_synchronizer_inline_impl.cc
index 399be4abe..ee040e3b4 100644
--- a/src/synchronizer/dof_synchronizer_inline_impl.cc
+++ b/src/synchronizer/dof_synchronizer_inline_impl.cc
@@ -1,315 +1,315 @@
 /**
  * @file   dof_synchronizer_inline_impl.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Jun 17 2011
  * @date last modification: Thu Jun 05 2014
  *
  * @brief  DOFSynchronizer inline implementation
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 
 
 /* -------------------------------------------------------------------------- */
 template<typename T> void DOFSynchronizer::gather(const Array<T> & to_gather, UInt root,
 						  Array<T> * gathered) const {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(gather_scatter_scheme_initialized == true, "You should call initScatterGatherCommunicationScheme before trying to gather a Array !!");
 
   if(psize == 1) {
     gathered->copy(to_gather, true);
 
     AKANTU_DEBUG_OUT();
     return;
   }
 
   UInt * dof_global_id = dof_global_ids.storage();
   Int  * dof_type      = dof_types.storage();
   T * to_gather_val    = to_gather.storage();
 
   T  * buffer;
   if(prank == root) {
     gathered->resize(nb_global_dofs / gathered->getNbComponent());
     buffer = gathered->storage();
   } else
     buffer = new T[nb_local_dofs];
 
   UInt dof = 0;
   for (UInt d = 0; d < nb_dofs; ++d) {
     if(*dof_type != -3) {
       if(*dof_type == -1 || *dof_type == -2) {
 	if (prank == root) dof = *dof_global_id;
 	buffer[dof++] = *to_gather_val;
       }
     }
     dof_type++;
     dof_global_id++;
     to_gather_val++;
   }
 
   if (prank == root) {
     for (UInt p = 0; p < psize; ++p) {
       if(p == root) continue;
       UInt nb_dofs = proc_informations[p].dofs.getSize();
       AKANTU_DEBUG_INFO("Gather - Receiving " << nb_dofs << " from " << p);
       if(nb_dofs) {
 	buffer = new T[nb_dofs];
-	communicator->receive(buffer, nb_dofs, p, 0);
+	static_communicator->receive(buffer, nb_dofs, p, 0);
 
 	T * buffer_tmp = buffer;
 	UInt * remote_dofs = proc_informations[p].dofs.storage();
 	for (UInt d = 0; d < nb_dofs; ++d) {
 	  gathered->storage()[*remote_dofs++] = *(buffer_tmp++);
 	}
 
 	delete [] buffer;
       }
     }
   } else {
     AKANTU_DEBUG_INFO("Gather - Sending " << nb_local_dofs << " to " << root);
     if(nb_local_dofs)
-      communicator->send(buffer, nb_local_dofs, root, 0);
+      static_communicator->send(buffer, nb_local_dofs, root, 0);
     delete [] buffer;
   }
 
 
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template<typename T> void DOFSynchronizer::scatter(Array<T> & scattered, UInt root,
 				  const Array<T> * to_scatter) const {
   AKANTU_DEBUG_IN();
 
   AKANTU_DEBUG_ASSERT(gather_scatter_scheme_initialized == true, "You should call initScatterGatherCommunicationScheme before trying to scatter a Array !!");
 
   if(psize == 1) {
     scattered.copy(*to_scatter, true);
     AKANTU_DEBUG_OUT();
     return;
   }
 
   scattered.resize(nb_dofs / scattered.getNbComponent());
 
   UInt * dof_global_id = dof_global_ids.storage();
   Int  * dof_type      = dof_types.storage();
 
   if (prank == root) {
     for (UInt p = 0; p < psize; ++p) {
       if(p == root) continue;
 
       UInt nb_needed_dof = proc_informations[p].needed_dofs.getSize();
       UInt nb_local_dof  = proc_informations[p].dofs.getSize();
 
       AKANTU_DEBUG_INFO("Scatter - Sending " << nb_local_dof + nb_needed_dof << " to " << p);
       if(nb_local_dof + nb_needed_dof) {
 	T * send_buffer = new T[nb_local_dof + nb_needed_dof];
 
 	T * buffer_tmp = send_buffer;
 
 	UInt * remote_dofs = proc_informations[p].dofs.storage();
 	for (UInt d = 0; d < nb_local_dof; ++d) {
 	  *(buffer_tmp++) = to_scatter->storage()[*remote_dofs++];
 	}
 
 	remote_dofs = proc_informations[p].needed_dofs.storage();
 	for (UInt d = 0; d < nb_needed_dof; ++d) {
 	  *(buffer_tmp++) = to_scatter->storage()[*remote_dofs++];
 	}
 
-	communicator->send(send_buffer, nb_local_dof + nb_needed_dof, p, 0);
+	static_communicator->send(send_buffer, nb_local_dof + nb_needed_dof, p, 0);
 	delete [] send_buffer;
       }
     }
 
     T * scattered_val = scattered.storage();
     for (UInt d = 0; d < nb_dofs; ++d) {
       if(*dof_type != -3) {
 	if(*dof_type >= -2)
 	  *scattered_val = to_scatter->storage()[*dof_global_id];
       }
       scattered_val++;
       dof_type++;
       dof_global_id++;
     }
   } else {
     T  * buffer;
     AKANTU_DEBUG_INFO("Scatter - Receiving " << nb_dofs << " from " << root);
     if(nb_local_dofs + nb_needed_dofs) {
       buffer = new T[nb_local_dofs + nb_needed_dofs];
-      communicator->receive(buffer, nb_local_dofs + nb_needed_dofs, root, 0);
+      static_communicator->receive(buffer, nb_local_dofs + nb_needed_dofs, root, 0);
 
 
       T * scattered_val = scattered.storage();
       UInt local_dofs = 0;
       UInt needed_dofs = nb_local_dofs;
       for (UInt d = 0; d < nb_dofs; ++d) {
 	if(*dof_type != -3) {
 	  if(*dof_type == -1 || *dof_type == -2)
 	    *scattered_val = buffer[local_dofs++];
 	  else if(*dof_type >= 0)
 	    *scattered_val = buffer[needed_dofs++];
 	}
 	scattered_val++;
 	dof_type++;
       }
       delete [] buffer;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template<typename T> void DOFSynchronizer::synchronize(Array<T> & dof_vector) const {
   AKANTU_DEBUG_IN();
 
   if(psize == 1) {
     AKANTU_DEBUG_OUT();
     return;
   }
 
 
   for (UInt p = 1; p < psize; ++p) {
     UInt sendto   = (psize + prank + p) % psize;
     UInt recvfrom = (psize + prank - p) % psize;
 
     UInt nb_slave_dofs = proc_informations[sendto].slave_dofs.getSize();
     UInt * slave_dofs  = proc_informations[sendto].slave_dofs.storage();
 
     UInt nb_master_dofs = proc_informations[recvfrom].master_dofs.getSize();
     UInt * master_dofs  = proc_informations[recvfrom].master_dofs.storage();
 
     T * send_buffer = new T[nb_slave_dofs];
     T * recv_buffer = new T[nb_master_dofs];
 
     for (UInt d = 0; d < nb_slave_dofs; ++d) {
       AKANTU_DEBUG_ASSERT(dof_types(slave_dofs[d]) == -2,
 			  "Sending node " << slave_dofs[d]
 			  << "(gid" << dof_global_ids(d) << ") to proc "
 			  << sendto << " but it is not a master node.");
       send_buffer[d] = dof_vector.storage()[slave_dofs[d]];
     }
 
     /// ring blocking communications
     CommunicationRequest * request = NULL;
-    if(nb_slave_dofs  != 0) request = communicator->asyncSend(send_buffer, nb_slave_dofs,  sendto  , 0);
-    if(nb_master_dofs != 0) communicator->receive(recv_buffer, nb_master_dofs, recvfrom, 0);
+    if(nb_slave_dofs  != 0) request = static_communicator->asyncSend(send_buffer, nb_slave_dofs,  sendto  , 0);
+    if(nb_master_dofs != 0) static_communicator->receive(recv_buffer, nb_master_dofs, recvfrom, 0);
 
     for (UInt d = 0; d < nb_master_dofs; ++d) {
       AKANTU_DEBUG_ASSERT(dof_types(master_dofs[d]) >= 0,
 			  "Received node " << master_dofs[d]
 			  << "(gid" << dof_global_ids(d) << ")  from proc "
 			  << recvfrom << " but it is not a slave node.");
       dof_vector.storage()[master_dofs[d]] = recv_buffer[d];
     }
 
     if(nb_slave_dofs != 0) {
-      communicator->wait(request);
-      communicator->freeCommunicationRequest(request);
+      static_communicator->wait(request);
+      static_communicator->freeCommunicationRequest(request);
     }
     delete [] send_buffer;
     delete [] recv_buffer;
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 
 /* -------------------------------------------------------------------------- */
 template<template <class> class Op, typename T> void DOFSynchronizer::reduceSynchronize(Array<T> & dof_vector) const {
   AKANTU_DEBUG_IN();
 
   if(psize == 1) {
     AKANTU_DEBUG_OUT();
     return;
   }
 
   for (UInt p = 1; p < psize; ++p) {
     UInt sendto   = (psize + prank + p) % psize;
     UInt recvfrom = (psize + prank - p) % psize;
 
     UInt nb_slave_dofs = proc_informations[recvfrom].slave_dofs.getSize();
     UInt * slave_dofs  = proc_informations[recvfrom].slave_dofs.storage();
 
     UInt nb_master_dofs = proc_informations[sendto].master_dofs.getSize();
     UInt * master_dofs  = proc_informations[sendto].master_dofs.storage();
 
     T * send_buffer = new T[nb_master_dofs];
     T * recv_buffer = new T[nb_slave_dofs];
 
     for (UInt d = 0; d < nb_master_dofs; ++d) {
       send_buffer[d] = dof_vector.storage()[master_dofs[d]];
     }
 
     CommunicationRequest * request = NULL;
-    if(nb_master_dofs != 0) request = communicator->asyncSend(send_buffer, nb_master_dofs, sendto  , 0);
-    if(nb_slave_dofs  != 0) communicator->receive(recv_buffer, nb_slave_dofs,  recvfrom, 0);
+    if(nb_master_dofs != 0) request = static_communicator->asyncSend(send_buffer, nb_master_dofs, sendto  , 0);
+    if(nb_slave_dofs  != 0) static_communicator->receive(recv_buffer, nb_slave_dofs,  recvfrom, 0);
 
     Op<T> oper;
 
     for (UInt d = 0; d < nb_slave_dofs; ++d) {
       dof_vector.storage()[slave_dofs[d]] = oper(dof_vector.storage()[slave_dofs[d]], recv_buffer[d]);
     }
 
     if(nb_master_dofs != 0) {
-      communicator->wait(request);
-      communicator->freeCommunicationRequest(request);
+      static_communicator->wait(request);
+      static_communicator->freeCommunicationRequest(request);
     }
     delete [] send_buffer;
     delete [] recv_buffer;
   }
 
   synchronize(dof_vector);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 inline bool DOFSynchronizer::isPureGhostDOF(UInt n) const {
   return dof_types.getSize() ? (dof_types(n) == -3) : false;
 }
 
 /* -------------------------------------------------------------------------- */
 inline bool DOFSynchronizer::isLocalOrMasterDOF(UInt n) const {
   return dof_types.getSize() ? (dof_types(n) == -2) || (dof_types(n) == -1) : true;
 }
 
 
 /* -------------------------------------------------------------------------- */
 inline bool DOFSynchronizer::isLocalDOF(UInt n) const {
   return dof_types.getSize() ? dof_types(n) == -1 : true;
 }
 
 /* -------------------------------------------------------------------------- */
 inline bool DOFSynchronizer::isMasterDOF(UInt n) const {
   return dof_types.getSize() ? dof_types(n) == -2 : false;
 }
 
 /* -------------------------------------------------------------------------- */
 inline bool DOFSynchronizer::isSlaveDOF(UInt n) const {
   return dof_types.getSize() ? dof_types(n) >= 0 : false;
 }
diff --git a/src/synchronizer/synchronizer.cc b/src/synchronizer/synchronizer.cc
index beab3974c..bcd018f79 100644
--- a/src/synchronizer/synchronizer.cc
+++ b/src/synchronizer/synchronizer.cc
@@ -1,56 +1,57 @@
 /**
  * @file   synchronizer.cc
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Sep 01 2010
  * @date last modification: Wed Nov 13 2013
  *
  * @brief  implementation of the common part
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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.hh"
 
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_AKANTU__
 
 /* -------------------------------------------------------------------------- */
 Synchronizer::Synchronizer(SynchronizerID id, MemoryID memory_id) :
-  Memory(id, memory_id) {
+  Memory(id, memory_id),
+  static_communicator(&StaticCommunicator::getStaticCommunicator()) {
 
 }
 
 /* -------------------------------------------------------------------------- */
 void Synchronizer::synchronize(DataAccessor & data_accessor,
 			       SynchronizationTag tag) {
   AKANTU_DEBUG_IN();
   asynchronousSynchronize(data_accessor,tag);
   waitEndSynchronize(data_accessor,tag);
   AKANTU_DEBUG_OUT();
 }
 /* -------------------------------------------------------------------------- */
 
 
 __END_AKANTU__
diff --git a/src/synchronizer/synchronizer.hh b/src/synchronizer/synchronizer.hh
index a4b4c232f..46c01892b 100644
--- a/src/synchronizer/synchronizer.hh
+++ b/src/synchronizer/synchronizer.hh
@@ -1,133 +1,163 @@
 /**
  * @file   synchronizer.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @date creation: Wed Sep 01 2010
  * @date last modification: Tue Apr 30 2013
  *
  * @brief  interface for communicator and pbc synchronizers
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_SYNCHRONIZER_HH__
 #define __AKANTU_SYNCHRONIZER_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_memory.hh"
 #include "data_accessor.hh"
+#include "real_static_communicator.hh"
+#include "static_communicator.hh"
+
 /* -------------------------------------------------------------------------- */
 #include <map>
 /* -------------------------------------------------------------------------- */
 
 __BEGIN_AKANTU__
 
 class Synchronizer : protected Memory {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
 
   Synchronizer(SynchronizerID id = "synchronizer", MemoryID memory_id = 0);
 
   virtual ~Synchronizer() { };
 
   virtual void printself(__attribute__((unused)) std::ostream & stream,
 			 __attribute__((unused)) int indent = 0) const {};
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
 
   /// synchronize ghosts
   void synchronize(DataAccessor & data_accessor,SynchronizationTag tag);
 
   /// asynchronous synchronization of ghosts
   virtual void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag) = 0;
 
   /// wait end of asynchronous synchronization of ghosts
   virtual void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag) = 0;
 
   /// compute buffer size for a given tag and data accessor
   virtual void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag)=0;
 
   /**
    * tag = |__________20_________|___8____|_4_|
    *       |          proc       | num mes| ct|
    */
   class Tag {
   public:
     operator int() { return int(tag); }
 
     template<typename CommTag>
     static inline Tag genTag(int proc, UInt msg_count, CommTag tag) {
       Tag t;
       t.tag = (((proc & 0xFFFFF) << 12) + ((msg_count & 0xFF) << 4) + ((Int)tag & 0xF));
       return t;
     }
 
     virtual void printself(std::ostream & stream,
 			   __attribute__((unused)) int indent = 0) const {
       stream << (tag >> 12) << ":" << (tag >> 4 & 0xFF) << ":" << (tag & 0xF);
     }
   private:
     UInt tag;
   };
 
 protected:
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
+
+  class Communication {
+  public:
+    void resize(UInt size) {
+      send_buffer.resize(size);
+      recv_buffer.resize(size);
+      size_to_send   .resize(size);
+      size_to_receive.resize(size);
+    }
+
+  public:
+    /// size of data to send to each processor
+    std::vector<UInt> size_to_send;
+    /// size of data to recv to each processor
+    std::vector<UInt> size_to_receive;
+    std::vector< CommunicationBuffer > send_buffer;
+    std::vector< CommunicationBuffer > recv_buffer;
+
+    std::vector<CommunicationRequest *> send_requests;
+    std::vector<CommunicationRequest *> recv_requests;
+  };
+
   /// id of the synchronizer
   SynchronizerID id;
 
   /// message counter per tag
   std::map<SynchronizationTag, UInt> tag_counter;
+
+
+  /// the static memory instance
+  StaticCommunicator * static_communicator;
 };
 
 
 /// standard output stream operator
 inline std::ostream & operator <<(std::ostream & stream, const Synchronizer & _this)
 {
   _this.printself(stream);
   return stream;
 }
 
 inline std::ostream & operator <<(std::ostream & stream, const Synchronizer::Tag & _this)
 {
   _this.printself(stream);
   return stream;
 }
 
 
 __END_AKANTU__
 
 #endif /* __AKANTU_SYNCHRONIZER_HH__ */
diff --git a/src/synchronizer/synchronizer_registry.hh b/src/synchronizer/synchronizer_registry.hh
index 7b116afef..5e7e09617 100644
--- a/src/synchronizer/synchronizer_registry.hh
+++ b/src/synchronizer/synchronizer_registry.hh
@@ -1,115 +1,115 @@
 /**
  * @file   synchronizer_registry.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  *
  * @date creation: Thu Jun 16 2011
  * @date last modification: Tue Nov 06 2012
  *
  * @brief  Registry of synchronizers
  *
  * @section LICENSE
  *
  * Copyright (©) 2010-2012, 2014 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_SYNCHRONIZER_REGISTRY_HH__
 #define __AKANTU_SYNCHRONIZER_REGISTRY_HH__
 
 /* -------------------------------------------------------------------------- */
 #include "aka_common.hh"
 #include "data_accessor.hh"
 #include "synchronizer.hh"
 /* -------------------------------------------------------------------------- */
 
 
 __BEGIN_AKANTU__
 
 class SynchronizerRegistry {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
 
   SynchronizerRegistry(DataAccessor & data_accessor);
   virtual ~SynchronizerRegistry();
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
 
   /// synchronize operation
   void synchronize(SynchronizationTag tag);
 
   /// asynchronous synchronization
   void asynchronousSynchronize(SynchronizationTag tag);
 
   /// wait end of asynchronous synchronization
   void waitEndSynchronize(SynchronizationTag tag);
 
   /// register a new synchronization
   void registerSynchronizer(Synchronizer & synchronizer,SynchronizationTag tag);
-
+  
   /// function to print the containt of the class
   virtual void printself(std::ostream & stream, int indent = 0) const;
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 private:
 
   // /// number of tags registered
   // UInt nb_synchronization_tags;
 
   typedef std::multimap<SynchronizationTag, Synchronizer *> Tag2Sync;
   /// list of registered synchronization
   Tag2Sync synchronizers;
 
   /// data accessor that will permit to do the pack/unpack things
   DataAccessor & data_accessor;
 };
 
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 
 // #include "synchronizer_registry_inline_impl.cc"
 
 /// standard output stream operator
 inline std::ostream & operator <<(std::ostream & stream, const SynchronizerRegistry & _this)
 {
   _this.printself(stream);
   return stream;
 }
 
 
 __END_AKANTU__
 
 
 
 #endif /* __AKANTU_SYNCHRONIZER_REGISTRY_HH__ */
diff --git a/test/test_solver/CMakeLists.txt b/test/test_solver/CMakeLists.txt
index 42f17633c..ee414464d 100644
--- a/test/test_solver/CMakeLists.txt
+++ b/test/test_solver/CMakeLists.txt
@@ -1,54 +1,64 @@
 #===============================================================================
 # @file   CMakeLists.txt
 #
 # @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Mon Dec 13 2010
 # @date last modification: Tue Nov 06 2012
 #
 # @brief  configuration for solver tests
 #
 # @section LICENSE
 #
 # Copyright (©) 2014 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_mesh(test_solver_mesh triangle.geo 2 1)
 
 register_test(test_sparse_matrix_profile
   SOURCES test_sparse_matrix_profile.cc
   DEPENDENCIES test_solver_mesh
   )
 
 register_test(test_sparse_matrix_assemble
   SOURCES test_sparse_matrix_assemble.cc
   DEPENDENCIES test_solver_mesh
   )
 
 register_test(test_sparse_matrix_product
   SOURCES test_sparse_matrix_product.cc
   FILES_TO_COPY bar.msh
   )
 
 register_test(test_petsc_matrix_profile
   SOURCES test_petsc_matrix_profile.cc
   DEPENDENCIES test_solver_mesh
+  )
+
+register_test(test_petsc_matrix_apply_boundary
+  SOURCES test_petsc_matrix_apply_boundary.cc
+  DEPENDENCIES test_solver_mesh
+  )
+
+register_test(test_solver_petsc
+  SOURCES test_solver_petsc.cc
+  DEPENDENCIES profile.mtx
   )
\ No newline at end of file
diff --git a/test/test_solver/test_petsc_matrix_profile.cc b/test/test_solver/test_petsc_matrix_profile.cc
index 04b32cbfe..1a8f2f4e7 100644
--- a/test/test_solver/test_petsc_matrix_profile.cc
+++ b/test/test_solver/test_petsc_matrix_profile.cc
@@ -1,126 +1,137 @@
 /**
  * @file   test_petsc_matrix_profile.cc
  * @author Aurelia Cuba Ramos <aurelia.cubaramos@epfl.ch>
  * @date   Wed Jul 30 12:34:08 2014
  *
  * @brief  test the profile generation of the PETScMatrix class
  *
  * @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 <cstdlib>
 /* -------------------------------------------------------------------------- */
 #include "static_communicator.hh"
 #include "aka_common.hh"
 #include "aka_csr.hh"
 #include "mesh.hh"
 #include "mesh_io.hh"
 #include "mesh_utils.hh"
 #include "distributed_synchronizer.hh"
 #include "petsc_matrix.hh"
 #include "fe_engine.hh"
 #include "dof_synchronizer.hh"
 
 #include "mesh_partition_scotch.hh"
 
 using namespace akantu;
 int main(int argc, char *argv[]) {
 
   initialize(argc, argv);
   const ElementType element_type = _triangle_3;
   const GhostType ghost_type = _not_ghost; 
   UInt spatial_dimension = 2;
 
 
   StaticCommunicator & comm = akantu::StaticCommunicator::getStaticCommunicator();
   Int psize = comm.getNbProc();
   Int prank = comm.whoAmI();
 
   /// read the mesh and partition it
   Mesh mesh(spatial_dimension);
 
   /* ------------------------------------------------------------------------ */
   /* Parallel initialization                                                  */
   /* ------------------------------------------------------------------------ */
   DistributedSynchronizer * communicator = NULL;
   if(prank == 0) {
     /// creation mesh
     mesh.read("triangle.msh");
     MeshPartitionScotch * partition = new MeshPartitionScotch(mesh, spatial_dimension);
     partition->partitionate(psize);
     communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, partition);
     delete partition;
   } else {
     communicator = DistributedSynchronizer::createDistributedSynchronizerMesh(mesh, NULL);
   }
   
 
   FEEngine *fem = new FEEngineTemplate<IntegratorGauss,ShapeLagrange,_ek_regular>(mesh, spatial_dimension, "my_fem");
 
   DOFSynchronizer dof_synchronizer(mesh, spatial_dimension);
   UInt nb_global_nodes = mesh.getNbGlobalNodes();
 
   dof_synchronizer.initGlobalDOFEquationNumbers();
 
   // fill the matrix with 
   UInt nb_element = mesh.getNbElement(element_type);
   UInt nb_nodes_per_element = mesh.getNbNodesPerElement(element_type);
   UInt nb_dofs_per_element = spatial_dimension * nb_nodes_per_element;
-  SparseMatrix K(nb_global_nodes * spatial_dimension, _symmetric);
+  SparseMatrix K(nb_global_nodes * spatial_dimension, _unsymmetric);
   K.buildProfile(mesh, dof_synchronizer, spatial_dimension);
   Matrix<Real> element_input(nb_dofs_per_element, nb_dofs_per_element, 1);
   Array<Real> K_e = Array<Real>(nb_element, nb_dofs_per_element * nb_dofs_per_element, "K_e");
   Array<Real>::matrix_iterator K_e_it = K_e.begin(nb_dofs_per_element, nb_dofs_per_element);
   Array<Real>::matrix_iterator K_e_end = K_e.end(nb_dofs_per_element, nb_dofs_per_element);
 
   for(; K_e_it != K_e_end; ++K_e_it)
     *K_e_it = element_input;
 
   // assemble the test matrix
   fem->assembleMatrix(K_e, K, spatial_dimension, element_type, ghost_type);
 
   CSR<Element> node_to_elem;
 
   MeshUtils::buildNode2Elements(mesh, node_to_elem, spatial_dimension);
 
   for (UInt i = 0; i < mesh.getNbNodes(); ++i) {
     std::cout << node_to_elem.getNbCols(i) << std::endl;
   }
 
-  PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _symmetric);
-  
-  petsc_matrix.resize(dof_synchronizer);
+  PETScMatrix petsc_matrix(nb_global_nodes * spatial_dimension, _unsymmetric);
+
   petsc_matrix.buildProfile(mesh, dof_synchronizer, spatial_dimension);
   
 
   petsc_matrix.add(K, 1);
-  petsc_matrix.performAssembly();
   
+  // for (UInt i = 0; i < mesh.getNbNodes(); ++i) { 
+  //   for (UInt j = 0; j < spatial_dimension; ++j) {
+  //     UInt dof = i * spatial_dimension + j;
+  //     if (dof_synchronizer.isLocalOrMasterDOF(dof)) {
+  // 	UInt global_dof = dof_synchronizer.getDOFGlobalID(dof);
+  // 	std::cout << "K(" << global_dof << "," << global_dof << ")=" << petsc_matrix(dof,dof) << std::endl;
+  // 	std::cout << node_to_elem.getNbCols(i) << std::endl; 
+  //     }
+  //   }
+  // }
+
+  
+
 
-  petsc_matrix.saveMatrix("profile.mtx");
+  petsc_matrix.saveMatrix("profile.dat");
 
   delete communicator;
 
   finalize();
   
   return EXIT_SUCCESS;
 
 }
diff --git a/test/test_synchronizer/CMakeLists.txt b/test/test_synchronizer/CMakeLists.txt
index 52a6c6b31..971dbc550 100644
--- a/test/test_synchronizer/CMakeLists.txt
+++ b/test/test_synchronizer/CMakeLists.txt
@@ -1,62 +1,68 @@
 #===============================================================================
 # @file   CMakeLists.txt
 #
 # @author Nicolas Richart <nicolas.richart@epfl.ch>
 #
 # @date creation: Sun Sep 12 2010
 # @date last modification: Fri Sep 05 2014
 #
 # @brief  configuration for synchronizer tests
 #
 # @section LICENSE
 #
 # Copyright (©) 2010-2012, 2014 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_mesh(test_synchronizer_communication_mesh
   cube.geo 3 2)
 
 register_test(test_synchronizer_communication
   SOURCES test_synchronizer_communication.cc
   DEPENDENCIES test_synchronizer_communication_mesh
   PACKAGE parallel
   )
 
 if(AKANTU_DAMAGE_NON_LOCAL)
   add_executable(test_grid_synchronizer_check_neighbors test_grid_synchronizer_check_neighbors.cc)
   target_link_libraries(test_grid_synchronizer_check_neighbors akantu)
 endif()
 
 register_test(test_grid_synchronizer
   SOURCES test_grid_synchronizer.cc test_data_accessor.hh
   DEPENDENCIES test_synchronizer_communication_mesh test_grid_synchronizer_check_neighbors
   EXTRA_FILES test_grid_synchronizer_check_neighbors.cc test_grid_tools.hh
   PACKAGE damage_non_local
   )
 
 register_test(test_dof_synchronizer
   SOURCES test_dof_synchronizer.cc test_data_accessor.hh
   FILES_TO_COPY bar.msh)
 
+register_test(test_dof_synchronizer_communication
+  SOURCES test_dof_synchronizer_communication.cc test_dof_data_accessor.hh
+  DEPENDENCIES test_synchronizer_communication_mesh
+  PACKAGE parallel
+  )
+
 register_test(test_data_distribution
   SOURCES test_data_distribution.cc
   FILES_TO_COPY data_split.msh
   PACKAGE parallel
   )