diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 60a3fe604b2e26c55ddfe55e0cf2a8098712927f..bf0e4b0b29a98e95df25ee13be948ce60eeecb18 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -7,7 +7,7 @@ image: gitlab-registry.mpcdf.mpg.de/mpcdf/module-image
 
 .load_modules: &load_modules |
     module purge
-    module load cmake/3.22 $COMPILER $MPI gsl hdf5-mpi fftw-mpi anaconda/3
+    module load cmake/3.22 ${COMPILER} ${MPI} gsl hdf5-mpi/1.12.1 fftw-mpi anaconda
     export FFTW_DIR=$FFTW_HOME
 
 .build: &build |
@@ -37,6 +37,8 @@ build-gcc:
     script:
       - *load_modules
       - *export_GCC_compilers
+      - >
+        export MPI_HOME=${I_MPI_ROOT}
       - *build
     variables:
       COMPILER: "gcc"
@@ -55,6 +57,8 @@ build-intel:
     script:
       - *load_modules
       - *export_INTEL_compilers
+      - >
+        export MPI_HOME=${I_MPI_ROOT}
       - *build
     variables:
       COMPILER: "intel"
@@ -73,6 +77,8 @@ test-gcc:
     script:
       - *load_modules
       - *export_GCC_compilers
+      - >
+        export MPI_HOME=${I_MPI_ROOT}
       - *run_tests
     tags:
       - docker
@@ -89,6 +95,8 @@ test-intel:
     script:
       - *load_modules
       - *export_INTEL_compilers
+      - >
+        export MPI_HOME=${I_MPI_ROOT}
       - *run_tests
     tags:
       - docker
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d28cce28d684237e08dcbcc6b00c6c0ded1e6049..da1d4bd2924c017dd82018265cd1f04d04a8d97e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -182,6 +182,7 @@ if(TIMING_OUTPUT)
 endif()
 #####################################################################################
 
+
 set(TURTLE_LIBS "")
 #####################################################################################
 ## HDF5
@@ -488,7 +489,15 @@ LIST(APPEND source_files ${hpp_for_lib} ${cpp_for_lib})
 
 add_library(TurTLE ${source_files})
 
+# TODO: we should be using the bit below, but we need to fix everything else about TURTLE_LIBS before we can do that
+#target_link_libraries(TurTLE PUBLIC OpenMP::OpenMP_CXX)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
+list(APPEND TURTLE_LIBS "${OpenMP_CXX_LIB_NAMES}")
+
 target_link_libraries(TurTLE ${TURTLE_LIBS})
+target_compile_options(TurTLE PRIVATE $<$<CONFIG:DEBUG>:-O1>)
 
 install(TARGETS TurTLE EXPORT TURTLE_EXPORT DESTINATION lib/ )
 install(DIRECTORY ${PROJECT_SOURCE_DIR}/cpp/ DESTINATION include/TurTLE/ FILES_MATCHING PATTERN "*.h*")
@@ -585,6 +594,11 @@ if (BUILD_TESTING)
         NAME test_Heun_p2p
         COMMAND turtle.test_Heun_p2p  -n 32 --np 2 --ntpp 2 --simname tracer_set_Heun_p2p --src-simname dns_nsveparticles --src-iteration 0
         WORKING_DIRECTORY ${TEST_OUTPUT_DIRECTORY})
+    ### check whether particle deletion works
+    add_test(
+        NAME test_particle_deleter
+        COMMAND turtle.test_particle_deleter  -n 32 --np 2 --ntpp 2 --simname tracer_set_particle_deleter --src-simname dns_nsveparticles --src-iteration 0
+        WORKING_DIRECTORY ${TEST_OUTPUT_DIRECTORY})
     ### simple runs of post-processing tools
     add_test(
         NAME test_pp_single_to_double
diff --git a/TurTLE/test/particle_set/NSVEparticle_set.cpp b/TurTLE/test/particle_set/NSVEparticle_set.cpp
index 8a32ebc0172282929ca70f6bef1733d0b2f78b0b..ee89c2e36df943fd38dc04372dd2b459d5e21632 100644
--- a/TurTLE/test/particle_set/NSVEparticle_set.cpp
+++ b/TurTLE/test/particle_set/NSVEparticle_set.cpp
@@ -3,20 +3,20 @@
 *  Copyright 2019 Max Planck Institute                                *
 *                 for Dynamics and Self-Organization                  *
 *                                                                     *
-*  This file is part of bfps.                                         *
+*  This file is part of TurTLE.                                       *
 *                                                                     *
-*  bfps is free software: you can redistribute it and/or modify       *
+*  TurTLE is free software: you can redistribute it and/or modify     *
 *  it under the terms of the GNU General Public License as published  *
 *  by the Free Software Foundation, either version 3 of the License,  *
 *  or (at your option) any later version.                             *
 *                                                                     *
-*  bfps is distributed in the hope that it will be useful,            *
+*  TurTLE is distributed in the hope that it will be useful,          *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
 *  GNU General Public License for more details.                       *
 *                                                                     *
 *  You should have received a copy of the GNU General Public License  *
-*  along with bfps.  If not, see <http://www.gnu.org/licenses/>       *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>     *
 *                                                                     *
 * Contact: Cristian.Lalescu@ds.mpg.de                                 *
 *                                                                     *
@@ -87,7 +87,7 @@ int NSVEparticle_set<rnumber>::initialize(void)
                 nparticles,
                 tracers0_integration_steps);
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 this->pset->getTotalNumberOfParticles(),
                 (this->simname + "_particles.h5"),
@@ -129,12 +129,13 @@ template <typename rnumber>
 int NSVEparticle_set<rnumber>::finalize(void)
 {
     TIMEZONE("NSVEparticle_set::finalize");
-    delete this->particles_output_writer_mpi;
     delete this->particles_sample_writer_mpi;
+    delete this->particles_output_writer_mpi;
     delete this->psolver;
     delete this->pset;
     delete this->trhs;
     delete this->fti;
+    delete this->previous_velocity;
     this->NSVE<rnumber>::finalize();
     return EXIT_SUCCESS;
 }
@@ -166,15 +167,20 @@ int NSVEparticle_set<rnumber>::do_stats()
             "position",
             psolver->getIteration());
 
+    MPI_Barrier(this->comm);
+
     // sample velocity
     // first ensure velocity field is computed, and is in real space
+    DEBUG_MSG("test 00\n");
     if (!(this->iteration % this->niter_stat == 0))
     {
         // we need to compute velocity field manually, because it didn't happen in NSVE::do_stats()
         this->fs->compute_velocity(this->fs->cvorticity);
-        *this->tmp_vec_field = this->fs->cvelocity->get_cdata();
+        *this->tmp_vec_field = *(this->fs->cvelocity);
         this->tmp_vec_field->ift();
     }
