diff --git a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
index 68dd33e7f..855158ebd 100644
--- a/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
+++ b/extra_packages/extra-materials/src/material_FE2/material_FE2.cc
@@ -1,199 +1,195 @@
 /**
  * @file   material_FE2.cc
  *
  * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch>
  *
  * @brief Material for multi-scale simulations. It stores an
  * underlying RVE on each integration point of the material.
  *
  *
  * Copyright (©) 2010-2012, 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "material_FE2.hh"
 #include "communicator.hh"
 #include "solid_mechanics_model_RVE.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 MaterialFE2<spatial_dimension>::MaterialFE2(SolidMechanicsModel & model,
                                             const ID & id)
     : Parent(model, id), C("material_stiffness", *this) {
   AKANTU_DEBUG_IN();
 
   this->C.initialize(voigt_h::size * voigt_h::size);
   this->initialize();
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 MaterialFE2<spatial_dimension>::~MaterialFE2() = default;
 
 /* -------------------------------------------------------------------------- */
 template <UInt dim> void MaterialFE2<dim>::initialize() {
   this->registerParam("element_type", el_type, _triangle_3,
                       _pat_parsable | _pat_modifiable,
                       "element type in RVE mesh");
   this->registerParam("mesh_file", mesh_file, _pat_parsable | _pat_modifiable,
                       "the mesh file for the RVE");
   this->registerParam("nb_gel_pockets", nb_gel_pockets,
                       _pat_parsable | _pat_modifiable,
                       "the number of gel pockets in each RVE");
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::initMaterial() {
   AKANTU_DEBUG_IN();
   Parent::initMaterial();
 
-  /// create a Mesh and SolidMechanicsModel on each integration point of the
-  /// material
-  auto C_it = this->C(this->el_type).begin(voigt_h::size, voigt_h::size);
-
-  for (auto && data :
-       enumerate(make_view(C(this->el_type), voigt_h::size, voigt_h::size))) {
-    auto q = std::get<0>(data);
-    auto & C = std::get<1>(data);
+  // create a Mesh and SolidMechanicsModel on each integration point of the
+  // material
+  auto & mesh = this->model.getMesh();
+  auto & g_ids = mesh.template getData<UInt>("global_ids", this->el_type);
+  auto const & element_filter = this->getElementFilter()(this->el_type);
+  for (auto && data : zip(element_filter)) {
+    UInt proc_el_id = std::get<0>(data);
+    UInt gl_el_id = g_ids(proc_el_id);
 
     meshes.emplace_back(std::make_unique<Mesh>(
-        spatial_dimension, "RVE_mesh_" + std::to_string(q), q + 1));
+        spatial_dimension, "RVE_mesh_" + std::to_string(gl_el_id)));
 
     auto & mesh = *meshes.back();
     mesh.read(mesh_file);
 
     RVEs.emplace_back(std::make_unique<SolidMechanicsModelRVE>(
         mesh, true, this->nb_gel_pockets, _all_dimensions,
-        "SMM_RVE_" + std::to_string(q), q + 1));
+        "SMM_RVE_" + std::to_string(gl_el_id)));
 
     auto & RVE = *RVEs.back();
     RVE.initFull(_analysis_method = _static);
