diff --git a/CMakeLists.txt b/CMakeLists.txt
index 341828ab792657d2c2d45a5da6bc1b4160f06a36..e369d66949e771f78d44b82d0ff7cc0cd23e400e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -136,8 +136,6 @@ include_directories(src/output)
 include_directories(src/utils)
 include_directories(src/scheme)
 
-include_directories(src/experimental)
-
 # Pastis tests
 
 set(CATCH_MODULE_PATH "${PASTIS_SOURCE_DIR}/packages/Catch2")
@@ -167,7 +165,6 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage")
   endif()
 
   set (GCOVR_EXCLUDE
-    -e "${PASTIS_SOURCE_DIR}/src/experimental"
     -e "${PASTIS_SOURCE_DIR}/src/main.cpp"
     -e "${PASTIS_SOURCE_DIR}/src/utils/BacktraceManager.cpp"
     -e "${PASTIS_SOURCE_DIR}/src/utils/BacktraceManager.hpp"
@@ -216,5 +213,4 @@ target_link_libraries(
   pastis
   kokkos
   PastisUtils
-  PastisMesh
-  PastisExperimental)
+  PastisMesh)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fcc3e886e01edf90d0aca9447099d64056d2b91c..ebf2a69d275051fcd7e0bdfd6a0a0718ae8e37ea 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -21,7 +21,3 @@ include_directories(scheme)
 
 # Pastis output
 include_directories(output)
