diff --git a/bfps/cpp/particles/NavierStokes-v2.0.1-single-particles.cpp b/bfps/cpp/particles/NavierStokes-v2.0.1-single-particles.cpp
index b6cd2a11d3a6521764538274faec23b31a65b53b..8bf93750d8676276f387c4caf4c0e28ad54fe4db 100644
--- a/bfps/cpp/particles/NavierStokes-v2.0.1-single-particles.cpp
+++ b/bfps/cpp/particles/NavierStokes-v2.0.1-single-particles.cpp
@@ -545,7 +545,7 @@ int main(int argc, char *argv[])
         //        ps0->read();
 
         // Interpolator size
-        const int InterpNbNeighbors = 5;
+        const int InterpNbNeighbors = 1; // start with one and then use 2 or 3
 
         // Only the Z grid
         const std::array<size_t,3> field_grid_dim{nx,ny,nz};
@@ -553,7 +553,7 @@ int main(int argc, char *argv[])
         const int myPartitionInterval[2] = {fs->cvelocity->rlayout->start[0],
                                             fs->cvelocity->rlayout->start[0] + fs->cvelocity->rlayout->subsizes[0]};
 
-        const std::array<double,3> spatial_box_width{dkx, dky, dkz};
+        const std::array<double,3> spatial_box_width{2PI/dkx, 2PI/dky, 2PI/dkz};
         const double spatial_partition_width = spatial_box_width/double(field_grid_dim);
         const double my_spatial_low_limit = myPartitionInterval[0]*spatial_partition_width;
         const double my_spatial_up_limit = myPartitionInterval[1]*spatial_partition_width;