+    DEBUG_MSG("test 01\n");
+    MPI_Barrier(this->comm);
     this->pset->writeSample(
             this->tmp_vec_field,
             this->particles_sample_writer_mpi,
diff --git a/TurTLE/test/particle_set/NSVEparticle_set.hpp b/TurTLE/test/particle_set/NSVEparticle_set.hpp
index 64a5beebbcc3feefb06cb7fc1cc6df8dcd578dec..57d7a584fe34d6c9a271a0754712d8cb97657344 100644
--- a/TurTLE/test/particle_set/NSVEparticle_set.hpp
+++ b/TurTLE/test/particle_set/NSVEparticle_set.hpp
@@ -3,20 +3,20 @@
 *  Copyright 2017 Max Planck Institute                                *
 *                 for Dynamics and Self-Organization                  *
 *                                                                     *
-*  This file is part of bfps.                                         *
+*  This file is part of TurTLE.                                       *
 *                                                                     *
-*  bfps is free software: you can redistribute it and/or modify       *
+*  TurTLE is free software: you can redistribute it and/or modify     *
 *  it under the terms of the GNU General Public License as published  *
 *  by the Free Software Foundation, either version 3 of the License,  *
 *  or (at your option) any later version.                             *
 *                                                                     *
-*  bfps is distributed in the hope that it will be useful,            *
+*  TurTLE is distributed in the hope that it will be useful,          *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
 *  GNU General Public License for more details.                       *
 *                                                                     *
 *  You should have received a copy of the GNU General Public License  *
-*  along with bfps.  If not, see <http://www.gnu.org/licenses/>       *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>     *
 *                                                                     *
 * Contact: Cristian.Lalescu@ds.mpg.de                                 *
 *                                                                     *
@@ -76,7 +76,7 @@ class NSVEparticle_set: public NSVE<rnumber>
         field<rnumber, FFTW, THREE> *previous_velocity;
 
         particles_output_hdf5<long long int, double, 3> *particles_output_writer_mpi;
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
         NSVEparticle_set(
                 const MPI_Comm COMMUNICATOR,
diff --git a/TurTLE/test/particle_set/particle_deleter.cpp b/TurTLE/test/particle_set/particle_deleter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..884517cc8ff891fbc19cf9785153245dd019bc5a
--- /dev/null
+++ b/TurTLE/test/particle_set/particle_deleter.cpp
@@ -0,0 +1,296 @@
+/**********************************************************************
+*                                                                     *
+*  Copyright 2021 Max Planck Institute                                *
+*                 for Dynamics and Self-Organization                  *
+*                                                                     *
+*  This file is part of TurTLE.                                       *
+*                                                                     *
+*  TurTLE is free software: you can redistribute it and/or modify     *
+*  it under the terms of the GNU General Public License as published  *
+*  by the Free Software Foundation, either version 3 of the License,  *
+*  or (at your option) any later version.                             *
+*                                                                     *
+*  TurTLE is distributed in the hope that it will be useful,          *
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
+*  GNU General Public License for more details.                       *
+*                                                                     *
+*  You should have received a copy of the GNU General Public License  *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>     *
+*                                                                     *
+* Contact: Cristian.Lalescu@ds.mpg.de                                 *
+*                                                                     *
+**********************************************************************/
+
+
+
+#include <string>
+#include <cmath>
+//#include "particle_deleter.hpp"
+#include "scope_timer.hpp"
+
+template <typename rnumber>
+int particle_deleter<rnumber>::initialize(void)
+{
+    TIMEZONE("particle_deleter::intialize");
+    this->NSVE<rnumber>::initialize();
+
+
+    // allocate previous velocity
+    this->previous_velocity = new field<rnumber, FFTW, THREE>(
+            this->fs->cvelocity->rlayout->sizes[2],
+            this->fs->cvelocity->rlayout->sizes[1],
+            this->fs->cvelocity->rlayout->sizes[0],
+            this->fs->cvelocity->rlayout->comm,
+            this->fs->cvelocity->fftw_plan_rigor);
+    this->fs->compute_velocity(this->fs->cvorticity);
+    *this->previous_velocity = *this->fs->cvelocity;
+    this->previous_velocity->ift();
+
+    this->fti = new field_tinterpolator<rnumber, FFTW, THREE, LINEAR>();
+    this->trhs = new tracer_with_collision_counter_rhs<rnumber, FFTW, LINEAR>();
+
+    // We're not using Adams-Bashforth in this code.
+    // This assert is there to ensure
+    // user knows what's happening.
+    assert(tracers0_integration_steps == 0);
+    // neighbours and smoothness are second and third template parameters of particle_set
+    assert(tracers0_neighbours == 3);
+    assert(tracers0_smoothness == 2);
+    this->pset = new particle_set<3, 3, 2>(
+            this->fs->cvelocity->rlayout,
+            this->dkx,
+            this->dky,
+            this->dkz,
+            0.5);
+
+    // set two fields for the temporal interpolation
+    this->fti->set_field(this->previous_velocity, 0);
+    this->fti->set_field(this->fs->cvelocity, 1);
+    this->trhs->setVelocity(this->fti);
+
+    particles_input_hdf5<long long int, double, 3, 3> particle_reader(
+            this->comm,
+            this->fs->get_current_fname(),
+            std::string("/tracers0/state/") + std::to_string(this->fs->iteration), // dataset name for initial input
+            std::string("/tracers0/rhs/")  + std::to_string(this->fs->iteration),  // dataset name for initial input
+            this->pset->getSpatialLowLimitZ(),
+            this->pset->getSpatialUpLimitZ());
+    this->pset->init(particle_reader);
+
+    this->psolver = new particle_solver(*(this->pset), 0);
+
+    this->particles_output_writer_mpi = new particles_output_hdf5<
+        long long int, double, 3>(
+                MPI_COMM_WORLD,
+                "tracers0",
+                nparticles,
+                tracers0_integration_steps);
+    this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
+        long long int, double, double, 3>(
+                MPI_COMM_WORLD,
+                this->pset->getTotalNumberOfParticles(),
+                (this->simname + "_particles.h5"),
+                "tracers0",
+                "position/0");
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int particle_deleter<rnumber>::step(void)
+{
+    TIMEZONE("particle_deleter::step");
+    // compute next step Navier-Stokes
+    this->NSVE<rnumber>::step();
+    // update velocity 1
+    this->fs->compute_velocity(this->fs->cvorticity);
+    this->fs->cvelocity->ift();
+    // compute particle step using velocity 0 and velocity 1
+    this->psolver->Heun(this->dt, *(this->trhs));
+    // update velocity 0
+    *this->previous_velocity = *this->fs->cvelocity;
+    this->psolver->setIteration(this->fs->iteration);
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int particle_deleter<rnumber>::write_checkpoint(void)
+{
+    TIMEZONE("particle_deleter::write_checkpoint");
+    this->NSVE<rnumber>::write_checkpoint();
+    this->psolver->setIteration(this->fs->iteration);
+    this->particles_output_writer_mpi->open_file(this->fs->get_current_fname());
+    this->psolver->template writeCheckpoint<3>(this->particles_output_writer_mpi);
+    this->particles_output_writer_mpi->close_file();
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int particle_deleter<rnumber>::finalize(void)
+{
+    TIMEZONE("particle_deleter::finalize");
+    delete this->particles_sample_writer_mpi;
+    delete this->particles_output_writer_mpi;
+    delete this->psolver;
+    delete this->pset;
+    delete this->trhs;
+    delete this->fti;
+    delete this->previous_velocity;
+    this->NSVE<rnumber>::finalize();
+    return EXIT_SUCCESS;
+}
+
+/** \brief Compute fluid stats and sample fields at particle locations.
+ */
+
+template <typename rnumber>
+int particle_deleter<rnumber>::do_stats()
+{
+    TIMEZONE("particle_deleter::do_stats");
+    /// fluid stats go here
+    this->NSVE<rnumber>::do_stats();
+
+
+    /// either one of two conditions suffices to compute statistics:
+    /// 1) current iteration is a multiple of niter_part
+    /// 2) we are within niter_part_fine_duration/2 of a multiple of niter_part_fine_period
+    if (!(this->iteration % this->niter_part == 0 ||
+          ((this->iteration + this->niter_part_fine_duration/2) % this->niter_part_fine_period <=
+           this->niter_part_fine_duration)))
+        return EXIT_SUCCESS;
+
+    // sample position
+    this->pset->writeStateTriplet(
+            0,
+            this->particles_sample_writer_mpi,
+            "tracers0",
+            "position",
+            psolver->getIteration());
+
+    // sample velocity
+    // first ensure velocity field is computed, and is in real space
+    if (!(this->iteration % this->niter_stat == 0))
+    {
+        // we need to compute velocity field manually, because it didn't happen in NSVE::do_stats()
+        this->fs->compute_velocity(this->fs->cvorticity);
+        *this->tmp_vec_field = this->fs->cvelocity->get_cdata();
+        this->tmp_vec_field->ift();
+    }
+    this->pset->writeSample(
+            this->tmp_vec_field,
+            this->particles_sample_writer_mpi,
+            "tracers0",
+            "velocity",
+            psolver->getIteration());
+
+    if (this->pset->getTotalNumberOfParticles() > 3)
+    {
+        this->pset->writeParticleLabels(
+                "particle_index_before.h5",
+                "tracers0",
+                "index",
+                psolver->getIteration());
+        std::vector<long long int> indices_to_delete(2);
+        indices_to_delete[0] = 1;
+        indices_to_delete[1] = (this->iteration*3)%this->pset->getTotalNumberOfParticles();
+        if (indices_to_delete[1] == indices_to_delete[0])
+            indices_to_delete[1] = 3;
+        std::sort(indices_to_delete.begin(), indices_to_delete.end());
+
+        DEBUG_MSG("computed indices_to_delete:\n");
+        DEBUG_MSG("indices_to_delete[0] = %d\n",
+                indices_to_delete[0]);
+        DEBUG_MSG("indices_to_delete[1] = %d\n",
+                indices_to_delete[1]);
+        DEBUG_MSG("before delete particles, iteration %d\n",
+                this->iteration);
+        this->pset->_print_debug_info();
+        particle_set<3, 3, 2> *tmp_pset = new particle_set<3, 3, 2>(
+                this->fs->cvelocity->rlayout,
+                this->dkx,
+                this->dky,
+                this->dkz,
+                0.5);
+        tmp_pset->init_as_subset_of(
+                *(this->pset),
+                indices_to_delete,
+                true);
+        *(this->pset) = tmp_pset;
+        delete tmp_pset;
+
+        DEBUG_MSG("after delete particles\n");
+        this->pset->_print_debug_info();
+
+        delete this->particles_output_writer_mpi;
+        delete this->particles_sample_writer_mpi;
+        this->particles_output_writer_mpi = new particles_output_hdf5<
+            long long int, double, 3>(
+                    MPI_COMM_WORLD,
+                    "tracers0",
+                    this->pset->getTotalNumberOfParticles(),
+                    tracers0_integration_steps);
+        this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
+            long long int, double, double, 3>(
+                    MPI_COMM_WORLD,
+                    this->pset->getTotalNumberOfParticles(),
+                    (this->simname + "_particles.h5"),
+                    "tracers0",
+                    "position/0");
+
+        DEBUG_MSG("before writeParticleIndex\n");
+        this->pset->writeParticleLabels(
+                "particle_index_after.h5",
+                "tracers0",
+                "index",
+                psolver->getIteration());
+        DEBUG_MSG("after writeParticleIndex\n");
+    }
+
+    // test particle subset extraction
+    if (this->pset->getTotalNumberOfParticles() > 4)
+    {
+        particle_set<3, 1, 0> temp_pset(
+            this->fs->cvelocity->rlayout,
+            this->dkx,
+            this->dky,
+            this->dkz);
+        std::vector<long long int> indices_to_extract(2);
+        // TODO: possibly use a more complicated pattern, but remember to keep
+        // indices smaller than current total number of particles
+        indices_to_extract[0] = 2;
+        indices_to_extract[1] = 4;
+        temp_pset.init_as_subset_of(*(this->pset), indices_to_extract, false);
+        DEBUG_MSG("before writeParticleLabels for extracted subset\n");
+        temp_pset.writeParticleLabels(
+                "particle_subset_index.h5",
+                "tracers_subset",
+                "index",
+                psolver->getIteration());
+        DEBUG_MSG("after writeParticleLabels for extracted subset\n");
+    }
+
+    return EXIT_SUCCESS;
+}
+
+template <typename rnumber>
+int particle_deleter<rnumber>::read_parameters(void)
+{
+    TIMEZONE("particle_deleter::read_parameters");
+    this->NSVE<rnumber>::read_parameters();
+    hid_t parameter_file = H5Fopen((this->simname + ".h5").c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
+    this->niter_part = hdf5_tools::read_value<int>(parameter_file, "parameters/niter_part");
+    this->niter_part_fine_period = hdf5_tools::read_value<int>(parameter_file, "parameters/niter_part_fine_period");
+    this->niter_part_fine_duration = hdf5_tools::read_value<int>(parameter_file, "parameters/niter_part_fine_duration");
+    this->nparticles = hdf5_tools::read_value<int>(parameter_file, "parameters/nparticles");
+    this->tracers0_integration_steps = hdf5_tools::read_value<int>(parameter_file, "parameters/tracers0_integration_steps");
+    this->tracers0_neighbours = hdf5_tools::read_value<int>(parameter_file, "parameters/tracers0_neighbours");
+    this->tracers0_smoothness = hdf5_tools::read_value<int>(parameter_file, "parameters/tracers0_smoothness");
+    H5Fclose(parameter_file);
+    MPI_Barrier(this->comm);
+    return EXIT_SUCCESS;
+}
+
+template class particle_deleter<float>;
+template class particle_deleter<double>;
+
+
diff --git a/TurTLE/test/particle_set/particle_deleter.hpp b/TurTLE/test/particle_set/particle_deleter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0561b56d9cb9c2915ac9a8e133449e50ebd239b3
--- /dev/null
+++ b/TurTLE/test/particle_set/particle_deleter.hpp
@@ -0,0 +1,98 @@
+/**********************************************************************
+*                                                                     *
+*  Copyright 2021 Max Planck Institute                                *
+*                 for Dynamics and Self-Organization                  *
+*                                                                     *
+*  This file is part of TurTLE.                                       *
+*                                                                     *
+*  TurTLE is free software: you can redistribute it and/or modify     *
+*  it under the terms of the GNU General Public License as published  *
+*  by the Free Software Foundation, either version 3 of the License,  *
+*  or (at your option) any later version.                             *
+*                                                                     *
+*  TurTLE is distributed in the hope that it will be useful,          *
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
+*  GNU General Public License for more details.                       *
+*                                                                     *
+*  You should have received a copy of the GNU General Public License  *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>     *
+*                                                                     *
+* Contact: Cristian.Lalescu@ds.mpg.de                                 *
+*                                                                     *
+**********************************************************************/
+
+
+
+#ifndef PARTICLE_DELETER_HPP
+#define PARTICLE_DELETER_HPP
+
+
+
+#include <cstdlib>
+#include "base.hpp"
+#include "vorticity_equation.hpp"
+#include "full_code/NSVE.hpp"
+#include "particles/particles_system_builder.hpp"
+#include "particles/particles_output_hdf5.hpp"
+#include "particles/particles_sampling.hpp"
+#include "particles/interpolation/field_tinterpolator.hpp"
+#include "particles/interpolation/particle_set.hpp"
+#include "particles/particle_solver.hpp"
+#include "particles/rhs/tracer_with_collision_counter_rhs.hpp"
+
+/** \brief Test of particle deletion functionality.
+ *
+ *  Child of Navier Stokes vorticity equation solver, this class calls all the
+ *  methods from `NSVE`, and in addition:
+ *   --- integrates simple Lagrangian tracers in the resulting velocity field.
+ *   --- removes arbitrary particles from the set of tracers at each time step.
+ *  It also executes a p2p kernel that doesn't affect the particle trajectories
+ *  in any way.
+ *
+ */
+
+template <typename rnumber>
+class particle_deleter: public NSVE<rnumber>
+{
+    public:
+
+        /* parameters that are read in read_parameters */
+        int niter_part;
+        int niter_part_fine_period;
+        int niter_part_fine_duration;
+        int nparticles;
+        int tracers0_integration_steps;
+        int tracers0_neighbours;
+        int tracers0_smoothness;
+
+        /* other stuff */
+        field_tinterpolator<rnumber, FFTW, THREE, LINEAR> *fti;
+        tracer_with_collision_counter_rhs<rnumber, FFTW, LINEAR> *trhs;
+        particle_set<3, 3, 2> *pset;
+        particle_solver *psolver;
+
+        field<rnumber, FFTW, THREE> *previous_velocity;
+
+        particles_output_hdf5<long long int, double, 3> *particles_output_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
+
+        particle_deleter(
+                const MPI_Comm COMMUNICATOR,
+                const std::string &simulation_name):
+            NSVE<rnumber>(
+                    COMMUNICATOR,
+                    simulation_name){}
+        ~particle_deleter(){}
+
+        int initialize(void);
+        int step(void);
+        int finalize(void);
+
+        int read_parameters(void);
+        int write_checkpoint(void);
+        int do_stats(void);
+};
+
+#endif//PARTICLE_DELETER_HPP
+
diff --git a/TurTLE/test/profiler/Kraichnan_scalar_v1.cpp b/TurTLE/test/profiler/Kraichnan_scalar_v1.cpp
index 1b33f36fd29111844c09cea1639fbc8b8b809e7e..7e9a647da18ccf034b4a1ff050aedf575ea9abe4 100644
--- a/TurTLE/test/profiler/Kraichnan_scalar_v1.cpp
+++ b/TurTLE/test/profiler/Kraichnan_scalar_v1.cpp
@@ -2,20 +2,20 @@
 *                                                                             *
 *  Copyright 2019 Max Planck Institute for Dynamics and Self-Organization     *
 *                                                                             *
-*  This file is part of bfps.                                                 *
+*  This file is part of TurTLE.                                               *
 *                                                                             *
-*  bfps is free software: you can redistribute it and/or modify               *
+*  TurTLE is free software: you can redistribute it and/or modify             *
 *  it under the terms of the GNU General Public License as published          *
 *  by the Free Software Foundation, either version 3 of the License,          *
 *  or (at your option) any later version.                                     *
 *                                                                             *
-*  bfps is distributed in the hope that it will be useful,                    *
+*  TurTLE is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
 *  GNU General Public License for more details.                               *
 *                                                                             *
 *  You should have received a copy of the GNU General Public License          *
-*  along with bfps.  If not, see <http://www.gnu.org/licenses/>               *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>             *
 *                                                                             *
 * Contact: Cristian.Lalescu@ds.mpg.de                                         *
 *                                                                             *
diff --git a/TurTLE/test/profiler/Kraichnan_scalar_v1.hpp b/TurTLE/test/profiler/Kraichnan_scalar_v1.hpp
index cb50290650294cf795fc74011d64fe9925a3fab7..97aa9cdb6e37c49dc6ae446dc3ea88984894eb31 100644
--- a/TurTLE/test/profiler/Kraichnan_scalar_v1.hpp
+++ b/TurTLE/test/profiler/Kraichnan_scalar_v1.hpp
@@ -3,20 +3,20 @@
 *  Copyright 2017 Max Planck Institute                                *
 *                 for Dynamics and Self-Organization                  *
 *                                                                     *
-*  This file is part of bfps.                                         *
+*  This file is part of TurTLE.                                       *
 *                                                                     *
-*  bfps is free software: you can redistribute it and/or modify       *
+*  TurTLE is free software: you can redistribute it and/or modify     *
 *  it under the terms of the GNU General Public License as published  *
 *  by the Free Software Foundation, either version 3 of the License,  *
 *  or (at your option) any later version.                             *
 *                                                                     *
-*  bfps is distributed in the hope that it will be useful,            *
+*  TurTLE is distributed in the hope that it will be useful,          *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
 *  GNU General Public License for more details.                       *
 *                                                                     *
 *  You should have received a copy of the GNU General Public License  *
-*  along with bfps.  If not, see <http://www.gnu.org/licenses/>       *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>     *
 *                                                                     *
 * Contact: Cristian.Lalescu@ds.mpg.de                                 *
 *                                                                     *
diff --git a/TurTLE/test/profiler/scalar_evolution.cpp b/TurTLE/test/profiler/scalar_evolution.cpp
index fa52286ea563588cc25260be9dff989e0b8e187c..5e112ea31ecc86aabbfd67f38f326ec5a0627d37 100644
--- a/TurTLE/test/profiler/scalar_evolution.cpp
+++ b/TurTLE/test/profiler/scalar_evolution.cpp
@@ -2,20 +2,20 @@
 *                                                                             *
 *  Copyright 2019 Max Planck Institute for Dynamics and Self-Organization     *
 *                                                                             *
-*  This file is part of bfps.                                                 *
+*  This file is part of TurTLE.                                               *
 *                                                                             *
-*  bfps is free software: you can redistribute it and/or modify               *
+*  TurTLE is free software: you can redistribute it and/or modify             *
 *  it under the terms of the GNU General Public License as published          *
 *  by the Free Software Foundation, either version 3 of the License,          *
 *  or (at your option) any later version.                                     *
 *                                                                             *
-*  bfps is distributed in the hope that it will be useful,                    *
+*  TurTLE is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
 *  GNU General Public License for more details.                               *
 *                                                                             *
 *  You should have received a copy of the GNU General Public License          *
-*  along with bfps.  If not, see <http://www.gnu.org/licenses/>               *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>             *
 *                                                                             *
 * Contact: Cristian.Lalescu@ds.mpg.de                                         *
 *                                                                             *
diff --git a/TurTLE/test/profiler/scalar_evolution.hpp b/TurTLE/test/profiler/scalar_evolution.hpp
index 48eca0284006ed3344469441fbe23bd8709a3809..0eea813183e52d1f489e502f4205b00fcef48833 100644
--- a/TurTLE/test/profiler/scalar_evolution.hpp
+++ b/TurTLE/test/profiler/scalar_evolution.hpp
@@ -3,20 +3,20 @@
 *  Copyright 2017 Max Planck Institute                                *
 *                 for Dynamics and Self-Organization                  *
 *                                                                     *
-*  This file is part of bfps.                                         *
+*  This file is part of TurTLE.                                       *
 *                                                                     *
-*  bfps is free software: you can redistribute it and/or modify       *
+*  TurTLE is free software: you can redistribute it and/or modify     *
 *  it under the terms of the GNU General Public License as published  *
 *  by the Free Software Foundation, either version 3 of the License,  *
 *  or (at your option) any later version.                             *
 *                                                                     *
-*  bfps is distributed in the hope that it will be useful,            *
+*  TurTLE is distributed in the hope that it will be useful,          *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
 *  GNU General Public License for more details.                       *
 *                                                                     *
 *  You should have received a copy of the GNU General Public License  *
-*  along with bfps.  If not, see <http://www.gnu.org/licenses/>       *
+*  along with TurTLE.  If not, see <http://www.gnu.org/licenses/>     *
 *                                                                     *
 * Contact: Cristian.Lalescu@ds.mpg.de                                 *
 *                                                                     *
diff --git a/TurTLE/test/test_particle_deleter.py b/TurTLE/test/test_particle_deleter.py
new file mode 100644
index 0000000000000000000000000000000000000000..a7bbe788433c201c01e16bf6f27f8ad9cf706b92
--- /dev/null
+++ b/TurTLE/test/test_particle_deleter.py
@@ -0,0 +1,379 @@
+import os
+import sys
+import argparse
+import getpass
+
+import numpy as np
+import h5py
+
+import TurTLE
+import TurTLE._base
+import TurTLE.DNS
+from TurTLE._code import _code
+
+cpp_location = os.path.join(
+        TurTLE.data_dir, 'particle_set')
+
+
+class ADNS(TurTLE.DNS):
+    def __init__(
+            self,
+            **kwargs):
+        TurTLE.DNS.__init__(self, **kwargs)
+        return None
+    def write_src(
+            self):
+        self.version_message = (
+                '/***********************************************************************\n' +
+                '* this code automatically generated by TurTLE\n' +
+                '* version {0}\n'.format(TurTLE.__version__) +
+                '***********************************************************************/\n\n\n')
+        self.include_list = [
+                '"base.hpp"',
+                '"scope_timer.hpp"',
+                '"fftw_interface.hpp"',
+                '"full_code/main_code.hpp"',
+                '"full_code/NSVEparticles.hpp"',
+                '<cmath>',
+                '<iostream>',
+                '<hdf5.h>',
+                '<string>',
+                '<cstring>',
+                '<fftw3-mpi.h>',
+                '<omp.h>',
+                '<cfenv>',
+                '<cstdlib>']
+        self.main = """
+            int main(int argc, char *argv[])
+            {{
+                bool fpe = (
+                    (getenv("BFPS_FPE_OFF") == nullptr) ||
+                    (getenv("BFPS_FPE_OFF") != std::string("TRUE")));
+                return main_code< {0} >(argc, argv, fpe);
+            }}
+            """.format(self.dns_type + '<{0}>'.format(self.C_field_dtype))
+        self.includes = '\n'.join(
+                ['#include ' + hh
+                 for hh in self.include_list])
+        self.name = 'particle_deleter'
+        self.dns_type = 'particle_deleter'
+        self.definitions += open(
+            os.path.join(
+                cpp_location, self.dns_type + '.hpp'), 'r').read()
+        self.definitions += open(
+            os.path.join(
+                cpp_location, self.dns_type + '.cpp'), 'r').read()
+        with open(self.name + '.cpp', 'w') as outfile:
+            outfile.write(self.version_message + '\n\n')
+            outfile.write(self.includes + '\n\n')
+            outfile.write(self.definitions + '\n\n')
+            outfile.write(self.main + '\n')
+        self.check_current_vorticity_exists = True
+        return None
+    def generate_default_parameters(self):
+        # these parameters are relevant for all DNS classes
+        self.parameters['fftw_plan_rigor'] = 'FFTW_ESTIMATE'
+        self.parameters['dealias_type'] = int(1)
+        self.parameters['dkx'] = float(1.0)
+        self.parameters['dky'] = float(1.0)
+        self.parameters['dkz'] = float(1.0)
+        self.parameters['niter_todo'] = int(20)
+        self.parameters['niter_stat'] = int(2)
+        self.parameters['niter_out'] = int(20)
+        self.parameters['checkpoints_per_file'] = int(1)
+        self.parameters['dt'] = float(0.0001)
+        self.parameters['histogram_bins'] = int(64)
+        self.parameters['max_velocity_estimate'] = float(1)
+        self.parameters['max_vorticity_estimate'] = float(1)
+        self.parameters['niter_part'] = int(1)
+        self.parameters['niter_part_fine_period'] = int(2)
+        self.parameters['niter_part_fine_duration'] = int(0)
+        self.parameters['nparticles'] = int(100)
+        self.parameters['tracers0_integration_steps'] = int(0)
+        self.parameters['tracers0_neighbours'] = int(3)
+        self.parameters['tracers0_smoothness'] = int(2)
+        self.parameters['tracers0_enable_p2p'] = int(0)
+        self.parameters['tracers0_enable_inner'] = int(0)
+        self.parameters['tracers0_enable_vorticity_omega'] = int(0)
+        self.parameters['tracers0_cutoff'] = float(0.920272)
+        self.parameters['tracers0_inner_v0'] = float(1)
+        self.parameters['tracers0_lambda'] = float(1)
+
+        self.parameters['nu'] = float(0.1)
+        self.parameters['fmode'] = int(1)
+        self.parameters['famplitude'] = float(0.5)
+        self.parameters['friction_coefficient'] = float(0.5)
+        self.parameters['injection_rate'] = float(0.4)
+        self.parameters['fk0'] = float(2.0)
+        self.parameters['fk1'] = float(4.0)
+        self.parameters['energy'] = float(0.5)
+        self.parameters['forcing_type'] = 'fixed_energy_injection_rate'
+        return None
+    def generate_tracer_state(
+            self,
+            rseed = None,
+            species = 0,
+            integration_steps = None,
+            ncomponents = 3):
+        try:
+            if type(integration_steps) == type(None):
+                integration_steps = self.NSVEp_extra_parameters['tracers0_integration_steps']
+            if 'tracers{0}_integration_steps'.format(species) in self.parameters.keys():
+                integration_steps = self.parameters['tracers{0}_integration_steps'.format(species)]
+            with h5py.File(self.get_checkpoint_0_fname(), 'a') as data_file:
+                nn = self.parameters['nparticles']
+                if not 'tracers{0}'.format(species) in data_file.keys():
+                    data_file.create_group('tracers{0}'.format(species))
+                    data_file.create_group('tracers{0}/rhs'.format(species))
+                    data_file.create_group('tracers{0}/state'.format(species))
+                data_file['tracers{0}/rhs'.format(species)].create_dataset(
+                        '0',
+                        shape = (integration_steps, nn, ncomponents,),
+                        dtype = np.float)
+                dset = data_file['tracers{0}/state'.format(species)].create_dataset(
+                        '0',
+                        shape = (nn, ncomponents,),
+                        dtype = np.float)
+                if not type(rseed) == type(None):
+                    np.random.seed(rseed)
+                cc = int(0)
+                batch_size = int(1e6)
+                def get_random_phases(npoints):
+                    return np.random.random(
+                                (npoints, 3))*2*np.pi
+                def get_random_versors(npoints):
+                    bla = np.random.normal(
+                            size = (npoints, 3))
+                    bla  /= np.sum(bla**2, axis = 1)[:, None]**.5
+                    return bla
+                while nn > 0:
+                    if nn > batch_size:
+                        dset[cc*batch_size:(cc+1)*batch_size, :3] = get_random_phases(batch_size)
+                        if dset.shape[1] == 6:
+                            dset[cc*batch_size:(cc+1)*batch_size, 3:] = 0.0* get_random_versors(batch_size)
+                        nn -= batch_size
+                    else:
+                        dset[cc*batch_size:cc*batch_size+nn, :3] = get_random_phases(nn)
+                        if dset.shape[1] == 6:
+                            dset[cc*batch_size:cc*batch_size+nn, 3:] = 0.0* get_random_versors(nn)
+                        nn = 0
+                    cc += 1
+        except Exception as e:
+            print(e)
+        return None
+    def prepare_launch(
+            self,
+            args = [],
+            **kwargs):
+        parser = argparse.ArgumentParser('turtle ' + type(self).__name__)
+        self.job_parser_arguments(parser)
+        self.simulation_parser_arguments(parser)
+        self.particle_parser_arguments(parser)
+        self.parameters_to_parser_arguments(parser)
+        opt = parser.parse_args(args)
+        self.simname=opt.simname
+        self.set_precision(opt.precision)
+        self.dns_type = 'particle_deleter'
+        self.name = self.dns_type + '-' + self.fluid_precision + '-v' + TurTLE.__version__
+        if ((self.parameters['niter_todo'] % self.parameters['niter_out']) != 0):
+            self.parameters['niter_out'] = self.parameters['niter_todo']
+        if len(opt.src_work_dir) == 0:
+            opt.src_work_dir = os.path.realpath(opt.work_dir)
+        if type(opt.dkx) == type(None):
+            opt.dkx = 2. / opt.Lx
+        if type(opt.dky) == type(None):
+            opt.dky = 2. / opt.Ly
+        if type(opt.dkz) == type(None):
+            opt.dkz = 2. / opt.Lz
+        if type(opt.nx) == type(None):
+            opt.nx = opt.n
+        if type(opt.ny) == type(None):
+            opt.ny = opt.n
+        if type(opt.nz) == type(None):
+            opt.nz = opt.n
+        if type(opt.fk0) == type(None):
+            opt.fk0 = self.parameters['fk0']
+        if type(opt.fk1) == type(None):
+            opt.fk1 = self.parameters['fk1']
+        if type(opt.injection_rate) == type(None):
+            opt.injection_rate = self.parameters['injection_rate']
+        if type(opt.dealias_type) == type(None):
+            opt.dealias_type = self.parameters['dealias_type']
+        if (opt.nx > opt.n or
+            opt.ny > opt.n or
+            opt.nz > opt.n):
+            opt.n = min(opt.nx, opt.ny, opt.nz)
+            print("Warning: '-n' parameter changed to minimum of nx, ny, nz. This affects the computation of nu.")
+        self.parameters['nu'] = (opt.kMeta * 2 / opt.n)**(4./3)
+        # check value of kMax
+        kM = opt.n * 0.5
+        if opt.dealias_type == 1:
+            kM *= 0.8
+        # tweak forcing/viscosity based on forcint type
+        if opt.forcing_type == 'linear':
+            # custom famplitude for 288 and 576
+            if opt.n == 288:
+                self.parameters['famplitude'] = 0.45
+            elif opt.n == 576:
+                self.parameters['famplitude'] = 0.47
+        elif opt.forcing_type == 'fixed_energy_injection_rate':
+            # use the fact that mean dissipation rate is equal to injection rate
+            self.parameters['nu'] = (
+                    opt.injection_rate *
+                    (opt.kMeta / kM)**4)**(1./3)
+        elif opt.forcing_type == 'fixed_energy':
+            kf = 1. / (1./opt.fk0 +
+                       1./opt.fk1)
+            self.parameters['nu'] = (
+                    (opt.kMeta / kM)**(4./3) *
+                    (np.pi / kf)**(1./3) *
+                    (2*self.parameters['energy'] / 3)**0.5)
+        if type(opt.checkpoints_per_file) == type(None):
+            # hardcoded FFTW complex representation size
+            field_size = 3*(opt.nx+2)*opt.ny*opt.nz*self.fluid_dtype.itemsize
+            checkpoint_size = field_size
+        self.set_host_info(TurTLE.host_info)
+        if type(opt.environment) != type(None):
+            self.host_info['environment'] = opt.environment
+        self.pars_from_namespace(opt)
+        return opt
+
+    def write_par(
+            self,
+            iter0 = 0):
+        assert (self.parameters['niter_todo'] % self.parameters['niter_stat'] == 0)
+        assert (self.parameters['niter_todo'] % self.parameters['niter_out']  == 0)
+        assert (self.parameters['niter_out']  % self.parameters['niter_stat'] == 0)
+        assert (self.parameters['niter_todo'] % self.parameters['niter_part'] == 0)
+        assert (self.parameters['niter_out']  % self.parameters['niter_part'] == 0)
+        _code.write_par(self, iter0 = iter0)
+        with h5py.File(self.get_data_file_name(), 'r+') as ofile:
+            ofile['code_info/exec_name'] = self.name
+            kspace = self.get_kspace()
+            for k in kspace.keys():
+                ofile['kspace/' + k] = kspace[k]
+            nshells = kspace['nshell'].shape[0]
+            kspace = self.get_kspace()
+            nshells = kspace['nshell'].shape[0]
+            vec_stat_datasets = ['velocity', 'vorticity']
+            scal_stat_datasets = []
+            for k in vec_stat_datasets:
+                time_chunk = 2**20//(8*3*3*nshells)
+                time_chunk = max(time_chunk, 1)
+                ofile.create_dataset('statistics/spectra/' + k + '_' + k,
+                                     (1, nshells, 3, 3),
+                                     chunks = (time_chunk, nshells, 3, 3),
+                                     maxshape = (None, nshells, 3, 3),
+                                     dtype = np.float64)
+                time_chunk = 2**20//(8*4*10)
+                time_chunk = max(time_chunk, 1)
+                a = ofile.create_dataset('statistics/moments/' + k,
+                                     (1, 10, 4),
+                                     chunks = (time_chunk, 10, 4),
+                                     maxshape = (None, 10, 4),
+                                     dtype = np.float64)
+                time_chunk = 2**20//(8*4*self.parameters['histogram_bins'])
+                time_chunk = max(time_chunk, 1)
+                ofile.create_dataset('statistics/histograms/' + k,
+                                     (1,
+                                      self.parameters['histogram_bins'],
+                                      4),
+                                     chunks = (time_chunk,
+                                               self.parameters['histogram_bins'],
+                                               4),
+                                     maxshape = (None,
+                                                 self.parameters['histogram_bins'],
+                                                 4),
+                                     dtype = np.int64)
+            #TODO move collision stats to particle stats
+            for i in range(self.parameters['niter_out']):
+                ofile.create_dataset('statistics/collisions/'+str(i),
+                                     shape=(1,),
+                                     dtype = np.int64)
+            ofile['checkpoint'] = int(0)
+        if (self.dns_type in ['NSVE', 'NSVE_no_output']):
+            return None
+        return None
+
+    def launch(
+            self,
+            args = [],
+            **kwargs):
+        opt = self.prepare_launch(args = args)
+        if not os.path.exists(self.get_data_file_name()):
+            self.write_par()
+            self.generate_initial_condition(opt = opt)
+            with h5py.File(self.get_particle_file_name(), 'w') as particle_file:
+                particle_file.create_group('tracers0/position')
+                particle_file.create_group('tracers0/velocity')
+                particle_file.create_group('collisions0')
+            with h5py.File('particle_index_before.h5', 'w') as particle_file:
+                particle_file.create_group('tracers0/index')
+            with h5py.File('particle_index_after.h5', 'w') as particle_file:
+                particle_file.create_group('tracers0/index')
+            with h5py.File('particle_subset_index.h5', 'w') as particle_file:
+                particle_file.create_group('tracers_subset/index')
+            self.generate_tracer_state(integration_steps = self.parameters['tracers0_integration_steps'],
+                                       rseed = opt.particle_rand_seed,
+                                       ncomponents = 3)
+        self.run(
+                nb_processes = opt.nb_processes,
+                nb_threads_per_process = opt.nb_threads_per_process,
+                njobs = opt.njobs,
+                hours = opt.minutes // 60,
+                minutes = opt.minutes % 60,
+                no_submit = opt.no_submit,
+                no_debug = opt.no_debug)
+        return None
+
+def main():
+    #####################################################################
+    ## run c++ test
+    bla = ADNS()
+    bla.launch(sys.argv[1:])
+    #####################################################################
+
+    #####################################################################
+    ## python routine replicating deleting pattern of the test in c++
+    def delete_index(before_py, iteration):
+        index2 =  (iteration*3)%len(before_py)
+        index_to_delete = np.array([1, index2])
+        if index2==1:
+            index_to_delete = np.array([1, 3])
+        after_py = np.delete(before_py, index_to_delete)
+        return before_py, after_py
+    #####################################################################
+
+    #####################################################################
+    ## perform sanity check
+    f = h5py.File(bla.simname + '.h5', 'r')
+    p = f['parameters']
+    #initialising list of indeces
+    before_py = np.arange(0,np.array(p['nparticles']))
+    #comparing list of particles for each iteration 
+    for i in range(np.array(p['niter_todo'])):
+        #apply python routine
+        before_py, after_py = delete_index(before_py, i)
+        #load turtle indeces
+        before_turtle = h5py.File('particle_index_before.h5','r')
+        after_turtle = h5py.File('particle_index_after.h5','r')
+        subset_turtle = h5py.File('particle_subset_index.h5', 'r')
+        index_before_turtle = np.array(before_turtle['tracers0/index/'+str(i)])
+        index_after_turtle = np.array(after_turtle['tracers0/index/'+str(i)])
+        index_subset = np.array(subset_turtle['tracers_subset/index/'+str(i)])
+        index_before_turtle = index_before_turtle.flatten()
+        index_after_turtle = index_after_turtle.flatten()
+        index_subset = index_subset.flatten()
+        print('testing labels iteration {0}'.format(i))
+        assert(np.all(before_py==index_before_turtle) and
+               np.all(after_py==index_after_turtle))
+        print('testing subset labels iteration {0}'.format(i))
+        assert(np.all(after_py[[2, 4]]==index_subset))
+        if(len(after_py)==2):
+            break
+        before_py = after_py
+    #####################################################################
+    return None
+
+if __name__ == '__main__':
+    main()
diff --git a/cpp/base.hpp b/cpp/base.hpp
index be05de0490194d34148f7afc888281a918169d8f..55562ebcefd600fbeb6087f60552bede030ec64f 100644
--- a/cpp/base.hpp
+++ b/cpp/base.hpp
@@ -23,17 +23,16 @@
 **********************************************************************/
 
 
+#ifndef BASE_HPP
+
+#define BASE_HPP
+
 
 #include <cassert>
 #include <mpi.h>
 #include <stdarg.h>
 #include <iostream>
 #include <typeinfo>
-#include "hdf5_tools.hpp"
-
-#ifndef BASE
-
-#define BASE
 
 
 /////////////////////////////////////////////////////////////
@@ -210,5 +209,5 @@ inline void DEBUG_MSG_WAIT(MPI_Comm communicator, const char * format, ...)
 
 #define variable_used_only_in_assert(x) ((void)(x))
 
-#endif//BASE
+#endif//BASE_HPP
 
diff --git a/cpp/fftw_tools.hpp b/cpp/fftw_tools.hpp
index 11c1cbf9e32377f6b59caa90f1350c1a73606d84..5fbcdf81bb3e3e82def8e897ed80a8c803584282 100644
--- a/cpp/fftw_tools.hpp
+++ b/cpp/fftw_tools.hpp
@@ -24,16 +24,16 @@
 
 
 
+#ifndef FFTW_TOOLS
+#define FFTW_TOOLS
+
+
 #include <mpi.h>
 #include <fftw3-mpi.h>
 #include <string>
 #include <map>
 #include <cmath>
 
-#ifndef FFTW_TOOLS
-
-#define FFTW_TOOLS
-
 
 // helper function
 inline void complex_number_phase_shifter(double &xx, double &yy, const double cos_val, const double sin_val)
diff --git a/cpp/field.cpp b/cpp/field.cpp
index 3efc8ee29007f7a2305a9d53d9d09d3d5280826f..6e950ad450553dbfccfa3ba33f0ae0bab168c58b 100644
--- a/cpp/field.cpp
+++ b/cpp/field.cpp
@@ -103,7 +103,7 @@ field<rnumber, be, fc>::field(
                     sizes, subsizes, starts, this->comm);
             this->data = fftw_interface<rnumber>::alloc_real(
                     this->rmemlayout->local_size);
-            char *plan_information = NULL;
+            //char *plan_information = NULL;
             this->c2r_plan = fftw_interface<rnumber>::mpi_plan_many_dft_c2r(
                     3, nfftw, ncomp(fc),
                     FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK,
@@ -1604,6 +1604,7 @@ template <typename rnumber,
 void field<rnumber, be, fc>::symmetrize_alternate()
 {
     TIMEZONE("field::symmetrize");
+    MPI_Barrier(this->clayout->comm); // TODO: figure out if this can be taken out by careful MPI tag generation
     start_mpi_profiling_zone(turtle_mpi_pcontrol::FIELD);
     assert(!this->real_space_representation);
     typename fftw_interface<rnumber>::complex *cdata = this->get_cdata();
@@ -1812,8 +1813,6 @@ void field<rnumber, be, fc>::symmetrize_alternate()
             ptrdiff_t cindex1 = this->get_cindex(0, 0, this->clayout->sizes[1] - iz);
             for (int cc = 0; cc < int(ncomp(fc)); cc++)
             {
-                double re = ((*(cdata + cc + ncomp(fc)*cindex0))[0] + (*(cdata + cc + ncomp(fc)*cindex1))[0])/2;
-                double im = ((*(cdata + cc + ncomp(fc)*cindex0))[1] - (*(cdata + cc + ncomp(fc)*cindex1))[1])/2;
                 const double ampp = sqrt(
                         (*(cdata + cc + ncomp(fc)*cindex0))[0]*(*(cdata + cc + ncomp(fc)*cindex0))[0] +
                         (*(cdata + cc + ncomp(fc)*cindex0))[1]*(*(cdata + cc + ncomp(fc)*cindex0))[1]);
@@ -1836,6 +1835,7 @@ void field<rnumber, be, fc>::symmetrize_alternate()
         }
     }
     finish_mpi_profiling_zone(turtle_mpi_pcontrol::FIELD);
+    MPI_Barrier(this->clayout->comm); // TODO: figure out if this can be taken out by careful MPI tag generation
 }
 
 /** \brief Enforce Hermitian symmetry (fast and reasonable)
@@ -3085,7 +3085,7 @@ int generate_random_phase_field(
                             }
                         }
                     }
-                    if (xindex == output_field->clayout->sizes[2]-1)
+                    if (xindex == ptrdiff_t(output_field->clayout->sizes[2])-ptrdiff_t(1))
                         {
                         output_field->cval(cindex, 0) = 0;
                         output_field->cval(cindex, 1) = 0;
diff --git a/cpp/field.hpp b/cpp/field.hpp
index a42d480111bd62339bf7d547d3c049685291de23..f6c69a7d1e10d6751e0be0055518b1fa4c2d2e6c 100644
--- a/cpp/field.hpp
+++ b/cpp/field.hpp
@@ -24,6 +24,10 @@
 
 
 
+#ifndef FIELD_HPP
+
+#define FIELD_HPP
+
 #include <hdf5.h>
 #include <unordered_map>
 #include <vector>
@@ -31,10 +35,6 @@
 #include "kspace.hpp"
 #include "omputils.hpp"
 
-#ifndef FIELD_HPP
-
-#define FIELD_HPP
-
 /** \class field
  *  \brief Holds field data, performs FFTs and HDF5 I/O operations.
  *
@@ -87,7 +87,7 @@ class field
                 const int nz,
                 const MPI_Comm COMM_TO_USE,
                 const unsigned FFTW_PLAN_RIGOR = DEFAULT_FFTW_FLAG);
-        ~field();
+        ~field() noexcept(false);
 
         int io(
                 const std::string fname,
diff --git a/cpp/field_binary_IO.hpp b/cpp/field_binary_IO.hpp
index 0742a2cb0408ea5aee2022aca02d62104fdfea13..c615f9e266fa7de5816c0cd98b5a830dc81d6e48 100644
--- a/cpp/field_binary_IO.hpp
+++ b/cpp/field_binary_IO.hpp
@@ -24,6 +24,10 @@
 
 
 
+#ifndef FIELD_BINARY_IO_HPP
+
+#define FIELD_BINARY_IO_HPP
+
 #include <vector>
 #include <string>
 #include "base.hpp"
@@ -31,10 +35,6 @@
 #include "field_layout.hpp"
 #include "field.hpp"
 
-#ifndef FIELD_BINARY_IO_HPP
-
-#define FIELD_BINARY_IO_HPP
-
 /* could this be a boolean somehow?*/
 enum field_representation: bool {
     REAL = true,
@@ -72,7 +72,7 @@ class field_binary_IO:public field_layout<fc>
                 const hsize_t *SUBSIZES,
                 const hsize_t *STARTS,
                 const MPI_Comm COMM_TO_USE);
-        ~field_binary_IO();
+        ~field_binary_IO() noexcept(false);
 
         int read(
                 const std::string fname,
diff --git a/cpp/field_layout.hpp b/cpp/field_layout.hpp
index edc094a953e16b2817d1d68bb4248c8b4cbc7d13..e7ba578cbeb5f7e990e2c21f95e0cb9cc1054985 100644
--- a/cpp/field_layout.hpp
+++ b/cpp/field_layout.hpp
@@ -24,13 +24,14 @@
 
 
 
-#include <vector>
-#include "base.hpp"
-
 #ifndef FIELD_LAYOUT_HPP
 
 #define FIELD_LAYOUT_HPP
 
+#include <vector>
+#include <hdf5.h>
+#include "base.hpp"
+
 enum field_components {ONE, THREE, THREExTHREE};
 
 constexpr unsigned int ncomp(
@@ -52,7 +53,7 @@ constexpr unsigned int ndim(
 class abstract_field_layout
 {
     public:
-        virtual ~abstract_field_layout(){}
+        virtual ~abstract_field_layout() noexcept(false){}
 
         virtual MPI_Comm getMPIComm() const = 0;
         virtual int getMPIRank() const = 0;
@@ -85,7 +86,7 @@ class field_layout: public abstract_field_layout
                 const hsize_t *SUBSIZES,
                 const hsize_t *STARTS,
                 const MPI_Comm COMM_TO_USE);
-        ~field_layout(){}
+        ~field_layout() noexcept(false){}
 
         MPI_Comm getMPIComm() const
         {
diff --git a/cpp/full_code/Gauss_field_test.cpp b/cpp/full_code/Gauss_field_test.cpp
index a9c604ee46352acf85c505d05cfa7c6a72f0279c..6f7cdfd16877f3d207dd8f1a30c5058bf2a03dfb 100644
--- a/cpp/full_code/Gauss_field_test.cpp
+++ b/cpp/full_code/Gauss_field_test.cpp
@@ -29,6 +29,7 @@
 #include <random>
 #include "Gauss_field_test.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 
diff --git a/cpp/full_code/NSE.cpp b/cpp/full_code/NSE.cpp
index 7c1c058d27fda089418c343145478e530f264e3c..25a4c3956f98143bba4be477490499fa67533921 100644
--- a/cpp/full_code/NSE.cpp
+++ b/cpp/full_code/NSE.cpp
@@ -28,6 +28,7 @@
 #include "NSE.hpp"
 #include "scope_timer.hpp"
 #include "fftw_tools.hpp"
+#include "hdf5_tools.hpp"
 #include "shared_array.hpp"
 
 
diff --git a/cpp/full_code/NSVE.cpp b/cpp/full_code/NSVE.cpp
index 9abb40fa2d6beeb96887af79641165bbebb5a2e8..09ca7f286be9d1d17ba3bce5125187bf88fb8024 100644
--- a/cpp/full_code/NSVE.cpp
+++ b/cpp/full_code/NSVE.cpp
@@ -28,6 +28,7 @@
 #include "NSVE.hpp"
 #include "scope_timer.hpp"
 #include "fftw_tools.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
diff --git a/cpp/full_code/NSVE.hpp b/cpp/full_code/NSVE.hpp
index df8ffc5daf2aea10dd8891334ff9fd6c1aa62182..2f29f91fef5c990f1676dc547e30458c0ff97a0b 100644
--- a/cpp/full_code/NSVE.hpp
+++ b/cpp/full_code/NSVE.hpp
@@ -75,7 +75,7 @@ class NSVE: public direct_numerical_simulation
             direct_numerical_simulation(
                     COMMUNICATOR,
                     simulation_name){}
-        ~NSVE(){}
+        ~NSVE() noexcept(false){}
 
         int initialize(void);
         int step(void);
diff --git a/cpp/full_code/NSVE_Stokes_particles.cpp b/cpp/full_code/NSVE_Stokes_particles.cpp
index 83a1a7eff29b9b02f017df3476546e5d4d37715f..8da3bcd0ac5dd8091d05b7c938856858dd8ffef8 100644
--- a/cpp/full_code/NSVE_Stokes_particles.cpp
+++ b/cpp/full_code/NSVE_Stokes_particles.cpp
@@ -70,7 +70,7 @@ int NSVE_Stokes_particles<rnumber>::initialize(void)
                 tracers0_integration_steps);
     this->particles_output_writer_mpi->setParticleFileLayout(this->ps->getParticleFileLayout());
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 this->ps->getGlobalNbParticles(),
                 (this->simname + "_particles.h5"),
diff --git a/cpp/full_code/NSVE_Stokes_particles.hpp b/cpp/full_code/NSVE_Stokes_particles.hpp
index ecc2d135064f245a36d905714e05770e3574d074..fb8497c99074e52c246ac83ba9a071e53d3023c6 100644
--- a/cpp/full_code/NSVE_Stokes_particles.hpp
+++ b/cpp/full_code/NSVE_Stokes_particles.hpp
@@ -65,7 +65,7 @@ class NSVE_Stokes_particles: public NSVE<rnumber>
         field<rnumber, FFTW, ONE> *pressure;
 
         particles_output_hdf5<long long int, double,6> *particles_output_writer_mpi;
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
 
         NSVE_Stokes_particles(
diff --git a/cpp/full_code/NSVE_field_stats.cpp b/cpp/full_code/NSVE_field_stats.cpp
index 3063943d4baf4111b06e98ea1acdf5efce50f240..4ee109b88463436a9448a421dad31b5833af76b0 100644
--- a/cpp/full_code/NSVE_field_stats.cpp
+++ b/cpp/full_code/NSVE_field_stats.cpp
@@ -28,6 +28,7 @@
 #include "NSVE_field_stats.hpp"
 #include "fftw_tools.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
diff --git a/cpp/full_code/NSVE_field_stats.hpp b/cpp/full_code/NSVE_field_stats.hpp
index de2078eedf23a576a58b7faca1f3b34bb314bf16..a04215389a7773f8ecbdf052d4a2a6fd4119b1b0 100644
--- a/cpp/full_code/NSVE_field_stats.hpp
+++ b/cpp/full_code/NSVE_field_stats.hpp
@@ -52,7 +52,7 @@ class NSVE_field_stats: public postprocess
             postprocess(
                     COMMUNICATOR,
                     simulation_name){}
-        virtual ~NSVE_field_stats(){}
+        virtual ~NSVE_field_stats() noexcept(false){}
 
         virtual int initialize(void);
         virtual int work_on_current_iteration(void);
diff --git a/cpp/full_code/NSVE_no_output.hpp b/cpp/full_code/NSVE_no_output.hpp
index d912aec40fe32e5423300495251f4cd0f55dc40c..d739745cff1df3fe98ad555b0c1c919834cd64da 100644
--- a/cpp/full_code/NSVE_no_output.hpp
+++ b/cpp/full_code/NSVE_no_output.hpp
@@ -39,7 +39,7 @@ class NSVE_no_output: public NSVE<rnumber>
         NSVE<rnumber>(
                 COMMUNICATOR,
                 simulation_name){}
-    ~NSVE_no_output(){}
+    ~NSVE_no_output() noexcept(false){}
     int write_checkpoint(void)
     {
         TIMEZONE("NSVE_no_output::write_checkpoint");
diff --git a/cpp/full_code/NSVEcomplex_particles.cpp b/cpp/full_code/NSVEcomplex_particles.cpp
index f42518f77c90eda1efb73a6a769c06bbd3123f75..0c71cf723ca18e982a9b684a76b9f9c9f8834ae9 100644
--- a/cpp/full_code/NSVEcomplex_particles.cpp
+++ b/cpp/full_code/NSVEcomplex_particles.cpp
@@ -68,7 +68,7 @@ int NSVEcomplex_particles<rnumber>::initialize(void)
                 nparticles,
                 tracers0_integration_steps);
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 this->ps->getGlobalNbParticles(),
                 (this->simname + "_particles.h5"),
diff --git a/cpp/full_code/NSVEcomplex_particles.hpp b/cpp/full_code/NSVEcomplex_particles.hpp
index a63995f986d9793307b3c57230866ddde2b25e84..3f6adaac45e79594e1e15a1e1fde737e4a1ea27f 100644
--- a/cpp/full_code/NSVEcomplex_particles.hpp
+++ b/cpp/full_code/NSVEcomplex_particles.hpp
@@ -70,7 +70,7 @@ class NSVEcomplex_particles: public NSVE<rnumber>
         std::unique_ptr<abstract_particles_system<long long int, double>> ps;
         // TODO P2P use a reader with particle data
         particles_output_hdf5<long long int, double,6> *particles_output_writer_mpi;
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
         // field for sampling velocity gradient
         field<rnumber, FFTW, THREExTHREE> *nabla_u;
 
@@ -82,7 +82,7 @@ class NSVEcomplex_particles: public NSVE<rnumber>
                     COMMUNICATOR,
                     simulation_name),
             cutoff(10), inner_v0(1), lambda(1.0), enable_p2p(true), enable_inner(true), enable_vorticity_omega(true){}
-        ~NSVEcomplex_particles(){}
+        ~NSVEcomplex_particles() noexcept(false){}
 
         int initialize(void);
         int step(void);
diff --git a/cpp/full_code/NSVEparticles.cpp b/cpp/full_code/NSVEparticles.cpp
index e9bdfaf760565ba477f8634d34b98b5719143ff2..f2c53a4eadb5770ffecb4bb440fbc5e899b662a6 100644
--- a/cpp/full_code/NSVEparticles.cpp
+++ b/cpp/full_code/NSVEparticles.cpp
@@ -92,7 +92,7 @@ int NSVEparticles<rnumber>::initialize(void)
         this->particles_output_writer_mpi->template save<3>(
                 pset.getParticleState(),
                 rhs_data.data(),
-                pset.getParticleIndex(),
+                pset.getParticleIndices(),
                 pset.getLocalNumberOfParticles(),
                 0);
         this->particles_output_writer_mpi->close_file();
@@ -115,7 +115,7 @@ int NSVEparticles<rnumber>::initialize(void)
 
     // initialize sample object
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 this->ps->getGlobalNbParticles(),
                 (this->simname + "_particles.h5"),
diff --git a/cpp/full_code/NSVEparticles.hpp b/cpp/full_code/NSVEparticles.hpp
index bbb8ca9f508f3a4e4b1e0b6279b68cb7ffa847a6..dfa5598a911c3a6f7071312a8c22a43e9d0095e7 100644
--- a/cpp/full_code/NSVEparticles.hpp
+++ b/cpp/full_code/NSVEparticles.hpp
@@ -65,7 +65,7 @@ class NSVEparticles: public NSVE<rnumber>
         field<rnumber, FFTW, ONE> *pressure;
 
         particles_output_hdf5<long long int, double,3> *particles_output_writer_mpi;
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
 
         NSVEparticles(
@@ -74,7 +74,7 @@ class NSVEparticles: public NSVE<rnumber>
             NSVE<rnumber>(
                     COMMUNICATOR,
                     simulation_name){}
-        ~NSVEparticles(){}
+        ~NSVEparticles() noexcept(false){}
 
         int initialize(void);
         int step(void);
diff --git a/cpp/full_code/bandpass_stats.cpp b/cpp/full_code/bandpass_stats.cpp
index b176f892abdc5338dee3cd9a6127148c968bed44..7985a26af9be291915a0fcc088d4ccc084a6280f 100644
--- a/cpp/full_code/bandpass_stats.cpp
+++ b/cpp/full_code/bandpass_stats.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "bandpass_stats.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
@@ -47,6 +48,8 @@ int bandpass_stats<rnumber>::initialize(void)
     if (this->checkpoints_per_file == INT_MAX) // value returned if dataset does not exist
         this->checkpoints_per_file = 1;
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -67,6 +70,8 @@ int bandpass_stats<rnumber>::initialize(void)
             parameter_file,
             "/bandpass_stats/parameters/filter_type");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     assert(this->k0list.size() == this->k1list.size());
     if (this->myrank == 0)
     {
diff --git a/cpp/full_code/code_base.cpp b/cpp/full_code/code_base.cpp
index 1015aed91151bbcc94b5516a30a60ff6cf96f516..b62f50150fe815fc554c5bf63eab8568fa0218e6 100644
--- a/cpp/full_code/code_base.cpp
+++ b/cpp/full_code/code_base.cpp
@@ -26,6 +26,7 @@
 
 #include "code_base.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 code_base::code_base(
         const MPI_Comm COMMUNICATOR,
diff --git a/cpp/full_code/code_base.hpp b/cpp/full_code/code_base.hpp
index d42a7f99f10f5f71a6131e8d8bb72192315623e5..017785d4a3e52cd92c06c2fa356a6c1c76763eaa 100644
--- a/cpp/full_code/code_base.hpp
+++ b/cpp/full_code/code_base.hpp
@@ -71,7 +71,7 @@ class code_base
         code_base(
                 const MPI_Comm COMMUNICATOR,
                 const std::string &simulation_name);
-        virtual ~code_base(){}
+        virtual ~code_base() noexcept(false){}
 
         int check_stopping_condition(void);
 
diff --git a/cpp/full_code/dealias_test.cpp b/cpp/full_code/dealias_test.cpp
index e3afa2ac17fe66b79b4354310203e700c9601cf7..56980b54a9bbb8c7e35574e7c26908cd948a831f 100644
--- a/cpp/full_code/dealias_test.cpp
+++ b/cpp/full_code/dealias_test.cpp
@@ -29,6 +29,7 @@
 #include <random>
 #include "dealias_test.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 
diff --git a/cpp/full_code/dealias_test.hpp b/cpp/full_code/dealias_test.hpp
index 1757892819d68ce89b7c1296b8bbeba4fa9ae1ba..ba765c45086760910cd8bbc7270b55189e58b48e 100644
--- a/cpp/full_code/dealias_test.hpp
+++ b/cpp/full_code/dealias_test.hpp
@@ -65,7 +65,7 @@ class dealias_test: public test
             test(
                     COMMUNICATOR,
                     simulation_name){}
-        ~dealias_test(){}
+        ~dealias_test() noexcept(false){}
 
         int initialize(void);
         int do_work(void);
diff --git a/cpp/full_code/direct_numerical_simulation.hpp b/cpp/full_code/direct_numerical_simulation.hpp
index 668fa53f50d6a86dd1c281001af7ca1e64feb4e9..be5d498866372c2a7843fbac0768add479dcc271 100644
--- a/cpp/full_code/direct_numerical_simulation.hpp
+++ b/cpp/full_code/direct_numerical_simulation.hpp
@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "base.hpp"
+#include "hdf5_tools.hpp"
 #include "full_code/code_base.hpp"
 
 class direct_numerical_simulation: public code_base
@@ -50,7 +51,7 @@ class direct_numerical_simulation: public code_base
             code_base(
                     COMMUNICATOR,
                     simulation_name){}
-        virtual ~direct_numerical_simulation(){}
+        virtual ~direct_numerical_simulation() noexcept(false){}
 
         virtual int read_parameters(void);
         virtual int write_checkpoint(void) = 0;
diff --git a/cpp/full_code/field_single_to_double.cpp b/cpp/full_code/field_single_to_double.cpp
index 37eb482f511abd495f3999f029acbb0ad90bfcb3..9f2082e63613e7c2d64943c01d8c782f57e4a1cf 100644
--- a/cpp/full_code/field_single_to_double.cpp
+++ b/cpp/full_code/field_single_to_double.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "field_single_to_double.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
@@ -58,6 +59,8 @@ int field_single_to_double<rnumber>::initialize(void)
     else
         this->checkpoints_per_file = 1;
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -67,6 +70,8 @@ int field_single_to_double<rnumber>::initialize(void)
             parameter_file,
             "/field_single_to_double/parameters/iteration_list");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     return EXIT_SUCCESS;
 }
 
diff --git a/cpp/full_code/field_single_to_double.hpp b/cpp/full_code/field_single_to_double.hpp
index 04f56357c34b5365e1aa60cbb21ad5c7c60a30b9..de98e63ed5fda3fa9e6ffadfbb076c38436d414f 100644
--- a/cpp/full_code/field_single_to_double.hpp
+++ b/cpp/full_code/field_single_to_double.hpp
@@ -52,7 +52,7 @@ class field_single_to_double: public NSVE_field_stats<rnumber>
             NSVE_field_stats<rnumber>(
                     COMMUNICATOR,
                     simulation_name){}
-        virtual ~field_single_to_double(){}
+        virtual ~field_single_to_double() noexcept(false){}
 
         int initialize(void);
         int work_on_current_iteration(void);
diff --git a/cpp/full_code/field_test.cpp b/cpp/full_code/field_test.cpp
index 9b4c44605584efef0033c4930a7f48f831eb9603..0aa2b940fe69a5919d7ce6a7c38bc2d1ffb07f93 100644
--- a/cpp/full_code/field_test.cpp
+++ b/cpp/full_code/field_test.cpp
@@ -28,6 +28,7 @@
 #include <random>
 #include "field_test.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
diff --git a/cpp/full_code/filter_test.cpp b/cpp/full_code/filter_test.cpp
index 8d0ae00fd0ec0fa5c3fd2085163953d6d3303f90..e70cc61c7ce8d40b606262a451e99f3829958832 100644
--- a/cpp/full_code/filter_test.cpp
+++ b/cpp/full_code/filter_test.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "filter_test.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
diff --git a/cpp/full_code/get_3D_correlations.cpp b/cpp/full_code/get_3D_correlations.cpp
index 9a672f1c9cdd08730a4936e719e4a5e115d75f8e..6970e7af4a10e2f97d0a9fca542a0ee65989d800 100644
--- a/cpp/full_code/get_3D_correlations.cpp
+++ b/cpp/full_code/get_3D_correlations.cpp
@@ -27,7 +27,7 @@
 #include <cmath>
 #include "get_3D_correlations.hpp"
 #include "scope_timer.hpp"
-
+#include "hdf5_tools.hpp"
 
 template <typename rnumber>
 int get_3D_correlations<rnumber>::initialize(void)
@@ -62,6 +62,8 @@ int get_3D_correlations<rnumber>::initialize(void)
     if (this->checkpoints_per_file == INT_MAX) // value returned if dataset does not exist
         this->checkpoints_per_file = 1;
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -70,6 +72,8 @@ int get_3D_correlations<rnumber>::initialize(void)
             parameter_file,
             "/get_3D_correlations/parameters/iteration_list");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     return EXIT_SUCCESS;
 }
 
diff --git a/cpp/full_code/get_rfields.cpp b/cpp/full_code/get_rfields.cpp
index c3cf6c9b1d7a802f831c4faac939ed07d5552f3c..85864ee4d8f4fda468539a94cd43512a6aea5573 100644
--- a/cpp/full_code/get_rfields.cpp
+++ b/cpp/full_code/get_rfields.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "get_rfields.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
@@ -65,6 +66,8 @@ int get_rfields<rnumber>::initialize(void)
     if (this->checkpoints_per_file == INT_MAX) // value returned if dataset does not exist
         this->checkpoints_per_file = 1;
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -76,6 +79,8 @@ int get_rfields<rnumber>::initialize(void)
             parameter_file,
             "/get_rfields/parameters/TrS2_on");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     return EXIT_SUCCESS;
 }
 
diff --git a/cpp/full_code/get_velocity.cpp b/cpp/full_code/get_velocity.cpp
index 1509854d8d329e98fe2028257315941e7ce4cafc..a29cc660c72fd6e07cfcd41ad9f03482be7f1c1b 100644
--- a/cpp/full_code/get_velocity.cpp
+++ b/cpp/full_code/get_velocity.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "get_velocity.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
@@ -53,6 +54,8 @@ int get_velocity<rnumber>::initialize(void)
     if (this->checkpoints_per_file == INT_MAX) // value returned if dataset does not exist
         this->checkpoints_per_file = 1;
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -61,6 +64,8 @@ int get_velocity<rnumber>::initialize(void)
             parameter_file,
             "/get_velocity/parameters/iteration_list");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     return EXIT_SUCCESS;
 }
 
diff --git a/cpp/full_code/joint_acc_vel_stats.cpp b/cpp/full_code/joint_acc_vel_stats.cpp
index f0f500dd3a561486bca0643570040aabc5c3c53f..8fe55d2025e1cf7c0c1b91144db2aab56ba6b4bc 100644
--- a/cpp/full_code/joint_acc_vel_stats.cpp
+++ b/cpp/full_code/joint_acc_vel_stats.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "joint_acc_vel_stats.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
@@ -62,6 +63,8 @@ int joint_acc_vel_stats<rnumber>::initialize(void)
     else
         this->checkpoints_per_file = 1;
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -76,6 +79,8 @@ int joint_acc_vel_stats<rnumber>::initialize(void)
     H5Dread(dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &this->max_velocity_estimate);
     H5Dclose(dset);
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     if (this->myrank == 0)
     {
         // set caching parameters
diff --git a/cpp/full_code/kraichnan_field.cpp b/cpp/full_code/kraichnan_field.cpp
index 32502b47d17d75dc0082036db37667474b39fa43..bb63f5def0bef1b470801aff19bbd2d916e16235 100644
--- a/cpp/full_code/kraichnan_field.cpp
+++ b/cpp/full_code/kraichnan_field.cpp
@@ -93,7 +93,7 @@ int kraichnan_field<rnumber>::initialize(void)
                 tracers0_integration_steps);
     this->particles_output_writer_mpi->setParticleFileLayout(this->ps->getParticleFileLayout());
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 this->ps->getGlobalNbParticles(),
                 (this->simname + "_particles.h5"),
diff --git a/cpp/full_code/kraichnan_field.hpp b/cpp/full_code/kraichnan_field.hpp
index 0a9d4a3f833e9cd85bc5c896181b53b43a09dd1f..020cd0cdc7b2c5b8e35114bc7d78106e9a8c1fb2 100644
--- a/cpp/full_code/kraichnan_field.hpp
+++ b/cpp/full_code/kraichnan_field.hpp
@@ -72,7 +72,7 @@ class kraichnan_field: public direct_numerical_simulation
         std::unique_ptr<abstract_particles_system<long long int, double>> ps;
 
         particles_output_hdf5<long long int, double,3> *particles_output_writer_mpi;
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
 
         kraichnan_field(
diff --git a/cpp/full_code/native_binary_to_hdf5.cpp b/cpp/full_code/native_binary_to_hdf5.cpp
index a1a3277c0a0235ca97751accf55af2211eea25c2..ac0973d61144e0e7bdd5bb08533ece0779d7d757 100644
--- a/cpp/full_code/native_binary_to_hdf5.cpp
+++ b/cpp/full_code/native_binary_to_hdf5.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "native_binary_to_hdf5.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
diff --git a/cpp/full_code/native_binary_to_hdf5.hpp b/cpp/full_code/native_binary_to_hdf5.hpp
index d8ded73b4f24d6f73ae03c3b148ff740d72d8a88..3baaf609bfa4bba093dd097dce3be3d3aa590a4e 100644
--- a/cpp/full_code/native_binary_to_hdf5.hpp
+++ b/cpp/full_code/native_binary_to_hdf5.hpp
@@ -50,7 +50,7 @@ class native_binary_to_hdf5: public postprocess
             postprocess(
                     COMMUNICATOR,
                     simulation_name){}
-        virtual ~native_binary_to_hdf5(){}
+        virtual ~native_binary_to_hdf5() noexcept(false){}
 
         int initialize(void);
         int work_on_current_iteration(void);
diff --git a/cpp/full_code/phase_shift_test.hpp b/cpp/full_code/phase_shift_test.hpp
index 8e805300cd38d2283e8cb5eb8fb1f276d35f1fa7..e98f76cd568239a88f15da18c4fa72bc255fae9b 100644
--- a/cpp/full_code/phase_shift_test.hpp
+++ b/cpp/full_code/phase_shift_test.hpp
@@ -51,7 +51,7 @@ class phase_shift_test: public test
             test(
                     COMMUNICATOR,
                     simulation_name){}
-        ~phase_shift_test(){}
+        ~phase_shift_test() noexcept(false){}
 
         int initialize(void);
         int do_work(void);
diff --git a/cpp/full_code/postprocess.hpp b/cpp/full_code/postprocess.hpp
index c232a6b3d2395515f94ce3ad43178f0efa825da6..da22c91e9f7ca187cf7b3038994c0852e255924b 100644
--- a/cpp/full_code/postprocess.hpp
+++ b/cpp/full_code/postprocess.hpp
@@ -63,7 +63,7 @@ class postprocess: public code_base
             code_base(
                     COMMUNICATOR,
                     simulation_name){}
-        virtual ~postprocess(){}
+        virtual ~postprocess() noexcept(false){}
 
         virtual int initialize(void) = 0;
         virtual int work_on_current_iteration(void) = 0;
diff --git a/cpp/full_code/pressure_stats.cpp b/cpp/full_code/pressure_stats.cpp
index fc060b4dc152ec5a0a578879e82329a0a214b3a6..abeccf5cacca445032bd1e1f8898522f280c745f 100644
--- a/cpp/full_code/pressure_stats.cpp
+++ b/cpp/full_code/pressure_stats.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "pressure_stats.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
@@ -83,6 +84,8 @@ int pressure_stats<rnumber>::initialize(void)
     if (this->checkpoints_per_file == INT_MAX) // value returned if dataset does not exist
         this->checkpoints_per_file = 1;
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -94,6 +97,8 @@ int pressure_stats<rnumber>::initialize(void)
             parameter_file,
             "/pressure_stats/parameters/max_pressure_estimate");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     if (this->myrank == 0)
     {
         // set caching parameters
diff --git a/cpp/full_code/pressure_stats.hpp b/cpp/full_code/pressure_stats.hpp
index d8a54494660198adab52a0d12277b2fda407a317..f20ba08ee767fcd44bf6017670f3a3a41d7ba96e 100644
--- a/cpp/full_code/pressure_stats.hpp
+++ b/cpp/full_code/pressure_stats.hpp
@@ -64,7 +64,7 @@ class pressure_stats: public NSVE_field_stats<rnumber>
             NSVE_field_stats<rnumber>(
                     COMMUNICATOR,
                     simulation_name){}
-        virtual ~pressure_stats(){}
+        virtual ~pressure_stats() noexcept(false){}
 
         int initialize(void);
         int work_on_current_iteration(void);
diff --git a/cpp/full_code/resize.cpp b/cpp/full_code/resize.cpp
index f074a46c1d734b1873b9b09a1eda7d10aaed18cc..12f125e026e9faf864b5d510d59371390d5874e9 100644
--- a/cpp/full_code/resize.cpp
+++ b/cpp/full_code/resize.cpp
@@ -27,6 +27,7 @@
 #include <cmath>
 #include "resize.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
@@ -43,6 +44,8 @@ int resize<rnumber>::initialize(void)
     this->niter_out = hdf5_tools::read_value<int>(
             parameter_file, "/parameters/niter_out");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     parameter_file = H5Fopen(
             (this->simname + std::string("_post.h5")).c_str(),
             H5F_ACC_RDONLY,
@@ -61,6 +64,8 @@ int resize<rnumber>::initialize(void)
     this->new_simname = hdf5_tools::read_string(
             parameter_file, "/resize/parameters/new_simname");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
 
     this->new_field = new field<rnumber, FFTW, THREE>(
             this->new_nx, this->new_ny, this->new_nz,
diff --git a/cpp/full_code/static_field.cpp b/cpp/full_code/static_field.cpp
index 25760cf322debb4bb2438bb5242ef8fb5c01b96e..1fa52b646deb48f53b2066440221e10b01c3ab55 100644
--- a/cpp/full_code/static_field.cpp
+++ b/cpp/full_code/static_field.cpp
@@ -117,7 +117,7 @@ int static_field<rnumber>::initialize(void)
                 tracers0_integration_steps);
     this->particles_output_writer_mpi->setParticleFileLayout(this->ps->getParticleFileLayout());
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 this->ps->getGlobalNbParticles(),
                 (this->simname + "_particles.h5"),
diff --git a/cpp/full_code/static_field.hpp b/cpp/full_code/static_field.hpp
index 6393ae21151f2b6475972fdab991b808804a091a..90b563d1cd777768a63591e78ef121c9a594fc27 100644
--- a/cpp/full_code/static_field.hpp
+++ b/cpp/full_code/static_field.hpp
@@ -65,7 +65,7 @@ class static_field: public direct_numerical_simulation
         std::unique_ptr<abstract_particles_system<long long int, double>> ps;
 
         particles_output_hdf5<long long int, double,3> *particles_output_writer_mpi;
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
 
         static_field(
@@ -74,7 +74,7 @@ class static_field: public direct_numerical_simulation
             direct_numerical_simulation(
                     COMMUNICATOR,
                     simulation_name){}
-        ~static_field(){}
+        ~static_field() noexcept(false){}
 
         int initialize(void);
         int step(void);
diff --git a/cpp/full_code/symmetrize_test.cpp b/cpp/full_code/symmetrize_test.cpp
index da2bef880c13dd76221477e2088dafdff6453892..904b57ae2e32004c97f0ca1046e450822f853809 100644
--- a/cpp/full_code/symmetrize_test.cpp
+++ b/cpp/full_code/symmetrize_test.cpp
@@ -28,6 +28,7 @@
 #include "symmetrize_test.hpp"
 #include "fftw_tools.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <typename rnumber>
diff --git a/cpp/full_code/symmetrize_test.hpp b/cpp/full_code/symmetrize_test.hpp
index 52fbac28c57efb85518b69384f3e0319c60dfa26..69443d1a8dbeee28d035c5c2364f2d79dce8f8af 100644
--- a/cpp/full_code/symmetrize_test.hpp
+++ b/cpp/full_code/symmetrize_test.hpp
@@ -51,7 +51,7 @@ class symmetrize_test: public test
             test(
                     COMMUNICATOR,
                     simulation_name){}
-        ~symmetrize_test(){}
+        ~symmetrize_test() noexcept(false){}
 
         int initialize(void);
         int do_work(void);
diff --git a/cpp/full_code/test_interpolation.cpp b/cpp/full_code/test_interpolation.cpp
index 7325b894bac280bcf384da46a1734a52845d9727..9b9f2f50b53d05205eef6ece4287f2e8f2b136a2 100644
--- a/cpp/full_code/test_interpolation.cpp
+++ b/cpp/full_code/test_interpolation.cpp
@@ -101,7 +101,7 @@ int test_interpolation<rnumber>::initialize(void)
                 nparticles,
                 this->tracers0_integration_steps);
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 this->ps->getGlobalNbParticles(),
                 (this->simname + "_output.h5"),
diff --git a/cpp/full_code/test_interpolation.hpp b/cpp/full_code/test_interpolation.hpp
index 59ff49b81ea146b465b4e18c907e1f36ffbfa2bd..7c9e0fff1f1d286865fd1f29b62005063f141e75 100644
--- a/cpp/full_code/test_interpolation.hpp
+++ b/cpp/full_code/test_interpolation.hpp
@@ -52,7 +52,7 @@ class test_interpolation: public test
         std::unique_ptr<abstract_particles_system<long long int, double>> ps;
 
         particles_output_hdf5<long long int, double,3> *particles_output_writer_mpi;
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
         field<rnumber, FFTW, THREE> *velocity, *vorticity;
         field<rnumber, FFTW, THREExTHREE> *nabla_u;
diff --git a/cpp/full_code/test_interpolation_methods.cpp b/cpp/full_code/test_interpolation_methods.cpp
index 5d4a63760b8ea2b1b730eba3db137610e79eebd1..17cdfaf0ad75a02f78859bdedf61edf8536d9929 100644
--- a/cpp/full_code/test_interpolation_methods.cpp
+++ b/cpp/full_code/test_interpolation_methods.cpp
@@ -123,7 +123,7 @@ int test_interpolation_methods<rnumber>::do_work()
 
     // initialize writer
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 this->comm,
                 pset.getTotalNumberOfParticles(),
                 (this->simname + "_particles.h5"),
diff --git a/cpp/full_code/test_interpolation_methods.hpp b/cpp/full_code/test_interpolation_methods.hpp
index d0c43b9fbabcf3be9f52548b7d0f1eabc3fb12a7..62f661729cfbec51a25e6bb73819c8daac6dec66 100644
--- a/cpp/full_code/test_interpolation_methods.hpp
+++ b/cpp/full_code/test_interpolation_methods.hpp
@@ -47,7 +47,7 @@ class test_interpolation_methods: public test
         int nzparticles;
         int random_seed;
 
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
         field<rnumber, FFTW, ONE> *phi;
 
@@ -59,10 +59,10 @@ class test_interpolation_methods: public test
             test(
                     COMMUNICATOR,
                     simulation_name),
+            random_seed(0),
             particles_sample_writer_mpi(nullptr),
             phi(nullptr),
-            kk(nullptr),
-            random_seed(0){}
+            kk(nullptr){}
         ~test_interpolation_methods(){}
 
         int initialize(void);
diff --git a/cpp/full_code/test_particle_integration.cpp b/cpp/full_code/test_particle_integration.cpp
index 92d5eff4582b20f6aa9949606b8924d705767002..a1d3cbaf957ffb6dab9070746ac70d3d22f57695 100644
--- a/cpp/full_code/test_particle_integration.cpp
+++ b/cpp/full_code/test_particle_integration.cpp
@@ -196,7 +196,7 @@ int test_particle_integration<rnumber>::do_work()
 
     // initialize writer
     this->particles_sample_writer_mpi = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+        long long int, double, double, 3>(
                 this->comm,
                 pset.getTotalNumberOfParticles(),
                 (this->simname + "_particles.h5"),
diff --git a/cpp/full_code/test_particle_integration.hpp b/cpp/full_code/test_particle_integration.hpp
index c303e080d21b04600720bd43207214af24a14a4a..88a32dc19216887d619832fddcf6c5dc6ec18118 100644
--- a/cpp/full_code/test_particle_integration.hpp
+++ b/cpp/full_code/test_particle_integration.hpp
@@ -53,7 +53,7 @@ class test_particle_integration: public test
 
         field_tinterpolator<rnumber, FFTW, THREE, NONE> *velocity_front;
 
-        particles_output_sampling_hdf5<long long int, double, 3> *particles_sample_writer_mpi;
+        particles_output_sampling_hdf5<long long int, double, double, 3> *particles_sample_writer_mpi;
 
         field<rnumber, FFTW, THREE> *velocity_back;
 
@@ -65,11 +65,11 @@ class test_particle_integration: public test
             test(
                     COMMUNICATOR,
                     simulation_name),
-            particles_sample_writer_mpi(nullptr),
+            random_seed(0),
             velocity_front(nullptr),
+            particles_sample_writer_mpi(nullptr),
             velocity_back(nullptr),
-            kk(nullptr),
-            random_seed(0){}
+            kk(nullptr){}
         ~test_particle_integration(){}
 
         int initialize(void);
diff --git a/cpp/full_code/test_tracer_set.cpp b/cpp/full_code/test_tracer_set.cpp
index d457a090b06723c08ffc523fd483f47471de629d..ec8893577686cab0410ec49b396133535868b586 100644
--- a/cpp/full_code/test_tracer_set.cpp
+++ b/cpp/full_code/test_tracer_set.cpp
@@ -109,8 +109,8 @@ int test_tracer_set<rnumber>::do_work(void)
                 "tracers0",
                 pset.getTotalNumberOfParticles(),
                 0);
-    particles_output_sampling_hdf5<long long int, double, 3> *particle_sample_writer = new particles_output_sampling_hdf5<
-        long long int, double, 3>(
+    particles_output_sampling_hdf5<long long int, double, double, 3> *particle_sample_writer = new particles_output_sampling_hdf5<
+        long long int, double, double, 3>(
                 MPI_COMM_WORLD,
                 pset.getTotalNumberOfParticles(),
                 "test_particle_sample.h5",
diff --git a/cpp/full_code/write_rpressure.cpp b/cpp/full_code/write_rpressure.cpp
index 5835ee33625b6ac0240bb3c46e5aa9932b3a514a..a9e5e4ffa6972030c597befdb7e1020464af3f73 100644
--- a/cpp/full_code/write_rpressure.cpp
+++ b/cpp/full_code/write_rpressure.cpp
@@ -1,8 +1,9 @@
 #include <string>
 #include <cmath>
+#include <hdf5.h>
 #include "write_rpressure.hpp"
 #include "scope_timer.hpp"
-
+#include "hdf5_tools.hpp"
 
 template <typename rnumber>
 int write_rpressure<rnumber>::initialize(void)
@@ -20,6 +21,8 @@ int write_rpressure<rnumber>::initialize(void)
             parameter_file,
             "/write_rpressure/parameters/iteration_list");
     H5Fclose(parameter_file);
+    // the following ensures the file is free for rank 0 to open in read/write mode
+    MPI_Barrier(this->comm);
     if (this->myrank==0) DEBUG_MSG("Iteration list[0] = %d \n", this->iteration_list[0]);
 
     //get the pressure from here
diff --git a/cpp/full_code/write_rpressure.hpp b/cpp/full_code/write_rpressure.hpp
index 64fbcfc75a5feb17871fba515e089fd20f6a22a3..2a14dcb6d58188cb5ad7b6d9333cff76ef963282 100644
--- a/cpp/full_code/write_rpressure.hpp
+++ b/cpp/full_code/write_rpressure.hpp
@@ -56,7 +56,7 @@ class write_rpressure: public NSVE_field_stats<rnumber>
             NSVE_field_stats<rnumber>(
                     COMMUNICATOR,
                     simulation_name){}
-        virtual ~write_rpressure(){}
+        virtual ~write_rpressure() noexcept(false){}
 
         int initialize(void);
         int work_on_current_iteration(void);
diff --git a/cpp/hdf5_tools.cpp b/cpp/hdf5_tools.cpp
index 920db174b8e665ec8e9c1101fd98b6d15ff8c9c2..0d0854f92e023db0ca8d05301bf53d38b3e51dc3 100644
--- a/cpp/hdf5_tools.cpp
+++ b/cpp/hdf5_tools.cpp
@@ -213,6 +213,8 @@ std::vector<number> hdf5_tools::read_vector(
         mem_dtype = H5Tcopy(H5T_NATIVE_INT);
     else if (typeid(number) == typeid(double))
         mem_dtype = H5Tcopy(H5T_NATIVE_DOUBLE);
+    else
+        return result;
     dset = H5Dopen(group, dset_name.c_str(), H5P_DEFAULT);
     dspace = H5Dget_space(dset);
     assert(H5Sget_simple_extent_ndims(dspace) == 1);
@@ -240,6 +242,8 @@ number hdf5_tools::read_value(
         mem_dtype = H5Tcopy(H5T_NATIVE_LLONG);
     else if (typeid(number) == typeid(double))
         mem_dtype = H5Tcopy(H5T_NATIVE_DOUBLE);
+    else
+        return result;
     if (H5Lexists(group, dset_name.c_str(), H5P_DEFAULT))
     {
         dset = H5Dopen(group, dset_name.c_str(), H5P_DEFAULT);
@@ -276,6 +280,8 @@ int hdf5_tools::write_value_with_single_rank(
         mem_dtype = H5Tcopy(H5T_NATIVE_INT);
     else if (typeid(number) == typeid(double))
         mem_dtype = H5Tcopy(H5T_NATIVE_DOUBLE);
+    else
+        return EXIT_FAILURE;
     if (H5Lexists(group, dset_name.c_str(), H5P_DEFAULT))
     {
         dset = H5Dopen(group, dset_name.c_str(), H5P_DEFAULT);
diff --git a/cpp/kspace.hpp b/cpp/kspace.hpp
index 656b8ca290b32a9cf87bbdb0305ac7e8a2b7fe43..6457c8bd0a65d229d154984c05341f69a7728f7b 100644
--- a/cpp/kspace.hpp
+++ b/cpp/kspace.hpp
@@ -24,6 +24,10 @@
 
 
 
+#ifndef KSPACE_HPP
+
+#define KSPACE_HPP
+
 #include <hdf5.h>
 #include <vector>
 #include <string>
@@ -31,10 +35,6 @@
 #include "fftw_interface.hpp"
 #include "field_layout.hpp"
 
-#ifndef KSPACE_HPP
-
-#define KSPACE_HPP
-
 enum field_backend {FFTW};
 enum kspace_dealias_type {ONE_HALF, TWO_THIRDS, SMOOTH};
 
@@ -78,7 +78,7 @@ class kspace
                 const double DKX = 1.0,
                 const double DKY = 1.0,
                 const double DKZ = 1.0);
-        ~kspace();
+        ~kspace() noexcept(false);
 
         int store(hid_t stat_file);
 
diff --git a/cpp/particles/abstract_particle_rhs.hpp b/cpp/particles/abstract_particle_rhs.hpp
index d1a47bdcf164f24d1617e9f3f9f7b972fe06c2e5..947e152430cb14bc439021d83e48860411c2c175 100644
--- a/cpp/particles/abstract_particle_rhs.hpp
+++ b/cpp/particles/abstract_particle_rhs.hpp
@@ -45,7 +45,7 @@ class abstract_particle_rhs
         using particle_rnumber = abstract_particle_set::particle_rnumber;
     public:
         // destructor
-        virtual ~abstract_particle_rhs(){}
+        virtual ~abstract_particle_rhs() noexcept(false){}
 
         /** Probe the dimension of the ODE
          */
diff --git a/cpp/particles/abstract_particles_input.hpp b/cpp/particles/abstract_particles_input.hpp
index ab078a423834b075e05d864b25d4b07b994a6a49..20884283491a8f316277ef78be20026080a34e9a 100644
--- a/cpp/particles/abstract_particles_input.hpp
+++ b/cpp/particles/abstract_particles_input.hpp
@@ -31,7 +31,7 @@
 template <class partsize_t, class real_number>
 class abstract_particles_input {
 public:
-    virtual ~abstract_particles_input(){}
+    virtual ~abstract_particles_input() noexcept(false){}
 
     virtual partsize_t getTotalNbParticles()  = 0;
     virtual partsize_t getLocalNbParticles()  = 0;
@@ -39,6 +39,7 @@ public:
 
     virtual std::unique_ptr<real_number[]> getMyParticles()  = 0;
     virtual std::unique_ptr<partsize_t[]> getMyParticlesIndexes()  = 0;
+    virtual std::unique_ptr<partsize_t[]> getMyParticlesLabels()  = 0;
     virtual std::vector<std::unique_ptr<real_number[]>> getMyRhs()  = 0;
     virtual std::vector<hsize_t> getParticleFileLayout() = 0;
 };
diff --git a/cpp/particles/abstract_particles_output.hpp b/cpp/particles/abstract_particles_output.hpp
index 2674946190a9de678c3c839c79f8704715426cbf..af690dcbd72ca06cf756d1d639a6efaebfd6b677 100644
--- a/cpp/particles/abstract_particles_output.hpp
+++ b/cpp/particles/abstract_particles_output.hpp
@@ -38,7 +38,15 @@
 #include "scope_timer.hpp"
 #include "env_utils.hpp"
 
-template <class partsize_t, class real_number, int size_particle_positions>
+/** \brief Class to handle distributed output of particle data
+ *
+ * \tparam partsize_t data type of particle index
+ * \tparam position_type data type of particle positions
+ * \tparam output_type data type of output (typically same as position_type, but it may be different)
+ * \tparam size_particle_positions int, size of particle state
+ *
+ */
+template <class partsize_t, class position_type, class output_type, int size_particle_positions>
 class abstract_particles_output {
     MPI_Comm mpi_com;
     MPI_Comm mpi_com_writer;
@@ -50,13 +58,13 @@ class abstract_particles_output {
     const int nb_rhs;
 
     std::unique_ptr<std::pair<partsize_t,partsize_t>[]> buffer_indexes_send;
-    std::unique_ptr<real_number[]> buffer_particles_positions_send;
-    std::vector<std::unique_ptr<real_number[]>> buffer_particles_rhs_send;
+    std::unique_ptr<position_type[]> buffer_particles_positions_send;
+    std::vector<std::unique_ptr<output_type[]>> buffer_particles_rhs_send;
     partsize_t size_buffers_send;
     int buffers_size_particle_rhs_send;
 
-    std::unique_ptr<real_number[]> buffer_particles_positions_recv;
-    std::vector<std::unique_ptr<real_number[]>> buffer_particles_rhs_recv;
+    std::unique_ptr<position_type[]> buffer_particles_positions_recv;
+    std::vector<std::unique_ptr<output_type[]>> buffer_particles_rhs_recv;
     std::unique_ptr<partsize_t[]> buffer_indexes_recv;
     partsize_t size_buffers_recv;
     int buffers_size_particle_rhs_recv;
@@ -89,7 +97,7 @@ protected:
     }
 
 public:
-    abstract_particles_output(MPI_Comm in_mpi_com, const partsize_t inTotalNbParticles, const int in_nb_rhs) throw()
+    abstract_particles_output(MPI_Comm in_mpi_com, const partsize_t inTotalNbParticles, const int in_nb_rhs) noexcept(false)
             : mpi_com(in_mpi_com), my_rank(-1), nb_processes(-1),
                 total_nb_particles(inTotalNbParticles), nb_rhs(in_nb_rhs),
                 buffer_particles_rhs_send(in_nb_rhs), size_buffers_send(0),
@@ -107,7 +115,7 @@ public:
         const int MaxProcessesInvolved = std::min(nb_processes, env_utils::GetValue<int>("BFPS_PO_MAX_PROCESSES", 128));
 
         // We split the processes using positions size only
-        const size_t totalBytesForPositions = total_nb_particles*size_particle_positions*sizeof(real_number);
+        const size_t totalBytesForPositions = total_nb_particles*size_particle_positions*sizeof(position_type);
 
 
         if(MinBytesPerProcess*MaxProcessesInvolved < totalBytesForPositions){
@@ -116,13 +124,13 @@ public:
                 extraChunkBytes += 1;
             }
             const size_t bytesPerProcess = (MinBytesPerProcess+extraChunkBytes*ChunkBytes);
-            particles_chunk_per_process = partsize_t((bytesPerProcess+sizeof(real_number)*size_particle_positions-1)/(sizeof(real_number)*size_particle_positions));
+            particles_chunk_per_process = partsize_t((bytesPerProcess+sizeof(position_type)*size_particle_positions-1)/(sizeof(position_type)*size_particle_positions));
             nb_processes_involved = int((total_nb_particles+particles_chunk_per_process-1)/particles_chunk_per_process);
         }
         // else limit based on minBytesPerProcess
         else{
             nb_processes_involved = std::max(1,std::min(MaxProcessesInvolved,int((totalBytesForPositions+MinBytesPerProcess-1)/MinBytesPerProcess)));
-            particles_chunk_per_process = partsize_t((MinBytesPerProcess+sizeof(real_number)*size_particle_positions-1)/(sizeof(real_number)*size_particle_positions));
+            particles_chunk_per_process = partsize_t((MinBytesPerProcess+sizeof(position_type)*size_particle_positions-1)/(sizeof(position_type)*size_particle_positions));
         }
 
         // Print out
@@ -178,8 +186,8 @@ public:
 
     template <int size_particle_rhs>
     void save(
-            const real_number input_particles_positions[],
-            const std::unique_ptr<real_number[]> input_particles_rhs[],
+            const position_type input_particles_positions[],
+            const std::unique_ptr<output_type[]> input_particles_rhs[],
             const partsize_t index_particles[],
             const partsize_t nb_particles,
             const int idx_time_step){
@@ -192,20 +200,20 @@ public:
             if(size_buffers_send < nb_particles){
                 size_buffers_send = nb_particles;
                 buffer_indexes_send.reset(new std::pair<partsize_t,partsize_t>[size_buffers_send]);
-                buffer_particles_positions_send.reset(new real_number[size_buffers_send*size_particle_positions]);
+                buffer_particles_positions_send.reset(new position_type[size_buffers_send*size_particle_positions]);
 
                 if(buffers_size_particle_rhs_send < size_particle_rhs){
                     buffers_size_particle_rhs_send = size_particle_rhs;
                 }
                 for(int idx_rhs = 0 ; idx_rhs < nb_rhs ; ++idx_rhs){
-                    buffer_particles_rhs_send[idx_rhs].reset(new real_number[size_buffers_send*buffers_size_particle_rhs_send]);
+                    buffer_particles_rhs_send[idx_rhs].reset(new output_type[size_buffers_send*buffers_size_particle_rhs_send]);
                 }
             }
             else if(buffers_size_particle_rhs_send < size_particle_rhs){
                 buffers_size_particle_rhs_send = size_particle_rhs;
                 if(size_buffers_send > 0){
                     for(int idx_rhs = 0 ; idx_rhs < nb_rhs ; ++idx_rhs){
-                        buffer_particles_rhs_send[idx_rhs].reset(new real_number[size_buffers_send*buffers_size_particle_rhs_send]);
+                        buffer_particles_rhs_send[idx_rhs].reset(new output_type[size_buffers_send*buffers_size_particle_rhs_send]);
                     }
                 }
             }
@@ -215,10 +223,14 @@ public:
                 buffer_indexes_send[idx_part].second = index_particles[idx_part];
             }
 
-            std::sort(&buffer_indexes_send[0], &buffer_indexes_send[nb_particles], [](const std::pair<partsize_t,partsize_t>& p1,
-                                                                                      const std::pair<partsize_t,partsize_t>& p2){
-                return p1.second < p2.second;
-            });
+            std::sort(
+                    &buffer_indexes_send[0],
+                    &buffer_indexes_send[nb_particles],
+                    [](const std::pair<partsize_t,partsize_t>& p1,
+                       const std::pair<partsize_t,partsize_t>& p2)
+                    {
+                        return p1.second < p2.second;
+                    });
 
             for(partsize_t idx_part = 0 ; idx_part < nb_particles ; ++idx_part){
                 const partsize_t src_idx = buffer_indexes_send[idx_part].first;
@@ -250,23 +262,25 @@ public:
         // nb_particles_to_send is invalid after here
 
         const int nb_to_receive = exchanger.getTotalToRecv();
+        //DEBUG_MSG("nb_to_receive = %d, particles_chunk_current_size = %d\n",
+        //        nb_to_receive, particles_chunk_current_size);
         assert(nb_to_receive == particles_chunk_current_size);
 
         if(size_buffers_recv < nb_to_receive){
             size_buffers_recv = nb_to_receive;
             buffer_indexes_recv.reset(new partsize_t[size_buffers_recv]);
-            buffer_particles_positions_recv.reset(new real_number[size_buffers_recv*size_particle_positions]);
+            buffer_particles_positions_recv.reset(new position_type[size_buffers_recv*size_particle_positions]);
 
             buffers_size_particle_rhs_recv = size_particle_rhs;
             for(int idx_rhs = 0 ; idx_rhs < nb_rhs ; ++idx_rhs){
-                buffer_particles_rhs_recv[idx_rhs].reset(new real_number[size_buffers_recv*buffers_size_particle_rhs_recv]);
+                buffer_particles_rhs_recv[idx_rhs].reset(new output_type[size_buffers_recv*buffers_size_particle_rhs_recv]);
             }
         }
         else if(buffers_size_particle_rhs_recv < size_particle_rhs){
             buffers_size_particle_rhs_recv = size_particle_rhs;
             if(size_buffers_recv > 0){
                 for(int idx_rhs = 0 ; idx_rhs < nb_rhs ; ++idx_rhs){
-                    buffer_particles_rhs_recv[idx_rhs].reset(new real_number[size_buffers_recv*buffers_size_particle_rhs_recv]);
+                    buffer_particles_rhs_recv[idx_rhs].reset(new output_type[size_buffers_recv*buffers_size_particle_rhs_recv]);
                 }
             }
         }
@@ -275,9 +289,9 @@ public:
             TIMEZONE("exchange");
             // Could be done with multiple asynchronous coms
             exchanger.alltoallv<partsize_t>(buffer_indexes_send_tmp, buffer_indexes_recv.get());
-            exchanger.alltoallv<real_number>(buffer_particles_positions_send.get(), buffer_particles_positions_recv.get(), size_particle_positions);
+            exchanger.alltoallv<position_type>(buffer_particles_positions_send.get(), buffer_particles_positions_recv.get(), size_particle_positions);
             for(int idx_rhs = 0 ; idx_rhs < nb_rhs ; ++idx_rhs){
-                exchanger.alltoallv<real_number>(buffer_particles_rhs_send[idx_rhs].get(), buffer_particles_rhs_recv[idx_rhs].get(), size_particle_rhs);
+                exchanger.alltoallv<output_type>(buffer_particles_rhs_send[idx_rhs].get(), buffer_particles_rhs_recv[idx_rhs].get(), size_particle_rhs);
             }
         }
 
@@ -290,18 +304,29 @@ public:
         if(size_buffers_send < nb_to_receive){
             size_buffers_send = nb_to_receive;
             buffer_indexes_send.reset(new std::pair<partsize_t,partsize_t>[size_buffers_send]);
-            buffer_particles_positions_send.reset(new real_number[size_buffers_send*size_particle_positions]);
+            buffer_particles_positions_send.reset(new position_type[size_buffers_send*size_particle_positions]);
             buffers_size_particle_rhs_send = size_particle_rhs;
             for(int idx_rhs = 0 ; idx_rhs < nb_rhs ; ++idx_rhs){
-                buffer_particles_rhs_send[idx_rhs].reset(new real_number[size_buffers_send*buffers_size_particle_rhs_send]);
+                buffer_particles_rhs_send[idx_rhs].reset(new output_type[size_buffers_send*buffers_size_particle_rhs_send]);
             }
         }
 
         {
+            // Local process has received particles in `buffer_particles_positions_recv`.
+            // It will now place this data (which is shuffled), in order, in the `buffer_particles_positions_send` array.
+            // However, to place the data it uses the particle indices as memory addresses.
+            // This is fine in general, but if we use particle indices as labels, and we sometimes delete particles, the particle indices are no longer valid memory addresses.
+            // So we need to fix this.
             TIMEZONE("copy-local-order");
             for(partsize_t idx_part = 0 ; idx_part < nb_to_receive ; ++idx_part){
                 const partsize_t src_idx = idx_part;
+                //DEBUG_MSG("idx_part = %d, buffer_indexes_recv[idx_part] = %d, particles_chunk_current_offset = %d\n",
+                //        idx_part,
+                //        buffer_indexes_recv[idx_part],
+                //        particles_chunk_current_size);
                 const partsize_t dst_idx = buffer_indexes_recv[idx_part]-particles_chunk_current_offset;
+                //DEBUG_MSG("dst_idx is %d, particles_chunk_current_size is %d\n",
+                //        dst_idx, particles_chunk_current_size);
                 assert(0 <= dst_idx);
                 assert(dst_idx < particles_chunk_current_size);
 
@@ -322,7 +347,7 @@ public:
               nb_to_receive, particles_chunk_current_offset, size_particle_rhs);
     }
 
-    virtual void write(const int idx_time_step, const real_number* positions, const std::unique_ptr<real_number[]>* rhs,
+    virtual void write(const int idx_time_step, const position_type* positions, const std::unique_ptr<output_type[]>* rhs,
                        const partsize_t nb_particles, const partsize_t particles_idx_offset, const int size_particle_rhs) = 0;
 };
 
diff --git a/cpp/particles/abstract_particles_system.hpp b/cpp/particles/abstract_particles_system.hpp
index abcb8e684c5f269f10f47f337e36260486fba931..4edf20c7ca2d34fb023c6a0ea1e370c29e288df0 100644
--- a/cpp/particles/abstract_particles_system.hpp
+++ b/cpp/particles/abstract_particles_system.hpp
@@ -38,7 +38,7 @@
 template <class partsize_t, class real_number>
 class abstract_particles_system {
 public:
-    virtual ~abstract_particles_system(){}
+    virtual ~abstract_particles_system() noexcept(false){}
 
     virtual void delete_particles_from_indexes(const std::vector<partsize_t>& inIndexToDelete) = 0;
 
diff --git a/cpp/particles/interpolation/abstract_particle_set.hpp b/cpp/particles/interpolation/abstract_particle_set.hpp
index 085956f4d377ef9ba24f42995a844d4f10da1a6f..1227f0667107429c0516aac78b67e904a6b9ee18 100644
--- a/cpp/particles/interpolation/abstract_particle_set.hpp
+++ b/cpp/particles/interpolation/abstract_particle_set.hpp
@@ -30,13 +30,14 @@
 #include <cassert>
 #include <vector>
 #include <memory>
+#include <string>
 #include "field.hpp"
 #include "particles/p2p/p2p_distr_mpi.hpp"
 #include "particles/particles_sampling.hpp"
 
 
 
-/** Brings together particle information with interpolation functionality.
+/** \brief Brings together particle information with interpolation functionality.
  *
  * This is an abstract class that defines the functionality required by the
  * particle solver code.
@@ -56,11 +57,12 @@ class abstract_particle_set
         using particle_rnumber = double;
 
         // virtual destructor
-        virtual ~abstract_particle_set(){}
+        virtual ~abstract_particle_set() noexcept(false){}
 
         // extract particle information
         virtual particle_rnumber* getParticleState() const = 0;
-        virtual partsize_t* getParticleIndex() const = 0;
+        virtual partsize_t* getParticleIndices() const = 0;
+        virtual partsize_t* getParticleLabels() const = 0;
         virtual int setParticleState(particle_rnumber *) = 0;
         virtual int getParticleState(particle_rnumber *) = 0;
 
@@ -183,7 +185,48 @@ class abstract_particle_set
                     this->getParticleState(),
                     additional_data.data(),
                     int(additional_data.size()),
-                    this->getParticleIndex());
+                    this->getParticleIndices(),
+                    this->getParticleLabels());
+            return EXIT_SUCCESS;
+        }
+
+        int writeParticleLabels(
+                const std::string file_name,
+                const std::string species_name,
+                const std::string field_name,
+                const int iteration)
+        {
+            TIMEZONE("abstract_particle_set::writeParticleLabels");
+            particles_output_sampling_hdf5<partsize_t, particle_rnumber, partsize_t, 3> *particle_sample_writer = new particles_output_sampling_hdf5<partsize_t, double, partsize_t, 3>(
+                    MPI_COMM_WORLD,
+                    this->getTotalNumberOfParticles(),
+                    file_name,
+                    species_name,
+                    field_name + std::string("/") + std::to_string(iteration));
+            // set file layout
+            particle_sample_writer->setParticleFileLayout(this->getParticleFileLayout());
+            // allocate position array
+            std::unique_ptr<particle_rnumber[]> xx = this->extractFromParticleState(0, 3);
+            // allocate temporary array
+            std::unique_ptr<partsize_t[]> pdata(new partsize_t[this->getLocalNumberOfParticles()]);
+            // clean up temporary array
+            std::copy(this->getParticleLabels(),
+                      this->getParticleLabels() + this->getLocalNumberOfParticles(),
+                      pdata.get());
+            particle_sample_writer->template save_dataset<1>(
+                    species_name,
+                    field_name,
+                    xx.get(),
+                    &pdata,
+                    this->getParticleIndices(),
+                    this->getLocalNumberOfParticles(),
+                    iteration);
+            // deallocate sample writer
+            delete particle_sample_writer;
+            // deallocate temporary array
+            delete[] pdata.release();
+            // deallocate position array
+            delete[] xx.release();
             return EXIT_SUCCESS;
         }
 
@@ -192,7 +235,10 @@ class abstract_particle_set
                   field_components fc>
         int writeSample(
                 field<field_rnumber, be, fc> *field_to_sample,
-                particles_output_sampling_hdf5<partsize_t, particle_rnumber, 3> *particle_sample_writer,
+                particles_output_sampling_hdf5<partsize_t,
+                                               particle_rnumber,
+                                               particle_rnumber,
+                                               3> *particle_sample_writer,
                 const std::string species_name,
                 const std::string field_name,
                 const int iteration)
@@ -212,7 +258,7 @@ class abstract_particle_set
                     field_name,
                     xx.get(),
                     &pdata,
-                    this->getParticleIndex(),
+                    this->getParticleIndices(),
                     this->getLocalNumberOfParticles(),
                     iteration);
             // deallocate temporary array
@@ -257,7 +303,10 @@ class abstract_particle_set
         int writeStateChunk(
                 const int i0,
                 const int contiguous_state_chunk,
-                particles_output_sampling_hdf5<partsize_t, particle_rnumber, 3> *particle_sample_writer,
+                particles_output_sampling_hdf5<partsize_t,
+                                               particle_rnumber,
+                                               particle_rnumber,
+                                               3> *particle_sample_writer,
                 const std::string species_name,
                 const std::string field_name,
                 const int iteration)
@@ -279,7 +328,7 @@ class abstract_particle_set
                             field_name,
                             xx.get(),
                             &yy,
-                            this->getParticleIndex(),
+                            this->getParticleIndices(),
                             this->getLocalNumberOfParticles(),
                             iteration);
                     break;
@@ -289,7 +338,7 @@ class abstract_particle_set
                             field_name,
                             xx.get(),
                             &yy,
-                            this->getParticleIndex(),
+                            this->getParticleIndices(),
                             this->getLocalNumberOfParticles(),
                             iteration);
                     break;
@@ -299,7 +348,7 @@ class abstract_particle_set
                             field_name,
                             xx.get(),
                             &yy,
-                            this->getParticleIndex(),
+                            this->getParticleIndices(),
                             this->getLocalNumberOfParticles(),
                             iteration);
                     break;
@@ -316,7 +365,10 @@ class abstract_particle_set
 
         int writeStateTriplet(
                 const int i0,
-                particles_output_sampling_hdf5<partsize_t, particle_rnumber, 3> *particle_sample_writer,
+                particles_output_sampling_hdf5<partsize_t,
+                                               particle_rnumber,
+                                               particle_rnumber,
+                                               3> *particle_sample_writer,
                 const std::string species_name,
                 const std::string field_name,
                 const int iteration)
@@ -332,7 +384,10 @@ class abstract_particle_set
 
         int writeStateComponent(
                 const int i0,
-                particles_output_sampling_hdf5<partsize_t, particle_rnumber, 3> *particle_sample_writer,
+                particles_output_sampling_hdf5<partsize_t,
+                                               particle_rnumber,
+                                               particle_rnumber,
+                                               3> *particle_sample_writer,
                 const std::string species_name,
                 const std::string field_name,
                 const int iteration)
diff --git a/cpp/particles/interpolation/field_tinterpolator.hpp b/cpp/particles/interpolation/field_tinterpolator.hpp
index 60175a288cf55a246e82a7a8baac71431b02eaaa..2dc27b56a69d5462b131347b23c8fce1903864af 100644
--- a/cpp/particles/interpolation/field_tinterpolator.hpp
+++ b/cpp/particles/interpolation/field_tinterpolator.hpp
@@ -56,7 +56,7 @@ class field_tinterpolator
             this->field_list[3] = NULL;
         }
 
-        ~field_tinterpolator(){}
+        ~field_tinterpolator() noexcept(false){}
 
         int set_field(
                 field<rnumber, be, fc> *field_src = NULL,
diff --git a/cpp/particles/interpolation/particle_set.hpp b/cpp/particles/interpolation/particle_set.hpp
index 206e9da519432a1226c441517f97d26c5f03c123..071614ad52369d596565a50fa2e8ac34d5c22e99 100644
--- a/cpp/particles/interpolation/particle_set.hpp
+++ b/cpp/particles/interpolation/particle_set.hpp
@@ -29,6 +29,7 @@
 #include <array>
 #include <cassert>
 #include <vector>
+#include <set>
 #include <memory>
 #include "field_layout.hpp"
 #include "field.hpp"
@@ -73,7 +74,8 @@ class particle_set: public abstract_particle_set
         std::unique_ptr<partsize_t[]> offset_particles_for_partition;
 
         std::unique_ptr<particle_rnumber[]> local_state;
-        std::unique_ptr<partsize_t[]>       local_index;
+        std::unique_ptr<partsize_t[]>       local_indices;
+        std::unique_ptr<partsize_t[]>       local_labels;
         partsize_t                          local_number_of_particles;
         partsize_t                          total_number_of_particles;
 
@@ -159,15 +161,77 @@ class particle_set: public abstract_particle_set
             assert(IDXC_Y == 1);
             assert(IDXC_Z == 2);
 
-            DEBUG_MSG("current partition interval %d %d\n",
-                    current_partition_interval.first,
-                    current_partition_interval.second);
+            //DEBUG_MSG("current partition interval %d %d\n",
+            //        current_partition_interval.first,
+            //        current_partition_interval.second);
 
             this->number_particles_per_partition.reset(new partsize_t[partition_interval_size]);
             this->offset_particles_for_partition.reset(new partsize_t[partition_interval_size+1]);
         }
 
-        ~particle_set(){}
+        int _print_debug_info()
+        {
+            int myrank;
+            AssertMpi(MPI_Comm_rank(mpi_comm, &myrank));
+            int nprocs;
+            AssertMpi(MPI_Comm_size(mpi_comm, &nprocs));
+
+            for (int rr = 0; rr < nprocs; rr++)
+            {
+                if (myrank == rr)
+                {
+                    DEBUG_MSG("##########################################\n");
+                    DEBUG_MSG("# particle_set debug info follows\n");
+
+                    DEBUG_MSG("current partition interval %d %d\n",
+                            this->current_partition_interval.first,
+                            this->current_partition_interval.second);
+                    DEBUG_MSG("partition_interval_size %d\n",
+                            this->partition_interval_size);
+
+                    for (int i=0; i<this->partition_interval_size; i++)
+                    {
+                        DEBUG_MSG("number_particles_per_partition[%d] = %d\n",
+                                i,
+                                number_particles_per_partition[i]);
+                    }
+
+                    for (int i=0; i<this->partition_interval_size+1; i++)
+                    {
+                        DEBUG_MSG("offset_particles_for_partition[%d] = %d\n",
+                                i,
+                                offset_particles_for_partition[i]);
+                    }
+
+                    DEBUG_MSG("local_number_of_particles = %d\n",
+                            this->local_number_of_particles);
+                    DEBUG_MSG("total_number_of_particles = %d\n",
+                            this->total_number_of_particles);
+
+                    for (int i=0; i<int(this->particle_file_layout.size()); i++)
+                        DEBUG_MSG("particle_file_layout[%d] = %d\n",
+                                i,
+                                this->particle_file_layout[i]);
+                    if (this->total_number_of_particles < 100)
+                    {
+                        for (partsize_t ii=0; ii < this->local_number_of_particles; ii++)
+                        {
+                            DEBUG_MSG("local_counter = %d, index = %d, label = %d\n",
+                                    ii,
+                                    this->local_indices[ii],
+                                    this->local_labels[ii]);
+                        }
+                    }
+
+                    DEBUG_MSG("# particle_set debug info ends\n");
+                    DEBUG_MSG("##########################################\n");
+                }
+                MPI_Barrier(this->mpi_comm);
+            }
+            return EXIT_SUCCESS;
+        }
+
+        ~particle_set() noexcept(false){}
 
         particle_rnumber* getParticleState() const
         {
@@ -192,9 +256,14 @@ class particle_set: public abstract_particle_set
             return EXIT_SUCCESS;
         }
 
-        partsize_t* getParticleIndex() const
+        partsize_t* getParticleIndices() const
+        {
+            return this->local_indices.get();
+        }
+
+        partsize_t* getParticleLabels() const
         {
-            return this->local_index.get();
+            return this->local_labels.get();
         }
 
         partsize_t getLocalNumberOfParticles() const
@@ -314,7 +383,8 @@ class particle_set: public abstract_particle_set
                     &this->local_state,
                     additional_data.data(),
                     int(additional_data.size()),
-                    &this->local_index);
+                    &this->local_indices,
+                    &this->local_labels);
             return EXIT_SUCCESS;
         }
 
@@ -323,10 +393,12 @@ class particle_set: public abstract_particle_set
             TIMEZONE("particle_set::init");
 
             this->local_state = particles_input.getMyParticles();
-            this->local_index = particles_input.getMyParticlesIndexes();
+            this->local_indices = particles_input.getMyParticlesIndexes();
+            this->local_labels = particles_input.getMyParticlesLabels();
             this->local_number_of_particles = particles_input.getLocalNbParticles();
             this->total_number_of_particles = particles_input.getTotalNbParticles();
 
+
             particles_utils::partition_extra_z<partsize_t, state_size>(
                     &this->local_state[0],
                     this->local_number_of_particles,
@@ -339,7 +411,8 @@ class particle_set: public abstract_particle_set
                         return partition_level - current_partition_interval.first;
                     },
                     [&](const partsize_t idx1, const partsize_t idx2){
-                        std::swap(this->local_index[idx1], this->local_index[idx2]);
+                        std::swap(this->local_indices[idx1], this->local_indices[idx2]);
+                        std::swap(this->local_labels[idx1], this->local_labels[idx2]);
                     });
 
             int file_layout_result = this->setParticleFileLayout(particles_input.getParticleFileLayout());
@@ -356,25 +429,26 @@ class particle_set: public abstract_particle_set
             TIMEZONE("particle_set::init_as_subset_of");
             assert(indices_to_copy.size() > 0);
             particle_rnumber *tmp_local_state = new particle_rnumber[state_size * src.getLocalNbParticles()];
-            partsize_t *tmp_local_index = new partsize_t[src.getLocalNbParticles()];
+            partsize_t *tmp_local_indices = new partsize_t[src.getLocalNbParticles()];
+            partsize_t *tmp_local_labels = new partsize_t[src.getLocalNbParticles()];
             this->local_number_of_particles = 0;
             this->total_number_of_particles = indices_to_copy.size();
 
-            DEBUG_MSG("particle_set::init_as_subset_of, desired subset_size = %ld, src_local_number = %ld, src_total_number = %ld\n",
-                    this->total_number_of_particles,
-                    src.getLocalNbParticles(),
-                    src.getGlobalNbParticles());
+            //DEBUG_MSG("particle_set::init_as_subset_of, desired subset_size = %ld, src_local_number = %ld, src_total_number = %ld\n",
+            //        this->total_number_of_particles,
+            //        src.getLocalNbParticles(),
+            //        src.getGlobalNbParticles());
 
             // dumb selection of interesting particles
             for (partsize_t ii = 0; ii < partsize_t(src.getLocalNbParticles()); ii++)
             {
-                partsize_t src_index = src.getParticlesIndexes()[ii];
+                partsize_t src_label = src.getParticlesIndexes()[ii];
                 for (partsize_t iii=0; iii < partsize_t(indices_to_copy.size()); iii++)
                 {
-                    if (src_index == indices_to_copy[iii])
+                    if (src_label == indices_to_copy[iii])
                     {
-                        tmp_local_index[this->local_number_of_particles] = src_index;
-                        //tmp_local_index[this->local_number_of_particles] = iii;
+                        tmp_local_indices[this->local_number_of_particles] = iii;
+                        tmp_local_labels[this->local_number_of_particles] = src_label;
                         std::copy(src.getParticlesState()+state_size*ii,
                                   src.getParticlesState()+state_size*(ii+1),
                                   tmp_local_state + state_size*this->local_number_of_particles);
@@ -388,13 +462,221 @@ class particle_set: public abstract_particle_set
             if (this->local_number_of_particles > 0)
             {
                 this->local_state.reset(new particle_rnumber[state_size*this->local_number_of_particles]);
-                this->local_index.reset(new partsize_t[this->local_number_of_particles]);
+                this->local_indices.reset(new partsize_t[this->local_number_of_particles]);
+                this->local_labels.reset(new partsize_t[this->local_number_of_particles]);
+                std::copy(tmp_local_state,
+                          tmp_local_state + state_size*this->local_number_of_particles,
+                          this->local_state.get());
+                std::copy(tmp_local_indices,
+                          tmp_local_indices + this->local_number_of_particles,
+                          this->local_indices.get());
+                std::copy(tmp_local_labels,
+                          tmp_local_labels + this->local_number_of_particles,
+                          this->local_labels.get());
+            }
+
+            particles_utils::partition_extra_z<partsize_t, state_size>(
+                    &this->local_state[0],
+                    this->local_number_of_particles,
+                    partition_interval_size,
+                    this->number_particles_per_partition.get(),
+                    this->offset_particles_for_partition.get(),
+                    [&](const particle_rnumber& z_pos){
+                        const int partition_level = this->pInterpolator.pbc_field_layer(z_pos, IDXC_Z);
+                        assert(current_partition_interval.first <= partition_level && partition_level < current_partition_interval.second);
+                        return partition_level - current_partition_interval.first;
+                    },
+                    [&](const partsize_t idx1, const partsize_t idx2){
+                        std::swap(this->local_indices[idx1], this->local_indices[idx2]);
+                        std::swap(this->local_labels[idx1], this->local_labels[idx2]);
+                    });
+
+            delete[] tmp_local_state;
+            delete[] tmp_local_indices;
+            delete[] tmp_local_labels;
+
+            std::vector<hsize_t> tmp_file_layout(1);
+            tmp_file_layout[0] = hsize_t(this->total_number_of_particles);
+
+            int file_layout_result = this->setParticleFileLayout(tmp_file_layout);
+            variable_used_only_in_assert(file_layout_result);
+            assert(file_layout_result == EXIT_SUCCESS);
+            return EXIT_SUCCESS;
+        }
+
+        int operator=(
+                abstract_particle_set *src)
+        {
+            TIMEZONE("particle_set::operator=");
+            assert(src->getStateSize() == state_size);
+            particle_rnumber *tmp_local_state = new particle_rnumber[state_size * src->getLocalNumberOfParticles()];
+            partsize_t *tmp_local_indices = new partsize_t[src->getLocalNumberOfParticles()];
+            partsize_t *tmp_local_labels = new partsize_t[src->getLocalNumberOfParticles()];
+            this->local_number_of_particles = 0;
+
+            this->total_number_of_particles = src->getTotalNumberOfParticles();
+
+            for (partsize_t ii = 0; ii < partsize_t(src->getLocalNumberOfParticles()); ii++)
+            {
+                partsize_t src_label = src->getParticleLabels()[ii];
+                partsize_t src_index = src->getParticleIndices()[ii];
+
+                {
+                    // set new index
+                    tmp_local_indices[this->local_number_of_particles] = src_index;
+                    tmp_local_labels[this->local_number_of_particles] = src_label;
+                    std::copy(src->getParticleState()+state_size*ii,
+                              src->getParticleState()+state_size*(ii+1),
+                              tmp_local_state + state_size*this->local_number_of_particles);
+                    this->local_number_of_particles++;
+                }
+            }
+
+            // now we actually put the data "here"
+            if (this->local_number_of_particles > 0)
+            {
+                this->local_state.reset(new particle_rnumber[state_size*this->local_number_of_particles]);
+                this->local_indices.reset(new partsize_t[this->local_number_of_particles]);
+                this->local_labels.reset(new partsize_t[this->local_number_of_particles]);
+                std::copy(tmp_local_state,
+                          tmp_local_state + state_size*this->local_number_of_particles,
+                          this->local_state.get());
+                std::copy(tmp_local_indices,
+                          tmp_local_indices + this->local_number_of_particles,
+                          this->local_indices.get());
+                std::copy(tmp_local_labels,
+                          tmp_local_labels + this->local_number_of_particles,
+                          this->local_labels.get());
+            }
+
+            particles_utils::partition_extra_z<partsize_t, state_size>(
+                    &this->local_state[0],
+                    this->local_number_of_particles,
+                    partition_interval_size,
+                    this->number_particles_per_partition.get(),
+                    this->offset_particles_for_partition.get(),
+                    [&](const particle_rnumber& z_pos){
+                        const int partition_level = this->pInterpolator.pbc_field_layer(z_pos, IDXC_Z);
+                        assert(current_partition_interval.first <= partition_level && partition_level < current_partition_interval.second);
+                        return partition_level - current_partition_interval.first;
+                    },
+                    [&](const partsize_t idx1, const partsize_t idx2){
+                        std::swap(this->local_indices[idx1], this->local_indices[idx2]);
+                        std::swap(this->local_labels[idx1], this->local_labels[idx2]);
+                    });
+
+            delete[] tmp_local_state;
+            delete[] tmp_local_indices;
+            delete[] tmp_local_labels;
+
+            int file_layout_result = this->setParticleFileLayout(src->getParticleFileLayout());
+            variable_used_only_in_assert(file_layout_result);
+            assert(file_layout_result == EXIT_SUCCESS);
+            return EXIT_SUCCESS;
+        }
+
+        int reset_labels()
+        {
+            std::copy(
+                    this->local_indices.get(),
+                    this->local_indices.get() + this->getLocalNumberOfParticles(),
+                    this->local_labels.get());
+            return EXIT_SUCCESS;
+        }
+
+        /** \brief Filter particle set versus small list of particle indices.
+         *
+         * Using this method, we can select particles from a `src` particle set into the current object.
+         * The code will work reasonably as long as a small list of "indices of interest" is used.
+         *
+         * \warning The indices of interest must be existing indices, otherwise the object will be broken.
+         * In principle we could have a general algorithm that could handle anything, but it would be a messy code,
+         * which would need multiple passes of the data to figure out the new indices.
+         * It's easier to just clean up the data before feeding it to this method.
+         *
+         * \warning `indices_of_interest` must be in increasing order.
+         *
+         */
+        int init_as_subset_of(
+                abstract_particle_set &src,
+                const std::vector<partsize_t> indices_of_interest,
+                bool use_set_complement)
+        {
+            TIMEZONE("particle_set::init_as_subset_of version 2");
+            assert(indices_of_interest.size() > 0);
+            assert(partsize_t(indices_of_interest.size()) < src.getTotalNumberOfParticles());
+            // ensure that indices of interest are sorted
+            particle_rnumber *tmp_local_state = new particle_rnumber[state_size * src.getLocalNumberOfParticles()];
+            partsize_t *tmp_local_indices = new partsize_t[src.getLocalNumberOfParticles()];
+            partsize_t *tmp_local_labels = new partsize_t[src.getLocalNumberOfParticles()];
+            this->local_number_of_particles = 0;
+
+            // set new number of particles
+            if (use_set_complement)
+                this->total_number_of_particles = src.getTotalNumberOfParticles() - indices_of_interest.size();
+            else
+                this->total_number_of_particles = indices_of_interest.size();
+
+            // select interesting particles
+            for (partsize_t ii = 0; ii < partsize_t(src.getLocalNumberOfParticles()); ii++)
+            {
+                partsize_t src_label = src.getParticleLabels()[ii];
+                partsize_t src_index = src.getParticleIndices()[ii];
+
+                bool index_is_interesting = false;
+                // find out if index is interesting
+                partsize_t iii = 0;
+                for (; iii < partsize_t(indices_of_interest.size()); iii++)
+                {
+                    index_is_interesting = (indices_of_interest[iii] == src_index);
+                    if (indices_of_interest[iii] >= src_index)
+                        break;
+                }
+                bool copy_data = false;
+
+                if (use_set_complement && (!index_is_interesting)) // we are effectively deleting particles present in "indices_of_interest"
+                    copy_data = true;
+                if ((!use_set_complement) && index_is_interesting) // we are only keeping particles present in "indices_of_interest"
+                    copy_data = true;
+                if (copy_data)
+                {
+                    // set new index
+                    tmp_local_indices[this->local_number_of_particles] = src_index;
+                    if (use_set_complement)
+                        tmp_local_indices[this->local_number_of_particles] -= iii;
+                    else
+                        tmp_local_indices[this->local_number_of_particles] = iii;
+                    // copy particle with label src_label
+                    tmp_local_labels[this->local_number_of_particles] = src_label;
+                    std::copy(src.getParticleState()+state_size*ii,
+                              src.getParticleState()+state_size*(ii+1),
+                              tmp_local_state + state_size*this->local_number_of_particles);
+                    this->local_number_of_particles++;
+                }
+            }
+            //DEBUG_MSG("particle_set::init_as_subset_of --- after particle selection local number of particles is %d\n",
+            //        this->local_number_of_particles);
+            //for (partsize_t ii = 0; ii < this->local_number_of_particles; ii++)
+            //    DEBUG_MSG(" --- ii = %d, tmp_local_labels[ii] = %d, tmp_local_indices[ii] = %d\n",
+            //            ii,
+            //            tmp_local_labels[ii],
+            //            tmp_local_indices[ii]);
+
+            // now we actually put the data "here"
+            if (this->local_number_of_particles > 0)
+            {
+                this->local_state.reset(new particle_rnumber[state_size*this->local_number_of_particles]);
+                this->local_indices.reset(new partsize_t[this->local_number_of_particles]);
+                this->local_labels.reset(new partsize_t[this->local_number_of_particles]);
                 std::copy(tmp_local_state,
                           tmp_local_state + state_size*this->local_number_of_particles,
                           this->local_state.get());
-                std::copy(tmp_local_index,
-                          tmp_local_index + this->local_number_of_particles,
-                          this->local_index.get());
+                std::copy(tmp_local_indices,
+                          tmp_local_indices + this->local_number_of_particles,
+                          this->local_indices.get());
+                std::copy(tmp_local_labels,
+                          tmp_local_labels + this->local_number_of_particles,
+                          this->local_labels.get());
             }
 
             particles_utils::partition_extra_z<partsize_t, state_size>(
@@ -409,11 +691,21 @@ class particle_set: public abstract_particle_set
                         return partition_level - current_partition_interval.first;
                     },
                     [&](const partsize_t idx1, const partsize_t idx2){
-                        std::swap(this->local_index[idx1], this->local_index[idx2]);
+                        std::swap(this->local_indices[idx1], this->local_indices[idx2]);
+                        std::swap(this->local_labels[idx1], this->local_labels[idx2]);
                     });
 
             delete[] tmp_local_state;
-            delete[] tmp_local_index;
+            delete[] tmp_local_indices;
+            delete[] tmp_local_labels;
+
+            // update particle file layout
+            std::vector<hsize_t> tmp_file_layout(1);
+            tmp_file_layout[0] = hsize_t(this->total_number_of_particles);
+
+            int file_layout_result = this->setParticleFileLayout(tmp_file_layout);
+            variable_used_only_in_assert(file_layout_result);
+            assert(file_layout_result == EXIT_SUCCESS);
             return EXIT_SUCCESS;
         }
 
@@ -431,6 +723,19 @@ class particle_set: public abstract_particle_set
         {
             return &(this->p2pComputer);
         }
+
+        std::vector<partsize_t> selectLocalParticleFromFewIndices(
+                const std::vector<partsize_t> &inGlobalIndicesToDelete)
+        {
+            std::vector<partsize_t> local_indices;
+            for (partsize_t i=0; i<this->getLocalNumberOfParticles(); i++)
+                for (partsize_t ii=0; ii<partsize_t(inGlobalIndicesToDelete.size()); ii++)
+                {
+                    if (this->getParticleIndices()[i] == inGlobalIndicesToDelete[ii])
+                        local_indices.push_back(inGlobalIndicesToDelete[ii]);
+                }
+            return local_indices;
+        }
 };
 
 #endif//PARTICLE_SET_HPP
diff --git a/cpp/particles/lock_free_bool_array.hpp b/cpp/particles/lock_free_bool_array.hpp
index bfcd48880cfc6308f63afe235f0528b1a927f68b..9c0ab5de0c13ab49e88b3d05403631e49656599b 100644
--- a/cpp/particles/lock_free_bool_array.hpp
+++ b/cpp/particles/lock_free_bool_array.hpp
@@ -42,7 +42,7 @@ class lock_free_bool_array{
         Locker(){
             omp_init_nest_lock(&lock);
         }
-        ~Locker(){
+        ~Locker() noexcept(false){
             omp_destroy_nest_lock(&lock);
         }
         omp_nest_lock_t lock;
@@ -68,7 +68,7 @@ public:
         }
     }
 #ifndef NDEBUG
-    ~lock_free_bool_array(){
+    ~lock_free_bool_array() noexcept(false){
         for(auto& k : keys){
 #ifdef __INTEL_COMPILER
 #else
diff --git a/cpp/particles/p2p/p2p_distr_mpi.hpp b/cpp/particles/p2p/p2p_distr_mpi.hpp
index ecf6aa4ddf7c3bd56a745f4ebec01009325cf725..3051bcee05b5d6078abdbac571cc4500ff6af475 100644
--- a/cpp/particles/p2p/p2p_distr_mpi.hpp
+++ b/cpp/particles/p2p/p2p_distr_mpi.hpp
@@ -50,6 +50,7 @@ protected:
         TAG_NB_PARTICLES,
         TAG_POSITION_PARTICLES,
         TAG_INDEX_PARTICLES,
+        TAG_LABEL_PARTICLES,
         TAG_RESULT_PARTICLES,
     };
 
@@ -64,6 +65,7 @@ protected:
         std::unique_ptr<real_number[]> toCompute;
         std::unique_ptr<real_number[]> results;
         std::unique_ptr<partsize_t[]> indexes;
+        std::unique_ptr<partsize_t[]> labels;
     };
 
     enum Action{
@@ -197,7 +199,7 @@ public:
         nb_cell_levels[IDXC_Z] = nb_cells_factor;
     }
 
-    virtual ~p2p_distr_mpi(){}
+    virtual ~p2p_distr_mpi() noexcept(false){}
 
     ////////////////////////////////////////////////////////////////////////////
 
@@ -288,7 +290,8 @@ public:
                        const partsize_t current_my_nb_particles_per_partition[],
                        real_number particles_positions[],
                        std::unique_ptr<real_number[]> particles_current_rhs[], const int nb_rhs,
-                       partsize_t inout_index_particles[]){
+                       partsize_t inout_index_particles[],
+                       partsize_t inout_label_particles[] = nullptr){
         TIMEZONE("p2p_distr_mpi::compute_distr");
 
         // Some processes might not be involved
@@ -297,6 +300,8 @@ public:
             return;
         }
 
+        const bool labels_present = (inout_label_particles != nullptr);
+
         const long int my_top_z_cell_level = last_cell_level_proc(my_rank);
         assert(my_top_z_cell_level < nb_cell_levels[IDXC_Z]);
         const long int my_down_z_cell_level = first_cell_level_proc(my_rank);
@@ -369,6 +374,13 @@ public:
                                 part_to_sort.data(),
                                 inout_index_particles,
                                 &buffer);
+                if (labels_present)
+                    permute_copy<partsize_t, 1>(
+                                    current_offset_particles_for_partition[idxPartition],
+                                    current_my_nb_particles_per_partition[idxPartition],
+                                    part_to_sort.data(),
+                                    inout_label_particles,
+                                    &buffer);
                 permute_copy<long int, 1>(
                                 current_offset_particles_for_partition[idxPartition],
                                 current_my_nb_particles_per_partition[idxPartition],
@@ -434,13 +446,18 @@ public:
         DEBUG_MSG("my_down_z_cell_level = %d\n", int(my_down_z_cell_level));
         DEBUG_MSG("first_cell_level_proc(0) = %d\n", int(first_cell_level_proc(0)));
         DEBUG_MSG("first_cell_level_proc(1) = %d\n", int(first_cell_level_proc(1)));
-        DEBUG_MSG("first_cell_level_proc(2) = %d\n", int(first_cell_level_proc(2)));
-        DEBUG_MSG("first_cell_level_proc(3) = %d\n", int(first_cell_level_proc(3)));
+        if (nb_processes > 1)
+            DEBUG_MSG("first_cell_level_proc(2) = %d\n", int(first_cell_level_proc(2)));
+        if (nb_processes > 2)
+            DEBUG_MSG("first_cell_level_proc(3) = %d\n", int(first_cell_level_proc(3)));
         DEBUG_MSG("nb_cell_levels[IDXC_Z] = %d\n", int(nb_cell_levels[IDXC_Z]));
         DEBUG_MSG("last_cell_level_proc(0) = %d\n", int(last_cell_level_proc(0)));
-        DEBUG_MSG("last_cell_level_proc(1) = %d\n", int(last_cell_level_proc(1)));
-        DEBUG_MSG("last_cell_level_proc(2) = %d\n", int(last_cell_level_proc(2)));
-        DEBUG_MSG("last_cell_level_proc(3) = %d\n", int(last_cell_level_proc(3)));
+        if (nb_processes > 1)
+            DEBUG_MSG("last_cell_level_proc(1) = %d\n", int(last_cell_level_proc(1)));
+        if (nb_processes > 2)
+            DEBUG_MSG("last_cell_level_proc(2) = %d\n", int(last_cell_level_proc(2)));
+        if (nb_processes > 3)
+            DEBUG_MSG("last_cell_level_proc(3) = %d\n", int(last_cell_level_proc(3)));
 
         // Find process with at least one neighbor
         {
@@ -549,6 +566,21 @@ public:
                                 current_com,
                                 &mpiRequests.back()));
 
+                    if (labels_present)
+                    {
+                        whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
+                        mpiRequests.emplace_back();
+                        assert(descriptor.nbParticlesToExchange*size_particle_positions < std::numeric_limits<int>::max());
+                        AssertMpi(MPI_Isend(
+                                    const_cast<partsize_t*>(&inout_label_particles[particles_offset_layers[my_nb_cell_levels-descriptor.nbLevelsToExchange]]),
+                                    int(descriptor.nbParticlesToExchange),
+                                    particles_utils::GetMpiType(partsize_t()),
+                                    descriptor.destProc,
+                                    TAG_LABEL_PARTICLES,
+                                    current_com,
+                                    &mpiRequests.back()));
+                    }
+
                     assert(descriptor.toRecvAndMerge == nullptr);
                     descriptor.toRecvAndMerge.reset(new real_number[descriptor.nbParticlesToExchange*size_particle_rhs]);
                     whatNext.emplace_back(std::pair<Action,int>{MERGE_PARTICLES, idxDescr});
@@ -675,6 +707,8 @@ public:
                         assert(NbParticlesToReceive != -1);
                         assert(descriptor.toCompute == nullptr);
                         assert(descriptor.indexes == nullptr);
+                        if (labels_present)
+                            assert(descriptor.labels == nullptr);
 
                         if(NbParticlesToReceive){
                             descriptor.toCompute.reset(new real_number[NbParticlesToReceive*size_particle_positions]);
@@ -702,6 +736,22 @@ public:
                                         TAG_INDEX_PARTICLES,
                                         current_com,
                                         &mpiRequests.back()));
+
+                            if (labels_present)
+                            {
+                                descriptor.labels.reset(new partsize_t[NbParticlesToReceive]);
+                                whatNext.emplace_back(std::pair<Action,int>{COMPUTE_PARTICLES, releasedAction.second});
+                                mpiRequests.emplace_back();
+                                assert(NbParticlesToReceive*size_particle_positions < std::numeric_limits<int>::max());
+                                AssertMpi(MPI_Irecv(
+                                            descriptor.labels.get(),
+                                            int(NbParticlesToReceive),
+                                            particles_utils::GetMpiType(partsize_t()),
+                                            destProc,
+                                            TAG_LABEL_PARTICLES,
+                                            current_com,
+                                            &mpiRequests.back()));
+                            }
                         }
                     }
 
@@ -711,9 +761,12 @@ public:
                     if(releasedAction.first == COMPUTE_PARTICLES){
                         NeighborDescriptor& descriptor = neigDescriptors[releasedAction.second];
                         descriptor.nbReceived += 1;
-                        assert(descriptor.nbReceived <= 2);
 
-                        if(descriptor.nbReceived == 2){
+                        int nbReceived_desired_value = 2;
+                        if (labels_present)
+                            nbReceived_desired_value = 3;
+
+                        if(descriptor.nbReceived == nbReceived_desired_value){
                             TIMEZONE("compute-particles");
                             NeighborDescriptor& descriptor = neigDescriptors[releasedAction.second];
                             assert(descriptor.isRecv);
@@ -721,6 +774,8 @@ public:
 
                             assert(descriptor.toCompute != nullptr);
                             assert(descriptor.indexes != nullptr);
+                            if (labels_present)
+                                assert(descriptor.labels != nullptr);
                             // allocate rhs buffer
                             descriptor.results.reset(new real_number[NbParticlesToReceive*size_particle_rhs]);
                             // clean up rhs buffer
@@ -818,6 +873,7 @@ public:
                                         &mpiRequests.back()));
                             delete[] descriptor.toCompute.release();
                             delete[] descriptor.indexes.release();
+                            delete[] descriptor.labels.release();
                         }
                     }
                     //////////////////////////////////////////////////////////////////////
diff --git a/cpp/particles/particle_solver.cpp b/cpp/particles/particle_solver.cpp
index f53b24bdf731f70dd7437966baecac1571583f53..e22290e0a815f9e072b5fdc4a524aa31ef089d9c 100644
--- a/cpp/particles/particle_solver.cpp
+++ b/cpp/particles/particle_solver.cpp
@@ -315,7 +315,7 @@ int particle_solver::writeCheckpoint(
     particles_output_writer->template save<state_size>(
             this->pset->getParticleState(),
             this->additional_states.data(),
-            this->pset->getParticleIndex(),
+            this->pset->getParticleIndices(),
             this->pset->getLocalNumberOfParticles(),
             this->iteration);
     return EXIT_SUCCESS;
diff --git a/cpp/particles/particle_solver.hpp b/cpp/particles/particle_solver.hpp
index 004581c8961364714fdbfd775ad683be43748117..54bbc3c846022c00f220d9f427e121241fd10223 100644
--- a/cpp/particles/particle_solver.hpp
+++ b/cpp/particles/particle_solver.hpp
@@ -74,7 +74,7 @@ class particle_solver
             this->additional_states.resize(number_of_additional_states);
             this->particle_species_name = "tracers0";
         }
-        ~particle_solver(){}
+        ~particle_solver() noexcept(false){}
 
         int setIteration(const int i)
         {
diff --git a/cpp/particles/particles_distr_mpi.hpp b/cpp/particles/particles_distr_mpi.hpp
index 7a4d646c2e663aa31a972a8c488e9c6aca6f6e18..0a468253dc4d38d362d2dec189445de55df3ec7e 100644
--- a/cpp/particles/particles_distr_mpi.hpp
+++ b/cpp/particles/particles_distr_mpi.hpp
@@ -60,6 +60,9 @@ protected:
         TAG_LOW_UP_MOVED_PARTICLES_INDEXES,
         TAG_UP_LOW_MOVED_PARTICLES_INDEXES,
 
+        TAG_LOW_UP_MOVED_PARTICLES_LABELS,
+        TAG_UP_LOW_MOVED_PARTICLES_LABELS,
+
         TAG_LOW_UP_MOVED_PARTICLES_RHS,
         TAG_LOW_UP_MOVED_PARTICLES_RHS_MAX = TAG_LOW_UP_MOVED_PARTICLES_RHS+MaxNbRhs,
 
@@ -160,7 +163,7 @@ public:
         assert(int(field_grid_dim[IDXC_Z]) == partition_interval_offset_per_proc[nb_processes_involved]);
     }
 
-    virtual ~particles_distr_mpi(){}
+    virtual ~particles_distr_mpi() noexcept(false){}
 
     ////////////////////////////////////////////////////////////////////////////
 
@@ -557,7 +560,8 @@ public:
                       partsize_t* nb_particles,
                       std::unique_ptr<real_number[]>* inout_positions_particles,
                       std::unique_ptr<real_number[]> inout_rhs_particles[], const int in_nb_rhs,
-                      std::unique_ptr<partsize_t[]>* inout_index_particles){
+                      std::unique_ptr<partsize_t[]>* inout_index_particles,
+                      std::unique_ptr<partsize_t[]>* inout_label_particles = nullptr){
         TIMEZONE("redistribute");
 
         // Some latest processes might not be involved
@@ -565,6 +569,8 @@ public:
             return;
         }
 
+        const bool labels_present = (inout_label_particles != nullptr);
+
         {// this fails when particles move more than one cell during a single time-step
             partsize_t partOffset = 0;
             for(int idxPartition = 0 ; idxPartition < current_partition_size ; ++idxPartition){
@@ -603,6 +609,15 @@ public:
                           (*inout_index_particles)[size_particle_index*idx2+idx_val]);
             }
 
+            if (labels_present)
+            {
+                for(int idx_val = 0 ; idx_val < size_particle_index ; ++idx_val)
+                {
+                    std::swap((*inout_label_particles)[size_particle_index*idx1+idx_val],
+                              (*inout_label_particles)[size_particle_index*idx2+idx_val]);
+                }
+            }
+
             for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                 for(int idx_val = 0 ; idx_val < size_particle_rhs ; ++idx_val){
                     std::swap(inout_rhs_particles[idx_rhs][idx1*size_particle_rhs + idx_val],
@@ -629,6 +644,15 @@ public:
                           (*inout_index_particles)[size_particle_index*idx2+idx_val]);
             }
 
+            if (labels_present)
+            {
+                for(int idx_val = 0 ; idx_val < size_particle_index ; ++idx_val)
+                {
+                    std::swap((*inout_label_particles)[size_particle_index*idx1+idx_val],
+                              (*inout_label_particles)[size_particle_index*idx2+idx_val]);
+                }
+            }
+
             for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                 for(int idx_val = 0 ; idx_val < size_particle_rhs ; ++idx_val){
                     std::swap(inout_rhs_particles[idx_rhs][idx1*size_particle_rhs + idx_val],
@@ -645,6 +669,8 @@ public:
         std::unique_ptr<real_number[]> newParticlesUp;
         std::unique_ptr<partsize_t[]> newParticlesLowIndexes;
         std::unique_ptr<partsize_t[]> newParticlesUpIndexes;
+        std::unique_ptr<partsize_t[]> newParticlesLowLabels;
+        std::unique_ptr<partsize_t[]> newParticlesUpLabels;
         std::vector<std::unique_ptr<real_number[]>> newParticlesLowRhs(in_nb_rhs);
         std::vector<std::unique_ptr<real_number[]>> newParticlesUpRhs(in_nb_rhs);
 
@@ -679,6 +705,13 @@ public:
                           (my_rank-1+nb_processes_involved)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_LOW_UP_MOVED_PARTICLES_INDEXES,
                           MPI_COMM_WORLD, &mpiRequests.back()));
 
+                if (labels_present)
+                {
+                    AssertMpi(MPI_Isend(&(*inout_label_particles)[0], int(nbOutLower*size_particle_index), particles_utils::GetMpiType(partsize_t()),
+                              (my_rank-1+nb_processes_involved)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_LOW_UP_MOVED_PARTICLES_LABELS,
+                              MPI_COMM_WORLD, &mpiRequests.back()));
+                }
+
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                     whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
                     mpiRequests.emplace_back();
@@ -715,6 +748,12 @@ public:
                 AssertMpi(MPI_Isend(&(*inout_index_particles)[(myTotalNbParticles-nbOutUpper)*size_particle_index], int(nbOutUpper*size_particle_index),
                           particles_utils::GetMpiType(partsize_t()), (my_rank+1)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_UP_LOW_MOVED_PARTICLES_INDEXES,
                           MPI_COMM_WORLD, &mpiRequests.back()));
+                if (labels_present)
+                {
+                    AssertMpi(MPI_Isend(&(*inout_label_particles)[(myTotalNbParticles-nbOutUpper)*size_particle_index], int(nbOutUpper*size_particle_index),
+                              particles_utils::GetMpiType(partsize_t()), (my_rank+1)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_UP_LOW_MOVED_PARTICLES_LABELS,
+                              MPI_COMM_WORLD, &mpiRequests.back()));
+                }
 
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                     whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
@@ -758,6 +797,18 @@ public:
                                   (my_rank-1+nb_processes_involved)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_UP_LOW_MOVED_PARTICLES_INDEXES,
                                   MPI_COMM_WORLD, &mpiRequests.back()));
 
