diff --git a/bfps/NavierStokes.py b/bfps/NavierStokes.py
index 33a820330795e907b6a6fff574d04c3a0c5acdd7..7f82de445391d8628e69bd4177f2ca201cda5779 100644
--- a/bfps/NavierStokes.py
+++ b/bfps/NavierStokes.py
@@ -24,6 +24,7 @@
 
 
 
+import sys
 import os
 import numpy as np
 import h5py
@@ -74,7 +75,6 @@ class NavierStokes(_fluid_particle_base):
         self.parameters['max_R_estimate'] = 1.0
         self.file_datasets_grow = """
                 //begincpp
-                std::string temp_string;
                 hsize_t dims[4];
                 hid_t group;
                 hid_t Cspace, Cdset;
@@ -338,6 +338,7 @@ class NavierStokes(_fluid_particle_base):
         self.fluid_includes += '#include <cstring>\n'
         self.fluid_variables += ('fluid_solver<{0}> *fs;\n'.format(self.C_dtype) +
                                  'int *kindices;\n' +
+                                 'hid_t particle_file;\n' +
                                  'hid_t H5T_field_complex;\n')
         self.fluid_definitions += """
                     typedef struct {{
@@ -373,6 +374,15 @@ class NavierStokes(_fluid_particle_base):
                     H5Tinsert(H5T_field_complex, "r", HOFFSET(tmp_complex_type, re), {2});
                     H5Tinsert(H5T_field_complex, "i", HOFFSET(tmp_complex_type, im), {2});
                 }}
+                if (myrank == 0)
+                {{
+                    // set caching parameters
+                    hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
+                    herr_t cache_err = H5Pset_cache(fapl, 0, 521, 134217728, 1.0);
+                    DEBUG_MSG("when setting cache for particles I got %d\\n", cache_err);
+                    sprintf(fname, "%s_particles.h5", simname);
+                    particle_file = H5Fopen(fname, H5F_ACC_RDWR, fapl);
+                }}
                 //endcpp
                 """.format(self.C_dtype, self.fftw_plan_rigor, field_H5T)
         if not self.frozen_fields:
@@ -480,10 +490,8 @@ class NavierStokes(_fluid_particle_base):
             self.parameters['tracers{0}_integration_steps'.format(s0 + s)] = integration_steps[s]
             self.file_datasets_grow += """
                         //begincpp
-                        temp_string = (std::string("/particles/") +
-                                       std::string(ps{0}->name));
-                        group = H5Gopen(stat_file, temp_string.c_str(), H5P_DEFAULT);
-                        grow_particle_datasets(group, temp_string.c_str(), NULL, NULL);
+                        group = H5Gopen(particle_file, ps{0}->name, H5P_DEFAULT);
+                        grow_particle_datasets(group, "", NULL, NULL);
                         H5Gclose(group);
                         //endcpp
                         """.format(s0 + s)
@@ -515,40 +523,13 @@ class NavierStokes(_fluid_particle_base):
                     {0}->field = {1};
                     ps{2}->sample_vec_field({0}, acceleration);
                     """.format(interpolator[s], acc_name, s0 + s)
-            output_vel_acc += """
-                if (myrank == 0)
-                {{
-                //VELOCITY begin
-                std::string temp_string = (std::string("/particles/") +
-                                           std::string(ps{0}->name) +
-                                           std::string("/velocity"));
-                hid_t Cdset = H5Dopen(stat_file, temp_string.c_str(), H5P_DEFAULT);
-                hid_t mspace, wspace;
-                int ndims;
-                hsize_t count[3], offset[3];
-                wspace = H5Dget_space(Cdset);
-                ndims = H5Sget_simple_extent_dims(wspace, count, NULL);
-                count[0] = 1;
-                offset[0] = ps{0}->iteration / ps{0}->traj_skip;
-                offset[1] = 0;
-                offset[2] = 0;
-                mspace = H5Screate_simple(ndims, count, NULL);
-                H5Sselect_hyperslab(wspace, H5S_SELECT_SET, offset, NULL, count, NULL);
-                H5Dwrite(Cdset, H5T_NATIVE_DOUBLE, mspace, wspace, H5P_DEFAULT, velocity);
-                H5Dclose(Cdset);
-                //VELOCITY end\n""".format(s0 + s)
+            output_vel_acc += (
+                    'if (myrank == 0)\n' +
+                    '{\n' +
+                    'ps{0}->write(particle_file, "velocity", velocity);\n'.format(s0 + s))
             if not type(acc_name) == type(None):