diff --git a/bfps/cpp/particles/abstract_particle_system.hpp b/bfps/cpp/particles/abstract_particle_system.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7ffee82f17cd1200eba1b680be9f6bb3074b8bf8
--- /dev/null
+++ b/bfps/cpp/particles/abstract_particle_system.hpp
@@ -0,0 +1,27 @@
+#ifndef ABSTRACT_PARTICLE_SYSTEM_HPP
+#define ABSTRACT_PARTICLE_SYSTEM_HPP
+
+class abstract_particle_system {
+public:
+    virtual void compute() = 0;
+
+    virtual void move(const double dt) = 0;
+
+    virtual void redistribute() = 0;
+
+    virtual void inc_step_idx() = 0;
+
+    virtual void shift_rhs_vectors() = 0;
+
+    virtual void completeLoop(const double dt) = 0;
+
+    virtual const double* getParticlesPositions() const = 0;
+
+    virtual const double* getParticlesCurrentRhs() const = 0;
+
+    virtual const int* getParticlesIndexes() const = 0;
+
+    virtual int getLocalNbParticles() const = 0;
+};
+
+#endif
diff --git a/bfps/cpp/particles/abstract_particles_distr.hpp b/bfps/cpp/particles/abstract_particles_distr.hpp
index 1e6508cb359bcfa8fb7dd7a5bbbacd71f3498673..0cf7147c23c842b569b1dca7c66ae1ddf46db82f 100644
--- a/bfps/cpp/particles/abstract_particles_distr.hpp
+++ b/bfps/cpp/particles/abstract_particles_distr.hpp
@@ -431,7 +431,7 @@ public:
         // Find particles outside my interval
         const int nbOutLower = particles_utils::partition_extra<size_particle_positions>(&(*inout_positions_particles)[0], current_my_nb_particles_per_partition[0],
                     [&](const double val[]){
-            const bool isLower = val[2] < mySpatialLowLimit;
+            const bool isLower = val[IDX_Z] < mySpatialLowLimit;
             return isLower;
         },
                     [&](const int idx1, const int idx2){
@@ -454,7 +454,7 @@ public:
                     &(*inout_positions_particles)[(current_offset_particles_for_partition[current_partition_size-1]+offesetOutLow)*size_particle_positions],
                     myTotalNbParticles - (current_offset_particles_for_partition[current_partition_size-1]+offesetOutLow),
                     [&](const double val[]){
-            const bool isUpper = mySpatialUpLimit <= val[2];
+            const bool isUpper = mySpatialUpLimit <= val[IDX_Z];
             return !isUpper;
         },
                     [&](const int idx1, const int idx2){
@@ -578,7 +578,7 @@ public:
                                   MPI_COMM_WORLD, &mpiRequests.back()));
 
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                            newParticlesLowRhs[idx_rhs].reset(new double[nbNewFromLow]);
+                            newParticlesLowRhs[idx_rhs].reset(new double[nbNewFromLow*size_particle_rhs]);
                             whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
                             mpiRequests.emplace_back();
                             AssertMpi(MPI_Irecv(&newParticlesLowRhs[idx_rhs][0], nbNewFromLow*size_particle_rhs, MPI_DOUBLE, (my_rank-1+nb_processes)%nb_processes, TAG_UP_LOW_MOVED_PARTICLES_RHS+idx_rhs,
@@ -605,7 +605,7 @@ public:
                                   MPI_COMM_WORLD, &mpiRequests.back()));
 
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                            newParticlesUpRhs[idx_rhs].reset(new double[nbNewFromUp]);
+                            newParticlesUpRhs[idx_rhs].reset(new double[nbNewFromUp*size_particle_rhs]);
                             whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
                             mpiRequests.emplace_back();
                             AssertMpi(MPI_Irecv(&newParticlesUpRhs[idx_rhs][0], nbNewFromUp*size_particle_rhs, MPI_DOUBLE, (my_rank+1)%nb_processes, TAG_LOW_UP_MOVED_PARTICLES_RHS+idx_rhs,
@@ -650,31 +650,31 @@ public:
             if(myTotalNewNbParticles > myTotalNbParticlesAllocated){
                 DEBUG_MSG("[%d] reuse array\n", my_rank);
                 std::unique_ptr<double[]> newArray(new double[myTotalNewNbParticles*size_particle_positions]);
-                std::unique_ptr<int[]> newArrayIndexes(new int[myTotalNewNbParticles*size_particle_positions]);
+                std::unique_ptr<int[]> newArrayIndexes(new int[myTotalNewNbParticles]);
                 std::vector<std::unique_ptr<double[]>> newArrayRhs(in_nb_rhs);
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                    newArrayRhs[idx_rhs].reset(new double[myTotalNewNbParticles*size_particle_positions]);
+                    newArrayRhs[idx_rhs].reset(new double[myTotalNewNbParticles*size_particle_rhs]);
                 }
 
                 if(nbNewFromLow){
                     memcpy(&newArray[0], &newParticlesLow[0], sizeof(double)*nbNewFromLow*size_particle_positions);
                     memcpy(&newArrayIndexes[0], &newParticlesLowIndexes[0], sizeof(int)*nbNewFromLow);
                     for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                        memcpy(&newArrayRhs[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbNewFromLow);
+                        memcpy(&newArrayRhs[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbNewFromLow*size_particle_rhs);
                     }
                 }
 
                 memcpy(&newArray[nbNewFromLow*size_particle_positions], &(*inout_positions_particles)[nbOutLower*size_particle_positions], sizeof(double)*nbOldParticlesInside*size_particle_positions);
                 memcpy(&newArrayIndexes[nbNewFromLow], &(*inout_positions_particles)[nbOutLower], sizeof(int)*nbOldParticlesInside);
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                    memcpy(&newArrayRhs[idx_rhs][nbNewFromLow], &inout_positions_particles[idx_rhs][nbOutLower], sizeof(double)*nbOldParticlesInside);
+                    memcpy(&newArrayRhs[idx_rhs][nbNewFromLow*size_particle_rhs], &inout_positions_particles[idx_rhs][nbOutLower*size_particle_rhs], sizeof(double)*nbOldParticlesInside*size_particle_rhs);
                 }
 
                 if(nbNewFromUp){
                     memcpy(&newArray[(nbNewFromLow+nbOldParticlesInside)*size_particle_positions], &newParticlesUp[0], sizeof(double)*nbNewFromUp*size_particle_positions);
                     memcpy(&newArrayIndexes[(nbNewFromLow+nbOldParticlesInside)], &newParticlesUpIndexes[0], sizeof(int)*nbNewFromUp);
                     for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                        memcpy(&newArrayRhs[idx_rhs][(nbNewFromLow+nbOldParticlesInside)], &newParticlesUpRhs[idx_rhs][0], sizeof(double)*nbNewFromUp);
+                        memcpy(&newArrayRhs[idx_rhs][(nbNewFromLow+nbOldParticlesInside)*size_particle_rhs], &newParticlesUpRhs[idx_rhs][0], sizeof(double)*nbNewFromUp*size_particle_rhs);
                     }
                 }
 
@@ -695,21 +695,21 @@ public:
                     memcpy(&(*inout_positions_particles)[0], &newParticlesLow[0], sizeof(double)*nbOutLower*size_particle_positions);
                     memcpy(&(*inout_index_particles)[0], &newParticlesLowIndexes[0], sizeof(int)*nbOutLower);
                     for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                        memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbOutLower);
+                        memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbOutLower*size_particle_rhs);
                     }
                 }
                 if(nbNewFromLow){
                     memcpy(&(*inout_positions_particles)[(nbOutLower+nbOldParticlesInside)*size_particle_positions], &newParticlesLow[nbOutLower*size_particle_positions], sizeof(double)*nbLowToMoveBack*size_particle_positions);
                     memcpy(&(*inout_index_particles)[(nbOutLower+nbOldParticlesInside)], &newParticlesLowIndexes[nbOutLower], sizeof(int)*nbLowToMoveBack);
                     for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                        memcpy(&inout_rhs_particles[idx_rhs][(nbOutLower+nbOldParticlesInside)], &newParticlesLowRhs[idx_rhs][nbOutLower], sizeof(double)*nbLowToMoveBack);
+                        memcpy(&inout_rhs_particles[idx_rhs][(nbOutLower+nbOldParticlesInside)*size_particle_rhs], &newParticlesLowRhs[idx_rhs][nbOutLower*size_particle_rhs], sizeof(double)*nbLowToMoveBack*size_particle_rhs);
                     }
                 }
                 if(nbNewFromUp){
                     memcpy(&(*inout_positions_particles)[(nbNewFromLow+nbOldParticlesInside)*size_particle_positions], &newParticlesUp[0], sizeof(double)*nbNewFromUp*size_particle_positions);
                     memcpy(&(*inout_index_particles)[(nbNewFromLow+nbOldParticlesInside)], &newParticlesUpIndexes[0], sizeof(int)*nbNewFromUp);
                     for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                        memcpy(&inout_rhs_particles[idx_rhs][(nbNewFromLow+nbOldParticlesInside)], &newParticlesUpRhs[0], sizeof(double)*nbNewFromUp);
+                        memcpy(&inout_rhs_particles[idx_rhs][(nbNewFromLow+nbOldParticlesInside)*size_particle_rhs], &newParticlesUpRhs[0], sizeof(double)*nbNewFromUp*size_particle_rhs);
                     }
                 }
             }
