diff --git a/src/common/aka_types.hh b/src/common/aka_types.hh
index 11e464ebe..fbd84f695 100644
--- a/src/common/aka_types.hh
+++ b/src/common/aka_types.hh
@@ -1,1548 +1,1556 @@
 /**
  * @file   aka_types.hh
  *
  * @author Nicolas Richart <nicolas.richart@epfl.ch>
  *
  * @date creation: Thu Feb 17 2011
  * @date last modification: Tue Feb 20 2018
  *
  * @brief  description of the "simple" types
  *
  *
  * 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_math.hh"
 /* -------------------------------------------------------------------------- */
 #include <initializer_list>
 #include <iomanip>
 #include <type_traits>
 /* -------------------------------------------------------------------------- */
 
 #ifndef AKANTU_AKA_TYPES_HH_
 #define AKANTU_AKA_TYPES_HH_
 
 namespace akantu {
 
 enum NormType { L_1 = 1, L_2 = 2, L_inf = UInt(-1) };
 
 /**
  * DimHelper is a class to generalize the setup of a dim array from 3
  * values. This gives a common interface in the TensorStorage class
  * independently of its derived inheritance (Vector, Matrix, Tensor3)
  * @tparam dim
  */
 template <UInt dim> struct DimHelper {
   static inline void setDims(UInt m, UInt n, UInt p,
-                             std::array<UInt, dim> dims);
+                             std::array<UInt, dim> & dims);
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct DimHelper<1> {
   static inline void setDims(UInt m, UInt /*n*/, UInt /*p*/,
-                             std::array<UInt, 1> dims) {
+                             std::array<UInt, 1> & dims) {
     dims[0] = m;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct DimHelper<2> {
   static inline void setDims(UInt m, UInt n, UInt /*p*/,
-                             std::array<UInt, 2> dims) {
+                             std::array<UInt, 2> & dims) {
     dims[0] = m;
     dims[1] = n;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <> struct DimHelper<3> {
-  static inline void setDims(UInt m, UInt n, UInt p, std::array<UInt, 3> dims) {
+  static inline void setDims(UInt m, UInt n, UInt p,
+                             std::array<UInt, 3> & dims) {
     dims[0] = m;
     dims[1] = n;
     dims[2] = p;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T, UInt ndim, class RetType> class TensorStorage;
 
 /* -------------------------------------------------------------------------- */
 /* Proxy classes                                                              */
 /* -------------------------------------------------------------------------- */
 namespace tensors {
   template <class A, class B> struct is_copyable {
     enum : bool { value = false };
   };
 
   template <class A> struct is_copyable<A, A> {
     enum : bool { value = true };
   };
 
   template <class A> struct is_copyable<A, typename A::RetType> {
     enum : bool { value = true };
   };
 
   template <class A> struct is_copyable<A, typename A::RetType::proxy> {
     enum : bool { value = true };
   };
 
 } // namespace tensors
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 namespace types {
   namespace details {
     template <typename reference_> class vector_iterator {
     public:
       using difference_type = std::ptrdiff_t;
       using value_type = std::decay_t<reference_>;
       using pointer = value_type *;
       using reference = reference_;
       using iterator_category = std::input_iterator_tag;
 
       vector_iterator(pointer ptr) : ptr(ptr) {}
 
       // input iterator ++it
       vector_iterator & operator++() {
         ++ptr;
         return *this;
       }
       // input iterator it++
       vector_iterator operator++(int) {
         auto cpy = *this;
         ++ptr;
         return cpy;
       }
       vector_iterator & operator+=(int n) {
         ptr += n;
         return *this;
       }
 
       vector_iterator operator+(int n) {
         vector_iterator cpy(*this);
         cpy += n;
         return cpy;
       }
 
       // input iterator it != other_it
       bool operator!=(const vector_iterator & other) const {
         return ptr != other.ptr;
       }
       bool operator==(const vector_iterator & other) const {
         return ptr == other.ptr;
       }
 
       difference_type operator-(const vector_iterator & other) const {
         return this->ptr - other.ptr;
       }
 
       // input iterator dereference *it
       reference operator*() { return *ptr; }
       pointer operator->() { return ptr; }
 
     private:
       pointer ptr;
     };
   } // namespace details
 } // namespace types
 
 /**
  * @class TensorProxy aka_types.hh
  * The TensorProxy class is a proxy class to the
  * TensorStorage it handles the wrapped case. That is to say if an accessor
  * should give access to a Tensor wrapped on some data, like the
  * Array<T>::iterator they can return a TensorProxy that will be automatically
  * transformed as a TensorStorage wrapped on the same data
  * @tparam T stored type
  * @tparam ndim order of the tensor
  * @tparam _RetType real derived type
  */
 template <typename T, UInt ndim, class RetType_>
 class TensorProxy : public TensorProxyTrait {
 protected:
   using RetTypeProxy = typename RetType_::proxy;
 
   constexpr TensorProxy(T * data, UInt m, UInt n, UInt p) {
     DimHelper<ndim>::setDims(m, n, p, this->n);
     this->values = data;
   }
 
   template <class Other, typename = std::enable_if_t<
                              tensors::is_copyable<TensorProxy, Other>::value>>
   explicit TensorProxy(const Other & other) {
     this->values = other.storage();
     for (UInt i = 0; i < ndim; ++i) {
       this->n[i] = other.size(i);
     }
   }
 
 public:
   using RetType = RetType_;
 
   UInt size(UInt i) const {
     AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim
                                                           << " dimensions, not "
                                                           << (i + 1));
     return n[i];
   }
 
   inline UInt size() const {
     UInt _size = 1;
     for (UInt d = 0; d < ndim; ++d) {
       _size *= this->n[d];
     }
     return _size;
   }
 
   T * storage() const { return values; }
 
   template <class Other, typename = std::enable_if_t<
                              tensors::is_copyable<TensorProxy, Other>::value>>
   inline TensorProxy & operator=(const Other & other) {
     AKANTU_DEBUG_ASSERT(
         other.size() == this->size(),
         "You are trying to copy two tensors with different sizes");
     std::copy_n(other.storage(), this->size(), this->values);
     return *this;
   }
   // template <class Other, typename = std::enable_if_t<
   //                          tensors::is_copyable<TensorProxy, Other>::value>>
   // inline TensorProxy & operator=(const Other && other) {
   //   AKANTU_DEBUG_ASSERT(
   //       other.size() == this->size(),
   //       "You are trying to copy two tensors with different sizes");
   //   memcpy(this->values, other.storage(), this->size() * sizeof(T));
   //   return *this;
   // }
 
   template <typename O> inline RetTypeProxy & operator*=(const O & o) {
     RetType(*this) *= o;
     return static_cast<RetTypeProxy &>(*this);
   }
 
   template <typename O> inline RetTypeProxy & operator/=(const O & o) {
     RetType(*this) /= o;
     return static_cast<RetTypeProxy &>(*this);
   }
 
 protected:
   T * values;
   std::array<UInt, ndim> n;
 };
 
 /* -------------------------------------------------------------------------- */
 template <typename T> class VectorProxy : public TensorProxy<T, 1, Vector<T>> {
   using parent = TensorProxy<T, 1, Vector<T>>;
   using type = Vector<T>;
 
 public:
   constexpr VectorProxy(T * data, UInt n) : parent(data, n, 0, 0) {}
   template <class Other> explicit VectorProxy(Other & src) : parent(src) {}
 
   /* ---------------------------------------------------------------------- */
   template <class Other>
   inline VectorProxy<T> & operator=(const Other & other) {
     parent::operator=(other);
     return *this;
   }
 
   // inline VectorProxy<T> & operator=(const VectorProxy && other) {
   //   parent::operator=(other);
   //   return *this;
   // }
   using iterator = types::details::vector_iterator<T &>;
   using const_iterator = types::details::vector_iterator<const T &>;
 
   iterator begin() { return iterator(this->storage()); }
   iterator end() { return iterator(this->storage() + this->size()); }
 
   const_iterator begin() const { return const_iterator(this->storage()); }
   const_iterator end() const {
     return const_iterator(this->storage() + this->size());
   }
 
   /* ------------------------------------------------------------------------ */
   T & operator()(UInt index) { return this->values[index]; };
   const T & operator()(UInt index) const { return this->values[index]; };
 };
 
 template <typename T> class MatrixProxy : public TensorProxy<T, 2, Matrix<T>> {
   using parent = TensorProxy<T, 2, Matrix<T>>;
   using type = Matrix<T>;
 
 public:
   MatrixProxy(T * data, UInt m, UInt n) : parent(data, m, n, 0) {}
   template <class Other> explicit MatrixProxy(Other & src) : parent(src) {}
 
   /* ---------------------------------------------------------------------- */
   template <class Other>
   inline MatrixProxy<T> & operator=(const Other & other) {
     parent::operator=(other);
     return *this;
   }
 };
 
 template <typename T>
 class Tensor3Proxy : public TensorProxy<T, 3, Tensor3<T>> {
   using parent = TensorProxy<T, 3, Tensor3<T>>;
   using type = Tensor3<T>;
 
 public:
   Tensor3Proxy(const T * data, UInt m, UInt n, UInt k)
       : parent(data, m, n, k) {}
   Tensor3Proxy(const Tensor3Proxy & src) : parent(src) {}
   Tensor3Proxy(const Tensor3<T> & src) : parent(src) {}
 
   /* ---------------------------------------------------------------------- */
   template <class Other>
   inline Tensor3Proxy<T> & operator=(const Other & other) {
     parent::operator=(other);
     return *this;
   }
 };
 
 /* -------------------------------------------------------------------------- */
 /* Tensor base class                                                          */
 /* -------------------------------------------------------------------------- */
 template <typename T, UInt ndim, class RetType>
 class TensorStorage : public TensorTrait {
 public:
   using value_type = T;
 
   friend class Array<T>;
 
 protected:
   template <class TensorType> void copySize(const TensorType & src) {
     for (UInt d = 0; d < ndim; ++d) {
       this->n[d] = src.size(d); // NOLINT
     }
     this->_size = src.size();
   }
 
   TensorStorage() = default;
   TensorStorage(const TensorProxy<T, ndim, RetType> & proxy) {
     this->copySize(proxy);
     this->values = proxy.storage();
     this->wrapped = true;
   }
 
 public:
   TensorStorage(const TensorStorage & src) = delete;
 
   TensorStorage(const TensorStorage & src, bool deep_copy) : values(nullptr) {
     if (deep_copy) {
       this->deepCopy(src);
     } else {
       this->shallowCopy(src);
     }
   }
 
 protected:
   TensorStorage(UInt m, UInt n, UInt p, const T & def) {
     static_assert(std::is_trivially_constructible<T>{},
                   "Cannot create a tensor on non trivial types");
     DimHelper<ndim>::setDims(m, n, p, this->n);
 
     this->computeSize();
     this->values = new T[this->_size]; // NOLINT
     this->set(def);
     this->wrapped = false;
   }
 
   TensorStorage(T * data, UInt m, UInt n, UInt p) {
     DimHelper<ndim>::setDims(m, n, p, this->n);
 
     this->computeSize();
     this->values = data;
     this->wrapped = true;
   }
 
 public:
   /* ------------------------------------------------------------------------ */
   template <class TensorType> inline void shallowCopy(const TensorType & src) {
     this->copySize(src);
     if (!this->wrapped) {
       delete[] this->values;
     }
     this->values = src.storage();
     this->wrapped = true;
   }
 
   /* ------------------------------------------------------------------------ */
   template <class TensorType> inline void deepCopy(const TensorType & src) {
     this->copySize(src);
 
     if (!this->wrapped) {
       delete[] this->values;
     }
 
     static_assert(std::is_trivially_constructible<T>{},
                   "Cannot create a tensor on non trivial types");
     this->values = new T[this->_size]; // NOLINT
 
     static_assert(std::is_trivially_copyable<T>{},
                   "Cannot copy a tensor on non trivial types");
     std::copy_n(src.storage(), this->_size, this->values);
 
     this->wrapped = false;
   }
 
   virtual ~TensorStorage() {
     if (!this->wrapped) {
       delete[] this->values;
     }
   }
 
   /* ------------------------------------------------------------------------ */
   inline TensorStorage & operator=(const TensorStorage & other) {
-    if(this == &other) {
+    if (this == &other) {
       return *this;
     }
     this->operator=(aka::as_type<RetType>(other));
     return *this;
   }
 
-  inline TensorStorage & operator=(TensorStorage && other) noexcept = default;
+  // inline TensorStorage & operator=(TensorStorage && other) noexcept {
+  //   std::swap(n, other.n);
+  //   std::swap(_size, other._size);
+  //   std::swap(values, other.values);
+  //   std::swap(wrapped, other.wrapped);
+  //   return *this;
+  // }
 
   /* ------------------------------------------------------------------------ */
   inline TensorStorage & operator=(const RetType & src) {
     if (this != &src) {
       if (this->wrapped) {
         static_assert(std::is_trivially_copyable<T>{},
                       "Cannot copy a tensor on non trivial types");
         // this test is not sufficient for Tensor of order higher than 1
         AKANTU_DEBUG_ASSERT(this->_size == src.size(),
                             "Tensors of different size ("
                                 << this->_size << " != " << src.size() << ")");
         std::copy_n(src.storage(), this->_size, this->values);
       } else {
         deepCopy(src);
       }
     }
     return *this;
   }
 
   /* ------------------------------------------------------------------------ */
   template <class R>
   inline RetType & operator+=(const TensorStorage<T, ndim, R> & other) {
     T * a = this->storage();
     T * b = other.storage();
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be subtracted");
     for (UInt i = 0; i < _size; ++i) {
       *(a++) += *(b++);
     }
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   template <class R>
   inline RetType & operator-=(const TensorStorage<T, ndim, R> & other) {
     T * a = this->storage();
     T * b = other.storage();
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be subtracted");
     for (UInt i = 0; i < _size; ++i) {
       *(a++) -= *(b++);
     }
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   inline RetType & operator+=(const T & x) {
     T * a = this->values;
     for (UInt i = 0; i < _size; ++i) {
       *(a++) += x;
     }
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   inline RetType & operator-=(const T & x) {
     T * a = this->values;
     for (UInt i = 0; i < _size; ++i) {
       *(a++) -= x;
     }
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   inline RetType & operator*=(const T & x) {
     T * a = this->storage();
     for (UInt i = 0; i < _size; ++i) {
       *(a++) *= x;
     }
     return *(static_cast<RetType *>(this));
   }
 
   /* ---------------------------------------------------------------------- */
   inline RetType & operator/=(const T & x) {
     T * a = this->values;
     for (UInt i = 0; i < _size; ++i) {
       *(a++) /= x;
     }
     return *(static_cast<RetType *>(this));
   }
 
   /// \f[Y = \alpha X + Y\f]
   inline RetType & aXplusY(const TensorStorage & other, const T & alpha = 1.) {
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be subtracted");
 
     Math::aXplusY(this->_size, alpha, other.storage(), this->storage());
     return *(static_cast<RetType *>(this));
   }
 
   /* ------------------------------------------------------------------------ */
   T * storage() const { return values; }
   UInt size() const { return _size; }
   UInt size(UInt i) const {
     AKANTU_DEBUG_ASSERT(i < ndim, "This tensor has only " << ndim
                                                           << " dimensions, not "
                                                           << (i + 1));
     return n[i];
   };
   /* ------------------------------------------------------------------------ */
   inline void set(const T & t) { std::fill_n(values, _size, t); };
   inline void zero() { this->set(0.); };
-  
+
   template <class TensorType> inline void copy(const TensorType & other) {
     AKANTU_DEBUG_ASSERT(
         _size == other.size(),
         "The two tensors do not have the same size, they cannot be copied");
     std::copy_n(other.storage(), _size, values);
   }
 
   bool isWrapped() const { return this->wrapped; }
 
 protected:
   inline void computeSize() {
     _size = 1;
     for (UInt d = 0; d < ndim; ++d) {
       _size *= this->n[d];
     }
   }
 
 protected:
   template <typename R, NormType norm_type> struct NormHelper {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it) {
         _norm += std::pow(std::abs(*it), norm_type);
       }
       return std::pow(_norm, 1. / norm_type);
     }
-  };
+  }; // namespace akantu
 
   template <typename R> struct NormHelper<R, L_1> {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it) {
         _norm += std::abs(*it);
       }
       return _norm;
     }
   };
 
   template <typename R> struct NormHelper<R, L_2> {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it) {
         _norm += *it * *it;
       }
       return sqrt(_norm);
     }
   };
 
   template <typename R> struct NormHelper<R, L_inf> {
     template <class Ten> static R norm(const Ten & ten) {
       R _norm = 0.;
       R * it = ten.storage();
       R * end = ten.storage() + ten.size();
       for (; it < end; ++it) {
         _norm = std::max(std::abs(*it), _norm);
       }
       return _norm;
     }
   };
 
 public:
   /*----------------------------------------------------------------------- */
   /// "Entrywise" norm norm<L_p> @f[ \|\boldsymbol{T}\|_p = \left(
   /// \sum_i^{n[0]}\sum_j^{n[1]}\sum_k^{n[2]} |T_{ijk}|^p \right)^{\frac{1}{p}}
   /// @f]
   template <NormType norm_type> inline T norm() const {
     return NormHelper<T, norm_type>::norm(*this);
   }
 
 protected:
   std::array<UInt, ndim> n{};
   UInt _size{0};
   T * values{nullptr};
   bool wrapped{false};
 };
 
 /* -------------------------------------------------------------------------- */
 /* Vector                                                                     */
 /* -------------------------------------------------------------------------- */
 template <typename T> class Vector : public TensorStorage<T, 1, Vector<T>> {
   using parent = TensorStorage<T, 1, Vector<T>>;
 
 public:
   using value_type = typename parent::value_type;
   using proxy = VectorProxy<T>;
 
 public:
   Vector() : parent() {}
   explicit Vector(UInt n, const T & def = T()) : parent(n, 0, 0, def) {}
   Vector(T * data, UInt n) : parent(data, n, 0, 0) {}
   Vector(const Vector & src, bool deep_copy = true) : parent(src, deep_copy) {}
   Vector(const TensorProxy<T, 1, Vector> & src) : parent(src) {}
 
   Vector(std::initializer_list<T> list) : parent(list.size(), 0, 0, T()) {
     UInt i = 0;
     for (auto val : list) {
       operator()(i++) = val;
     }
   }
 
 public:
   using iterator = types::details::vector_iterator<T &>;
   using const_iterator = types::details::vector_iterator<const T &>;
 
   iterator begin() { return iterator(this->storage()); }
   iterator end() { return iterator(this->storage() + this->size()); }
 
   const_iterator begin() const { return const_iterator(this->storage()); }
   const_iterator end() const {
     return const_iterator(this->storage() + this->size());
   }
 
 public:
   ~Vector() override = default;
 
   /* ------------------------------------------------------------------------ */
   inline Vector & operator=(const Vector & src) {
     parent::operator=(src);
     return *this;
   }
 
   inline Vector & operator=(Vector && src) noexcept = default;
 
   /* ------------------------------------------------------------------------ */
   inline T & operator()(UInt i) {
     AKANTU_DEBUG_ASSERT((i < this->n[0]),
                         "Access out of the vector! "
                             << "Index (" << i
                             << ") is out of the vector of size (" << this->n[0]
                             << ")");
     return *(this->values + i);
   }
 
   inline const T & operator()(UInt i) const {
     AKANTU_DEBUG_ASSERT((i < this->n[0]),
                         "Access out of the vector! "
                             << "Index (" << i
                             << ") is out of the vector of size (" << this->n[0]
                             << ")");
     return *(this->values + i);
   }
 
   inline T & operator[](UInt i) { return this->operator()(i); }
   inline const T & operator[](UInt i) const { return this->operator()(i); }
 
   /* ------------------------------------------------------------------------ */
   inline Vector<T> & operator*=(Real x) { return parent::operator*=(x); }
   inline Vector<T> & operator/=(Real x) { return parent::operator/=(x); }
   /* ------------------------------------------------------------------------ */
   inline Vector<T> & operator*=(const Vector<T> & vect) {
     AKANTU_DEBUG_ASSERT(this->_size == vect._size,
                         "The vectors have non matching sizes");
     T * a = this->storage();
     T * b = vect.storage();
     for (UInt i = 0; i < this->_size; ++i) {
       *(a++) *= *(b++);
     }
     return *this;
   }
 
   /* ------------------------------------------------------------------------ */
   inline Real dot(const Vector<T> & vect) const {
     return Math::vectorDot(this->values, vect.storage(), this->_size);
   }
 
   /* ------------------------------------------------------------------------ */
   inline Real mean() const {
     Real mean = 0;
     T * a = this->storage();
     for (UInt i = 0; i < this->_size; ++i) {
       mean += *(a++);
     }
     return mean / this->_size;
   }
 
   /* ------------------------------------------------------------------------ */
   inline Vector & crossProduct(const Vector<T> & v1, const Vector<T> & v2) {
     AKANTU_DEBUG_ASSERT(this->size() == 3,
                         "crossProduct is only defined in 3D (n=" << this->size()
                                                                  << ")");
     AKANTU_DEBUG_ASSERT(
         this->size() == v1.size() && this->size() == v2.size(),
         "crossProduct is not a valid operation non matching size vectors");
     Math::vectorProduct3(v1.storage(), v2.storage(), this->values);
     return *this;
   }
 
   inline Vector crossProduct(const Vector<T> & v) {
     Vector<T> tmp(this->size());
     tmp.crossProduct(*this, v);
     return tmp;
   }
 
   /* ------------------------------------------------------------------------ */
   inline void solve(const Matrix<T> & A, const Vector<T> & b) {
     AKANTU_DEBUG_ASSERT(
         this->size() == A.rows() && this->_size == A.cols(),
         "The size of the solution vector mismatches the size of the matrix");
     AKANTU_DEBUG_ASSERT(
         this->_size == b._size,
         "The rhs vector has a mismatch in size with the matrix");
     Math::solve(this->_size, A.storage(), this->values, b.storage());
   }
 
   /* ------------------------------------------------------------------------ */
   template <bool tr_A>
   inline void mul(const Matrix<T> & A, const Vector<T> & x, T alpha = T(1));
   /* ------------------------------------------------------------------------ */
   inline Real norm() const { return parent::template norm<L_2>(); }
 
   template <NormType nt> inline Real norm() const {
     return parent::template norm<nt>();
   }
 
   /* ------------------------------------------------------------------------ */
   inline Vector<Real> & normalize() {
     Real n = norm();
     operator/=(n);
     return *this;
   }
 
   /* ------------------------------------------------------------------------ */
   /// norm of (*this - x)
   inline Real distance(const Vector<T> & y) const {
     Real * vx = this->values;
     Real * vy = y.storage();
     Real sum_2 = 0;
     for (UInt i = 0; i < this->_size; ++i, ++vx, ++vy) { // NOLINT
       sum_2 += (*vx - *vy) * (*vx - *vy);
     }
     return sqrt(sum_2);
   }
 
   /* ------------------------------------------------------------------------ */
   inline bool equal(const Vector<T> & v,
                     Real tolerance = Math::getTolerance()) const {
     T * a = this->storage();
     T * b = v.storage();
     UInt i = 0;
     while (i < this->_size && (std::abs(*(a++) - *(b++)) < tolerance)) {
       ++i;
     }
     return i == this->_size;
   }
 
   /* ------------------------------------------------------------------------ */
   inline short compare(const Vector<T> & v,
                        Real tolerance = Math::getTolerance()) const {
     T * a = this->storage();
     T * b = v.storage();
     for (UInt i(0); i < this->_size; ++i, ++a, ++b) {
       if (std::abs(*a - *b) > tolerance) {
         return (((*a - *b) > tolerance) ? 1 : -1);
       }
     }
     return 0;
   }
 
   /* ------------------------------------------------------------------------ */
   inline bool operator==(const Vector<T> & v) const { return equal(v); }
   inline bool operator!=(const Vector<T> & v) const { return !operator==(v); }
   inline bool operator<(const Vector<T> & v) const { return compare(v) == -1; }
   inline bool operator>(const Vector<T> & v) const { return compare(v) == 1; }
 
   template <typename Func, typename Acc>
   decltype(auto) accumulate(const Vector<T> & v, Acc && accumulator,
                             Func && func) const {
     T * a = this->storage();
     T * b = v.storage();
     for (UInt i(0); i < this->_size; ++i, ++a, ++b) {
       accumulator = func(*a, *b, std::forward<Acc>(accumulator));
     }
     return accumulator;
   }
 
   inline bool operator<=(const Vector<T> & v) const {
     bool res = true;
     return accumulate(v, res, [](auto && a, auto && b, auto && accumulator) {
       return accumulator & (a <= b);
     });
   }
 
   inline bool operator>=(const Vector<T> & v) const {
     bool res = true;
     return accumulate(v, res, [](auto && a, auto && b, auto && accumulator) {
       return accumulator & (a >= b);
     });
   }
 
   /* ------------------------------------------------------------------------ */
   /// function to print the containt of the class
   virtual void printself(std::ostream & stream, int indent = 0) const {
     std::string space;
     for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) {
       ;
     }
 
     stream << "[";
     for (UInt i = 0; i < this->_size; ++i) {
       if (i != 0) {
         stream << ", ";
       }
       stream << this->values[i];
     }
     stream << "]";
   }
 
   /* ---------------------------------------------------------------------- */
   static inline Vector<T> zeros(UInt n) {
     Vector<T> tmp(n);
     tmp.set(T());
     return tmp;
   }
 };
 
 using RVector = Vector<Real>;
 
 /* ------------------------------------------------------------------------ */
 template <>
 inline bool Vector<UInt>::equal(const Vector<UInt> & v,
                                 __attribute__((unused)) Real tolerance) const {
   UInt * a = this->storage();
   UInt * b = v.storage();
   UInt i = 0;
   while (i < this->_size && (*(a++) == *(b++))) {
     ++i;
   }
   return i == this->_size;
 }
 
 /* -------------------------------------------------------------------------- */
 namespace types {
   namespace details {
     template <typename Mat> class column_iterator {
     public:
       using difference_type = std::ptrdiff_t;
       using value_type = decltype(std::declval<Mat>().operator()(0));
       using pointer = value_type *;
       using reference = value_type &;
       using iterator_category = std::input_iterator_tag;
 
       column_iterator(Mat & mat, UInt col) : mat(mat), col(col) {}
       decltype(auto) operator*() { return mat(col); }
       decltype(auto) operator++() {
         ++col;
         AKANTU_DEBUG_ASSERT(col <= mat.cols(), "The iterator is out of bound");
         return *this;
       }
       decltype(auto) operator++(int) {
         auto tmp = *this;
         ++col;
         AKANTU_DEBUG_ASSERT(col <= mat.cols(), "The iterator is out of bound");
         return tmp;
       }
       bool operator!=(const column_iterator & other) const {
         return col != other.col;
       }
 
       bool operator==(const column_iterator & other) const {
         return not operator!=(other);
       }
 
     private:
       Mat & mat;
       UInt col;
     };
   } // namespace details
 } // namespace types
 
 /* ------------------------------------------------------------------------ */
 /* Matrix                                                                   */
 /* ------------------------------------------------------------------------ */
 template <typename T> class Matrix : public TensorStorage<T, 2, Matrix<T>> {
   using parent = TensorStorage<T, 2, Matrix<T>>;
 
 public:
   using value_type = typename parent::value_type;
   using proxy = MatrixProxy<T>;
 
 public:
   Matrix() : parent() {}
   Matrix(UInt m, UInt n, const T & def = T()) : parent(m, n, 0, def) {}
   Matrix(T * data, UInt m, UInt n) : parent(data, m, n, 0) {}
   Matrix(const Matrix & src, bool deep_copy = true) : parent(src, deep_copy) {}
   Matrix(const MatrixProxy<T> & src) : parent(src) {}
   Matrix(std::initializer_list<std::initializer_list<T>> list) {
     static_assert(std::is_trivially_copyable<T>{},
                   "Cannot create a tensor on non trivial types");
     std::size_t n = 0;
     std::size_t m = list.size();
     for (auto row : list) {
       n = std::max(n, row.size());
     }
 
     DimHelper<2>::setDims(m, n, 0, this->n);
     this->computeSize();
     this->values = new T[this->_size];
     this->set(0);
 
     UInt i{0};
     UInt j{0};
     for (auto & row : list) {
       for (auto & val : row) {
         at(i, j++) = val;
       }
       ++i;
       j = 0;
     }
   }
 
   ~Matrix() override = default;
   /* ------------------------------------------------------------------------ */
   inline Matrix & operator=(const Matrix & src) {
     parent::operator=(src);
     return *this;
   }
 
   inline Matrix & operator=(Matrix && src) noexcept = default;
+
 public:
   /* ---------------------------------------------------------------------- */
   UInt rows() const { return this->n[0]; }
   UInt cols() const { return this->n[1]; }
 
   /* ---------------------------------------------------------------------- */
   inline T & at(UInt i, UInt j) {
     AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])),
                         "Access out of the matrix! "
                             << "Index (" << i << ", " << j
                             << ") is out of the matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return *(this->values + i + j * this->n[0]);
   }
 
   inline const T & at(UInt i, UInt j) const {
     AKANTU_DEBUG_ASSERT(((i < this->n[0]) && (j < this->n[1])),
                         "Access out of the matrix! "
                             << "Index (" << i << ", " << j
                             << ") is out of the matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return *(this->values + i + j * this->n[0]);
   }
 
   /* ------------------------------------------------------------------------ */
   inline T & operator()(UInt i, UInt j) { return this->at(i, j); }
   inline const T & operator()(UInt i, UInt j) const { return this->at(i, j); }
 
   /// give a line vector wrapped on the column i
   inline VectorProxy<T> operator()(UInt j) {
     AKANTU_DEBUG_ASSERT(j < this->n[1],
                         "Access out of the matrix! "
                             << "You are trying to access the column vector "
                             << j << " in a matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return VectorProxy<T>(this->values + j * this->n[0], this->n[0]);
   }
 
   inline VectorProxy<T> operator()(UInt j) const {
     AKANTU_DEBUG_ASSERT(j < this->n[1],
                         "Access out of the matrix! "
                             << "You are trying to access the column vector "
                             << j << " in a matrix of size (" << this->n[0]
                             << ", " << this->n[1] << ")");
     return VectorProxy<T>(this->values + j * this->n[0], this->n[0]);
   }
 
 public:
   decltype(auto) begin() {
     return types::details::column_iterator<Matrix<T>>(*this, 0);
   }
   decltype(auto) begin() const {
     return types::details::column_iterator<const Matrix<T>>(*this, 0);
   }
 
   decltype(auto) end() {
     return types::details::column_iterator<Matrix<T>>(*this, this->cols());
   }
   decltype(auto) end() const {
     return types::details::column_iterator<const Matrix<T>>(*this,
                                                             this->cols());
   }
 
   /* ------------------------------------------------------------------------ */
   inline void block(const Matrix & block, UInt pos_i, UInt pos_j) {
     AKANTU_DEBUG_ASSERT(pos_i + block.rows() <= rows(),
                         "The block size or position are not correct");
     AKANTU_DEBUG_ASSERT(pos_i + block.cols() <= cols(),
                         "The block size or position are not correct");
     for (UInt i = 0; i < block.rows(); ++i) {
       for (UInt j = 0; j < block.cols(); ++j) {
         this->at(i + pos_i, j + pos_j) = block(i, j);
       }
     }
   }
 
   inline Matrix block(UInt pos_i, UInt pos_j, UInt block_rows,
                       UInt block_cols) const {
     AKANTU_DEBUG_ASSERT(pos_i + block_rows <= rows(),
                         "The block size or position are not correct");
     AKANTU_DEBUG_ASSERT(pos_i + block_cols <= cols(),
                         "The block size or position are not correct");
     Matrix block(block_rows, block_cols);
     for (UInt i = 0; i < block_rows; ++i) {
       for (UInt j = 0; j < block_cols; ++j) {
         block(i, j) = this->at(i + pos_i, j + pos_j);
       }
     }
     return block;
   }
 
   inline T & operator[](UInt idx) { return *(this->values + idx); };
   inline const T & operator[](UInt idx) const { return *(this->values + idx); };
 
   /* ---------------------------------------------------------------------- */
   inline Matrix operator*(const Matrix & B) const {
     Matrix C(this->rows(), B.cols());
     C.mul<false, false>(*this, B);
     return C;
   }
 
   /* ----------------------------------------------------------------------- */
   inline Matrix & operator*=(const T & x) { return parent::operator*=(x); }
 
   inline Matrix & operator*=(const Matrix & B) {
     Matrix C(*this);
     this->mul<false, false>(C, B);
     return *this;
   }
 
   /* ---------------------------------------------------------------------- */
   template <bool tr_A, bool tr_B>
   inline void mul(const Matrix & A, const Matrix & B, T alpha = 1.0) {
     UInt k = A.cols();
     if (tr_A) {
       k = A.rows();
     }
 
 #ifndef AKANTU_NDEBUG
     if (tr_B) {
       AKANTU_DEBUG_ASSERT(k == B.cols(),
                           "matrices to multiply have no fit dimensions");
       AKANTU_DEBUG_ASSERT(this->cols() == B.rows(),
                           "matrices to multiply have no fit dimensions");
     } else {
       AKANTU_DEBUG_ASSERT(k == B.rows(),
                           "matrices to multiply have no fit dimensions");
       AKANTU_DEBUG_ASSERT(this->cols() == B.cols(),
                           "matrices to multiply have no fit dimensions");
     }
     if (tr_A) {
       AKANTU_DEBUG_ASSERT(this->rows() == A.cols(),
                           "matrices to multiply have no fit dimensions");
     } else {
       AKANTU_DEBUG_ASSERT(this->rows() == A.rows(),
                           "matrices to multiply have no fit dimensions");
     }
 #endif // AKANTU_NDEBUG
 
     Math::matMul<tr_A, tr_B>(this->rows(), this->cols(), k, alpha, A.storage(),
                              B.storage(), 0., this->storage());
   }
 
   /* ---------------------------------------------------------------------- */
   inline void outerProduct(const Vector<T> & A, const Vector<T> & B) {
     AKANTU_DEBUG_ASSERT(
         A.size() == this->rows() && B.size() == this->cols(),
         "A and B are not compatible with the size of the matrix");
     for (UInt i = 0; i < this->rows(); ++i) {
       for (UInt j = 0; j < this->cols(); ++j) {
         this->values[i + j * this->rows()] += A[i] * B[j];
       }
     }
   }
 
 private:
   class EigenSorter {
   public:
     EigenSorter(const Vector<T> & eigs) : eigs(eigs) {}
 
     bool operator()(const UInt & a, const UInt & b) const {
       return (eigs(a) > eigs(b));
     }
 
   private:
     const Vector<T> & eigs;
   };
 
 public:
   /* ---------------------------------------------------------------------- */
   inline void eig(Vector<T> & eigenvalues, Matrix<T> & eigenvectors,
                   bool sort = true) const {
     AKANTU_DEBUG_ASSERT(this->cols() == this->rows(),
                         "eig is not a valid operation on a rectangular matrix");
     AKANTU_DEBUG_ASSERT(eigenvalues.size() == this->cols(),
                         "eigenvalues should be of size " << this->cols()
                                                          << ".");
 #ifndef AKANTU_NDEBUG
     if (eigenvectors.storage() != nullptr) {
       AKANTU_DEBUG_ASSERT((eigenvectors.rows() == eigenvectors.cols()) &&
                               (eigenvectors.rows() == this->cols()),
                           "Eigenvectors needs to be a square matrix of size "
                               << this->cols() << " x " << this->cols() << ".");
     }
 #endif
 
     Matrix<T> tmp = *this;
     Vector<T> tmp_eigs(eigenvalues.size());
     Matrix<T> tmp_eig_vects(eigenvectors.rows(), eigenvectors.cols());
 
     if (tmp_eig_vects.rows() == 0 || tmp_eig_vects.cols() == 0) {
       Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage());
     } else {
       Math::matrixEig(tmp.cols(), tmp.storage(), tmp_eigs.storage(),
                       tmp_eig_vects.storage());
     }
 
     if (not sort) {
       eigenvalues = tmp_eigs;
       eigenvectors = tmp_eig_vects;
       return;
     }
 
     Vector<UInt> perm(eigenvalues.size());
     for (UInt i = 0; i < perm.size(); ++i) {
       perm(i) = i;
     }
 
     std::sort(perm.storage(), perm.storage() + perm.size(),
               EigenSorter(tmp_eigs));
 
     for (UInt i = 0; i < perm.size(); ++i) {
       eigenvalues(i) = tmp_eigs(perm(i));
     }
 
     if (tmp_eig_vects.rows() != 0 && tmp_eig_vects.cols() != 0) {
       for (UInt i = 0; i < perm.size(); ++i) {
         for (UInt j = 0; j < eigenvectors.rows(); ++j) {
           eigenvectors(j, i) = tmp_eig_vects(j, perm(i));
         }
       }
     }
   }
 
   /* ---------------------------------------------------------------------- */
   inline void eig(Vector<T> & eigenvalues) const {
     Matrix<T> empty;
     eig(eigenvalues, empty);
   }
 
   /* ---------------------------------------------------------------------- */
   inline void eye(T alpha = 1.) {
     AKANTU_DEBUG_ASSERT(this->cols() == this->rows(),
                         "eye is not a valid operation on a rectangular matrix");
     this->zero();
     for (UInt i = 0; i < this->cols(); ++i) {
       this->values[i + i * this->rows()] = alpha;
     }
   }
 
   /* ---------------------------------------------------------------------- */
   static inline Matrix<T> eye(UInt m, T alpha = 1.) {
     Matrix<T> tmp(m, m);
     tmp.eye(alpha);
     return tmp;
   }
 
   /* ---------------------------------------------------------------------- */
   inline T trace() const {
     AKANTU_DEBUG_ASSERT(
         this->cols() == this->rows(),
         "trace is not a valid operation on a rectangular matrix");
     T trace = 0.;
     for (UInt i = 0; i < this->rows(); ++i) {
       trace += this->values[i + i * this->rows()];
     }
     return trace;
   }
 
   /* ---------------------------------------------------------------------- */
   inline Matrix transpose() const {
     Matrix tmp(this->cols(), this->rows());
     for (UInt i = 0; i < this->rows(); ++i) {
       for (UInt j = 0; j < this->cols(); ++j) {
         tmp(j, i) = operator()(i, j);
       }
     }
     return tmp;
   }
 
   /* ---------------------------------------------------------------------- */
   inline void inverse(const Matrix & A) {
     AKANTU_DEBUG_ASSERT(A.cols() == A.rows(),
                         "inv is not a valid operation on a rectangular matrix");
     AKANTU_DEBUG_ASSERT(this->cols() == A.cols(),
                         "the matrix should have the same size as its inverse");
 
     if (this->cols() == 1) {
       *this->values = 1. / *A.storage();
     } else if (this->cols() == 2) {
       Math::inv2(A.storage(), this->values);
     } else if (this->cols() == 3) {
       Math::inv3(A.storage(), this->values);
     } else {
       Math::inv(this->cols(), A.storage(), this->values);
     }
   }
 
   inline Matrix inverse() {
     Matrix inv(this->rows(), this->cols());
     inv.inverse(*this);
     return inv;
   }
 
   /* --------------------------------------------------------------------- */
   inline T det() const {
     AKANTU_DEBUG_ASSERT(this->cols() == this->rows(),
                         "inv is not a valid operation on a rectangular matrix");
     if (this->cols() == 1) {
       return *(this->values);
     }
     if (this->cols() == 2) {
       return Math::det2(this->values);
     }
     if (this->cols() == 3) {
       return Math::det3(this->values);
     }
     return Math::det(this->cols(), this->values);
   }
 
   /* --------------------------------------------------------------------- */
   inline T doubleDot(const Matrix<T> & other) const {
     AKANTU_DEBUG_ASSERT(
         this->cols() == this->rows(),
         "doubleDot is not a valid operation on a rectangular matrix");
     if (this->cols() == 1) {
       return *(this->values) * *(other.storage());
     }
     if (this->cols() == 2) {
       return Math::matrixDoubleDot22(this->values, other.storage());
     }
     if (this->cols() == 3) {
       return Math::matrixDoubleDot33(this->values, other.storage());
     }
 
     AKANTU_ERROR("doubleDot is not defined for other spatial dimensions"
                  << " than 1, 2 or 3.");
   }
 
   /* ---------------------------------------------------------------------- */
   /// function to print the containt of the class
   virtual void printself(std::ostream & stream, int indent = 0) const {
     std::string space;
     for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) {
       ;
     }
 
     stream << "[";
     for (UInt i = 0; i < this->n[0]; ++i) {
       if (i != 0) {
         stream << ", ";
       }
       stream << "[";
       for (UInt j = 0; j < this->n[1]; ++j) {
         if (j != 0) {
           stream << ", ";
         }
         stream << operator()(i, j);
       }
       stream << "]";
     }
     stream << "]";
   };
 };
 
 /* ------------------------------------------------------------------------ */
 template <typename T>
 template <bool tr_A>
 inline void Vector<T>::mul(const Matrix<T> & A, const Vector<T> & x, T alpha) {
 #ifndef AKANTU_NDEBUG
   UInt n = x.size();
   if (tr_A) {
     AKANTU_DEBUG_ASSERT(n == A.rows(),
                         "matrix and vector to multiply have no fit dimensions");
     AKANTU_DEBUG_ASSERT(this->size() == A.cols(),
                         "matrix and vector to multiply have no fit dimensions");
   } else {
     AKANTU_DEBUG_ASSERT(n == A.cols(),
                         "matrix and vector to multiply have no fit dimensions");
     AKANTU_DEBUG_ASSERT(this->size() == A.rows(),
                         "matrix and vector to multiply have no fit dimensions");
   }
 #endif
   Math::matVectMul<tr_A>(A.rows(), A.cols(), alpha, A.storage(), x.storage(),
                          0., this->storage());
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline std::ostream & operator<<(std::ostream & stream,
                                  const Matrix<T> & _this) {
   _this.printself(stream);
   return stream;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 inline std::ostream & operator<<(std::ostream & stream,
                                  const Vector<T> & _this) {
   _this.printself(stream);
   return stream;
 }
 
 /* ------------------------------------------------------------------------ */
 /* Tensor3                                                                  */
 /* ------------------------------------------------------------------------ */
 template <typename T> class Tensor3 : public TensorStorage<T, 3, Tensor3<T>> {
   using parent = TensorStorage<T, 3, Tensor3<T>>;
 
 public:
   using value_type = typename parent::value_type;
   using proxy = Tensor3Proxy<T>;
 
 public:
   Tensor3() : parent(){};
 
   Tensor3(UInt m, UInt n, UInt p, const T & def = T()) : parent(m, n, p, def) {}
 
   Tensor3(T * data, UInt m, UInt n, UInt p) : parent(data, m, n, p) {}
 
   Tensor3(const Tensor3 & src, bool deep_copy = true)
       : parent(src, deep_copy) {}
 
   Tensor3(const proxy & src) : parent(src) {}
 
 public:
   /* ------------------------------------------------------------------------ */
   inline Tensor3 & operator=(const Tensor3 & src) {
     parent::operator=(src);
     return *this;
   }
 
   /* ---------------------------------------------------------------------- */
   inline T & operator()(UInt i, UInt j, UInt k) {
     AKANTU_DEBUG_ASSERT(
         (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]),
         "Access out of the tensor3! "
             << "You are trying to access the element "
             << "(" << i << ", " << j << ", " << k << ") in a tensor of size ("
             << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")");
     return *(this->values + (k * this->n[0] + i) * this->n[1] + j);
   }
 
   inline const T & operator()(UInt i, UInt j, UInt k) const {
     AKANTU_DEBUG_ASSERT(
         (i < this->n[0]) && (j < this->n[1]) && (k < this->n[2]),
         "Access out of the tensor3! "
             << "You are trying to access the element "
             << "(" << i << ", " << j << ", " << k << ") in a tensor of size ("
             << this->n[0] << ", " << this->n[1] << ", " << this->n[2] << ")");
     return *(this->values + (k * this->n[0] + i) * this->n[1] + j);
   }
 
   inline MatrixProxy<T> operator()(UInt k) {
     AKANTU_DEBUG_ASSERT((k < this->n[2]),
                         "Access out of the tensor3! "
                             << "You are trying to access the slice " << k
                             << " in a tensor3 of size (" << this->n[0] << ", "
                             << this->n[1] << ", " << this->n[2] << ")");
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 
   inline MatrixProxy<T> operator()(UInt k) const {
     AKANTU_DEBUG_ASSERT((k < this->n[2]),
                         "Access out of the tensor3! "
                             << "You are trying to access the slice " << k
                             << " in a tensor3 of size (" << this->n[0] << ", "
                             << this->n[1] << ", " << this->n[2] << ")");
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 
   inline MatrixProxy<T> operator[](UInt k) {
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 
   inline MatrixProxy<T> operator[](UInt k) const {
     return MatrixProxy<T>(this->values + k * this->n[0] * this->n[1],
                           this->n[0], this->n[1]);
   }
 };
 
 /* -------------------------------------------------------------------------- */
 // support operations for the creation of other vectors
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Vector<T> operator*(const T & scalar, const Vector<T> & a) {
   Vector<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Vector<T> operator*(const Vector<T> & a, const T & scalar) {
   Vector<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Vector<T> operator/(const Vector<T> & a, const T & scalar) {
   Vector<T> r(a);
   r /= scalar;
   return r;
 }
 
 template <typename T>
 Vector<T> operator*(const Vector<T> & a, const Vector<T> & b) {
   Vector<T> r(a);
   r *= b;
   return r;
 }
 
 template <typename T>
 Vector<T> operator+(const Vector<T> & a, const Vector<T> & b) {
   Vector<T> r(a);
   r += b;
   return r;
 }
 
 template <typename T>
 Vector<T> operator-(const Vector<T> & a, const Vector<T> & b) {
   Vector<T> r(a);
   r -= b;
   return r;
 }
 
 template <typename T>
 Vector<T> operator*(const Matrix<T> & A, const Vector<T> & b) {
   Vector<T> r(b.size());
   r.template mul<false>(A, b);
   return r;
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename T>
 Matrix<T> operator*(const T & scalar, const Matrix<T> & a) {
   Matrix<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator*(const Matrix<T> & a, const T & scalar) {
   Matrix<T> r(a);
   r *= scalar;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator/(const Matrix<T> & a, const T & scalar) {
   Matrix<T> r(a);
   r /= scalar;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator+(const Matrix<T> & a, const Matrix<T> & b) {
   Matrix<T> r(a);
   r += b;
   return r;
 }
 
 template <typename T>
 Matrix<T> operator-(const Matrix<T> & a, const Matrix<T> & b) {
   Matrix<T> r(a);
   r -= b;
   return r;
 }
 
 } // namespace akantu
 
 #include <iterator>
 
 namespace std {
 template <typename R>
 struct iterator_traits<::akantu::types::details::vector_iterator<R>> {
 protected:
   using iterator = ::akantu::types::details::vector_iterator<R>;
 
 public:
   using iterator_category = typename iterator::iterator_category;
   using value_type = typename iterator::value_type;
   using difference_type = typename iterator::difference_type;
   using pointer = typename iterator::pointer;
   using reference = typename iterator::reference;
 };
 
 template <typename Mat>
 struct iterator_traits<::akantu::types::details::column_iterator<Mat>> {
 protected:
   using iterator = ::akantu::types::details::column_iterator<Mat>;
 
 public:
   using iterator_category = typename iterator::iterator_category;
   using value_type = typename iterator::value_type;
   using difference_type = typename iterator::difference_type;
   using pointer = typename iterator::pointer;
   using reference = typename iterator::reference;
 };
 
 } // namespace std
 
 #endif /* AKANTU_AKA_TYPES_HH_ */
diff --git a/src/io/mesh_io/mesh_io_msh.cc b/src/io/mesh_io/mesh_io_msh.cc
index 9549a66a8..c6c76f2d3 100644
--- a/src/io/mesh_io/mesh_io_msh.cc
+++ b/src/io/mesh_io/mesh_io_msh.cc
@@ -1,1123 +1,1123 @@
 /**
  * @file   mesh_io_msh.cc
  *
  * @author Dana Christen <dana.christen@gmail.com>
  * @author Mauro Corrado <mauro.corrado@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  Read/Write for MSH files generated by gmsh
  *
  *
  * 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/>.
  *
  */
 
 /* -----------------------------------------------------------------------------
    Version (Legacy) 1.0
 
    $NOD
    number-of-nodes
    node-number x-coord y-coord z-coord
    ...
    $ENDNOD
    $ELM
    number-of-elements
    elm-number elm-type reg-phys reg-elem number-of-nodes node-number-list
    ...
    $ENDELM
    -----------------------------------------------------------------------------
    Version 2.1
 
    $MeshFormat
    version-number file-type data-size
    $EndMeshFormat
    $Nodes
    number-of-nodes
    node-number x-coord y-coord z-coord
    ...
    $EndNodes
    $Elements
    number-of-elements
    elm-number elm-type number-of-tags < tag > ... node-number-list
    ...
    $EndElements
    $PhysicalNames
    number-of-names
    physical-dimension physical-number "physical-name"
    ...
    $EndPhysicalNames
    $NodeData
    number-of-string-tags
    < "string-tag" >
    ...
    number-of-real-tags
    < real-tag >
    ...
    number-of-integer-tags
    < integer-tag >
    ...
    node-number value ...
    ...
    $EndNodeData
    $ElementData
    number-of-string-tags
    < "string-tag" >
    ...
    number-of-real-tags
    < real-tag >
    ...
    number-of-integer-tags
    < integer-tag >
    ...
    elm-number value ...
    ...
    $EndElementData
    $ElementNodeData
    number-of-string-tags
    < "string-tag" >
    ...
    number-of-real-tags
    < real-tag >
    ...
    number-of-integer-tags
    < integer-tag >
    ...
    elm-number number-of-nodes-per-element value ...
    ...
    $ElementEndNodeData
 
    -----------------------------------------------------------------------------
    elem-type
 
    1:  2-node line.
    2:  3-node triangle.
    3:  4-node quadrangle.
    4:  4-node tetrahedron.
    5:  8-node hexahedron.
    6:  6-node prism.
    7:  5-node pyramid.
    8:  3-node second order line
    9:  6-node second order triangle
    10: 9-node second order quadrangle
    11: 10-node second order tetrahedron
    12: 27-node second order hexahedron
    13: 18-node second order prism
    14: 14-node second order pyramid
    15: 1-node point.
    16: 8-node second order quadrangle
    17: 20-node second order hexahedron
    18: 15-node second order prism
    19: 13-node second order pyramid
    20: 9-node third order incomplete triangle
    21: 10-node third order triangle
    22: 12-node fourth order incomplete triangle
    23: 15-node fourth order triangle
    24: 15-node fifth order incomplete triangle
    25: 21-node fifth order complete triangle
    26: 4-node third order edge
    27: 5-node fourth order edge
    28: 6-node fifth order edge
    29: 20-node third order tetrahedron
    30: 35-node fourth order tetrahedron
    31: 56-node fifth order tetrahedron
    -------------------------------------------------------------------------- */
 
 /* -------------------------------------------------------------------------- */
 #include "element_group.hh"
 #include "mesh_io.hh"
 #include "mesh_utils.hh"
 #include "node_group.hh"
 /* -------------------------------------------------------------------------- */
 #include <fstream>
 /* -------------------------------------------------------------------------- */
 
 namespace akantu {
 
 /* -------------------------------------------------------------------------- */
 /*   Methods Implentations                                                    */
 /* -------------------------------------------------------------------------- */
 MeshIOMSH::MeshIOMSH() {
   canReadSurface = true;
   canReadExtendedData = true;
 
   _msh_nodes_per_elem[_msh_not_defined] = 0;
   _msh_nodes_per_elem[_msh_segment_2] = 2;
   _msh_nodes_per_elem[_msh_triangle_3] = 3;
   _msh_nodes_per_elem[_msh_quadrangle_4] = 4;
   _msh_nodes_per_elem[_msh_tetrahedron_4] = 4;
   _msh_nodes_per_elem[_msh_hexahedron_8] = 8;
   _msh_nodes_per_elem[_msh_prism_1] = 6;
   _msh_nodes_per_elem[_msh_pyramid_1] = 1;
   _msh_nodes_per_elem[_msh_segment_3] = 3;
   _msh_nodes_per_elem[_msh_triangle_6] = 6;
   _msh_nodes_per_elem[_msh_quadrangle_9] = 9;
   _msh_nodes_per_elem[_msh_tetrahedron_10] = 10;
   _msh_nodes_per_elem[_msh_hexahedron_27] = 27;
   _msh_nodes_per_elem[_msh_hexahedron_20] = 20;
   _msh_nodes_per_elem[_msh_prism_18] = 18;
   _msh_nodes_per_elem[_msh_prism_15] = 15;
   _msh_nodes_per_elem[_msh_pyramid_14] = 14;
   _msh_nodes_per_elem[_msh_point] = 1;
   _msh_nodes_per_elem[_msh_quadrangle_8] = 8;
 
   _msh_to_akantu_element_types[_msh_not_defined] = _not_defined;
   _msh_to_akantu_element_types[_msh_segment_2] = _segment_2;
   _msh_to_akantu_element_types[_msh_triangle_3] = _triangle_3;
   _msh_to_akantu_element_types[_msh_quadrangle_4] = _quadrangle_4;
   _msh_to_akantu_element_types[_msh_tetrahedron_4] = _tetrahedron_4;
   _msh_to_akantu_element_types[_msh_hexahedron_8] = _hexahedron_8;
   _msh_to_akantu_element_types[_msh_prism_1] = _pentahedron_6;
   _msh_to_akantu_element_types[_msh_pyramid_1] = _not_defined;
   _msh_to_akantu_element_types[_msh_segment_3] = _segment_3;
   _msh_to_akantu_element_types[_msh_triangle_6] = _triangle_6;
   _msh_to_akantu_element_types[_msh_quadrangle_9] = _not_defined;
   _msh_to_akantu_element_types[_msh_tetrahedron_10] = _tetrahedron_10;
   _msh_to_akantu_element_types[_msh_hexahedron_27] = _not_defined;
   _msh_to_akantu_element_types[_msh_hexahedron_20] = _hexahedron_20;
   _msh_to_akantu_element_types[_msh_prism_18] = _not_defined;
   _msh_to_akantu_element_types[_msh_prism_15] = _pentahedron_15;
   _msh_to_akantu_element_types[_msh_pyramid_14] = _not_defined;
   _msh_to_akantu_element_types[_msh_point] = _point_1;
   _msh_to_akantu_element_types[_msh_quadrangle_8] = _quadrangle_8;
 
   _akantu_to_msh_element_types[_not_defined] = _msh_not_defined;
   _akantu_to_msh_element_types[_segment_2] = _msh_segment_2;
   _akantu_to_msh_element_types[_segment_3] = _msh_segment_3;
   _akantu_to_msh_element_types[_triangle_3] = _msh_triangle_3;
   _akantu_to_msh_element_types[_triangle_6] = _msh_triangle_6;
   _akantu_to_msh_element_types[_tetrahedron_4] = _msh_tetrahedron_4;
   _akantu_to_msh_element_types[_tetrahedron_10] = _msh_tetrahedron_10;
   _akantu_to_msh_element_types[_quadrangle_4] = _msh_quadrangle_4;
   _akantu_to_msh_element_types[_quadrangle_8] = _msh_quadrangle_8;
   _akantu_to_msh_element_types[_hexahedron_8] = _msh_hexahedron_8;
   _akantu_to_msh_element_types[_hexahedron_20] = _msh_hexahedron_20;
   _akantu_to_msh_element_types[_pentahedron_6] = _msh_prism_1;
   _akantu_to_msh_element_types[_pentahedron_15] = _msh_prism_15;
   _akantu_to_msh_element_types[_point_1] = _msh_point;
 
 #if defined(AKANTU_STRUCTURAL_MECHANICS)
   _akantu_to_msh_element_types[_bernoulli_beam_2] = _msh_segment_2;
   _akantu_to_msh_element_types[_bernoulli_beam_3] = _msh_segment_2;
   _akantu_to_msh_element_types[_discrete_kirchhoff_triangle_18] =
       _msh_triangle_3;
 #endif
 
   std::map<ElementType, MSHElementType>::iterator it;
   for (it = _akantu_to_msh_element_types.begin();
        it != _akantu_to_msh_element_types.end(); ++it) {
     UInt nb_nodes = _msh_nodes_per_elem[it->second];
 
     std::vector<UInt> tmp(nb_nodes);
     for (UInt i = 0; i < nb_nodes; ++i) {
       tmp[i] = i;
     }
 
     switch (it->first) {
     case _tetrahedron_10:
       tmp[8] = 9;
       tmp[9] = 8;
       break;
     case _pentahedron_6:
       tmp[0] = 2;
       tmp[1] = 0;
       tmp[2] = 1;
       tmp[3] = 5;
       tmp[4] = 3;
       tmp[5] = 4;
       break;
     case _pentahedron_15:
       tmp[0] = 2;
       tmp[1] = 0;
       tmp[2] = 1;
       tmp[3] = 5;
       tmp[4] = 3;
       tmp[5] = 4;
       tmp[6] = 8;
       tmp[8] = 11;
       tmp[9] = 6;
       tmp[10] = 9;
       tmp[11] = 10;
       tmp[12] = 14;
       tmp[14] = 12;
       break;
     case _hexahedron_20:
       tmp[9] = 11;
       tmp[10] = 12;
       tmp[11] = 9;
       tmp[12] = 13;
       tmp[13] = 10;
       tmp[17] = 19;
       tmp[18] = 17;
       tmp[19] = 18;
       break;
     default:
       // nothing to change
       break;
     }
     _read_order[it->first] = tmp;
   }
 }
 
 /* -------------------------------------------------------------------------- */
 MeshIOMSH::~MeshIOMSH() = default;
 
 /* -------------------------------------------------------------------------- */
 namespace {
   struct File {
     std::string filename;
     std::ifstream infile;
     std::string line;
     size_t current_line{0};
 
     size_t first_node_number{std::numeric_limits<UInt>::max()},
         last_node_number{0};
     bool has_physical_names{false};
 
     std::unordered_map<size_t, size_t> node_tags;
     std::unordered_map<size_t, Element> element_tags;
     double version{0};
     int size_of_size_t{0};
     Mesh & mesh;
     MeshAccessor mesh_accessor;
 
     std::multimap<std::pair<int, int>, int> entity_tag_to_physical_tags;
 
     File(const std::string & filename, Mesh & mesh)
         : filename(filename), mesh(mesh), mesh_accessor(mesh) {
       infile.open(filename.c_str());
       if (not infile.good()) {
         AKANTU_EXCEPTION("Cannot open file " << filename);
       }
     }
 
     ~File() { infile.close(); }
 
     auto good() { return infile.good(); }
 
     std::stringstream get_line() {
       std::string tmp_str;
       if (infile.eof()) {
         AKANTU_EXCEPTION("Reached the end of the file " << filename);
       }
       std::getline(infile, tmp_str);
       line = trim(tmp_str);
       ++current_line;
 
       return std::stringstream(line);
     }
 
     template <typename... Ts> void read_line(Ts &&... ts) {
       auto && sstr = get_line();
       (void)std::initializer_list<int>{
           (sstr >> std::forward<decltype(ts)>(ts), 0)...};
     }
   };
 } // namespace
 
 /* -------------------------------------------------------------------------- */
 template <typename File, typename Readers>
 void MeshIOMSH::populateReaders2(File & file, Readers & readers) {
   readers["$NOD"] = readers["$Nodes"] = [&](const std::string & /*unused*/) {
     UInt nb_nodes;
     file.read_line(nb_nodes);
 
     Array<Real> & nodes = file.mesh_accessor.getNodes();
     nodes.resize(nb_nodes);
     file.mesh_accessor.setNbGlobalNodes(nb_nodes);
 
     size_t index;
     Vector<double> coord(3);
 
     /// for each node, read the coordinates
     for (auto && data : enumerate(make_view(nodes, nodes.getNbComponent()))) {
       file.read_line(index, coord(0), coord(1), coord(2));
 
       if (index > std::numeric_limits<UInt>::max()) {
         AKANTU_EXCEPTION(
             "There are more nodes in this files than the index type of akantu "
             "can handle, consider recompiling with a bigger index type");
       }
 
       file.first_node_number = std::min(file.first_node_number, index);
       file.last_node_number = std::max(file.last_node_number, index);
 
       for (auto && coord_data : zip(std::get<1>(data), coord)) {
         std::get<0>(coord_data) = std::get<1>(coord_data);
       }
       file.node_tags[index] = std::get<0>(data);
     }
   };
 
   readers["$ELM"] = readers["$Elements"] = [&](const std::string & /*unused*/) {
     UInt nb_elements;
     file.read_line(nb_elements);
 
     Int index;
     UInt msh_type;
     ElementType akantu_type;
 
     for (UInt i = 0; i < nb_elements; ++i) {
       auto && sstr_elem = file.get_line();
 
       sstr_elem >> index;
       sstr_elem >> msh_type;
 
       /// get the connectivity vector depending on the element type
       akantu_type =
           this->_msh_to_akantu_element_types[MSHElementType(msh_type)];
 
       if (akantu_type == _not_defined) {
         AKANTU_DEBUG_WARNING("Unsuported element kind "
                              << msh_type << " at line " << file.current_line);
         continue;
       }
 
       Element elem{akantu_type, 0, _not_ghost};
 
       auto & connectivity = file.mesh_accessor.getConnectivity(akantu_type);
       auto node_per_element = connectivity.getNbComponent();
       auto & read_order = this->_read_order[akantu_type];
 
       /// read tags informations
       if (file.version < 2) {
         Int tag0;
         Int tag1;
         Int nb_nodes; // reg-phys, reg-elem, number-of-nodes
         sstr_elem >> tag0 >> tag1 >> nb_nodes;
 
         auto & data0 =
             file.mesh_accessor.template getData<UInt>("tag_0", akantu_type);
         data0.push_back(tag0);
 
         auto & data1 =
             file.mesh_accessor.template getData<UInt>("tag_1", akantu_type);
         data1.push_back(tag1);
       } else if (file.version < 4) {
         UInt nb_tags;
         sstr_elem >> nb_tags;
         for (UInt j = 0; j < nb_tags; ++j) {
           Int tag;
           sstr_elem >> tag;
 
           auto & data = file.mesh_accessor.template getData<UInt>(
               "tag_" + std::to_string(j), akantu_type);
           data.push_back(tag);
         }
       }
 
       Vector<UInt> local_connect(node_per_element);
       for (UInt j = 0; j < node_per_element; ++j) {
         UInt node_index;
         sstr_elem >> node_index;
 
         AKANTU_DEBUG_ASSERT(node_index <= file.last_node_number,
                             "Node number not in range : line "
                                 << file.current_line);
 
         local_connect(read_order[j]) = file.node_tags[node_index];
       }
 
       connectivity.push_back(local_connect);
       elem.element = connectivity.size() - 1;
       file.element_tags[index] = elem;
     }
   };
 
   readers["$Periodic"] = [&](const std::string & /*unused*/) {
     UInt nb_periodic_entities;
     file.read_line(nb_periodic_entities);
 
     file.mesh_accessor.getNodesFlags().resize(file.mesh.getNbNodes(),
                                               NodeFlag::_normal);
 
     for (UInt p = 0; p < nb_periodic_entities; ++p) {
       // dimension slave-tag master-tag
       UInt dimension;
       file.read_line(dimension);
 
       // transformation
       file.get_line();
 
       // nb nodes
       UInt nb_nodes;
       file.read_line(nb_nodes);
 
       for (UInt n = 0; n < nb_nodes; ++n) {
         // slave master
         auto && sstr = file.get_line();
 
         // The info in the mesh seem inconsistent so they are ignored for now.
         continue;
 
         if (dimension == file.mesh.getSpatialDimension() - 1) {
           UInt slave;
           UInt master;
 
           sstr >> slave;
           sstr >> master;
           file.mesh_accessor.addPeriodicSlave(file.node_tags[slave],
                                               file.node_tags[master]);
         }
       }
     }
 
     // mesh_accessor.markMeshPeriodic();
   };
 }
 
 /* -------------------------------------------------------------------------- */
 template <typename File, typename Readers>
 void MeshIOMSH::populateReaders4(File & file, Readers & readers) {
   static std::map<int, std::string> entity_type{
       {0, "points"},
       {1, "curve"},
       {2, "surface"},
       {3, "volume"},
   };
 
   readers["$Entities"] = [&](const std::string & /*unused*/) {
     size_t num_entity[4];
     file.read_line(num_entity[0], num_entity[1], num_entity[2], num_entity[3]);
 
     for (auto entity_dim : arange(4)) {
       for (auto _ [[gnu::unused]] : arange(num_entity[entity_dim])) {
         auto && sstr = file.get_line();
 
         int tag;
         double min_x;
         double min_y;
         double min_z;
         double max_x;
         double max_y;
         double max_z;
         size_t num_physical_tags;
         sstr >> tag >> min_x >> min_y >> min_z;
 
         if (entity_dim > 0 or file.version < 4.1) {
           sstr >> max_x >> max_y >> max_z;
         }
 
         sstr >> num_physical_tags;
 
         for (auto _ [[gnu::unused]] : arange(num_physical_tags)) {
           int phys_tag;
           sstr >> phys_tag;
 
           std::string physical_name;
           if (this->physical_names.find(phys_tag) ==
               this->physical_names.end()) {
             physical_name = "msh_block_" + std::to_string(phys_tag);
           } else {
             physical_name = this->physical_names[phys_tag];
           }
 
           if (not file.mesh.elementGroupExists(physical_name)) {
             file.mesh.createElementGroup(physical_name, entity_dim);
           } else {
             file.mesh.getElementGroup(physical_name).addDimension(entity_dim);
           }
           file.entity_tag_to_physical_tags.insert(
               std::make_pair(std::make_pair(tag, entity_dim), phys_tag));
         }
       }
     }
   };
 
   readers["$Nodes"] = [&](const std::string & /*unused*/) {
     size_t num_blocks;
     size_t num_nodes;
     if (file.version >= 4.1) {
       file.read_line(num_blocks, num_nodes, file.first_node_number,
                      file.last_node_number);
     } else {
       file.read_line(num_blocks, num_nodes);
     }
     auto & nodes = file.mesh_accessor.getNodes();
     nodes.reserve(num_nodes);
     file.mesh_accessor.setNbGlobalNodes(num_nodes);
 
     if (num_nodes > std::numeric_limits<UInt>::max()) {
       AKANTU_EXCEPTION(
           "There are more nodes in this files than the index type of akantu "
           "can handle, consider recompiling with a bigger index type");
     }
 
     size_t node_id{0};
 
     for (auto block [[gnu::unused]] : arange(num_blocks)) {
       int entity_dim;
       int entity_tag;
       int parametric;
       size_t num_nodes_in_block;
       Vector<double> pos(3);
       Vector<double> real_pos(nodes.getNbComponent());
 
       if (file.version >= 4.1) {
         file.read_line(entity_dim, entity_tag, parametric, num_nodes_in_block);
         if (parametric) {
           AKANTU_EXCEPTION(
               "Akantu does not support parametric nodes in msh files");
         }
         for (auto _ [[gnu::unused]] : arange(num_nodes_in_block)) {
           size_t tag;
           file.read_line(tag);
           file.node_tags[tag] = node_id;
           ++node_id;
         }
 
         for (auto _ [[gnu::unused]] : arange(num_nodes_in_block)) {
           file.read_line(pos(_x), pos(_y), pos(_z));
           for (auto && data : zip(real_pos, pos)) {
             std::get<0>(data) = std::get<1>(data);
           }
 
           nodes.push_back(real_pos);
         }
       } else {
         file.read_line(entity_tag, entity_dim, parametric, num_nodes_in_block);
 
         for (auto _ [[gnu::unused]] : arange(num_nodes_in_block)) {
           size_t tag;
           file.read_line(tag, pos(_x), pos(_y), pos(_z));
 
           if (file.version < 4.1) {
             file.first_node_number = std::min(file.first_node_number, tag);
             file.last_node_number = std::max(file.last_node_number, tag);
           }
 
           for (auto && data : zip(real_pos, pos)) {
             std::get<0>(data) = std::get<1>(data);
           }
 
           nodes.push_back(real_pos);
           file.node_tags[tag] = node_id;
           ++node_id;
         }
       }
     }
   };
 
   readers["$Elements"] = [&](const std::string & /*unused*/) {
     size_t num_blocks;
     size_t num_elements;
     file.read_line(num_blocks, num_elements);
 
     for (auto block [[gnu::unused]] : arange(num_blocks)) {
       int entity_dim;
       int entity_tag;
       int element_type;
       size_t num_elements_in_block;
 
       if (file.version >= 4.1) {
         file.read_line(entity_dim, entity_tag, element_type,
                        num_elements_in_block);
       } else {
         file.read_line(entity_tag, entity_dim, element_type,
                        num_elements_in_block);
       }
 
       /// get the connectivity vector depending on the element type
       auto && akantu_type =
           this->_msh_to_akantu_element_types[(MSHElementType)element_type];
 
       if (akantu_type == _not_defined) {
         AKANTU_DEBUG_WARNING("Unsuported element kind " << element_type
                                                         << " at line "
                                                         << file.current_line);
         continue;
       }
 
       Element elem{akantu_type, 0, _not_ghost};
 
       auto & connectivity = file.mesh_accessor.getConnectivity(akantu_type);
       Vector<UInt> local_connect(connectivity.getNbComponent());
       auto && read_order = this->_read_order[akantu_type];
 
       auto & data0 =
           file.mesh_accessor.template getData<UInt>("tag_0", akantu_type);
       data0.resize(data0.size() + num_elements_in_block, 0);
 
       auto & physical_data = file.mesh_accessor.template getData<std::string>(
           "physical_names", akantu_type);
       physical_data.resize(physical_data.size() + num_elements_in_block, "");
 
       for (auto _ [[gnu::unused]] : arange(num_elements_in_block)) {
         auto && sstr_elem = file.get_line();
         size_t elem_tag;
         sstr_elem >> elem_tag;
         for (auto && c : arange(connectivity.getNbComponent())) {
           size_t node_tag;
           sstr_elem >> node_tag;
 
           AKANTU_DEBUG_ASSERT(node_tag <= file.last_node_number,
                               "Node number not in range : line "
                                   << file.current_line);
 
           node_tag = file.node_tags[node_tag];
           local_connect(read_order[c]) = node_tag;
         }
         connectivity.push_back(local_connect);
         elem.element = connectivity.size() - 1;
         file.element_tags[elem_tag] = elem;
 
         auto range = file.entity_tag_to_physical_tags.equal_range(
             std::make_pair(entity_tag, entity_dim));
         bool first = true;
         for (auto it = range.first; it != range.second; ++it) {
           auto phys_it = this->physical_names.find(it->second);
           if (first) {
             data0(elem.element) =
                 it->second; // for compatibility with version 2
             if (phys_it != this->physical_names.end()) {
               physical_data(elem.element) = phys_it->second;
             }
             first = false;
           }
           if (phys_it != this->physical_names.end()) {
             file.mesh.getElementGroup(phys_it->second).add(elem, true, false);
           }
         }
       }
     }
 
     for (auto && element_group : file.mesh.iterateElementGroups()) {
       element_group.getNodeGroup().optimize();
     }
   };
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshIOMSH::read(const std::string & filename, Mesh & mesh) {
 
   File file(filename, mesh);
 
   std::map<std::string, std::function<void(const std::string &)>> readers;
 
   readers["$MeshFormat"] = [&](const std::string & /*unused*/) {
     auto && sstr = file.get_line();
 
     int format;
     sstr >> file.version >> format;
 
     if (format != 0) {
       AKANTU_ERROR("This reader can only read ASCII files.");
     }
 
     if (file.version > 2) {
       sstr >> file.size_of_size_t;
       if (file.size_of_size_t > int(sizeof(UInt))) {
         AKANTU_DEBUG_INFO("The size of the indexes in akantu might be to small "
                           "to read this file (akantu "
                           << sizeof(UInt) << " vs. msh file "
                           << file.size_of_size_t << ")");
       }
     }
 
     if (file.version < 4) {
       this->populateReaders2(file, readers);
     } else {
       this->populateReaders4(file, readers);
     }
   };
 
   auto && read_data = [&](auto && entity_tags, auto && get_data,
                           auto && read_data) {
     auto read_data_tags = [&](auto x) {
       UInt number_of_tags{0};
       file.read_line(number_of_tags);
       std::vector<decltype(x)> tags(number_of_tags);
 
       for (auto && tag : tags) {
         file.read_line(tag);
       }
       return tags;
     };
 
     auto && string_tags = read_data_tags(std::string{});
     auto && real_tags [[gnu::unused]] = read_data_tags(double{});
     auto && int_tags = read_data_tags(int{});
 
     for (auto & s : string_tags) {
       s = trim(s, '"');
     }
 
     auto id = string_tags[0];
     auto size = int_tags[2];
     auto nb_component = int_tags[1];
     auto & data = get_data(id, size, nb_component);
 
     for (auto n [[gnu::unused]] : arange(size)) {
       auto && sstr = file.get_line();
 
       size_t tag;
       sstr >> tag;
       const auto & entity = entity_tags[tag];
       read_data(entity, sstr, data, nb_component);
     }
   };
 
   readers["$NodeData"] = [&](const std::string & /*unused*/) {
     /* $NodeData
        numStringTags(ASCII int)
        stringTag(string) ...
        numRealTags(ASCII int)
        realTag(ASCII double) ...
        numIntegerTags(ASCII int)
        integerTag(ASCII int) ...
        nodeTag(size_t) value(double) ...
        ...
        $EndNodeData */
     read_data(
         file.node_tags,
         [&](auto && id, auto && size [[gnu::unused]],
             auto && nb_component [[gnu::unused]]) -> Array<double> & {
           auto & data =
               file.mesh.template getNodalData<double>(id, nb_component);
           data.resize(size);
           return data;
         },
         [&](auto && node, auto && sstr, auto && data,
             auto && nb_component [[gnu::unused]]) {
           for (auto c : arange(nb_component)) {
             sstr >> data(node, c);
           }
         });
   };
 
   readers["$ElementData"] = [&](const std::string & /*unused*/) {
     /* $ElementData
        numStringTags(ASCII int)
        stringTag(string) ...
        numRealTags(ASCII int)
        realTag(ASCII double) ...
        numIntegerTags(ASCII int)
        integerTag(ASCII int) ...
        elementTag(size_t) value(double) ...
        ...
        $EndElementData
     */
     read_data(
         file.element_tags,
         [&](auto && id, auto && size [[gnu::unused]],
             auto && nb_component
             [[gnu::unused]]) -> ElementTypeMapArray<double> & {
           file.mesh.template getElementalData<double>(id);
           return file.mesh.template getElementalData<double>(id);
         },
         [&](auto && element, auto && sstr, auto && data, auto && nb_component) {
           if (not data.exists(element.type)) {
             data.alloc(mesh.getNbElement(element.type), nb_component,
                        element.type, element.ghost_type);
           }
           auto & data_array = data(element.type);
           for (auto c : arange(nb_component)) {
             sstr >> data_array(element.element, c);
           }
         });
   };
 
   readers["$ElementNodeData"] = [&](const std::string & /*unused*/) {
     /* $ElementNodeData
        numStringTags(ASCII int)
        stringTag(string) ...
        numRealTags(ASCII int)
        realTag(ASCII double) ...
        numIntegerTags(ASCII int)
        integerTag(ASCII int) ...
        elementTag(size_t) value(double) ...
        ...
        $EndElementNodeData
     */
     read_data(
         file.element_tags,
         [&](auto && id, auto && size [[gnu::unused]],
             auto && nb_component
             [[gnu::unused]]) -> ElementTypeMapArray<double> & {
           file.mesh.template getElementalData<double>(id);
           auto & data = file.mesh.template getElementalData<double>(id);
           data.isNodal(true);
           return data;
         },
         [&](auto && element, auto && sstr, auto && data, auto && nb_component) {
           int nb_nodes_per_element;
           sstr >> nb_nodes_per_element;
           if (not data.exists(element.type)) {
             data.alloc(mesh.getNbElement(element.type),
                        nb_component * nb_nodes_per_element, element.type,
                        element.ghost_type);
           }
           auto & data_array = data(element.type);
           for (auto c : arange(nb_component)) {
             sstr >> data_array(element.element, c);
           }
         });
   };
 
   readers["$PhysicalNames"] = [&](const std::string & /*unused*/) {
     file.has_physical_names = true;
     int num_of_phys_names;
     file.read_line(num_of_phys_names); /// the format line
 
     for (auto k [[gnu::unused]] : arange(num_of_phys_names)) {
       int phys_name_id;
       int phys_dim;
       std::string phys_name;
       file.read_line(phys_dim, phys_name_id, std::quoted(phys_name));
 
       this->physical_names[phys_name_id] = phys_name;
     }
   };
 
   readers["Unsupported"] = [&](const std::string & _block) {
     std::string block = _block.substr(1);
     AKANTU_DEBUG_WARNING("Unsupported block_kind " << block << " at line "
                                                    << file.current_line);
     auto && end_block = "$End" + block;
     while (file.line != end_block) {
       file.get_line();
     }
   };
 
   while (file.good()) {
     std::string block;
     file.read_line(block);
 
     auto && it = readers.find(block);
 
     if (it != readers.end()) {
       it->second(block);
 
       std::string end_block;
       file.read_line(end_block);
       block = block.substr(1);
 
       if (end_block != "$End" + block) {
         AKANTU_EXCEPTION("The reader failed to properly read the block "
                          << block << ". Expected a $End" << block << " at line "
                          << file.current_line);
       }
     } else if (not block.empty()) {
       readers["Unsupported"](block);
     }
   }
 
   // mesh.updateTypesOffsets(_not_ghost);
   if (file.version < 4) {
     this->constructPhysicalNames("tag_0", mesh);
     if (file.has_physical_names) {
       mesh.createGroupsFromMeshData<std::string>("physical_names");
     }
   }
 
   MeshUtils::fillElementToSubElementsData(mesh);
 }
 
 /* -------------------------------------------------------------------------- */
 void MeshIOMSH::write(const std::string & filename, const Mesh & mesh) {
   std::ofstream outfile;
   const Array<Real> & nodes = mesh.getNodes();
 
   outfile.open(filename.c_str());
 
   outfile << "$MeshFormat"
           << "\n";
   outfile << "2.2 0 8"
           << "\n";
   outfile << "$EndMeshFormat"
           << "\n";
 
   outfile << std::setprecision(std::numeric_limits<Real>::digits10);
   outfile << "$Nodes"
           << "\n";
 
   outfile << nodes.size() << "\n";
 
   outfile << std::uppercase;
   for (UInt i = 0; i < nodes.size(); ++i) {
     Int offset = i * nodes.getNbComponent();
     outfile << i + 1;
     for (UInt j = 0; j < nodes.getNbComponent(); ++j) {
       outfile << " " << nodes.storage()[offset + j];
     }
 
     for (UInt p = nodes.getNbComponent(); p < 3; ++p) {
       outfile << " " << 0.;
     }
     outfile << "\n";
     ;
   }
   outfile << std::nouppercase;
   outfile << "$EndNodes"
           << "\n";
 
   outfile << "$Elements"
           << "\n";
   Int nb_elements = 0;
   for (auto && type :
        mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) {
     const Array<UInt> & connectivity = mesh.getConnectivity(type, _not_ghost);
     nb_elements += connectivity.size();
   }
   outfile << nb_elements << "\n";
 
   std::map<Element, size_t> element_to_msh_element;
 
   UInt element_idx = 1;
-  Element element;
+  auto element = ElementNull;
   for (auto && type :
        mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) {
     const auto & connectivity = mesh.getConnectivity(type, _not_ghost);
     element.type = type;
 
     UInt * tag[2] = {nullptr, nullptr};
     if (mesh.hasData<UInt>("tag_0", type, _not_ghost)) {
       const auto & data_tag_0 = mesh.getData<UInt>("tag_0", type, _not_ghost);
       tag[0] = data_tag_0.storage();
     }
 
     if (mesh.hasData<UInt>("tag_1", type, _not_ghost)) {
       const auto & data_tag_1 = mesh.getData<UInt>("tag_1", type, _not_ghost);
       tag[1] = data_tag_1.storage();
     }
 
     for (auto && data :
          enumerate(make_view(connectivity, connectivity.getNbComponent()))) {
       element.element = std::get<0>(data);
       const auto & conn = std::get<1>(data);
-      element_to_msh_element[element] = element_idx;
+      element_to_msh_element.insert(std::make_pair(element, element_idx));
 
       outfile << element_idx << " " << _akantu_to_msh_element_types[type]
               << " 2";
 
       /// \todo write the real data in the file
       for (UInt t = 0; t < 2; ++t) {
         if (tag[t] != nullptr) {
           outfile << " " << tag[t][element.element];
         } else {
           outfile << " 0";
         }
       }
 
       for (auto && c : conn) {
         outfile << " " << c + 1;
       }
       outfile << "\n";
       element_idx++;
     }
   }
   outfile << "$EndElements"
           << "\n";
 
   if (mesh.hasData(MeshDataType::_nodal)) {
     auto && tags = mesh.getTagNames();
     for (auto && tag : tags) {
       auto type = mesh.getTypeCode(tag, MeshDataType::_nodal);
       if (type != MeshDataTypeCode::_real) {
         AKANTU_DEBUG_WARNING(
             "The field "
             << tag << " is ignored by the MSH writer, msh files do not support "
             << type << " data");
         continue;
       }
       auto && data = mesh.getNodalData<double>(tag);
       outfile << "$NodeData"
               << "\n";
       outfile << "1"
               << "\n";
       outfile << "\"" << tag << "\"\n";
       outfile << "1\n0.0"
               << "\n";
       outfile << "3\n0"
               << "\n";
       outfile << data.getNbComponent() << "\n";
       outfile << data.size() << "\n";
       for (auto && d : enumerate(make_view(data, data.getNbComponent()))) {
         outfile << std::get<0>(d) + 1;
         for (auto && v : std::get<1>(d)) {
           outfile << " " << v;
         }
         outfile << "\n";
       }
       outfile << "$EndNodeData"
               << "\n";
     }
   }
 
   if (mesh.hasData(MeshDataType::_elemental)) {
     auto && tags = mesh.getTagNames();
     for (auto && tag : tags) {
       auto && data = mesh.getElementalData<double>(tag);
       auto type = mesh.getTypeCode(tag, MeshDataType::_elemental);
       if (type != MeshDataTypeCode::_real) {
         AKANTU_DEBUG_WARNING(
             "The field "
             << tag << " is ignored by the MSH writer, msh files do not support "
             << type << " data");
         continue;
       }
       if (data.isNodal()) {
         continue;
       }
 
       auto size = data.size();
       if (size == 0) {
         continue;
       }
       auto && nb_components = data.getNbComponents();
       auto nb_component = nb_components(*(data.elementTypes().begin()));
 
       outfile << "$ElementData"
               << "\n";
       outfile << "1"
               << "\n";
       outfile << "\"" << tag << "\"\n";
       outfile << "1\n0.0"
               << "\n";
       outfile << "3\n0"
               << "\n";
       outfile << nb_component << "\n";
       outfile << size << "\n";
 
       Element element;
       for (auto type : data.elementTypes()) {
         element.type = type;
         for (auto && _ :
              enumerate(make_view(data(type), nb_components(type)))) {
           element.element = std::get<0>(_);
           outfile << element_to_msh_element[element];
           for (auto && v : std::get<1>(_)) {
             outfile << " " << v;
           }
           outfile << "\n";
         }
       }
       outfile << "$EndElementData"
               << "\n";
     }
   }
 
   outfile.close();
 }
 
 /* --------------------------------------------------------------------------
  */
 
 } // namespace akantu