+                        if (labels_present)
+                        {
+                            newParticlesLowLabels.reset(new partsize_t[nbNewFromLow*size_particle_index]);
+                            whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
+                            mpiRequests.emplace_back();
+                            assert(nbNewFromLow*size_particle_index < std::numeric_limits<int>::max());
+                            AssertMpi(MPI_Irecv(&newParticlesLowLabels[0], int(nbNewFromLow*size_particle_index),
+                                      particles_utils::GetMpiType(partsize_t()),
+                                      (my_rank-1+nb_processes_involved)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_UP_LOW_MOVED_PARTICLES_LABELS,
+                                      MPI_COMM_WORLD, &mpiRequests.back()));
+                        }
+
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                             newParticlesLowRhs[idx_rhs].reset(new real_number[nbNewFromLow*size_particle_rhs]);
                             whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
@@ -788,6 +839,18 @@ public:
                                   (my_rank+1)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_LOW_UP_MOVED_PARTICLES_INDEXES,
                                   MPI_COMM_WORLD, &mpiRequests.back()));
 
+                        if (labels_present)
+                        {
+                            newParticlesUpLabels.reset(new partsize_t[nbNewFromUp*size_particle_index]);
+                            whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
+                            mpiRequests.emplace_back();
+                            assert(nbNewFromUp*size_particle_index < std::numeric_limits<int>::max());
+                            AssertMpi(MPI_Irecv(&newParticlesUpLabels[0], int(nbNewFromUp*size_particle_index),
+                                      particles_utils::GetMpiType(partsize_t()),
+                                      (my_rank+1)%nb_processes_involved, TAG_SHIFT_OFFSET*counter_shift_tags + TAG_LOW_UP_MOVED_PARTICLES_LABELS,
+                                      MPI_COMM_WORLD, &mpiRequests.back()));
+                        }
+
                         for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                             newParticlesUpRhs[idx_rhs].reset(new real_number[nbNewFromUp*size_particle_rhs]);
                             whatNext.emplace_back(std::pair<Action,int>{NOTHING_TODO, -1});