-                output_vel_acc += """
-                    //ACCELERATION begin
-                    temp_string = (std::string("/particles/") +
-                                   std::string(ps{0}->name) +
-                                   std::string("/acceleration"));
-                    Cdset = H5Dopen(stat_file, temp_string.c_str(), H5P_DEFAULT);
-                    H5Dwrite(Cdset, H5T_NATIVE_DOUBLE, mspace, wspace, H5P_DEFAULT, acceleration);
-                    H5Sclose(mspace);
-                    H5Sclose(wspace);
-                    H5Dclose(Cdset);
-                    //ACCELERATION end\n""".format(s0 + s)
+                output_vel_acc += (
+                        'ps{0}->write(particle_file, "acceleration", acceleration);\n'.format(s0 + s))
             output_vel_acc += '}\n'
         output_vel_acc += 'delete[] velocity;\n'
         if not type(acc_name) == type(None):
@@ -570,7 +551,7 @@ class NavierStokes(_fluid_particle_base):
         for s in range(nspecies):
             neighbours = self.parameters[interpolator[s] + '_neighbours']
             self.particle_start += 'sprintf(fname, "tracers{0}");\n'.format(s0 + s)
-            self.particle_end += ('ps{0}->write(stat_file);\n' +
+            self.particle_end += ('ps{0}->write(particle_file);\n' +
                                   'delete ps{0};\n').format(s0 + s)
             self.particle_variables += 'rFFTW_particles<VELOCITY_TRACER, {0}, {1}> *ps{2};\n'.format(
                     self.C_dtype,
@@ -586,7 +567,7 @@ class NavierStokes(_fluid_particle_base):
                                             interpolator[s])
             self.particle_start += ('ps{0}->dt = dt;\n' +
                                     'ps{0}->iteration = iteration;\n' +
-                                    'ps{0}->read(stat_file);\n').format(s0 + s)
+                                    'ps{0}->read(particle_file);\n').format(s0 + s)
             if not frozen_particles:
                 if type(kcut) == list:
                     update_field = ('fs->low_pass_Fourier(fs->cvelocity, 3, {0});\n'.format(kcut[s]) +
@@ -594,8 +575,7 @@ class NavierStokes(_fluid_particle_base):
                     self.particle_loop += update_field
                 self.particle_loop += '{0}->field = fs->rvelocity;\n'.format(interpolator[s])
                 self.particle_loop += 'ps{0}->step();\n'.format(s0 + s)
-            self.particle_stat_src += 'ps{0}->write(stat_file, false);\n'.format(s0 + s)
-        self.particle_start += output_vel_acc
+            self.particle_stat_src += 'ps{0}->write(particle_file, false);\n'.format(s0 + s)
         self.particle_stat_src += output_vel_acc
         self.particle_stat_src += '}\n'
         self.particle_species += nspecies
@@ -604,6 +584,10 @@ class NavierStokes(_fluid_particle_base):
         return os.path.join(self.work_dir, self.simname + '.h5')
     def get_data_file(self):
         return h5py.File(self.get_data_file_name(), 'r')
+    def get_particle_file_name(self):
+        return os.path.join(self.work_dir, self.simname + '_particles.h5')
+    def get_particle_file(self):
+        return h5py.File(self.get_particle_file_name(), 'r')
     def get_postprocess_file_name(self):
         return os.path.join(self.work_dir, self.simname + '_postprocess.h5')
     def get_postprocess_file(self):
@@ -627,11 +611,6 @@ class NavierStokes(_fluid_particle_base):
             self.statistics['kshell'] = data_file['kspace/kshell'].value
             self.statistics['kM'] = data_file['kspace/kM'].value
             self.statistics['dk'] = data_file['kspace/dk'].value
-            if self.particle_species > 0:
-                self.trajectories = [data_file['particles/' + key + '/state'][
-                                        iter0//self.parameters['niter_part'] :
-                                        iter1//self.parameters['niter_part']+1]
-                                     for key in data_file['particles'].keys()]
             computation_needed = True
             pp_file = h5py.File(self.get_postprocess_file_name(), 'a')
             if 'ii0' in pp_file.keys():
@@ -746,7 +725,7 @@ class NavierStokes(_fluid_particle_base):
                          3))
     def write_par(self, iter0 = 0):
         _fluid_particle_base.write_par(self, iter0 = iter0)