@@ -721,24 +721,26 @@ public:
                         memcpy(&(*inout_positions_particles)[0], &newParticlesLow[0], sizeof(double)*nbNewFromLow*size_particle_positions);
                         memcpy(&(*inout_index_particles)[0], &newParticlesLowIndexes[0], sizeof(int)*nbNewFromLow);
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                            memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbNewFromLow);
+                            memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbNewFromLow*size_particle_rhs);
                         }
                     }
                     if(nbNewFromUp){
                         memcpy(&(*inout_positions_particles)[nbNewFromLow*size_particle_positions], &newParticlesUp[0], sizeof(double)*nbUpToMoveBegin*size_particle_positions);
                         memcpy(&(*inout_index_particles)[nbNewFromLow], &newParticlesUpIndexes[0], sizeof(int)*nbUpToMoveBegin);
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                            memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbNewFromLow);
+                            memcpy(&inout_rhs_particles[idx_rhs][nbNewFromLow*size_particle_rhs], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbUpToMoveBegin*size_particle_rhs);
                         }
                     }
                     if(nbNewFromUp){
-                        memcpy(&(*inout_positions_particles)[(nbOutLower+nbOldParticlesInside)*size_particle_positions], &newParticlesUp[nbUpToMoveBegin*size_particle_positions],
+                        memcpy(&(*inout_positions_particles)[(nbOutLower+nbOldParticlesInside)*size_particle_positions],
+                                &newParticlesUp[nbUpToMoveBegin*size_particle_positions],
                                         sizeof(double)*(nbNewFromUp-nbUpToMoveBegin)*size_particle_positions);
                         memcpy(&(*inout_index_particles)[(nbOutLower+nbOldParticlesInside)], &newParticlesUpIndexes[nbUpToMoveBegin],
                                         sizeof(int)*(nbNewFromUp-nbUpToMoveBegin));
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                            memcpy(&inout_rhs_particles[idx_rhs][(nbOutLower+nbOldParticlesInside)], &newParticlesUpRhs[idx_rhs][nbUpToMoveBegin],
-                                            sizeof(double)*(nbNewFromUp-nbUpToMoveBegin));
+                            memcpy(&inout_rhs_particles[idx_rhs][(nbOutLower+nbOldParticlesInside)*size_particle_rhs],
+                                   &newParticlesUpRhs[idx_rhs][nbUpToMoveBegin*size_particle_rhs],
+                                   sizeof(double)*(nbNewFromUp-nbUpToMoveBegin)*size_particle_rhs);
                         }
                     }
                 }
@@ -748,14 +750,14 @@ public:
                         memcpy(&(*inout_positions_particles)[0], &newParticlesLow[0], sizeof(double)*nbNewFromLow*size_particle_positions);
                         memcpy(&(*inout_index_particles)[0], &newParticlesLowIndexes[0], sizeof(int)*nbNewFromLow);
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                            memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbNewFromLow);
+                            memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesLowRhs[idx_rhs][0], sizeof(double)*nbNewFromLow*size_particle_rhs);
                         }
                     }
                     if(nbNewFromUp){
                         memcpy(&(*inout_positions_particles)[0], &newParticlesUp[0], sizeof(double)*nbNewFromUp*size_particle_positions);
                         memcpy(&(*inout_index_particles)[0], &newParticlesUpIndexes[0], sizeof(int)*nbNewFromUp);
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                            memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesUpRhs[idx_rhs][0], sizeof(double)*nbNewFromUp);
+                            memcpy(&inout_rhs_particles[idx_rhs][0], &newParticlesUpRhs[idx_rhs][0], sizeof(double)*nbNewFromUp*size_particle_rhs);
                         }
                     }
                     const int padding = nbOutLower - nbNewFromLow+nbNewFromUp;
@@ -766,9 +768,9 @@ public:
                             &(*inout_index_particles)[(nbOutLower+nbOldParticlesInside-padding)],
                             sizeof(int)*padding);
                     for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
-                        memcpy(&inout_rhs_particles[idx_rhs][(nbNewFromLow+nbNewFromUp)],
-                                &inout_rhs_particles[idx_rhs][(nbOutLower+nbOldParticlesInside-padding)],
-                                sizeof(double)*padding);
+                        memcpy(&inout_rhs_particles[idx_rhs][(nbNewFromLow+nbNewFromUp)*size_particle_rhs],
+                                &inout_rhs_particles[idx_rhs][(nbOutLower+nbOldParticlesInside-padding)*size_particle_rhs],
+                                sizeof(double)*padding*size_particle_rhs);
                     }
                 }
             }
@@ -808,10 +810,10 @@ public:
                            current_offset_particles_for_partition[idxPartition+1] - current_offset_particles_for_partition[idxPartition]);
                     const double limitPartition = (idxPartition+1)*spatialPartitionWidth + mySpatialLowLimit;
                     for(int idx = 0 ; idx < current_offset_particles_for_partition[idxPartition+1] ; ++idx){
-                        assert((*inout_positions_particles)[idx*3+2] < limitPartition);
+                        assert((*inout_positions_particles)[idx*3+IDX_Z] < limitPartition);
                     }
                     for(int idx = current_offset_particles_for_partition[idxPartition+1] ; idx < myTotalNbParticles ; ++idx){
-                        assert((*inout_positions_particles)[idx*3+2] >= limitPartition);
+                        assert((*inout_positions_particles)[idx*3+IDX_Z] >= limitPartition);
                     }
                 }
             }
diff --git a/bfps/cpp/particles/field_accessor.hpp b/bfps/cpp/particles/field_accessor.hpp
index e8937d31d79c6d7fc2ed65de3cf2d93b4468d7e1..cdf6c8560f86076548dc7b934a3f2440f4726a44 100644
--- a/bfps/cpp/particles/field_accessor.hpp
+++ b/bfps/cpp/particles/field_accessor.hpp
@@ -4,19 +4,23 @@
 #include <algorithm>
 #include <array>
 
+#include "particles_utils.hpp"
 
 class field_accessor {
     static const int nb_dim = 3;
 
     const double* field_date;
     std::array<size_t,3> local_field_dims;
-    std::array<size_t,3> dim_offset;
+    std::array<size_t,3> local_field_offset;
+    std::array<size_t,3> field_memory_dims;
 
 public:
     field_accessor(const double* in_field_date, const std::array<size_t,3>& in_dims,
-                   const std::array<size_t,3>& in_dim_offset)
+                   const std::array<size_t,3>& in_local_field_offset,
+                   const std::array<size_t,3>& in_field_memory_dims)
             : field_date(in_field_date), local_field_dims(in_dims),