@@ -818,6 +881,7 @@ public:
 
             std::unique_ptr<real_number[]> newArray(new real_number[myTotalNewNbParticles*size_particle_positions]);
             std::unique_ptr<partsize_t[]> newArrayIndexes(new partsize_t[myTotalNewNbParticles*size_particle_index]);
+            std::unique_ptr<partsize_t[]> newArrayLabels(new partsize_t[myTotalNewNbParticles*size_particle_index]);
             std::vector<std::unique_ptr<real_number[]>> newArrayRhs(in_nb_rhs);
             for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                 newArrayRhs[idx_rhs].reset(new real_number[myTotalNewNbParticles*size_particle_rhs]);
@@ -828,6 +892,8 @@ public:
                 const particles_utils::fixed_copy fcp(0, 0, nbNewFromLow);
                 fcp.copy(newArray, newParticlesLow, size_particle_positions);
                 fcp.copy(newArrayIndexes, newParticlesLowIndexes, size_particle_index);
+                if (labels_present)
+                    fcp.copy(newArrayLabels, newParticlesLowLabels, size_particle_index);
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                     fcp.copy(newArrayRhs[idx_rhs], newParticlesLowRhs[idx_rhs], size_particle_rhs);
                 }
@@ -838,6 +904,10 @@ public:
                 const particles_utils::fixed_copy fcp(nbNewFromLow, nbOutLower, nbOldParticlesInside);
                 fcp.copy(newArray, (*inout_positions_particles), size_particle_positions);
                 fcp.copy(newArrayIndexes, (*inout_index_particles), size_particle_index);