-
-# Pastis experimental
-add_subdirectory(experimental)
-include_directories(experimental)
diff --git a/src/experimental/AcousticSolverClass.cpp b/src/experimental/AcousticSolverClass.cpp
deleted file mode 100644
index 051e148bb21babf5eb65c22b2bcf820df37632b6..0000000000000000000000000000000000000000
--- a/src/experimental/AcousticSolverClass.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-#include <AcousticSolverClass.hpp>
-#include <rang.hpp>
-
-#include <BlockPerfectGas.hpp>
-
-typedef const double my_double;
-
-struct AcousticSolverClass::ReduceMin
-{
-private:
-  const Kokkos::View<my_double*> x_;
-
-public:
-  typedef Kokkos::View<my_double*>::non_const_value_type value_type;
-
-  ReduceMin(const Kokkos::View<my_double*>& x) : x_ (x) {}
-
-  typedef Kokkos::View<my_double*>::size_type size_type;
-    
-  KOKKOS_INLINE_FUNCTION void
-  operator() (const size_type i, value_type& update) const
-  {
-    if (x_(i) < update) {
-      update = x_(i);
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  join (volatile value_type& dst,
-	const volatile value_type& src) const
-  {
-    if (src < dst) {
-      dst = src;
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  init (value_type& dst) const
-  { // The identity under max is -Inf.
-    dst= Kokkos::reduction_identity<value_type>::min();
-  }
-};
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const double*>
-AcousticSolverClass::computeRhoCj(const Kokkos::View<const double*>& rhoj,
-				  const Kokkos::View<const double*>& cj)
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j) {
-      m_rhocj[j] = rhoj[j]*cj[j];
-    });
-  return m_rhocj;
-}
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const double*[2]>
-AcousticSolverClass::computeAjr(const Kokkos::View<const double*>& rhocj,
-				const Kokkos::View<const double*[2]>& Cjr)
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j) {
-      for (int r=0; r<2; ++r) {
-	m_Ajr(j,r) = rhocj(j)*Cjr(j,r)*Cjr(j,r);
-      }
-    });
-
-  return m_Ajr;
-}
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const double*>
-AcousticSolverClass::computeAr(const Kokkos::View<const double*[2]>& Ajr,
-			       const Kokkos::View<const int*[2]>& node_cells,
-			       const Kokkos::View<const int*[2]>& node_cell_local_node,
-			       const Kokkos::View<const int*>& node_nb_cells)
-{
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r) {
-      double sum = 0;
-      for (int j=0; j<node_nb_cells(r); ++j) {
-	const int J = node_cells(r,j);
-	const int R = node_cell_local_node(r,j);
-  	sum += Ajr(J,R);
-      }
-      m_Ar(r) = sum;
-    });
-
-  return m_Ar;
-}
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const double*>
-AcousticSolverClass::computeBr(const Kokkos::View<const double*[2]>& Ajr,
-			       const Kokkos::View<const double*[2]>& Cjr,
-			       const Kokkos::View<const double*>& uj,
-			       const Kokkos::View<const double*>& pj,
-			       const Kokkos::View<const int*[2]>& node_cells,
-			       const Kokkos::View<const int*[2]>& node_cell_local_node,
-			       const Kokkos::View<const int*>& node_nb_cells)
-{
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r) {
-      double sum = 0;
-      for (int j=0; j<node_nb_cells(r); ++j) {
-  	const int J = node_cells(r,j);
-  	const int R = node_cell_local_node(r,j);
-  	sum += Ajr(J,R)*uj(J) + Cjr(J,R)*pj(J);
-      }
-      m_br(r) = sum;
-    });
-
-  return m_br;
-}
-
-KOKKOS_INLINE_FUNCTION
-Kokkos::View<double*>
-AcousticSolverClass::computeUr(const Kokkos::View<const double*>& Ar,
-			       const Kokkos::View<const double*>& br)
-{
-  inverse(Ar, m_inv_Ar);
-  const Kokkos::View<const double*> invAr = m_inv_Ar;
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r) {
-      m_ur[r]=br(r)*invAr(r);
-    });
-  m_ur[0]=0;
-  m_ur[m_nr-1]=0;
-
-  return m_ur;
-}
-
-KOKKOS_INLINE_FUNCTION
-Kokkos::View<double*[2]>
-AcousticSolverClass::computeFjr(const Kokkos::View<const double*[2]>& Ajr,
-				const Kokkos::View<const double*>& ur,
-				const Kokkos::View<const double*[2]>& Cjr,
-				const Kokkos::View<const double*>& uj,
-				const Kokkos::View<const double*>& pj,
-				const Kokkos::View<const int*[2]>& cell_nodes)
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j) {
-      for (int r=0; r<2; ++r) {
-	m_Fjr(j,r) = Ajr(j,r)*(uj(j)-ur(cell_nodes(j,r)))+Cjr(j,r)*pj(j);
-      }
-    });
-
-  return m_Fjr;
-}
-
-KOKKOS_INLINE_FUNCTION
-double AcousticSolverClass::
-acoustic_dt(const Kokkos::View<const double*>& Vj,
-	    const Kokkos::View<const double*>& cj) const
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j){
-      m_Vj_over_cj[j] = Vj[j]/cj[j];
-    });
-
-  double dt = std::numeric_limits<double>::max();
-  Kokkos::parallel_reduce(m_nj, ReduceMin(m_Vj_over_cj), dt);
-
-  return dt;
-}
-
-KOKKOS_INLINE_FUNCTION
-void
-AcousticSolverClass::inverse(const Kokkos::View<const double*>& x,
-			     Kokkos::View<double*>& inv_x) const
-{
-  Kokkos::parallel_for(x.size(), KOKKOS_LAMBDA(const int& r) {
-      inv_x(r) = 1./x(r);
-    });
-}
-
-KOKKOS_INLINE_FUNCTION
-void AcousticSolverClass::computeExplicitFluxes(const Kokkos::View<const double*>& xr,
-						const Kokkos::View<const double*>& xj,
-						const Kokkos::View<const double*>& rhoj,
-						const Kokkos::View<const double*>& uj,
-						const Kokkos::View<const double*>& pj,
-						const Kokkos::View<const double*>& cj,
-						const Kokkos::View<const double*>& Vj,
-						const Kokkos::View<const double*[2]>& Cjr,
-						const Kokkos::View<const int*[2]>& cell_nodes,
-						const Kokkos::View<const int*[2]>& node_cells,
-						const Kokkos::View<const int*>& node_nb_cells,
-						const Kokkos::View<const int*[2]>& node_cell_local_node,
-						Kokkos::View<double*>& ur,
-						Kokkos::View<double*[2]>& Fjr)
-{
-  const Kokkos::View<const double*> rhocj  = computeRhoCj(rhoj, cj);
-  const Kokkos::View<const double*[2]> Ajr = computeAjr(rhocj, Cjr);
-
-  const Kokkos::View<const double*> Ar = computeAr(Ajr, node_cells, node_cell_local_node, node_nb_cells);
-  const Kokkos::View<const double*> br = computeBr(Ajr, Cjr, uj, pj,
-						   node_cells, node_cell_local_node, node_nb_cells);
-
-  ur  = computeUr(Ar, br);
-  Fjr = computeFjr(Ajr, ur, Cjr, uj, pj, cell_nodes);
-}
-
-AcousticSolverClass::AcousticSolverClass(const long int& nj)
-  : m_nj(nj),
-    m_nr(nj+1),
-    m_br("br", m_nr),
-    m_Ajr("Ajr", m_nj),
-    m_Ar("Ar", m_nr),
-    m_inv_Ar("inv_Ar", m_nr),
-    m_Fjr("Fjr", m_nj),
-    m_ur("ur", m_nr),
-    m_rhocj("rho_c", m_nj),
-    m_Vj_over_cj("Vj_over_cj", m_nj)
-{
-  Kokkos::View<double*> xj("xj",m_nj);
-  Kokkos::View<double*> rhoj("rhoj",m_nj);
-
-  Kokkos::View<double*> uj("uj",m_nj);
-
-  Kokkos::View<double*> Ej("Ej",m_nj);
-  Kokkos::View<double*> ej("ej",m_nj);
-  Kokkos::View<double*> pj("pj",m_nj);
-  Kokkos::View<double*> Vj("Vj",m_nj);
-  Kokkos::View<double*> gammaj("gammaj",m_nj);
-  Kokkos::View<double*> cj("cj",m_nj);
-  Kokkos::View<double*> mj("mj",m_nj);
-
-  Kokkos::View<double*>  xr("xr", m_nr);
-
-  const double delta_x = 1./m_nj;
-
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-      xr[r] = r*delta_x;
-    });
-
-  Kokkos::View<int*[2]> cell_nodes("cell_nodes",m_nj,2);
-  Kokkos::View<int*[2]> node_cells("node_cells",m_nr,2);
-  Kokkos::View<int*[2]> node_cell_local_node("node_cells",m_nr,2);
-  Kokkos::View<int*> node_nb_cells("node_cells",m_nr);
-
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-      node_nb_cells(r) = 2;
-    });
-  node_nb_cells(0) = 1;
-  node_nb_cells(m_nr-1) = 1;
-
-  node_cells(0,0) = 0;
-  Kokkos::parallel_for(m_nr-2, KOKKOS_LAMBDA(const int& r){
-      node_cells(r+1,0) = r;
-      node_cells(r+1,1) = r+1;
-    });
-  node_cells(m_nr-1,0) =m_nj-1;
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      cell_nodes(j,0) = j;
-      cell_nodes(j,1) = j+1;
-    });
-
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-      for (int J=0; J<node_nb_cells(r); ++J) {
-	int j = node_cells(r,J);
-	for (int R=0; R<2; ++R) {
-	  if (cell_nodes(j,R) == r) {
-	    node_cell_local_node(r,J) = R;
-	  }
-	}
-      }
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      xj[j] = 0.5*(xr[cell_nodes(j,0)]+xr[cell_nodes(j,1)]);
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Vj[j] = xr[cell_nodes(j,1)]-xr[cell_nodes(j,0)];
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      if (xj[j]<0.5) {
-	rhoj[j]=1;
-      } else {
-	rhoj[j]=0.125;
-      }
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      if (xj[j]<0.5) {
-	pj[j]=1;
-      } else {
-	pj[j]=0.1;
-      }
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      gammaj[j] = 1.4;
-    });
-
-  BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj);
-
-  block_eos.updateEandCFromRhoP();
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Ej[j] = ej[j]+0.5*uj[j]*uj[j];
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      mj[j] = rhoj[j] * Vj[j];
-    });
-
-  Kokkos::View<double*> inv_mj("inv_mj",m_nj);
-  inverse(mj, inv_mj);
-
-  const double tmax=0.2;
-  double t=0;
-
-  int itermax=std::numeric_limits<int>::max();
-  int iteration=0;
-
-  Kokkos::View<double*[2]> Cjr("Cjr",m_nj);
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j) {
-      Cjr(j,0)=-1;
-      Cjr(j,1)= 1;
-    });
-
-  while((t<tmax) and (iteration<itermax)) {
-    double dt = 0.4*acoustic_dt(Vj, cj);
-    if (t+dt<tmax) {
-      t+=dt;
-    } else {
-      dt=tmax-t;
-      t=tmax;
-    }
-
-    computeExplicitFluxes(xr, xj,
-			  rhoj, uj, pj, cj, Vj, Cjr,
-			  cell_nodes, node_cells, node_nb_cells, node_cell_local_node,
-			  m_ur, m_Fjr);
-
-    const Kokkos::View<const double*[2]> Fjr = m_Fjr;
-    const Kokkos::View<const double*> ur = m_ur;
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	double momentum_fluxes = 0;
-	double energy_fluxes = 0;
-	for (int R=0; R<2; ++R) {
-	  const int r=cell_nodes(j,R);
-	  momentum_fluxes += Fjr(j,R);
-	  energy_fluxes += Fjr(j,R)*ur[r];
-	}
-	uj[j] -= dt*inv_mj[j]*(momentum_fluxes);
-	Ej[j] -= dt*inv_mj[j]*(energy_fluxes);
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j) {
-	ej[j] = Ej[j] - 0.5 * uj[j]*uj[j];
-      });
-
-    Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-	xr[r] += dt*ur[r];
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	xj[j] = 0.5*(xr[j]+xr[j+1]);
-	Vj[j] = xr[j+1]-xr[j];
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	rhoj[j] = mj[j]/Vj[j];
-      });
-
-    block_eos.updatePandCFromRhoE();    
-    
-    ++iteration;
-  }
-
-  // {
-  //   std::ofstream fout("rho");
-  //   for (int j=0; j<nj; ++j) {
-  //     fout << xj[j] << ' ' << rhoj[j] << '\n';
-  //   }
-  // }
-
-  std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset
-	    << ":  " << rang::fgB::green << t << rang::fg::reset << " (" << iteration << " iterations)\n";
-
-}
diff --git a/src/experimental/AcousticSolverClass.hpp b/src/experimental/AcousticSolverClass.hpp
deleted file mode 100644
index 2c2f8c0eccad97536b2e7f840aa01d8ccca058bf..0000000000000000000000000000000000000000
--- a/src/experimental/AcousticSolverClass.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef ACOUSTIC_SOLVER_CLASS_HPP
-#define ACOUSTIC_SOLVER_CLASS_HPP
-
-#include <Kokkos_Core.hpp>
-
-class AcousticSolverClass
-{
-private:
-  inline const Kokkos::View<const double*>
-  computeRhoCj(const Kokkos::View<const double*>& rhoj,
-	       const Kokkos::View<const double*>& cj);
-
-  inline const Kokkos::View<const double*[2]>
-  computeAjr(const Kokkos::View<const double*>& rhocj,
-	     const Kokkos::View<const double*[2]>& Cjr);
-
-  inline const Kokkos::View<const double*>
-  computeAr(const Kokkos::View<const double*[2]>& Ajr,
-	    const Kokkos::View<const int*[2]>& node_cells,
-	    const Kokkos::View<const int*[2]>& node_cell_local_node,
-	    const Kokkos::View<const int*>& node_nb_cells);
-
-  inline const Kokkos::View<const double*>
-  computeBr(const Kokkos::View<const double*[2]>& Ajr,
-	    const Kokkos::View<const double*[2]>& Cjr,
-	    const Kokkos::View<const double*>& uj,
-	    const Kokkos::View<const double*>& pj,
-	    const Kokkos::View<const int*[2]>& node_cells,
-	    const Kokkos::View<const int*[2]>& node_cell_local_node,
-	    const Kokkos::View<const int*>& node_nb_cells);
-
-  Kokkos::View<double*>
-  computeUr(const Kokkos::View<const double*>& Ar,
-	    const Kokkos::View<const double*>& br);
-
-  Kokkos::View<double*[2]>
-  computeFjr(const Kokkos::View<const double*[2]>& Ajr,
-	     const Kokkos::View<const double*>& ur,
-	     const Kokkos::View<const double*[2]>& Cjr,
-	     const Kokkos::View<const double*>& uj,
-	     const Kokkos::View<const double*>& pj,
-	     const Kokkos::View<const int*[2]>& cell_nodes);
-
-  void inverse(const Kokkos::View<const double*>& x,
-	       Kokkos::View<double*>& inv_x) const;
-
-  inline double acoustic_dt(const Kokkos::View<const double*>& Vj,
-			    const Kokkos::View<const double*>& cj) const;
-
-  inline void computeExplicitFluxes(const Kokkos::View<const double*>& xr,
-				    const Kokkos::View<const double*>& xj,
-				    const Kokkos::View<const double*>& rhoj,
-				    const Kokkos::View<const double*>& uj,
-				    const Kokkos::View<const double*>& pj,
-				    const Kokkos::View<const double*>& cj,
-				    const Kokkos::View<const double*>& Vj,
-				    const Kokkos::View<const double*[2]>& Cjr,
-				    const Kokkos::View<const int*[2]>& cell_nodes,
-				    const Kokkos::View<const int*[2]>& node_cells,
-				    const Kokkos::View<const int*>& node_nb_cells,
-				    const Kokkos::View<const int*[2]>& node_cell_local_node,
-				    Kokkos::View<double*>& ur,
-				    Kokkos::View<double*[2]>& Fjr);
-
-  struct ReduceMin;
-
-  const long int m_nj;
-  const long int m_nr;
-
-  Kokkos::View<double*> m_br;
-  Kokkos::View<double*[2]> m_Ajr;
-  Kokkos::View<double*> m_Ar;
-  Kokkos::View<double*> m_inv_Ar;
-  Kokkos::View<double*[2]> m_Fjr;
-  Kokkos::View<double*> m_ur;
-  Kokkos::View<double*> m_rhocj;
-  Kokkos::View<double*> m_Vj_over_cj;
-
-
-public:
-  AcousticSolverClass(const long int& nj);
-};
-
-#endif // ACOUSTIC_SOLVER_CLASS_HPP
diff --git a/src/experimental/AcousticSolverTest.cpp b/src/experimental/AcousticSolverTest.cpp
deleted file mode 100644
index aaa9c0dbfefdbb603a95d657b81e23813ad5e69c..0000000000000000000000000000000000000000
--- a/src/experimental/AcousticSolverTest.cpp
+++ /dev/null
@@ -1,402 +0,0 @@
-#include <AcousticSolverTest.hpp>
-#include <rang.hpp>
-
-#include <BlockPerfectGas.hpp>
-#include <fstream>
-
-typedef const double my_double;
-
-struct AcousticSolverTest::ReduceMin
-{
-private:
-  const Kokkos::View<my_double*> x_;
-
-public:
-  typedef Kokkos::View<my_double*>::non_const_value_type value_type;
-
-  ReduceMin(const Kokkos::View<my_double*>& x) : x_ (x) {}
-
-  typedef Kokkos::View<my_double*>::size_type size_type;
-
-  KOKKOS_INLINE_FUNCTION void
-  operator() (const size_type i, value_type& update) const
-  {
-    if (x_(i) < update) {
-      update = x_(i);
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  join (volatile value_type& dst,
-	const volatile value_type& src) const
-  {
-    if (src < dst) {
-      dst = src;
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  init (value_type& dst) const
-  { // The identity under max is -Inf.
-    dst= Kokkos::reduction_identity<value_type>::min();
-  }
-};
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const double*>
-AcousticSolverTest::computeRhoCj(const Kokkos::View<const double*>& rhoj,
-				 const Kokkos::View<const double*>& cj)
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j) {
-      m_rhocj[j] = rhoj[j]*cj[j];
-    });
-  return m_rhocj;
-}
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const Rdd*[2]>
-AcousticSolverTest::computeAjr(const Kokkos::View<const double*>& rhocj,
-			       const Kokkos::View<const Rd*[2]>& Cjr)
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j) {
-      for (int r=0; r<2; ++r) {
-	m_Ajr(j,r) = tensorProduct(rhocj(j)*Cjr(j,r), Cjr(j,r));
-      }
-    });
-
-  return m_Ajr;
-}
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const Rdd*>
-AcousticSolverTest::computeAr(const Kokkos::View<const Rdd*[2]>& Ajr,
-			      const Kokkos::View<const int*[2]>& node_cells,
-			      const Kokkos::View<const int*[2]>& node_cell_local_node,
-			      const Kokkos::View<const int*>& node_nb_cells)
-{
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r) {
-      Rdd sum = zero;
-      for (int j=0; j<node_nb_cells(r); ++j) {
-	const int J = node_cells(r,j);
-	const int R = node_cell_local_node(r,j);
-  	sum += Ajr(J,R);
-      }
-      m_Ar(r) = sum;
-    });
-
-  return m_Ar;
-}
-
-KOKKOS_INLINE_FUNCTION
-const Kokkos::View<const Rd*>
-AcousticSolverTest::computeBr(const Kokkos::View<const Rdd*[2]>& Ajr,
-			      const Kokkos::View<const Rd*[2]>& Cjr,
-			      const Kokkos::View<const Rd*>& uj,
-			      const Kokkos::View<const double*>& pj,
-			      const Kokkos::View<const int*[2]>& node_cells,
-			      const Kokkos::View<const int*[2]>& node_cell_local_node,
-			      const Kokkos::View<const int*>& node_nb_cells)
-{
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r) {
-      Rd& br = m_br(r);
-      br = zero;
-      for (int j=0; j<node_nb_cells(r); ++j) {
-  	const int J = node_cells(r,j);
-  	const int R = node_cell_local_node(r,j);
-  	br += Ajr(J,R)*uj(J) + pj(J)*Cjr(J,R);
-      }
-    });
-
-  return m_br;
-}
-
-KOKKOS_INLINE_FUNCTION
-Kokkos::View<Rd*>
-AcousticSolverTest::computeUr(const Kokkos::View<const Rdd*>& Ar,
-			      const Kokkos::View<const Rd*>& br)
-{
-  inverse(Ar, m_inv_Ar);
-  const Kokkos::View<const Rdd*> invAr = m_inv_Ar;
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r) {
-      m_ur[r]=invAr(r)*br(r);
-    });
-  m_ur[0]=zero;
-  m_ur[m_nr-1]=zero;
-
-  return m_ur;
-}
-
-KOKKOS_INLINE_FUNCTION
-Kokkos::View<Rd*[2]>
-AcousticSolverTest::computeFjr(const Kokkos::View<const Rdd*[2]>& Ajr,
-			       const Kokkos::View<const Rd*>& ur,
-			       const Kokkos::View<const Rd*[2]>& Cjr,
-			       const Kokkos::View<const Rd*>& uj,
-			       const Kokkos::View<const double*>& pj,
-			       const Kokkos::View<const int*[2]>& cell_nodes)
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j) {
-      for (int r=0; r<2; ++r) {
-	m_Fjr(j,r) = Ajr(j,r)*(uj(j)-ur(cell_nodes(j,r)))+pj(j)*Cjr(j,r);
-      }
-    });
-
-  return m_Fjr;
-}
-
-KOKKOS_INLINE_FUNCTION
-double AcousticSolverTest::
-acoustic_dt(const Kokkos::View<const double*>& Vj,
-	    const Kokkos::View<const double*>& cj) const
-{
-  Kokkos::parallel_for(m_nj, KOKKOS_LAMBDA(const int& j){
-      m_Vj_over_cj[j] = Vj[j]/cj[j];
-    });
-
-  double dt = std::numeric_limits<double>::max();
-  Kokkos::parallel_reduce(m_nj, ReduceMin(m_Vj_over_cj), dt);
-
-  return dt;
-}
-
-KOKKOS_INLINE_FUNCTION
-void
-AcousticSolverTest::inverse(const Kokkos::View<const double*>& x,
-			    Kokkos::View<double*>& inv_x) const
-{
-  Kokkos::parallel_for(x.size(), KOKKOS_LAMBDA(const int& r) {
-      inv_x(r) = 1./x(r);
-    });
-}
-
-KOKKOS_INLINE_FUNCTION
-void
-AcousticSolverTest::inverse(const Kokkos::View<const Rdd*>& A,
-			    Kokkos::View<Rdd*>& inv_A) const
-{
-  Kokkos::parallel_for(A.size(), KOKKOS_LAMBDA(const int& r) {
-      inv_A(r) = Rdd{1./(A(r)(0,0))};
-    });
-}
-
-
-KOKKOS_INLINE_FUNCTION
-void AcousticSolverTest::computeExplicitFluxes(const Kokkos::View<const Rd*>& xr,
-					       const Kokkos::View<const Rd*>& xj,
-					       const Kokkos::View<const double*>& rhoj,
-					       const Kokkos::View<const Rd*>& uj,
-					       const Kokkos::View<const double*>& pj,
-					       const Kokkos::View<const double*>& cj,
-					       const Kokkos::View<const double*>& Vj,
-					       const Kokkos::View<const Rd*[2]>& Cjr,
-					       const Kokkos::View<const int*[2]>& cell_nodes,
-					       const Kokkos::View<const int*[2]>& node_cells,
-					       const Kokkos::View<const int*>& node_nb_cells,
-					       const Kokkos::View<const int*[2]>& node_cell_local_node,
-					       Kokkos::View<Rd*>& ur,
-					       Kokkos::View<Rd*[2]>& Fjr)
-{
-  const Kokkos::View<const double*> rhocj  = computeRhoCj(rhoj, cj);
-  const Kokkos::View<const Rdd*[2]> Ajr = computeAjr(rhocj, Cjr);
-
-  const Kokkos::View<const Rdd*> Ar = computeAr(Ajr, node_cells, node_cell_local_node, node_nb_cells);
-  const Kokkos::View<const Rd*> br = computeBr(Ajr, Cjr, uj, pj,
-						   node_cells, node_cell_local_node, node_nb_cells);
-
-  ur  = computeUr(Ar, br);
-  Fjr = computeFjr(Ajr, ur, Cjr, uj, pj, cell_nodes);
-}
-
-AcousticSolverTest::AcousticSolverTest(const long int& nj)
-  : m_nj(nj),
-    m_nr(nj+1),
-    m_br("br", m_nr),
-    m_Ajr("Ajr", m_nj),
-    m_Ar("Ar", m_nr),
-    m_inv_Ar("inv_Ar", m_nr),
-    m_Fjr("Fjr", m_nj),
-    m_ur("ur", m_nr),
-    m_rhocj("rho_c", m_nj),
-    m_Vj_over_cj("Vj_over_cj", m_nj)
-{
-  Kokkos::View<Rd*> xj("xj",m_nj);
-  Kokkos::View<double*> rhoj("rhoj",m_nj);
-
-  Kokkos::View<Rd*> uj("uj",m_nj);
-
-  Kokkos::View<double*> Ej("Ej",m_nj);
-  Kokkos::View<double*> ej("ej",m_nj);
-  Kokkos::View<double*> pj("pj",m_nj);
-  Kokkos::View<double*> Vj("Vj",m_nj);
-  Kokkos::View<double*> gammaj("gammaj",m_nj);
-  Kokkos::View<double*> cj("cj",m_nj);
-  Kokkos::View<double*> mj("mj",m_nj);
-
-  Kokkos::View<Rd*>  xr("xr", m_nr);
-
-  const double delta_x = 1./m_nj;
-
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-      xr[r][0] = r*delta_x;
-    });
-
-  Kokkos::View<int*[2]> cell_nodes("cell_nodes",m_nj,2);
-  Kokkos::View<int*[2]> node_cells("node_cells",m_nr,2);
-  Kokkos::View<int*[2]> node_cell_local_node("node_cells",m_nr,2);
-  Kokkos::View<int*> node_nb_cells("node_cells",m_nr);
-
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-      node_nb_cells(r) = 2;
-    });
-  node_nb_cells(0) = 1;
-  node_nb_cells(m_nr-1) = 1;
-
-  node_cells(0,0) = 0;
-  Kokkos::parallel_for(m_nr-2, KOKKOS_LAMBDA(const int& r){
-      node_cells(r+1,0) = r;
-      node_cells(r+1,1) = r+1;
-    });
-  node_cells(m_nr-1,0) =m_nj-1;
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      cell_nodes(j,0) = j;
-      cell_nodes(j,1) = j+1;
-    });
-
-  Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-      for (int J=0; J<node_nb_cells(r); ++J) {
-	int j = node_cells(r,J);
-	for (int R=0; R<2; ++R) {
-	  if (cell_nodes(j,R) == r) {
-	    node_cell_local_node(r,J) = R;
-	  }
-	}
-      }
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      xj[j] = 0.5*(xr[cell_nodes(j,0)]+xr[cell_nodes(j,1)]);
-    });
-
-  Kokkos::View<Rd*[2]> Cjr("Cjr",m_nj);
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j) {
-      Cjr(j,0)=-1;
-      Cjr(j,1)= 1;
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Vj[j] = (xr[cell_nodes(j,1)], Cjr(j,1))
-	    + (xr[cell_nodes(j,0)], Cjr(j,0));
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      if (xj[j][0]<0.5) {
-	rhoj[j]=1;
-      } else {
-	rhoj[j]=0.125;
-      }
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      if (xj[j][0]<0.5) {
-	pj[j]=1;
-      } else {
-	pj[j]=0.1;
-      }
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      uj[j] = zero;
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      gammaj[j] = 1.4;
-    });
-
-  BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj);
-
-  block_eos.updateEandCFromRhoP();
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Ej[j] = ej[j]+0.5*(uj[j],uj[j]);
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      mj[j] = rhoj[j] * Vj[j];
-    });
-
-  Kokkos::View<double*> inv_mj("inv_mj",m_nj);
-  inverse(mj, inv_mj);
-
-  const double tmax=0.2;
-  double t=0;
-
-  int itermax=std::numeric_limits<int>::max();
-  int iteration=0;
-
-  while((t<tmax) and (iteration<itermax)) {
-    double dt = 0.4*acoustic_dt(Vj, cj);
-    if (t+dt<tmax) {
-      t+=dt;
-    } else {
-      dt=tmax-t;
-      t=tmax;
-    }
-
-    computeExplicitFluxes(xr, xj,
-			  rhoj, uj, pj, cj, Vj, Cjr,
-			  cell_nodes, node_cells, node_nb_cells, node_cell_local_node,
-			  m_ur, m_Fjr);
-
-    const Kokkos::View<const Rd*[2]> Fjr = m_Fjr;
-    const Kokkos::View<const Rd*> ur = m_ur;
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j) {
-	Rd momentum_fluxes = zero;
-	double energy_fluxes = 0;
-	for (int R=0; R<2; ++R) {
-	  const int r=cell_nodes(j,R);
-	  momentum_fluxes +=  Fjr(j,R);
-	  energy_fluxes   += ((Fjr(j,R), ur[r]));
-	}
-	uj[j] -= (dt*inv_mj[j]) * momentum_fluxes;
-	Ej[j] -= (dt*inv_mj[j]) * energy_fluxes;
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j) {
-	ej[j] = Ej[j] - 0.5 * (uj[j],uj[j]);
-      });
-
-    Kokkos::parallel_for(m_nr, KOKKOS_LAMBDA(const int& r){
-	xr[r] += dt*ur[r];
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	xj[j] = 0.5*(xr[j]+xr[j+1]);
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Vj[j] = (xr[cell_nodes(j,1)], Cjr(j,1))
-	    + (xr[cell_nodes(j,0)], Cjr(j,0));
-    });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	rhoj[j] = mj[j]/Vj[j];
-      });
-
-    block_eos.updatePandCFromRhoE();
-
-    ++iteration;
-  }
-
-  {
-    std::ofstream fout("rho");
-    for (int j=0; j<nj; ++j) {
-      fout << xj[j][0] << ' ' << rhoj[j] << '\n';
-    }
-  }
-
-  std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset
-	    << ":  " << rang::fgB::green << t << rang::fg::reset << " (" << iteration << " iterations)\n";
-
-}
diff --git a/src/experimental/AcousticSolverTest.hpp b/src/experimental/AcousticSolverTest.hpp
deleted file mode 100644
index 209a18747bb42eb467e6a992faaf8f64e706f856..0000000000000000000000000000000000000000
--- a/src/experimental/AcousticSolverTest.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef ACOUSTIC_SOLVER_TEST_HPP
-#define ACOUSTIC_SOLVER_TEST_HPP
-
-#include <Kokkos_Core.hpp>
-
-#include <TinyVector.hpp>
-#include <TinyMatrix.hpp>
-
-constexpr static size_t dimension = 1;
-
-typedef TinyVector<dimension> Rd;
-typedef TinyMatrix<dimension> Rdd;
-
-class AcousticSolverTest 
-{
-private:
-
-  inline const Kokkos::View<const double*>
-  computeRhoCj(const Kokkos::View<const double*>& rhoj,
-	       const Kokkos::View<const double*>& cj);
-
-  inline const Kokkos::View<const Rdd*[2]>
-  computeAjr(const Kokkos::View<const double*>& rhocj,
-	     const Kokkos::View<const Rd*[2]>& Cjr);
-
-  inline const Kokkos::View<const Rdd*>
-  computeAr(const Kokkos::View<const Rdd*[2]>& Ajr,
-	    const Kokkos::View<const int*[2]>& node_cells,
-	    const Kokkos::View<const int*[2]>& node_cell_local_node,
-	    const Kokkos::View<const int*>& node_nb_cells);
-
-  inline const Kokkos::View<const Rd*>
-  computeBr(const Kokkos::View<const Rdd*[2]>& Ajr,
-	    const Kokkos::View<const Rd*[2]>& Cjr,
-	    const Kokkos::View<const Rd*>& uj,
-	    const Kokkos::View<const double*>& pj,
-	    const Kokkos::View<const int*[2]>& node_cells,
-	    const Kokkos::View<const int*[2]>& node_cell_local_node,
-	    const Kokkos::View<const int*>& node_nb_cells);
-
-  Kokkos::View<Rd*>
-  computeUr(const Kokkos::View<const Rdd*>& Ar,
-	    const Kokkos::View<const Rd*>& br);
-
-  Kokkos::View<Rd*[2]>
-  computeFjr(const Kokkos::View<const Rdd*[2]>& Ajr,
-	     const Kokkos::View<const Rd*>& ur,
-	     const Kokkos::View<const Rd*[2]>& Cjr,
-	     const Kokkos::View<const Rd*>& uj,
-	     const Kokkos::View<const double*>& pj,
-	     const Kokkos::View<const int*[2]>& cell_nodes);
-
-  void inverse(const Kokkos::View<const Rdd*>& A,
-	       Kokkos::View<Rdd*>& inv_A) const;
-
-  void inverse(const Kokkos::View<const double*>& x,
-	       Kokkos::View<double*>& inv_x) const;
-
-  inline double acoustic_dt(const Kokkos::View<const double*>& Vj,
-			    const Kokkos::View<const double*>& cj) const;
-
-  inline void computeExplicitFluxes(const Kokkos::View<const Rd*>& xr,
-				    const Kokkos::View<const Rd*>& xj,
-				    const Kokkos::View<const double*>& rhoj,
-				    const Kokkos::View<const Rd*>& uj,
-				    const Kokkos::View<const double*>& pj,
-				    const Kokkos::View<const double*>& cj,
-				    const Kokkos::View<const double*>& Vj,
-				    const Kokkos::View<const Rd*[2]>& Cjr,
-				    const Kokkos::View<const int*[2]>& cell_nodes,
-				    const Kokkos::View<const int*[2]>& node_cells,
-				    const Kokkos::View<const int*>& node_nb_cells,
-				    const Kokkos::View<const int*[2]>& node_cell_local_node,
-				    Kokkos::View<Rd*>& ur,
-				    Kokkos::View<Rd*[2]>& Fjr);
-
-  struct ReduceMin;
-
-  const size_t m_nj;
-  const size_t m_nr;
-
-  Kokkos::View<Rd*> m_br;
-  Kokkos::View<Rdd*[2]> m_Ajr;
-  Kokkos::View<Rdd*> m_Ar;
-  Kokkos::View<Rdd*> m_inv_Ar;
-  Kokkos::View<Rd*[2]> m_Fjr;
-  Kokkos::View<Rd*> m_ur;
-  Kokkos::View<double*> m_rhocj;
-  Kokkos::View<double*> m_Vj_over_cj;
-
-
-public:
-  AcousticSolverTest(const long int& nj);
-};
-
-#endif // ACOUSTIC_SOLVER_TEST_HPP
diff --git a/src/experimental/CMakeLists.txt b/src/experimental/CMakeLists.txt
deleted file mode 100644
index 1c6043787ec8d6809e233214fc57a465618eddc8..0000000000000000000000000000000000000000
--- a/src/experimental/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-include_directories(${Kokkos_INCLUDE_DIRS_RET})
-include_directories(${PASTIS_SOURCE_DIR}/packages/rang/include)
-
-# ------------------- Source files --------------------
-
-add_library(
-  PastisExperimental
-  AcousticSolverClass.cpp
-  AcousticSolverTest.cpp
-  RawKokkosAcousticSolver.cpp
-  MeshLessAcousticSolver.cpp
-  )
-
-
diff --git a/src/experimental/MeshLessAcousticSolver.cpp b/src/experimental/MeshLessAcousticSolver.cpp
deleted file mode 100644
index bf501448130f9e2291a2692d956f2757f5ccfc05..0000000000000000000000000000000000000000
--- a/src/experimental/MeshLessAcousticSolver.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-#include <MeshLessAcousticSolver.hpp>
-#include <rang.hpp>
-
-#include <memory>
-
-#include <BlockPerfectGas.hpp>
-
-typedef const double my_double;
-
-struct MeshLessAcousticSolver::ReduceMin {
-private:
-  const Kokkos::View<my_double*> x_;
-
-public:
-  typedef Kokkos::View<my_double*>::non_const_value_type value_type;
-
-  ReduceMin(const Kokkos::View<my_double*>& x) : x_ (x) {}
-
-  typedef Kokkos::View<my_double*>::size_type size_type;
-    
-  KOKKOS_INLINE_FUNCTION void
-  operator() (const size_type i, value_type& update) const
-  {
-    if (x_(i) < update) {
-      update = x_(i);
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  join (volatile value_type& dst,
-	const volatile value_type& src) const
-  {
-    if (src < dst) {
-      dst = src;
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  init (value_type& dst) const
-  { // The identity under max is -Inf.
-    dst= Kokkos::reduction_identity<value_type>::min();
-  }
-};
-    
-
-KOKKOS_INLINE_FUNCTION
-double MeshLessAcousticSolver::
-acoustic_dt(const Kokkos::View<const double*>& Vj,
-	    const Kokkos::View<const double*>& cj) const
-{
-  const size_t nj = Vj.size();
-  double dt = std::numeric_limits<double>::max();
-
-  Kokkos::View<double*> Vj_cj("Vj_cj", nj);
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Vj_cj[j] = Vj[j]/cj[j];
-    });
-
-  Kokkos::parallel_reduce(nj, ReduceMin(Vj_cj), dt);
-
-  return dt;
-}
-
-
-KOKKOS_INLINE_FUNCTION
-void MeshLessAcousticSolver::computeExplicitFluxes(const Kokkos::View<const double*>& xr,
-					   const Kokkos::View<const double*>& xj,
-					   const Kokkos::View<const double*>& rhoj,
-					   const Kokkos::View<const double*>& uj,
-					   const Kokkos::View<const double*>& pj,
-					   const Kokkos::View<const double*>& cj,
-					   const Kokkos::View<const double*>& Vj,
-					   Kokkos::View<double*>& ur,
-					   Kokkos::View<double*>& pr) const
-{
-  // calcul de ur
-  ur[0]=0;
-  const size_t nr = ur.size();
-  const size_t nj = uj.size();
-
-  Kokkos::parallel_for(nj-1, KOKKOS_LAMBDA(const int& j) {
-    const int r = j+1;
-    const int k = r;
-
-    const double ujr = uj[j];
-    const double ukr = uj[k];
-    const double pjr = pj[j];
-    const double pkr = pj[k];
-
-    ur[r]=(rhoj[j]*cj[j]*ujr + rhoj[k]*cj[k]*ukr + pjr-pkr)/(rhoj[j]*cj[j]+rhoj[k]*cj[k]);
-    });
-  ur[nr-1]=0;
-
-  // calcul de pr
-  pr[0] = pj[0] + rhoj[0]*cj[0]*(ur[0] - uj[0]);
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j) {
-    const int r = j+1;
-
-    const double ujr = uj[j];
-    const double pjr = pj[j];
-
-    pr[r]=pjr+rhoj[j]*cj[j]*(ujr-ur[r]);
-    });
-}
-
-
-MeshLessAcousticSolver::MeshLessAcousticSolver(const long int& nj)
-{
-  Kokkos::View<double*> xj("xj", nj);
-  Kokkos::View<double*> rhoj("rhoj", nj);
-
-  Kokkos::View<double*> uj("uj", nj);
-
-  Kokkos::View<double*> Ej("Ej", nj);
-  Kokkos::View<double*> ej("ej", nj);
-  Kokkos::View<double*> pj("pj", nj);
-  Kokkos::View<double*> Vj("Vj", nj);
-  Kokkos::View<double*> gammaj("gammaj", nj);
-  Kokkos::View<double*> cj("cj", nj);
-  Kokkos::View<double*> mj("mj", nj);
-  Kokkos::View<double*> inv_mj("inv_mj", nj);
-
-  const int nr=nj+1;
-
-  Kokkos::View<double*>  xr("xr", nr);
-
-  const double delta_x = 1./nj;
-
-  Kokkos::parallel_for(nr, KOKKOS_LAMBDA(const int& r){
-      xr[r] = r*delta_x;
-    });
-
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      xj[j] = 0.5*(xr[j]+xr[j+1]);
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Vj[j] = xr[j+1]-xr[j];
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    if (xj[j]<0.5) {
-      rhoj[j]=1;
-    } else {
-      rhoj[j]=0.125;
-    }
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    if (xj[j]<0.5) {
-      pj[j]=1;
-    } else {
-      pj[j]=0.1;
-    }
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      gammaj[j] = 1.4;
-    });
-
-  BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj);
-
-  block_eos.updateEandCFromRhoP();
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Ej[j] = ej[j]+0.5*uj[j]*uj[j];
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    mj[j] = rhoj[j] * Vj[j];
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      inv_mj[j] = 1./mj[j];
-    });
-
-  const double tmax=0.2;
-  double t=0;
-
-  int itermax=std::numeric_limits<int>::max();
-  int iteration=0;
-
-  while((t<tmax) and (iteration<itermax)) {
-    double dt = 0.4*acoustic_dt(Vj, cj);
-    if (t+dt<tmax) {
-      t+=dt;
-    } else {
-      dt=tmax-t;
-      t=tmax;
-    }
-    
-    Kokkos::View<double*> ur("ur", nr);
-    Kokkos::View<double*> pr("pr", nr);
-
-    computeExplicitFluxes(xr, xj,
-			  rhoj, uj, pj, cj, Vj,
-			  ur, pr);
-
-    Kokkos::View<double*> new_uj("new_uj", nj);
-    Kokkos::View<double*> new_Ej("new_Ej", nj);
-    
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      int rm=j;
-      int rp=j+1;
-
-      new_uj[j] = uj[j] + dt*inv_mj[j]*(pr[rm]-pr[rp]);
-      new_Ej[j] = Ej[j] + dt*inv_mj[j]*(pr[rm]*ur[rm]-pr[rp]*ur[rp]);
-      });
-
-    uj=new_uj;
-    Ej=new_Ej;
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	ej[j] = Ej[j] - 0.5 * uj[j]*uj[j];
-      });
-
-    Kokkos::View<double*> xr_new("new_xr", nr);
-
-    Kokkos::parallel_for(nr, KOKKOS_LAMBDA(const int& r){
-      xr_new[r] = xr[r] + dt*ur[r];
-      });
-
-    xr = xr_new;
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      xj[j] = 0.5*(xr[j]+xr[j+1]);
-      Vj[j] = xr[j+1]-xr[j];
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	rhoj[j] = mj[j]/Vj[j];
-      });
-
-    block_eos.updatePandCFromRhoE();    
-    
-    ++iteration;
-  }
-
-  std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset
-	    << ":  " << rang::fgB::green << t << rang::fg::reset << " (" << iteration << " iterations)\n";
-
-}
diff --git a/src/experimental/MeshLessAcousticSolver.hpp b/src/experimental/MeshLessAcousticSolver.hpp
deleted file mode 100644
index ccdba58383fa691ed713887a3b0fd09e37b92446..0000000000000000000000000000000000000000
--- a/src/experimental/MeshLessAcousticSolver.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef MESH_LESS_ACOUSTIC_SOLVER_HPP
-#define MESH_LESS_ACOUSTIC_SOLVER_HPP
-
-#include <Kokkos_Core.hpp>
-
-class MeshLessAcousticSolver 
-{
-private:
-
-  inline double e(double rho, double p, double gamma) const;
-  inline double p(double rho, double e, double gamma) const;
-
-  inline double acoustic_dt(const Kokkos::View<const double*>& Vj,
-			    const Kokkos::View<const double*>& cj) const;
-
-  inline void computeExplicitFluxes(const Kokkos::View<const double*>& xr,
-				    const Kokkos::View<const double*>& xj,
-				    const Kokkos::View<const double*>& rhoj,
-				    const Kokkos::View<const double*>& uj,
-				    const Kokkos::View<const double*>& pj,
-				    const Kokkos::View<const double*>& cj,
-				    const Kokkos::View<const double*>& Vj,
-				    Kokkos::View<double*>& ur,
-				    Kokkos::View<double*>& pr) const;
-
-  struct ReduceMin;
-public:
-  MeshLessAcousticSolver(const long int& nj);
-};
-
-#endif // MESH_LESS_ACOUSTIC_SOLVER_HPP
diff --git a/src/experimental/RawKokkosAcousticSolver.cpp b/src/experimental/RawKokkosAcousticSolver.cpp
deleted file mode 100644
index d27549d349183d6eb714be477750ca4fee6381b5..0000000000000000000000000000000000000000
--- a/src/experimental/RawKokkosAcousticSolver.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-#include <RawKokkosAcousticSolver.hpp>
-#include <Kokkos_Core.hpp>
-#include <rang.hpp>
-
-namespace RawKokkos
-{
-
-inline double e(double rho, double p, double gamma)
-{
-  return p/(rho*(gamma-1));
-}
-
-inline double p(double rho, double e, double gamma)
-{
-  return (gamma-1)*rho*e;
-}
-
-typedef const double my_double;
-
-struct ReduceMin {
-private:
-  const Kokkos::View<my_double*> x_;
-
-public:
-  typedef Kokkos::View<my_double*>::non_const_value_type value_type;
-
-  ReduceMin(const Kokkos::View<my_double*>& x) : x_ (x) {}
-
-  typedef Kokkos::View<my_double*>::size_type size_type;
-    
-  KOKKOS_INLINE_FUNCTION void
-  operator() (const size_type i, value_type& update) const
-  {
-    if (x_(i) < update) {
-      update = x_(i);
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  join (volatile value_type& dst,
-	const volatile value_type& src) const
-  {
-    if (src < dst) {
-      dst = src;
-    }
-  }
-
-  KOKKOS_INLINE_FUNCTION void
-  init (value_type& dst) const
-  { // The identity under max is -Inf.
-    dst= Kokkos::reduction_identity<value_type>::min();
-  }
-};
-    
-
-double acoustic_dt(const Kokkos::View<double*>& Vj,
-		   const Kokkos::View<double*>& cj)
-{
-  const size_t nj = Vj.size();
-  double dt = std::numeric_limits<double>::max();
-
-  Kokkos::View<double*> Vj_cj("Vj_cj", nj);
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Vj_cj[j] = Vj[j]/cj[j];
-    });
-
-  Kokkos::parallel_reduce(nj, ReduceMin(Vj_cj), dt);
-
-  // Kokkos::parallel_reduce(n, KOKKOS_LAMBDA(const long i, long& lcount) {
-  //   lcount += (i % 2) == 0;
-  // }, count);
-  return dt;
-}
-
-
-void computeExplicitFluxes(const Kokkos::View<double*>& xr,
-			   const Kokkos::View<double*>& xj,
-			   const Kokkos::View<double*>& rhoj,
-			   const Kokkos::View<double*>& uj,
-			   const Kokkos::View<double*>& pj,
-			   const Kokkos::View<double*>& cj,
-			   const Kokkos::View<double*>& Vj,
-			   Kokkos::View<double*>& ur,
-			   Kokkos::View<double*>& pr)
-{
-  // calcul de ur
-  ur[0]=0;
-  const size_t nr = ur.size();
-  const size_t nj = uj.size();
-
-  Kokkos::parallel_for(nj-1, KOKKOS_LAMBDA(const int& j) {
-    const int r = j+1;
-    const int k = r;
-    const double ujr = uj[j];
-    const double ukr = uj[k];
-    const double pjr = pj[j];
-    const double pkr = pj[k];
-
-    ur[r]=(rhoj[j]*cj[j]*ujr + rhoj[k]*cj[k]*ukr + pjr-pkr)/(rhoj[j]*cj[j]+rhoj[k]*cj[k]);
-    });
-  ur[nr-1]=0;
-
-  // calcul de pr
-  pr[0] = pj[0] + rhoj[0]*cj[0]*(ur[0] - uj[0]);
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j) {
-    const int r = j+1;
-
-    const double ujr = uj[j];
-    const double pjr = pj[j];
-
-    pr[r]=pjr+rhoj[j]*cj[j]*(ujr-ur[r]);
-    });
-}
-
-
-void AcousticSolver(const long int& nj)
-{
-  Kokkos::View<double*> xj("xj", nj);
-  Kokkos::View<double*> rhoj("rhoj", nj);
-
-  Kokkos::View<double*> uj("uj", nj);
-
-  Kokkos::View<double*> Ej("Ej", nj);
-  Kokkos::View<double*> ej("ej", nj);
-  Kokkos::View<double*> pj("pj", nj);
-  Kokkos::View<double*> Vj("Vj", nj);
-  Kokkos::View<double*> gammaj("gammaj", nj);
-  Kokkos::View<double*> cj("cj", nj);
-  Kokkos::View<double*> mj("mj", nj);
-  Kokkos::View<double*> inv_mj("inv_mj", nj);
-
-  const int nr=nj+1;
-
-  Kokkos::View<double*>  xr("xr", nr);
-
-  const double delta_x = 1./nj;
-
-  Kokkos::parallel_for(nr, KOKKOS_LAMBDA(const int& r){
-      xr[r] = r*delta_x;
-    });
-
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      xj[j] = 0.5*(xr[j]+xr[j+1]);
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      Vj[j] = xr[j+1]-xr[j];
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    if (xj[j]<0.5) {
-      rhoj[j]=1;
-    } else {
-      rhoj[j]=0.125;
-    }
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    if (xj[j]<0.5) {
-      pj[j]=1;
-    } else {
-      pj[j]=0.1;
-    }
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      gammaj[j] = 1.4;
-    });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    ej[j] = e(rhoj[j],pj[j],gammaj[j]);
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    Ej[j] = ej[j]+0.5*uj[j]*uj[j];
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    cj[j] = std::sqrt(gammaj[j]*pj[j]/rhoj[j]);
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-    mj[j] = rhoj[j] * Vj[j];
-  });
-
-  Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      inv_mj[j] = 1./mj[j];
-  });
-
-  const double tmax=0.2;
-  double t=0;
-
-  int itermax=std::numeric_limits<int>::max();
-  int iteration=0;
-
-  while((t<tmax) and (iteration<itermax)) {
-    double dt = 0.4*acoustic_dt(Vj, cj);
-    if (t+dt<tmax) {
-      t+=dt;
-    } else {
-      dt=tmax-t;
-      t=tmax;
-    }
-    
-    Kokkos::View<double*> ur("ur", nr);
-    Kokkos::View<double*> pr("pr", nr);
-
-    computeExplicitFluxes(xr, xj,
-			  rhoj, uj, pj, cj, Vj,
-			  ur, pr);
-    
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      int rm=j;
-      int rp=j+1;
-
-      uj[j] += dt*inv_mj[j]*(pr[rm]-pr[rp]);
-      Ej[j] += dt*inv_mj[j]*(pr[rm]*ur[rm]-pr[rp]*ur[rp]);
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	ej[j] = Ej[j] - 0.5 * uj[j]*uj[j];
-      });
-
-    Kokkos::parallel_for(nr, KOKKOS_LAMBDA(const int& r){
-      xr[r] += dt*ur[r];
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-      xj[j] = 0.5*(xr[j]+xr[j+1]);
-      Vj[j] = xr[j+1]-xr[j];
-      });
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	rhoj[j] = mj[j]/Vj[j];
-	pj[j] = p(rhoj[j], ej[j], gammaj[j]);
-	cj[j] = std::sqrt(gammaj[j]*pj[j]/rhoj[j]); // inv_mj*vj
-      });
-    
-    ++iteration;
-  }
-
-  std::cout << "* " << rang::style::underline << "Final time" << rang::style::reset
-	    << ":  " << rang::fgB::green << t << rang::fg::reset << " (" << iteration << " iterations)\n";
-}
-
-}
diff --git a/src/experimental/RawKokkosAcousticSolver.hpp b/src/experimental/RawKokkosAcousticSolver.hpp
deleted file mode 100644
index e9c36ff437a7ef0f0c28c72e93b0a367d8142185..0000000000000000000000000000000000000000
--- a/src/experimental/RawKokkosAcousticSolver.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef RAW_KOKKOS_ACOUSTIC_SOLVER_HPP
-#define RAW_KOKKOS_ACOUSTIC_SOLVER_HPP
-
-namespace RawKokkos
-{
-  void AcousticSolver(const long int& nj);
-}
-
-#endif // RAW_KOKKOS_ACOUSTIC_SOLVER_HPP
diff --git a/src/main.cpp b/src/main.cpp
index b1a3decd13b36a4b738c49c9815a0c4bfb327d5f..ba6f6c504ae02f7859d722de46295e192f92fffe 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -147,10 +147,10 @@ int main(int argc, char *argv[])
             bc_descriptor_list.push_back(std::shared_ptr<BoundaryConditionDescriptor>(sym_bc_descriptor));
           }
 