-              dim_offset(in_dim_offset){
+              local_field_offset(in_local_field_offset),
+              field_memory_dims(in_field_memory_dims){
     }
 
     ~field_accessor(){}
@@ -27,17 +31,20 @@ public:
     }
 
     size_t getIndexFromGlobalPosition(const size_t in_global_x, const size_t in_global_y, const size_t in_global_z) const {
-        return getIndexFromLocalPosition(in_global_x - dim_offset[0],
-                                         in_global_y - dim_offset[1],
-                                         in_global_z - dim_offset[2]);
+        return getIndexFromLocalPosition(in_global_x - local_field_offset[IDX_X],
+                                         in_global_y - local_field_offset[IDX_Y],
+                                         in_global_z - local_field_offset[IDX_Z]);
     }
 
     size_t getIndexFromLocalPosition(const size_t in_local_x, const size_t in_local_y, const size_t in_local_z) const {
-        assert(in_local_x < local_field_dims[0]);
-        assert(in_local_y < local_field_dims[1]);
-        assert(in_local_z < local_field_dims[2]);
-        return (((in_local_z)*local_field_dims[1] +
-                in_local_y)*(local_field_dims[2]) + // TODO there was a +2 on local_field_dims[2]
+        assert(0 <= in_local_x && in_local_x < local_field_dims[IDX_X]);
+        assert(0 <= in_local_y && in_local_y < local_field_dims[IDX_Y]);
+        assert(0 <= in_local_z && in_local_z < local_field_dims[IDX_Z]);
+        static_assert(IDX_X == 2 && IDX_Y == 1 && IDX_Z == 0,
+                      "Dimension idx does not match, please ensure getIndexFromLocalPosition"
+                      "is correct before commenting this assert");
+        return (((in_local_z)*field_memory_dims[1] +
+                in_local_y)*(field_memory_dims[2]) +
                 in_local_x);
     }
 };
diff --git a/bfps/cpp/particles/main_tocompile.cpp b/bfps/cpp/particles/main_tocompile.cpp
index 38db2ec7bd4d9f1cf0d0fcc8b8cacfdd011652a6..9f6420d79b78e70a85232c77d693c616935c475f 100644
--- a/bfps/cpp/particles/main_tocompile.cpp
+++ b/bfps/cpp/particles/main_tocompile.cpp
@@ -9,6 +9,7 @@
 #include "particles_interp_spline.hpp"
 #include "abstract_particles_input.hpp"
 #include "particles_input_hdf5.hpp"