+                if (labels_present)
+                {
+                    fcp.copy(newArrayLabels, (*inout_label_particles), size_particle_index);
+                }
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                     fcp.copy(newArrayRhs[idx_rhs], inout_rhs_particles[idx_rhs], size_particle_rhs);
                 }
@@ -848,6 +918,8 @@ public:
                 const particles_utils::fixed_copy fcp(nbNewFromLow+nbOldParticlesInside, 0, nbNewFromUp);
                 fcp.copy(newArray, newParticlesUp, size_particle_positions);
                 fcp.copy(newArrayIndexes, newParticlesUpIndexes, size_particle_index);
+                if (labels_present)
+                    fcp.copy(newArrayLabels, newParticlesUpLabels, size_particle_index);
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                     fcp.copy(newArrayRhs[idx_rhs], newParticlesUpRhs[idx_rhs], size_particle_rhs);
                 }
@@ -855,6 +927,10 @@ public:
 
             (*inout_positions_particles) = std::move(newArray);
             (*inout_index_particles) = std::move(newArrayIndexes);
+            if (labels_present)
+            {
+                (*inout_label_particles) = std::move(newArrayLabels);
+            }
             for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                 inout_rhs_particles[idx_rhs] = std::move(newArrayRhs[idx_rhs]);
             }