-          typedef Connectivity1D ConnectivityType;
-          typedef Mesh<ConnectivityType> MeshType;
-          typedef MeshData<MeshType> MeshDataType;
-          typedef FiniteVolumesEulerUnknowns<MeshDataType> UnknownsType;
+          using ConnectivityType = Connectivity1D;
+          using MeshType = Mesh<ConnectivityType>;
+          using MeshDataType = MeshData<MeshType>;
+          using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>;
 
           const MeshType& mesh = dynamic_cast<const MeshType&>(*gmsh_reader.mesh());
 
@@ -192,9 +192,9 @@ int main(int argc, char *argv[])
 
           AcousticSolver<MeshDataType> acoustic_solver(mesh_data, unknowns, bc_list);
 
-          typedef TinyVector<MeshType::dimension> Rd;
+          using Rd = TinyVector<MeshType::dimension>;
 
-          const Kokkos::View<const double*> Vj = mesh_data.Vj();
+          const CellValue<const double>& Vj = mesh_data.Vj();
 
           const double tmax=0.2;
           double t=0;
@@ -202,11 +202,11 @@ int main(int argc, char *argv[])
           int itermax=std::numeric_limits<int>::max();
           int iteration=0;
 
-          Kokkos::View<double*> rhoj = unknowns.rhoj();
-          Kokkos::View<double*> ej = unknowns.ej();
-          Kokkos::View<double*> pj = unknowns.pj();
-          Kokkos::View<double*> gammaj = unknowns.gammaj();
-          Kokkos::View<double*> cj = unknowns.cj();
+          CellValue<double>& rhoj = unknowns.rhoj();
+          CellValue<double>& ej = unknowns.ej();
+          CellValue<double>& pj = unknowns.pj();
+          CellValue<double>& gammaj = unknowns.gammaj();
+          CellValue<double>& cj = unknowns.cj();
 
           BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj);
 
@@ -233,10 +233,10 @@ int main(int argc, char *argv[])
           method_cost_map["AcousticSolverWithMesh"] = timer.seconds();
 
           { // gnuplot output for density
-            const Kokkos::View<const Rd*> xj   = mesh_data.xj();
-            const Kokkos::View<const double*> rhoj = unknowns.rhoj();
+            const CellValue<const Rd>& xj = mesh_data.xj();
+            const CellValue<const double>& rhoj = unknowns.rhoj();
             std::ofstream fout("rho");
-            for (size_t j=0; j<mesh.numberOfCells(); ++j) {
+            for (CellId j=0; j<mesh.numberOfCells(); ++j) {
               fout << xj[j][0] << ' ' << rhoj[j] << '\n';
             }
           }
@@ -256,10 +256,10 @@ int main(int argc, char *argv[])
             bc_descriptor_list.push_back(std::shared_ptr<BoundaryConditionDescriptor>(sym_bc_descriptor));
           }
 
-          typedef Connectivity2D ConnectivityType;
-          typedef Mesh<ConnectivityType> MeshType;
-          typedef MeshData<MeshType> MeshDataType;
-          typedef FiniteVolumesEulerUnknowns<MeshDataType> UnknownsType;
+          using ConnectivityType = Connectivity2D;
+          using MeshType = Mesh<ConnectivityType>;
+          using MeshDataType = MeshData<MeshType>;
+          using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>;
 
           const MeshType& mesh = dynamic_cast<const MeshType&>(*gmsh_reader.mesh());
 
@@ -301,7 +301,7 @@ int main(int argc, char *argv[])
 
           AcousticSolver<MeshDataType> acoustic_solver(mesh_data, unknowns, bc_list);
 
-          const Kokkos::View<const double*> Vj = mesh_data.Vj();
+          const CellValue<const double>& Vj = mesh_data.Vj();
 
           const double tmax=0.2;
           double t=0;
@@ -309,11 +309,11 @@ int main(int argc, char *argv[])
           int itermax=std::numeric_limits<int>::max();
           int iteration=0;
 
-          Kokkos::View<double*> rhoj = unknowns.rhoj();
-          Kokkos::View<double*> ej = unknowns.ej();
-          Kokkos::View<double*> pj = unknowns.pj();
-          Kokkos::View<double*> gammaj = unknowns.gammaj();
-          Kokkos::View<double*> cj = unknowns.cj();
+          CellValue<double>& rhoj = unknowns.rhoj();
+          CellValue<double>& ej = unknowns.ej();
+          CellValue<double>& pj = unknowns.pj();
+          CellValue<double>& gammaj = unknowns.gammaj();
+          CellValue<double>& cj = unknowns.cj();
 
           BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj);
 
@@ -352,10 +352,10 @@ int main(int argc, char *argv[])
             bc_descriptor_list.push_back(std::shared_ptr<BoundaryConditionDescriptor>(sym_bc_descriptor));
           }
 
-          typedef Connectivity3D ConnectivityType;
-          typedef Mesh<ConnectivityType> MeshType;
-          typedef MeshData<MeshType> MeshDataType;
-          typedef FiniteVolumesEulerUnknowns<MeshDataType> UnknownsType;
+          using ConnectivityType = Connectivity3D;
+          using MeshType = Mesh<ConnectivityType>;
+          using MeshDataType = MeshData<MeshType>;
+          using UnknownsType = FiniteVolumesEulerUnknowns<MeshDataType>;
 
           const MeshType& mesh = dynamic_cast<const MeshType&>(*gmsh_reader.mesh());
 
@@ -397,7 +397,7 @@ int main(int argc, char *argv[])
 
           AcousticSolver<MeshDataType> acoustic_solver(mesh_data, unknowns, bc_list);
 
-          const Kokkos::View<const double*> Vj = mesh_data.Vj();
+          const CellValue<const double>& Vj = mesh_data.Vj();
 
           const double tmax=0.2;
           double t=0;
@@ -405,11 +405,11 @@ int main(int argc, char *argv[])
           int itermax=std::numeric_limits<int>::max();
           int iteration=0;
 
-          Kokkos::View<double*> rhoj = unknowns.rhoj();
-          Kokkos::View<double*> ej = unknowns.ej();
-          Kokkos::View<double*> pj = unknowns.pj();
-          Kokkos::View<double*> gammaj = unknowns.gammaj();
-          Kokkos::View<double*> cj = unknowns.cj();
+          CellValue<double>& rhoj = unknowns.rhoj();
+          CellValue<double>& ej = unknowns.ej();
+          CellValue<double>& pj = unknowns.pj();
+          CellValue<double>& gammaj = unknowns.gammaj();
+          CellValue<double>& cj = unknowns.cj();
 
           BlockPerfectGas block_eos(rhoj, ej, pj, gammaj, cj);
 
diff --git a/src/mesh/Connectivity.cpp b/src/mesh/Connectivity.cpp
index eb5fb87b36947a5e4778f2e38161e6f35cb3f92d..f84f3835abe00acb25561ada3d071a29c5adc167 100644
--- a/src/mesh/Connectivity.cpp
+++ b/src/mesh/Connectivity.cpp
@@ -4,14 +4,14 @@
 template<>
 void Connectivity<3>::_computeCellFaceAndFaceNodeConnectivities()
 {
-  typedef std::tuple<unsigned int, unsigned short, bool> CellFaceInfo;
+  using CellFaceInfo = std::tuple<CellId, unsigned short, bool>;
 
   const auto& cell_to_node_matrix
-      = this->getMatrix(ItemType::cell, ItemType::node);
+      = this->_getMatrix(ItemType::cell, ItemType::node);
 
-  Kokkos::View<unsigned short*> cell_nb_faces("cell_nb_faces", this->numberOfCells());
+  CellValue<unsigned short> cell_nb_faces(*this);
   std::map<Face, std::vector<CellFaceInfo>> face_cells_map;
-  for (unsigned int j=0; j<this->numberOfCells(); ++j) {
+  for (CellId j=0; j<this->numberOfCells(); ++j) {
     const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
 
     switch (m_cell_type[j]) {
@@ -97,12 +97,12 @@ void Connectivity<3>::_computeCellFaceAndFaceNodeConnectivities()
 
   {
     auto& cell_to_face_matrix
-        = m_item_to_item_matrix[itemId(ItemType::cell)][itemId(ItemType::face)];
+        = m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::face)];
     std::vector<std::vector<unsigned int>> cell_to_face_vector(this->numberOfCells());
-    for (size_t j=0; j<cell_to_face_vector.size(); ++j) {
+    for (CellId j=0; j<cell_to_face_vector.size(); ++j) {
       cell_to_face_vector[j].resize(cell_nb_faces[j]);
     }
-    int l=0;
+    FaceId l=0;
     for (const auto& face_cells_vector : face_cells_map) {
       const auto& cells_vector = face_cells_vector.second;
       for (unsigned short lj=0; lj<cells_vector.size(); ++lj) {
@@ -129,7 +129,7 @@ void Connectivity<3>::_computeCellFaceAndFaceNodeConnectivities()
 
   {
     auto& face_to_node_matrix
-        = m_item_to_item_matrix[itemId(ItemType::face)][itemId(ItemType::node)];
+        = m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::node)];
 
     std::vector<std::vector<unsigned int>> face_to_node_vector(face_cells_map.size());
     int l=0;
@@ -157,16 +157,16 @@ template<>
 void Connectivity<2>::_computeCellFaceAndFaceNodeConnectivities()
 {
   const auto& cell_to_node_matrix
-      = this->getMatrix(ItemType::cell, ItemType::node);
+      = this->_getMatrix(ItemType::cell, ItemType::node);
 
   // In 2D faces are simply define
-  typedef std::pair<unsigned int, unsigned short> CellFaceId;
+  using CellFaceId = std::pair<CellId, unsigned short>;
   std::map<Face, std::vector<CellFaceId>> face_cells_map;
-  for (unsigned int j=0; j<this->numberOfCells(); ++j) {
+  for (CellId j=0; j<this->numberOfCells(); ++j) {
     const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
     for (unsigned short r=0; r<cell_nodes.length; ++r) {
-      unsigned int node0_id = cell_nodes(r);
-      unsigned int node1_id = cell_nodes((r+1)%cell_nodes.length);
+      NodeId node0_id = cell_nodes(r);
+      NodeId node1_id = cell_nodes((r+1)%cell_nodes.length);
       if (node1_id<node0_id) {
         std::swap(node0_id, node1_id);
       }
@@ -175,7 +175,7 @@ void Connectivity<2>::_computeCellFaceAndFaceNodeConnectivities()
   }
 
   {
-    int l=0;
+    FaceId l=0;
     for (const auto& face_cells_vector : face_cells_map) {
       const Face& face = face_cells_vector.first;
       m_face_number_map[face] = l;
@@ -192,7 +192,7 @@ void Connectivity<2>::_computeCellFaceAndFaceNodeConnectivities()
       ++l;
     }
     auto& face_to_node_matrix
-        = m_item_to_item_matrix[itemId(ItemType::face)][itemId(ItemType::node)];
+        = m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::node)];
     face_to_node_matrix = face_to_node_vector;
   }
 
@@ -207,7 +207,7 @@ void Connectivity<2>::_computeCellFaceAndFaceNodeConnectivities()
       ++l;
     }
     auto& face_to_cell_matrix
-        = m_item_to_item_matrix[itemId(ItemType::face)][itemId(ItemType::cell)];
+        = m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::cell)];
     face_to_cell_matrix = face_to_cell_vector;
   }
 }
@@ -221,21 +221,21 @@ Connectivity(const std::vector<std::vector<unsigned int>>& cell_by_node_vector,
   Assert(cell_by_node_vector.size() == cell_type_vector.size());
 
   auto& cell_to_node_matrix
-      = m_item_to_item_matrix[itemId(ItemType::cell)][itemId(ItemType::node)];
+      = m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::node)];
   cell_to_node_matrix = cell_by_node_vector;
 
   Assert(this->numberOfCells()>0);
 
   {
-    Kokkos::View<CellType*> cell_type("cell_type", this->numberOfCells());
-    Kokkos::parallel_for(this->numberOfCells(), KOKKOS_LAMBDA(const int& j){
+    CellValue<CellType> cell_type(*this);
+    Kokkos::parallel_for(this->numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
         cell_type[j] = cell_type_vector[j];
       });
     m_cell_type = cell_type;
   }
   {
-    Kokkos::View<double*> inv_cell_nb_nodes("inv_cell_nb_nodes", this->numberOfCells());
-    Kokkos::parallel_for(this->numberOfCells(), KOKKOS_LAMBDA(const int& j){
+    CellValue<double> inv_cell_nb_nodes(*this);
+    Kokkos::parallel_for(this->numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
         const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
         inv_cell_nb_nodes[j] = 1./cell_nodes.length;
       });
diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp
index 0994fc9c84e4105c3f9de66b55231f3fd61ff8fe..cfcb7f67909e2c7668bb11d842eb5437e57734c2 100644
--- a/src/mesh/Connectivity.hpp
+++ b/src/mesh/Connectivity.hpp
@@ -5,10 +5,13 @@
 #include <TinyVector.hpp>
 
 #include <Kokkos_Core.hpp>
+#include <ItemValue.hpp>
 
 #include <IConnectivity.hpp>
 
 #include <ConnectivityMatrix.hpp>
+#include <ItemToItemMatrix.hpp>
+
 #include <SubItemValuePerItem.hpp>
 #include <ConnectivityComputer.hpp>
 
@@ -126,7 +129,7 @@ class ConnectivityFace<3>
   };
 
   bool m_reversed;
-  std::vector<unsigned int> m_node_id_list;
+  std::vector<NodeId::base_type> m_node_id_list;
 
   friend std::ostream& operator<<(std::ostream& os, const ConnectivityFace& f)
   {
@@ -222,19 +225,20 @@ class ConnectivityFace<3>
   ~ConnectivityFace() = default;
 };
 
+
 template <size_t Dimension>
 class Connectivity final
     : public IConnectivity
 {
  private:
-  constexpr static auto& itemId = ItemId<Dimension>::itemId;
+  constexpr static auto& itemTId = ItemTypeId<Dimension>::itemTId;
 
  public:
   static constexpr size_t dimension = Dimension;
 
  private:
   ConnectivityMatrix m_item_to_item_matrix[Dimension+1][Dimension+1];
-  Kokkos::View<const CellType*> m_cell_type;
+  CellValue<const CellType> m_cell_type;
 
   FaceValuePerCell<const bool> m_cell_face_is_reversed;
 
@@ -259,11 +263,11 @@ class Connectivity final
   std::vector<RefFaceList> m_ref_face_list;
   std::vector<RefNodeList> m_ref_node_list;
 
-  Kokkos::View<double*> m_inv_cell_nb_nodes;
+  CellValue<const double> m_inv_cell_nb_nodes;
 
   using Face = ConnectivityFace<Dimension>;
 
-  std::unordered_map<Face, unsigned int, typename Face::Hash> m_face_number_map;
+  std::unordered_map<Face, FaceId, typename Face::Hash> m_face_number_map;
 
   void _computeCellFaceAndFaceNodeConnectivities();
 
@@ -281,6 +285,23 @@ class Connectivity final
     return sub_item_value_per_item;
   }
 
+  friend class ConnectivityComputer;
+
+  KOKKOS_INLINE_FUNCTION
+  const ConnectivityMatrix& _getMatrix(const ItemType& item_type_0,
+                                       const ItemType& item_type_1) const
+  {
+    const ConnectivityMatrix& connectivity_matrix
+        = m_item_to_item_matrix[itemTId(item_type_0)][itemTId(item_type_1)];
+    if (not connectivity_matrix.isBuilt()) {
+      const_cast<ConnectivityMatrix&>(connectivity_matrix)
+          = m_connectivity_computer
+          . computeConnectivityMatrix(*this, item_type_0, item_type_1);
+
+    }
+    return connectivity_matrix;
+  }
+
  public:
 
   KOKKOS_INLINE_FUNCTION
@@ -288,25 +309,92 @@ class Connectivity final
                                         const ItemType& item_type_1) const
   {
     const ConnectivityMatrix& connectivity_matrix
-        = m_item_to_item_matrix[itemId(item_type_0)][itemId(item_type_1)];
+        = m_item_to_item_matrix[itemTId(item_type_0)][itemTId(item_type_1)];
     return connectivity_matrix.isBuilt();
   }
+  template <ItemType source_item_type,
+            ItemType target_item_type>
+  KOKKOS_INLINE_FUNCTION
+  const auto getItemToItemMatrix() const
+  {
+    return ItemToItemMatrix<source_item_type,
+                            target_item_type>(_getMatrix(source_item_type,
+                                                         target_item_type));
+  }
 
   KOKKOS_INLINE_FUNCTION
-  const ConnectivityMatrix& getMatrix(const ItemType& item_type_0,
-                                      const ItemType& item_type_1) const
+  const auto cellToFaceMatrix() const
   {
-    const ConnectivityMatrix& connectivity_matrix
-        = m_item_to_item_matrix[itemId(item_type_0)][itemId(item_type_1)];
-    if (not connectivity_matrix.isBuilt()) {
-      const_cast<ConnectivityMatrix&>(connectivity_matrix)
-          = m_connectivity_computer
-          . computeConnectivityMatrix(*this, item_type_0, item_type_1);
+    return this->template getItemToItemMatrix<ItemType::cell, ItemType::face>();
+  }
 
-    }
-    return connectivity_matrix;
+  KOKKOS_INLINE_FUNCTION
+  const auto cellToEdgeMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::cell, ItemType::edge>();
   }
 
+  KOKKOS_INLINE_FUNCTION
+  const auto cellToNodeMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::cell, ItemType::node>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto faceToCellMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::face, ItemType::cell>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto faceToEdgeMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::face, ItemType::edge>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto faceToNodeMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::face, ItemType::node>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto edgeToCellMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::edge, ItemType::cell>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto edgeToFaceMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::edge, ItemType::face>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto edgeToNodeMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::edge, ItemType::node>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto nodeToCellMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::node, ItemType::cell>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto nodeToFaceMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::node, ItemType::face>();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  const auto nodeToEdgeMatrix() const
+  {
+    return this->template getItemToItemMatrix<ItemType::node, ItemType::edge>();
+  }
+
+
   KOKKOS_INLINE_FUNCTION
   const auto& cellFaceIsReversed() const
   {
@@ -439,30 +527,38 @@ class Connectivity final
   }
 
   KOKKOS_INLINE_FUNCTION
-  size_t numberOfNodes() const
+  size_t numberOfNodes() const final
   {
     const auto& node_to_cell_matrix
-        = this->getMatrix(ItemType::node,ItemType::cell);
+        = this->_getMatrix(ItemType::node,ItemType::cell);
     return node_to_cell_matrix.numRows();
   }
 
   KOKKOS_INLINE_FUNCTION