-        with h5py.File(os.path.join(self.work_dir, self.simname + '.h5'), 'r+') as ofile:
+        with h5py.File(self.get_data_file_name(), 'r+') as ofile:
             kspace = self.get_kspace()
             nshells = kspace['nshell'].shape[0]
             for k in ['velocity', 'vorticity']:
@@ -788,44 +767,6 @@ class NavierStokes(_fluid_particle_base):
                                                  4),
                                      dtype = np.int64,
                                      compression = 'gzip')
-            for s in range(self.particle_species):
-                time_chunk = 2**20 // (8*3*
-                                       self.parameters['nparticles']*
-                                       self.parameters['tracers{0}_integration_steps'.format(s)])
-                time_chunk = max(time_chunk, 1)
-                ofile.create_dataset('particles/tracers{0}/rhs'.format(s),
-                                     (1,
-                                      self.parameters['tracers{0}_integration_steps'.format(s)],
-                                      self.parameters['nparticles'],
-                                      3),
-                                     maxshape = (None,
-                                                 self.parameters['tracers{0}_integration_steps'.format(s)],
-                                                 self.parameters['nparticles'],
-                                                 3),
-                                     chunks =  (time_chunk,
-                                                self.parameters['tracers{0}_integration_steps'.format(s)],
-                                                self.parameters['nparticles'],
-                                                3),
-                                     dtype = np.float64)
-                time_chunk = 2**20 // (8*3*self.parameters['nparticles'])
-                time_chunk = max(time_chunk, 1)
-                ofile.create_dataset(
-                    '/particles/tracers{0}/velocity'.format(s),
-                    (1,
-                     self.parameters['nparticles'],
-                     3),
-                    chunks = (time_chunk, self.parameters['nparticles'], 3),
-                    maxshape = (None, self.parameters['nparticles'], 3),
-                    dtype = np.float64)
-                if self.parameters['tracers{0}_acc_on'.format(s)]:
-                    ofile.create_dataset(
-                        '/particles/tracers{0}/acceleration'.format(s),
-                        (1,
-                         self.parameters['nparticles'],
-                         3),
-                        chunks = (time_chunk, self.parameters['nparticles'], 3),
-                        maxshape = (None, self.parameters['nparticles'], 3),
-                        dtype = np.float64)
             if self.QR_stats_on:
                 time_chunk = 2**20//(8*3*self.parameters['histogram_bins'])
                 time_chunk = max(time_chunk, 1)
@@ -888,6 +829,80 @@ class NavierStokes(_fluid_particle_base):
                                                  self.parameters['QR2D_histogram_bins']),
                                      dtype = np.int64,
                                      compression = 'gzip')