@@ -878,6 +954,13 @@ public:
                     std::swap((*inout_index_particles)[size_particle_index*idx1 + idx_val],
                               (*inout_index_particles)[size_particle_index*idx2 + idx_val]);
                 }
+                if (labels_present)
+                {
+                    for(int idx_val = 0 ; idx_val < size_particle_index ; ++idx_val){
+                        std::swap((*inout_label_particles)[size_particle_index*idx1 + idx_val],
+                                  (*inout_label_particles)[size_particle_index*idx2 + idx_val]);
+                    }
+                }
 
                 for(int idx_rhs = 0 ; idx_rhs < in_nb_rhs ; ++idx_rhs){
                     for(int idx_val = 0 ; idx_val < size_particle_rhs ; ++idx_val){
diff --git a/cpp/particles/particles_input_grid.hpp b/cpp/particles/particles_input_grid.hpp
index e132095ee20c527039d23824a5243816957b32df..784c08e0623b602dc6e81a7b4bd13ed3c8a8dfe0 100644
--- a/cpp/particles/particles_input_grid.hpp
+++ b/cpp/particles/particles_input_grid.hpp
@@ -45,8 +45,10 @@ class particles_input_grid: public abstract_particles_input<partsize_t, particle
 
         std::unique_ptr<particle_rnumber[]> local_particle_state;
         std::unique_ptr<partsize_t[]> local_particle_index;
+        std::unique_ptr<partsize_t[]> local_particle_label;
         std::vector<std::unique_ptr<particle_rnumber[]>> local_particle_rhs;
     public:
+        ~particles_input_grid() noexcept(false){}
         particles_input_grid(
                 const MPI_Comm in_mpi_comm,
                 const partsize_t NXPARTICLES,
@@ -179,6 +181,12 @@ class particles_input_grid: public abstract_particles_input<partsize_t, particle
             }
             /*************************************************/
 
+
+        // clone indices in labels:
+        local_particle_label.reset(new partsize_t[this->getLocalNbParticles()]);
+        std::copy(local_particle_index.get(),
+                  local_particle_index.get()+this->getLocalNbParticles(),
+                  local_particle_label.get());
         }
 
         partsize_t getTotalNbParticles()
@@ -206,6 +214,12 @@ class particles_input_grid: public abstract_particles_input<partsize_t, particle
             return std::move(this->local_particle_index);
         }
 