-  size_t numberOfFaces() const
+  size_t numberOfEdges() const final
+  {
+    const auto& edge_to_node_matrix
+        = this->_getMatrix(ItemType::edge,ItemType::node);
+    return edge_to_node_matrix.numRows();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  size_t numberOfFaces() const final
   {
     const auto& face_to_node_matrix
-        = this->getMatrix(ItemType::face,ItemType::cell);
+        = this->_getMatrix(ItemType::face,ItemType::cell);
     return face_to_node_matrix.numRows();
   }
 
   KOKKOS_INLINE_FUNCTION
-  size_t numberOfCells() const
+  size_t numberOfCells() const final
   {
     const auto& cell_to_node_matrix
-        = this->getMatrix(ItemType::cell,ItemType::node);
+        = this->_getMatrix(ItemType::cell,ItemType::node);
     return cell_to_node_matrix.numRows();
   }
 
-  const Kokkos::View<const double*> invCellNbNodes() const
+  const CellValue<const double>& invCellNbNodes() const
   {
 #warning add calculation on demand when variables will be defined
     return m_inv_cell_nb_nodes;
diff --git a/src/mesh/ConnectivityComputer.cpp b/src/mesh/ConnectivityComputer.cpp
index 0c87ccb6d64f840cd450eb5ded67c6a337a5cf25..aa6f5c56ae612133afc3040d84fd6fe3c807b507 100644
--- a/src/mesh/ConnectivityComputer.cpp
+++ b/src/mesh/ConnectivityComputer.cpp
@@ -14,7 +14,7 @@ computeConnectivityMatrix(const ConnectivityType& connectivity,
   ConnectivityMatrix item_to_child_item_matrix;
   if (connectivity.isConnectivityMatrixBuilt(child_item_type, item_type)) {
     const ConnectivityMatrix& child_to_item_matrix
-        = connectivity.getMatrix(child_item_type, item_type);
+        = connectivity._getMatrix(child_item_type, item_type);
 
     std::cout << "computing connectivity "
               << itemName(item_type) << " -> " << itemName(child_item_type) << '\n';
@@ -83,12 +83,12 @@ SubItemValuePerItem<const unsigned short, child_item_type, item_type>
 ConnectivityComputer::computeLocalItemNumberInChildItem(const ConnectivityType& connectivity) const
 {
   const ConnectivityMatrix& child_item_to_items_matrix
-      = connectivity.getMatrix(child_item_type, item_type);
+      = connectivity._getMatrix(child_item_type, item_type);
   const ConnectivityMatrix& item_to_child_items_matrix
-      = connectivity.getMatrix(item_type, child_item_type);
+      = connectivity._getMatrix(item_type, child_item_type);
 
   SubItemValuePerItem<unsigned short, child_item_type, item_type> item_number_in_child_item(connectivity);
-  for (unsigned int r=0; r<item_to_child_items_matrix.numRows(); ++r) {
+  for (ItemIdT<item_type> r=0; r<item_to_child_items_matrix.numRows(); ++r) {
     const auto& item_to_child_items = item_to_child_items_matrix.rowConst(r);
     for (unsigned short J=0; J<item_to_child_items.length; ++J) {
       const unsigned int j = item_to_child_items(J);
diff --git a/src/mesh/ConnectivityMatrix.hpp b/src/mesh/ConnectivityMatrix.hpp
index 356ee6da56d474836180cc867318c2d4f912549a..4387070d0bc9ffc91e88f16c160b87a65e176925 100644
--- a/src/mesh/ConnectivityMatrix.hpp
+++ b/src/mesh/ConnectivityMatrix.hpp
@@ -7,13 +7,13 @@
 class ConnectivityMatrix
 {
  private:
-  typedef Kokkos::StaticCrsGraph<unsigned int, Kokkos::HostSpace> HostMatrix;
+  using HostMatrix = Kokkos::StaticCrsGraph<unsigned int, Kokkos::HostSpace>;
   HostMatrix m_host_matrix;
 
   bool m_is_built{false};
 
  public:
-  typedef HostMatrix::row_map_type HostRowType;
+  using HostRowType = HostMatrix::row_map_type;
 
   const bool& isBuilt() const
   {
diff --git a/src/mesh/GmshReader.cpp b/src/mesh/GmshReader.cpp
index f16ab2fa02e06aad3715eeb7c84028476c7565ae..ea003eb9b6c41d7f049c648ab62b01a01b0add26 100644
--- a/src/mesh/GmshReader.cpp
+++ b/src/mesh/GmshReader.cpp
@@ -310,7 +310,7 @@ void GmshReader::__readVertices()
   }
 
   __verticesNumbers.resize(numberOfVerices);
-  __vertices = Kokkos::View<R3*>("vertices",numberOfVerices);
+  __vertices = Array<R3>(numberOfVerices);
 
   if (not __binary) {
     for (int i=0; i<numberOfVerices; ++i) {
@@ -552,38 +552,32 @@ GmshReader::__proceedData()
         switch (i) {
           // Supported entities
           case 0: { // edges
-            __edges = Kokkos::View<Edge*>("edges",
-                                          elementNumber[i]);
+            __edges = Array<Edge>(elementNumber[i]);
             __edges_ref.resize(elementNumber[i]);
             break;
           }
           case 1: { // triangles
-            __triangles = Kokkos::View<Triangle*>("triangles",
-                                                  elementNumber[i]);
+            __triangles = Array<Triangle>(elementNumber[i]);
             __triangles_ref.resize(elementNumber[i]);
             break;
           }
           case  2: { // quadrangles
-            __quadrangles = Kokkos::View<Quadrangle*>("quadrangles",
-                                                      elementNumber[i]);
+            __quadrangles = Array<Quadrangle>(elementNumber[i]);
             __quadrangles_ref.resize(elementNumber[i]);
             break;
           }
           case 3: { // tetrahedra
-            __tetrahedra = Kokkos::View<Tetrahedron*>("tetrahedra",
-                                                      elementNumber[i]);
+            __tetrahedra = Array<Tetrahedron>(elementNumber[i]);
             __tetrahedra_ref.resize(elementNumber[i]);
             break;
           }
           case  4: {// hexahedra
-            __hexahedra = Kokkos::View<Hexahedron*>("hexahedra",
-                                                    elementNumber[i]);
+            __hexahedra = Array<Hexahedron>(elementNumber[i]);
             __hexahedra_ref.resize(elementNumber[i]);
           }
             // Ignored entities
           case 14: {// point
-            __points = Kokkos::View<Point*>("points",
-                                            elementNumber[i]);
+            __points = Array<Point>(elementNumber[i]);
             __points_ref.resize(elementNumber[i]);
             break;
           }
@@ -798,7 +792,7 @@ GmshReader::__proceedData()
     std::vector<CellType> cell_type_vector(nb_cells);
 
     std::vector<std::vector<unsigned int>> cell_by_node_vector(nb_cells);
-    const size_t nb_tetrahedra = __tetrahedra.extent(0);
+    const size_t nb_tetrahedra = __tetrahedra.size();
     for (size_t j=0; j<nb_tetrahedra; ++j) {
       cell_by_node_vector[j].resize(4);
       for (int r=0; r<4; ++r) {
@@ -806,7 +800,7 @@ GmshReader::__proceedData()
       }
       cell_type_vector[j] = CellType::Tetrahedron;
     }
-    const size_t nb_hexahedra = __hexahedra.extent(0);
+    const size_t nb_hexahedra = __hexahedra.size();
     for (size_t j=0; j<nb_hexahedra; ++j) {
       const size_t jh = nb_tetrahedra+j;
       cell_by_node_vector[jh].resize(8);
@@ -821,13 +815,13 @@ GmshReader::__proceedData()
     Connectivity3D& connectivity = *p_connectivity;
 
     std::map<unsigned int, std::vector<unsigned int>> ref_faces_map;
-    for (unsigned int f=0; f<__triangles.extent(0); ++f) {
+    for (unsigned int f=0; f<__triangles.size(); ++f) {
       const unsigned int face_number
           = connectivity.getFaceNumber({__triangles[f][0], __triangles[f][1], __triangles[f][2]});
       const unsigned int& ref = __triangles_ref[f];
       ref_faces_map[ref].push_back(face_number);
     }
-    for (unsigned int f=0; f<__quadrangles.extent(0); ++f) {
+    for (unsigned int f=0; f<__quadrangles.size(); ++f) {
       const unsigned int face_number
           = connectivity.getFaceNumber({__quadrangles[f][0], __quadrangles[f][1],
                                         __quadrangles[f][2], __quadrangles[f][3]});
@@ -835,7 +829,7 @@ GmshReader::__proceedData()
       ref_faces_map[ref].push_back(face_number);
     }
     for (const auto& ref_face_list : ref_faces_map) {
-      Kokkos::View<unsigned int*> face_list("face_list", ref_face_list.second.size());
+      Array<FaceId> face_list(ref_face_list.second.size());
       for (size_t j=0; j<ref_face_list.second.size(); ++j) {
         face_list[j]=ref_face_list.second[j];
       }
@@ -843,11 +837,11 @@ GmshReader::__proceedData()
       connectivity.addRefFaceList(RefFaceList(physical_ref_id.refId(), face_list));
     }
 
-    typedef Mesh<Connectivity3D> MeshType;
-    typedef TinyVector<3, double> Rd;
+    using MeshType = Mesh<Connectivity3D>;
+    using Rd = TinyVector<3, double>;
 
-    Kokkos::View<Rd*> xr("xr", __vertices.extent(0));
-    for (size_t i=0; i<__vertices.extent(0); ++i) {
+    NodeValue<Rd> xr(connectivity);
+    for (NodeId i=0; i<__vertices.size(); ++i) {
       xr[i][0] = __vertices[i][0];
       xr[i][1] = __vertices[i][1];
       xr[i][2] = __vertices[i][2];
@@ -860,7 +854,7 @@ GmshReader::__proceedData()
     std::vector<CellType> cell_type_vector(nb_cells);
 
     std::vector<std::vector<unsigned int>> cell_by_node_vector(nb_cells);
-    const size_t nb_triangles = __triangles.extent(0);
+    const size_t nb_triangles = __triangles.size();
     for (size_t j=0; j<nb_triangles; ++j) {
       cell_by_node_vector[j].resize(3);
       for (int r=0; r<3; ++r) {
@@ -869,7 +863,7 @@ GmshReader::__proceedData()
       cell_type_vector[j] = CellType::Triangle;
     }
 
-    const size_t nb_quadrangles = __quadrangles.extent(0);
+    const size_t nb_quadrangles = __quadrangles.size();
     for (size_t j=0; j<nb_quadrangles; ++j) {
       const size_t jq = j+nb_triangles;
       cell_by_node_vector[jq].resize(4);
@@ -884,14 +878,14 @@ GmshReader::__proceedData()
     Connectivity2D& connectivity = *p_connectivity;
 
     std::map<unsigned int, std::vector<unsigned int>> ref_faces_map;
-    for (unsigned int e=0; e<__edges.extent(0); ++e) {
+    for (unsigned int e=0; e<__edges.size(); ++e) {
       const unsigned int edge_number = connectivity.getFaceNumber({__edges[e][0], __edges[e][1]});
       const unsigned int& ref = __edges_ref[e];
       ref_faces_map[ref].push_back(edge_number);
     }
 
     for (const auto& ref_face_list : ref_faces_map) {
-      Kokkos::View<unsigned int*> face_list("face_list", ref_face_list.second.size());
+      Array<FaceId> face_list(ref_face_list.second.size());
       for (size_t j=0; j<ref_face_list.second.size(); ++j) {
         face_list[j]=ref_face_list.second[j];
       }
@@ -900,14 +894,14 @@ GmshReader::__proceedData()
     }
 
     std::map<unsigned int, std::vector<unsigned int>> ref_points_map;
-    for (unsigned int r=0; r<__points.extent(0); ++r) {
+    for (unsigned int r=0; r<__points.size(); ++r) {
       const unsigned int point_number = __points[r];
       const unsigned int& ref = __points_ref[r];
       ref_points_map[ref].push_back(point_number);
     }
 
     for (const auto& ref_point_list : ref_points_map) {
-      Kokkos::View<unsigned int*> point_list("point_list", ref_point_list.second.size());
+      Array<NodeId> point_list(ref_point_list.second.size());
       for (size_t j=0; j<ref_point_list.second.size(); ++j) {
         point_list[j]=ref_point_list.second[j];
       }
@@ -915,11 +909,11 @@ GmshReader::__proceedData()
       connectivity.addRefNodeList(RefNodeList(physical_ref_id.refId(), point_list));
     }
 
-    typedef Mesh<Connectivity2D> MeshType;
-    typedef TinyVector<2, double> Rd;
+    using MeshType = Mesh<Connectivity2D>;
+    using Rd = TinyVector<2, double>;
 
-    Kokkos::View<Rd*> xr("xr", __vertices.extent(0));
-    for (size_t i=0; i<__vertices.extent(0); ++i) {
+    NodeValue<Rd> xr(connectivity);
+    for (NodeId i=0; i<__vertices.size(); ++i) {
       xr[i][0] = __vertices[i][0];
       xr[i][1] = __vertices[i][1];
     }
@@ -944,14 +938,14 @@ GmshReader::__proceedData()
     Connectivity1D& connectivity = *p_connectivity;
 
     std::map<unsigned int, std::vector<unsigned int>> ref_points_map;
-    for (unsigned int r=0; r<__points.extent(0); ++r) {
+    for (unsigned int r=0; r<__points.size(); ++r) {
       const unsigned int point_number = __points[r];
       const unsigned int& ref = __points_ref[r];
       ref_points_map[ref].push_back(point_number);
     }
 
     for (const auto& ref_point_list : ref_points_map) {
-      Kokkos::View<unsigned int*> point_list("point_list", ref_point_list.second.size());
+      Array<NodeId> point_list(ref_point_list.second.size());
       for (size_t j=0; j<ref_point_list.second.size(); ++j) {
         point_list[j]=ref_point_list.second[j];
       }
@@ -959,11 +953,11 @@ GmshReader::__proceedData()
       connectivity.addRefNodeList(RefNodeList(physical_ref_id.refId(), point_list));
     }
 
-    typedef Mesh<Connectivity1D> MeshType;
-    typedef TinyVector<1, double> Rd;
+    using MeshType = Mesh<Connectivity1D>;
+    using Rd = TinyVector<1, double>;
 
-    Kokkos::View<Rd*> xr("xr", __vertices.extent(0));
-    for (size_t i=0; i<__vertices.extent(0); ++i) {
+    NodeValue<Rd> xr(connectivity);
+    for (NodeId i=0; i<__vertices.size(); ++i) {
       xr[i][0] = __vertices[i][0];
     }
 
diff --git a/src/mesh/GmshReader.hpp b/src/mesh/GmshReader.hpp
index 8825a67df3d6cf1593ff54bb6af8b7a96b079b5b..ba9ffe2502b4df46f59308f411747c7c2deaaac0 100644
--- a/src/mesh/GmshReader.hpp
+++ b/src/mesh/GmshReader.hpp
@@ -1,7 +1,7 @@
 #ifndef GMSH_READER_HPP
 #define GMSH_READER_HPP
 
-#include <Kokkos_Core.hpp>
+#include <Array.hpp>
 #include <TinyVector.hpp>
 
 #include <Mesh.hpp>
@@ -17,7 +17,7 @@
 class GmshReader
 {
 public:
-  typedef TinyVector<3, double> R3;
+  using R3 = TinyVector<3, double>;
 
   class PhysicalRefId
   {
@@ -78,25 +78,30 @@ private:
    */
   std::vector<int> __verticesNumbers;
 
-  Kokkos::View<R3*> __vertices;
+  Array<R3> __vertices;
 
-  typedef unsigned int Point;
-  Kokkos::View<Point*> __points;
+  using Point = unsigned int;
+  Array<Point> __points;
   std::vector<int> __points_ref;
-  typedef TinyVector<2,unsigned int> Edge;
-  Kokkos::View<Edge*> __edges;
+
+  using Edge = TinyVector<2,unsigned int>;
+  Array<Edge> __edges;
   std::vector<int> __edges_ref;
-  typedef TinyVector<3,unsigned int> Triangle;
-  Kokkos::View<Triangle*> __triangles;
+
+  using Triangle = TinyVector<3,unsigned int>;
+  Array<Triangle> __triangles;
   std::vector<int> __triangles_ref;
-  typedef TinyVector<4,unsigned int> Quadrangle;
-  Kokkos::View<Quadrangle*> __quadrangles;
+
+  using Quadrangle = TinyVector<4,unsigned int>;
+  Array<Quadrangle> __quadrangles;
   std::vector<int> __quadrangles_ref;
-  typedef TinyVector<4,unsigned int> Tetrahedron;
-  Kokkos::View<Tetrahedron*> __tetrahedra;
+
+  using Tetrahedron = TinyVector<4,unsigned int>;
+  Array<Tetrahedron> __tetrahedra;
   std::vector<int> __tetrahedra_ref;
-  typedef TinyVector<8,unsigned int> Hexahedron;
-  Kokkos::View<Hexahedron*> __hexahedra;
+
+  using Hexahedron = TinyVector<8,unsigned int>;
+  Array<Hexahedron> __hexahedra;
   std::vector<int> __hexahedra_ref;
 
   /**
@@ -194,7 +199,7 @@ private:
    * List of known keywords
    *
    */
-  typedef std::map<std::string, int> KeywordList;
+  using KeywordList = std::map<std::string, int>;
 
   KeywordList __keywordList;	/**< The keyword list */
 
@@ -202,7 +207,7 @@ private:
    * Type for keyword
    *
    */
-  typedef std::pair<std::string, int> Keyword;
+  using Keyword = std::pair<std::string, int>;
 
   /**
    * Skips next comments if exists
diff --git a/src/mesh/IConnectivity.hpp b/src/mesh/IConnectivity.hpp
index 49432fdea276d770c993960a2ffb48da2f7407b0..e27c2ef08bf13e7e9946c095da1cb628027e3a44 100644
--- a/src/mesh/IConnectivity.hpp
+++ b/src/mesh/IConnectivity.hpp
@@ -4,15 +4,60 @@
 #include <ItemType.hpp>
 #include <ConnectivityMatrix.hpp>
 
-struct IConnectivity
+class IConnectivity
 {
+ protected:
+  template <typename DataType,
+            ItemType sub_item_type,
+            ItemType item_type,
+            typename Allowed>
+  friend
+  class SubItemValuePerItem;
+
   virtual const ConnectivityMatrix&
-  getMatrix(const ItemType& item_type_0,
-            const ItemType& item_type_1) const = 0;
+  _getMatrix(const ItemType& item_type_0,
+             const ItemType& item_type_1) const = 0;
+
+ public:
+  virtual size_t numberOfNodes() const = 0;
+  virtual size_t numberOfEdges() const = 0;
+  virtual size_t numberOfFaces() const = 0;
+  virtual size_t numberOfCells() const = 0;
+
+  template <ItemType item_type>
+  size_t numberOf() const = delete;
 
   IConnectivity() = default;
   IConnectivity(const IConnectivity&) = delete;
   ~IConnectivity() = default;
 };
 
+template <>
+KOKKOS_INLINE_FUNCTION
+size_t IConnectivity::numberOf<ItemType::node>() const
+{
+  return this->numberOfNodes();
+}
+
+template <>
+KOKKOS_INLINE_FUNCTION
+size_t IConnectivity::numberOf<ItemType::edge>() const
+{
+  return this->numberOfEdges();
+}
+
+template <>
+KOKKOS_INLINE_FUNCTION
+size_t IConnectivity::numberOf<ItemType::face>() const
+{
+  return this->numberOfFaces();
+}
+
+template <>
+KOKKOS_INLINE_FUNCTION
+size_t IConnectivity::numberOf<ItemType::cell>() const
+{
+  return this->numberOfCells();
+}
+
 #endif // ICONNECTIVITY_HPP
diff --git a/src/mesh/ItemId.hpp b/src/mesh/ItemId.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..11b87f7082bddbbbef76826bdc32b6272bc87d27
--- /dev/null
+++ b/src/mesh/ItemId.hpp
@@ -0,0 +1,81 @@
+#ifndef ITEM_ID_HPP
+#define ITEM_ID_HPP
+
+#include <ItemType.hpp>
+
+template <ItemType item_type>
+class ItemIdT
+{
+ public:
+  using base_type = unsigned int;
+
+ private:
+  base_type m_id;
+
+ public:
+  operator const base_type&() const
+  {
+    return m_id;
+  }
+
+  ItemIdT operator++(int)
+  {
+    ItemIdT item_id(m_id);
+    ++m_id;
+    return std::move(item_id);
+  }
+
+  ItemIdT& operator++()
+  {
+    ++m_id;
+    return *this;
+  }
+
+  ItemIdT& operator=(const base_type& id)
+  {
+    m_id = id;
+    return *this;
+  }
+
+  ItemIdT& operator=(const ItemIdT&) = default;
+  ItemIdT& operator=(ItemIdT&&) = default;
+
+  ItemIdT(const base_type& id) : m_id{id}{}
+
+  ItemIdT(const ItemIdT&) = default;
+
+  ItemIdT(ItemIdT&&) = default;
+  ItemIdT() = default;
+  ~ItemIdT() = default;
+
+  // forbidden rules
+  template <ItemType other_item_type>
+  ItemIdT(const ItemIdT<other_item_type>&)
+  {
+    static_assert(other_item_type == item_type,
+                  "wrong type of item");
+  }
+
+  template <ItemType other_item_type>
+  ItemIdT& operator=(const ItemIdT<other_item_type>&)
+  {
+    static_assert(other_item_type == item_type,
+                  "wrong type of item");
+  }
+
+
+  template <ItemType other_item_type>
+  ItemIdT& operator=(ItemIdT<other_item_type>&&)
+  {
+    static_assert(other_item_type == item_type,
+                  "wrong type of item");
+  }
+
+};
+
+using NodeId = ItemIdT<ItemType::node>;
+using EdgeId = ItemIdT<ItemType::edge>;
+using FaceId = ItemIdT<ItemType::face>;
+using CellId = ItemIdT<ItemType::cell>;
+
+#endif // ITEM_ID_HPP
diff --git a/src/mesh/ItemToItemMatrix.hpp b/src/mesh/ItemToItemMatrix.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..510c421fc9c1a67d0565d4b5e5e3e08c91c4ccd9
--- /dev/null
+++ b/src/mesh/ItemToItemMatrix.hpp
@@ -0,0 +1,105 @@
+#ifndef ITEM_TO_ITEM_MATRIX_HPP
+#define ITEM_TO_ITEM_MATRIX_HPP
+
+#include <ItemType.hpp>
+#include <ItemId.hpp>
+
+#include <Kokkos_Core.hpp>
+#include <ConnectivityMatrix.hpp>
+
+template <ItemType SourceItemType,
+          ItemType TargetItemType>
+class ItemToItemMatrix
+{
+ public:
+  using SourceItemId = ItemIdT<SourceItemType>;
+  using TargetItemId = ItemIdT<TargetItemType>;
+
+  template <typename RowType>
+  class SubItemList
+  {
+   private:
+    const RowType m_row;
+
+   public:
+
+    KOKKOS_INLINE_FUNCTION
+    size_t size() const
+    {
+      return m_row.length;
+    }
+
+    KOKKOS_INLINE_FUNCTION
+    TargetItemId operator[](const size_t& j) const
+    {
+      return m_row(j);
+    }
+
+    KOKKOS_INLINE_FUNCTION
+    SubItemList(const RowType& row)
+        : m_row{row}
+    {
+      ;
+    }
+
+    KOKKOS_INLINE_FUNCTION
+    SubItemList& operator=(const SubItemList&) = default;
+
+    KOKKOS_INLINE_FUNCTION
+    SubItemList& operator=(SubItemList&&) = default;
+
+    KOKKOS_INLINE_FUNCTION
+    SubItemList(const SubItemList&) = default;
+
+    KOKKOS_INLINE_FUNCTION
+    SubItemList(SubItemList&&) = default;
+
+    KOKKOS_INLINE_FUNCTION
+    ~SubItemList() = default;
+  };
+
+ private:
+  const ConnectivityMatrix& m_connectivity_matrix;
+
+ public:
+  KOKKOS_INLINE_FUNCTION
+  const auto operator[](const SourceItemId& source_id) const
+  {
+    using RowType = decltype(m_connectivity_matrix.rowConst(source_id));
+    return SubItemList<RowType>(m_connectivity_matrix.rowConst(source_id));
+  }
+
+  template <typename IndexType>
+  KOKKOS_INLINE_FUNCTION
+  const auto operator[](const IndexType& source_id) const
+  {
+    static_assert(std::is_same<IndexType, SourceItemId>(),
+                  "ItemToItemMatrix must be indexed using correct ItemId");
+    using RowType = decltype(m_connectivity_matrix.rowConst(source_id));
+    return SubItemList<RowType>(m_connectivity_matrix.rowConst(source_id));
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  ItemToItemMatrix(const ConnectivityMatrix& connectivity_matrix)
+      : m_connectivity_matrix{connectivity_matrix}
+  {
+    ;
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  ItemToItemMatrix& operator=(const ItemToItemMatrix&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  ItemToItemMatrix& operator=(ItemToItemMatrix&&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  ItemToItemMatrix(ItemToItemMatrix&&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  ItemToItemMatrix(const ItemToItemMatrix&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  ~ItemToItemMatrix() = default;
+};
+
+#endif // ITEM_TO_ITEM_MATRIX_HPP
diff --git a/src/mesh/ItemType.hpp b/src/mesh/ItemType.hpp
index d37c02fae15120b872c008f939c5d4907debb085..965f888b1b7315f28f5132b0457b86ca1e85b210 100644
--- a/src/mesh/ItemType.hpp
+++ b/src/mesh/ItemType.hpp
@@ -39,12 +39,12 @@ std::string_view itemName(const ItemType& item_type)
 }
 
 template <size_t Dimension>
-struct ItemId {};
+struct ItemTypeId {};
 
 template <>
-struct ItemId<1>
+struct ItemTypeId<1>
 {
-  inline static constexpr size_t itemId(const ItemType& item_type) {
+  inline static constexpr size_t itemTId(const ItemType& item_type) {
     size_t i = std::numeric_limits<size_t>::max();
     switch(item_type) {
       case ItemType::cell: {
@@ -64,9 +64,9 @@ struct ItemId<1>
 };
 
 template <>
-struct ItemId<2>
+struct ItemTypeId<2>
 {
-  inline static constexpr size_t itemId(const ItemType& item_type) {
+  inline static constexpr size_t itemTId(const ItemType& item_type) {
     size_t i = std::numeric_limits<size_t>::max();
     switch(item_type) {
       case ItemType::cell: {
@@ -89,9 +89,9 @@ struct ItemId<2>
 };
 
 template <>
-struct ItemId<3>
+struct ItemTypeId<3>
 {
-  inline static constexpr size_t itemId(const ItemType& item_type) {
+  inline static constexpr size_t itemTId(const ItemType& item_type) {
     size_t i = std::numeric_limits<size_t>::max();
     switch(item_type) {
       case ItemType::cell: {
diff --git a/src/mesh/ItemValue.hpp b/src/mesh/ItemValue.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..77eb1cb37d9998fb1af6e4a27d05ff7fcdb60077
--- /dev/null
+++ b/src/mesh/ItemValue.hpp
@@ -0,0 +1,122 @@
+#ifndef ITEM_VALUE_HPP
+#define ITEM_VALUE_HPP
+
+#include <PastisAssert.hpp>
+
+#include <Array.hpp>
+
+#include <ItemType.hpp>
+#include <ItemId.hpp>
+
+#include <IConnectivity.hpp>
+
+template <typename DataType,
+          ItemType item_type>
+class ItemValue
+{
+ public:
+  static const ItemType item_t{item_type};
+  using data_type = DataType;
+
+  using ItemId = ItemIdT<item_type>;
+  using index_type = ItemId;
+
+ private:
+  bool m_is_built{false};
+
+  Array<DataType> m_values;
+
+  // Allows const version to access our data
+  friend ItemValue<std::add_const_t<DataType>,
+                   item_type>;
+
+ public:
+  KOKKOS_FORCEINLINE_FUNCTION
+  const bool& isBuilt() const
+  {
+    return m_is_built;
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  size_t size() const
+  {
+    Assert(m_is_built);
+    return m_values.size();
+  }
+
+  // Following Kokkos logic, these classes are view and const view does allow
+  // changes in data
+  KOKKOS_FORCEINLINE_FUNCTION
+  DataType& operator[](const ItemId& i) const
+  {
+    Assert(m_is_built);
+    return m_values[i];
+  }
+
+  template <typename IndexType>
+  DataType& operator[](const IndexType& i) const
+  {
+    static_assert(std::is_same<IndexType,ItemId>(),
+                  "ItemValue must be indexed by ItemId");
+    return m_values[i];
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  size_t numberOfItems() const
+  {
+    Assert(m_is_built);
+    return m_values.size();
+  }
+
+  template <typename DataType2>
+  KOKKOS_INLINE_FUNCTION
+  ItemValue&
+  operator=(const ItemValue<DataType2, item_type>& value_per_item)
+  {
+    // ensures that DataType is the same as source DataType2
+    static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(),
+                  "Cannot assign ItemValue of different type");
+    // ensures that const is not lost through copy
+    static_assert(((std::is_const<DataType2>() and std::is_const<DataType>())
+                   or not std::is_const<DataType2>()),
+                  "Cannot assign  ItemValue of const to ItemValue of non-const");
+
+    m_values = value_per_item.m_values;
+    m_is_built = value_per_item.m_is_built;
+
+    return *this;
+  }
+
+  template <typename DataType2>
+  KOKKOS_INLINE_FUNCTION
+  ItemValue(const ItemValue<DataType2, item_type>& value_per_item)
+  {
+    this->operator=(value_per_item);
+  }
+
+  ItemValue() = default;
+
+  ItemValue(const IConnectivity& connectivity)
+      : m_is_built{true},
+        m_values(connectivity.numberOf<item_type>())
+  {
+    static_assert(not std::is_const<DataType>(),
+                  "Cannot allocate ItemValue of const data: only view is supported"); ;
+  }
+
+  ~ItemValue() = default;
+};
+
+template <typename DataType>
+using NodeValue = ItemValue<DataType, ItemType::node>;
+
+template <typename DataType>
+using EdgeValue = ItemValue<DataType, ItemType::edge>;
+
+template <typename DataType>
+using FaceValue = ItemValue<DataType, ItemType::face>;
+
+template <typename DataType>
+using CellValue = ItemValue<DataType, ItemType::cell>;
+
+#endif // ITEM_VALUE_HPP
diff --git a/src/mesh/Mesh.hpp b/src/mesh/Mesh.hpp
index 3aee2c287d5cdd06c4a754115caf930973c4f2cb..0188d507cb2d463b899e3e318b5a75a002b152e4 100644
--- a/src/mesh/Mesh.hpp
+++ b/src/mesh/Mesh.hpp
@@ -1,7 +1,7 @@
 #ifndef MESH_HPP
 #define MESH_HPP
 
-#include <Kokkos_Core.hpp>
+#include <ItemValue.hpp>
 #include <TinyVector.hpp>
 
 #include <memory>
@@ -16,21 +16,24 @@ template <typename ConnectivityType>
 class Mesh final : public IMesh
 {
 public:
-  typedef ConnectivityType Connectivity;
+  using Connectivity = ConnectivityType;
+
   static constexpr size_t dimension = ConnectivityType::dimension;
-  typedef TinyVector<dimension> Rd;
+  using Rd = TinyVector<dimension>;
 
 private:
   const std::shared_ptr<Connectivity> m_connectivity;
-  Kokkos::View<Rd*> m_xr;
+  NodeValue<const Rd> m_xr;
+  NodeValue<Rd> m_mutable_xr;
 
 public:
-
+  KOKKOS_INLINE_FUNCTION
   const size_t meshDimension() const
   {
     return dimension;
   }
 
+  KOKKOS_INLINE_FUNCTION
   const Connectivity& connectivity() const
   {
     return *m_connectivity;
@@ -54,28 +57,25 @@ public:
     return m_connectivity->numberOfCells();
   }
 
-  Kokkos::View<Rd*> xr() const
+  KOKKOS_INLINE_FUNCTION
+  const NodeValue<const Rd>& xr() const
   {
     return m_xr;
   }
 
+  [[deprecated("should rework this class: quite ugly")]]
   KOKKOS_INLINE_FUNCTION
-  Mesh(const std::shared_ptr<Connectivity>& connectivity)
-    : m_connectivity(connectivity),
-      m_xr("xr", connectivity->numberOfNodes())
+  NodeValue<Rd> mutableXr() const
   {
-    static_assert (Connectivity::dimension ==1,"no automatic calculation of vertices in dim>1");
-    const double delta_x = 1./connectivity->numberOfCells();
-    Kokkos::parallel_for(connectivity->numberOfNodes(), KOKKOS_LAMBDA(const int& r){
-	m_xr[r][0] = r*delta_x;
-      });
+    return m_mutable_xr;
   }
 
   KOKKOS_INLINE_FUNCTION
   Mesh(const std::shared_ptr<Connectivity>& connectivity,
-       Kokkos::View<Rd*>& xr)
-    : m_connectivity(connectivity),
-      m_xr(xr)
+       NodeValue<Rd>& xr)
+      : m_connectivity{connectivity},
+        m_xr{xr},
+        m_mutable_xr{xr}
   {
     ;
   }
diff --git a/src/mesh/MeshData.hpp b/src/mesh/MeshData.hpp
index 0fe98256bb87d8d02b29899906e475737f4e835d..1a07f1bcc0e477a0141e0ab7d4f7065aad633336 100644
--- a/src/mesh/MeshData.hpp
+++ b/src/mesh/MeshData.hpp
@@ -4,6 +4,7 @@
 #include <Kokkos_Core.hpp>
 #include <TinyVector.hpp>
 
+#include <ItemValue.hpp>
 #include <SubItemValuePerItem.hpp>
 
 #include <map>
@@ -12,74 +13,77 @@ template <typename M>
 class MeshData
 {
  public:
-  typedef M MeshType;
+  using  MeshType = M;
 
   static constexpr size_t dimension = MeshType::dimension;
   static_assert(dimension>0, "dimension must be strictly positive");
 
-  typedef TinyVector<dimension> Rd;
+  using Rd = TinyVector<dimension>;
 
   static constexpr double inv_dimension = 1./dimension;
 
  private:
   const MeshType& m_mesh;
-  NodeValuePerCell<Rd> m_Cjr;
-  NodeValuePerCell<double> m_ljr;
-  NodeValuePerCell<Rd> m_njr;
-  Kokkos::View<Rd*>  m_xj;
-  Kokkos::View<double*>   m_Vj;
+  NodeValuePerCell<const Rd> m_Cjr;
+  NodeValuePerCell<const double> m_ljr;
+  NodeValuePerCell<const Rd> m_njr;
+  CellValue<const Rd> m_xj;
+  CellValue<const double> m_Vj;
 
   KOKKOS_INLINE_FUNCTION
   void _updateCenter()
   { // Computes vertices isobarycenter
     if constexpr (dimension == 1) {
-      const Kokkos::View<const Rd*> xr = m_mesh.xr();
+      const NodeValue<const Rd>& xr = m_mesh.xr();
 
       const auto& cell_to_node_matrix
-          = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                            ItemType::node);
+          = m_mesh.connectivity().cellToNodeMatrix();
 
-      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-          const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
-          m_xj[j] = 0.5*(xr[cell_nodes(0)]+xr[cell_nodes(1)]);
+      CellValue<Rd> xj(m_mesh.connectivity());
+      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+          const auto& cell_nodes = cell_to_node_matrix[j];
+          xj[j] = 0.5*(xr[cell_nodes[0]]+xr[cell_nodes[1]]);
         });
+      m_xj = xj;
     } else {
-      const Kokkos::View<const Rd*> xr = m_mesh.xr();
-      const Kokkos::View<const double*>& inv_cell_nb_nodes
+      const NodeValue<const Rd>& xr = m_mesh.xr();
+
+      const CellValue<const double>& inv_cell_nb_nodes
           = m_mesh.connectivity().invCellNbNodes();
 
       const auto& cell_to_node_matrix
-          = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                            ItemType::node);
-
-      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
+          = m_mesh.connectivity().cellToNodeMatrix();
+      CellValue<Rd> xj(m_mesh.connectivity());
+      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
           Rd X = zero;
-          const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
-          for (size_t R=0; R<cell_nodes.length; ++R) {
-            X += xr[cell_nodes(R)];
+          const auto& cell_nodes = cell_to_node_matrix[j];
+          for (size_t R=0; R<cell_nodes.size(); ++R) {
+            X += xr[cell_nodes[R]];
           }
-          m_xj[j] = inv_cell_nb_nodes[j]*X;
+          xj[j] = inv_cell_nb_nodes[j]*X;
         });
+      m_xj = xj;
     }
   }
 
   KOKKOS_INLINE_FUNCTION
   void _updateVolume()
   {
-    const Kokkos::View<const Rd*> xr = m_mesh.xr();
+    const NodeValue<const Rd>& xr = m_mesh.xr();
     const auto& cell_to_node_matrix
-        = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                          ItemType::node);
+        = m_mesh.connectivity().cellToNodeMatrix();
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
+    CellValue<double> Vj(m_mesh.connectivity());
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
         double sum_cjr_xr = 0;
-        const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
+        const auto& cell_nodes = cell_to_node_matrix[j];
 
-        for (size_t R=0; R<cell_nodes.length; ++R) {
-          sum_cjr_xr += (xr[cell_nodes(R)], m_Cjr(j,R));
+        for (size_t R=0; R<cell_nodes.size(); ++R) {
+          sum_cjr_xr += (xr[cell_nodes[R]], m_Cjr(j,R));
         }
-        m_Vj[j] = inv_dimension * sum_cjr_xr;
+        Vj[j] = inv_dimension * sum_cjr_xr;
       });
+    m_Vj = Vj;
   }
 
   KOKKOS_INLINE_FUNCTION
@@ -88,117 +92,136 @@ class MeshData
       // Cjr/njr/ljr are constant overtime
     }
     else if constexpr (dimension == 2) {
-      const Kokkos::View<const Rd*> xr = m_mesh.xr();
+      const NodeValue<const Rd>& xr = m_mesh.xr();
       const auto& cell_to_node_matrix
-          = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                            ItemType::node);
-
-      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-          const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
-          for (size_t R=0; R<cell_nodes.length; ++R) {
-            int Rp1 = (R+1)%cell_nodes.length;
-            int Rm1 = (R+cell_nodes.length-1)%cell_nodes.length;
-            Rd half_xrp_xrm = 0.5*(xr(cell_nodes(Rp1))-xr(cell_nodes(Rm1)));
-            m_Cjr(j,R) = Rd{-half_xrp_xrm[1], half_xrp_xrm[0]};
-          }
-        });
-
-      const NodeValuePerCell<Rd>& Cjr = m_Cjr;
-      Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const int& j){
-          m_ljr[j] = l2Norm(Cjr[j]);
-        });
-
-      const NodeValuePerCell<double>& ljr = m_ljr;
-      Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const int& j){
-          m_njr[j] = (1./ljr[j])*Cjr[j];
-        });
-
+          = m_mesh.connectivity().cellToNodeMatrix();
+
+      {
+        NodeValuePerCell<Rd> Cjr(m_mesh.connectivity());
+        Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+            const auto& cell_nodes = cell_to_node_matrix[j];
+            for (size_t R=0; R<cell_nodes.size(); ++R) {
+              int Rp1 = (R+1)%cell_nodes.size();
+              int Rm1 = (R+cell_nodes.size()-1)%cell_nodes.size();
+              Rd half_xrp_xrm = 0.5*(xr[cell_nodes[Rp1]]-xr[cell_nodes[Rm1]]);
+              Cjr(j,R) = Rd{-half_xrp_xrm[1], half_xrp_xrm[0]};
+            }
+          });
+        m_Cjr = Cjr;
+      }
+
+      {
+        NodeValuePerCell<double> ljr(m_mesh.connectivity());
+        Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const size_t& jr){
+            ljr[jr] = l2Norm(m_Cjr[jr]);
+          });
+        m_ljr = ljr;
+      }
+
+      {
+        NodeValuePerCell<Rd> njr(m_mesh.connectivity());
+        Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const size_t& jr){
+            njr[jr] = (1./m_ljr[jr])*m_Cjr[jr];
+          });
+        m_njr = njr;
+      }
     } else if (dimension ==3) {
-      const Kokkos::View<const Rd*> xr = m_mesh.xr();
+      const NodeValue<const Rd>& xr = m_mesh.xr();
 
       NodeValuePerFace<Rd> Nlr(m_mesh.connectivity());
       const auto& face_to_node_matrix
-          = m_mesh.connectivity().getMatrix(ItemType::face,
-                                            ItemType::node);
+          = m_mesh.connectivity().faceToNodeMatrix();
 
-      Kokkos::parallel_for(m_mesh.numberOfFaces(), KOKKOS_LAMBDA(const int& l) {
-          const auto& face_nodes = face_to_node_matrix.rowConst(l);
-          const size_t nb_nodes = face_nodes.length;
+      Kokkos::parallel_for(m_mesh.numberOfFaces(), KOKKOS_LAMBDA(const FaceId& l) {
+          const auto& face_nodes = face_to_node_matrix[l];
+          const size_t nb_nodes = face_nodes.size();
           std::vector<Rd> dxr(nb_nodes);
           for (size_t r=0; r<nb_nodes; ++r) {
-            dxr[r] = xr[face_nodes((r+1)%nb_nodes)] - xr[face_nodes((r+nb_nodes-1)%nb_nodes)];
+            dxr[r]
+                = xr[face_nodes[(r+1)%nb_nodes]]
+                - xr[face_nodes[(r+nb_nodes-1)%nb_nodes]];
           }
           const double inv_12_nb_nodes = 1./(12.*nb_nodes);
           for (size_t r=0; r<nb_nodes; ++r) {
             Rd Nr = zero;
             const Rd two_dxr = 2*dxr[r];
             for (size_t s=0; s<nb_nodes; ++s) {
-              Nr += crossProduct((two_dxr - dxr[s]), xr[face_nodes(s)]);
+              Nr += crossProduct((two_dxr - dxr[s]), xr[face_nodes[s]]);
             }
             Nr *= inv_12_nb_nodes;
-            Nr -= (1./6.)*crossProduct(dxr[r], xr[face_nodes(r)]);
+            Nr -= (1./6.)*crossProduct(dxr[r], xr[face_nodes[r]]);
             Nlr(l,r) = Nr;
           }
         });
 
-      Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const int& jr){
-          m_Cjr[jr] = zero;
-        });
-
       const auto& cell_to_node_matrix
-          = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                            ItemType::node);
+          = m_mesh.connectivity().cellToNodeMatrix();
 
       const auto& cell_to_face_matrix
-          = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                            ItemType::face);
+          = m_mesh.connectivity().cellToFaceMatrix();
 
       const auto& cell_face_is_reversed = m_mesh.connectivity().cellFaceIsReversed();
-      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
-          const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
 
-          const auto& cell_faces = cell_to_face_matrix.rowConst(j);
-          const auto& face_is_reversed = cell_face_is_reversed.itemValues(j);
+      {
+        NodeValuePerCell<Rd> Cjr(m_mesh.connectivity());
+        Kokkos::parallel_for(Cjr.numberOfValues(), KOKKOS_LAMBDA(const size_t& jr){
+            Cjr[jr] = zero;
+          });
+
+        Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j) {
+            const auto& cell_nodes = cell_to_node_matrix[j];
+
+            const auto& cell_faces = cell_to_face_matrix[j];
+            const auto& face_is_reversed = cell_face_is_reversed.itemValues(j);
 
-          for (size_t L=0; L<cell_faces.length; ++L) {
-            const size_t l = cell_faces(L);
-            const auto& face_nodes = face_to_node_matrix.rowConst(l);
+            for (size_t L=0; L<cell_faces.size(); ++L) {
+              const FaceId& l = cell_faces[L];
+              const auto& face_nodes = face_to_node_matrix[l];
 
 #warning should this lambda be replaced by a precomputed correspondance?
-            std::function local_node_number_in_cell
-                = [&](const size_t& node_number) {
-                    for (size_t i_node=0; i_node<cell_nodes.length; ++i_node) {
-                      if (node_number == cell_nodes(i_node)) {
-                        return i_node;
-                        break;
+              std::function local_node_number_in_cell
+                  = [&](const NodeId& node_number) {
+                      for (size_t i_node=0; i_node<cell_nodes.size(); ++i_node) {
+                        if (node_number == cell_nodes[i_node]) {
+                          return i_node;
+                          break;
+                        }
                       }
-                    }
-                    return std::numeric_limits<size_t>::max();
-                  };
-
-            if (face_is_reversed[L]) {
-              for (size_t rl = 0; rl<face_nodes.length; ++rl) {
-                const size_t R = local_node_number_in_cell(face_nodes(rl));
-                m_Cjr(j, R) -= Nlr(l,rl);
-              }
-            } else {
-              for (size_t rl = 0; rl<face_nodes.length; ++rl) {
-                const size_t R = local_node_number_in_cell(face_nodes(rl));
-                m_Cjr(j, R) += Nlr(l,rl);
+                      return std::numeric_limits<size_t>::max();
+                    };
+
+              if (face_is_reversed[L]) {
+                for (size_t rl = 0; rl<face_nodes.size(); ++rl) {
+                  const size_t R = local_node_number_in_cell(face_nodes[rl]);
+                  Cjr(j, R) -= Nlr(l,rl);
+                }
+              } else {
+                for (size_t rl = 0; rl<face_nodes.size(); ++rl) {
+                  const size_t R = local_node_number_in_cell(face_nodes[rl]);
+                  Cjr(j, R) += Nlr(l,rl);
+                }
               }
             }
-          }
-        });
-
-      const NodeValuePerCell<Rd>& Cjr = m_Cjr;
-      Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const int& jr){
-          m_ljr[jr] = l2Norm(Cjr[jr]);
-        });
-
-      const NodeValuePerCell<double>& ljr = m_ljr;
-      Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const int& jr){
-          m_njr[jr] = (1./ljr[jr])*Cjr[jr];
-        });
+          });
+
+        m_Cjr = Cjr;
+      }
+
+      {
+        NodeValuePerCell<double> ljr(m_mesh.connectivity());
+        Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const size_t& jr){
+            ljr[jr] = l2Norm(m_Cjr[jr]);
+          });
+        m_ljr = ljr;
+      }
+
+      {
+        NodeValuePerCell<Rd> njr(m_mesh.connectivity());
+        Kokkos::parallel_for(m_Cjr.numberOfValues(), KOKKOS_LAMBDA(const size_t& jr){
+            njr[jr] = (1./m_ljr[jr])*m_Cjr[jr];
+          });
+        m_njr = njr;
+      }
     }
     static_assert((dimension<=3), "only 1d, 2d and 3d are implemented");
   }
@@ -209,27 +232,27 @@ class MeshData
     return m_mesh;
   }
 
-  const NodeValuePerCell<Rd>& Cjr() const
+  const NodeValuePerCell<const Rd>& Cjr() const
   {
     return m_Cjr;
   }
 
-  const NodeValuePerCell<double>& ljr() const
+  const NodeValuePerCell<const double>& ljr() const
   {
     return m_ljr;
   }
 
-  const NodeValuePerCell<Rd>& njr() const
+  const NodeValuePerCell<const Rd>& njr() const
   {
     return m_njr;
   }
 
-  const Kokkos::View<const Rd*> xj() const
+  const CellValue<const Rd>& xj() const
   {
     return m_xj;
   }
 
-  const Kokkos::View<const double*> Vj() const
+  const CellValue<const double>& Vj() const
   {
     return m_Vj;
   }
@@ -242,25 +265,27 @@ class MeshData
   }
 
   MeshData(const MeshType& mesh)
-      : m_mesh(mesh),
-        m_Cjr(mesh.connectivity()),
-        m_ljr(mesh.connectivity()),
-        m_njr(mesh.connectivity()),
-        m_xj("xj", mesh.numberOfCells()),
-        m_Vj("Vj", mesh.numberOfCells())
+      : m_mesh(mesh)
   {
     if constexpr (dimension==1) {
       // in 1d Cjr are computed once for all
-      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
-          m_Cjr(j,0)=-1;
-          m_Cjr(j,1)= 1;
-        });
+      {
+        NodeValuePerCell<Rd> Cjr(m_mesh.connectivity());
+        Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j) {
+            Cjr(j,0)=-1;
+            Cjr(j,1)= 1;
+          });
+        m_Cjr = Cjr;
+      }
       // in 1d njr=Cjr (here performs a shallow copy)
-      m_njr=m_Cjr;
-      Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
-          m_ljr(j,0)= 1;
-          m_ljr(j,1)= 1;
+      m_njr = m_Cjr;
+      {
+        NodeValuePerCell<double> ljr(m_mesh.connectivity());
+        Kokkos::parallel_for(ljr.numberOfValues(), KOKKOS_LAMBDA(const size_t& jr){
+            ljr[jr] = 1;
         });
+        m_ljr = ljr;
+      }
     }
     this->updateAllData();
   }
diff --git a/src/mesh/MeshNodeBoundary.hpp b/src/mesh/MeshNodeBoundary.hpp
index 87c537439bf1a27e8443865677cd6b58c132378c..0a4b9ec63ff74b71e25342144871c34e3236c163 100644
--- a/src/mesh/MeshNodeBoundary.hpp
+++ b/src/mesh/MeshNodeBoundary.hpp
@@ -1,7 +1,9 @@
 #ifndef MESH_NODE_BOUNDARY_HPP
 #define MESH_NODE_BOUNDARY_HPP
 
-#include <Kokkos_Core.hpp>
+#include <Array.hpp>
+#include <ItemValue.hpp>
+
 #include <Kokkos_Vector.hpp>
 #include <TinyVector.hpp>
 
@@ -16,12 +18,12 @@ template <size_t dimension>
 class MeshNodeBoundary
 {
  protected:
-  Kokkos::View<const unsigned int*> m_node_list;
+  Array<const NodeId> m_node_list;
  public:
   MeshNodeBoundary& operator=(const MeshNodeBoundary&) = default;
   MeshNodeBoundary& operator=(MeshNodeBoundary&&) = default;
 
-  const Kokkos::View<const unsigned int*>& nodeList() const
+  const Array<const NodeId>& nodeList() const
   {
     return m_node_list;
   }
@@ -32,12 +34,12 @@ class MeshNodeBoundary
   {
     static_assert(dimension == MeshType::dimension);
     const auto& face_to_cell_matrix
-        = mesh.connectivity().getMatrix(ItemType::face, ItemType::cell);
+        = mesh.connectivity().faceToCellMatrix();
 
-    const Kokkos::View<const unsigned int*>& face_list = ref_face_list.faceList();
-    Kokkos::parallel_for(face_list.extent(0), KOKKOS_LAMBDA(const int& l){
-        const auto& face_cells = face_to_cell_matrix.rowConst(face_list[l]);
-        if (face_cells.length>1) {
+    const Array<const FaceId>& face_list = ref_face_list.faceList();
+    Kokkos::parallel_for(face_list.size(), KOKKOS_LAMBDA(const int& l){
+        const auto& face_cells = face_to_cell_matrix[face_list[l]];
+        if (face_cells.size()>1) {
           std::cerr << "internal faces cannot be used to define mesh boundaries\n";
           std::exit(1);
         }
@@ -45,24 +47,23 @@ class MeshNodeBoundary
 
     Kokkos::vector<unsigned int> node_ids;
     // not enough but should reduce significantly the number of resizing
-    node_ids.reserve(dimension*face_list.extent(0));
+    node_ids.reserve(dimension*face_list.size());
     const auto& face_to_node_matrix
-        = mesh.connectivity().getMatrix(ItemType::face,
-                                        ItemType::node);
+        = mesh.connectivity().faceToNodeMatrix();
 
-    for (size_t l=0; l<face_list.extent(0); ++l) {
-      const size_t face_number = face_list[l];
-      const auto& face_nodes = face_to_node_matrix.rowConst(face_number);
+    for (size_t l=0; l<face_list.size(); ++l) {
+      const FaceId face_number = face_list[l];
+      const auto& face_nodes = face_to_node_matrix[face_number];
 
-      for (size_t r=0; r<face_nodes.length; ++r) {
-        node_ids.push_back(face_nodes(r));
+      for (size_t r=0; r<face_nodes.size(); ++r) {
+        node_ids.push_back(face_nodes[r]);
       }
     }
     std::sort(node_ids.begin(), node_ids.end());
     auto last = std::unique(node_ids.begin(), node_ids.end());
     node_ids.resize(std::distance(node_ids.begin(), last));
 
-    Kokkos::View<unsigned int*> node_list("node_list", node_ids.size());
+    Array<NodeId> node_list(node_ids.size());
     Kokkos::parallel_for(node_ids.size(), KOKKOS_LAMBDA(const int& r){
         node_list[r] = node_ids[r];
       });
@@ -88,7 +89,9 @@ template <size_t dimension>
 class MeshFlatNodeBoundary
     : public MeshNodeBoundary<dimension>
 {
-  typedef TinyVector<dimension, double> Rd;
+ public:
+  using Rd = TinyVector<dimension, double>;
+
  private:
   const Rd m_outgoing_normal;
 
@@ -145,13 +148,14 @@ _checkBoundaryIsFlat(const TinyVector<2,double>& normal,
                      const MeshType& mesh) const
 {
   static_assert(MeshType::dimension == 2);
-  typedef TinyVector<2,double> R2;
+  using R2 = TinyVector<2,double>;
+
   const R2 origin = 0.5*(xmin+xmax);
   const double length = l2Norm(xmax-xmin);
 
-  const Kokkos::View<const R2*> xr = mesh.xr();
+  const NodeValue<const R2>& xr = mesh.xr();
 
-  Kokkos::parallel_for(m_node_list.extent(0), KOKKOS_LAMBDA(const size_t& r) {
+  Kokkos::parallel_for(m_node_list.size(), KOKKOS_LAMBDA(const size_t& r) {
       const R2& x = xr[m_node_list[r]];
       if ((x-origin,normal)>1E-13*length) {
         std::cerr << "this FlatBoundary is not flat!\n";
@@ -167,9 +171,9 @@ MeshFlatNodeBoundary<1>::
 _getNormal(const MeshType& mesh)
 {
   static_assert(MeshType::dimension == 1);
-  typedef TinyVector<1,double> R;
+  using R = TinyVector<1,double>;
 
-  if (m_node_list.extent(0) != 1) {
+  if (m_node_list.size() != 1) {
     std::cerr << "Node boundaries in 1D require to have exactly 1 node\n";
     std::exit(1);
   }
@@ -184,9 +188,9 @@ MeshFlatNodeBoundary<2>::
 _getNormal(const MeshType& mesh)
 {
   static_assert(MeshType::dimension == 2);
-  typedef TinyVector<2,double> R2;
+  using R2 = TinyVector<2,double>;
 
-  const Kokkos::View<const R2*> xr = mesh.xr();
+  const NodeValue<const R2>& xr = mesh.xr();
 
   R2 xmin(std::numeric_limits<double>::max(),
           std::numeric_limits<double>::max());
@@ -194,7 +198,7 @@ _getNormal(const MeshType& mesh)
   R2 xmax(-std::numeric_limits<double>::max(),
           -std::numeric_limits<double>::max());
 
-  for (size_t r=0; r<m_node_list.extent(0); ++r) {
+  for (size_t r=0; r<m_node_list.size(); ++r) {
     const R2& x = xr[m_node_list[r]];
     if ((x[0]<xmin[0]) or ((x[0] == xmin[0]) and (x[1] < xmin[1]))) {
       xmin = x;
@@ -226,7 +230,7 @@ MeshFlatNodeBoundary<3>::
 _getNormal(const MeshType& mesh)
 {
   static_assert(MeshType::dimension == 3);
-  typedef TinyVector<3,double> R3;
+  using R3 = TinyVector<3,double>;
 
 
   R3 xmin(std::numeric_limits<double>::max(),
@@ -239,9 +243,9 @@ _getNormal(const MeshType& mesh)
   R3 ymax = xmax;
   R3 zmax = xmax;
 
-  const Kokkos::View<const R3*> xr = mesh.xr();
+  const NodeValue<const R3>& xr = mesh.xr();
 
-  for (size_t r=0; r<m_node_list.extent(0); ++r) {
+  for (size_t r=0; r<m_node_list.size(); ++r) {
     const R3& x = xr[m_node_list[r]];
     if (x[0]<xmin[0]) {
       xmin = x;
@@ -310,25 +314,23 @@ MeshFlatNodeBoundary<1>::
 _getOutgoingNormal(const MeshType& mesh)
 {
   static_assert(MeshType::dimension == 1);
-  typedef TinyVector<1,double> R;
+  using R = TinyVector<1,double>;
 
   const R normal = this->_getNormal(mesh);
 
-  const Kokkos::View<const R*>& xr = mesh.xr();
+  const NodeValue<const R>& xr = mesh.xr();
   const auto& cell_to_node_matrix
-      = mesh.connectivity().getMatrix(ItemType::cell,
-                                      ItemType::node);
+      = mesh.connectivity().cellToNodeMatrix();
 
   const auto& node_to_cell_matrix
-      = mesh.connectivity().getMatrix(ItemType::node,
-                                      ItemType::cell);
+      = mesh.connectivity().nodeToCellMatrix();
 
-  const size_t r0 = m_node_list[0];
-  const size_t j0 = node_to_cell_matrix.rowConst(r0)(0);
-  const auto& j0_nodes = cell_to_node_matrix.rowConst(j0);
+  const NodeId r0 = m_node_list[0];
+  const CellId j0 = node_to_cell_matrix[r0][0];
+  const auto& j0_nodes = cell_to_node_matrix[j0];
   double max_height = 0;
-  for (size_t r=0; r<j0_nodes.length; ++r) {
-    const double height = (xr(j0_nodes(r))-xr(r0), normal);
+  for (size_t r=0; r<j0_nodes.size(); ++r) {
+    const double height = (xr[j0_nodes[r]]-xr[r0], normal);
     if (std::abs(height) > std::abs(max_height)) {
       max_height = height;
     }
@@ -347,25 +349,23 @@ MeshFlatNodeBoundary<2>::
 _getOutgoingNormal(const MeshType& mesh)
 {
   static_assert(MeshType::dimension == 2);
-  typedef TinyVector<2,double> R2;
+  using R2 = TinyVector<2,double>;
 
   const R2 normal = this->_getNormal(mesh);
 
-  const Kokkos::View<const R2*>& xr = mesh.xr();
+  const NodeValue<const R2>& xr = mesh.xr();
   const auto& cell_to_node_matrix
-      = mesh.connectivity().getMatrix(ItemType::cell,
-                                      ItemType::node);
+      = mesh.connectivity().cellToNodeMatrix();
 
   const auto& node_to_cell_matrix
-      = mesh.connectivity().getMatrix(ItemType::node,
-                                      ItemType::cell);
+      = mesh.connectivity().nodeToCellMatrix();
 
-  const size_t r0 = m_node_list[0];
-  const size_t j0 = node_to_cell_matrix.rowConst(r0)(0);
-  const auto& j0_nodes = cell_to_node_matrix.rowConst(j0);
+  const NodeId r0 = m_node_list[0];
+  const CellId j0 = node_to_cell_matrix[r0][0];
+  const auto& j0_nodes = cell_to_node_matrix[j0];
   double max_height = 0;
-  for (size_t r=0; r<j0_nodes.length; ++r) {
-    const double height = (xr(j0_nodes(r))-xr(r0), normal);
+  for (size_t r=0; r<j0_nodes.size(); ++r) {
+    const double height = (xr[j0_nodes[r]]-xr[r0], normal);
     if (std::abs(height) > std::abs(max_height)) {
       max_height = height;
     }
@@ -384,25 +384,23 @@ MeshFlatNodeBoundary<3>::
 _getOutgoingNormal(const MeshType& mesh)
 {
   static_assert(MeshType::dimension == 3);
-  typedef TinyVector<3,double> R3;
+  using R3 = TinyVector<3,double>;
 
   const R3 normal = this->_getNormal(mesh);
 
-  const Kokkos::View<const R3*>& xr = mesh.xr();
+  const NodeValue<const R3>& xr = mesh.xr();
   const auto& cell_to_node_matrix
-      = mesh.connectivity().getMatrix(ItemType::cell,
-                                      ItemType::node);
+      = mesh.connectivity().cellToNodeMatrix();
 
   const auto& node_to_cell_matrix
-      = mesh.connectivity().getMatrix(ItemType::node,
-                                      ItemType::cell);
+      = mesh.connectivity().nodeToCellMatrix();
 
-  const size_t r0 = m_node_list[0];
-  const size_t j0 = node_to_cell_matrix.rowConst(r0)(0);
-  const auto& j0_nodes = cell_to_node_matrix.rowConst(j0);
+  const NodeId r0 = m_node_list[0];
+  const CellId j0 = node_to_cell_matrix[r0][0];
+  const auto& j0_nodes = cell_to_node_matrix[j0];
   double max_height = 0;
-  for (size_t r=0; r<j0_nodes.length; ++r) {
-    const double height = (xr(j0_nodes(r))-xr(r0), normal);
+  for (size_t r=0; r<j0_nodes.size(); ++r) {
+    const double height = (xr[j0_nodes[r]]-xr[r0], normal);
     if (std::abs(height) > std::abs(max_height)) {
       max_height = height;
     }
diff --git a/src/mesh/RefFaceList.hpp b/src/mesh/RefFaceList.hpp
index e891ea2581bc1dbb19a0e82f4178a2a172112574..ab66943936c091735c404b287d587a15d81a1a9f 100644
--- a/src/mesh/RefFaceList.hpp
+++ b/src/mesh/RefFaceList.hpp
@@ -1,14 +1,14 @@
 #ifndef REF_FACE_LIST_HPP
 #define REF_FACE_LIST_HPP
 
-#include <Kokkos_Core.hpp>
+#include <Array.hpp>
 #include <RefId.hpp>
 
 class RefFaceList
 {
  private:
   const RefId m_ref_id;
-  const Kokkos::View<const unsigned int*> m_face_id_list;
+  const Array<const FaceId> m_face_id_list;
 
  public:
   const RefId& refId() const
@@ -16,13 +16,13 @@ class RefFaceList
     return m_ref_id;
   }
 
-  const Kokkos::View<const unsigned int*>& faceList() const
+  const Array<const FaceId>& faceList() const
   {
     return m_face_id_list;
   }
 
   RefFaceList(const RefId& ref_id,
-              const Kokkos::View<const unsigned int*>& face_id_list)
+              const Array<const FaceId>& face_id_list)
       : m_ref_id(ref_id),
         m_face_id_list(face_id_list)
   {
diff --git a/src/mesh/RefNodeList.hpp b/src/mesh/RefNodeList.hpp
index 7bdc36fac84b1dd9cb713be5a5a64e9d992232c0..462d23bb3d35a6384fcd5176d0584419a586abc3 100644
--- a/src/mesh/RefNodeList.hpp
+++ b/src/mesh/RefNodeList.hpp
@@ -1,14 +1,14 @@
 #ifndef REF_NODE_LIST_HPP
 #define REF_NODE_LIST_HPP
 
-#include <Kokkos_Core.hpp>
+#include <Array.hpp>
 #include <RefId.hpp>
 
 class RefNodeList
 {
  private:
   RefId m_ref_id;
-  Kokkos::View<const unsigned int*> m_node_id_list;
+  Array<const NodeId> m_node_id_list;
 
  public:
   const RefId& refId() const
@@ -16,13 +16,13 @@ class RefNodeList
     return m_ref_id;
   }
 
-  const Kokkos::View<const unsigned int*>& nodeList() const
+  const Array<const NodeId>& nodeList() const
   {
     return m_node_id_list;
   }
 
   RefNodeList(const RefId& ref_id,
-              const Kokkos::View<const unsigned int*>& node_id_list)
+              const Array<const NodeId>& node_id_list)
       : m_ref_id(ref_id),
         m_node_id_list(node_id_list)
   {
diff --git a/src/mesh/SubItemValuePerItem.hpp b/src/mesh/SubItemValuePerItem.hpp
index 5778fc73989ca547130288d1737bf9b1d767c2ef..3853038a1822ccd5bc6e4eb6d5c2d2696c8876ba 100644
--- a/src/mesh/SubItemValuePerItem.hpp
+++ b/src/mesh/SubItemValuePerItem.hpp
@@ -2,9 +2,14 @@
 #define SUBITEM_VALUE_PER_ITEM_HPP
 
 #include <Kokkos_StaticCrsGraph.hpp>
-#include <ItemType.hpp>
+
 #include <PastisAssert.hpp>
 
+#include <Array.hpp>
+#include <ItemType.hpp>
+
+#include <ItemId.hpp>
+
 #include <ConnectivityMatrix.hpp>
 #include <IConnectivity.hpp>
 
@@ -25,11 +30,16 @@ class SubItemValuePerItem<DataType,
  public:
   static const ItemType item_t{item_type};
   static const ItemType sub_item_t{sub_item_type};
+
+  using data_type = DataType;
+  using ItemId = ItemIdT<item_type>;
+  using index_type = ItemId;
+
  private:
   bool m_is_built{false};
 
-  ConnectivityMatrix::HostRowType m_host_row_map;
-  Kokkos::View<DataType*> m_values;
+  typename ConnectivityMatrix::HostRowType m_host_row_map;
+  Array<DataType> m_values;
 
   // Allows const version to access our data
   friend SubItemValuePerItem<std::add_const_t<DataType>,
@@ -39,9 +49,13 @@ class SubItemValuePerItem<DataType,
  public:
   class SubView
   {
+   public:
+    using data_type = DataType;
+
    private:
     KOKKOS_RESTRICT DataType* const m_sub_values;
     const size_t m_size;
+
    public:
     KOKKOS_INLINE_FUNCTION
     const DataType& operator[](const size_t& i) const
@@ -69,14 +83,14 @@ class SubItemValuePerItem<DataType,
     SubView(SubView&&) = default;
 
     KOKKOS_INLINE_FUNCTION
-    SubView(const Kokkos::View<DataType*>& values,
+    SubView(const Array<DataType>& values,
             const size_t& begin,
             const size_t& end)
         : m_sub_values(&(values[begin])),
           m_size(end-begin)
     {
       Assert(begin<=end);
-      Assert(end<=values.extent(0));
+      Assert(end<=values.size());
     }
   };
 
@@ -86,42 +100,45 @@ class SubItemValuePerItem<DataType,
     return m_is_built;
   }
 
+  // Following Kokkos logic, these classes are view and const view does allow
+  // changes in data
   KOKKOS_FORCEINLINE_FUNCTION
-  DataType& operator()(const size_t& j, const size_t& r)
+  DataType& operator()(const ItemId& j, const size_t& r) const
   {
     Assert(m_is_built);
-    return m_values[m_host_row_map(j)+r];
+    return m_values[m_host_row_map(size_t{j})+r];
   }
 
-  // Following Kokkos logic, these classes are view and const view does allow
-  // changes in data
+  template <typename IndexType>
   KOKKOS_FORCEINLINE_FUNCTION
-  DataType& operator()(const size_t& j, const size_t& r) const
+  DataType& operator()(const IndexType& j, const size_t& r) const
   {
-    Assert(m_is_built);
-    return m_values[m_host_row_map(j)+r];
+    static_assert(std::is_same<IndexType, size_t>(),
+                  "SubItemValuePerItem indexed by ItemId");
+    return m_values[m_host_row_map(size_t{j})+r];
   }
 
   KOKKOS_INLINE_FUNCTION
   size_t numberOfValues() const
   {
     Assert(m_is_built);
-    return m_values.extent(0);
+    return m_values.size();
   }
 
+  // Following Kokkos logic, these classes are view and const view does allow
+  // changes in data
   KOKKOS_FORCEINLINE_FUNCTION
-  DataType& operator[](const size_t& i)
+  DataType& operator[](const size_t& i) const
   {
     Assert(m_is_built);
     return m_values[i];
   }
 
-  // Following Kokkos logic, these classes are view and const view does allow
-  // changes in data
-  KOKKOS_FORCEINLINE_FUNCTION
-  DataType& operator[](const size_t & i) const
+  template <typename IndexType>
+  DataType& operator[](const IndexType& i) const
   {
-    Assert(m_is_built);
+    static_assert(std::is_same<IndexType, size_t>(),
+                  "Access to SubItemValuePerItem's array must be indexed by size_t");
     return m_values[i];
   }
 
@@ -171,7 +188,7 @@ class SubItemValuePerItem<DataType,
     // ensures that const is not lost through copy
     static_assert(((std::is_const<DataType2>() and std::is_const<DataType>())
                    or not std::is_const<DataType2>()),
-                  "Cannot assign const  SubItemValuePerItem to a non const SubItemValuePerItem");
+                  "Cannot assign SubItemValuePerItem of const data to SubItemValuePerItem of non-const data");
     m_host_row_map = sub_item_value_per_item.m_host_row_map;
     m_values = sub_item_value_per_item.m_values;
 
@@ -192,11 +209,14 @@ class SubItemValuePerItem<DataType,
   SubItemValuePerItem(const IConnectivity& connectivity)
       : m_is_built{true}
   {
+    static_assert(not std::is_const<DataType>(),
+                  "Cannot allocate SubItemValuePerItem of const data: only view is supported"); ;
+
     ConnectivityMatrix connectivity_matrix
-        = connectivity.getMatrix(item_type, sub_item_type);
+        = connectivity._getMatrix(item_type, sub_item_type);
 
     m_host_row_map = connectivity_matrix.rowsMap();
-    m_values = Kokkos::View<DataType*>("values", connectivity_matrix.numEntries());
+    m_values = Array<std::remove_const_t<DataType>>(connectivity_matrix.numEntries());
   }
 
   ~SubItemValuePerItem() = default;
diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp
index a33fef0bfbe2abf2c73b34e7c3b564fb2cd81461..276bad33d5624f018b9d512743f4f7695a6213e5 100644
--- a/src/output/VTKWriter.hpp
+++ b/src/output/VTKWriter.hpp
@@ -8,6 +8,8 @@
 #include <TinyVector.hpp>
 #include <IConnectivity.hpp>
 
+#include <ItemValue.hpp>
+
 class VTKWriter
 {
  private:
@@ -39,25 +41,24 @@ class VTKWriter
 
     fout << "<Points>\n";
     fout << "<DataArray Name=\"Positions\" NumberOfComponents=\"3\" type=\"Float64\" format=\"ascii\">\n";
-    if constexpr(MeshType::dimension ==1) {
-      const Kokkos::View<const TinyVector<1>*> xr = mesh.xr();
-      for (unsigned int r=0; r<mesh.numberOfNodes(); ++r) {
+    using Rd = TinyVector<MeshType::dimension>;
+    const NodeValue<const Rd>& xr = mesh.xr();
+    if constexpr(MeshType::dimension == 1) {
+      for (NodeId r=0; r<mesh.numberOfNodes(); ++r) {
         for (unsigned short i=0; i<1; ++i) {
           fout << xr[r][i] << ' ';
         }
         fout << "0 0 "; // VTK requires 3 components
       }
-    } else if constexpr (MeshType::dimension ==2) {
-      const Kokkos::View<const TinyVector<2>*> xr = mesh.xr();
-      for (unsigned int r=0; r<mesh.numberOfNodes(); ++r) {
+    } else if constexpr (MeshType::dimension == 2) {
+      for (NodeId r=0; r<mesh.numberOfNodes(); ++r) {
         for (unsigned short i=0; i<2; ++i) {
           fout << xr[r][i] << ' ';
         }
         fout << "0 "; // VTK requires 3 components
       }
     } else {
-      const Kokkos::View<const TinyVector<3>*> xr = mesh.xr();
-      for (unsigned int r=0; r<mesh.numberOfNodes(); ++r) {
+      for (NodeId r=0; r<mesh.numberOfNodes(); ++r) {
         for (unsigned short i=0; i<3; ++i) {
           fout << xr[r][i] << ' ';
         }
@@ -72,13 +73,12 @@ class VTKWriter
     fout << "<DataArray type=\"Int32\" Name=\"connectivity\" NumberOfComponents=\"1\" format=\"ascii\">\n";
 
     const auto& cell_to_node_matrix
-        = mesh.connectivity().getMatrix(ItemType::cell,
-                                        ItemType::node);
+        = mesh.connectivity().cellToNodeMatrix();
 
-    for (unsigned int j=0; j<mesh.numberOfCells(); ++j) {
-      const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
-      for (unsigned short r=0; r<cell_nodes.length; ++r) {
-        fout << cell_nodes(r) << ' ';
+    for (CellId j=0; j<mesh.numberOfCells(); ++j) {
+      const auto& cell_nodes = cell_to_node_matrix[j];
+      for (unsigned short r=0; r<cell_nodes.size(); ++r) {
+        fout << cell_nodes[r] << ' ';
       }
     }
     fout << '\n';
@@ -87,9 +87,9 @@ class VTKWriter
     fout << "<DataArray type=\"UInt32\" Name=\"offsets\" NumberOfComponents=\"1\" format=\"ascii\">\n";
     {
       unsigned int offset=0;
-      for (unsigned int j=0; j<mesh.numberOfCells(); ++j) {
-        const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
-        offset += cell_nodes.length;
+      for (CellId j=0; j<mesh.numberOfCells(); ++j) {
+        const auto& cell_nodes = cell_to_node_matrix[j];
+        offset += cell_nodes.size();
         fout << offset << ' ';
       }
     }
@@ -97,9 +97,9 @@ class VTKWriter
     fout << "</DataArray>\n";
 
     fout << "<DataArray type=\"Int8\" Name=\"types\" NumberOfComponents=\"1\" format=\"ascii\">\n";
-    for (unsigned int j=0; j<mesh.numberOfCells(); ++j) {
-      const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
-      switch (cell_nodes.length) {
+    for (CellId j=0; j<mesh.numberOfCells(); ++j) {
+      const auto& cell_nodes = cell_to_node_matrix[j];
+      switch (cell_nodes.size()) {
         case 2: {
           fout << "3 ";
           break;
diff --git a/src/scheme/AcousticSolver.hpp b/src/scheme/AcousticSolver.hpp
index 0cc6ec0df7a97b91999376873ed7b35a0c5acf6c..375828f41a86eef02f1d7fe87e48bb6ff4388223 100644
--- a/src/scheme/AcousticSolver.hpp
+++ b/src/scheme/AcousticSolver.hpp
@@ -1,9 +1,10 @@
 #ifndef ACOUSTIC_SOLVER_HPP
 #define ACOUSTIC_SOLVER_HPP
 
-#include <Kokkos_Core.hpp>
 #include <rang.hpp>
 
+#include <ArrayUtils.hpp>
+
 #include <BlockPerfectGas.hpp>
 #include <PastisAssert.hpp>
 
@@ -19,8 +20,8 @@
 template<typename MeshData>
 class AcousticSolver
 {
-  typedef typename MeshData::MeshType MeshType;
-  typedef FiniteVolumesEulerUnknowns<MeshData> UnknownsType;
+  using MeshType = typename MeshData::MeshType;
+  using UnknownsType = FiniteVolumesEulerUnknowns<MeshData>;
 
   MeshData& m_mesh_data;
   const MeshType& m_mesh;
@@ -29,66 +30,30 @@ class AcousticSolver
 
   constexpr static size_t dimension = MeshType::dimension;
 
-  typedef TinyVector<dimension> Rd;
-  typedef TinyMatrix<dimension> Rdd;
+  using Rd = TinyVector<dimension>;
+  using Rdd = TinyMatrix<dimension>;
 
  private:
-  struct ReduceMin
-  {
-   private:
-    const Kokkos::View<const double*> x_;
-
-   public:
-    typedef Kokkos::View<const double*>::non_const_value_type value_type;
-
-    ReduceMin(const Kokkos::View<const double*>& x) : x_ (x) {}
-
-    typedef Kokkos::View<const double*>::size_type size_type;
-
-    KOKKOS_INLINE_FUNCTION
-    void operator() (const size_type i, value_type& update) const
-    {
-      if (x_(i) < update) {
-        update = x_(i);
-      }
-    }
-
-    KOKKOS_INLINE_FUNCTION
-    void join (volatile value_type& dst,
-               const volatile value_type& src) const
-    {
-      if (src < dst) {
-        dst = src;
-      }
-    }
-
-    KOKKOS_INLINE_FUNCTION void
-    init (value_type& dst) const
-    { // The identity under max is -Inf.
-      dst= Kokkos::reduction_identity<value_type>::min();
-    }
-  };
-
   KOKKOS_INLINE_FUNCTION
-  const Kokkos::View<const double*>
-  computeRhoCj(const Kokkos::View<const double*>& rhoj,
-               const Kokkos::View<const double*>& cj)
+  const CellValue<const double>
+  computeRhoCj(const CellValue<const double>& rhoj,
+               const CellValue<const double>& cj)
   {
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j) {
         m_rhocj[j] = rhoj[j]*cj[j];
       });
     return m_rhocj;
   }
 
   KOKKOS_INLINE_FUNCTION
-  void computeAjr(const Kokkos::View<const double*>& rhocj,
-                  const NodeValuePerCell<Rd>& Cjr,
-                  const NodeValuePerCell<double>& ljr,
-                  const NodeValuePerCell<Rd>& njr)
+  void computeAjr(const CellValue<const double>& rhocj,
+                  const NodeValuePerCell<const Rd>& Cjr,
+                  const NodeValuePerCell<const double>& ljr,
+                  const NodeValuePerCell<const Rd>& njr)
   {
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j) {
         const size_t& nb_nodes =m_Ajr.numberOfSubValues(j);
-        const double& rho_c = rhocj(j);
+        const double& rho_c = rhocj[j];
         for (size_t r=0; r<nb_nodes; ++r) {
           m_Ajr(j,r) = tensorProduct(rho_c*Cjr(j,r), njr(j,r));
         }
@@ -96,53 +61,51 @@ class AcousticSolver
   }
 
   KOKKOS_INLINE_FUNCTION
-  const Kokkos::View<const Rdd*>
-  computeAr(const NodeValuePerCell<Rdd>& Ajr) {
+  const NodeValue<const Rdd>
+  computeAr(const NodeValuePerCell<const Rdd>& Ajr) {
     const auto& node_to_cell_matrix
-        = m_connectivity.getMatrix(ItemType::node,
-                                   ItemType::cell);
+        = m_connectivity.nodeToCellMatrix();
     const auto& node_local_numbers_in_their_cells
         = m_connectivity.nodeLocalNumbersInTheirCells();
 
-    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const int& r) {
+    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const NodeId& r) {
         Rdd sum = zero;
-        const auto& node_to_cell = node_to_cell_matrix.rowConst(r);
+        const auto& node_to_cell = node_to_cell_matrix[r];
         const auto& node_local_number_in_its_cells
             = node_local_numbers_in_their_cells.itemValues(r);
 
-        for (size_t j=0; j<node_to_cell.length; ++j) {
-          const unsigned int J = node_to_cell(j);
+        for (size_t j=0; j<node_to_cell.size(); ++j) {
+          const CellId J = node_to_cell[j];
           const unsigned int R = node_local_number_in_its_cells[j];
           sum += Ajr(J,R);
         }
-        m_Ar(r) = sum;
+        m_Ar[r] = sum;
       });
 
     return m_Ar;
   }
 
   KOKKOS_INLINE_FUNCTION
-  const Kokkos::View<const Rd*>
+  const NodeValue<const Rd>
   computeBr(const NodeValuePerCell<Rdd>& Ajr,
-            const NodeValuePerCell<Rd>& Cjr,
-            const Kokkos::View<const Rd*>& uj,
-            const Kokkos::View<const double*>& pj) {
+            const NodeValuePerCell<const Rd>& Cjr,
+            const CellValue<const Rd>& uj,
+            const CellValue<const double>& pj) {
     const auto& node_to_cell_matrix
-        = m_connectivity.getMatrix(ItemType::node,
-                                   ItemType::cell);
+        = m_connectivity.nodeToCellMatrix();
     const auto& node_local_numbers_in_their_cells
         = m_connectivity.nodeLocalNumbersInTheirCells();
 
-    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const int& r) {
-        Rd& br = m_br(r);
+    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const NodeId& r) {
+        Rd& br = m_br[r];
         br = zero;
-        const auto& node_to_cell = node_to_cell_matrix.rowConst(r);
+        const auto& node_to_cell = node_to_cell_matrix[r];
         const auto& node_local_number_in_its_cells
             = node_local_numbers_in_their_cells.itemValues(r);
-        for (size_t j=0; j<node_to_cell.length; ++j) {
-          const unsigned int J = node_to_cell(j);
+        for (size_t j=0; j<node_to_cell.size(); ++j) {
+          const CellId J = node_to_cell[j];
           const unsigned int R = node_local_number_in_its_cells[j];
-          br += Ajr(J,R)*uj(J) + pj(J)*Cjr(J,R);
+          br += Ajr(J,R)*uj[J] + pj[J]*Cjr(J,R);
         }
       });
 
@@ -179,11 +142,13 @@ class AcousticSolver
           const Rdd nxn = tensorProduct(n,n);
           const Rdd P = I-nxn;
 
+          const Array<const NodeId>& node_list
+              = symmetry_bc.nodeList();
           Kokkos::parallel_for(symmetry_bc.numberOfNodes(), KOKKOS_LAMBDA(const int& r_number) {
-              const int r = symmetry_bc.nodeList()[r_number];
+              const NodeId r = node_list[r_number];
 
-              m_Ar(r) = P*m_Ar(r)*P + nxn;
-              m_br(r) = P*m_br(r);
+              m_Ar[r] = P*m_Ar[r]*P + nxn;
+              m_br[r] = P*m_br[r];
             });
           break;
         }
@@ -191,14 +156,14 @@ class AcousticSolver
     }
   }
 
-  Kokkos::View<Rd*>
-  computeUr(const Kokkos::View<const Rdd*>& Ar,
-            const Kokkos::View<const Rd*>& br)
+  NodeValue<Rd>
+  computeUr(const NodeValue<const Rdd>& Ar,
+            const NodeValue<const Rd>& br)
   {
     inverse(Ar, m_inv_Ar);
-    const Kokkos::View<const Rdd*> invAr = m_inv_Ar;
-    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const int& r) {
-        m_ur[r]=invAr(r)*br(r);
+    const NodeValue<const Rdd> invAr = m_inv_Ar;
+    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const NodeId& r) {
+        m_ur[r]=invAr[r]*br[r];
       });
 
     return m_ur;
@@ -206,64 +171,64 @@ class AcousticSolver
 
   void
   computeFjr(const NodeValuePerCell<Rdd>& Ajr,
-             const Kokkos::View<const Rd*>& ur,
-             const NodeValuePerCell<Rd>& Cjr,
-             const Kokkos::View<const Rd*>& uj,
-             const Kokkos::View<const double*>& pj)
+             const NodeValue<const Rd>& ur,
+             const NodeValuePerCell<const Rd>& Cjr,
+             const CellValue<const Rd>& uj,
+             const CellValue<const double>& pj)
   {
     const auto& cell_to_node_matrix
-        = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                          ItemType::node);
+        = m_mesh.connectivity().cellToNodeMatrix();
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
-        const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j) {
+        const auto& cell_nodes = cell_to_node_matrix[j];
 
-        for (size_t r=0; r<cell_nodes.length; ++r) {
-          m_Fjr(j,r) = Ajr(j,r)*(uj(j)-ur(cell_nodes(r)))+pj(j)*Cjr(j,r);
+        for (size_t r=0; r<cell_nodes.size(); ++r) {
+          m_Fjr(j,r) = Ajr(j,r)*(uj[j]-ur[cell_nodes[r]])+pj[j]*Cjr(j,r);
         }
       });
   }
 
-  void inverse(const Kokkos::View<const Rdd*>& A,
-               Kokkos::View<Rdd*>& inv_A) const
+  void inverse(const NodeValue<const Rdd>& A,
+               NodeValue<Rdd>& inv_A) const
   {
-    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const int& r) {
-        inv_A(r) = ::inverse(A(r));
+    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const NodeId& r) {
+        inv_A[r] = ::inverse(A[r]);
       });
   }
 
   KOKKOS_INLINE_FUNCTION
-  void computeExplicitFluxes(const Kokkos::View<const Rd*>& xr,
-                             const Kokkos::View<const Rd*>& xj,
-                             const Kokkos::View<const double*>& rhoj,
-                             const Kokkos::View<const Rd*>& uj,
-                             const Kokkos::View<const double*>& pj,
-                             const Kokkos::View<const double*>& cj,
-                             const Kokkos::View<const double*>& Vj,
-                             const NodeValuePerCell<Rd>& Cjr,
-                             const NodeValuePerCell<double>& ljr,
-                             const NodeValuePerCell<Rd>& njr) {
-    const Kokkos::View<const double*> rhocj  = computeRhoCj(rhoj, cj);
+  void computeExplicitFluxes(const NodeValue<const Rd>& xr,
+                             const CellValue<const Rd>& xj,
+                             const CellValue<const double>& rhoj,
+                             const CellValue<const Rd>& uj,
+                             const CellValue<const double>& pj,
+                             const CellValue<const double>& cj,
+                             const CellValue<const double>& Vj,
+                             const NodeValuePerCell<const Rd>& Cjr,
+                             const NodeValuePerCell<const double>& ljr,
+                             const NodeValuePerCell<const Rd>& njr) {
+    const CellValue<const double> rhocj = computeRhoCj(rhoj, cj);
     computeAjr(rhocj, Cjr, ljr, njr);
 
-    const Kokkos::View<const Rdd*> Ar = computeAr(m_Ajr);
-    const Kokkos::View<const Rd*> br = computeBr(m_Ajr, Cjr, uj, pj);
+    NodeValuePerCell<const Rdd> Ajr = m_Ajr;
+    const NodeValue<const Rdd> Ar = computeAr(Ajr);
+    const NodeValue<const Rd> br = computeBr(m_Ajr, Cjr, uj, pj);
 
     this->applyBoundaryConditions();
 
-    Kokkos::View<Rd*> ur = m_ur;
-    ur  = computeUr(Ar, br);
+    NodeValue<Rd>& ur = m_ur;
+    ur = computeUr(Ar, br);
     computeFjr(m_Ajr, ur, Cjr, uj, pj);
   }
 
-  Kokkos::View<Rd*> m_br;
+  NodeValue<Rd> m_br;
   NodeValuePerCell<Rdd> m_Ajr;
-  Kokkos::View<Rdd*> m_Ar;
-  Kokkos::View<Rdd*> m_inv_Ar;
+  NodeValue<Rdd> m_Ar;
+  NodeValue<Rdd> m_inv_Ar;
   NodeValuePerCell<Rd> m_Fjr;
-  Kokkos::View<Rd*> m_ur;
-  Kokkos::View<double*> m_rhocj;
-  Kokkos::View<double*> m_Vj_over_cj;
+  NodeValue<Rd> m_ur;
+  CellValue<double> m_rhocj;
+  CellValue<double> m_Vj_over_cj;
 
  public:
   AcousticSolver(MeshData& mesh_data,
@@ -273,79 +238,72 @@ class AcousticSolver
         m_mesh(mesh_data.mesh()),
         m_connectivity(m_mesh.connectivity()),
         m_boundary_condition_list(bc_list),
-        m_br("br", m_mesh.numberOfNodes()),
+        m_br(m_connectivity),
         m_Ajr(m_connectivity),
-        m_Ar("Ar", m_mesh.numberOfNodes()),
-        m_inv_Ar("inv_Ar", m_mesh.numberOfNodes()),
+        m_Ar(m_connectivity),
+        m_inv_Ar(m_connectivity),
         m_Fjr(m_connectivity),
-        m_ur("ur", m_mesh.numberOfNodes()),
-        m_rhocj("rho_c", m_mesh.numberOfCells()),
-        m_Vj_over_cj("Vj_over_cj", m_mesh.numberOfCells())
+        m_ur(m_connectivity),
+        m_rhocj(m_connectivity),
+        m_Vj_over_cj(m_connectivity)
   {
     ;
   }
 
   KOKKOS_INLINE_FUNCTION
-  double acoustic_dt(const Kokkos::View<const double*>& Vj,
-                     const Kokkos::View<const double*>& cj) const
+  double acoustic_dt(const CellValue<const double>& Vj,
+                     const CellValue<const double>& cj) const
   {
-    const NodeValuePerCell<double>& ljr = m_mesh_data.ljr();
+    const NodeValuePerCell<const double>& ljr = m_mesh_data.ljr();
     const auto& cell_to_node_matrix
-        = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                          ItemType::node);
+        = m_mesh.connectivity().cellToNodeMatrix();
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-        const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        const auto& cell_nodes = cell_to_node_matrix[j];
 
         double S = 0;
-        for (size_t r=0; r<cell_nodes.length; ++r) {
+        for (size_t r=0; r<cell_nodes.size(); ++r) {
           S += ljr(j,r);
         }
         m_Vj_over_cj[j] = 2*Vj[j]/(S*cj[j]);
       });
 
-    double dt = std::numeric_limits<double>::max();
-    Kokkos::parallel_reduce(m_mesh.numberOfCells(), ReduceMin(m_Vj_over_cj), dt);
-
-    return dt;
+    return ReduceMin(m_Vj_over_cj);
   }
 
-
   void computeNextStep(const double& t, const double& dt,
                        UnknownsType& unknowns)
   {
-    Kokkos::View<double*> rhoj = unknowns.rhoj();
-    Kokkos::View<Rd*> uj = unknowns.uj();
-    Kokkos::View<double*> Ej = unknowns.Ej();
-
-    Kokkos::View<double*> ej = unknowns.ej();
-    Kokkos::View<double*> pj = unknowns.pj();
-    Kokkos::View<double*> gammaj = unknowns.gammaj();
-    Kokkos::View<double*> cj = unknowns.cj();
-
-    const Kokkos::View<const Rd*> xj = m_mesh_data.xj();
-    const Kokkos::View<const double*> Vj = m_mesh_data.Vj();
-    const NodeValuePerCell<Rd>& Cjr = m_mesh_data.Cjr();
-    const NodeValuePerCell<double>& ljr = m_mesh_data.ljr();
-    const NodeValuePerCell<Rd>& njr = m_mesh_data.njr();
-    Kokkos::View<Rd*> xr = m_mesh.xr();
+    CellValue<double>& rhoj = unknowns.rhoj();
+    CellValue<Rd>& uj = unknowns.uj();
+    CellValue<double>& Ej = unknowns.Ej();
+
+    CellValue<double>& ej = unknowns.ej();
+    CellValue<double>& pj = unknowns.pj();
+    CellValue<double>& cj = unknowns.cj();
+
+    const CellValue<const Rd>& xj = m_mesh_data.xj();
+    const CellValue<const double>& Vj = m_mesh_data.Vj();
+    const NodeValuePerCell<const Rd>& Cjr = m_mesh_data.Cjr();
+    const NodeValuePerCell<const double>& ljr = m_mesh_data.ljr();
+    const NodeValuePerCell<const Rd>& njr = m_mesh_data.njr();
+    const NodeValue<const Rd>& xr = m_mesh.xr();
 
     computeExplicitFluxes(xr, xj, rhoj, uj, pj, cj, Vj, Cjr, ljr, njr);
 
     const NodeValuePerCell<Rd>& Fjr = m_Fjr;
-    const Kokkos::View<const Rd*> ur = m_ur;
+    const NodeValue<const Rd> ur = m_ur;
     const auto& cell_to_node_matrix
-        = m_mesh.connectivity().getMatrix(ItemType::cell,
-                                          ItemType::node);
+        = m_mesh.connectivity().cellToNodeMatrix();
 
-    const Kokkos::View<const double*> inv_mj = unknowns.invMj();
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
-        const auto& cell_nodes = cell_to_node_matrix.rowConst(j);
+    const CellValue<const double> inv_mj = unknowns.invMj();
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j) {
+        const auto& cell_nodes = cell_to_node_matrix[j];
 
         Rd momentum_fluxes = zero;
         double energy_fluxes = 0;
-        for (size_t R=0; R<cell_nodes.length; ++R) {
-          const unsigned int r=cell_nodes(R);
+        for (size_t R=0; R<cell_nodes.size(); ++R) {
+          const NodeId r=cell_nodes[R];
           momentum_fluxes +=  Fjr(j,R);
           energy_fluxes   += (Fjr(j,R), ur[r]);
         }
@@ -353,18 +311,18 @@ class AcousticSolver
         Ej[j] -= (dt*inv_mj[j]) * energy_fluxes;
       });
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j) {
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j) {
         ej[j] = Ej[j] - 0.5 * (uj[j],uj[j]);
       });
 
-    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const int& r){
-        xr[r] += dt*ur[r];
+    NodeValue<Rd> mutable_xr = m_mesh.mutableXr();
+    Kokkos::parallel_for(m_mesh.numberOfNodes(), KOKKOS_LAMBDA(const NodeId& r){
+        mutable_xr[r] += dt*ur[r];
       });
-
     m_mesh_data.updateAllData();
 
-    const Kokkos::View<const double*> mj = unknowns.mj();
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
+    const CellValue<const double> mj = unknowns.mj();
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
         rhoj[j] = mj[j]/Vj[j];
       });
   }
diff --git a/src/scheme/BlockPerfectGas.hpp b/src/scheme/BlockPerfectGas.hpp
index c018399e5d0644762a2474f3a99da6de20f82ffa..704787756bc97ac60b48699c8215c9444cb87bf2 100644
--- a/src/scheme/BlockPerfectGas.hpp
+++ b/src/scheme/BlockPerfectGas.hpp
@@ -1,58 +1,60 @@
 #ifndef BLOCK_PERFECTGAS_HPP
 #define BLOCK_PERFECTGAS_HPP
 
+#include <ItemValue.hpp>
+
 struct BlockPerfectGas
 {
 private:
-  Kokkos::View<double*> m_rhoj;
-  Kokkos::View<double*> m_ej;
-  Kokkos::View<double*> m_pj;
-  Kokkos::View<double*> m_gammaj;
-  Kokkos::View<double*> m_cj;
+  CellValue<double>& m_rhoj;
+  CellValue<double>& m_ej;
+  CellValue<double>& m_pj;
+  CellValue<double>& m_gammaj;
+  CellValue<double>& m_cj;
 
 public:
-  BlockPerfectGas(Kokkos::View<double*> rhoj,
-		 Kokkos::View<double*> ej,
-		 Kokkos::View<double*> pj,
-		 Kokkos::View<double*> gammaj,
-		 Kokkos::View<double*> cj)
-    : m_rhoj(rhoj),
-      m_ej(ej),
-      m_pj(pj),
-      m_gammaj(gammaj),
-      m_cj(cj)
+  BlockPerfectGas(CellValue<double>& rhoj,
+                  CellValue<double>& ej,
+                  CellValue<double>& pj,
+                  CellValue<double>& gammaj,
+                  CellValue<double>& cj)
+      : m_rhoj(rhoj),
+        m_ej(ej),
+        m_pj(pj),
+        m_gammaj(gammaj),
+        m_cj(cj)
   {
     ;
   }
 
   void updatePandCFromRhoE()
   {
-    const int nj = m_ej.size();
-    const Kokkos::View<const double*> rho = m_rhoj;
-    const Kokkos::View<const double*> e = m_ej;
-    const Kokkos::View<const double*> gamma = m_gammaj;
-
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	const double gamma_minus_one = gamma[j]-1;
-	m_pj[j] = gamma_minus_one*rho[j]*e[j];
-	m_cj[j] = std::sqrt(gamma[j]*gamma_minus_one*e[j]);
+    const size_t nj = m_ej.size();
+    const CellValue<const double>& rho = m_rhoj;
+    const CellValue<const double>& e = m_ej;
+    const CellValue<const double>& gamma = m_gammaj;
+
+    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const CellId& j){
+        const double gamma_minus_one = gamma[j]-1;
+        m_pj[j] = gamma_minus_one*rho[j]*e[j];
+        m_cj[j] = std::sqrt(gamma[j]*gamma_minus_one*e[j]);
       });
   }
 
   void updateEandCFromRhoP()
   {
-    const int nj = m_ej.size();
-    const Kokkos::View<const double*> rho = m_rhoj;
-    const Kokkos::View<const double*> p = m_pj;
-    const Kokkos::View<const double*> gamma = m_gammaj;
+    const size_t nj = m_ej.size();
+    const CellValue<const double>& rho = m_rhoj;
+    const CellValue<const double>& p = m_pj;
+    const CellValue<const double>& gamma = m_gammaj;
 
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	m_ej[j] = p[j]/(rho[j]*(gamma[j]-1));
+    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const CellId& j){
+        m_ej[j] = p[j]/(rho[j]*(gamma[j]-1));
       });
 
-    const Kokkos::View<const double*> e = m_ej;
-    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const int& j){
-	m_cj[j] = std::sqrt(gamma[j]*(gamma[j]-1)*e[j]);
+    const CellValue<const double>& e = m_ej;
+    Kokkos::parallel_for(nj, KOKKOS_LAMBDA(const CellId& j){
+        m_cj[j] = std::sqrt(gamma[j]*(gamma[j]-1)*e[j]);
       });
   }
 };
diff --git a/src/scheme/BoundaryCondition.hpp b/src/scheme/BoundaryCondition.hpp
index c59eae3d347d6354a6772c3c2001bfbf412595d5..8747cb0c5cff48ca787e4186638cb03902966ca7 100644
--- a/src/scheme/BoundaryCondition.hpp
+++ b/src/scheme/BoundaryCondition.hpp
@@ -4,7 +4,7 @@
 #include <vector>
 #include <memory>
 
-#include <Kokkos_Core.hpp>
+#include <Array.hpp>
 
 #include <RefNodeList.hpp>
 #include <MeshNodeBoundary.hpp>
@@ -44,7 +44,7 @@ private:
   const double m_value;
 
   const size_t m_number_of_faces;
-  Kokkos::View<unsigned int*> m_face_list;
+  Array<const unsigned int> m_face_list;
 
 public:
   double value() const
@@ -57,7 +57,7 @@ public:
     return m_number_of_faces;
   }
 
-  const Kokkos::View<const unsigned int*> faceList() const
+  const Array<const unsigned int>& faceList() const
   {
     return m_face_list;
   }
@@ -66,12 +66,13 @@ public:
                             const std::vector<unsigned int>& faces)
     : BoundaryCondition(BoundaryCondition::pressure),
       m_value(value),
-      m_number_of_faces(faces.size()),
-      m_face_list("faces_list", m_number_of_faces)
+      m_number_of_faces(faces.size())
   {
+    Array<unsigned int> face_list(faces.size());
     Kokkos::parallel_for(m_number_of_faces, KOKKOS_LAMBDA(const int& f){
-        m_face_list[f]=faces[f];
+        face_list[f]=faces[f];
       });
+    m_face_list = face_list;
   }
 
   ~PressureBoundaryCondition() = default;
@@ -82,7 +83,7 @@ class SymmetryBoundaryCondition
   : public BoundaryCondition
 {
 public:
-  typedef TinyVector<dimension, double> Rd;
+  using Rd = TinyVector<dimension, double>;
 
 private:
 
@@ -95,10 +96,10 @@ public:
 
   size_t numberOfNodes() const
   {
-    return m_mesh_flat_node_boundary.nodeList().extent(0);
+    return m_mesh_flat_node_boundary.nodeList().size();
   }
 
-  const Kokkos::View<const unsigned int*> nodeList() const
+  const Array<const NodeId>& nodeList() const
   {
     return m_mesh_flat_node_boundary.nodeList();
   }
diff --git a/src/scheme/FiniteVolumesEulerUnknowns.hpp b/src/scheme/FiniteVolumesEulerUnknowns.hpp
index 617cb8b39759dcf4ae4ff6f4a41f09a7bc056584..2eaaf474dbbe520da30cc2c5b0ad5b4737e12538 100644
--- a/src/scheme/FiniteVolumesEulerUnknowns.hpp
+++ b/src/scheme/FiniteVolumesEulerUnknowns.hpp
@@ -1,179 +1,182 @@
 #ifndef FINITE_VOLUMES_EULER_UNKNOWNS_HPP
 #define FINITE_VOLUMES_EULER_UNKNOWNS_HPP
 
+#include <TinyVector.hpp>
+#include <ItemValue.hpp>
+
 template <typename TMeshData>
 class FiniteVolumesEulerUnknowns
 {
 public:
-  typedef TMeshData MeshDataType;
-  typedef typename MeshDataType::MeshType MeshType;
+  using MeshDataType = TMeshData;
+  using MeshType = typename MeshDataType::MeshType;
 
   static constexpr size_t dimension = MeshType::dimension;
-  typedef TinyVector<dimension> Rd;
+  using Rd = TinyVector<dimension>;
 
 private:
   const MeshDataType& m_mesh_data;
   const MeshType& m_mesh;
 
-  Kokkos::View<double*> m_rhoj;
-  Kokkos::View<Rd*> m_uj;
-  Kokkos::View<double*> m_Ej;
+  CellValue<double> m_rhoj;
+  CellValue<Rd> m_uj;
+  CellValue<double> m_Ej;
 
-  Kokkos::View<double*> m_ej;
-  Kokkos::View<double*> m_pj;
-  Kokkos::View<double*> m_gammaj;
-  Kokkos::View<double*> m_cj;
-  Kokkos::View<double*> m_mj;
-  Kokkos::View<double*> m_inv_mj;
+  CellValue<double> m_ej;
+  CellValue<double> m_pj;
+  CellValue<double> m_gammaj;
+  CellValue<double> m_cj;
+  CellValue<double> m_mj;
+  CellValue<double> m_inv_mj;
 
 public:
-  Kokkos::View<double*> rhoj()
+  CellValue<double>& rhoj()
   {
     return m_rhoj;
   }
 
-  const Kokkos::View<const double*> rhoj() const
+  const CellValue<const double> rhoj() const
   {
     return m_rhoj;
   }
 
-  Kokkos::View<Rd*> uj()
+  CellValue<Rd>& uj()
   {
     return m_uj;
   }
 
-  const Kokkos::View<const Rd*> uj() const
+  const CellValue<const Rd> uj() const
   {
     return m_uj;
   }
 
-  Kokkos::View<double*> Ej()
+  CellValue<double>& Ej()
   {
     return m_Ej;
   }
 
-  const Kokkos::View<const double*> Ej() const
+  const CellValue<const double> Ej() const
   {
     return m_Ej;
   }
 
-  Kokkos::View<double*> ej()
+  CellValue<double>& ej()
   {
     return m_ej;
   }
 
-  const Kokkos::View<const double*> ej() const
+  const CellValue<const double> ej() const
   {
     return m_ej;
   }
 
-  Kokkos::View<double*> pj()
+  CellValue<double>& pj()
   {
     return m_pj;
   }
 
-  const Kokkos::View<const double*> pj() const
+  const CellValue<const double> pj() const
   {
     return m_pj;
   }
 
-  Kokkos::View<double*> gammaj()
+  CellValue<double>& gammaj()
   {
     return m_gammaj;
   }
 
-  const Kokkos::View<const double*> gammaj() const
+  const CellValue<const double> gammaj() const
   {
     return m_gammaj;
   }
 
-  Kokkos::View<double*> cj()
+  CellValue<double>& cj()
   {
     return m_cj;
   }
 
-  const Kokkos::View<const double*> cj() const
+  const CellValue<const double> cj() const
   {
     return m_cj;
   }
 
-  Kokkos::View<double*> mj()
+  CellValue<double>& mj()
   {
     return m_mj;
   }
 
-  const Kokkos::View<const double*> mj() const
+  const CellValue<const double> mj() const
   {
     return m_mj;
   }
 
-  Kokkos::View<double*> invMj()
+  CellValue<double>& invMj()
   {
     return m_inv_mj;
   }
 
-  const Kokkos::View<const double*> invMj() const
+  const CellValue<const double> invMj() const
   {
     return m_inv_mj;
   }
 
   void initializeSod()
   {
-    const Kokkos::View<const Rd*> xj = m_mesh_data.xj();
+    const CellValue<const Rd>& xj = m_mesh_data.xj();
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-	if (xj[j][0]<0.5) {
-	  m_rhoj[j]=1;
-	} else {
-	  m_rhoj[j]=0.125;
-	}
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        if (xj[j][0]<0.5) {
+          m_rhoj[j]=1;
+        } else {
+          m_rhoj[j]=0.125;
+        }
       });
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-	if (xj[j][0]<0.5) {
-	  m_pj[j]=1;
-	} else {
-	  m_pj[j]=0.1;
-	}
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        if (xj[j][0]<0.5) {
+          m_pj[j]=1;
+        } else {
+          m_pj[j]=0.1;
+        }
       });
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-	m_uj[j] = zero;
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        m_uj[j] = zero;
       });
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-	m_gammaj[j] = 1.4;
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        m_gammaj[j] = 1.4;
       });
 
     BlockPerfectGas block_eos(m_rhoj, m_ej, m_pj, m_gammaj, m_cj);
     block_eos.updateEandCFromRhoP();
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-	m_Ej[j] = m_ej[j]+0.5*(m_uj[j],m_uj[j]);
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        m_Ej[j] = m_ej[j]+0.5*(m_uj[j],m_uj[j]);
       });
 
-    const Kokkos::View<const double*> Vj = m_mesh_data.Vj();
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-	m_mj[j] = m_rhoj[j] * Vj[j];
+    const CellValue<const double>& Vj = m_mesh_data.Vj();
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        m_mj[j] = m_rhoj[j] * Vj[j];
       });
 
-    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const int& j){
-	m_inv_mj[j] = 1./m_mj[j];
+    Kokkos::parallel_for(m_mesh.numberOfCells(), KOKKOS_LAMBDA(const CellId& j){
+        m_inv_mj[j] = 1./m_mj[j];
       });
   }
 
   FiniteVolumesEulerUnknowns(const MeshDataType& mesh_data)
     : m_mesh_data(mesh_data),
       m_mesh(m_mesh_data.mesh()),
-      m_rhoj("rhoj",m_mesh.numberOfCells()),
-      m_uj("uj",m_mesh.numberOfCells()),
-      m_Ej("Ej",m_mesh.numberOfCells()),
-      m_ej("ej",m_mesh.numberOfCells()),
-      m_pj("pj",m_mesh.numberOfCells()),
-      m_gammaj("gammaj",m_mesh.numberOfCells()),
-      m_cj("cj",m_mesh.numberOfCells()),
-      m_mj("mj",m_mesh.numberOfCells()),
-      m_inv_mj("inv_mj",m_mesh.numberOfCells())
+      m_rhoj(m_mesh.connectivity()),
+      m_uj(m_mesh.connectivity()),
+      m_Ej(m_mesh.connectivity()),
+      m_ej(m_mesh.connectivity()),
+      m_pj(m_mesh.connectivity()),
+      m_gammaj(m_mesh.connectivity()),
+      m_cj(m_mesh.connectivity()),
+      m_mj(m_mesh.connectivity()),
+      m_inv_mj(m_mesh.connectivity())
   {
     ;
   }
diff --git a/src/utils/Array.hpp b/src/utils/Array.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e72efb042c5c9006960a15dfd20c87ed29c29d82
--- /dev/null
+++ b/src/utils/Array.hpp
@@ -0,0 +1,83 @@
+#ifndef ARRAY_HPP
+#define ARRAY_HPP
+
+#include <PastisAssert.hpp>
+#include <Kokkos_Core.hpp>
+
+template <typename DataType>
+class Array
+{
+ public:
+  using data_type = DataType;
+  using index_type = size_t;
+
+ private:
+  Kokkos::View<DataType*> m_values;
+
+  // Allows const version to access our data
+  friend Array<std::add_const_t<DataType>>;
+
+ public:
+  KOKKOS_INLINE_FUNCTION
+  size_t size() const
+  {
+    return m_values.extent(0);
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  DataType& operator[](const index_type& i) const
+  {
+    Assert(i<m_values.extent(0));
+    return m_values[i];
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  Array(const size_t& size)
+      : m_values("anonymous", size)
+  {
+    static_assert(not std::is_const<DataType>(),
+                  "Cannot allocate Array of const data: only view is supported");
+  }
+
+  template <typename DataType2>
+  KOKKOS_INLINE_FUNCTION
+  Array& operator=(const Array<DataType2>& array)
+  {
+    // ensures that DataType is the same as source DataType2
+    static_assert(std::is_same<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>(),
+                  "Cannot assign Array of different type");
+    // ensures that const is not lost through copy
+    static_assert(((std::is_const<DataType2>() and std::is_const<DataType>())
+                   or not std::is_const<DataType2>()),
+                  "Cannot assign Array of const to  Array of non-const");
+    m_values = array.m_values;
+    return *this;
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  Array& operator=(const Array&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  Array& operator=(Array&&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  Array() = default;
+
+  template <typename DataType2>
+  KOKKOS_INLINE_FUNCTION
+  Array(const Array<DataType2>& array)
+  {
+    this->operator=(array);
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  Array(Array&&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  Array(const Array&) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  ~Array() = default;
+};
+
+#endif // ARRAY_HPP
diff --git a/src/utils/ArrayUtils.hpp b/src/utils/ArrayUtils.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9a55abfebde94b4ab53adff473c52907ec5385f8
--- /dev/null
+++ b/src/utils/ArrayUtils.hpp
@@ -0,0 +1,109 @@
+#ifndef ARRAY_UTILS_HPP
+#define ARRAY_UTILS_HPP
+
+#include <Kokkos_Core.hpp>
+
+template <typename ArrayType>
+class ReduceMin
+{
+ private:
+  const ArrayType& m_array;
+  using data_type = std::remove_const_t<typename ArrayType::data_type>;
+  using index_type = typename ArrayType::index_type;
+
+ public:
+  KOKKOS_INLINE_FUNCTION
+  operator data_type()
+  {
+    data_type reduced_value;
+    Kokkos::parallel_reduce(m_array.size(), *this, reduced_value);
+    return reduced_value;
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  void operator()(const index_type& i, data_type& data) const
+  {
+    if (m_array[i] < data) {
+      data = m_array[i];
+    }
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  void join(volatile data_type& dst,
+            const volatile data_type& src) const
+  {
+    if (src < dst) {
+      dst = src;
+    }
+  }
+
+  KOKKOS_INLINE_FUNCTION void
+  init(data_type& value) const
+  {
+    value = std::numeric_limits<data_type>::max();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  ReduceMin(const ArrayType& array)
+      : m_array(array)
+  {
+    ;
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  ~ReduceMin() = default;
+};
+
+
+template <typename ArrayType>
+class ReduceMax
+{
+ private:
+  const ArrayType& m_array;
+  using data_type = std::remove_const_t<typename ArrayType::data_type>;
+  using index_type = typename ArrayType::index_type;
+
+ public:
+  KOKKOS_INLINE_FUNCTION
+  operator data_type()
+  {
+    data_type reduced_value;
+    Kokkos::parallel_reduce(m_array.size(), *this, reduced_value);
+    return reduced_value;
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  void operator()(const index_type& i, data_type& data) const
+  {
+    if (m_array[i] > data) {
+      data = m_array[i];
+    }
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  void join(volatile data_type& dst,
+            const volatile data_type& src) const
+  {
+    if (src > dst) {
+      dst = src;
+    }
+  }
+
+  KOKKOS_INLINE_FUNCTION void
+  init(data_type& value) const
+  {
+    value = -std::numeric_limits<data_type>::max();
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  ReduceMax(const ArrayType& array)
+      : m_array(array)
+  {
+    ;
+  }
+
+  KOKKOS_INLINE_FUNCTION
+  ~ReduceMax() = default;
+};
+
+#endif //ARRAY_UTILS_HPP
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3b4823f1eaa5d56c7bb2a7e7201d623e8308d60a..c36e9a2d570b0a385e679904a61dd3b260c25cd8 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -4,6 +4,8 @@ set(EXECUTABLE_OUTPUT_PATH ${PASTIS_BINARY_DIR})
 
 add_executable (unit_tests
   test_main.cpp
+  test_Array.cpp
+  test_ArrayUtils.cpp
   test_ItemType.cpp
   test_PastisAssert.cpp
   test_RevisionInfo.cpp
@@ -15,6 +17,7 @@ target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
 
 target_link_libraries (unit_tests
   PastisUtils
+  kokkos
   Catch
   )
 
diff --git a/tests/test_Array.cpp b/tests/test_Array.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6cd02146c8775dca7a061672b8efed1fbdcad236
--- /dev/null
+++ b/tests/test_Array.cpp
@@ -0,0 +1,87 @@
+#include <catch.hpp>
+
+#include <PastisAssert.hpp>
+#include <Array.hpp>
+#include <Types.hpp>
+
+// Instantiate to ensure full coverage is performed
+template class Array<int>;
+
+TEST_CASE("Array", "[utils]") {
+
+  Array<int> a(10);
+  REQUIRE(a.size() == 10);
+
+  for (size_t i=0; i<a.size(); ++i) {
+    a[i] = 2*i;
+  }
+
+  REQUIRE(((a[0] == 0) and (a[1] == 2) and
+           (a[2] == 4) and (a[3] == 6) and
+           (a[4] == 8) and (a[5] ==10) and
+           (a[6] ==12) and (a[7] ==14) and
+           (a[8] ==16) and (a[9] ==18)));
+
+  SECTION("checking for copies") {
+    Array<const int> b{a};
+
+    REQUIRE(((b[0] == 0) and (b[1] == 2) and
+             (b[2] == 4) and (b[3] == 6) and
+             (b[4] == 8) and (b[5] ==10) and
+             (b[6] ==12) and (b[7] ==14) and
+             (b[8] ==16) and (b[9] ==18)));
+
+    Array<int> c{a};
+
+    REQUIRE(((c[0] == 0) and (c[1] == 2) and
+             (c[2] == 4) and (c[3] == 6) and
+             (c[4] == 8) and (c[5] ==10) and
+             (c[6] ==12) and (c[7] ==14) and
+             (c[8] ==16) and (c[9] ==18)));
+
+
+    Array<int> d = std::move(c);
+
+    REQUIRE(((d[0] == 0) and (d[1] == 2) and
+             (d[2] == 4) and (d[3] == 6) and
+             (d[4] == 8) and (d[5] ==10) and
+             (d[6] ==12) and (d[7] ==14) and
+             (d[8] ==16) and (d[9] ==18)));
+
+  }
+
+  SECTION("checking for affectations") {
+    Array<const int> b;
+    b = a;
+
+    REQUIRE(((b[0] == 0) and (b[1] == 2) and
+             (b[2] == 4) and (b[3] == 6) and
+             (b[4] == 8) and (b[5] ==10) and
+             (b[6] ==12) and (b[7] ==14) and
+             (b[8] ==16) and (b[9] ==18)));
+
+
+    Array<int> c;
+    c = a;
+
+    REQUIRE(((c[0] == 0) and (c[1] == 2) and
+             (c[2] == 4) and (c[3] == 6) and
+             (c[4] == 8) and (c[5] ==10) and
+             (c[6] ==12) and (c[7] ==14) and
+             (c[8] ==16) and (c[9] ==18)));
+
+    Array<int> d;
+    d = std::move(c);
+
+    REQUIRE(((d[0] == 0) and (d[1] == 2) and
+             (d[2] == 4) and (d[3] == 6) and
+             (d[4] == 8) and (d[5] ==10) and
+             (d[6] ==12) and (d[7] ==14) and
+             (d[8] ==16) and (d[9] ==18)));
+  }
+#ifndef NDEBUG
+  SECTION("checking for bounds violation") {
+    REQUIRE_THROWS_AS(a[10], AssertError);
+  }
+#endif // NDEBUG
+}
diff --git a/tests/test_ArrayUtils.cpp b/tests/test_ArrayUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8183e7157a2c39d3f27b3fbd703917fcdf567ff1
--- /dev/null
+++ b/tests/test_ArrayUtils.cpp
@@ -0,0 +1,96 @@
+#include <catch.hpp>
+
+#include <PastisAssert.hpp>
+#include <Array.hpp>
+#include <ArrayUtils.hpp>
+
+// Instantiate to ensure full coverage is performed
+template class Array<int>;
+
+TEST_CASE("ArrayUtils", "[utils]") {
+
+  SECTION("checking for reductions") {
+    using ArrayType = Array<int>;
+    using data_type = ArrayType::data_type;
+
+    Array<int> a(10);
+    a[0] =13;
+    a[1] = 1;
+    a[2] = 8;
+    a[3] =-3;
+    a[4] =23;
+    a[5] =-1;
+    a[6] =13;
+    a[7] = 0;
+    a[8] =12;
+    a[9] = 9;
+
+    SECTION("ReduceMin") {
+      ReduceMin r_min(a);
+      data_type data;
+
+      r_min.init(data);
+      REQUIRE(data == std::numeric_limits<data_type>::max());
+
+      r_min(2,data);
+      REQUIRE(data == 8);
+
+      r_min(9,data);
+      REQUIRE(data == 8);
+
+      r_min(5,data);
+      REQUIRE(data == -1);
+
+      {
+        data = 0;
+        data_type r_value{3};
+        r_min.join(data, r_value);
+        REQUIRE(data == 0);
+      }
+
+      {
+        data = 0;
+        data_type r_value{-5};
+        r_min.join(data, r_value);
+        REQUIRE(data == -5);
+      }
+
+      REQUIRE((r_min == -3));
+
+      REQUIRE((ReduceMin(a) == -3));
+    }
+
+    SECTION("ReduceMax") {
+      ReduceMax r_max(a);
+      data_type data;
+
+      r_max.init(data);
+      REQUIRE(data == -std::numeric_limits<data_type>::max());
+
+      r_max(3,data);
+      REQUIRE(data == -3);
+      r_max(5,data);
+      REQUIRE(data == -1);
+      r_max(8,data);
+      REQUIRE(data == 12);
+
+      {
+        data = 0;
+        data_type r_value{3};
+        r_max.join(data, r_value);
+        REQUIRE(data == 3);
+      }
+
+      {
+        data = 0;
+        data_type r_value{-5};
+        r_max.join(data, r_value);
+        REQUIRE(data == 0);
+      }
+
+      REQUIRE((r_max == 23));
+
+      REQUIRE((ReduceMax(a) == 23));
+    }
+  }
+}
diff --git a/tests/test_ItemType.cpp b/tests/test_ItemType.cpp
index 7c39963613dd3bae8d60e5fb4c9a4b0915ce6343..096dbdaf5b8a85099c8ec892a15c7f6ceb1000ca 100644
--- a/tests/test_ItemType.cpp
+++ b/tests/test_ItemType.cpp
@@ -26,23 +26,23 @@ TEST_CASE("ItemType", "[connectivity]") {
   }
 
   SECTION("checking for item ids in 1d") {
-    REQUIRE(ItemId<1>::itemId(cell_type)==0);
-    REQUIRE(ItemId<1>::itemId(edge_type)==1);
-    REQUIRE(ItemId<1>::itemId(face_type)==1);
-    REQUIRE(ItemId<1>::itemId(node_type)==1);
+    REQUIRE(ItemTypeId<1>::itemTId(cell_type)==0);
+    REQUIRE(ItemTypeId<1>::itemTId(edge_type)==1);
+    REQUIRE(ItemTypeId<1>::itemTId(face_type)==1);
+    REQUIRE(ItemTypeId<1>::itemTId(node_type)==1);
   }
 
   SECTION("checking for item ids in 2d") {
-    REQUIRE(ItemId<2>::itemId(cell_type)==0);
-    REQUIRE(ItemId<2>::itemId(edge_type)==1);
-    REQUIRE(ItemId<2>::itemId(face_type)==1);
-    REQUIRE(ItemId<2>::itemId(node_type)==2);
+    REQUIRE(ItemTypeId<2>::itemTId(cell_type)==0);
+    REQUIRE(ItemTypeId<2>::itemTId(edge_type)==1);
+    REQUIRE(ItemTypeId<2>::itemTId(face_type)==1);
+    REQUIRE(ItemTypeId<2>::itemTId(node_type)==2);
   }
 
   SECTION("checking for item ids in 3d") {
-    REQUIRE(ItemId<3>::itemId(cell_type)==0);
-    REQUIRE(ItemId<3>::itemId(edge_type)==1);
-    REQUIRE(ItemId<3>::itemId(face_type)==2);
-    REQUIRE(ItemId<3>::itemId(node_type)==3);
+    REQUIRE(ItemTypeId<3>::itemTId(cell_type)==0);
+    REQUIRE(ItemTypeId<3>::itemTId(edge_type)==1);
+    REQUIRE(ItemTypeId<3>::itemTId(face_type)==2);
+    REQUIRE(ItemTypeId<3>::itemTId(node_type)==3);
   }
 }
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index b3143fbb1788b7daef8a6cc20d8a0e9bafb308a5..98ed156f241538f4f0f47e967576a190ad949cf5 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -1,2 +1,15 @@
-#define CATCH_CONFIG_MAIN
+#define CATCH_CONFIG_RUNNER
 #include <catch.hpp>
+
+#include <Kokkos_Core.hpp>
+
+int main( int argc, char* argv[] )
+{
+  Kokkos::initialize({4,-1,-1,true});
+
+  int result = Catch::Session().run( argc, argv );
+
+  Kokkos::finalize();
+
+  return result;
+}