-
-    /// compute intial stiffness of the RVE
-    RVE.homogenizeStiffness(C);
   }
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::computeStress(ElementType el_type,
                                                    GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   // Compute thermal stresses first
 
   Parent::computeStress(el_type, ghost_type);
   Array<Real>::const_scalar_iterator sigma_th_it =
       this->sigma_th(el_type, ghost_type).begin();
 
   // Wikipedia convention:
   // 2*eps_ij (i!=j) = voigt_eps_I
   // http://en.wikipedia.org/wiki/Voigt_notation
 
   Array<Real>::const_matrix_iterator C_it =
       this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size);
 
   // create vectors to store stress and strain in Voigt notation
   // for efficient computation of stress
   Vector<Real> voigt_strain(voigt_h::size);
   Vector<Real> voigt_stress(voigt_h::size);
 
   MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type);
 
   const Matrix<Real> & C_mat = *C_it;
   const Real & sigma_th = *sigma_th_it;
 
   /// copy strains in Voigt notation
   for (UInt I = 0; I < voigt_h::size; ++I) {
     /// copy stress in
     Real voigt_factor = voigt_h::factors[I];
     UInt i = voigt_h::vec[I][0];
     UInt j = voigt_h::vec[I][1];
 
     voigt_strain(I) = voigt_factor * (grad_u(i, j) + grad_u(j, i)) / 2.;
   }
 
   // compute stresses in Voigt notation
   voigt_stress.mul<false>(C_mat, voigt_strain);
 
   /// copy stresses back in full vectorised notation
   for (UInt I = 0; I < voigt_h::size; ++I) {
     UInt i = voigt_h::vec[I][0];
     UInt j = voigt_h::vec[I][1];
     sigma(i, j) = sigma(j, i) = voigt_stress(I) + (i == j) * sigma_th;
   }
 
   ++C_it;
   ++sigma_th_it;
 
   MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END;
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::computeTangentModuli(
-    ElementType el_type, Array<Real> & tangent_matrix,
-    GhostType ghost_type) {
+    ElementType el_type, Array<Real> & tangent_matrix, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   Array<Real>::const_matrix_iterator C_it =
       this->C(el_type, ghost_type).begin(voigt_h::size, voigt_h::size);
 
   MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_matrix);
   tangent.copy(*C_it);
   ++C_it;
   MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END;
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <UInt spatial_dimension>
 void MaterialFE2<spatial_dimension>::advanceASR(
     const Matrix<Real> & prestrain) {
   AKANTU_DEBUG_IN();
 
   for (auto && data :
        zip(RVEs,
            make_view(this->gradu(this->el_type), spatial_dimension,
                      spatial_dimension),
            make_view(this->eigengradu(this->el_type), spatial_dimension,
                      spatial_dimension),
            make_view(this->C(this->el_type), voigt_h::size, voigt_h::size),
            this->delta_T(this->el_type))) {
     auto & RVE = *(std::get<0>(data));
 
     /// apply boundary conditions based on the current macroscopic displ.
     /// gradient
     RVE.applyBoundaryConditions(std::get<1>(data));
 
     /// apply homogeneous temperature field to each RVE to obtain thermoelastic
     /// effect
     RVE.applyHomogeneousTemperature(std::get<4>(data));
 
     /// advance the ASR in every RVE
     RVE.advanceASR(prestrain);
 
     /// compute the average eigen_grad_u
     RVE.homogenizeEigenGradU(std::get<2>(data));
 
     /// compute the new effective stiffness of the RVE
     RVE.homogenizeStiffness(std::get<3>(data));
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 INSTANTIATE_MATERIAL(material_FE2, MaterialFE2);
 
 } // namespace akantu
diff --git a/packages/fluid_diffusion.cmake b/packages/fluid_diffusion.cmake
new file mode 100644
index 000000000..b64028200
--- /dev/null
+++ b/packages/fluid_diffusion.cmake
@@ -0,0 +1,41 @@
+#===============================================================================
+# @file   heat_transfer.cmake
+#
+# @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
+# @author Nicolas Richart <nicolas.richart@epfl.ch>
+#
+# @date creation: Mon Nov 21 2011
+# @date last modification: Mon Mar 30 2015
+#
+# @brief  package description for heat transfer
+#
+# @section LICENSE
+#
+# Copyright (©)  2010-2012, 2014,  2015 EPFL  (Ecole Polytechnique  Fédérale de
+# Lausanne)  Laboratory (LSMS  -  Laboratoire de  Simulation  en Mécanique  des
+# Solides)
+#
+# Akantu is free  software: you can redistribute it and/or  modify it under the
+# terms  of the  GNU Lesser  General Public  License as  published by  the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A  PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
+# details.
+#
+# You should  have received  a copy  of the GNU  Lesser General  Public License
+# along with Akantu. If not, see <http://www.gnu.org/licenses/>.
+#
+#===============================================================================
+
+package_declare(fluid_diffusion
+  DESCRIPTION "Use Fluid Diffusion package of Akantu")
+
+package_declare_sources(fluid_diffusion
+  model/fluid_diffusion/fluid_diffusion_model.cc
+  model/fluid_diffusion/fluid_diffusion_model.hh
+  model/fluid_diffusion/fluid_diffusion_model_inline_impl.hh
+  model/fluid_diffusion/fluid_diffusion_model_event_handler.hh
+  )
diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh
index ebd779e80..bfb83ae2a 100644
--- a/src/common/aka_common.hh
+++ b/src/common/aka_common.hh
@@ -1,677 +1,685 @@
 /**
  * @file   aka_common.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Jun 14 2010
  * @date last modification: Mon Feb 12 2018
  *
  * @brief  common type descriptions for akantu
  *
  *
  * Copyright (©)  2010-2018 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_COMMON_HH_
 #define AKANTU_COMMON_HH_
 
 #include "aka_compatibilty_with_cpp_standard.hh"
 
 /* -------------------------------------------------------------------------- */
 #if defined(WIN32)
 #define __attribute__(x)
 #endif
 
 /* -------------------------------------------------------------------------- */
 #include "aka_config.hh"
 #include "aka_error.hh"
 #include "aka_safe_enum.hh"
 /* -------------------------------------------------------------------------- */
 #include <boost/preprocessor.hpp>
 #include <limits>
 #include <list>
 #include <memory>
 #include <string>
 #include <type_traits>
 #include <unordered_map>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /* Constants                                                                  */
 /* -------------------------------------------------------------------------- */
 namespace {
   [[gnu::unused]] constexpr UInt _all_dimensions{
       std::numeric_limits<UInt>::max()};
 #ifdef AKANTU_NDEBUG
   [[gnu::unused]] constexpr Real REAL_INIT_VALUE{0.};
 #else
   [[gnu::unused]] constexpr Real REAL_INIT_VALUE{
       std::numeric_limits<Real>::quiet_NaN()};
 #endif
 } // namespace
 
 /* -------------------------------------------------------------------------- */
 /* Common types                                                               */
 /* -------------------------------------------------------------------------- */
 using ID = std::string;
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 #include "aka_enum_macros.hh"
 /* -------------------------------------------------------------------------- */
 #include "aka_element_classes_info.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 /* -------------------------------------------------------------------------- */
 /* Mesh/FEM/Model types                                                       */
 /* -------------------------------------------------------------------------- */
 
 /// small help to use names for directions
 enum SpatialDirection { _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 MeshEventHandlerPriority defines relative order of execution of
 /// events
 enum EventHandlerPriority {
   _ehp_highest = 0,
   _ehp_mesh = 5,
   _ehp_fe_engine = 9,
   _ehp_synchronizer = 10,
   _ehp_dof_manager = 20,
   _ehp_model = 94,
   _ehp_non_local_manager = 100,
   _ehp_lowest = 100
 };
 
 #if !defined(DOXYGEN)
 // clang-format off
 #define AKANTU_MODEL_TYPES                                              \
   (model)                                                               \
   (solid_mechanics_model)                                               \
   (solid_mechanics_model_cohesive)                                      \
   (heat_transfer_model)                                                 \
+  (fluid_diffusion_model)                                               \
   (structural_mechanics_model)						\
   (embedded_model)							\
   (phase_field_model)							\
   (coupler_solid_phasefield)
 // clang-format on
 
 /// enum ModelType defines which type of physics is solved
 AKANTU_CLASS_ENUM_DECLARE(ModelType, AKANTU_MODEL_TYPES)
 AKANTU_CLASS_ENUM_OUTPUT_STREAM(ModelType, AKANTU_MODEL_TYPES)
 AKANTU_CLASS_ENUM_INPUT_STREAM(ModelType, AKANTU_MODEL_TYPES)
 #else
 enum class ModelType {
   model,
   solid_mechanics_model,
   solid_mechanics_model_cohesive,
   heat_transfer_model,
   structural_mechanics_model,
   embedded_model,
 };
 #endif
 /// enum AnalysisMethod type of solving method used to solve the equation of
 /// motion
 enum AnalysisMethod {
   _static = 0,
   _implicit_dynamic = 1,
   _explicit_lumped_mass = 2,
   _explicit_lumped_capacity = 2,
   _explicit_consistent_mass = 3
 };
 
 /// enum DOFSupportType defines which kind of dof that can exists
 enum DOFSupportType { _dst_nodal, _dst_generic };
 
 #if !defined(DOXYGEN)
 // clang-format off
 #define AKANTU_NON_LINEAR_SOLVER_TYPES                                 \
   (linear)                                                             \
   (newton_raphson)                                                     \
   (newton_raphson_modified)                                            \
   (lumped)                                                             \
   (gmres)                                                              \
   (bfgs)                                                               \
   (cg)                                                                 \
   (auto)
 // clang-format on
 AKANTU_CLASS_ENUM_DECLARE(NonLinearSolverType, AKANTU_NON_LINEAR_SOLVER_TYPES)
 AKANTU_CLASS_ENUM_OUTPUT_STREAM(NonLinearSolverType,
                                 AKANTU_NON_LINEAR_SOLVER_TYPES)
 AKANTU_CLASS_ENUM_INPUT_STREAM(NonLinearSolverType,
                                AKANTU_NON_LINEAR_SOLVER_TYPES)
 #else
 /// Type of non linear resolution available in akantu
 enum class NonLinearSolverType {
   _linear,                  ///< No non linear convergence loop
   _newton_raphson,          ///< Regular Newton-Raphson
   _newton_raphson_modified, ///< Newton-Raphson with initial tangent
   _lumped,                  ///< Case of lumped mass or equivalent matrix
   _gmres,
   _bfgs,
   _cg,
   _auto ///< This will take a default value that make sense in case of
         ///  model::getNewSolver
 };
 #endif
 
 #if !defined(DOXYGEN)
 // clang-format off
 #define AKANTU_TIME_STEP_SOLVER_TYPE                                    \
   (static)                                                             \
   (dynamic)                                                            \
   (dynamic_lumped)                                                     \
   (not_defined)
 // clang-format on
 AKANTU_CLASS_ENUM_DECLARE(TimeStepSolverType, AKANTU_TIME_STEP_SOLVER_TYPE)
 AKANTU_CLASS_ENUM_OUTPUT_STREAM(TimeStepSolverType,
                                 AKANTU_TIME_STEP_SOLVER_TYPE)
 AKANTU_CLASS_ENUM_INPUT_STREAM(TimeStepSolverType, AKANTU_TIME_STEP_SOLVER_TYPE)
 #else
 /// Type of time stepping solver
 enum class TimeStepSolverType {
   _static,         ///< Static solution
   _dynamic,        ///< Dynamic solver
   _dynamic_lumped, ///< Dynamic solver with lumped mass
   _not_defined,    ///< For not defined cases
 };
 #endif
 
 #if !defined(DOXYGEN)
 // clang-format off
 #define AKANTU_INTEGRATION_SCHEME_TYPE                                  \
   (pseudo_time)                                                        \
   (forward_euler)                                                      \
   (trapezoidal_rule_1)                                                 \
   (backward_euler)                                                     \
   (central_difference)                                                 \
   (fox_goodwin)                                                        \
   (trapezoidal_rule_2)                                                 \
   (linear_acceleration)                                                \
   (newmark_beta)                                                       \
   (generalized_trapezoidal)
 // clang-format on
 AKANTU_CLASS_ENUM_DECLARE(IntegrationSchemeType, AKANTU_INTEGRATION_SCHEME_TYPE)
 AKANTU_CLASS_ENUM_OUTPUT_STREAM(IntegrationSchemeType,
                                 AKANTU_INTEGRATION_SCHEME_TYPE)
 AKANTU_CLASS_ENUM_INPUT_STREAM(IntegrationSchemeType,
                                AKANTU_INTEGRATION_SCHEME_TYPE)
 #else
 /// Type of integration scheme
 enum class IntegrationSchemeType {
   _pseudo_time,            ///< Pseudo Time
   _forward_euler,          ///< GeneralizedTrapezoidal(0)
   _trapezoidal_rule_1,     ///< GeneralizedTrapezoidal(1/2)
   _backward_euler,         ///< GeneralizedTrapezoidal(1)
   _central_difference,     ///< NewmarkBeta(0, 1/2)
   _fox_goodwin,            ///< NewmarkBeta(1/6, 1/2)
   _trapezoidal_rule_2,     ///< NewmarkBeta(1/2, 1/2)
   _linear_acceleration,    ///< NewmarkBeta(1/3, 1/2)
   _newmark_beta,           ///< generic NewmarkBeta with user defined
                            /// alpha and beta
   _generalized_trapezoidal ///< generic GeneralizedTrapezoidal with user
                            ///  defined alpha
 };
 #endif
 
 #if !defined(DOXYGEN)
 // clang-format off
 #define AKANTU_SOLVE_CONVERGENCE_CRITERIA       \
   (residual)                                    \
   (solution)                                    \
   (residual_mass_wgh)
 // clang-format on
 AKANTU_CLASS_ENUM_DECLARE(SolveConvergenceCriteria,
                           AKANTU_SOLVE_CONVERGENCE_CRITERIA)
 AKANTU_CLASS_ENUM_OUTPUT_STREAM(SolveConvergenceCriteria,
                                 AKANTU_SOLVE_CONVERGENCE_CRITERIA)
 AKANTU_CLASS_ENUM_INPUT_STREAM(SolveConvergenceCriteria,
                                AKANTU_SOLVE_CONVERGENCE_CRITERIA)
 #else
 /// enum SolveConvergenceCriteria different convergence criteria
 enum class SolveConvergenceCriteria {
   _residual,         ///< Use residual to test the convergence
   _solution,         ///< Use solution to test the convergence
   _residual_mass_wgh ///< Use residual weighted by inv. nodal mass to
                      ///< testb
 };
 #endif
 
 /// enum CohesiveMethod type of insertion of cohesive elements
 enum CohesiveMethod { _intrinsic, _extrinsic };
 
 /// @enum MatrixType type of sparse matrix used
 enum MatrixType { _unsymmetric, _symmetric, _mt_not_defined };
 
 /* -------------------------------------------------------------------------- */
 /* Ghosts handling                                                            */
 /* -------------------------------------------------------------------------- */
 /// @enum CommunicatorType type of communication method to use
 enum CommunicatorType { _communicator_mpi, _communicator_dummy };
 
 #if !defined(DOXYGEN)
 // clang-format off
 #define AKANTU_SYNCHRONIZATION_TAG              \
   (whatever)                                    \
   (update)                                      \
   (ask_nodes)                                   \
   (size)                                        \
   (smm_mass)                                    \
   (smm_for_gradu)                               \
   (smm_boundary)                                \
   (smm_uv)                                      \
   (smm_res)                                     \
   (smm_init_mat)                                \
   (smm_stress)                                  \
   (smmc_facets)                                 \
   (smmc_facets_conn)                            \
   (smmc_facets_stress)                          \
   (smmc_damage)                                 \
   (giu_global_conn)                             \
   (ce_groups)                                   \
   (ce_insertion_order)                          \
   (gm_clusters)                                 \
   (htm_temperature)                             \
   (htm_gradient_temperature)                    \
   (htm_phi)                                     \
   (htm_gradient_phi)                            \
+  (fdm_pressure)                                \
+  (fdm_gradient_pressure)                       \
   (pfm_damage)					\
   (pfm_driving)					\
   (pfm_history)					\
   (pfm_energy)					\
   (csp_damage)					\
   (csp_strain)					\
   (mnl_for_average)                             \
   (mnl_weight)                                  \
   (nh_criterion)                                \
   (test)                                        \
   (user_1)                                      \
   (user_2)                                      \
   (material_id)                                 \
   (for_dump)                                    \
   (cf_nodal)                                    \
   (cf_incr)                                     \
   (solver_solution)
 // clang-format on
 AKANTU_CLASS_ENUM_DECLARE(SynchronizationTag, AKANTU_SYNCHRONIZATION_TAG)
 AKANTU_CLASS_ENUM_OUTPUT_STREAM(SynchronizationTag, AKANTU_SYNCHRONIZATION_TAG)
 #else
 /// @enum SynchronizationTag type of synchronizations
 enum class SynchronizationTag {
   //--- Generic tags ---
   _whatever,
   _update,
   _ask_nodes,
   _size,
 
   //--- SolidMechanicsModel tags ---
   _smm_mass,      ///< synchronization of the SolidMechanicsModel.mass
   _smm_for_gradu, ///< synchronization of the
                   /// SolidMechanicsModel.displacement
   _smm_boundary,  ///< synchronization of the boundary, forces, velocities
                   /// and displacement
   _smm_uv,        ///< synchronization of the nodal velocities and displacement
   _smm_res,       ///< synchronization of the nodal residual
   _smm_init_mat,  ///< synchronization of the data to initialize materials
   _smm_stress,    ///< synchronization of the stresses to compute the
                   ///< internal
                   /// forces
   _smmc_facets,   ///< synchronization of facet data to setup facet synch
   _smmc_facets_conn,   ///< synchronization of facet global connectivity
   _smmc_facets_stress, ///< synchronization of facets' stress to setup
                        ///< facet
                        /// synch
   _smmc_damage,        ///< synchronization of damage
 
   // --- GlobalIdsUpdater tags ---
   _giu_global_conn, ///< synchronization of global connectivities
 
   // --- CohesiveElementInserter tags ---
   _ce_groups, ///< synchronization of cohesive element insertion depending
               /// on facet groups
   _ce_insertion_order, ///< synchronization of the order of insertion of
                        /// cohesive elements
 
   // --- GroupManager tags ---
   _gm_clusters, ///< synchronization of clusters
 
   // --- HeatTransfer tags ---
   _htm_temperature,          ///< synchronization of the nodal temperature
   _htm_gradient_temperature, ///< synchronization of the element gradient
                              /// temperature
 
+  // --- FluidDiffusion tags ---
+  _fdm_pressure,          ///< synchronization of the nodal pressure
+  _fdm_gradient_pressure, ///< synchronization of the element gradient
+                          /// pressure
+
   // --- PhaseFieldModel tags ---
-  _pfm_damage,          ///< synchronization of the nodal damage
-  _pfm_driving,         ///< synchronization of the driving forces to
-			/// compute the internal
-  _pfm_history,         ///< synchronization of the damage history to
-			///  compute the internal
-  _pfm_energy,          ///< synchronization of the damage energy
-			/// density to compute the internal
+  _pfm_damage,  ///< synchronization of the nodal damage
+  _pfm_driving, ///< synchronization of the driving forces to
+                /// compute the internal
+  _pfm_history, ///< synchronization of the damage history to
+                ///  compute the internal
+  _pfm_energy,  ///< synchronization of the damage energy
+                /// density to compute the internal
 
   // --- CouplerSolidPhaseField tags ---
-  _csp_damage,        ///< synchronization of the damage from phase
-		      /// model to solid model
-  _csp_strain,        ///< synchronization of the strain from solid
-		      /// model to phase model  
-  
+  _csp_damage, ///< synchronization of the damage from phase
+               /// model to solid model
+  _csp_strain, ///< synchronization of the strain from solid
+               /// model to phase model
+
   // --- LevelSet tags ---
   _htm_phi,          ///< synchronization of the nodal level set value phi
   _htm_gradient_phi, ///< synchronization of the element gradient phi
 
   //--- Material non local ---
   _mnl_for_average, ///< synchronization of data to average in non local
                     /// material
   _mnl_weight,      ///< synchronization of data for the weight computations
 
   // --- NeighborhoodSynchronization tags ---
   _nh_criterion,
 
   // --- General tags ---
   _test,        ///< Test tag
   _user_1,      ///< tag for user simulations
   _user_2,      ///< tag for user simulations
   _material_id, ///< synchronization of the material ids
   _for_dump,    ///< everything that needs to be synch before dump
 
   // --- Contact & Friction ---
   _cf_nodal, ///< synchronization of disp, velo, and current position
   _cf_incr,  ///< synchronization of increment
 
   // --- Solver tags ---
   _solver_solution ///< synchronization of the solution obained with the
                    /// PETSc solver
 };
 #endif
 
 /// @enum GhostType type of ghost
 enum GhostType {
   _not_ghost = 0,
   _ghost = 1,
   _casper // not used but a real cute ghost
 };
 
 /// Define the flag that can be set to a node
 enum class NodeFlag : std::uint8_t {
   _normal = 0x00,
   _distributed = 0x01,
   _master = 0x03,
   _slave = 0x05,
   _pure_ghost = 0x09,
   _shared_mask = 0x0F,
   _periodic = 0x10,
   _periodic_master = 0x30,
   _periodic_slave = 0x50,
   _periodic_mask = 0xF0,
   _local_master_mask = 0xCC, // ~(_master & _periodic_mask)
 };
 
 inline NodeFlag operator&(const NodeFlag & a, const NodeFlag & b) {
   using under = std::underlying_type_t<NodeFlag>;
   return NodeFlag(under(a) & under(b));
 }
 
 inline NodeFlag operator|(const NodeFlag & a, const NodeFlag & b) {
   using under = std::underlying_type_t<NodeFlag>;
   return NodeFlag(under(a) | under(b));
 }
 
 inline NodeFlag & operator|=(NodeFlag & a, const NodeFlag & b) {
   a = a | b;
   return a;
 }
 
 inline NodeFlag & operator&=(NodeFlag & a, const NodeFlag & b) {
   a = a & b;
   return a;
 }
 
 inline NodeFlag operator~(const NodeFlag & a) {
   using under = std::underlying_type_t<NodeFlag>;
   return NodeFlag(~under(a));
 }
 
 std::ostream & operator<<(std::ostream & stream, NodeFlag flag);
 
 } // namespace akantu
 
 AKANTU_ENUM_HASH(GhostType)
 
 namespace akantu {
 /* -------------------------------------------------------------------------- */
 struct GhostType_def {
   using type = GhostType;
   static const type _begin_ = _not_ghost;
   static const type _end_ = _casper;
 };
 
 using ghost_type_t = safe_enum<GhostType_def>;
 namespace {
   constexpr ghost_type_t ghost_types{_casper};
 }
 
 /// standard output stream operator for GhostType
 // inline std::ostream & operator<<(std::ostream & stream, GhostType type);
 
 /* -------------------------------------------------------------------------- */
 /* Global defines                                                             */
 /* -------------------------------------------------------------------------- */
 #define AKANTU_MIN_ALLOCATION 2000
 
 #define AKANTU_INDENT ' '
 #define AKANTU_INCLUDE_INLINE_IMPL
 
 /* -------------------------------------------------------------------------- */
 #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_DEREF_PTR(name, ptr)                                  \
   inline const auto & get##name() const {                                      \
     if (not(ptr)) {                                                            \
       AKANTU_EXCEPTION("The member " << #ptr << " is not initialized");        \
     }                                                                          \
     return (*(ptr));                                                           \
   }
 
 #define AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(name, ptr)                        \
   inline auto & get##name() {                                                  \
     if (not(ptr)) {                                                            \
       AKANTU_EXCEPTION("The member " << #ptr << " is not initialized");        \
     }                                                                          \
     return (*(ptr));                                                           \
   }
 
 #define AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, support, con)   \
   inline con Array<type> & get##name(const support & el_type,                  \
                                      GhostType ghost_type = _not_ghost)        \
       con { /* NOLINT */                                                       \
     return variable(el_type, ghost_type);                                      \
   } // NOLINT
 
 #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();
 /* -------------------------------------------------------------------------- */
 /// Read an new input file
 void readInputFile(const std::string & input_file);
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 /* string manipulation */
 /* -------------------------------------------------------------------------- */
 inline std::string to_lower(const std::string & str);
 /* -------------------------------------------------------------------------- */
 inline std::string trim(const std::string & to_trim);
 inline std::string trim(const std::string & to_trim, char c);
 /* -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 /// give a string representation of the a human readable size in bit
 template <typename T> std::string printMemorySize(UInt size);
 /* -------------------------------------------------------------------------- */
 
 struct TensorTrait {};
 struct TensorProxyTrait {};
 
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 /* Type traits                                                                */
 /* -------------------------------------------------------------------------- */
 namespace aka {
 
 /* ------------------------------------------------------------------------ */
 template <typename T> using is_tensor = std::is_base_of<akantu::TensorTrait, T>;
 template <typename T>
 using is_tensor_proxy = std::is_base_of<akantu::TensorProxyTrait, T>;
 /* ------------------------------------------------------------------------ */
 template <typename T> using is_scalar = std::is_arithmetic<T>;
 /* ------------------------------------------------------------------------ */
 template <typename R, typename T,
           std::enable_if_t<std::is_reference<T>::value> * = nullptr>
 bool is_of_type(T && t) {
   return (
       dynamic_cast<std::add_pointer_t<
           std::conditional_t<std::is_const<std::remove_reference_t<T>>::value,
                              std::add_const_t<R>, R>>>(&t) != nullptr);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename R, typename T> bool is_of_type(std::unique_ptr<T> & t) {
   return (
       dynamic_cast<std::add_pointer_t<
           std::conditional_t<std::is_const<T>::value, std::add_const_t<R>, R>>>(
           t.get()) != nullptr);
 }
 
 /* ------------------------------------------------------------------------ */
 template <typename R, typename T,
           std::enable_if_t<std::is_reference<T>::value> * = nullptr>
 decltype(auto) as_type(T && t) {
   static_assert(
       disjunction<
           std::is_base_of<std::decay_t<T>, std::decay_t<R>>, // down-cast
           std::is_base_of<std::decay_t<R>, std::decay_t<T>>  // up-cast
           >::value,
       "Type T and R are not valid for a as_type conversion");
   return dynamic_cast<std::add_lvalue_reference_t<
       std::conditional_t<std::is_const<std::remove_reference_t<T>>::value,
                          std::add_const_t<R>, R>>>(t);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename R, typename T,
           std::enable_if_t<std::is_pointer<T>::value> * = nullptr>
 decltype(auto) as_type(T && t) {
   return &as_type<R>(*t);
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename R, typename T>
 decltype(auto) as_type(const std::shared_ptr<T> & t) {
   return std::dynamic_pointer_cast<R>(t);
 }
 
 } // namespace aka
 
 #include "aka_common_inline_impl.hh"
 
 #include "aka_fwd.hh"
 
 namespace 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();
 
 #define AKANTU_CURRENT_FUNCTION                                                \
   (std::string(__func__) + "():" + std::to_string(__LINE__))
 
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 #if AKANTU_INTEGER_SIZE == 4
 #define AKANTU_HASH_COMBINE_MAGIC_NUMBER 0x9e3779b9
 #elif AKANTU_INTEGER_SIZE == 8
 #define AKANTU_HASH_COMBINE_MAGIC_NUMBER 0x9e3779b97f4a7c13LL
 #endif
 
 namespace std {
 /**
  * Hashing function for pairs based on hash_combine from boost The magic
  * number is coming from the golden number @f[\phi = \frac{1 + \sqrt5}{2}@f]
  * @f[\frac{2^32}{\phi} = 0x9e3779b9@f]
  * http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine
  * http://burtleburtle.net/bob/hash/doobs.html
  */
 template <typename a, typename b> struct hash<std::pair<a, b>> {
   hash() = default;
   size_t operator()(const std::pair<a, b> & p) const {
     size_t seed = ah(p.first);
     return bh(p.second) + AKANTU_HASH_COMBINE_MAGIC_NUMBER + (seed << 6) +
            (seed >> 2);
   }
 
 private:
   const hash<a> ah{};
   const hash<b> bh{};
 };
 
 } // namespace std
 
 #endif // AKANTU_COMMON_HH_
diff --git a/src/common/aka_config.hh.in b/src/common/aka_config.hh.in
index 275e536c9..8e55d4d55 100644
--- a/src/common/aka_config.hh.in
+++ b/src/common/aka_config.hh.in
@@ -1,93 +1,103 @@
 /**
  * @file   aka_config.hh.in
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Sun Sep 26 2010
  * @date last modification: Thu Jan 25 2018
  *
  * @brief  Compilation time configuration of Akantu
  *
  *
- * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ * Copyright (©)  2010-2018 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 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.
+ * 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/>.
+ * 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_AKA_CONFIG_HH_
 #define AKANTU_AKA_CONFIG_HH_
 
+// clang-format off
 #define AKANTU_VERSION_MAJOR @AKANTU_MAJOR_VERSION@
 #define AKANTU_VERSION_MINOR @AKANTU_MINOR_VERSION@
 #define AKANTU_VERSION_PATCH @AKANTU_PATCH_VERSION@
-#define AKANTU_VERSION (AKANTU_VERSION_MAJOR * 10000 \
-                        + AKANTU_VERSION_MINOR * 100 \
-                        + AKANTU_VERSION_PATCH)
-
-@AKANTU_TYPES_EXTRA_INCLUDES@
-namespace akantu {
-using Real = @AKANTU_FLOAT_TYPE@;
-using Int = @AKANTU_SIGNED_INTEGER_TYPE@;
-using UInt = @AKANTU_UNSIGNED_INTEGER_TYPE@;
+#define AKANTU_VERSION                                                         \
+  (AKANTU_VERSION_MAJOR * 10000 + AKANTU_VERSION_MINOR * 100 +                 \
+   AKANTU_VERSION_PATCH)
+
+@AKANTU_TYPES_EXTRA_INCLUDES@ namespace akantu {
+  using Real = @AKANTU_FLOAT_TYPE@;
+  using Int = @AKANTU_SIGNED_INTEGER_TYPE@;
+  using UInt = @AKANTU_UNSIGNED_INTEGER_TYPE@;
 } // akantu
 
 #define AKANTU_INTEGER_SIZE @AKANTU_INTEGER_SIZE@
 #define AKANTU_FLOAT_SIZE @AKANTU_FLOAT_SIZE@
 
 #cmakedefine AKANTU_HAS_STRDUP
 
 #cmakedefine AKANTU_USE_BLAS
 #cmakedefine AKANTU_USE_LAPACK
 
 #cmakedefine AKANTU_PARALLEL
 #cmakedefine AKANTU_USE_MPI
 
 #cmakedefine AKANTU_USE_SCOTCH
 #cmakedefine AKANTU_USE_PTSCOTCH
 #cmakedefine AKANTU_SCOTCH_NO_EXTERN
 
 #cmakedefine AKANTU_IMPLICIT
 #cmakedefine AKANTU_USE_MUMPS
 #cmakedefine AKANTU_USE_PETSC
 
 #cmakedefine AKANTU_USE_IOHELPER
 #cmakedefine AKANTU_USE_QVIEW
 #cmakedefine AKANTU_USE_BLACKDYNAMITE
 
 #cmakedefine AKANTU_USE_PYBIND11
 
 #cmakedefine AKANTU_USE_OBSOLETE_GETTIMEOFDAY
 
 #cmakedefine AKANTU_EXTRA_MATERIALS
 #cmakedefine AKANTU_STUDENTS_EXTRA_PACKAGE
 #cmakedefine AKANTU_DAMAGE_NON_LOCAL
 
 #cmakedefine AKANTU_SOLID_MECHANICS
 #cmakedefine AKANTU_STRUCTURAL_MECHANICS
 #cmakedefine AKANTU_HEAT_TRANSFER
+#cmakedefine AKANTU_FLUID_DIFFUSION
 #cmakedefine AKANTU_PHASE_FIELD
 #cmakedefine AKANTU_PYTHON_INTERFACE
 
 #cmakedefine AKANTU_COHESIVE_ELEMENT
 #cmakedefine AKANTU_PARALLEL_COHESIVE_ELEMENT
 
 #cmakedefine MODEL_COUPLERS
 
 #cmakedefine AKANTU_IGFEM
 
 #cmakedefine AKANTU_USE_CGAL
 #cmakedefine AKANTU_EMBEDDED
 
 // Debug tools
 //#cmakedefine AKANTU_NDEBUG
 #cmakedefine AKANTU_DEBUG_TOOLS
 #cmakedefine READLINK_COMMAND @READLINK_COMMAND@
 #cmakedefine ADDR2LINE_COMMAND @ADDR2LINE_COMMAND@
+// clang-format on
 
 #endif /* AKANTU_AKA_CONFIG_HH_ */
diff --git a/src/fe_engine/shape_lagrange.hh b/src/fe_engine/shape_lagrange.hh
index 23cd96a4b..fc74c828f 100644
--- a/src/fe_engine/shape_lagrange.hh
+++ b/src/fe_engine/shape_lagrange.hh
@@ -1,176 +1,179 @@
 /**
  * @file   shape_lagrange.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Tue Feb 15 2011
  * @date last modification: Mon Jan 29 2018
  *
  * @brief  lagrangian shape functions class
  *
  *
  * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "shape_lagrange_base.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef AKANTU_SHAPE_LAGRANGE_HH_
 #define AKANTU_SHAPE_LAGRANGE_HH_
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 template <class Shape> class ShapeCohesive;
 class ShapeIGFEM;
 
 template <ElementKind kind> class ShapeLagrange : public ShapeLagrangeBase {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   ShapeLagrange(const Mesh & mesh, UInt spatial_dimension,
                 const ID & id = "shape_lagrange");
   ~ShapeLagrange() override = default;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// initialization function for structural elements not yet implemented
   inline void initShapeFunctions(const Array<Real> & nodes,
                                  const Matrix<Real> & integration_points,
-                                 ElementType type,
-                                 GhostType ghost_type);
+                                 ElementType type, GhostType ghost_type);
 
   /// computes the shape functions derivatives for given interpolation points
   template <ElementType type>
   void computeShapeDerivativesOnIntegrationPoints(
       const Array<Real> & nodes, const Matrix<Real> & integration_points,
       Array<Real> & shape_derivatives, GhostType ghost_type,
       const Array<UInt> & filter_elements = empty_filter) const;
 
   void computeShapeDerivativesOnIntegrationPoints(
       const Array<Real> & nodes, const Matrix<Real> & integration_points,
-      Array<Real> & shape_derivatives, ElementType type,
-      GhostType ghost_type,
+      Array<Real> & shape_derivatives, ElementType type, GhostType ghost_type,
       const Array<UInt> & filter_elements) const override;
 
+  /// computes the shape functions variations for spatial dim != natural dim
+  template <ElementType type>
+  void computeShapeDerivativesOnIntegrationPoints1DIn2D(
+      const Array<Real> & nodes, const Matrix<Real> & integration_points,
+      Array<Real> & shape_derivatives, const GhostType & ghost_type,
+      const Array<UInt> & filter_elements = empty_filter) const;
+
   /// pre compute all shapes on the element integration points from natural
   /// coordinates
   template <ElementType type>
   void precomputeShapesOnIntegrationPoints(const Array<Real> & nodes,
                                            GhostType ghost_type);
 
   /// pre compute all shape derivatives on the element integration points from
   /// natural coordinates
   template <ElementType type>
-  void
-  precomputeShapeDerivativesOnIntegrationPoints(const Array<Real> & nodes,
-                                                GhostType ghost_type);
+  void precomputeShapeDerivativesOnIntegrationPoints(const Array<Real> & nodes,
+                                                     GhostType ghost_type);
 
   /// interpolate nodal values on the integration points
   template <ElementType type>
   void interpolateOnIntegrationPoints(
       const Array<Real> & u, Array<Real> & uq, UInt nb_degree_of_freedom,
       GhostType ghost_type = _not_ghost,
       const Array<UInt> & filter_elements = empty_filter) const;
 
   template <ElementType type>
   void interpolateOnIntegrationPoints(
       const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom,
       const Array<Real> & shapes, GhostType ghost_type = _not_ghost,
       const Array<UInt> & filter_elements = empty_filter) const;
 
   /// interpolate on physical point
   template <ElementType type>
   void interpolate(const Vector<Real> & real_coords, UInt elem,
                    const Matrix<Real> & nodal_values,
-                   Vector<Real> & interpolated,
-                   GhostType ghost_type) const;
+                   Vector<Real> & interpolated, GhostType ghost_type) const;
 
   /// compute the gradient of u on the integration points
   template <ElementType type>
   void gradientOnIntegrationPoints(
       const Array<Real> & u, Array<Real> & nablauq, UInt nb_degree_of_freedom,
       GhostType ghost_type = _not_ghost,
       const Array<UInt> & filter_elements = empty_filter) const;
 
   template <ElementType type>
   void computeBtD(const Array<Real> & Ds, Array<Real> & BtDs,
                   GhostType ghost_type,
                   const Array<UInt> & filter_elements) const;
 
   template <ElementType type>
   void computeBtDB(const Array<Real> & Ds, Array<Real> & BtDBs, UInt order_d,
                    GhostType ghost_type,
                    const Array<UInt> & filter_elements) const;
 
   /// multiply a field by shape functions  @f$ fts_{ij} = f_i * \varphi_j @f$
   template <ElementType type>
   void computeNtb(const Array<Real> & bs, Array<Real> & Ntbs,
                   GhostType ghost_type,
                   const Array<UInt> & filter_elements = empty_filter) const;
 
   template <ElementType type>
   void computeNtbN(const Array<Real> & bs, Array<Real> & NtbNs,
                    GhostType ghost_type,
                    const Array<UInt> & filter_elements) const;
 
   /// find natural coords from real coords provided an element
   template <ElementType type>
   void inverseMap(const Vector<Real> & real_coords, UInt element,
                   Vector<Real> & natural_coords,
                   GhostType ghost_type = _not_ghost) const;
 
   /// return true if the coordinates provided are inside the element, false
   /// otherwise
   template <ElementType type>
   bool contains(const Vector<Real> & real_coords, UInt elem,
                 GhostType ghost_type) const;
 
   /// compute the shape on a provided point
   template <ElementType type>
   void computeShapes(const Vector<Real> & real_coords, UInt elem,
                      Vector<Real> & shapes, GhostType ghost_type) const;
 
   /// compute the shape derivatives on a provided point
   template <ElementType type>
   void computeShapeDerivatives(const Matrix<Real> & real_coords, UInt elem,
                                Tensor3<Real> & shapes,
                                GhostType ghost_type) const;
 
 protected:
   /// compute the shape derivatives on integration points for a given element
   template <ElementType type>
   inline void
   computeShapeDerivativesOnCPointsByElement(const Matrix<Real> & node_coords,
                                             const Matrix<Real> & natural_coords,
                                             Tensor3<Real> & shapesd) const;
 };
 
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 /* inline functions                                                           */
 /* -------------------------------------------------------------------------- */
 #include "shape_lagrange_inline_impl.hh"
 
 #endif /* AKANTU_SHAPE_LAGRANGE_HH_ */
diff --git a/src/fe_engine/shape_lagrange_inline_impl.hh b/src/fe_engine/shape_lagrange_inline_impl.hh
index 0cd7ee9c4..6fa81e2fd 100644
--- a/src/fe_engine/shape_lagrange_inline_impl.hh
+++ b/src/fe_engine/shape_lagrange_inline_impl.hh
@@ -1,579 +1,651 @@
 /**
  * @file   shape_lagrange_inline_impl.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Wed Oct 27 2010
  * @date last modification: Tue Feb 20 2018
  *
  * @brief  ShapeLagrange inline implementation
  *
  *
  * Copyright (©)  2010-2018 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_iterators.hh"
 #include "aka_voigthelper.hh"
 #include "fe_engine.hh"
 #include "shape_lagrange.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef AKANTU_SHAPE_LAGRANGE_INLINE_IMPL_HH_
 #define AKANTU_SHAPE_LAGRANGE_INLINE_IMPL_HH_
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 #define INIT_SHAPE_FUNCTIONS(type)                                             \
   setIntegrationPointsByType<type>(integration_points, ghost_type);            \
   precomputeShapesOnIntegrationPoints<type>(nodes, ghost_type);                \
   if (ElementClass<type>::getNaturalSpaceDimension() ==                        \
           mesh.getSpatialDimension() ||                                        \
       kind != _ek_regular)                                                     \
     precomputeShapeDerivativesOnIntegrationPoints<type>(nodes, ghost_type);
 
 template <ElementKind kind>
 inline void ShapeLagrange<kind>::initShapeFunctions(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     ElementType type, GhostType ghost_type) {
   AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(INIT_SHAPE_FUNCTIONS);
 }
 
 #undef INIT_SHAPE_FUNCTIONS
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 inline void ShapeLagrange<kind>::computeShapeDerivativesOnCPointsByElement(
     const Matrix<Real> & node_coords, const Matrix<Real> & natural_coords,
     Tensor3<Real> & shapesd) const {
   AKANTU_DEBUG_IN();
 
   // compute dnds
   Tensor3<Real> dnds(node_coords.rows(), node_coords.cols(),
                      natural_coords.cols());
   ElementClass<type>::computeDNDS(natural_coords, dnds);
   // compute jacobian
   Tensor3<Real> J(node_coords.rows(), natural_coords.rows(),
                   natural_coords.cols());
   ElementClass<type>::computeJMat(dnds, node_coords, J);
 
   // compute dndx
   ElementClass<type>::computeShapeDerivatives(J, dnds, shapesd);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::inverseMap(const Vector<Real> & real_coords,
                                      UInt elem, Vector<Real> & natural_coords,
                                      GhostType ghost_type) const {
 
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   UInt nb_nodes_per_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
 
   UInt * elem_val = mesh.getConnectivity(type, ghost_type).storage();
   Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element);
 
   mesh.extractNodalValuesFromElement(mesh.getNodes(), nodes_coord.storage(),
                                      elem_val + elem * nb_nodes_per_element,
                                      nb_nodes_per_element, spatial_dimension);
 
   ElementClass<type>::inverseMap(real_coords, nodes_coord, natural_coords);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 bool ShapeLagrange<kind>::contains(const Vector<Real> & real_coords, UInt elem,
                                    GhostType ghost_type) const {
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   Vector<Real> natural_coords(spatial_dimension);
 
   inverseMap<type>(real_coords, elem, natural_coords, ghost_type);
   return ElementClass<type>::contains(natural_coords);
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::interpolate(const Vector<Real> & real_coords,
                                       UInt elem,
                                       const Matrix<Real> & nodal_values,
                                       Vector<Real> & interpolated,
                                       GhostType ghost_type) const {
   UInt nb_shapes = ElementClass<type>::getShapeSize();
   Vector<Real> shapes(nb_shapes);
   computeShapes<type>(real_coords, elem, shapes, ghost_type);
   ElementClass<type>::interpolate(nodal_values, shapes, interpolated);
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::computeShapes(const Vector<Real> & real_coords,
                                         UInt elem, Vector<Real> & shapes,
                                         GhostType ghost_type) const {
 
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   Vector<Real> natural_coords(spatial_dimension);
 
   inverseMap<type>(real_coords, elem, natural_coords, ghost_type);
   ElementClass<type>::computeShapes(natural_coords, shapes);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::computeShapeDerivatives(
     const Matrix<Real> & real_coords, UInt elem, Tensor3<Real> & shapesd,
     GhostType ghost_type) const {
 
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
   UInt nb_points = real_coords.cols();
   UInt nb_nodes_per_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
 
   AKANTU_DEBUG_ASSERT(mesh.getSpatialDimension() == shapesd.size(0) &&
                           nb_nodes_per_element == shapesd.size(1),
                       "Shape size doesn't match");
   AKANTU_DEBUG_ASSERT(nb_points == shapesd.size(2),
                       "Number of points doesn't match shapes size");
 
   Matrix<Real> natural_coords(spatial_dimension, nb_points);
 
   // Creates the matrix of natural coordinates
   for (UInt i = 0; i < nb_points; i++) {
     Vector<Real> real_point = real_coords(i);
     Vector<Real> natural_point = natural_coords(i);
 
     inverseMap<type>(real_point, elem, natural_point, ghost_type);
   }
 
   UInt * elem_val = mesh.getConnectivity(type, ghost_type).storage();
   Matrix<Real> nodes_coord(spatial_dimension, nb_nodes_per_element);
 
   mesh.extractNodalValuesFromElement(mesh.getNodes(), nodes_coord.storage(),
                                      elem_val + elem * nb_nodes_per_element,
                                      nb_nodes_per_element, spatial_dimension);
 
   computeShapeDerivativesOnCPointsByElement<type>(nodes_coord, natural_coords,
                                                   shapesd);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 ShapeLagrange<kind>::ShapeLagrange(const Mesh & mesh, UInt spatial_dimension,
                                    const ID & id)
     : ShapeLagrangeBase(mesh, spatial_dimension, kind, id) {}
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::computeShapeDerivativesOnIntegrationPoints(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     Array<Real> & shape_derivatives, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   UInt spatial_dimension = mesh.getSpatialDimension();
 
   UInt nb_nodes_per_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
 
   UInt nb_points = integration_points.cols();
   UInt nb_element = mesh.getConnectivity(type, ghost_type).size();
 
   UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize();
   AKANTU_DEBUG_ASSERT(shape_derivatives.getNbComponent() == size_of_shapesd,
                       "The shapes_derivatives array does not have the correct "
                           << "number of component");
   shape_derivatives.resize(nb_element * nb_points);
 
   Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element);
   FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type,
                                        filter_elements);
 
   Real * shapesd_val = shape_derivatives.storage();
   Array<Real>::matrix_iterator x_it =
       x_el.begin(spatial_dimension, nb_nodes_per_element);
 
   if (filter_elements != empty_filter) {
     nb_element = filter_elements.size();
   }
 
   for (UInt elem = 0; elem < nb_element; ++elem, ++x_it) {
     if (filter_elements != empty_filter) {
       shapesd_val = shape_derivatives.storage() +
                     filter_elements(elem) * size_of_shapesd * nb_points;
     }
 
     Matrix<Real> & X = *x_it;
     Tensor3<Real> B(shapesd_val, spatial_dimension, nb_nodes_per_element,
                     nb_points);
     computeShapeDerivativesOnCPointsByElement<type>(X, integration_points, B);
 
     if (filter_elements == empty_filter) {
       shapesd_val += size_of_shapesd * nb_points;
     }
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 void ShapeLagrange<kind>::computeShapeDerivativesOnIntegrationPoints(
     const Array<Real> & nodes, const Matrix<Real> & integration_points,
     Array<Real> & shape_derivatives, ElementType type, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
 #define AKANTU_COMPUTE_SHAPES(type)                                            \
   computeShapeDerivativesOnIntegrationPoints<type>(                            \
       nodes, integration_points, shape_derivatives, ghost_type,                \
       filter_elements);
 
   AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES);
 
 #undef AKANTU_COMPUTE_SHAPES
 }
+/* -------------------------------------------------------------------------- */
+template <ElementKind kind>
+template <ElementType type>
+void ShapeLagrange<kind>::computeShapeDerivativesOnIntegrationPoints1DIn2D(
+    const Array<Real> & nodes, const Matrix<Real> & integration_points,
+    Array<Real> & shape_derivatives, const GhostType & ghost_type,
+    const Array<UInt> & filter_elements) const {
+  AKANTU_DEBUG_IN();
+
+  UInt spatial_dimension = mesh.getSpatialDimension();
+  UInt element_dimension = ElementClass<type>::getNaturalSpaceDimension();
+
+  UInt nb_nodes_per_element =
+      ElementClass<type>::getNbNodesPerInterpolationElement();
+
+  UInt nb_points = integration_points.cols();
+  UInt nb_element = mesh.getConnectivity(type, ghost_type).size();
+
+  UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize();
+  AKANTU_DEBUG_ASSERT(shape_derivatives.getNbComponent() == size_of_shapesd,
+                      "The shapes_derivatives array does not have the correct "
+                          << "number of component");
+  shape_derivatives.resize(nb_element * nb_points);
+
+  Array<Real> x_el(0, spatial_dimension * nb_nodes_per_element);
+  FEEngine::extractNodalToElementField(mesh, nodes, x_el, type, ghost_type,
+                                       filter_elements);
+
+  Real * shapesd_val = shape_derivatives.storage();
+  Array<Real>::matrix_iterator x_it =
+      x_el.begin(spatial_dimension, nb_nodes_per_element);
+
+  /// array of equivalent coordinates (works for 1D element in 2D only)
+  Array<Real> x_el_equiv(nb_element, element_dimension * nb_nodes_per_element);
+  for (auto && data :
+       zip(make_view(x_el, spatial_dimension, nb_nodes_per_element),
+           make_view(x_el_equiv, element_dimension, nb_nodes_per_element))) {
+    const Matrix<Real> & x = std::get<0>(data);
+    auto & x_eq = std::get<1>(data);
+    for (auto node_nb : arange(1, nb_nodes_per_element)) {
+      Vector<Real> delta_x = Vector<Real>(x(node_nb)) - Vector<Real>(x(0));
+      x_eq(element_dimension - 1, node_nb) = delta_x.norm();
+    }
+  }
+
+  if (filter_elements != empty_filter)
+    nb_element = filter_elements.size();
 
+  for (auto && data : enumerate(
+           make_view(x_el_equiv, element_dimension, nb_nodes_per_element))) {
+    auto & elem = std::get<0>(data);
+    const auto & X = std::get<1>(data);
+    if (filter_elements != empty_filter)
+      shapesd_val = shape_derivatives.storage() +
+                    filter_elements(elem) * size_of_shapesd * nb_points;
+
+    Tensor3<Real> B(shapesd_val, element_dimension, nb_nodes_per_element,
+                    nb_points);
+    computeShapeDerivativesOnCPointsByElement<type>(X, integration_points, B);
+
+    if (filter_elements == empty_filter)
+      shapesd_val += size_of_shapesd * nb_points;
+  }
+
+  AKANTU_DEBUG_OUT();
+}
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::precomputeShapesOnIntegrationPoints(
     const Array<Real> & nodes, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
   Matrix<Real> & natural_coords = integration_points(type, ghost_type);
   UInt size_of_shapes = ElementClass<type>::getShapeSize();
 
   Array<Real> & shapes_tmp =
       shapes.alloc(0, size_of_shapes, itp_type, ghost_type);
 
   this->computeShapesOnIntegrationPoints<type>(nodes, natural_coords,
                                                shapes_tmp, ghost_type);
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::precomputeShapeDerivativesOnIntegrationPoints(
     const Array<Real> & nodes, GhostType ghost_type) {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
   Matrix<Real> & natural_coords = integration_points(type, ghost_type);
   UInt size_of_shapesd = ElementClass<type>::getShapeDerivativesSize();
+  UInt spatial_dimension = mesh.getSpatialDimension();
+  UInt natural_dimension = ElementClass<type>::getNaturalSpaceDimension();
 
   Array<Real> & shapes_derivatives_tmp =
       shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type);
 
-  this->computeShapeDerivativesOnIntegrationPoints<type>(
-      nodes, natural_coords, shapes_derivatives_tmp, ghost_type);
+  if (spatial_dimension != natural_dimension) {
+    this->computeShapeDerivativesOnIntegrationPoints1DIn2D<type>(
+        nodes, natural_coords, shapes_derivatives_tmp, ghost_type);
+  } else {
+    this->computeShapeDerivativesOnIntegrationPoints<type>(
+        nodes, natural_coords, shapes_derivatives_tmp, ghost_type);
+  }
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::interpolateOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom,
     const Array<Real> & shapes, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   UInt nb_nodes_per_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
 
   Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element);
   FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type,
                                        filter_elements);
 
   this->interpolateElementalFieldOnIntegrationPoints<type>(
       u_el, out_uq, ghost_type, shapes, filter_elements);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::interpolateOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_uq, UInt nb_degree_of_freedom,
     GhostType ghost_type, const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
   AKANTU_DEBUG_ASSERT(shapes.exists(itp_type, ghost_type),
                       "No shapes for the type "
                           << shapes.printType(itp_type, ghost_type));
 
   this->interpolateOnIntegrationPoints<type>(in_u, out_uq, nb_degree_of_freedom,
                                              shapes(itp_type, ghost_type),
                                              ghost_type, filter_elements);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::gradientOnIntegrationPoints(
     const Array<Real> & in_u, Array<Real> & out_nablauq,
     UInt nb_degree_of_freedom, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   InterpolationType itp_type = ElementClassProperty<type>::interpolation_type;
   AKANTU_DEBUG_ASSERT(
       shapes_derivatives.exists(itp_type, ghost_type),
       "No shapes derivatives for the type "
           << shapes_derivatives.printType(itp_type, ghost_type));
 
   UInt nb_nodes_per_element =
       ElementClass<type>::getNbNodesPerInterpolationElement();
 
   Array<Real> u_el(0, nb_degree_of_freedom * nb_nodes_per_element);
   FEEngine::extractNodalToElementField(mesh, in_u, u_el, type, ghost_type,
                                        filter_elements);
 
   this->gradientElementalFieldOnIntegrationPoints<type>(
       u_el, out_nablauq, ghost_type, shapes_derivatives(itp_type, ghost_type),
       filter_elements);
 
   AKANTU_DEBUG_OUT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::computeBtD(
     const Array<Real> & Ds, Array<Real> & BtDs, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
   auto itp_type = ElementClassProperty<type>::interpolation_type;
   const auto & shapes_derivatives =
       this->shapes_derivatives(itp_type, ghost_type);
 
-  auto spatial_dimension = mesh.getSpatialDimension();
+  auto spatial_dimension = ElementClass<type>::getNaturalSpaceDimension();
   auto nb_nodes_per_element = mesh.getNbNodesPerElement(type);
 
   Array<Real> shapes_derivatives_filtered(0,
                                           shapes_derivatives.getNbComponent());
   auto && view =
       make_view(shapes_derivatives, spatial_dimension, nb_nodes_per_element);
   auto B_it = view.begin();
   auto B_end = view.end();
 
   if (filter_elements != empty_filter) {
     FEEngine::filterElementalData(this->mesh, shapes_derivatives,
                                   shapes_derivatives_filtered, type, ghost_type,
                                   filter_elements);
     auto && view = make_view(shapes_derivatives_filtered, spatial_dimension,
                              nb_nodes_per_element);
     B_it = view.begin();
     B_end = view.end();
   }
 
   for (auto && values :
        zip(range(B_it, B_end),
            make_view(Ds, Ds.getNbComponent() / spatial_dimension,
                      spatial_dimension),
            make_view(BtDs, BtDs.getNbComponent() / nb_nodes_per_element,
                      nb_nodes_per_element))) {
     const auto & B = std::get<0>(values);
     const auto & D = std::get<1>(values);
     auto & Bt_D = std::get<2>(values);
     // transposed due to the storage layout of B
     Bt_D.template mul<false, false>(D, B);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::computeBtDB(
     const Array<Real> & Ds, Array<Real> & BtDBs, UInt order_d,
     GhostType ghost_type, const Array<UInt> & filter_elements) const {
   auto itp_type = ElementClassProperty<type>::interpolation_type;
   const auto & shapes_derivatives =
       this->shapes_derivatives(itp_type, ghost_type);
 
   constexpr auto dim = ElementClass<type>::getSpatialDimension();
   auto nb_nodes_per_element = mesh.getNbNodesPerElement(type);
 
   Array<Real> shapes_derivatives_filtered(0,
                                           shapes_derivatives.getNbComponent());
   auto && view = make_view(shapes_derivatives, dim, nb_nodes_per_element);
   auto B_it = view.begin();
   auto B_end = view.end();
 
   if (filter_elements != empty_filter) {
     FEEngine::filterElementalData(this->mesh, shapes_derivatives,
                                   shapes_derivatives_filtered, type, ghost_type,
                                   filter_elements);
     auto && view =
         make_view(shapes_derivatives_filtered, dim, nb_nodes_per_element);
     B_it = view.begin();
     B_end = view.end();
   }
 
   if (order_d == 4) {
     UInt tangent_size = VoigtHelper<dim>::size;
     Matrix<Real> B(tangent_size, dim * nb_nodes_per_element);
     Matrix<Real> Bt_D(dim * nb_nodes_per_element, tangent_size);
 
     for (auto && values :
          zip(range(B_it, B_end), make_view(Ds, tangent_size, tangent_size),
              make_view(BtDBs, dim * nb_nodes_per_element,
                        dim * nb_nodes_per_element))) {
       const auto & Bfull = std::get<0>(values);
       const auto & D = std::get<1>(values);
       auto & Bt_D_B = std::get<2>(values);
 
       VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(Bfull, B,
                                                          nb_nodes_per_element);
       Bt_D.template mul<true, false>(B, D);
       Bt_D_B.template mul<false, false>(Bt_D, B);
     }
   } else if (order_d == 2) {
     Matrix<Real> Bt_D(nb_nodes_per_element, dim);
     for (auto && values :
          zip(range(B_it, B_end), make_view(Ds, dim, dim),
              make_view(BtDBs, nb_nodes_per_element, nb_nodes_per_element))) {
       const auto & B = std::get<0>(values);
       const auto & D = std::get<1>(values);
       auto & Bt_D_B = std::get<2>(values);
       Bt_D.template mul<true, false>(B, D);
       Bt_D_B.template mul<false, false>(Bt_D, B);
     }
   }
 }
 
 template <>
 template <>
 inline void ShapeLagrange<_ek_regular>::computeBtDB<_point_1>(
     const Array<Real> & /*Ds*/, Array<Real> & /*BtDBs*/, UInt /*order_d*/,
     GhostType /*ghost_type*/, const Array<UInt> & /*filter_elements*/) const {
   AKANTU_TO_IMPLEMENT();
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::computeNtbN(
     const Array<Real> & bs, Array<Real> & NtbNs, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
 
   auto itp_type = ElementClassProperty<type>::interpolation_type;
   auto size_of_shapes = ElementClass<type>::getShapeSize();
   auto nb_degree_of_freedom = bs.getNbComponent();
 
   auto nb_nodes_per_element = mesh.getNbNodesPerElement(type);
   Array<Real> shapes_filtered(0, size_of_shapes);
 
   auto && view = make_view(shapes(itp_type, ghost_type), 1, size_of_shapes);
   auto N_it = view.begin();
   auto N_end = view.end();
 
   if (filter_elements != empty_filter) {
     FEEngine::filterElementalData(this->mesh, shapes(itp_type, ghost_type),
                                   shapes_filtered, type, ghost_type,
                                   filter_elements);
     auto && view = make_view(shapes_filtered, 1, size_of_shapes);
     N_it = view.begin();
     N_end = view.end();
   }
 
   Matrix<Real> Nt_b(nb_nodes_per_element, nb_degree_of_freedom);
   for (auto && values :
        zip(range(N_it, N_end), make_view(bs, nb_degree_of_freedom, 1),
            make_view(NtbNs, nb_nodes_per_element, nb_nodes_per_element))) {
     const auto & N = std::get<0>(values);
     const auto & b = std::get<1>(values);
     auto & Nt_b_N = std::get<2>(values);
     Nt_b.template mul<true, false>(N, b);
     Nt_b_N.template mul<false, false>(Nt_b, N);
   }
 }
 
 /* -------------------------------------------------------------------------- */
 template <ElementKind kind>
 template <ElementType type>
 void ShapeLagrange<kind>::computeNtb(
     const Array<Real> & bs, Array<Real> & Ntbs, GhostType ghost_type,
     const Array<UInt> & filter_elements) const {
   AKANTU_DEBUG_IN();
 
   Ntbs.resize(bs.size());
 
   auto size_of_shapes = ElementClass<type>::getShapeSize();
   auto itp_type = ElementClassProperty<type>::interpolation_type;
   auto nb_degree_of_freedom = bs.getNbComponent();
 
   Array<Real> shapes_filtered(0, size_of_shapes);
   auto && view = make_view(shapes(itp_type, ghost_type), 1, size_of_shapes);
   auto N_it = view.begin();
   auto N_end = view.end();
 
   if (filter_elements != empty_filter) {
     FEEngine::filterElementalData(this->mesh, shapes(itp_type, ghost_type),
                                   shapes_filtered, type, ghost_type,
                                   filter_elements);
     auto && view = make_view(shapes_filtered, 1, size_of_shapes);
     N_it = view.begin();
     N_end = view.end();
   }
 
   for (auto && values :
        zip(make_view(bs, nb_degree_of_freedom, 1), range(N_it, N_end),
            make_view(Ntbs, nb_degree_of_freedom, size_of_shapes))) {
     const auto & b = std::get<0>(values);
     const auto & N = std::get<1>(values);
     auto & Ntb = std::get<2>(values);
 
     Ntb.template mul<false, false>(b, N);
   }
 
   AKANTU_DEBUG_OUT();
 }
 
 } // namespace akantu
 
 #endif /* AKANTU_SHAPE_LAGRANGE_INLINE_IMPL_HH_ */
diff --git a/src/mesh/element_type_map.cc b/src/mesh/element_type_map.cc
index 1e8a45c53..35faa4efd 100644
--- a/src/mesh/element_type_map.cc
+++ b/src/mesh/element_type_map.cc
@@ -1,73 +1,69 @@
 /**
  * @file   element_type_map.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Tue Feb 20 2018
  *
  * @brief  A Documented file.
  *
  *
  * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "fe_engine.hh"
 #include "mesh.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer(
     const FEEngine & fe_engine, UInt nb_component, UInt spatial_dimension,
     GhostType ghost_type, ElementKind element_kind)
-    : MeshElementTypeMapArrayInitializer(
-          fe_engine.getMesh(), nb_component,
-          spatial_dimension == UInt(-2)
-              ? fe_engine.getMesh().getSpatialDimension()
-              : spatial_dimension,
-          ghost_type, element_kind, true, false),
+    : MeshElementTypeMapArrayInitializer(fe_engine.getMesh(), nb_component,
+                                         spatial_dimension == UInt(-2)
+                                             ? fe_engine.getElementDimension()
+                                             : spatial_dimension,
+                                         ghost_type, element_kind, true, false),
       fe_engine(fe_engine) {}
 
 FEEngineElementTypeMapArrayInitializer::FEEngineElementTypeMapArrayInitializer(
     const FEEngine & fe_engine,
     const ElementTypeMapArrayInitializer::CompFunc & nb_component,
-    UInt spatial_dimension, GhostType ghost_type,
-    ElementKind element_kind)
-    : MeshElementTypeMapArrayInitializer(
-          fe_engine.getMesh(), nb_component,
-          spatial_dimension == UInt(-2)
-              ? fe_engine.getMesh().getSpatialDimension()
-              : spatial_dimension,
-          ghost_type, element_kind, true, false),
+    UInt spatial_dimension, GhostType ghost_type, ElementKind element_kind)
+    : MeshElementTypeMapArrayInitializer(fe_engine.getMesh(), nb_component,
+                                         spatial_dimension == UInt(-2)
+                                             ? fe_engine.getElementDimension()
+                                             : spatial_dimension,
+                                         ghost_type, element_kind, true, false),
       fe_engine(fe_engine) {}
 
-UInt FEEngineElementTypeMapArrayInitializer::size(
-    ElementType type) const {
+UInt FEEngineElementTypeMapArrayInitializer::size(ElementType type) const {
   return MeshElementTypeMapArrayInitializer::size(type) *
          fe_engine.getNbIntegrationPoints(type, this->ghost_type);
 }
 
 FEEngineElementTypeMapArrayInitializer::ElementTypesIteratorHelper
 FEEngineElementTypeMapArrayInitializer::elementTypes() const {
   return this->fe_engine.elementTypes(spatial_dimension, ghost_type,
                                       element_kind);
 }
 
 } // namespace akantu
diff --git a/src/model/common/integration_scheme/integration_scheme.cc b/src/model/common/integration_scheme/integration_scheme.cc
index 9fea35044..5a68bf6aa 100644
--- a/src/model/common/integration_scheme/integration_scheme.cc
+++ b/src/model/common/integration_scheme/integration_scheme.cc
@@ -1,92 +1,96 @@
 /**
  * @file   integration_scheme.cc
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Tue Aug 18 2015
  * @date last modification: Wed Jan 31 2018
  *
  * @brief  Common interface to all interface schemes
  *
  *
  * Copyright (©) 2015-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
  * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
  *
  * Akantu is free  software: you can redistribute it and/or  modify it under the
  * terms  of the  GNU Lesser  General Public  License as published by  the Free
  * Software Foundation, either version 3 of the License, or (at your option) any
  * later version.
  *
  * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
  * details.
  *
  * You should  have received  a copy  of the GNU  Lesser General  Public License
  * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* -------------------------------------------------------------------------- */
 #include "integration_scheme.hh"
 #include "dof_manager.hh"
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 IntegrationScheme::IntegrationScheme(DOFManager & dof_manager,
                                      const ID & dof_id, UInt order)
     : Parsable(ParserType::_integration_scheme, dof_id),
-      dof_manager(dof_manager), dof_id(dof_id), order(order), u_store(order + 1) {}
+      dof_manager(dof_manager), dof_id(dof_id), order(order),
+      u_store(order + 1) {}
 
 /* -------------------------------------------------------------------------- */
 /// standard input stream operator for SolutionType
 std::istream & operator>>(std::istream & stream,
                           IntegrationScheme::SolutionType & type) {
   std::string str;
   stream >> str;
   if (str == "displacement") {
     type = IntegrationScheme::_displacement;
   } else if (str == "temperature") {
     type = IntegrationScheme::_temperature;
   } else if (str == "velocity") {
     type = IntegrationScheme::_velocity;
   } else if (str == "temperature_rate") {
     type = IntegrationScheme::_temperature_rate;
+  } else if (str == "pressure") {
+    type = IntegrationScheme::_pressure;
+  } else if (str == "pressure_rate") {
+    type = IntegrationScheme::_pressure_rate;
   } else if (str == "acceleration") {
     type = IntegrationScheme::_acceleration;
   } else if (str == "damage") {
     type = IntegrationScheme::_damage;
   } else {
     stream.setstate(std::ios::failbit);
   }
 
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 void IntegrationScheme::store() {
   for (auto data : enumerate(u_store)) {
     auto o = std::get<0>(data);
     auto & u_store = std::get<1>(data);
     auto & u_o = dof_manager.getDOFsDerivatives(dof_id, o);
     if (not u_store) {
       u_store = std::make_unique<Array<Real>>(
           u_o, "integration_scheme_store:" + dof_id + ":" + std::to_string(o));
     } else {
       u_store->copy(u_o);
     }
   }
 }
 
 /* -------------------------------------------------------------------------- */
 void IntegrationScheme::restore() {
   for (auto o : arange(order)) {
     auto & u_o = dof_manager.getDOFsDerivatives(dof_id, o);
     u_o.copy(*u_store[o]);
   }
 }
 
-
 } // namespace akantu
diff --git a/src/model/common/integration_scheme/integration_scheme.hh b/src/model/common/integration_scheme/integration_scheme.hh
index c6706df0a..f9c7eecd8 100644
--- a/src/model/common/integration_scheme/integration_scheme.hh
+++ b/src/model/common/integration_scheme/integration_scheme.hh
@@ -1,123 +1,125 @@
 /**
  * @file   integration_scheme.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Wed Jan 31 2018
  *
  * @brief  This class is just a base class for the integration schemes
  *
  *
  * Copyright (©)  2010-2018 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 "parsable.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef AKANTU_INTEGRATION_SCHEME_HH_
 #define AKANTU_INTEGRATION_SCHEME_HH_
 
 namespace akantu {
 class DOFManager;
 }
 
 namespace akantu {
 
 class IntegrationScheme : public Parsable {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   enum SolutionType {
     _not_defined = -1,
     _displacement = 0,
     _temperature = 0,
+    _pressure = 0,
     _damage = 0,
     _velocity = 1,
     _temperature_rate = 1,
+    _pressure_rate = 1,
     _acceleration = 2,
   };
 
   IntegrationScheme(DOFManager & dof_manager, const ID & dof_id, UInt order);
   ~IntegrationScheme() override = default;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 public:
   /// generic interface of a predictor
   virtual void predictor(Real delta_t) = 0;
 
   /// generic interface of a corrector
   virtual void corrector(const SolutionType & type, Real delta_t) = 0;
 
   /// assemble the jacobian matrix
   virtual void assembleJacobian(const SolutionType & type, Real delta_t) = 0;
 
   /// assemble the residual
   virtual void assembleResidual(bool is_lumped) = 0;
 
   /// returns a list of needed matrices
   virtual std::vector<std::string> getNeededMatrixList() = 0;
 
   /// store dofs info (beginning of steps)
   virtual void store();
 
   /// restore dofs (solve failed)
   virtual void restore();
 
   /* ------------------------------------------------------------------------ */
   /* Accessors                                                                */
   /* ------------------------------------------------------------------------ */
 public:
   /// return the order of the integration scheme
   UInt getOrder() const;
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   /// The underlying DOFManager
   DOFManager & dof_manager;
 
   /// The id of the dof treated by this integration scheme.
   ID dof_id;
 
   /// The order of the integrator
   UInt order;
 
   /// last release of M matrix
   UInt m_release{UInt(-1)};
 
   /// stores the values at begining of solve
   std::vector<std::unique_ptr<Array<Real>>> u_store;
 };
 
 /* -------------------------------------------------------------------------- */
 // std::ostream & operator<<(std::ostream & stream,
 //                           const IntegrationScheme::SolutionType & type);
 std::istream & operator>>(std::istream & stream,
                           IntegrationScheme::SolutionType & type);
 /* -------------------------------------------------------------------------- */
 
 } // namespace akantu
 
 #endif /* AKANTU_INTEGRATION_SCHEME_HH_ */
diff --git a/src/model/fluid_diffusion/fluid_diffusion_model.cc b/src/model/fluid_diffusion/fluid_diffusion_model.cc
new file mode 100644
index 000000000..c876c1f7c
--- /dev/null
+++ b/src/model/fluid_diffusion/fluid_diffusion_model.cc
@@ -0,0 +1,1273 @@
+/**
+ * @file   fluid_diffusion_model.hh
+ *
+ * @author Emil Gallyamov <emil.gallyamov@epfl.ch>
+ *
+ * @date creation: Aug 2019
+ *
+ * @brief  Implementation of Transient fluid diffusion model
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2010-2018 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 "fluid_diffusion_model.hh"
+#include "dumpable_inline_impl.hh"
+#include "element_synchronizer.hh"
+#include "fe_engine_template.hh"
+#include "generalized_trapezoidal.hh"
+#include "group_manager_inline_impl.hh"
+#include "integrator_gauss.hh"
+#include "mesh.hh"
+#include "parser.hh"
+#include "shape_lagrange.hh"
+
+#ifdef AKANTU_USE_IOHELPER
+#include "dumper_element_partition.hh"
+#include "dumper_elemental_field.hh"
+#include "dumper_internal_material_field.hh"
+#include "dumper_iohelper_paraview.hh"
+#endif
+
+/* -------------------------------------------------------------------------- */
+namespace akantu {
+
+namespace fluid_diffusion {
+  namespace details {
+    class ComputeRhoFunctor {
+    public:
+      ComputeRhoFunctor(const FluidDiffusionModel & model) : model(model){};
+
+      void operator()(Matrix<Real> & rho, const Element & element) const {
+        const auto & type = element.type;
+        const auto & gt = element.ghost_type;
+        const auto & aperture = model.getApertureOnQpoints(type, gt);
+        auto nb_quad_points = aperture.getNbComponent();
+        Real aperture_av = 0.;
+        for (auto q : arange(nb_quad_points)) {
+          aperture_av += aperture(element.element, q);
+        }
+        aperture_av /= nb_quad_points;
+        if (model.isModelVelocityDependent()) {
+          rho.set(model.getCompressibility() * aperture_av);
+        } else {
+          rho.set((model.getCompressibility() + model.getPushability()) *
+                  aperture_av);
+        }
+      }
+
+    private:
+      const FluidDiffusionModel & model;
+    };
+  } // namespace details
+} // namespace fluid_diffusion
+
+/* -------------------------------------------------------------------------- */
+FluidDiffusionModel::FluidDiffusionModel(Mesh & mesh, UInt dim, const ID & id)
+    : Model(mesh, ModelType::_fluid_diffusion_model, dim, id),
+      pressure_gradient("pressure_gradient", id),
+      pressure_on_qpoints("pressure_on_qpoints", id),
+      delta_pres_on_qpoints("delta_pres_on_qpoints", id),
+      permeability_on_qpoints("permeability_on_qpoints", id),
+      aperture_on_qpoints("aperture_on_qpoints", id),
+      prev_aperture_on_qpoints("prev_aperture_on_qpoints", id),
+      k_gradp_on_qpoints("k_gradp_on_qpoints", id) {
+  AKANTU_DEBUG_IN();
+
+  // mesh.registerEventHandler(*this, akantu::_ehp_lowest);
+
+  this->spatial_dimension = std::max(1, int(mesh.getSpatialDimension()) - 1);
+
+  this->initDOFManager();
+
+  this->registerDataAccessor(*this);
+
+  if (this->mesh.isDistributed()) {
+    auto & synchronizer = this->mesh.getElementSynchronizer();
+    this->registerSynchronizer(synchronizer, SynchronizationTag::_fdm_pressure);
+    this->registerSynchronizer(synchronizer,
+                               SynchronizationTag::_fdm_gradient_pressure);
+  }
+
+  registerFEEngineObject<FEEngineType>(id + ":fem", mesh, spatial_dimension);
+
+#ifdef AKANTU_USE_IOHELPER
+  this->mesh.registerDumper<DumperParaview>("fluid_diffusion", id, true);
+  this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular);
+#endif
+
+  this->registerParam("viscosity", viscosity, 1., _pat_parsmod);
+  this->registerParam("compressibility", compressibility, 1., _pat_parsmod);
+  this->registerParam("default_aperture", default_aperture, 1.e-5,
+                      _pat_parsmod);
+  this->registerParam("use_aperture_speed", use_aperture_speed, _pat_parsmod);
+  this->registerParam("pushability", pushability, 1., _pat_parsmod);
+  this->registerParam("insertion_damage", insertion_damage, 0., _pat_parsmod);
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::initModel() {
+  auto & fem = this->getFEEngine();
+  fem.initShapeFunctions(_not_ghost);
+  fem.initShapeFunctions(_ghost);
+
+  pressure_on_qpoints.initialize(fem, _nb_component = 1);
+  delta_pres_on_qpoints.initialize(fem, _nb_component = 1);
+  pressure_gradient.initialize(fem, _nb_component = 1);
+  permeability_on_qpoints.initialize(fem, _nb_component = 1);
+  aperture_on_qpoints.initialize(fem, _nb_component = 1);
+  if (use_aperture_speed) {
+    prev_aperture_on_qpoints.initialize(fem, _nb_component = 1);
+  }
+  k_gradp_on_qpoints.initialize(fem, _nb_component = 1);
+}
+
+/* -------------------------------------------------------------------------- */
+FEEngine & FluidDiffusionModel::getFEEngineBoundary(const ID & name) {
+  return aka::as_type<FEEngine>(getFEEngineClassBoundary<FEEngineType>(name));
+}
+/* -------------------------------------------------------------------------- */
+FluidDiffusionModel::~FluidDiffusionModel() = default;
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assembleCapacityLumped(const GhostType & ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  auto & fem = getFEEngineClass<FEEngineType>();
+  fluid_diffusion::details::ComputeRhoFunctor compute_rho(*this);
+
+  for (const auto & type :
+       mesh.elementTypes(spatial_dimension, ghost_type, _ek_regular)) {
+    fem.assembleFieldLumped(compute_rho, "M", "pressure", this->getDOFManager(),
+                            type, ghost_type);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+MatrixType FluidDiffusionModel::getMatrixType(const ID & matrix_id) {
+  if (matrix_id == "K" or matrix_id == "M") {
+    return _symmetric;
+  }
+
+  return _mt_not_defined;
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assembleMatrix(const ID & matrix_id) {
+  if (matrix_id == "K") {
+    this->assemblePermeabilityMatrix();
+  } else if (matrix_id == "M" and need_to_reassemble_capacity) {
+    this->assembleCapacity();
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assembleLumpedMatrix(const ID & matrix_id) {
+  if (matrix_id == "M" and need_to_reassemble_capacity) {
+    this->assembleCapacityLumped();
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assembleResidual() {
+  AKANTU_DEBUG_IN();
+
+  this->assembleInternalFlux();
+
+  this->getDOFManager().assembleToResidual("pressure", *this->external_flux, 1);
+  this->getDOFManager().assembleToResidual("pressure", *this->internal_flux, 1);
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::predictor() { ++pressure_release; }
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::afterSolveStep(bool converged) {
+  AKANTU_DEBUG_IN();
+
+  if (not converged) {
+    return;
+  }
+
+  ++solution_release;
+  need_to_reassemble_capacity_lumped = true;
+  need_to_reassemble_capacity = true;
+
+  /// interpolating pressures on integration points for further use by BC
+  const GhostType gt = _not_ghost;
+  for (auto && type : mesh.elementTypes(spatial_dimension, gt, _ek_regular)) {
+    Array<Real> tmp(pressure_on_qpoints(type, gt));
+    this->getFEEngine().interpolateOnIntegrationPoints(
+        *pressure, pressure_on_qpoints(type, gt), 1, type, gt);
+    delta_pres_on_qpoints(type, gt) = pressure_on_qpoints(type, gt);
+    delta_pres_on_qpoints(type, gt) -= tmp;
+  }
+  AKANTU_DEBUG_OUT();
+}
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assembleCapacityLumped() {
+  AKANTU_DEBUG_IN();
+
+  if (!this->getDOFManager().hasLumpedMatrix("M")) {
+    this->getDOFManager().getNewLumpedMatrix("M");
+  }
+
+  this->getDOFManager().getLumpedMatrix("M").zero();
+
+  assembleCapacityLumped(_not_ghost);
+  assembleCapacityLumped(_ghost);
+
+  need_to_reassemble_capacity_lumped = false;
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::initSolver(
+    TimeStepSolverType time_step_solver_type,
+    NonLinearSolverType /*non_linear_solver_type*/) {
+  DOFManager & dof_manager = this->getDOFManager();
+
+  this->allocNodalField(this->pressure, 1, "pressure");
+  this->allocNodalField(this->external_flux, 1, "external_flux");
+  this->allocNodalField(this->internal_flux, 1, "internal_flux");
+  this->allocNodalField(this->blocked_dofs, 1, "blocked_dofs");
+  // this->allocNodalField(this->aperture, "aperture");
+
+  if (!dof_manager.hasDOFs("pressure")) {
+    dof_manager.registerDOFs("pressure", *this->pressure, _dst_nodal);
+    dof_manager.registerBlockedDOFs("pressure", *this->blocked_dofs);
+  }
+
+  if (time_step_solver_type == TimeStepSolverType::_dynamic ||
+      time_step_solver_type == TimeStepSolverType::_dynamic_lumped) {
+    this->allocNodalField(this->pressure_rate, 1, "pressure_rate");
+
+    if (!dof_manager.hasDOFsDerivatives("pressure", 1)) {
+      dof_manager.registerDOFsDerivative("pressure", 1, *this->pressure_rate);
+    }
+  }
+}
+/* -------------------------------------------------------------------------- */
+std::tuple<ID, TimeStepSolverType>
+FluidDiffusionModel::getDefaultSolverID(const AnalysisMethod & method) {
+  switch (method) {
+  case _explicit_lumped_mass: {
+    return std::make_tuple("explicit_lumped",
+                           TimeStepSolverType::_dynamic_lumped);
+  }
+  case _static: {
+    return std::make_tuple("static", TimeStepSolverType::_static);
+  }
+  case _implicit_dynamic: {
+    return std::make_tuple("implicit", TimeStepSolverType::_dynamic);
+  }
+  default:
+    return std::make_tuple("unknown", TimeStepSolverType::_not_defined);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+ModelSolverOptions FluidDiffusionModel::getDefaultSolverOptions(
+    const TimeStepSolverType & type) const {
+  ModelSolverOptions options;
+
+  switch (type) {
+  case TimeStepSolverType::_dynamic_lumped: {
+    options.non_linear_solver_type = NonLinearSolverType::_lumped;
+    options.integration_scheme_type["pressure"] =
+        IntegrationSchemeType::_forward_euler;
+    options.solution_type["pressure"] = IntegrationScheme::_pressure_rate;
+    break;
+  }
+  case TimeStepSolverType::_static: {
+    options.non_linear_solver_type = NonLinearSolverType::_newton_raphson;
+    options.integration_scheme_type["pressure"] =
+        IntegrationSchemeType::_pseudo_time;
+    options.solution_type["pressure"] = IntegrationScheme::_not_defined;
+    break;
+  }
+  case TimeStepSolverType::_dynamic: {
+    if (this->method == _explicit_consistent_mass) {
+      options.non_linear_solver_type = NonLinearSolverType::_newton_raphson;
+      options.integration_scheme_type["pressure"] =
+          IntegrationSchemeType::_forward_euler;
+      options.solution_type["pressure"] = IntegrationScheme::_pressure_rate;
+    } else {
+      options.non_linear_solver_type = NonLinearSolverType::_newton_raphson;
+      options.integration_scheme_type["pressure"] =
+          IntegrationSchemeType::_backward_euler;
+      options.solution_type["pressure"] = IntegrationScheme::_pressure;
+    }
+    break;
+  }
+  default:
+    AKANTU_EXCEPTION(type << " is not a valid time step solver type");
+  }
+
+  return options;
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assemblePermeabilityMatrix() {
+  AKANTU_DEBUG_IN();
+
+  this->computePermeabilityOnQuadPoints(_not_ghost);
+  if (permeability_release[_not_ghost] == permeability_matrix_release) {
+    return;
+  }
+
+  if (!this->getDOFManager().hasMatrix("K")) {
+    this->getDOFManager().getNewMatrix("K", getMatrixType("K"));
+  }
+  this->getDOFManager().getMatrix("K").zero();
+
+  this->assemblePermeabilityMatrix(_not_ghost);
+  // switch (mesh.getSpatialDimension()) {
+  // case 1:
+  // this->assemblePermeabilityMatrix<1>(_not_ghost);
+  //   break;
+  // case 2:
+  // this->assemblePermeabilityMatrix<2>(_not_ghost);
+  //   break;
+  // case 3:
+  //   this->assemblePermeabilityMatrix<3>(_not_ghost);
+  //   break;
+  // }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assemblePermeabilityMatrix(
+    const GhostType & ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  auto & fem = this->getFEEngine();
+
+  for (auto && type :
+       mesh.elementTypes(spatial_dimension, ghost_type, _ek_regular)) {
+    auto nb_element = mesh.getNbElement(type, ghost_type);
+    auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+    auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type);
+
+    auto bt_d_b = std::make_unique<Array<Real>>(
+        nb_element * nb_quadrature_points,
+        nb_nodes_per_element * nb_nodes_per_element, "B^t*D*B");
+
+    fem.computeBtDB(permeability_on_qpoints(type, ghost_type), *bt_d_b, 2, type,
+                    ghost_type);
+
+    /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$
+    auto K_e = std::make_unique<Array<Real>>(
+        nb_element, nb_nodes_per_element * nb_nodes_per_element, "K_e");
+
+    fem.integrate(*bt_d_b, *K_e, nb_nodes_per_element * nb_nodes_per_element,
+                  type, ghost_type);
+
+    this->getDOFManager().assembleElementalMatricesToMatrix(
+        "K", "pressure", *K_e, type, ghost_type, _symmetric);
+  }
+
+  permeability_matrix_release = permeability_release[ghost_type];
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::computePermeabilityOnQuadPoints(
+    const GhostType & ghost_type) {
+
+  // if already computed once check if need to compute
+  if (not initial_permeability[ghost_type]) {
+    // if aperture did not change, permeability will not vary
+    if (solution_release == permeability_release[ghost_type]) {
+      return;
+    }
+  }
+
+  for (const auto & type :
+       mesh.elementTypes(spatial_dimension, ghost_type, _ek_regular)) {
+
+    // auto nb_nodes_per_element = mesh.getNbNodesPerElement(type);
+    // auto nb_element = mesh.getNbElement(type);
+    // Array<Real> aperture_interpolated(nb_element * nb_nodes_per_element,
+    // 1);
+
+    // // compute the pressure on quadrature points
+    // this->getFEEngine().interpolateOnIntegrationPoints(
+    //     *aperture, aperture_interpolated, 1, type, ghost_type);
+
+    auto & perm = permeability_on_qpoints(type, ghost_type);
+    auto & aperture = aperture_on_qpoints(type, ghost_type);
+    for (auto && tuple : zip(perm, aperture)) {
+      auto & k = std::get<0>(tuple);
+      auto & aper = std::get<1>(tuple);
+      k = aper * aper * aper / (12 * this->viscosity);
+    }
+  }
+
+  permeability_release[ghost_type] = solution_release;
+  initial_permeability[ghost_type] = false;
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::computeKgradP(const GhostType & ghost_type) {
+  computePermeabilityOnQuadPoints(ghost_type);
+
+  for (const auto & type :
+       mesh.elementTypes(spatial_dimension, ghost_type, _ek_regular)) {
+    auto & gradient = pressure_gradient(type, ghost_type);
+    this->getFEEngine().gradientOnIntegrationPoints(*pressure, gradient, 1,
+                                                    type, ghost_type);
+
+    for (auto && values : zip(permeability_on_qpoints(type, ghost_type),
+                              gradient, k_gradp_on_qpoints(type, ghost_type))) {
+      const auto & k = std::get<0>(values);
+      const auto & BP = std::get<1>(values);
+      auto & k_BP = std::get<2>(values);
+
+      k_BP = k * BP;
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assembleInternalFlux() {
+  AKANTU_DEBUG_IN();
+
+  this->internal_flux->clear();
+
+  this->synchronize(SynchronizationTag::_fdm_pressure);
+  auto & fem = this->getFEEngine();
+
+  for (auto ghost_type : ghost_types) {
+    // compute k \grad P
+    computeKgradP(ghost_type);
+
+    for (auto type :
+         mesh.elementTypes(spatial_dimension, ghost_type, _ek_regular)) {
+      UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type);
+
+      auto & k_gradp_on_qpoints_vect = k_gradp_on_qpoints(type, ghost_type);
+
+      UInt nb_quad_points = k_gradp_on_qpoints_vect.size();
+      Array<Real> bt_k_gP(nb_quad_points, nb_nodes_per_element);
+      fem.computeBtD(k_gradp_on_qpoints_vect, bt_k_gP, type, ghost_type);
+
+      if (this->use_aperture_speed) {
+        auto aper_speed = aperture_on_qpoints(type, ghost_type);
+        aper_speed -= prev_aperture_on_qpoints(type, ghost_type);
+        aper_speed *= 1 / this->time_step;
+        Array<Real> aper_speed_by_shapes(nb_quad_points, nb_nodes_per_element);
+
+        fem.computeNtb(aper_speed, aper_speed_by_shapes, type, ghost_type);
+        bt_k_gP += aper_speed_by_shapes;
+      }
+      UInt nb_elements = mesh.getNbElement(type, ghost_type);
+      Array<Real> int_bt_k_gP(nb_elements, nb_nodes_per_element);
+
+      fem.integrate(bt_k_gP, int_bt_k_gP, nb_nodes_per_element, type,
+                    ghost_type);
+
+      this->getDOFManager().assembleElementalArrayLocalArray(
+          int_bt_k_gP, *this->internal_flux, type, ghost_type, -1);
+    }
+  }
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+Real FluidDiffusionModel::getStableTimeStep() {
+  AKANTU_DEBUG_IN();
+
+  Real el_size;
+  Real min_el_size = std::numeric_limits<Real>::max();
+  Real max_aper_on_qpoint = std::numeric_limits<Real>::min();
+
+  for (const auto & type :
+       mesh.elementTypes(spatial_dimension, _not_ghost, _ek_regular)) {
+
+    auto nb_nodes_per_element = mesh.getNbNodesPerElement(type);
+    auto & aper = aperture_on_qpoints(type, _not_ghost);
+    auto nb_quad_per_element = aper.getNbComponent();
+    auto mesh_dim = this->mesh.getSpatialDimension();
+    Array<Real> coord(0, nb_nodes_per_element * mesh_dim);
+    FEEngine::extractNodalToElementField(mesh, mesh.getNodes(), coord, type,
+                                         _not_ghost);
+
+    for (auto && data : zip(make_view(coord, mesh_dim, nb_nodes_per_element),
+                            make_view(aper, nb_quad_per_element))) {
+      Matrix<Real> & el_coord = std::get<0>(data);
+      Vector<Real> & el_aper = std::get<1>(data);
+      el_size = getFEEngine().getElementInradius(el_coord, type);
+      min_el_size = std::min(min_el_size, el_size);
+      max_aper_on_qpoint = std::max(max_aper_on_qpoint, el_aper.norm<L_inf>());
+    }
+
+    AKANTU_DEBUG_INFO("The minimum element size : "
+                      << min_el_size
+                      << " and the max aperture is : " << max_aper_on_qpoint);
+  }
+
+  Real min_dt = 2. * min_el_size * min_el_size / 4 * this->compressibility /
+                max_aper_on_qpoint / max_aper_on_qpoint;
+
+  mesh.getCommunicator().allReduce(min_dt, SynchronizerOperation::_min);
+
+  AKANTU_DEBUG_OUT();
+
+  return min_dt;
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::setTimeStep(Real dt, const ID & solver_id) {
+  Model::setTimeStep(time_step, solver_id);
+  this->time_step = dt;
+#if defined(AKANTU_USE_IOHELPER)
+  // this->mesh.getDumper("fluid_diffusion").setTimeStep(time_step);
+#endif
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::readMaterials() {
+  auto sect = this->getParserSection();
+
+  if (not std::get<1>(sect)) {
+    const auto & section = std::get<0>(sect);
+    this->parseSection(section);
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::initFullImpl(const ModelOptions & options) {
+  readMaterials();
+  Model::initFullImpl(options);
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::assembleCapacity() {
+  AKANTU_DEBUG_IN();
+  auto ghost_type = _not_ghost;
+
+  this->getDOFManager().getMatrix("M").zero();
+
+  auto & fem = getFEEngineClass<FEEngineType>();
+
+  fluid_diffusion::details::ComputeRhoFunctor rho_functor(*this);
+
+  for (auto && type :
+       mesh.elementTypes(spatial_dimension, ghost_type, _ek_regular)) {
+    fem.assembleFieldMatrix(rho_functor, "M", "pressure", this->getDOFManager(),
+                            type, ghost_type);
+  }
+
+  need_to_reassemble_capacity = false;
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::computeRho(Array<Real> & rho, ElementType type,
+                                     GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  rho.copy(aperture_on_qpoints(type, ghost_type));
+  if (this->use_aperture_speed) {
+    rho *= this->compressibility;
+  } else {
+    rho *= (this->compressibility + this->pushability);
+  }
+
+  AKANTU_DEBUG_OUT();
+} // namespace akantu
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::onElementsAdded(const Array<Element> & element_list,
+                                          const NewElementsEvent & /*event*/) {
+  AKANTU_DEBUG_IN();
+  if (element_list.empty()) {
+    return;
+  }
+  /// TODO had to do this ugly way because the meeting is in 3 days
+  // removing it will make the assemble mass matrix fail. jacobians are not
+  // updated
+  auto & fem = this->getFEEngine();
+  fem.initShapeFunctions(_not_ghost);
+  fem.initShapeFunctions(_ghost);
+
+  this->resizeFields();
+
+  auto type_fluid =
+      *mesh.elementTypes(spatial_dimension, _not_ghost, _ek_regular).begin();
+  const auto nb_quad_elem =
+      getFEEngine().getNbIntegrationPoints(type_fluid, _not_ghost);
+  auto aperture_it =
+      make_view(getApertureOnQpoints(type_fluid), nb_quad_elem).begin();
+
+  /// assign default aperture to newly added nodes
+  for (auto && element : element_list) {
+    auto elem_id = element.element;
+    for (auto ip : arange(nb_quad_elem)) {
+      aperture_it[elem_id](ip) = this->default_aperture;
+    }
+  }
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::resizeFields() {
+
+  AKANTU_DEBUG_IN();
+
+  /// elemental fields
+  auto & fem = this->getFEEngine();
+  pressure_on_qpoints.initialize(fem, _nb_component = 1);
+  delta_pres_on_qpoints.initialize(fem, _nb_component = 1);
+  pressure_gradient.initialize(fem, _nb_component = 1);
+  permeability_on_qpoints.initialize(fem, _nb_component = 1);
+  aperture_on_qpoints.initialize(fem, _nb_component = 1);
+  if (use_aperture_speed) {
+    prev_aperture_on_qpoints.initialize(fem, _nb_component = 1);
+  }
+  k_gradp_on_qpoints.initialize(fem, _nb_component = 1);
+
+  /// nodal fields
+  UInt nb_nodes = mesh.getNbNodes();
+
+  if (pressure != nullptr) {
+    pressure->resize(nb_nodes, 0.);
+    ++solution_release;
+  }
+  if (external_flux != nullptr) {
+    external_flux->resize(nb_nodes, 0.);
+  }
+  if (internal_flux != nullptr) {
+    internal_flux->resize(nb_nodes, 0.);
+  }
+  if (blocked_dofs != nullptr) {
+    blocked_dofs->resize(nb_nodes, false);
+  }
+  if (pressure_rate != nullptr) {
+    pressure_rate->resize(nb_nodes, 0.);
+  }
+  need_to_reassemble_capacity_lumped = true;
+  need_to_reassemble_capacity = true;
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+#if defined(AKANTU_COHESIVE_ELEMENT)
+void FluidDiffusionModel::getApertureOnQpointsFromCohesive(
+    const SolidMechanicsModelCohesive & coh_model, bool first_time) {
+  AKANTU_DEBUG_IN();
+
+  // get element types
+  auto & coh_mesh = coh_model.getMesh();
+  const auto dim = coh_mesh.getSpatialDimension();
+  const GhostType gt = _not_ghost;
+  auto type = *coh_mesh.elementTypes(dim, gt, _ek_regular).begin();
+  const ElementType type_facets = Mesh::getFacetType(type);
+  const ElementType typecoh = FEEngine::getCohesiveElementType(type_facets);
+  // const auto nb_coh_elem = coh_mesh.getNbElement(typecoh);
+  const auto nb_quad_coh_elem = coh_model.getFEEngine("CohesiveFEEngine")
+                                    .getNbIntegrationPoints(typecoh, gt);
+
+  auto type_fluid =
+      *mesh.elementTypes(spatial_dimension, gt, _ek_regular).begin();
+  const auto nb_fluid_elem = mesh.getNbElement(type_fluid);
+  const auto nb_quad_elem =
+      getFEEngine().getNbIntegrationPoints(type_fluid, gt);
+  // AKANTU_DEBUG_ASSERT(nb_quad_coh_elem == nb_quad_elem,
+  //                     "Different number of integration points per cohesive "
+  //                     "and fluid elements");
+
+  // save previous aperture
+  if (not first_time and use_aperture_speed) {
+    prev_aperture_on_qpoints.copy(aperture_on_qpoints);
+  }
+
+  // AKANTU_DEBUG_ASSERT(nb_coh_elem == nb_fluid_elem,
+  //                     "Different number of cohesive and fluid elements");
+
+  auto aperture_it =
+      make_view(getApertureOnQpoints(type_fluid), nb_quad_elem).begin();
+
+  /// loop on each segment element
+  for (auto && element_nb : arange(nb_fluid_elem)) {
+    Element element{type_fluid, element_nb, gt};
+    auto global_coh_elem =
+        mesh.getElementalData<akantu::Element>("cohesive_elements")(element);
+    auto ge = global_coh_elem.element;
+    auto le = coh_model.getMaterialLocalNumbering(
+        global_coh_elem.type, global_coh_elem.ghost_type)(ge);
+    auto model_mat_index = coh_model.getMaterialByElement(
+        global_coh_elem.type, global_coh_elem.ghost_type)(ge);
+    const auto & material = coh_model.getMaterial(model_mat_index);
+
+    // /// access cohesive material
+    // const auto & mat = dynamic_cast<const MaterialCohesive &>(material);
+    // const auto & normal_open_norm = mat.getNormalOpeningNorm(typecoh, gt);
+    const auto normal_open_norm_it =
+        make_view(material.getArray<Real>("normal_opening_norm", typecoh),
+                  nb_quad_coh_elem)
+            .begin();
+    if (nb_quad_elem == 1) {
+      /// coh el quad points are averaged to assign single opening to flow el
+      Real aperture_av = 0.;
+      for (UInt ip : arange(nb_quad_coh_elem)) {
+        auto normal_open_norm_ip = normal_open_norm_it[le](ip);
+        aperture_av += normal_open_norm_ip;
+      }
+      aperture_av /= nb_quad_coh_elem;
+      auto & aperture_ip = aperture_it[ge](0);
+      if (aperture_av < this->default_aperture) {
+        aperture_ip = this->default_aperture;
+      } else {
+        aperture_ip = aperture_av;
+      }
+    } else {
+      /// each flow el quad point gets aperture from corresponding coh el qp
+      for (UInt ip : arange(nb_quad_coh_elem)) {
+        auto normal_open_norm_ip = normal_open_norm_it[le](ip);
+        auto & aperture_ip = aperture_it[ge](ip);
+        if (normal_open_norm_ip < this->default_aperture) {
+          aperture_ip = this->default_aperture;
+        } else {
+          aperture_ip = normal_open_norm_ip;
+        }
+      }
+    }
+  }
+
+  // save previous aperture
+  if (first_time && use_aperture_speed) {
+    prev_aperture_on_qpoints.copy(aperture_on_qpoints);
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::updateFluidElementsFromCohesive(
+    const SolidMechanicsModelCohesive & coh_model) {
+  AKANTU_DEBUG_IN();
+
+  // get element types
+  auto & coh_mesh = coh_model.getMesh();
+  const auto dim = coh_mesh.getSpatialDimension();
+  const GhostType gt = _not_ghost;
+  auto type = *coh_mesh.elementTypes(dim, gt, _ek_regular).begin();
+  const ElementType type_facets = Mesh::getFacetType(type);
+  const ElementType typecoh = FEEngine::getCohesiveElementType(type_facets);
+  const auto nb_coh_elem = coh_mesh.getNbElement(typecoh);
+  const auto nb_quad_coh_elem = coh_model.getFEEngine("CohesiveFEEngine")
+                                    .getNbIntegrationPoints(typecoh, gt);
+
+  auto type_fluid =
+      *mesh.elementTypes(spatial_dimension, gt, _ek_regular).begin();
+  const auto nb_fluid_elem = mesh.getNbElement(type_fluid);
+
+  // check if there is need to add more fluid elements
+  if (nb_coh_elem == nb_fluid_elem) {
+    return;
+  }
+
+  NewElementsEvent new_facets;
+  NewNodesEvent new_nodes;
+  NewElementsEvent new_fluid_facets;
+
+  /// loop on each cohesive element and check its damage
+  for (auto && coh_el : arange(nb_coh_elem)) {
+
+    // check if this cohesive element is present in fluid mesh
+    auto & existing_coh_elements =
+        mesh.getData<Element>("cohesive_elements", type_facets, gt);
+    Element coh_element = {typecoh, coh_el, gt};
+    auto it = existing_coh_elements.find(coh_element);
+    if (it != UInt(-1)) {
+      continue;
+    }
+
+    // check damage at the cohesive element
+    // Element element{type_fluid, element_nb, gt};
+    auto le = coh_model.getMaterialLocalNumbering(typecoh, gt)(coh_el);
+    auto model_mat_index = coh_model.getMaterialByElement(typecoh, gt)(coh_el);
+    const auto & material = coh_model.getMaterial(model_mat_index);
+    const auto damage_it =
+        make_view(material.getArray<Real>("damage", typecoh), nb_quad_coh_elem)
+            .begin();
+    Real damage_av = 0.;
+    for (auto ip : arange(nb_quad_coh_elem)) {
+      auto damage_ip = damage_it[le](ip);
+      damage_av += damage_ip;
+    }
+    damage_av /= nb_quad_coh_elem;
+
+    if (damage_av < this->insertion_damage) {
+      continue;
+    }
+
+    // add fluid element to connectivity and corresponding nodes
+    Array<UInt> & nodes_added = new_nodes.getList();
+    auto & crack_facets = coh_mesh.getElementGroup("crack_facets");
+    auto & nodes = mesh.getNodes();
+    auto && coh_nodes = coh_mesh.getNodes();
+    auto && coh_conn = coh_mesh.getConnectivity(typecoh, gt);
+    Vector<UInt> conn(coh_conn.getNbComponent() / 2);
+    auto coh_facet_conn_it = make_view(coh_mesh.getConnectivity(typecoh, gt),
+                                       coh_conn.getNbComponent() / 2)
+                                 .begin();
+    auto cohesive_nodes_first_half = coh_facet_conn_it[2 * coh_el];
+    for (auto c : akantu::arange(conn.size())) {
+      auto coh_node = cohesive_nodes_first_half(c);
+      Vector<Real> pos(mesh.getSpatialDimension());
+      for (auto && data : enumerate(pos)) {
+        std::get<1>(data) = coh_nodes(coh_node, std::get<0>(data));
+      }
+      auto idx = nodes.find(pos);
+      if (idx == UInt(-1)) {
+        nodes.push_back(pos);
+        conn(c) = nodes.size() - 1;
+        nodes_added.push_back(nodes.size() - 1);
+      } else {
+        conn(c) = idx;
+      }
+    }
+    mesh.getData<Element>("cohesive_elements", type_facets, gt)
+        .push_back(coh_element);
+    mesh.getConnectivity(type_facets, gt).push_back(conn);
+    Element fluid_facet{type_facets,
+                        mesh.getConnectivity(type_facets, gt).size() - 1, gt};
+    new_fluid_facets.getList().push_back(fluid_facet);
+
+    // instantiate connectivity type for this facet type if not yet done
+    if (not coh_mesh.getConnectivities().exists(type_facets, gt)) {
+      coh_mesh.addConnectivityType(type_facets, gt);
+    }
+
+    // add two facets per cohesive element into cohesive mesh
+    auto & facet_conn_mesh = coh_mesh.getConnectivity(type_facets, gt);
+    for (auto f : akantu::arange(2)) {
+      Vector<UInt> coh_nodes_one_side = coh_facet_conn_it[2 * coh_el + f];
+      facet_conn_mesh.push_back(coh_nodes_one_side);
+      Element new_facet{type_facets, facet_conn_mesh.size() - 1, gt};
+      crack_facets.add(new_facet);
+      new_facets.getList().push_back(new_facet);
+    }
+  }
+  mesh.sendEvent(new_nodes);
+  mesh.sendEvent(new_fluid_facets);
+  MeshUtils::fillElementToSubElementsData(coh_mesh);
+  coh_mesh.sendEvent(new_facets);
+
+  AKANTU_DEBUG_OUT();
+}
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::applyExternalFluxAtElementGroup(
+    const Real & rate, const ElementGroup & source_facets,
+    GhostType ghost_type) {
+  AKANTU_DEBUG_IN();
+
+  for (auto && type :
+       source_facets.elementTypes(spatial_dimension, ghost_type)) {
+    const auto & element_ids = source_facets.getElements(type, ghost_type);
+
+    const auto nb_fluid_elem = mesh.getNbElement(type);
+    const auto type_size = element_ids.size();
+    AKANTU_DEBUG_ASSERT(type_size <= nb_fluid_elem,
+                        "Number of provided source facets exceeds total number "
+                        "of flow elements");
+    const auto fluid_conn_it =
+        make_view(mesh.getConnectivity(type, ghost_type),
+                  mesh.getConnectivity(type, ghost_type).getNbComponent())
+            .begin();
+    auto & source = getExternalFlux();
+    source.clear();
+
+    /// loop on each element of the group
+    for (auto el : element_ids) {
+      AKANTU_DEBUG_ASSERT(el <= nb_fluid_elem,
+                          "Element number in the source facets group exceeds "
+                          "maximum number of flow elements");
+
+      const Vector<UInt> fluid_conn = fluid_conn_it[el];
+      for (const auto & node : fluid_conn) {
+        source(node) += rate / (fluid_conn.size() * element_ids.size());
+      }
+    }
+  }
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+Array<Real> FluidDiffusionModel::getQpointsCoord() {
+  AKANTU_DEBUG_IN();
+
+  const auto & nodes_coords = mesh.getNodes();
+  const GhostType gt = _not_ghost;
+  auto type_fluid =
+      *mesh.elementTypes(spatial_dimension, gt, _ek_regular).begin();
+  const auto nb_fluid_elem = mesh.getNbElement(type_fluid);
+  auto & fem = this->getFEEngine();
+  const auto nb_quad_points = fem.getNbIntegrationPoints(type_fluid, gt);
+
+  Array<Real> quad_coords(nb_fluid_elem * nb_quad_points,
+                          spatial_dimension + 1);
+  fem.interpolateOnIntegrationPoints(nodes_coords, quad_coords,
+                                     spatial_dimension + 1, type_fluid, gt);
+  AKANTU_DEBUG_OUT();
+  return quad_coords;
+}
+
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+#ifdef AKANTU_USE_IOHELPER
+
+std::shared_ptr<dumpers::Field> FluidDiffusionModel::createNodalFieldBool(
+    const std::string & field_name, const std::string & group_name,
+    __attribute__((unused)) bool padding_flag) {
+
+  std::map<std::string, Array<bool> *> uint_nodal_fields;
+  uint_nodal_fields["blocked_dofs"] = blocked_dofs.get();
+
+  auto field = mesh.createNodalField(uint_nodal_fields[field_name], group_name);
+  return field;
+}
+
+/* -------------------------------------------------------------------------- */
+std::shared_ptr<dumpers::Field> FluidDiffusionModel::createNodalFieldReal(
+    const std::string & field_name, const std::string & group_name,
+    __attribute__((unused)) bool padding_flag) {
+
+  if (field_name == "capacity_lumped") {
+    AKANTU_EXCEPTION(
+        "Capacity lumped is a nodal field now stored in the DOF manager."
+        "Therefore it cannot be used by a dumper anymore");
+  }
+
+  std::map<std::string, Array<Real> *> real_nodal_fields;
+  real_nodal_fields["pressure"] = pressure.get();
+  real_nodal_fields["pressure_rate"] = pressure_rate.get();
+  real_nodal_fields["external_flux"] = external_flux.get();
+  real_nodal_fields["internal_flux"] = internal_flux.get();
+  // real_nodal_fields["increment"] = increment.get();
+
+  std::shared_ptr<dumpers::Field> field =
+      mesh.createNodalField(real_nodal_fields[field_name], group_name);
+
+  return field;
+}
+
+/* -------------------------------------------------------------------------- */
+std::shared_ptr<dumpers::Field> FluidDiffusionModel::createElementalField(
+    const std::string & field_name, const std::string & group_name,
+    bool /*padding_flag*/, UInt /*spatial_dimension*/,
+    ElementKind element_kind) {
+
+  std::shared_ptr<dumpers::Field> field;
+
+  if (field_name == "partitions") {
+    field = mesh.createElementalField<UInt, dumpers::ElementPartitionField>(
+        mesh.getConnectivities(), group_name, this->spatial_dimension,
+        element_kind);
+  } else if (field_name == "pressure_gradient") {
+    ElementTypeMap<UInt> nb_data_per_elem =
+        this->mesh.getNbDataPerElem(pressure_gradient);
+
+    field = mesh.createElementalField<Real, dumpers::InternalMaterialField>(
+        pressure_gradient, group_name, this->spatial_dimension, element_kind,
+        nb_data_per_elem);
+  } else if (field_name == "permeability") {
+    ElementTypeMap<UInt> nb_data_per_elem =
+        this->mesh.getNbDataPerElem(permeability_on_qpoints);
+
+    field = mesh.createElementalField<Real, dumpers::InternalMaterialField>(
+        permeability_on_qpoints, group_name, this->spatial_dimension,
+        element_kind, nb_data_per_elem);
+  } else if (field_name == "aperture") {
+    ElementTypeMap<UInt> nb_data_per_elem =
+        this->mesh.getNbDataPerElem(aperture_on_qpoints);
+
+    field = mesh.createElementalField<Real, dumpers::InternalMaterialField>(
+        aperture_on_qpoints, group_name, this->spatial_dimension, element_kind,
+        nb_data_per_elem);
+  } else if (field_name == "pressure_on_qpoints") {
+    ElementTypeMap<UInt> nb_data_per_elem =
+        this->mesh.getNbDataPerElem(pressure_on_qpoints);
+
+    field = mesh.createElementalField<Real, dumpers::InternalMaterialField>(
+        pressure_on_qpoints, group_name, this->spatial_dimension, element_kind,
+        nb_data_per_elem);
+  }
+
+  return field;
+}
+
+/* -------------------------------------------------------------------------- */
+#else
+/* -------------------------------------------------------------------------- */
+std::shared_ptr<dumpers::Field> FluidDiffusionModel::createElementalField(
+    __attribute__((unused)) const std::string & field_name,
+    __attribute__((unused)) const std::string & group_name,
+    __attribute__((unused)) bool padding_flag,
+    __attribute__((unused)) const ElementKind & element_kind) {
+  return nullptr;
+}
+
+/* -------------------------------------------------------------------------- */
+std::shared_ptr<dumpers::Field> FluidDiffusionModel::createNodalFieldBool(
+    __attribute__((unused)) const std::string & field_name,
+    __attribute__((unused)) const std::string & group_name,
+    __attribute__((unused)) bool padding_flag) {
+  return nullptr;
+}
+
+/* -------------------------------------------------------------------------- */
+std::shared_ptr<dumpers::Field> FluidDiffusionModel::createNodalFieldReal(
+    __attribute__((unused)) const std::string & field_name,
+    __attribute__((unused)) const std::string & group_name,
+    __attribute__((unused)) bool padding_flag) {
+  return nullptr;
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::dump(const std::string & dumper_name) {
+  mesh.dump(dumper_name);
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::dump(const std::string & dumper_name, UInt step) {
+  mesh.dump(dumper_name, step);
+}
+
+/* -------------------------------------------------------------------------
+ */
+void FluidDiffusionModel::dump(const std::string & dumper_name, Real time,
+                               UInt step) {
+  mesh.dump(dumper_name, time, step);
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::dump() { mesh.dump(); }
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::dump(UInt step) { mesh.dump(step); }
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::dump(Real time, UInt step) { mesh.dump(time, step); }
+
+/* -------------------------------------------------------------------------- */
+inline UInt
+FluidDiffusionModel::getNbData(const Array<UInt> & indexes,
+                               const SynchronizationTag & tag) const {
+  AKANTU_DEBUG_IN();
+
+  UInt size = 0;
+  UInt nb_nodes = indexes.size();
+
+  switch (tag) {
+  case SynchronizationTag::_fdm_pressure: {
+    size += nb_nodes * sizeof(Real);
+    break;
+  }
+  default: {
+    AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
+  }
+  }
+
+  AKANTU_DEBUG_OUT();
+  return size;
+}
+
+/* -------------------------------------------------------------------------- */
+inline void
+FluidDiffusionModel::packData(CommunicationBuffer & buffer,
+                              const Array<UInt> & indexes,
+                              const SynchronizationTag & tag) const {
+  AKANTU_DEBUG_IN();
+
+  for (auto index : indexes) {
+    switch (tag) {
+    case SynchronizationTag::_fdm_pressure: {
+      buffer << (*pressure)(index);
+      break;
+    }
+    default: {
+      AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
+    }
+    }
+  }
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+inline void FluidDiffusionModel::unpackData(CommunicationBuffer & buffer,
+                                            const Array<UInt> & indexes,
+                                            const SynchronizationTag & tag) {
+  AKANTU_DEBUG_IN();
+
+  for (auto index : indexes) {
+    switch (tag) {
+    case SynchronizationTag::_fdm_pressure: {
+      buffer >> (*pressure)(index);
+      break;
+    }
+    default: {
+      AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
+    }
+    }
+  }
+
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+inline UInt
+FluidDiffusionModel::getNbData(const Array<Element> & elements,
+                               const 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 SynchronizationTag::_fdm_pressure: {
+    size += nb_nodes_per_element * sizeof(Real); // pressure
+    break;
+  }
+  case SynchronizationTag::_fdm_gradient_pressure: {
+    // pressure gradient
+    size += getNbIntegrationPoints(elements) * sizeof(Real);
+    size += nb_nodes_per_element * sizeof(Real); // nodal pressures
+    break;
+  }
+  default: {
+    AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
+  }
+  }
+
+  AKANTU_DEBUG_OUT();
+  return size;
+}
+
+/* -------------------------------------------------------------------------- */
+inline void
+FluidDiffusionModel::packData(CommunicationBuffer & buffer,
+                              const Array<Element> & elements,
+                              const SynchronizationTag & tag) const {
+  switch (tag) {
+  case SynchronizationTag::_fdm_pressure: {
+    packNodalDataHelper(*pressure, buffer, elements, mesh);
+    break;
+  }
+  case SynchronizationTag::_fdm_gradient_pressure: {
+    packElementalDataHelper(pressure_gradient, buffer, elements, true,
+                            getFEEngine());
+    packNodalDataHelper(*pressure, buffer, elements, mesh);
+    break;
+  }
+  default: {
+    AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
+  }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+inline void FluidDiffusionModel::unpackData(CommunicationBuffer & buffer,
+                                            const Array<Element> & elements,
+                                            const SynchronizationTag & tag) {
+  switch (tag) {
+  case SynchronizationTag::_fdm_pressure: {
+    unpackNodalDataHelper(*pressure, buffer, elements, mesh);
+    break;
+  }
+  case SynchronizationTag::_fdm_gradient_pressure: {
+    unpackElementalDataHelper(pressure_gradient, buffer, elements, true,
+                              getFEEngine());
+    unpackNodalDataHelper(*pressure, buffer, elements, mesh);
+
+    break;
+  }
+  default: {
+    AKANTU_ERROR("Unknown ghost synchronization tag : " << tag);
+  }
+  }
+}
+
+/* -------------------------------------------------------------------------- */
+void FluidDiffusionModel::injectIntoFacetsByCoord(const Vector<Real> & position,
+                                                  const Real & injection_rate) {
+  AKANTU_DEBUG_IN();
+
+  auto dim = mesh.getSpatialDimension();
+  const auto gt = _not_ghost;
+  const auto & pos = mesh.getNodes();
+  const auto pos_it = make_view(pos, dim).begin();
+  auto & source = *external_flux;
+
+  Vector<Real> bary_facet(dim);
+
+  Real min_dist = std::numeric_limits<Real>::max();
+  Element inj_facet;
+  for_each_element(
+      mesh,
+      [&](auto && facet) {
+        mesh.getBarycenter(facet, bary_facet);
+        auto dist = std::abs(bary_facet.distance(position));
+        if (dist < min_dist) {
+          min_dist = dist;
+          inj_facet = facet;
+        }
+      },
+      _spatial_dimension = dim - 1);
+
+  auto & facet_conn = mesh.getConnectivity(inj_facet.type, gt);
+  auto nb_nodes_per_elem = facet_conn.getNbComponent();
+  for (auto node : arange(nb_nodes_per_elem)) {
+    source(facet_conn(inj_facet.element, node)) =
+        injection_rate / nb_nodes_per_elem;
+  }
+  AKANTU_DEBUG_OUT();
+}
+
+/* -------------------------------------------------------------------------- */
+} // namespace akantu
diff --git a/src/model/fluid_diffusion/fluid_diffusion_model.hh b/src/model/fluid_diffusion/fluid_diffusion_model.hh
new file mode 100644
index 000000000..bcf576dbb
--- /dev/null
+++ b/src/model/fluid_diffusion/fluid_diffusion_model.hh
@@ -0,0 +1,381 @@
+/**
+ * @file   fluid_diffusion_model.hh
+ *
+ * @author Emil Gallyamov <emil.gallyamov@epfl.ch>
+ *
+ * @date creation: Aug 2019
+ *
+ * @brief  Transient fluid diffusion model based on the Heat Transfer Model
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne)
+ * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
+ *
+ * Akantu is free  software: you can redistribute it and/or  modify it under the
+ * terms  of the  GNU Lesser  General Public  License as published by  the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * Akantu is  distributed in the  hope that it  will be useful, but  WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See  the GNU  Lesser General  Public License  for more
+ * details.
+ *
+ * You should  have received  a copy  of the GNU  Lesser General  Public License
+ * along with Akantu. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* -------------------------------------------------------------------------- */
+#include "data_accessor.hh"
+#include "fe_engine.hh"
+#include "fluid_diffusion_model_event_handler.hh"
+#include "model.hh"
+#if defined(AKANTU_COHESIVE_ELEMENT)
+#include "material_cohesive.hh"
+#include "solid_mechanics_model_cohesive.hh"
+#endif
+
+/* -------------------------------------------------------------------------- */
+#include <array>
+/* -------------------------------------------------------------------------- */
+
+#ifndef __AKANTU_FLUID_DIFFUSION_MODEL_HH__
+#define __AKANTU_FLUID_DIFFUSION_MODEL_HH__
+
+namespace akantu {
+template <ElementKind kind, class IntegrationOrderFunctor>
+class IntegratorGauss;
+template <ElementKind kind> class ShapeLagrange;
+} // namespace akantu
+
+namespace akantu {
+
+class FluidDiffusionModel
+    : public Model,
+      public DataAccessor<Element>,
+      public DataAccessor<UInt>,
+      public EventHandlerManager<FluidDiffusionModelEventHandler> {
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  using FEEngineType = FEEngineTemplate<IntegratorGauss, ShapeLagrange>;
+
+  FluidDiffusionModel(Mesh & mesh, UInt dim = _all_dimensions,
+                      const ID & id = "fluid_diffusion_model");
+
+  ~FluidDiffusionModel() override;
+
+  /* ------------------------------------------------------------------------ */
+  /* Methods                                                                  */
+  /* ------------------------------------------------------------------------ */
+protected:
+  /// generic function to initialize everything ready for explicit dynamics
+  void initFullImpl(const ModelOptions & options) override;
+
+  /// read one material file to instantiate all the materials
+  void readMaterials();
+
+  /// allocate all vectors
+  void initSolver(TimeStepSolverType, NonLinearSolverType) override;
+
+  /// initialize the model
+  void initModel() override;
+
+  void predictor() override;
+
+  /// callback for the solver, this is called at end of solve
+  void afterSolveStep(bool is_converged = false) override;
+
+  /// compute the heat flux
+  void assembleResidual() override;
+
+  /// get the type of matrix needed
+  MatrixType getMatrixType(const ID &) override;
+
+  /// callback to assemble a Matrix
+  void assembleMatrix(const ID &) override;
+
+  /// callback to assemble a lumped Matrix
+  void assembleLumpedMatrix(const ID &) override;
+
+  std::tuple<ID, TimeStepSolverType>
+  getDefaultSolverID(const AnalysisMethod & method) override;
+
+  ModelSolverOptions
+  getDefaultSolverOptions(const TimeStepSolverType & type) const override;
+
+  /// resize all fields on nodes added event
+  void resizeFields();
+
+public:
+  /// get coordinates of qpoints in same order as other elemental fields
+  Array<Real> getQpointsCoord();
+
+#ifdef AKANTU_COHESIVE_ELEMENT
+  /// get apperture at nodes from displacement field of cohesive model
+  void getApertureOnQpointsFromCohesive(
+      const SolidMechanicsModelCohesive & coh_model, bool first_time = false);
+
+  /// insert fluid elements based on cohesive elements and their damage
+  void updateFluidElementsFromCohesive(
+      const SolidMechanicsModelCohesive & coh_model);
+#endif
+
+  void applyExternalFluxAtElementGroup(const Real & rate,
+                                       const ElementGroup & source_facets,
+                                       GhostType ghost_type = _not_ghost);
+
+  void injectIntoFacetsByCoord(const Vector<Real> & position,
+                               const Real & injection_rate);
+  /* ------------------------------------------------------------------------ */
+  /* Methods for explicit                                                     */
+  /* ------------------------------------------------------------------------ */
+public:
+  /// compute and get the stable time step
+  Real getStableTimeStep();
+
+  /// set the stable timestep
+  void setTimeStep(Real dt, const ID & solver_id = "") override;
+
+  // temporary protection to prevent bad usage: should check for bug
+protected:
+  /// compute the internal heat flux \todo Need code review: currently not
+  /// public method
+  void assembleInternalFlux();
+
+public:
+  /// calculate the lumped capacity vector for heat transfer problem
+  void assembleCapacityLumped();
+
+  /* ------------------------------------------------------------------------ */
+  /* Mesh Event Handler inherited members                                     */
+  /* ------------------------------------------------------------------------ */
+protected:
+  void onElementsAdded(const Array<Element> & element_list,
+                       const NewElementsEvent & /*event*/) override;
+  /* ------------------------------------------------------------------------ */
+  /* Methods for static                                                       */
+  /* ------------------------------------------------------------------------ */
+public:
+  /// assemble the conductivity matrix
+  void assemblePermeabilityMatrix();
+
+  /// assemble the conductivity matrix
+  void assembleCapacity();
+
+  /// compute the capacity on quadrature points
+  void computeRho(Array<Real> & rho, ElementType type, GhostType ghost_type);
+
+private:
+  /// calculate the lumped capacity vector for heat transfer problem (w
+  /// ghost type)
+  void assembleCapacityLumped(const GhostType & ghost_type);
+
+  /// assemble the conductivity matrix (w/ ghost type)
+  void assemblePermeabilityMatrix(const GhostType & ghost_type);
+
+  /// compute the conductivity tensor for each quadrature point in an array
+  void computePermeabilityOnQuadPoints(const GhostType & ghost_type);
+
+  /// compute vector k \grad T for each quadrature point
+  void computeKgradP(const GhostType & ghost_type);
+
+  /// compute the thermal energy
+  Real computeThermalEnergyByNode();
+
+  /* ------------------------------------------------------------------------ */
+  /* Data Accessor inherited members                                          */
+  /* ------------------------------------------------------------------------ */
+public:
+  inline UInt getNbData(const Array<Element> & elements,
+                        const SynchronizationTag & tag) const override;
+  inline void packData(CommunicationBuffer & buffer,
+                       const Array<Element> & elements,
+                       const SynchronizationTag & tag) const override;
+  inline void unpackData(CommunicationBuffer & buffer,
+                         const Array<Element> & elements,
+                         const SynchronizationTag & tag) override;
+
+  inline UInt getNbData(const Array<UInt> & indexes,
+                        const SynchronizationTag & tag) const override;
+  inline void packData(CommunicationBuffer & buffer,
+                       const Array<UInt> & indexes,
+                       const SynchronizationTag & tag) const override;
+  inline void unpackData(CommunicationBuffer & buffer,
+                         const Array<UInt> & indexes,
+                         const SynchronizationTag & tag) override;
+
+  /* ------------------------------------------------------------------------ */
+  /* Dumpable interface                                                       */
+  /* ------------------------------------------------------------------------ */
+public:
+  std::shared_ptr<dumpers::Field>
+  createNodalFieldReal(const std::string & field_name,
+                       const std::string & group_name,
+                       bool padding_flag) override;
+
+  std::shared_ptr<dumpers::Field>
+  createNodalFieldBool(const std::string & field_name,
+                       const std::string & group_name,
+                       bool padding_flag) override;
+
+  std::shared_ptr<dumpers::Field>
+  createElementalField(const std::string & field_name,
+                       const std::string & group_name, bool padding_flag,
+                       UInt spatial_dimension, ElementKind kind) override;
+
+  virtual void dump(const std::string & dumper_name);
+  virtual void dump(const std::string & dumper_name, UInt step);
+  virtual void dump(const std::string & dumper_name, Real time, UInt step);
+
+  void dump() override;
+
+  virtual void dump(UInt step);
+
+  virtual void dump(Real time, UInt step);
+
+  /* ------------------------------------------------------------------------ */
+  /* Accessors                                                                */
+  /* ------------------------------------------------------------------------ */
+public:
+  AKANTU_GET_MACRO(Compressibility, compressibility, Real);
+  AKANTU_GET_MACRO(Pushability, pushability, Real);
+  /// get 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);
+  /// get the assembled heat flux
+  AKANTU_GET_MACRO(InternalFlux, *internal_flux, Array<Real> &);
+  /// get the boundary vector
+  AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, Array<bool> &);
+  /// get the external heat rate vector
+  AKANTU_GET_MACRO(ExternalFlux, *external_flux, Array<Real> &);
+  /// get the temperature gradient
+  AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PressureGradient, pressure_gradient,
+                                         Real);
+  /// get the permeability on q points
+  AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PermeabilityOnQpoints,
+                                         permeability_on_qpoints, Real);
+  /// get the pressure on q points
+  AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PressureOnQpoints, pressure_on_qpoints,
+                                         Real);
+  /// get the pressure change on q points
+  AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(DeltaPressureOnQpoints,
+                                         delta_pres_on_qpoints, Real);
+  /// get the aperture on q points
+  AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ApertureOnQpoints, aperture_on_qpoints,
+                                         Real);
+  /// get the aperture on q points
+  AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ApertureOnQpoints, aperture_on_qpoints,
+                                   Real);
+  /// internal variables
+  AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(KgradP, k_gradp_on_qpoints, Real);
+  /// get the temperature
+  AKANTU_GET_MACRO(Pressure, *pressure, Array<Real> &);
+  /// get the temperature derivative
+  AKANTU_GET_MACRO(PressureRate, *pressure_rate, Array<Real> &);
+
+  inline bool isModelVelocityDependent() const { return use_aperture_speed; }
+  // /// get the energy denominated by thermal
+  // Real getEnergy(const std::string & energy_id, const ElementType & type,
+  //                UInt index);
+  // /// get the energy denominated by thermal
+  // Real getEnergy(const std::string & energy_id);
+
+  // /// get the thermal energy for a given element
+  // Real getThermalEnergy(const ElementType & type, UInt index);
+  // /// get the thermal energy for a given element
+  // Real getThermalEnergy();
+
+protected:
+  /* ------------------------------------------------------------------------ */
+  FEEngine & getFEEngineBoundary(const ID & name = "") override;
+
+  /* ------------------------------------------------------------------------ */
+  /* Class Members                                                            */
+  /* ------------------------------------------------------------------------ */
+private:
+  /// number of iterations
+  UInt n_iter;
+
+  /// time step
+  Real time_step;
+
+  /// pressure array
+  std::unique_ptr<Array<Real>> pressure;
+
+  /// pressure derivatives array
+  std::unique_ptr<Array<Real>> pressure_rate;
+
+  // /// increment array (@f$\delta \dot P@f$ or @f$\delta P@f$)
+  // Array<Real> * increment{nullptr};
+
+  /// the speed of the changing temperature
+  ElementTypeMapArray<Real> pressure_gradient;
+
+  /// pressure field on quadrature points
+  ElementTypeMapArray<Real> pressure_on_qpoints;
+
+  /// pressure change on quadrature points
+  ElementTypeMapArray<Real> delta_pres_on_qpoints;
+
+  /// conductivity tensor on quadrature points
+  ElementTypeMapArray<Real> permeability_on_qpoints;
+
+  /// aperture on quadrature points
+  ElementTypeMapArray<Real> aperture_on_qpoints;
+
+  /// aperture on quadrature points
+  ElementTypeMapArray<Real> prev_aperture_on_qpoints;
+
+  /// vector k \grad T on quad points
+  ElementTypeMapArray<Real> k_gradp_on_qpoints;
+
+  /// external flux vector
+  std::unique_ptr<Array<Real>> external_flux;
+
+  /// residuals array
+  std::unique_ptr<Array<Real>> internal_flux;
+
+  /// boundary vector
+  std::unique_ptr<Array<bool>> blocked_dofs;
+
+  // viscosity
+  Real viscosity{0.};
+
+  /// compressibility Cf = 1/pho drho/dP
+  Real compressibility{0.};
+
+  // default value of aperture on a newly added nodesynchronizer
+  Real default_aperture{0.};
+
+  bool need_to_reassemble_capacity{true};
+  bool need_to_reassemble_capacity_lumped{true};
+  UInt pressure_release{0};
+  UInt solution_release{0};
+  UInt permeability_matrix_release{0};
+
+  std::unordered_map<GhostType, bool> initial_permeability{{_not_ghost, true},
+                                                           {_ghost, true}};
+  std::unordered_map<GhostType, UInt> permeability_release{{_not_ghost, 0},
+                                                           {_ghost, 0}};
+  bool use_aperture_speed{false};
+
+  // pushability Ch = 1/h dh/dP
+  Real pushability{0.};
+
+  // damage at which cohesive element will be duplicated in fluid mesh
+  Real insertion_damage{0.};
+};
+
+} // namespace akantu
+
+/* -------------------------------------------------------------------------- */
+/* inline functions                                                           */
+/* -------------------------------------------------------------------------- */
+#include "fluid_diffusion_model_inline_impl.hh"
+
+#endif /* __AKANTU_FLUID_DIFFUSION_MODEL_HH__ */
diff --git a/src/model/fluid_diffusion/fluid_diffusion_model_event_handler.hh b/src/model/fluid_diffusion/fluid_diffusion_model_event_handler.hh
new file mode 100644
index 000000000..52914f7d8
--- /dev/null
+++ b/src/model/fluid_diffusion/fluid_diffusion_model_event_handler.hh
@@ -0,0 +1,56 @@
+/**
+ * @file   fluid_diffusion_model_event_handler.hh
+ *
+ * @author Emil Gallyamov <emil.gallyamov@epfl.ch>
+ *
+ * @date creation: Mon Aug 19 2019
+ * @date last modification:
+ *
+ * @brief  EventHandler implementation for FluidDiffusionEvents
+ * modification of the SolidMecanicsModelEventHandler
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2010-2018 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_FLUID_DIFFUSION_MODEL_EVENT_HANDLER_HH__
+#define __AKANTU_FLUID_DIFFUSION_MODEL_EVENT_HANDLER_HH__
+
+namespace akantu {
+
+/// akantu::FluidDiffusionModelEvent is the base event for model
+namespace FluidDiffusionModelEvent {}
+
+/// akantu::SolidMechanicsModelEvent
+class FluidDiffusionModelEventHandler {
+  /* ------------------------------------------------------------------------ */
+  /* Constructors/Destructors                                                 */
+  /* ------------------------------------------------------------------------ */
+public:
+  virtual ~FluidDiffusionModelEventHandler() = default;
+
+  template <class EventHandler> friend class EventHandlerManager;
+
+};
+
+} // namespace akantu
+
+#endif /* __AKANTU_FLUID_DIFFUSION_MODEL_EVENT_HANDLER_HH__ */
diff --git a/src/model/fluid_diffusion/fluid_diffusion_model_inline_impl.hh b/src/model/fluid_diffusion/fluid_diffusion_model_inline_impl.hh
new file mode 100644
index 000000000..ea8a89cd5
--- /dev/null
+++ b/src/model/fluid_diffusion/fluid_diffusion_model_inline_impl.hh
@@ -0,0 +1,42 @@
+/**
+ * @file   heat_transfer_model_inline_impl.cc
+ *
+ * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
+ * @author Srinivasa Babu Ramisetti <srinivasa.ramisetti@epfl.ch>
+ * @author Nicolas Richart <nicolas.richart@epfl.ch>
+ *
+ * @date creation: Fri Aug 20 2010
+ * @date last modification: Wed Jan 31 2018
+ *
+ * @brief  Implementation of the inline functions of the HeatTransferModel class
+ *
+ * @section LICENSE
+ *
+ * Copyright (©)  2010-2018 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_FLUID_DIFFUSION_MODEL_INLINE_IMPL_CC__
+#define __AKANTU_FLUID_DIFFUSION_MODEL_INLINE_IMPL_CC__
+
+namespace akantu {
+
+/* -------------------------------------------------------------------------- */
+
+} // namespace akantu
+
+#endif /* __AKANTU_FLUID_DIFFUSION_MODEL_INLINE_IMPL_CC__ */
diff --git a/src/model/model.hh b/src/model/model.hh
index ffcf1d6af..bdec4baeb 100644
--- a/src/model/model.hh
+++ b/src/model/model.hh
@@ -1,363 +1,365 @@
 /**
  * @file   model.hh
  *
  * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
  * @author David Simon Kammer <david.kammer@epfl.ch>
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Fri Jun 18 2010
  * @date last modification: Tue Feb 20 2018
  *
  * @brief  Interface of a model
  *
  *
  * Copyright (©)  2010-2018 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_named_argument.hh"
 #include "fe_engine.hh"
 #include "mesh.hh"
 #include "model_options.hh"
 #include "model_solver.hh"
 /* -------------------------------------------------------------------------- */
 #include <typeindex>
 /* -------------------------------------------------------------------------- */
 
 #ifndef AKANTU_MODEL_HH_
 #define AKANTU_MODEL_HH_
 
 namespace akantu {
 class SynchronizerRegistry;
 class Parser;
 class DumperIOHelper;
 } // namespace akantu
 
 /* -------------------------------------------------------------------------- */
 namespace akantu {
 
 class Model : public ModelSolver, public MeshEventHandler {
   /* ------------------------------------------------------------------------ */
   /* Constructors/Destructors                                                 */
   /* ------------------------------------------------------------------------ */
 public:
   Model(Mesh & mesh, const ModelType & type, UInt dim = _all_dimensions,
         const ID & id = "model");
 
   ~Model() override;
 
   using FEEngineMap = std::map<std::string, std::unique_ptr<FEEngine>>;
 
   /* ------------------------------------------------------------------------ */
   /* Methods                                                                  */
   /* ------------------------------------------------------------------------ */
 protected:
   virtual void initFullImpl(const ModelOptions & options);
 
 public:
   template <typename... pack>
   std::enable_if_t<are_named_argument<pack...>::value>
   initFull(pack &&... _pack) {
     switch (this->model_type) {
 #ifdef AKANTU_SOLID_MECHANICS
     case ModelType::_solid_mechanics_model:
       this->initFullImpl(SolidMechanicsModelOptions{
           use_named_args, std::forward<decltype(_pack)>(_pack)...});
       break;
 #endif
 #ifdef AKANTU_COHESIVE_ELEMENT
     case ModelType::_solid_mechanics_model_cohesive:
       this->initFullImpl(SolidMechanicsModelCohesiveOptions{
           use_named_args, std::forward<decltype(_pack)>(_pack)...});
       break;
 #endif
 #ifdef AKANTU_HEAT_TRANSFER
     case ModelType::_heat_transfer_model:
       this->initFullImpl(HeatTransferModelOptions{
           use_named_args, std::forward<decltype(_pack)>(_pack)...});
       break;
 #endif
+#ifdef AKANTU_FLUID_DIFFUSION
+    case ModelType::_fluid_diffusion_model:
+      this->initFullImpl(FluidDiffusionModelOptions{
+          use_named_args, std::forward<decltype(_pack)>(_pack)...});
+      break;
+#endif
 #ifdef AKANTU_PHASE_FIELD
     case ModelType::_phase_field_model:
       this->initFullImpl(PhaseFieldModelOptions{
           use_named_args, std::forward<decltype(_pack)>(_pack)...});
       break;
-#endif      
+#endif
 #ifdef AKANTU_EMBEDDED
     case ModelType::_embedded_model:
       this->initFullImpl(EmbeddedInterfaceModelOptions{
           use_named_args, std::forward<decltype(_pack)>(_pack)...});
       break;
 #endif
     default:
       this->initFullImpl(ModelOptions{use_named_args,
                                       std::forward<decltype(_pack)>(_pack)...});
     }
   }
 
   template <typename... pack>
   std::enable_if_t<not are_named_argument<pack...>::value>
   initFull(pack &&... _pack) {
     this->initFullImpl(std::forward<decltype(_pack)>(_pack)...);
   }
 
   /// initialize a new solver if needed
   void initNewSolver(const AnalysisMethod & method);
 
 protected:
   /// get some default values for derived classes
   virtual std::tuple<ID, TimeStepSolverType>
   getDefaultSolverID(const AnalysisMethod & method) = 0;
 
   virtual void initModel() = 0;
 
   virtual void initFEEngineBoundary();
 
   /// function to print the containt of the class
   void printself(std::ostream & /*stream*/,
                  int /*indent*/ = 0) const override{};
 
 public:
   /* ------------------------------------------------------------------------ */
   /* Access to the dumpable interface of the boundaries                       */
   /* ------------------------------------------------------------------------ */
   /// Dump the data for a given group
   void dumpGroup(const std::string & group_name);
   void dumpGroup(const std::string & group_name,
                  const std::string & dumper_name);
   /// Dump the data for all boundaries
   void dumpGroup();
   /// Set the directory for a given group
   void setGroupDirectory(const std::string & directory,
                          const std::string & group_name);
   /// Set the directory for all boundaries
   void setGroupDirectory(const std::string & directory);
   /// Set the base name for a given group
   void setGroupBaseName(const std::string & basename,
                         const std::string & group_name);
   /// Get the internal dumper of a given group
   DumperIOHelper & getGroupDumper(const std::string & group_name);
 
   /* ------------------------------------------------------------------------ */
   /* Function for non local capabilities                                      */
   /* ------------------------------------------------------------------------ */
   virtual void updateDataForNonLocalCriterion(__attribute__((unused))
                                               ElementTypeMapReal & criterion) {
     AKANTU_TO_IMPLEMENT();
   }
 
 protected:
   template <typename T>
   void allocNodalField(std::unique_ptr<Array<T>> & array, UInt nb_component,
                        const ID & name) const;
 
   /* ------------------------------------------------------------------------ */
   /* Accessors */
   /* ------------------------------------------------------------------------ */
 public:
   /// get id of model
   AKANTU_GET_MACRO(ID, id, const ID &)
 
   /// get the number of surfaces
   AKANTU_GET_MACRO(Mesh, mesh, Mesh &)
 
   /// synchronize the boundary in case of parallel run
   virtual void synchronizeBoundaries(){};
 
   /// return the fem object associated with a provided name
   inline FEEngine & getFEEngine(const ID & name = "") const;
 
   /// return the fem boundary object associated with a provided name
   virtual FEEngine & getFEEngineBoundary(const ID & name = "");
 
   /// register a fem object associated with name
   template <typename FEEngineClass>
   inline void registerFEEngineObject(const std::string & name, Mesh & mesh,
                                      UInt spatial_dimension);
   /// unregister a fem object associated with name
   inline void unRegisterFEEngineObject(const std::string & name);
 
   /// return the synchronizer registry
   SynchronizerRegistry & getSynchronizerRegistry();
 
   /// return the fem object associated with a provided name
   template <typename FEEngineClass>
   inline FEEngineClass & getFEEngineClass(std::string name = "") const;
 
   /// return the fem boundary object associated with a provided name
   template <typename FEEngineClass>
   inline FEEngineClass & getFEEngineClassBoundary(std::string name = "");
 
   /// Get the type of analysis method used
   AKANTU_GET_MACRO(AnalysisMethod, method, AnalysisMethod);
 
   /* ------------------------------------------------------------------------ */
-  /* Pack and unpack hexlper functions                                         */
+  /* Pack and unpack hexlper functions */
   /* ------------------------------------------------------------------------ */
 public:
   inline UInt getNbIntegrationPoints(const Array<Element> & elements,
                                      const ID & fem_id = ID()) const;
 
   /* ------------------------------------------------------------------------ */
   /* Dumpable interface (kept for convenience) and dumper relative functions  */
   /* ------------------------------------------------------------------------ */
   void setTextModeToDumper();
 
   virtual void addDumpGroupFieldToDumper(const std::string & field_id,
                                          std::shared_ptr<dumpers::Field> field,
                                          DumperIOHelper & dumper);
 
   virtual void addDumpField(const std::string & field_id);
 
   virtual void addDumpFieldVector(const std::string & field_id);
 
   virtual void addDumpFieldToDumper(const std::string & dumper_name,
                                     const std::string & field_id);
 
   virtual void addDumpFieldVectorToDumper(const std::string & dumper_name,
                                           const std::string & field_id);
 
   virtual void addDumpFieldTensorToDumper(const std::string & dumper_name,
                                           const std::string & field_id);
 
   virtual void addDumpFieldTensor(const std::string & field_id);
 
   virtual void setBaseName(const std::string & field_id);
 
   virtual void setBaseNameToDumper(const std::string & dumper_name,
                                    const std::string & basename);
 
   virtual void addDumpGroupField(const std::string & field_id,
                                  const std::string & group_name);
 
   virtual void addDumpGroupFieldToDumper(const std::string & dumper_name,
                                          const std::string & field_id,
                                          const std::string & group_name,
                                          ElementKind element_kind,
                                          bool padding_flag);
 
   virtual void addDumpGroupFieldToDumper(const std::string & dumper_name,
                                          const std::string & field_id,
                                          const std::string & group_name,
                                          UInt spatial_dimension,
                                          ElementKind element_kind,
                                          bool padding_flag);
 
   virtual void removeDumpGroupField(const std::string & field_id,
                                     const std::string & group_name);
   virtual void removeDumpGroupFieldFromDumper(const std::string & dumper_name,
                                               const std::string & field_id,
                                               const std::string & group_name);
 
   virtual void addDumpGroupFieldVector(const std::string & field_id,
                                        const std::string & group_name);
 
   virtual void addDumpGroupFieldVectorToDumper(const std::string & dumper_name,
                                                const std::string & field_id,
                                                const std::string & group_name);
 
   virtual std::shared_ptr<dumpers::Field>
   createNodalFieldReal(const std::string & /*field_name*/,
                        const std::string & /*group_name*/,
                        bool /*padding_flag*/) {
     return nullptr;
   }
 
   virtual std::shared_ptr<dumpers::Field>
   createNodalFieldUInt(const std::string & /*field_name*/,
                        const std::string & /*group_name*/,
                        bool /*padding_flag*/) {
     return nullptr;
   }
 
   virtual std::shared_ptr<dumpers::Field>
   createNodalFieldBool(const std::string & /*field_name*/,
                        const std::string & /*group_name*/,
                        bool /*padding_flag*/) {
     return nullptr;
   }
 
-  virtual std::shared_ptr<dumpers::Field>
-  createElementalField(const std::string & /*field_name*/,
-                       const std::string & /*group_name*/,
-                       bool /*padding_flag*/,
-                       UInt /*spatial_dimension*/,
-                       ElementKind /*kind*/) {
+  virtual std::shared_ptr<dumpers::Field> createElementalField(
+      const std::string & /*field_name*/, const std::string & /*group_name*/,
+      bool /*padding_flag*/, UInt /*spatial_dimension*/, ElementKind /*kind*/) {
     return nullptr;
   }
 
   void setDirectory(const std::string & directory);
   void setDirectoryToDumper(const std::string & dumper_name,
                             const std::string & directory);
 
-
   /* ------------------------------------------------------------------------ */
   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);
 
   /* ------------------------------------------------------------------------ */
   /* Class Members                                                            */
   /* ------------------------------------------------------------------------ */
 protected:
   friend std::ostream & operator<<(std::ostream & /*stream*/,
                                    const Model & /*_this*/);
 
   ID id;
 
   /// analysis method check the list in akantu::AnalysisMethod
   AnalysisMethod method;
 
   /// Mesh
   Mesh & mesh;
 
   /// Spatial dimension of the problem
   UInt spatial_dimension;
 
   /// the main fem object present in all  models
   FEEngineMap fems;
 
   /// the fem object present in all  models for boundaries
   FEEngineMap fems_boundary;
 
   /// default fem object
   std::string default_fem;
 
   /// parser to the pointer to use
   Parser & parser;
 
   /// default ElementKind for dumper
   ElementKind dumper_default_element_kind{_ek_regular};
 };
 
 /// standard output stream operator
 inline std::ostream & operator<<(std::ostream & stream, const Model & _this) {
   _this.printself(stream);
   return stream;
 }
 
 } // namespace akantu
 
 #include "model_inline_impl.hh"
 
 #endif /* AKANTU_MODEL_HH_ */
diff --git a/src/model/model_options.hh b/src/model/model_options.hh
index a1fcebf60..1007ca3e1 100644
--- a/src/model/model_options.hh
+++ b/src/model/model_options.hh
@@ -1,154 +1,168 @@
 /**
  * @file   model_options.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Mon Dec 04 2017
  * @date last modification: Wed Jan 31 2018
  *
  * @brief  A Documented file.
  *
  *
  * Copyright (©) 2016-2018 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_named_argument.hh"
 /* -------------------------------------------------------------------------- */
 
 #ifndef AKANTU_MODEL_OPTIONS_HH_
 #define AKANTU_MODEL_OPTIONS_HH_
 
 namespace akantu {
 
 namespace {
   DECLARE_NAMED_ARGUMENT(analysis_method);
 }
 
 struct ModelOptions {
   explicit ModelOptions(AnalysisMethod analysis_method = _static)
       : analysis_method(analysis_method) {}
 
   template <typename... pack>
   ModelOptions(use_named_args_t /*unused*/, pack &&... _pack)
       : ModelOptions(OPTIONAL_NAMED_ARG(analysis_method, _static)) {}
 
   virtual ~ModelOptions() = default;
 
   AnalysisMethod analysis_method;
 };
 
 #ifdef AKANTU_SOLID_MECHANICS
 /* -------------------------------------------------------------------------- */
 struct SolidMechanicsModelOptions : public ModelOptions {
   explicit SolidMechanicsModelOptions(
       AnalysisMethod analysis_method = _explicit_lumped_mass)
       : ModelOptions(analysis_method) {}
 
   template <typename... pack>
   SolidMechanicsModelOptions(use_named_args_t /*unused*/, pack &&... _pack)
       : SolidMechanicsModelOptions(
             OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass)) {}
 };
 #endif
 
 /* -------------------------------------------------------------------------- */
 #ifdef AKANTU_COHESIVE_ELEMENT
 namespace {
   DECLARE_NAMED_ARGUMENT(is_extrinsic);
 }
 /* -------------------------------------------------------------------------- */
 struct SolidMechanicsModelCohesiveOptions : public SolidMechanicsModelOptions {
   SolidMechanicsModelCohesiveOptions(
       AnalysisMethod analysis_method = _explicit_lumped_mass,
       bool extrinsic = false)
       : SolidMechanicsModelOptions(analysis_method), is_extrinsic(extrinsic) {}
 
   template <typename... pack>
   SolidMechanicsModelCohesiveOptions(use_named_args_t /*unused*/,
                                      pack &&... _pack)
       : SolidMechanicsModelCohesiveOptions(
             OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass),
             OPTIONAL_NAMED_ARG(is_extrinsic, false)) {}
 
   bool is_extrinsic{false};
 };
 #endif
 
 #ifdef AKANTU_HEAT_TRANSFER
 /* -------------------------------------------------------------------------- */
 struct HeatTransferModelOptions : public ModelOptions {
   explicit HeatTransferModelOptions(
       AnalysisMethod analysis_method = _explicit_lumped_mass)
       : ModelOptions(analysis_method) {}
 
   template <typename... pack>
   HeatTransferModelOptions(use_named_args_t /*unused*/, pack &&... _pack)
       : HeatTransferModelOptions(
             OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass)) {}
 };
 #endif
 
+#ifdef AKANTU_FLUID_DIFFUSION
+/* --------------------------------------------------------------------------
+ */
+struct FluidDiffusionModelOptions : public ModelOptions {
+  explicit FluidDiffusionModelOptions(AnalysisMethod analysis_method = _static)
+      : ModelOptions(analysis_method) {}
+
+  template <typename... pack>
+  FluidDiffusionModelOptions(use_named_args_t, pack &&... _pack)
+      : FluidDiffusionModelOptions(
+            OPTIONAL_NAMED_ARG(analysis_method, _static)) {}
+};
+#endif
+
 #ifdef AKANTU_PHASE_FIELD
 /* -------------------------------------------------------------------------- */
 struct PhaseFieldModelOptions : public ModelOptions {
   explicit PhaseFieldModelOptions(
       AnalysisMethod analysis_method = _explicit_lumped_mass)
       : ModelOptions(analysis_method) {}
 
   template <typename... pack>
   PhaseFieldModelOptions(use_named_args_t, pack &&... _pack)
       : PhaseFieldModelOptions(
             OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass)) {}
 };
 #endif
 
 /* -------------------------------------------------------------------------- */
 #ifdef AKANTU_EMBEDDED
 
 namespace {
   DECLARE_NAMED_ARGUMENT(init_intersections);
 }
 /* -------------------------------------------------------------------------- */
 struct EmbeddedInterfaceModelOptions : SolidMechanicsModelOptions {
   /**
    * @brief Constructor for EmbeddedInterfaceModelOptions
    * @param analysis_method see SolidMechanicsModelOptions
    * @param init_intersections compute intersections
    */
   EmbeddedInterfaceModelOptions(
       AnalysisMethod analysis_method = _explicit_lumped_mass,
       bool init_intersections = true)
       : SolidMechanicsModelOptions(analysis_method),
         has_intersections(init_intersections) {}
 
   template <typename... pack>
   EmbeddedInterfaceModelOptions(use_named_args_t /*unused*/, pack &&... _pack)
       : EmbeddedInterfaceModelOptions(
             OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass),
             OPTIONAL_NAMED_ARG(init_intersections, true)) {}
 
   /// Should consider reinforcements
   bool has_intersections;
 };
 #endif
 
 } // namespace akantu
 
 #endif /* AKANTU_MODEL_OPTIONS_HH_ */