+        std::unique_ptr<partsize_t[]> getMyParticlesLabels()
+        {
+            assert(this->local_particle_label != nullptr || this->local_number_of_particles == 0);
+            return std::move(this->local_particle_label);
+        }
+
         std::vector<std::unique_ptr<particle_rnumber[]>> getMyRhs()
         {
             return std::move(std::vector<std::unique_ptr<particle_rnumber[]>>());
diff --git a/cpp/particles/particles_input_hdf5.hpp b/cpp/particles/particles_input_hdf5.hpp
index 680daff93c55ad1e6fe6951dfc3705b1229d17de..b1ea662ed14eaf4e725c532429eb631ade4ef8b7 100644
--- a/cpp/particles/particles_input_hdf5.hpp
+++ b/cpp/particles/particles_input_hdf5.hpp
@@ -37,6 +37,7 @@
 #include "alltoall_exchanger.hpp"
 #include "particles/particles_utils.hpp"
 #include "scope_timer.hpp"
+#include "hdf5_tools.hpp"
 
 
 template <class partsize_t, class real_number, int size_particle_positions, int size_particle_rhs>
@@ -54,6 +55,7 @@ class particles_input_hdf5 : public abstract_particles_input<partsize_t, real_nu
 
     std::unique_ptr<real_number[]> my_particles_positions;
     std::unique_ptr<partsize_t[]> my_particles_indexes;
+    std::unique_ptr<partsize_t[]> my_particles_labels;
     std::vector<std::unique_ptr<real_number[]>> my_particles_rhs;
 
 public:
@@ -166,7 +168,7 @@ public:
 
         static_assert(std::is_same<real_number, double>::value
                       || std::is_same<real_number, float>::value, "real_number must be double or float");
-        const hid_t type_id = (sizeof(real_number) == 8?H5T_NATIVE_DOUBLE:H5T_NATIVE_FLOAT);
+        const hid_t type_id = hdf5_tools::hdf5_type_id<real_number>();
 
         /// Load the data
         std::unique_ptr<real_number[]> split_particles_positions;
@@ -318,9 +320,15 @@ public:
             hdfret = H5Pclose(plist_id_par);
             assert(hdfret >= 0);
         }