+        if self.particle_species == 0:
+            return None
+        def create_particle_dataset(
+                data_file,
+                dset_name,
+                dset_shape,
+                dset_maxshape,
+                dset_chunks,
+                # maybe something more general can be used here
+                dset_dtype = h5py.h5t.IEEE_F64LE):
+            # create the dataspace.
+            space_id = h5py.h5s.create_simple(
+                    dset_shape,
+                    dset_maxshape)
+            # create the dataset creation property list.
+            dcpl = h5py.h5p.create(h5py.h5p.DATASET_CREATE)
+            # set the allocation time to "early".
+            dcpl.set_alloc_time(h5py.h5d.ALLOC_TIME_EARLY)
+            dcpl.set_chunk(dset_chunks)
+            # and now create dataset
+            if sys.version_info[0] == 3:
+                dset_name = dset_name.encode()
+            return h5py.h5d.create(
+                    data_file.id,
+                    dset_name,
+                    dset_dtype,
+                    space_id,
+                    dcpl,
+                    h5py.h5p.DEFAULT)
+
+        with h5py.File(self.get_particle_file_name(), 'a') as ofile:
+            for s in range(self.particle_species):
+                ofile.create_group('tracers{0}'.format(s))
+                time_chunk = 2**20 // (8*3*
+                                       self.parameters['nparticles']*
+                                       self.parameters['tracers{0}_integration_steps'.format(s)])
+                time_chunk = max(time_chunk, 1)
+                dims = (1,
+                        self.parameters['tracers{0}_integration_steps'.format(s)],
+                        self.parameters['nparticles'],
+                        3)
+                maxshape = (h5py.h5s.UNLIMITED,
+                            self.parameters['tracers{0}_integration_steps'.format(s)],
+                            self.parameters['nparticles'],
+                            3)
+                chunks = (time_chunk,
+                          self.parameters['tracers{0}_integration_steps'.format(s)],
+                          self.parameters['nparticles'],
+                          3)
+                create_particle_dataset(
+                        ofile,
+                        '/tracers{0}/rhs'.format(s),
+                        dims, maxshape, chunks)
+                time_chunk = 2**20 // (8*3*self.parameters['nparticles'])
+                time_chunk = max(time_chunk, 1)
+                create_particle_dataset(
+                        ofile,
+                        '/tracers{0}/state'.format(s),
+                        (1, self.parameters['nparticles'], 3),
+                        (h5py.h5s.UNLIMITED, self.parameters['nparticles'], 3),
+                        (time_chunk, self.parameters['nparticles'], 3))
+                create_particle_dataset(
+                        ofile,
+                        '/tracers{0}/velocity'.format(s),
+                        (1, self.parameters['nparticles'], 3),
+                        (h5py.h5s.UNLIMITED, self.parameters['nparticles'], 3),
+                        (time_chunk, self.parameters['nparticles'], 3))
+                if self.parameters['tracers{0}_acc_on'.format(s)]:
+                    create_particle_dataset(
+                            ofile,
+                            '/tracers{0}/acceleration'.format(s),
+                            (1, self.parameters['nparticles'], 3),
+                            (h5py.h5s.UNLIMITED, self.parameters['nparticles'], 3),
+                            (time_chunk, self.parameters['nparticles'], 3))
         return None
     def add_particle_fields(
             self,
diff --git a/bfps/_code.py b/bfps/_code.py
index 3589689cebd20104dd5bc034ecd6bcba63a2df97..80f1fdf4c5f5b3b7e78d4b4d107b096b0050da86 100644
--- a/bfps/_code.py
+++ b/bfps/_code.py
@@ -93,7 +93,13 @@ class _code(_base):
                     read_parameters(parameter_file);
                     H5Fclose(parameter_file);
                     if (myrank == 0)
-                        stat_file = H5Fopen(fname, H5F_ACC_RDWR, H5P_DEFAULT);
+                    {
+                        // set caching parameters
+                        hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
+                        herr_t cache_err = H5Pset_cache(fapl, 0, 521, 134217728, 1.0);
+                        DEBUG_MSG("when setting stat_file cache I got %d\\n", cache_err);
+                        stat_file = H5Fopen(fname, H5F_ACC_RDWR, fapl);
+                    }
                 //endcpp
                 """
         for ostream in ['cout', 'cerr']:
@@ -107,6 +113,7 @@ class _code(_base):
                         H5Dwrite(Cdset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &iteration);
                         H5Dclose(Cdset);
                         H5Fclose(stat_file);
+                        H5Fclose(particle_file);
                     }
                     fftwf_mpi_cleanup();
                     fftw_mpi_cleanup();
diff --git a/bfps/_fluid_base.py b/bfps/_fluid_base.py
index 0e407098d746ae964f2e6138468f2e3774859169..aece581924900cf9b01548c8305eb852c2529815 100644
--- a/bfps/_fluid_base.py
+++ b/bfps/_fluid_base.py
@@ -117,17 +117,15 @@ class _fluid_particle_base(_code):
                              'H5Dclose(dset);\n}\n' +
                              'return 0;\n}\n')
         self.definitions += ('herr_t grow_particle_datasets(hid_t g_id, const char *name, const H5L_info_t *info, void *op_data)\n{\n' +
-                             'std::string full_name;\n' +
                              'hsize_t dset;\n')
         for key in ['state', 'velocity', 'acceleration']:
-            self.definitions += ('full_name = (std::string(name) + std::string("/{0}"));\n'.format(key) +
-                                 'if (H5Lexists(g_id, full_name.c_str(), H5P_DEFAULT))\n{\n' +
-                                 'dset = H5Dopen(g_id, full_name.c_str(), H5P_DEFAULT);\n' +
+            self.definitions += ('if (H5Lexists(g_id, "{0}", H5P_DEFAULT))\n'.format(key) +
+                                 '{\n' +
+                                 'dset = H5Dopen(g_id, "{0}", H5P_DEFAULT);\n'.format(key) +
                                  'grow_single_dataset(dset, niter_todo/niter_part);\n' +
                                  'H5Dclose(dset);\n}\n')
-        self.definitions += ('full_name = (std::string(name) + std::string("/rhs"));\n' +
-                             'if (H5Lexists(g_id, full_name.c_str(), H5P_DEFAULT))\n{\n' +
-                             'dset = H5Dopen(g_id, full_name.c_str(), H5P_DEFAULT);\n' +
+        self.definitions += ('if (H5Lexists(g_id, "rhs", H5P_DEFAULT))\n{\n' +
+                             'dset = H5Dopen(g_id, "rhs", H5P_DEFAULT);\n' +
                              'grow_single_dataset(dset, 1);\n' +
                              'H5Dclose(dset);\n}\n' +
                              'return 0;\n}\n')
@@ -206,6 +204,7 @@ class _fluid_particle_base(_code):
         self.main       += '}\n'
         self.main       += 'do_stats();\n'
         self.main       += 'do_particle_stats();\n'
+        self.main       += output_time_difference
         if self.particle_species > 0:
             self.main   += self.particle_end
         self.main       += self.fluid_end
@@ -328,19 +327,8 @@ class _fluid_particle_base(_code):
         if testing:
             #data[0] = np.array([3.26434, 4.24418, 3.12157])
             data[0] = np.array([ 0.72086101,  2.59043666,  6.27501953])
-        with h5py.File(os.path.join(self.work_dir, self.simname + '.h5'), 'r+') as data_file:
-            time_chunk = 2**20 // (8*ncomponents*
-                                   self.parameters['nparticles'])
-            time_chunk = max(time_chunk, 1)
-            dset = data_file.create_dataset(
-                    '/particles/tracers{0}/state'.format(species),
-                    (1,
-                     self.parameters['nparticles'],
-                     ncomponents),
-                    chunks = (time_chunk, self.parameters['nparticles'], ncomponents),
-                    maxshape = (None, self.parameters['nparticles'], ncomponents),
-                    dtype = np.float64)
-            dset[0] = data
+        with h5py.File(self.get_particle_file_name(), 'r+') as data_file:
+            data_file['tracers{0}/state'.format(species)][0] = data
         if write_to_file:
             data.tofile(
                     os.path.join(
diff --git a/bfps/cpp/rFFTW_particles.cpp b/bfps/cpp/rFFTW_particles.cpp
index 4cd79c1259940861c1b0a8f07d147bc5a1356250..a71c0574326340dcdd80ee9ca4a29278b62e4a12 100644
--- a/bfps/cpp/rFFTW_particles.cpp
+++ b/bfps/cpp/rFFTW_particles.cpp
@@ -109,7 +109,8 @@ void rFFTW_particles<particle_type, rnumber, interp_neighbours>::roll_rhs()
 
 
 template <int particle_type, class rnumber, int interp_neighbours>
-void rFFTW_particles<particle_type, rnumber, interp_neighbours>::AdamsBashforth(int nsteps)
+void rFFTW_particles<particle_type, rnumber, interp_neighbours>::AdamsBashforth(
+        const int nsteps)
 {
     ptrdiff_t ii;
     this->get_rhs(this->state, this->rhs[0]);
@@ -194,11 +195,12 @@ void rFFTW_particles<particle_type, rnumber, interp_neighbours>::step()
 
 
 template <int particle_type, class rnumber, int interp_neighbours>
-void rFFTW_particles<particle_type, rnumber, interp_neighbours>::read(hid_t data_file_id)
+void rFFTW_particles<particle_type, rnumber, interp_neighbours>::read(
+        const hid_t data_file_id)
 {
     if (this->myrank == 0)
     {
-        std::string temp_string = (std::string("/particles/") +
+        std::string temp_string = (std::string("/") +
                                    std::string(this->name) +
                                    std::string("/state"));
         hid_t dset = H5Dopen(data_file_id, temp_string.c_str(), H5P_DEFAULT);
@@ -218,7 +220,7 @@ void rFFTW_particles<particle_type, rnumber, interp_neighbours>::read(hid_t data
         H5Dclose(dset);
         if (this->iteration > 0)
         {
-            temp_string = (std::string("/particles/") +
+            temp_string = (std::string("/") +
                            std::string(this->name) +
                            std::string("/rhs"));
             dset = H5Dopen(data_file_id, temp_string.c_str(), H5P_DEFAULT);
@@ -257,42 +259,57 @@ void rFFTW_particles<particle_type, rnumber, interp_neighbours>::read(hid_t data
 }
 
 template <int particle_type, class rnumber, int interp_neighbours>
-void rFFTW_particles<particle_type, rnumber, interp_neighbours>::write(hid_t data_file_id, bool write_rhs)
+void rFFTW_particles<particle_type, rnumber, interp_neighbours>::write(
+        const hid_t data_file_id,
+        const char *dset_name,
+        const double *data)
+{
+    std::string temp_string = (std::string(this->name) +
+                               std::string("/") +
+                               std::string(dset_name));
+    hid_t dset = H5Dopen(data_file_id, temp_string.c_str(), H5P_DEFAULT);
+    hid_t mspace, wspace;
+    hsize_t count[3], offset[3];
+    wspace = H5Dget_space(dset);
+    H5Sget_simple_extent_dims(wspace, count, NULL);
+    count[0] = 1;
+    offset[0] = this->iteration / this->traj_skip;
+    offset[1] = 0;
+    offset[2] = 0;
+    mspace = H5Screate_simple(3, count, NULL);
+    H5Sselect_hyperslab(wspace, H5S_SELECT_SET, offset, NULL, count, NULL);
+    H5Dwrite(dset, H5T_NATIVE_DOUBLE, mspace, wspace, H5P_DEFAULT, data);
+    H5Sclose(mspace);
+    H5Sclose(wspace);
+    H5Dclose(dset);
+}
+
+template <int particle_type, class rnumber, int interp_neighbours>
+void rFFTW_particles<particle_type, rnumber, interp_neighbours>::write(
+        const hid_t data_file_id,
+        const bool write_rhs)
 {
     if (this->myrank == 0)
     {
-        std::string temp_string = (std::string("/particles/") +
-                                   std::string(this->name) +
-                                   std::string("/state"));
-        hid_t dset = H5Dopen(data_file_id, temp_string.c_str(), H5P_DEFAULT);
-        hid_t mspace, wspace;
-        hsize_t count[4], offset[4];
-        wspace = H5Dget_space(dset);
-        H5Sget_simple_extent_dims(wspace, count, NULL);
-        count[0] = 1;
-        offset[0] = this->iteration / this->traj_skip;
-        offset[1] = 0;
-        offset[2] = 0;
-        mspace = H5Screate_simple(3, count, NULL);
-        H5Sselect_hyperslab(wspace, H5S_SELECT_SET, offset, NULL, count, NULL);
-        H5Dwrite(dset, H5T_NATIVE_DOUBLE, mspace, wspace, H5P_DEFAULT, this->state);
-        H5Sclose(mspace);
-        H5Sclose(wspace);
-        H5Dclose(dset);
+        this->write(data_file_id, "state", this->state);
         if (write_rhs)
         {
-            temp_string = (std::string("/particles/") +
-                           std::string(this->name) +
-                           std::string("/rhs"));
-            dset = H5Dopen(data_file_id, temp_string.c_str(), H5P_DEFAULT);
-            wspace = H5Dget_space(dset);
+            std::string temp_string = (
+                    std::string("/") +
+                    std::string(this->name) +
+                    std::string("/rhs"));
+            hid_t dset = H5Dopen(data_file_id, temp_string.c_str(), H5P_DEFAULT);
+            hid_t wspace = H5Dget_space(dset);
+            hsize_t count[4], offset[4];
             H5Sget_simple_extent_dims(wspace, count, NULL);
             //writing to last available position
             offset[0] = count[0] - 1;
+            offset[1] = 0;
+            offset[2] = 0;
+            offset[3] = 0;
             count[0] = 1;
             count[1] = 1;
-            offset[3] = 0;
-            mspace = H5Screate_simple(4, count, NULL);
+            hid_t mspace = H5Screate_simple(4, count, NULL);
             for (int i=0; i<this->integration_steps; i++)
             {
                 offset[1] = i;
diff --git a/bfps/cpp/rFFTW_particles.hpp b/bfps/cpp/rFFTW_particles.hpp
index b577da055b77f58703cbf175c8215c6178cd7600..488e6612fbb16f954efcca6b85e30bf74f8375fe 100644
--- a/bfps/cpp/rFFTW_particles.hpp
+++ b/bfps/cpp/rFFTW_particles.hpp
@@ -78,21 +78,26 @@ class rFFTW_particles
                 const int INTEGRATION_STEPS = 2);
         ~rFFTW_particles();
 
-        void get_rhs(double *__restrict__ x, double *__restrict__ rhs);
+        void get_rhs(
+                double *__restrict__ x,
+                double *__restrict__ rhs);
 
-        inline void sample_vec_field(rFFTW_interpolator<rnumber, interp_neighbours> *field, double *vec_values)
+        inline void sample_vec_field(
+                rFFTW_interpolator<rnumber, interp_neighbours> *field,
+                double *vec_values)
         {
             field->sample(this->nparticles, this->ncomponents, this->state, vec_values, NULL);
         }
 
         /* input/output */
-        void read(hid_t data_file_id);
-        void write(hid_t data_file_id, bool write_rhs = true);
+        void read(const hid_t data_file_id);
+        void write(const hid_t data_file_id, const char *dset_name, const double *data);
+        void write(const hid_t data_file_id, const bool write_rhs = true);
 
         /* solvers */
         void step();
         void roll_rhs();
-        void AdamsBashforth(int nsteps);
+        void AdamsBashforth(const int nsteps);
 };
 
 #endif//RFFTW_PARTICLES
diff --git a/bfps/tools.py b/bfps/tools.py
index 0ecfc768f6a972cfb5520b2998bc6eced110e46e..7502468810fd48f7b5f32fa3a51f66f57906ffd8 100644
--- a/bfps/tools.py
+++ b/bfps/tools.py
@@ -198,8 +198,12 @@ def particle_finite_diff_test(
 
     .. seealso:: :func:`get_fornberg_coeffs`
     """
-    d = c.get_data_file()
-    group = d['particles/tracers{0}'.format(species)]
+    df = c.get_data_file()
+    if 'particles' in df.keys():
+        group = df['particles/tracers{0}'.format(species)]
+    else:
+        pf = c.get_particle_file()
+        group = pf['tracers{0}'.format(species)]
     acc_on = 'acceleration' in group.keys()
     pos = group['state'].value
     vel = group['velocity'].value
@@ -207,7 +211,7 @@ def particle_finite_diff_test(
         acc = group['acceleration'].value
     n = m
     fc = get_fornberg_coeffs(0, range(-n, n+1))
-    dt = d['parameters/dt'].value*d['parameters/niter_part'].value
+    dt = c.parameters['dt']*c.parameters['niter_part']
 
     num_vel1 = sum(fc[1, n-i]*pos[1+n-i:pos.shape[0]-i-n-1] for i in range(-n, n+1)) / dt
     if acc_on:
@@ -220,7 +224,7 @@ def particle_finite_diff_test(
         pid = np.argmin(SNR(num_acc1, acc[n+1:-n-1]))
     else:
         pid = np.argmin(SNR(num_vel1, vel[n+1:-n-1]))
-    pars = d['parameters']
+    pars = df['parameters']
     to_print = (
             'steps={0}, interp={1}, neighbours={2}, '.format(
                 pars['tracers{0}_integration_steps'.format(species)].value,
@@ -246,7 +250,6 @@ def particle_finite_diff_test(
 
         for n in range(1, m):
             fc = get_fornberg_coeffs(0, range(-n, n+1))
-            dt = d['parameters/dt'].value*d['parameters/niter_part'].value
 
             num_acc1 = sum(fc[1, n-i]*vel[n-i:vel.shape[0]-i-n] for i in range(-n, n+1)) / dt
             num_acc2 = sum(fc[2, n-i]*pos[n-i:pos.shape[0]-i-n] for i in range(-n, n+1)) / dt**2
diff --git a/documentation/_static/development.rst b/documentation/_static/development.rst
index 446bc1ab765a281f05410939c74e8c08dabaf3e6..423a448946041d4ec0aca77f29a2311e3f0eb177 100644
--- a/documentation/_static/development.rst
+++ b/documentation/_static/development.rst
@@ -57,3 +57,30 @@ Code testing
 ------------
 
 Testing for :mod:`bfps` is done with ``tox``.
+
+----------------
+Work in progress
+----------------
+
+HDF5 field I/O
+--------------
+
+As you can tell from the ``todo.txt`` file, in the future the code will
+use HDF5 for input/output of fields.
+For now, field I/O is done with binary files, and the field data type is
+stored in the parameter file.
+
+HDF5 particle I/O
+-----------------
+
+Particle I/O seems to be very slow, no idea why.
+Relevant links:
+
+    1. http://api.h5py.org/index.html
+    2. https://www.hdfgroup.org/ftp/HDF5/examples/python/hdf5examples-py/low_level/h5ex_d_alloc.py
+
+Code flexibility
+----------------
+
+Version 2.0 will be designed so that new fluid equations can be coded in
+from python classes, rather than as new C++ files.
diff --git a/tests/base.py b/tests/base.py
index 712b5a24b88eb1bb43a3806d75018df52f237790..7b75080a44e12ffbd11243749fbbcd394671731d 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -191,7 +191,8 @@ def compare_stats(
     for i in range(c0.particle_species):
         print('maximum traj difference species {0} is {1}'.format(
             i,
-            np.max(np.abs(c0.trajectories[i] - c1.trajectories[i]))))
+            np.max(np.abs(c0.get_particle_file()['tracers{0}/state'.format(i)][:] -
+                          c1.get_particle_file()['tracers{0}/state'.format(i)][:]))))
     if plots_on:
         # plot energy and enstrophy
         fig = plt.figure(figsize = (12, 12))
diff --git a/tests/test_plain.py b/tests/test_plain.py
index 5d526cfd3412b097068f9ab1b93b2ca86523b34d..ab745d2e3cd4027010e3aab527be6bd477baf4ad 100644
--- a/tests/test_plain.py
+++ b/tests/test_plain.py
@@ -70,7 +70,6 @@ if __name__ == '__main__':
              '--nparticles', '1000',
              '--niter_todo', '48',
              '--precision', 'single',
-             '--multiplejob',
              '--wd', 'data/single'] +
             sys.argv[1:])
     plain(opt)