+#include "particles_utils.hpp"
 
 class random_particles : public abstract_particles_input {
     const int nb_particles;
@@ -43,9 +44,9 @@ public:
         std::unique_ptr<double[]> particles(new double[nb_particles*3]);
 
         for(int idx_part = 0 ; idx_part < nb_particles ; ++idx_part){
-            particles[idx_part*3+0] = drand48() * box_width;
-            particles[idx_part*3+1] = drand48() * box_width;
-            particles[idx_part*3+2] = (drand48() * (upper_limit-lower_limit))
+            particles[idx_part*3+IDX_X] = drand48() * box_width;
+            particles[idx_part*3+IDX_Y] = drand48() * box_width;
+            particles[idx_part*3+IDX_Z] = (drand48() * (upper_limit-lower_limit))
                                             + lower_limit;
         }
 
@@ -91,27 +92,33 @@ int main(int argc, char** argv){
         assert(my_rank < field_grid_dim[1]);
         assert(my_rank < field_grid_dim[2]);
 
-        const double partitionIntervalSize = double(field_grid_dim[2])/double(nb_processes);
-        const int myPartitionInterval[2] = { int(partitionIntervalSize*my_rank), (my_rank==nb_processes-1?field_grid_dim[2]:int(partitionIntervalSize*(my_rank+1)))};
+        const double partitionIntervalSize = double(field_grid_dim[IDX_Z])/double(nb_processes);
+        const int myPartitionInterval[2] = { int(partitionIntervalSize*my_rank), (my_rank==nb_processes-1?field_grid_dim[IDX_Z]:int(partitionIntervalSize*(my_rank+1)))};
 
 
         const std::array<double,3> spatial_box_width{10., 10., 10.};
-        const double spatial_partition_width = spatial_box_width[2]/double(field_grid_dim[2]);
+        const double spatial_partition_width = spatial_box_width[IDX_Z]/double(field_grid_dim[IDX_Z]);
         const double my_spatial_low_limit = myPartitionInterval[0]*spatial_partition_width;
         const double my_spatial_up_limit = myPartitionInterval[1]*spatial_partition_width;
 
         if(my_rank == 0){
-            std::cout << "spatial_box_width = " << spatial_box_width[0] << " " << spatial_box_width[1] << " " << spatial_box_width[2] << std::endl;
+            std::cout << "spatial_box_width = " << spatial_box_width[IDX_X] << " " << spatial_box_width[IDX_Y] << " " << spatial_box_width[IDX_Z] << std::endl;
             std::cout << "spatial_partition_width = " << spatial_partition_width << std::endl;
             std::cout << "my_spatial_low_limit = " << my_spatial_low_limit << std::endl;
             std::cout << "my_spatial_up_limit = " << my_spatial_up_limit << std::endl;
         }
 
-        std::array<size_t,3> local_field_dims{ field_grid_dim[0], field_grid_dim[1], myPartitionInterval[1]-myPartitionInterval[0]};
-        std::array<size_t,3> local_field_offset{ 0, 0, myPartitionInterval[0]};
+        std::array<size_t,3> local_field_dims;
+        local_field_dims[IDX_X] = field_grid_dim[IDX_X];
+        local_field_dims[IDX_Y] = field_grid_dim[IDX_Y];
+        local_field_dims[IDX_Z] = myPartitionInterval[1]-myPartitionInterval[0];
+        std::array<size_t,3> local_field_offset;
+        local_field_offset[IDX_X] = 0;
+        local_field_offset[IDX_Y] = 0;
+        local_field_offset[IDX_Z] = myPartitionInterval[0];
 
-        std::unique_ptr<double[]> field_data(new double[local_field_dims[0]*local_field_dims[1]*local_field_dims[2]]);
-        particles_utils::memzero(field_data.get(), local_field_dims[0]*local_field_dims[1]*local_field_dims[2]);
+        std::unique_ptr<double[]> field_data(new double[local_field_dims[IDX_X]*local_field_dims[IDX_Y]*local_field_dims[IDX_Z]*3]);
+        particles_utils::memzero(field_data.get(), local_field_dims[IDX_X]*local_field_dims[IDX_Y]*local_field_dims[IDX_Z]*3);
 
 
         particles_system<particles_interp_spline<InterpNbNeighbors,0>, InterpNbNeighbors> part_sys(field_grid_dim,
@@ -122,6 +129,7 @@ int main(int argc, char** argv){
                                                                                                 field_data.get(),
                                                                                                 local_field_dims,
                                                                                                 local_field_offset,
+                                                                                                local_field_dims,
                                                                                                 MPI_COMM_WORLD);
 
         int total_nb_particles;
@@ -134,7 +142,7 @@ int main(int argc, char** argv){
                 spatial_interval_per_proc[idx_proc] = partitionIntervalSize*spatial_partition_width*idx_proc;
                 std::cout << "spatial_interval_per_proc[idx_proc] " << spatial_interval_per_proc[idx_proc] << std::endl;
             }
-            spatial_interval_per_proc[nb_processes] = spatial_box_width[2];
+            spatial_interval_per_proc[nb_processes] = spatial_box_width[IDX_Z];
             assert(my_spatial_low_limit == spatial_interval_per_proc[my_rank] || fabs((spatial_interval_per_proc[my_rank]-my_spatial_low_limit)/my_spatial_low_limit) < 1e-13);
             assert(my_spatial_up_limit == spatial_interval_per_proc[my_rank+1] || fabs((spatial_interval_per_proc[my_rank+1]-my_spatial_up_limit)/my_spatial_up_limit) < 1e-13);
 
diff --git a/bfps/cpp/particles/particles_field_computer.hpp b/bfps/cpp/particles/particles_field_computer.hpp
index 1baac156b20005fb6e6c91a1bc0523bfd31c9550..0ca83ce40246c578a2d2afdf4a06565e55af1d78 100644
--- a/bfps/cpp/particles/particles_field_computer.hpp
+++ b/bfps/cpp/particles/particles_field_computer.hpp
@@ -6,6 +6,7 @@
 
 #include "abstract_particles_distr.hpp"
 #include "scope_timer.hpp"
+#include "particles_utils.hpp"
 
 template <class interpolator_class, class field_class, int interp_neighbours, class positions_updater_class >
 class particles_field_computer : public abstract_particles_distr<3,3,1> {
@@ -40,17 +41,17 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
         TIMEZONE("particles_field_computer::apply_computation");
         for(int idxPart = 0 ; idxPart < nb_particles ; ++idxPart){
             double bx[interp_neighbours*2+2], by[interp_neighbours*2+2], bz[interp_neighbours*2+2];
-            interpolator.compute_beta(deriv[0], particles_positions[idxPart*3], bx);
-            interpolator.compute_beta(deriv[1], particles_positions[idxPart*3+1], by);
-            interpolator.compute_beta(deriv[2], particles_positions[idxPart*3+2], bz);
+            interpolator.compute_beta(deriv[IDX_X], particles_positions[idxPart*3+IDX_X], bx);
+            interpolator.compute_beta(deriv[IDX_Y], particles_positions[idxPart*3+IDX_Y], by);
+            interpolator.compute_beta(deriv[IDX_Z], particles_positions[idxPart*3+IDX_Z], bz);
 
-            const int partGridIdx_x = int(particles_positions[idxPart*3]/box_step_width);
-            const int partGridIdx_y = int(particles_positions[idxPart*3+1]/box_step_width);
-            const int partGridIdx_z = int(particles_positions[idxPart*3+2]/box_step_width);
+            const int partGridIdx_x = int(particles_positions[idxPart*3+IDX_X]/box_step_width);
+            const int partGridIdx_y = int(particles_positions[idxPart*3+IDX_Y]/box_step_width);
+            const int partGridIdx_z = int(particles_positions[idxPart*3+IDX_Z]/box_step_width);
 
-            assert(0 <= partGridIdx_z && partGridIdx_z < field_grid_dim[2]);
-            assert(0 <= partGridIdx_x && partGridIdx_x < field_grid_dim[0]);
-            assert(0 <= partGridIdx_y && partGridIdx_y < field_grid_dim[1]);
+            assert(0 <= partGridIdx_x && partGridIdx_x < field_grid_dim[IDX_X]);
+            assert(0 <= partGridIdx_y && partGridIdx_y < field_grid_dim[IDX_Y]);
+            assert(0 <= partGridIdx_z && partGridIdx_z < field_grid_dim[IDX_Z]);
 
             const int interp_limit_mx = partGridIdx_x-interp_neighbours;
             const int interp_limit_x = partGridIdx_x+interp_neighbours+1;
@@ -62,8 +63,8 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
             int nb_z_intervals;
 
             if((partGridIdx_z-interp_neighbours) < 0){
-                assert(partGridIdx_z+interp_neighbours+1 < field_grid_dim[2]);
-                interp_limit_mz[0] = ((partGridIdx_z-interp_neighbours)+field_grid_dim[2])%field_grid_dim[2];
+                assert(partGridIdx_z+interp_neighbours+1 < field_grid_dim[IDX_Z]);
+                interp_limit_mz[0] = ((partGridIdx_z-interp_neighbours)+field_grid_dim[IDX_Z])%field_grid_dim[IDX_Z];
                 interp_limit_z[0] = current_partition_interval.second-1;
 
                 interp_limit_mz[1] = std::max(0, current_partition_interval.first);// max is not really needed here
@@ -73,10 +74,10 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
             }
             else if(field_grid_dim[2] <= (partGridIdx_z+interp_neighbours+1)){
                 interp_limit_mz[0] = std::max(current_partition_interval.first, partGridIdx_z-interp_neighbours);
-                interp_limit_z[0] = std::min(int(field_grid_dim[2])-1,current_partition_interval.second-1);// max is not really needed here
+                interp_limit_z[0] = std::min(int(field_grid_dim[IDX_Z])-1,current_partition_interval.second-1);// max is not really needed here
 
                 interp_limit_mz[1] = std::max(0, current_partition_interval.first);
-                interp_limit_z[1] = std::min(int((partGridIdx_z+interp_neighbours+1+field_grid_dim[2])%field_grid_dim[2]), current_partition_interval.second-1);
+                interp_limit_z[1] = std::min(int((partGridIdx_z+interp_neighbours+1+field_grid_dim[IDX_Z])%field_grid_dim[IDX_Z]), current_partition_interval.second-1);
 
                 nb_z_intervals = 2;
             }
@@ -88,16 +89,16 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
 
             for(int idx_inter = 0 ; idx_inter < nb_z_intervals ; ++idx_inter){
                 for(int idx_z = interp_limit_mz[idx_inter] ; idx_z <= interp_limit_z[idx_inter] ; ++idx_z ){
-                    const int idx_z_pbc = (idx_z + field_grid_dim[2])%field_grid_dim[2];
+                    const int idx_z_pbc = (idx_z + field_grid_dim[IDX_Z])%field_grid_dim[IDX_Z];
                     assert(current_partition_interval.first <= idx_z_pbc && idx_z_pbc < current_partition_interval.second);
                     assert(idx_z-interp_limit_mz[idx_inter] < interp_neighbours*2+2);
 
                     for(int idx_x = interp_limit_mx ; idx_x <= interp_limit_x ; ++idx_x ){
-                        const int idx_x_pbc = (idx_x + field_grid_dim[0])%field_grid_dim[0];
+                        const int idx_x_pbc = (idx_x + field_grid_dim[IDX_X])%field_grid_dim[IDX_X];
                         assert(idx_x-interp_limit_mx < interp_neighbours*2+2);
 
                         for(int idx_y = interp_limit_my ; idx_y <= interp_limit_y ; ++idx_y ){
-                            const int idx_y_pbc = (idx_y + field_grid_dim[1])%field_grid_dim[1];
+                            const int idx_y_pbc = (idx_y + field_grid_dim[IDX_Y])%field_grid_dim[IDX_Y];
                             assert(idx_y-interp_limit_my < interp_neighbours*2+2);
 
                             const double coef = (bz[idx_z-interp_limit_mz[idx_inter]]
@@ -106,9 +107,9 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
 
                             const ptrdiff_t tindex = field.getIndexFromGlobalPosition(idx_x_pbc, idx_y_pbc, idx_z_pbc);
 
-                            particles_current_rhs[idxPart*3+0] += field.getValue(tindex,0)*coef;
-                            particles_current_rhs[idxPart*3+1] += field.getValue(tindex,1)*coef;
-                            particles_current_rhs[idxPart*3+2] += field.getValue(tindex,2)*coef;
+                            particles_current_rhs[idxPart*3+IDX_X] += field.getValue(tindex,IDX_X)*coef;
+                            particles_current_rhs[idxPart*3+IDX_Y] += field.getValue(tindex,IDX_Y)*coef;
+                            particles_current_rhs[idxPart*3+IDX_Z] += field.getValue(tindex,IDX_Z)*coef;
                         }
                     }
                 }
@@ -123,9 +124,9 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
         TIMEZONE("particles_field_computer::reduce_particles");
         // Simply sum values
         for(int idxPart = 0 ; idxPart < nb_particles ; ++idxPart){
-            particles_current_rhs[idxPart*3+0] += extra_particles_current_rhs[idxPart*3+0];
-            particles_current_rhs[idxPart*3+1] += extra_particles_current_rhs[idxPart*3+1];
-            particles_current_rhs[idxPart*3+2] += extra_particles_current_rhs[idxPart*3+2];
+            particles_current_rhs[idxPart*3+IDX_X] += extra_particles_current_rhs[idxPart*3+IDX_X];
+            particles_current_rhs[idxPart*3+IDX_Y] += extra_particles_current_rhs[idxPart*3+IDX_Y];
+            particles_current_rhs[idxPart*3+IDX_Z] += extra_particles_current_rhs[idxPart*3+IDX_Z];
         }
     }
 
@@ -136,9 +137,10 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
 
     void apply_pbc_xy(double* inout_particles, const int size) const final {
         TIMEZONE("particles_field_computer::apply_pbc_xy");
+        const std::array<int, 2> dims_xy={IDX_X, IDX_Y};
         for(int idxPart = 0 ; idxPart < size ; ++idxPart){
             // Consider it will never move for more than one box repeatition
-            for(int idxDim = 0 ; idxDim < 2 ; ++idxDim){
+            for(const int idxDim : dims_xy){
                 if(inout_particles[idxPart*3+idxDim] < 0) inout_particles[idxPart*3+idxDim] += spatial_box_width[idxDim];
                 else if(spatial_box_width[idxDim] <= inout_particles[idxPart*3+idxDim]) inout_particles[idxPart*3+idxDim] -= spatial_box_width[idxDim];
                 assert(0 <= inout_particles[idxPart*3+idxDim] && inout_particles[idxPart*3+idxDim] < spatial_box_width[idxDim]);
@@ -149,7 +151,7 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
     void apply_pbc_z_new_particles(double* values, const int size) const final {
         TIMEZONE("particles_field_computer::apply_pbc_z_new_particles");
         if(my_rank == 0){
-            const int idxDim = 2;
+            const int idxDim = IDX_Z;
             for(int idxPart = 0 ; idxPart < size ; ++idxPart){
                 assert(values[idxPart*3+idxDim] < my_spatial_up_limit || spatial_box_width[idxDim] <= values[idxPart*3+idxDim]);
                 assert(my_spatial_low_limit <= values[idxPart*3+idxDim]);
@@ -161,7 +163,7 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
             }
         }
         else if(my_rank == nb_processes - 1){
-            const int idxDim = 2;
+            const int idxDim = IDX_Z;
             for(int idxPart = 0 ; idxPart < size ; ++idxPart){
                 assert(my_spatial_low_limit <= values[idxPart*3+idxDim] || values[idxPart*3+idxDim] < 0);
                 assert(values[idxPart*3+idxDim] < spatial_box_width[idxDim]);
@@ -173,7 +175,7 @@ class particles_field_computer : public abstract_particles_distr<3,3,1> {
             }
         }
         else{
-            const int idxDim = 2;
+            const int idxDim = IDX_Z;
             for(int idxPart = 0 ; idxPart < size ; ++idxPart){
                 assert(my_spatial_low_limit <= values[idxPart*3+idxDim] && values[idxPart*3+idxDim] < my_spatial_up_limit);
             }
@@ -194,9 +196,9 @@ public:
           interpolator(in_interpolator), field(in_field), positions_updater(),
           spatial_box_width(in_spatial_box_width), box_step_width(in_box_step_width),
           my_spatial_low_limit(in_my_spatial_low_limit), my_spatial_up_limit(in_my_spatial_up_limit){
-        deriv[0] = 0;
-        deriv[1] = 0;
-        deriv[2] = 0;
+        deriv[IDX_X] = 0;
+        deriv[IDX_Y] = 0;
+        deriv[IDX_Z] = 0;
     }
 
     ////////////////////////////////////////////////////////////////////////
diff --git a/bfps/cpp/particles/particles_input_hdf5.hpp b/bfps/cpp/particles/particles_input_hdf5.hpp
index c3b377a300e610d369938fdc8fd642f4ec7429c3..1ca9ae37d79a0018f6bc28486d680e7afeced69e 100644
--- a/bfps/cpp/particles/particles_input_hdf5.hpp
+++ b/bfps/cpp/particles/particles_input_hdf5.hpp
@@ -224,7 +224,7 @@ public:
                                                 &split_particles_positions[previousOffset*size_particle_positions],
                                                  load_splitter.getMySize()-previousOffset,
                                                  [&](const double val[]){
-                    return val[2] < limitPartition;
+                    return val[IDX_Z] < limitPartition;
                 },
                 [&](const int idx1, const int idx2){
                     std::swap(split_particles_indexes[idx1], split_particles_indexes[idx2]);
diff --git a/bfps/cpp/particles/particles_system.hpp b/bfps/cpp/particles/particles_system.hpp
index 52240591d1de54330b8f9a2ed95b020b48dfa70c..72c460993889e7abfed2ce7f1b529fc661b2ddd2 100644
--- a/bfps/cpp/particles/particles_system.hpp
+++ b/bfps/cpp/particles/particles_system.hpp
@@ -3,6 +3,7 @@
 
 #include <array>
 
+#include "abstract_particle_system.hpp"
 #include "particles_output_hdf5.hpp"
 #include "particles_output_mpiio.hpp"
 #include "particles_field_computer.hpp"
@@ -12,7 +13,7 @@
 #include "scope_timer.hpp"
 
 template <class interpolator_class, int interp_neighbours>
-class particles_system {
+class particles_system : public abstract_particle_system {
     MPI_Comm mpi_com;
 
     const std::pair<int,int> current_partition_interval;
@@ -45,11 +46,12 @@ public:
                      const double in_my_spatial_low_limit, const double in_my_spatial_up_limit,
                      const double* in_field_data, const std::array<size_t,3>& in_local_field_dims,
                      const std::array<size_t,3>& in_local_field_offset,
+                     const std::array<size_t,3>& in_field_memory_dims,
                      MPI_Comm in_mpi_com)
         : mpi_com(in_mpi_com),
-          current_partition_interval({in_local_field_offset[2], in_local_field_offset[2] + in_local_field_dims[2]}),
+          current_partition_interval({in_local_field_offset[IDX_Z], in_local_field_offset[IDX_Z] + in_local_field_dims[IDX_Z]}),
           partition_interval_size(current_partition_interval.second - current_partition_interval.first),
-          field(in_field_data, in_local_field_dims, in_local_field_offset),
+          field(in_field_data, in_local_field_dims, in_local_field_offset, in_field_memory_dims),
           interpolator(),
           computer(in_mpi_com, field_grid_dim, current_partition_interval,
                    interpolator, field, in_spatial_box_width, in_spatial_partition_width,
@@ -74,8 +76,8 @@ public:
         my_nb_particles = particles_input.getLocalNbParticles();
 
         for(int idx_part = 0 ; idx_part < my_nb_particles ; ++idx_part){ // TODO remove me
-            assert(my_particles_positions[idx_part*3+2] >= my_spatial_low_limit);
-            assert(my_particles_positions[idx_part*3+2] < my_spatial_up_limit);
+            assert(my_particles_positions[idx_part*3+IDX_Z] >= my_spatial_low_limit);
+            assert(my_particles_positions[idx_part*3+IDX_Z] < my_spatial_up_limit);
         }
 
         particles_utils::partition_extra_z<3>(&my_particles_positions[0], my_nb_particles, partition_interval_size,
@@ -100,17 +102,17 @@ public:
                        current_offset_particles_for_partition[idxPartition+1] - current_offset_particles_for_partition[idxPartition]);
                 const double limitPartition = (idxPartition+1)*spatial_partition_width + my_spatial_low_limit;
                 for(int idx = 0 ; idx < current_offset_particles_for_partition[idxPartition+1] ; ++idx){
-                    assert(my_particles_positions[idx*3+2] < limitPartition);
+                    assert(my_particles_positions[idx*3+IDX_Z] < limitPartition);
                 }
                 for(int idx = current_offset_particles_for_partition[idxPartition+1] ; idx < my_nb_particles ; ++idx){
-                    assert(my_particles_positions[idx*3+2] >= limitPartition);
+                    assert(my_particles_positions[idx*3+IDX_Z] >= limitPartition);
                 }
             }
         }
     }
 
 
-    void compute(){
+    void compute() final {
         TIMEZONE("particles_system::compute");
         computer.compute_distr(current_my_nb_particles_per_partition.get(),
                                my_particles_positions.get(),
@@ -118,14 +120,14 @@ public:
                                interp_neighbours);
     }
 
-    void move(const double dt){
+    void move(const double dt) final {
         TIMEZONE("particles_system::move");
         computer.move_particles(my_particles_positions.get(), my_nb_particles,
                                 my_particles_rhs.data(), std::min(step_idx,int(my_particles_rhs.size())),
                                 dt);
     }
 
-    void redistribute(){
+    void redistribute() final {
         TIMEZONE("particles_system::redistribute");
         computer.redistribute(current_my_nb_particles_per_partition.get(),
                               &my_nb_particles,
@@ -137,11 +139,11 @@ public:
                               spatial_partition_width);
     }
 
-    void inc_step_idx(){
+    void inc_step_idx() final {
         step_idx += 1;
     }
 
-    void shift_rhs_vectors(){
+    void shift_rhs_vectors() final {
         if(my_particles_rhs.size()){
             std::unique_ptr<double[]> next_current(std::move(my_particles_rhs.back()));
             for(int idx_rhs = my_particles_rhs.size()-1 ; idx_rhs > 0 ; --idx_rhs){
@@ -152,7 +154,7 @@ public:
         }
     }
 
-    void completeLoop(const double dt){
+    void completeLoop(const double dt) final {
         TIMEZONE("particles_system::completeLoop");
         compute();
         move(dt);
@@ -161,32 +163,32 @@ public:
         shift_rhs_vectors();
     }
 
-    const double* getParticlesPositions() const{
+    const double* getParticlesPositions() const final {
         return my_particles_positions.get();
     }
 
-    const double* getParticlesCurrentRhs() const{
+    const double* getParticlesCurrentRhs() const final {
         return my_particles_rhs.front().get();
     }
 
-    const int* getParticlesIndexes() const{
+    const int* getParticlesIndexes() const final {
         return my_particles_positions_indexes.get();
     }
 
-    int getLocalNbParticles() const{
+    int getLocalNbParticles() const final {
         return my_nb_particles;
     }
 
     void checkNan() const { // TODO remove
         for(int idx_part = 0 ; idx_part < my_nb_particles ; ++idx_part){ // TODO remove me
-            assert(std::isnan(my_particles_positions[idx_part*3+0]) == false);
-            assert(std::isnan(my_particles_positions[idx_part*3+1]) == false);
-            assert(std::isnan(my_particles_positions[idx_part*3+2]) == false);
+            assert(std::isnan(my_particles_positions[idx_part*3+IDX_X]) == false);
+            assert(std::isnan(my_particles_positions[idx_part*3+IDX_Y]) == false);
+            assert(std::isnan(my_particles_positions[idx_part*3+IDX_Z]) == false);
 
             for(int idx_rhs = 0 ; idx_rhs < my_particles_rhs.size() ; ++idx_rhs){
-                assert(std::isnan(my_particles_rhs[idx_rhs][idx_part*3+0]) == false);
-                assert(std::isnan(my_particles_rhs[idx_rhs][idx_part*3+1]) == false);
-                assert(std::isnan(my_particles_rhs[idx_rhs][idx_part*3+2]) == false);
+                assert(std::isnan(my_particles_rhs[idx_rhs][idx_part*3+IDX_X]) == false);
+                assert(std::isnan(my_particles_rhs[idx_rhs][idx_part*3+IDX_Y]) == false);
+                assert(std::isnan(my_particles_rhs[idx_rhs][idx_part*3+IDX_Z]) == false);
             }
         }
     }
diff --git a/bfps/cpp/particles/particles_utils.hpp b/bfps/cpp/particles/particles_utils.hpp
index eb3d22ab15e718026f53cf78bb1ea659e60bc6d1..3302a9f910b2e82a7236245c63899834cc9e8414 100644
--- a/bfps/cpp/particles/particles_utils.hpp
+++ b/bfps/cpp/particles/particles_utils.hpp
@@ -4,6 +4,11 @@
 #include <cassert>
 #include <stack>
 
+enum IDXS_3D {
+    IDX_X = 2,
+    IDX_Y = 1,
+    IDX_Z = 0
+};
 
 namespace particles_utils {
 
@@ -78,7 +83,7 @@ inline void partition_extra_z(double* array, const int size, const int nb_partit
         const double limit = partitions_limits(0);
         const int size_current = partition_extra<nb_values>(array, size,
                 [&](const double inval[]){
-            return inval[nb_values-1] < limit;
+            return inval[IDX_Z] < limit;
         }, pdcswap);
         partitions_size[0] = size_current;
         partitions_size[1] = size-size_current;
@@ -108,7 +113,7 @@ inline void partition_extra_z(double* array, const int size, const int nb_partit
             const int size_current = partition_extra<nb_values>(&array[partitions_offset[current_part.first]*nb_values],
                                                      size_unpart,
                     [&](const double inval[]){
-                return inval[nb_values-1] < limit;
+                return inval[IDX_Z] < limit;
             }, pdcswap, partitions_offset[current_part.first]);
 
             partitions_offset[idx_middle+1] = size_current + partitions_offset[current_part.first];
@@ -185,7 +190,9 @@ public:
     }
 
     NumType getOwner(const NumType in_item_idx) const {
-        return NumType(double(in_item_idx)/step_split);
+        const NumType owner = NumType(double(in_item_idx)/step_split);
+        assert(owner < nb_intervals);
+        return owner;
     }
 };