+
+        // clone indices in labels:
+        my_particles_labels.reset(new partsize_t[this->getLocalNbParticles()]);
+        std::copy(my_particles_indexes.get(),
+                  my_particles_indexes.get()+this->getLocalNbParticles(),
+                  my_particles_labels.get());
     }
 
-    ~particles_input_hdf5(){
+    ~particles_input_hdf5() noexcept(false){
     }
 
     partsize_t getTotalNbParticles() final{
@@ -350,6 +358,11 @@ public:
         return std::move(my_particles_indexes);
     }
 
+    std::unique_ptr<partsize_t[]> getMyParticlesLabels() final {
+        assert(my_particles_labels != nullptr || nb_particles_for_me == 0);
+        return std::move(my_particles_labels);
+    }
+
     std::vector<hsize_t> getParticleFileLayout(){
         return std::vector<hsize_t>(this->particle_file_layout);
     }
diff --git a/cpp/particles/particles_input_random.hpp b/cpp/particles/particles_input_random.hpp
index 1179b080f4079515b42d16e64a0de9daa7cb8af2..0b40ae57f70729b82984c4c5b4591568e4078485 100644
--- a/cpp/particles/particles_input_random.hpp
+++ b/cpp/particles/particles_input_random.hpp
@@ -44,6 +44,7 @@ class particles_input_random: public abstract_particles_input<partsize_t, partic
 
         std::unique_ptr<particle_rnumber[]> local_particle_state;
         std::unique_ptr<partsize_t[]> local_particle_index;
+        std::unique_ptr<partsize_t[]> local_particle_label;
         std::vector<std::unique_ptr<particle_rnumber[]>> local_particle_rhs;
     public:
         particles_input_random(
@@ -219,6 +220,12 @@ class particles_input_random: public abstract_particles_input<partsize_t, partic
             }
             /*************************************************/
 
+
+        // clone indices in labels:
+        local_particle_label.reset(new partsize_t[this->getLocalNbParticles()]);
+        std::copy(local_particle_index.get(),
+                  local_particle_index.get()+this->getLocalNbParticles(),
+                  local_particle_label.get());
         }
 
         partsize_t getTotalNbParticles()
@@ -246,6 +253,12 @@ class particles_input_random: public abstract_particles_input<partsize_t, partic
             return std::move(this->local_particle_index);
         }
 
+        std::unique_ptr<partsize_t[]> getMyParticlesLabels()
+        {
+            assert(this->local_particle_label != nullptr || this->local_number_of_particles == 0);
+            return std::move(this->local_particle_label);
+        }
+
         std::vector<std::unique_ptr<particle_rnumber[]>> getMyRhs()
         {
             return std::move(std::vector<std::unique_ptr<particle_rnumber[]>>());
diff --git a/cpp/particles/particles_output_hdf5.hpp b/cpp/particles/particles_output_hdf5.hpp
index 236504e15d00642723eb9cf7b46db042028b2a9c..0ef809e63114948509c96f5cbccc5cdd615b3599 100644
--- a/cpp/particles/particles_output_hdf5.hpp
+++ b/cpp/particles/particles_output_hdf5.hpp
@@ -38,9 +38,11 @@ template <class partsize_t,
           class real_number,
           int size_particle_positions>
 class particles_output_hdf5 : public abstract_particles_output<partsize_t,
+                                                               real_number,
                                                                real_number,
                                                                size_particle_positions>{
     using Parent = abstract_particles_output<partsize_t,
+                                             real_number,
                                              real_number,
                                              size_particle_positions>;
 
@@ -62,6 +64,7 @@ public:
                           const int in_nb_rhs,
                           const bool in_use_collective_io = false)
             : abstract_particles_output<partsize_t,
+                                        real_number,
                                         real_number,
                                         size_particle_positions>(
                                                 in_mpi_com,
@@ -112,7 +115,7 @@ public:
         return EXIT_SUCCESS;
     }
 
-    ~particles_output_hdf5(){}
+    ~particles_output_hdf5() noexcept(false){}
 
     void update_particle_species_name(
             const std::string new_name)
diff --git a/cpp/particles/particles_output_mpiio.hpp b/cpp/particles/particles_output_mpiio.hpp
index b05579e2e3cf013689ef0b2e30b763d285952e86..ee9bd9cee42d3973e1e9e1bb93eb67a6329836d3 100644
--- a/cpp/particles/particles_output_mpiio.hpp
+++ b/cpp/particles/particles_output_mpiio.hpp
@@ -36,8 +36,8 @@
 #include "particles_utils.hpp"
 
 template <class partsize_t, class real_number, int size_particle_positions, int size_particle_rhs>
-class particles_output_mpiio : public abstract_particles_output<partsize_t, real_number, size_particle_positions>{
-    using Parent = abstract_particles_output<partsize_t, real_number, size_particle_positions>;
+class particles_output_mpiio : public abstract_particles_output<partsize_t, real_number, real_number, size_particle_positions>{
+    using Parent = abstract_particles_output<partsize_t, real_number, real_number, size_particle_positions>;
 
     const std::string filename;
     const int nb_step_prealloc;
@@ -49,7 +49,7 @@ class particles_output_mpiio : public abstract_particles_output<partsize_t, real
 public:
     particles_output_mpiio(MPI_Comm in_mpi_com, const std::string in_filename, const partsize_t inTotalNbParticles,
                            const int in_nb_rhs, const int in_nb_step_prealloc = -1)
-            : abstract_particles_output<partsize_t, real_number, size_particle_positions>(in_mpi_com, inTotalNbParticles, in_nb_rhs),
+            : abstract_particles_output<partsize_t, real_number, real_number, size_particle_positions>(in_mpi_com, inTotalNbParticles, in_nb_rhs),
               filename(in_filename), nb_step_prealloc(in_nb_step_prealloc), current_step_in_file(0){
         if(Parent::isInvolved()){
             {
@@ -65,7 +65,7 @@ public:
         }
     }
 
-    ~particles_output_mpiio(){
+    ~particles_output_mpiio() noexcept(false){
         if(Parent::isInvolved()){
             TIMEZONE("particles_output_mpiio::MPI_File_close");
             AssertMpi(MPI_File_close(&mpi_file));
diff --git a/cpp/particles/particles_output_sampling_hdf5.hpp b/cpp/particles/particles_output_sampling_hdf5.hpp
index 11a7dcc13ad2b292a9f8215b669bdcf4c97addb9..e3cc2e021b7062471f384d1eac5c288afc882939 100644
--- a/cpp/particles/particles_output_sampling_hdf5.hpp
+++ b/cpp/particles/particles_output_sampling_hdf5.hpp
@@ -27,18 +27,21 @@
 #define PARTICLES_OUTPUT_SAMPLING_HDF5_HPP
 
 #include "abstract_particles_output.hpp"
+#include "hdf5_tools.hpp"
 
-#include <hdf5.h>
 
 template <class partsize_t,
-          class real_number,
+          class position_type,
+          class output_type,
           int size_particle_positions>
 class particles_output_sampling_hdf5 : public abstract_particles_output<
                                        partsize_t,
-                                       real_number,
+                                       position_type,
+                                       output_type,
                                        size_particle_positions>{
     using Parent = abstract_particles_output<partsize_t,
-                                             real_number,
+                                             position_type,
+                                             output_type,
                                              size_particle_positions>;
 
     hid_t file_id, pgroup_id;
@@ -116,7 +119,7 @@ public:
         }
     }
 
-    ~particles_output_sampling_hdf5(){
+    ~particles_output_sampling_hdf5() noexcept(false){
         if(Parent::isInvolved()){
             // close group
             int retTest = H5Gclose(pgroup_id);
@@ -151,8 +154,8 @@ public:
     int save_dataset(
             const std::string& in_groupname,
             const std::string& in_dataset_name,
-            const real_number input_particles_positions[],
-            const std::unique_ptr<real_number[]> input_particles_rhs[],
+            const position_type input_particles_positions[],
+            const std::unique_ptr<output_type[]> input_particles_rhs[],
             const partsize_t index_particles[],
             const partsize_t nb_particles,
             const int idx_time_step)
@@ -183,8 +186,8 @@ public:
 
     void write(
             const int /*idx_time_step*/,
-            const real_number* /*particles_positions*/,
-            const std::unique_ptr<real_number[]>* particles_rhs,
+            const position_type* /*particles_positions*/,
+            const std::unique_ptr<output_type[]>* particles_rhs,
             const partsize_t nb_particles,
             const partsize_t particles_idx_offset,
             const int size_particle_rhs) final{
@@ -197,12 +200,11 @@ public:
                 nb_particles == 0));
         assert(particles_idx_offset+nb_particles <= Parent::getTotalNbParticles());
 
-        static_assert(std::is_same<real_number, double>::value ||
-                      std::is_same<real_number, float>::value,
-                      "real_number must be double or float");
-        const hid_t type_id = (sizeof(real_number) == 8 ?
-                               H5T_NATIVE_DOUBLE :
-                               H5T_NATIVE_FLOAT);
+        static_assert(std::is_same<output_type, double>::value ||
+                      std::is_same<output_type, float>::value ||
+                      std::is_same<output_type, long long int>::value,
+                      "output_type must be double or float or long long int");
+        const hid_t type_id = hdf5_tools::hdf5_type_id<output_type>();
 
         hid_t plist_id = H5Pcreate(H5P_DATASET_XFER);
         assert(plist_id >= 0);
diff --git a/cpp/particles/particles_sampling.hpp b/cpp/particles/particles_sampling.hpp
index 1606b0228b334e15355644610e02410ec4253653..8e83a5a53690b6cb3abaddaafe2245b1f448d164 100644
--- a/cpp/particles/particles_sampling.hpp
+++ b/cpp/particles/particles_sampling.hpp
@@ -46,7 +46,7 @@ void sample_from_particles_system(const field<rnumber, be, fc>& in_field, // a p
     const int size_particle_rhs = ncomp(fc);
 
     // Stop here if already exists
-    if(particles_output_sampling_hdf5<partsize_t, particles_rnumber, 3>::DatasetExistsCol(MPI_COMM_WORLD,
+    if(particles_output_sampling_hdf5<partsize_t, particles_rnumber, particles_rnumber, 3>::DatasetExistsCol(MPI_COMM_WORLD,
                                                                                           filename,
                                                                                           parent_groupname,
                                                                                           datasetname)){
@@ -61,7 +61,7 @@ void sample_from_particles_system(const field<rnumber, be, fc>& in_field, // a p
 
 
 
-    particles_output_sampling_hdf5<partsize_t, particles_rnumber, 3> outputclass(MPI_COMM_WORLD,
+    particles_output_sampling_hdf5<partsize_t, particles_rnumber, particles_rnumber, 3> outputclass(MPI_COMM_WORLD,
                                                                                  ps->getGlobalNbParticles(),
                                                                                  filename,
                                                                                  parent_groupname,
@@ -82,7 +82,7 @@ void sample_particles_system_position(
     const std::string datasetname = fname + std::string("/") + std::to_string(ps->get_step_idx());
 
     // Stop here if already exists
-    if(particles_output_sampling_hdf5<partsize_t, particles_rnumber, 3>::DatasetExistsCol(MPI_COMM_WORLD,
+    if(particles_output_sampling_hdf5<partsize_t, particles_rnumber, particles_rnumber, 3>::DatasetExistsCol(MPI_COMM_WORLD,
                                                                                           filename,
                                                                                           parent_groupname,
                                                                                           datasetname)){
@@ -93,7 +93,7 @@ void sample_particles_system_position(
     std::unique_ptr<particles_rnumber[]> sample_rhs(new particles_rnumber[3*nb_particles]);
     std::copy(ps->getParticlesState(), ps->getParticlesState() + 3*nb_particles, sample_rhs.get());
 
-    particles_output_sampling_hdf5<partsize_t, particles_rnumber, 3> outputclass(MPI_COMM_WORLD,
+    particles_output_sampling_hdf5<partsize_t, particles_rnumber, particles_rnumber, 3> outputclass(MPI_COMM_WORLD,
                                                                                  ps->getGlobalNbParticles(),
                                                                                  filename,
                                                                                  parent_groupname,
diff --git a/cpp/particles/particles_system.hpp b/cpp/particles/particles_system.hpp
index b47763028aa25d040c51ffcde11a3dd3cfe7a87d..9589e4dcc2738c554f7ff364235b7bc92d8a155a 100644
--- a/cpp/particles/particles_system.hpp
+++ b/cpp/particles/particles_system.hpp
@@ -137,7 +137,7 @@ public:
         current_offset_particles_for_partition.reset(new partsize_t[partition_interval_size+1]);
     }
 
-    ~particles_system(){
+    ~particles_system() noexcept(false){
     }
 
     void init(abstract_particles_input<partsize_t, real_number>& particles_input) {
diff --git a/cpp/particles/rhs/deformation_tensor_rhs.hpp b/cpp/particles/rhs/deformation_tensor_rhs.hpp
index cbf43cbce49e039cc8ebb794dd541caed6889853..0835f9869645d14eacedea5990562dffbd0203e4 100644
--- a/cpp/particles/rhs/deformation_tensor_rhs.hpp
+++ b/cpp/particles/rhs/deformation_tensor_rhs.hpp
@@ -46,7 +46,7 @@ class deformation_tensor_rhs: public abstract_particle_rhs
 
     public:
         deformation_tensor_rhs(){}
-        ~deformation_tensor_rhs(){}
+        ~deformation_tensor_rhs() noexcept(false){}
 
         const int getStateSize() const
         {
diff --git a/cpp/particles/rhs/tracer_rhs.hpp b/cpp/particles/rhs/tracer_rhs.hpp
index 03bfab35d4803ff039f910a4d92305f455e26711..680b46fdbc330d3bd892a1343094dd066c1f83a5 100644
--- a/cpp/particles/rhs/tracer_rhs.hpp
+++ b/cpp/particles/rhs/tracer_rhs.hpp
@@ -41,7 +41,7 @@ class tracer_rhs: public abstract_particle_rhs
 
     public:
         tracer_rhs(){}
-        ~tracer_rhs(){}
+        ~tracer_rhs() noexcept(false){}
 
         const int getStateSize() const
         {
diff --git a/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp b/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp
index 9ba41c3092fab1f5de5605e050e9a7facb670511..5aa15213d02702eb96c198fab0e333584efb1598 100644
--- a/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp
+++ b/cpp/particles/rhs/tracer_with_collision_counter_rhs.hpp
@@ -42,7 +42,7 @@ class tracer_with_collision_counter_rhs: public tracer_rhs<rnumber, be, tt>
 
     public:
         tracer_with_collision_counter_rhs(){}
-        ~tracer_with_collision_counter_rhs(){}
+        ~tracer_with_collision_counter_rhs() noexcept(false){}
 
         virtual const int getStateSize() const
         {
diff --git a/cpp/scope_timer.hpp b/cpp/scope_timer.hpp
index 91365e01695b9a4b577d8863302b9fbed1002a12..211cccd49cabd63b3f874150406b285417a8f72d 100644
--- a/cpp/scope_timer.hpp
+++ b/cpp/scope_timer.hpp
@@ -244,7 +244,7 @@ public:
       omp_init_lock(&m_recordsLock);
     }
 
-    ~EventManager() throw() {
+    ~EventManager() noexcept(false) {
         assert(m_currentEventsStackPerThread[0].size() == 1);
 
         assert(m_currentEventsStackPerThread[0].top().size() == 1);
@@ -416,7 +416,7 @@ public:
         std::vector<SerializedEvent> myEvents;
         myEvents.reserve(m_records.size());
 
-        for(const std::pair<std::string, const CoreEvent*>& event : m_records){
+        for(const std::pair<const std::string, CoreEvent*>& event : m_records){
             myEvents.emplace_back();
             SerializedEvent& current_event = myEvents.back();
 
diff --git a/cpp/spectrum_function.hpp b/cpp/spectrum_function.hpp
index fcc729ff4763f2a417b8da20a4e5dc0aab31110d..7be4474c0a6151e4eed81248140ad95fc2cdec51 100644
--- a/cpp/spectrum_function.hpp
+++ b/cpp/spectrum_function.hpp
@@ -1,3 +1,6 @@
+#ifndef SPECTRUM_FUNCTION_CPP
+#define SPECTRUM_FUNCTION_CPP
+
 #include<cmath>
 #include<vector>
 
@@ -20,7 +23,7 @@ class spectrum_function
         {
             assert(this->values.size() == this->kk->nshells);
         }
-        ~spectrum_function(){}
+        ~spectrum_function() noexcept(false){}
 
         double operator()(double kvalue)
         {
@@ -30,3 +33,6 @@ class spectrum_function
             return this->values[index];
         }
 };
+
+#endif//SPECTRUM_FUNCTION_CPP
+
diff --git a/cpp/vorticity_equation.hpp b/cpp/vorticity_equation.hpp
index 8bf2ea8ef61d8f022b2e70280bac8916e514dee9..32c6547b9781d23bf180d2b28a13d5cfdcd4e69a 100644
--- a/cpp/vorticity_equation.hpp
+++ b/cpp/vorticity_equation.hpp
@@ -22,6 +22,11 @@
 *                                                                     *
 **********************************************************************/
 
+
+
+#ifndef VORTICITY_EQUATION
+#define VORTICITY_EQUATION
+
 #include <sys/stat.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -29,10 +34,6 @@
 
 #include "field.hpp"
 
-#ifndef VORTICITY_EQUATION
-
-#define VORTICITY_EQUATION
-
 extern int myrank, nprocs;
 
 
@@ -87,7 +88,7 @@ class vorticity_equation
                 double DKY = 1.0,
                 double DKZ = 1.0,
                 unsigned FFTW_PLAN_RIGOR = FFTW_MEASURE);
-        virtual ~vorticity_equation(void);
+        virtual ~vorticity_equation(void) noexcept(false);
 
         /* solver essential methods */
         virtual void omega_nonlin(int src);
diff --git a/setup.py.in b/setup.py.in
index 28eb48704653c4ec6ba90792f86a2c570bc4562a..1dd8a24eac4b11b30300391ee88363a883b4dce8 100644
--- a/setup.py.in
+++ b/setup.py.in
@@ -48,7 +48,8 @@ setup(
                 'turtle.test_particles = TurTLE.test.test_particles:main',
                 'turtle.test_Parseval = TurTLE.test.test_Parseval:main',
                 'turtle.test_fftw = TurTLE.test.test_fftw:main',
-                'turtle.test_Heun_p2p = TurTLE.test.test_Heun_p2p:main'],
+                'turtle.test_Heun_p2p = TurTLE.test.test_Heun_p2p:main',
+                'turtle.test_particle_deleter = TurTLE.test.test_particle_deleter:main'],
             },
         version = VERSION,
 ########################################################################