diff --git a/configure.ac b/configure.ac
index 8202e6c405e97dde2e8a788b2ecfebde0ddc378f..d119cfa3a99c1c85456056eab5d73b334ec86d15 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2382,6 +2382,12 @@ AM_CONDITIONAL([HAVEGRACKLECOOLING], [test "${with_cooling:0:7}" = "grackle"])
 # check if using gear feedback
 AM_CONDITIONAL([HAVEGEARFEEDBACK], [test "$with_feedback" = "GEAR"])
 
+# check if using SPHENIX
+AM_CONDITIONAL([HAVE_SPHENIX], [test "$with_hydro" = "sphenix"])
+
+# check if using GADGET2 SPH
+AM_CONDITIONAL([HAVE_GADGET2], [test "$with_hydro" = "gadget2"])
+
 # Handle .in files.
 AC_CONFIG_FILES([Makefile src/Makefile examples/Makefile examples/Cooling/CoolingRates/Makefile doc/Makefile doc/Doxyfile tests/Makefile])
 AC_CONFIG_FILES([argparse/Makefile tools/Makefile logger/Makefile logger/tests/Makefile])
diff --git a/examples/main.c b/examples/main.c
index 9f59e9d955f955ff0d8fe96b21c24d382e269cbd..1b9c21bdb1e9f9effccd29ece728d7bfb60df3bf 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -1638,8 +1638,13 @@ int main(int argc, char *argv[]) {
       engine_dump_index(&e);
 
       /* Write a sentinel timestamp */
-      logger_log_timestamp(e.logger, e.ti_current, e.time,
-                           &e.logger->timestamp_offset);
+      if (e.policy & engine_policy_cosmology) {
+        logger_log_timestamp(e.logger, e.ti_current, e.cosmology->a,
+                             &e.logger->timestamp_offset);
+      } else {
+        logger_log_timestamp(e.logger, e.ti_current, e.time,
+                             &e.logger->timestamp_offset);
+      }
     }
 #endif
 
diff --git a/logger/Makefile.am b/logger/Makefile.am
index af9c040e9c8fb5dbaf01cb8acf8ec671a2bac8f6..441aaab2a9be434b80b7903e290ff3535f1c0cf6 100644
--- a/logger/Makefile.am
+++ b/logger/Makefile.am
@@ -45,14 +45,20 @@ lib_LTLIBRARIES = liblogger.la
 
 GRAVITY_SRC = gravity/MultiSoftening/logger_gravity.c
 STARS_SRC = stars/Default/logger_stars.c
+
+if HAVE_SPHENIX
+HYDRO_SRC = hydro/SPHENIX/logger_hydro.c
+endif
+if HAVE_GADGET2
 HYDRO_SRC = hydro/Gadget2/logger_hydro.c
+endif
 
 # subdirectories
 SUBDIRS = tests
 
 # List required headers
 include_HEADERS = logger_header.h logger_loader_io.h logger_particle.h logger_time.h logger_tools.h logger_reader.h \
-	logger_logfile.h logger_index.h quick_sort.h logger_python_tools.h
+	logger_logfile.h logger_index.h quick_sort.h logger_python_tools.h logger_interpolation.h
 
 # Common source files
 AM_SOURCES = logger_header.c logger_loader_io.c logger_particle.c logger_time.c logger_tools.c logger_reader.c \
@@ -70,7 +76,8 @@ endif
 # Include files for distribution, not installation.
 nobase_noinst_HEADERS = logger_hydro.h hydro/Gadget2/logger_hydro.h \
 	logger_stars.h stars/Default/logger_stars.h \
-	logger_gravity.h gravity/MultiSoftening/logger_gravity.h
+	logger_gravity.h gravity/MultiSoftening/logger_gravity.h \
+  hydro/SPHENIX/logger_hydro.h
 
 # Sources and flags for regular library
 liblogger_la_SOURCES = $(AM_SOURCES)
diff --git a/logger/examples/reader_example.py b/logger/examples/reader_example.py
index 6fe65399cc70de43b6638820c19f41486ee2d9df..e3518cf61914ba6916075433c90b1f0877f0e4f8 100644
--- a/logger/examples/reader_example.py
+++ b/logger/examples/reader_example.py
@@ -6,12 +6,31 @@ Example: ./reader_example.py ../../examples/SedovBlast_3D/index 0.1
 import sys
 import numpy as np
 import matplotlib.pyplot as plt
+from glob import glob
 from mpl_toolkits.mplot3d import Axes3D
+import argparse
 sys.path.append("../.libs/")
 
 import liblogger as logger
 
 
+def parse_arguments():
+    parser = argparse.ArgumentParser(
+        description='Read a logfile and plots some basic properties')
+
+    default_files = "../../examples/HydroTests/SedovBlast_3D/index_*dump"
+    default_files = glob(default_files)
+
+    parser.add_argument("-t", '--time', dest='time',
+                        type=float, default=0.01,
+                        help='Simulation time')
+    parser.add_argument('files', metavar='filenames', type=str, nargs="*",
+                        help='The filenames of the logfiles')
+    args = parser.parse_args()
+    if len(args.files) == 0:
+        args.files = default_files
+    return args
+
 def plot3D(pos):
     fig = plt.figure()
     ax = fig.add_subplot(111, projection="3d")
@@ -31,36 +50,34 @@ def plot2D(pos, entropies):
     plt.ylabel("Entropy")
 
 
-basename = "../../examples/HydroTests/SedovBlast_3D/index_0000"
-time = 0.03
-if len(sys.argv) >= 2:
-    basename = sys.argv[1]
-else:
-    print("No basename supplied (first argument), using default.")
-if len(sys.argv) >= 3:
-    time = float(sys.argv[2])
-else:
-    print("No time supplied (second argument), using default.")
-if len(sys.argv) > 3:
-    print("Ignoring excess arguments '%s'." % sys.argv[3:])
-print("basename: %s" % basename)
-print("time: %g" % time)
+args = parse_arguments()
+print("basename: %s" % args.files)
+print("time: %g" % args.time)
 
 # read the logger
-gas_type = 0
-with logger.Reader(basename, verbose=0) as reader:
-    t = reader.get_time_limits()
-
-    fields = reader.get_list_fields(gas_type)
-    if ("Coordinates" not in fields or
-        "Entropies" not in fields):
-        raise Exception("Field not found in the logfile")
-
-    pos, ent = reader.get_particle_data(
-        ["Coordinates", "Entropies"], time, gas_type)
-
-print("Min/Max of the position:", pos.min(), pos.max())
-print("Min/Max of the entropy:", ent.min(), ent.max())
-plot3D(pos)
-plot2D(pos, ent)
+positions = np.empty((0, 3))
+entropies = np.empty(0)
+for f in args.files:
+    if f.endswith(".dump"):
+        filename = f[:-5]
+    else:
+        raise Exception("It seems that you are not providing a logfile (.dump)")
+    with logger.Reader(filename, verbose=0) as reader:
+        t = reader.get_time_limits()
+        out = reader.get_particle_data(
+            ["Coordinates", "Entropies"], args.time)
+
+        fields = reader.get_list_fields(gas_type)
+        if ("Coordinates" not in fields or
+            "Entropies" not in fields):
+            raise Exception("Field not found in the logfile")
+
+        # add the data to the list
+        positions = np.append(positions, out[0], axis=0)
+        entropies = np.append(entropies, out[1], axis=0)
+
+print("Min/Max of the position:", positions.min(), positions.max())
+print("Min/Max of the entropy:", entropies.min(), entropies.max())
+plot3D(positions)
+plot2D(positions, entropies)
 plt.show()
diff --git a/logger/gravity/MultiSoftening/logger_gravity.h b/logger/gravity/MultiSoftening/logger_gravity.h
index e89acb9afadda60a8c4d42620c0b67ad09340dd0..c5cfcdc07e476f8c04191fe139b446ed281fd107 100644
--- a/logger/gravity/MultiSoftening/logger_gravity.h
+++ b/logger/gravity/MultiSoftening/logger_gravity.h
@@ -23,6 +23,7 @@
 
 /* local includes */
 #include "gravity_logger.h"
+#include "logger_interpolation.h"
 #include "logger_loader_io.h"
 #include "logger_python_tools.h"
 
@@ -90,77 +91,24 @@ gravity_logger_interpolate_field(const double t_before,
   }
 #endif
 
-  /* Compute the interpolation scaling. */
-  const double wa = (t - t_before) / (t_after - t_before);
-  const double wb = 1. - wa;
-
   switch (field) {
     case gravity_logger_field_coordinates:
-      for (int i = 0; i < 3; i++) {
-        double *x = (double *)output;
-        const double *x_bef = (double *)before->field;
-        const float *v_bef = (float *)before->first_deriv;
-        const float *a_bef = (float *)before->second_deriv;
-
-        const double *x_aft = (double *)after->field;
-        const float *v_aft = (float *)after->first_deriv;
-        const float *a_aft = (float *)after->second_deriv;
-
-        /* Use quintic hermite spline. */
-        if (v_bef && v_aft && a_bef && a_aft) {
-          x[i] = logger_tools_quintic_hermite_spline(
-              t_before, x_bef[i], v_bef[i], a_bef[i], t_after, x_aft[i],
-              v_aft[i], a_aft[i], t);
-        }
-        /* Use cubic hermite spline. */
-        else if (v_bef && v_aft) {
-          x[i] = logger_tools_cubic_hermite_spline(
-              t_before, x_bef[i], v_bef[i], t_after, x_aft[i], v_aft[i], t);
-        }
-        /* Use linear interpolation. */
-        else {
-          x[i] = wa * x_aft[i] + wb * x_bef[i];
-        }
-      }
+      interpolate_quintic_double_float_ND(t_before, before, t_after, after,
+                                          output, t, /* dimension= */ 3);
       break;
     case gravity_logger_field_velocities:
-      for (int i = 0; i < 3; i++) {
-        float *v = (float *)output;
-        const float *v_bef = (float *)before->field;
-        const float *a_bef = (float *)before->first_deriv;
-
-        const float *v_aft = (float *)after->field;
-        const float *a_aft = (float *)after->first_deriv;
-
-        /* Use a cubic hermite spline. */
-        if (a_bef && a_aft) {
-          v[i] = logger_tools_cubic_hermite_spline(
-              t_before, v_bef[i], a_bef[i], t_after, v_aft[i], a_aft[i], t);
-        }
-        /* Use linear interpolation. */
-        else {
-          v[i] = wa * v_aft[i] + wb * v_bef[i];
-        }
-      }
+      interpolate_cubic_float_ND(t_before, before, t_after, after, output, t,
+                                 /* dimension= */ 3);
       break;
     case gravity_logger_field_accelerations:
-      /* interpolate vectors. */
-      for (int i = 0; i < 3; i++) {
-        float *a = (float *)output;
-        const float *a_bef = (float *)before->field;
-        const float *a_aft = (float *)after->field;
-        a[i] = wa * a_aft[i] + wb * a_bef[i];
-      }
+      interpolate_linear_float_ND(t_before, before, t_after, after, output, t,
+                                  /* dimension= */ 3);
       break;
     case gravity_logger_field_masses:
-      ((float *)output)[0] =
-          wa * ((float *)after->field)[0] + wb * ((float *)before->field)[0];
+      interpolate_linear_float(t_before, before, t_after, after, output, t);
       break;
     case gravity_logger_field_particle_ids:
-      if (*(long long *)after->field != *(long long *)before->field) {
-        error("Interpolating different particles");
-      }
-      *(long long *)output = *(long long *)after->field;
+      interpolate_ids(t_before, before, t_after, after, output, t);
       break;
     default:
       error("Not implemented");
diff --git a/logger/hydro/Gadget2/logger_hydro.c b/logger/hydro/Gadget2/logger_hydro.c
index 57c8cb35c9d46a14bc296a764fe7520abf173e46..9f252c4152179da33dc4c477db54e8c81bc00e41 100644
--- a/logger/hydro/Gadget2/logger_hydro.c
+++ b/logger/hydro/Gadget2/logger_hydro.c
@@ -19,6 +19,8 @@
 
 #include "logger_hydro.h"
 
+#include "config.h"
+
 int hydro_logger_local_to_global[hydro_logger_field_count];
 /* Define the size of all the fields. */
 #define member_size(type, member) sizeof(((type *)0)->member)
diff --git a/logger/hydro/Gadget2/logger_hydro.h b/logger/hydro/Gadget2/logger_hydro.h
index 96431e35735c88186c6aad1692f675f03814989c..affa61e8ec7bb6491f99ffdb134a0fa3bd0bf84e 100644
--- a/logger/hydro/Gadget2/logger_hydro.h
+++ b/logger/hydro/Gadget2/logger_hydro.h
@@ -23,6 +23,7 @@
 
 /* local includes */
 #include "hydro_logger.h"
+#include "logger_interpolation.h"
 #include "logger_loader_io.h"
 #include "logger_python_tools.h"
 
@@ -90,84 +91,31 @@ hydro_logger_interpolate_field(const double t_before,
   }
 #endif
 
-  /* Compute the interpolation scaling. */
-  const double wa = (t - t_before) / (t_after - t_before);
-  const double wb = 1. - wa;
-
   switch (field) {
     /* Do the position */
     case hydro_logger_field_coordinates:
-      for (int i = 0; i < 3; i++) {
-        double *x = (double *)output;
-        const double *x_bef = (double *)before->field;
-        const float *v_bef = (float *)before->first_deriv;
-        const float *a_bef = (float *)before->second_deriv;
-
-        const double *x_aft = (double *)after->field;
-        const float *v_aft = (float *)after->first_deriv;
-        const float *a_aft = (float *)after->second_deriv;
-
-        /* Use quintic hermite spline. */
-        if (v_bef && v_aft && a_bef && a_aft) {
-          x[i] = logger_tools_quintic_hermite_spline(
-              t_before, x_bef[i], v_bef[i], a_bef[i], t_after, x_aft[i],
-              v_aft[i], a_aft[i], t);
-        }
-        /* Use cubic hermite spline. */
-        else if (v_bef && v_aft) {
-          x[i] = logger_tools_cubic_hermite_spline(
-              t_before, x_bef[i], v_bef[i], t_after, x_aft[i], v_aft[i], t);
-        }
-        /* Use linear interpolation. */
-        else {
-          x[i] = wa * x_aft[i] + wb * x_bef[i];
-        }
-      }
+      interpolate_quintic_double_float_ND(t_before, before, t_after, after,
+                                          output, t, /* dimesion= */ 3);
       break;
       /* Do the velocity */
     case hydro_logger_field_velocities:
-      for (int i = 0; i < 3; i++) {
-        float *v = (float *)output;
-        const float *v_bef = (float *)before->field;
-        const float *a_bef = (float *)before->first_deriv;
-
-        const float *v_aft = (float *)after->field;
-        const float *a_aft = (float *)after->first_deriv;
-
-        /* Use a cubic hermite spline. */
-        if (a_bef && a_aft) {
-          v[i] = logger_tools_cubic_hermite_spline(
-              t_before, v_bef[i], a_bef[i], t_after, v_aft[i], a_aft[i], t);
-        }
-        /* Use linear interpolation. */
-        else {
-          v[i] = wa * v_aft[i] + wb * v_bef[i];
-        }
-      }
+      interpolate_cubic_float_ND(t_before, before, t_after, after, output, t,
+                                 /* dimesion= */ 3);
       break;
     case hydro_logger_field_accelerations:
-      /* interpolate vectors. */
-      for (int i = 0; i < 3; i++) {
-        float *a = (float *)output;
-        const float *a_bef = (float *)before->field;
-        const float *a_aft = (float *)after->field;
-        a[i] = wa * a_aft[i] + wb * a_bef[i];
-      }
+      interpolate_linear_float_ND(t_before, before, t_after, after, output, t,
+                                  /* dimesion= */ 3);
       break;
       /* Do the linear interpolation of float. */
     case hydro_logger_field_smoothing_lengths:
     case hydro_logger_field_entropies:
     case hydro_logger_field_densities:
     case hydro_logger_field_masses:
-      ((float *)output)[0] =
-          wa * ((float *)after->field)[0] + wb * ((float *)before->field)[0];
+      interpolate_linear_float(t_before, before, t_after, after, output, t);
       break;
       /* Check the ids */
     case hydro_logger_field_particle_ids:
-      if (*(long long *)after->field != *(long long *)before->field) {
-        error("Interpolating different particles");
-      }
-      *(long long *)output = *(long long *)after->field;
+      interpolate_ids(t_before, before, t_after, after, output, t);
       break;
     default:
       error("Not implemented");
diff --git a/logger/hydro/SPHENIX/logger_hydro.c b/logger/hydro/SPHENIX/logger_hydro.c
new file mode 100644
index 0000000000000000000000000000000000000000..d129cb51c06e12f2a59214c2c47ddb8b9589b6fc
--- /dev/null
+++ b/logger/hydro/SPHENIX/logger_hydro.c
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "logger_hydro.h"
+
+#include "config.h"
+
+int hydro_logger_local_to_global[hydro_logger_field_count];
+
+/* Define the size of all the fields. */
+#define member_size(type, member) sizeof(((type *)0)->member)
+
+const int hydro_logger_field_size[hydro_logger_field_count] = {
+    member_size(struct part, x),        // coordinates
+    member_size(struct part, v),        // velocities
+    member_size(struct part, a_hydro),  // accelerations
+    member_size(struct part, mass),     // massses
+    member_size(struct part, h),        // Smoothing Length
+    member_size(struct part, u),        // InternalEnergies
+    member_size(struct part, id),       // IDs
+    member_size(struct part, rho),      // density
+    sizeof(float),                      // Entropy
+    sizeof(float),                      // Pressure
+    3 * sizeof(float),                  // Viscosity / diffusion
+    2 * sizeof(float),                  // Velocity divergence + deriv
+};
diff --git a/logger/hydro/SPHENIX/logger_hydro.h b/logger/hydro/SPHENIX/logger_hydro.h
new file mode 100644
index 0000000000000000000000000000000000000000..0565db40a5a6a681460bb2641cb2d540864965cb
--- /dev/null
+++ b/logger/hydro/SPHENIX/logger_hydro.h
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_SPHENIX_LOGGER_HYDRO_H
+#define SWIFT_SPHENIX_LOGGER_HYDRO_H
+
+#include "../config.h"
+
+/* local includes */
+#include "hydro.h"
+#include "hydro_logger.h"
+#include "logger_interpolation.h"
+#include "logger_loader_io.h"
+#include "logger_python_tools.h"
+
+/* Index of the mask in the header mask array */
+extern int hydro_logger_local_to_global[hydro_logger_field_count];
+
+/* Size for each mask */
+extern const int hydro_logger_field_size[hydro_logger_field_count];
+
+/**
+ * @brief Create the link between the fields and their derivatives.
+ *
+ * @param head The #header.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_logger_reader_link_derivatives(struct header *head) {
+
+  /* Set the first and second derivatives */
+  const int pos_id =
+      hydro_logger_local_to_global[hydro_logger_field_coordinates];
+  const int vel_id =
+      hydro_logger_local_to_global[hydro_logger_field_velocities];
+  const int acc_id =
+      hydro_logger_local_to_global[hydro_logger_field_accelerations];
+
+  /* Coordinates */
+  header_set_first_derivative(head, pos_id, vel_id);
+  header_set_second_derivative(head, pos_id, acc_id);
+
+  /* Velocities */
+  header_set_first_derivative(head, vel_id, acc_id);
+}
+
+/**
+ * @brief Interpolate a field of the particle at the given time.
+ * Here we use a linear interpolation for most of the fields.
+ * For the position (velocity), we use a quintic (cubic) hermite interpolation
+ * based on the positions, velocities and accelerations at the time of the two
+ * particles.
+ *
+ * @param before Pointer to the #logger_field at a time < t.
+ * @param after Pointer to the #logger_field at a time > t.
+ * @param otuput Pointer to the output value.
+ * @param t_before Time of field_before (< t).
+ * @param t_after Time of field_after (> t).
+ * @param t Requested time.
+ * @param field The field to reconstruct (follows the order of
+ * #hydro_logger_fields).
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_logger_interpolate_field(const double t_before,
+                               const struct logger_field *restrict before,
+                               const double t_after,
+                               const struct logger_field *restrict after,
+                               void *restrict output, const double t,
+                               const int field) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Check the times */
+  if (t_before > t || t_after < t) {
+    error(
+        "The times for the interpolation are not "
+        "monotonically increasing %g < %g < %g.",
+        t_before, t, t_after);
+  }
+#endif
+
+  switch (field) {
+    /* Do the position */
+    case hydro_logger_field_coordinates:
+      interpolate_quintic_double_float_ND(t_before, before, t_after, after,
+                                          output, t, /* dimension= */ 3);
+      break;
+      /* Do the velocity */
+    case hydro_logger_field_velocities:
+      interpolate_cubic_float_ND(t_before, before, t_after, after, output, t,
+                                 /* dimension= */ 3);
+      break;
+    case hydro_logger_field_accelerations:
+    case hydro_logger_field_viscosity_diffusion:
+      interpolate_linear_float_ND(t_before, before, t_after, after, output, t,
+                                  /* dimension= */ 3);
+      break;
+      /* Do the linear interpolation of float. */
+    case hydro_logger_field_masses:
+    case hydro_logger_field_smoothing_lengths:
+    case hydro_logger_field_internal_energies:
+    case hydro_logger_field_densities:
+    case hydro_logger_field_entropies:
+    case hydro_logger_field_pressures:
+      interpolate_linear_float(t_before, before, t_after, after, output, t);
+      break;
+      /* Check the ids */
+    case hydro_logger_field_particle_ids:
+      interpolate_ids(t_before, before, t_after, after, output, t);
+      break;
+
+    case hydro_logger_field_velocity_divergences: {
+      /* Get some variables */
+      const float wa = (t - t_before) / (t_after - t_before);
+      const float wb = 1. - wa;
+      float *x = (float *)output;
+      const float *div_bef = (float *)before->field;
+      const float *div_aft = (float *)after->field;
+
+      /* Use cubic hermite spline. */
+      x[0] = interpolate_cubic_hermite_spline(
+          t_before, div_bef[0], div_bef[1], t_after, div_aft[0], div_aft[1], t);
+      /* Use the linear interpolation */
+      x[1] = wa * div_aft[1] + wb * div_bef[1];
+      break;
+    }
+
+    default:
+      error("Not implemented");
+  }
+}
+
+#ifdef HAVE_PYTHON
+__attribute__((always_inline)) INLINE static void hydro_logger_generate_python(
+    struct logger_python_field *fields) {
+
+  fields[hydro_logger_field_coordinates] =
+      logger_loader_python_field(/* Dimension */ 3, NPY_DOUBLE);
+  fields[hydro_logger_field_velocities] =
+      logger_loader_python_field(/* Dimension */ 3, NPY_FLOAT32);
+  fields[hydro_logger_field_accelerations] =
+      logger_loader_python_field(/* Dimension */ 3, NPY_FLOAT32);
+  fields[hydro_logger_field_masses] =
+      logger_loader_python_field(/* Dimension */ 1, NPY_FLOAT32);
+  fields[hydro_logger_field_smoothing_lengths] =
+      logger_loader_python_field(/* Dimension */ 1, NPY_FLOAT32);
+  fields[hydro_logger_field_internal_energies] =
+      logger_loader_python_field(/* Dimension */ 1, NPY_FLOAT32);
+  fields[hydro_logger_field_particle_ids] =
+      logger_loader_python_field(/* Dimension */ 1, NPY_LONGLONG);
+  fields[hydro_logger_field_densities] =
+      logger_loader_python_field(/* Dimension */ 1, NPY_FLOAT32);
+  fields[hydro_logger_field_entropies] =
+      logger_loader_python_field(/* Dimension */ 1, NPY_FLOAT32);
+  fields[hydro_logger_field_pressures] =
+      logger_loader_python_field(/* Dimension */ 1, NPY_FLOAT32);
+  fields[hydro_logger_field_viscosity_diffusion] =
+      logger_loader_python_field(/* Dimension */ 3, NPY_FLOAT32);
+  fields[hydro_logger_field_velocity_divergences] =
+      logger_loader_python_field(/* Dimension */ 2, NPY_FLOAT32);
+}
+
+#endif  // HAVE_PYTHON
+#endif  /* SWIFT_SPHENIX_LOGGER_HYDRO_H */
diff --git a/logger/logger_header.c b/logger/logger_header.c
index ec0d1453df757e4f128d637c9f08b8d0e7438f9b..52bc8132f7f0e218299139146ec01223ee024c5d 100644
--- a/logger/logger_header.c
+++ b/logger/logger_header.c
@@ -171,6 +171,11 @@ void header_read(struct header *h, struct logger_logfile *log) {
     map = logger_loader_io_read_data(map, sizeof(unsigned int),
                                      &h->masks[i].size);
 
+    /* Print the information. */
+    if (reader->verbose > 1) {
+      message("Field %s found in the logfile", h->masks[i].name);
+    }
+
     /* Keep the timestamp mask in memory */
     if (strcmp(h->masks[i].name, "Timestamp") == 0) {
       h->timestamp_mask = h->masks[i].mask;
@@ -182,6 +187,16 @@ void header_read(struct header *h, struct logger_logfile *log) {
     error_python("Unable to find the timestamp mask.");
   }
 
+  /* check the special flag. */
+  if (strcmp(h->masks[logger_index_special_flags].name, "SpecialFlags") != 0) {
+    error("The special flag is expected to be at position %i",
+          logger_index_special_flags);
+  }
+
+  if (h->masks[logger_index_special_flags].size != sizeof(uint32_t)) {
+    error("The special flag is expected to be 32 bits");
+  }
+
   /* Check the logfile header's size. */
   if (map != (char *)log->log.map + h->offset_first_record) {
     size_t offset = (char *)map - (char *)log->log.map;
diff --git a/logger/logger_hydro.h b/logger/logger_hydro.h
index f9729c55c4bc1e7b6b85e0977a517a23d80305d3..c012ad5962482c18cffa48d0efbd89a3e8c7710e 100644
--- a/logger/logger_hydro.h
+++ b/logger/logger_hydro.h
@@ -50,7 +50,6 @@
 #error TODO
 #include "./hydro/Planetary/logger_hydro.h"
 #elif defined(SPHENIX_SPH)
-#error TODO
 #include "./hydro/SPHENIX/logger_hydro.h"
 #elif defined(ANARCHY_PU_SPH)
 #error TODO
diff --git a/logger/logger_index.c b/logger/logger_index.c
index a62ff168bea2e21af4bd0998c37c186d020bd49c..50a8545b64a943bbd2446c7a3e16a9bf71abbf7f 100644
--- a/logger/logger_index.c
+++ b/logger/logger_index.c
@@ -72,15 +72,40 @@ void logger_index_read_header(struct logger_index *index,
          (char *)index->index.map + logger_index_integer_time_offset,
          logger_index_integer_time_size);
 
-  /* Read the number of particles */
+  /* Read the number of particles. */
   memcpy(index->nparts, (char *)index->index.map + logger_index_npart_offset,
          logger_index_npart_size);
 
-  /* Read if the file is sorted */
+  /* Read whether the file is sorted. */
   memcpy(&index->is_sorted,
          (char *)index->index.map + logger_index_is_sorted_offset,
          logger_index_is_sorted_size);
 
+  /* Compute the position of the history of new particles. */
+  size_t count = 0;
+  for (int i = 0; i < swift_type_count; i++) {
+    count += index->nparts[i];
+  }
+  count *= sizeof(struct index_data);
+
+  /* Read the number of new particles. */
+  memcpy(&index->nparts_created,
+         (char *)index->index.map + logger_index_data_offset + count,
+         logger_index_npart_size);
+
+  /* Compute the position of the history of particles removed. */
+  size_t count_new = 0;
+  for (int i = 0; i < swift_type_count; i++) {
+    count_new += index->nparts_created[i];
+  }
+  count_new *= sizeof(struct index_data);
+
+  /* Read the number of particles removed. */
+  memcpy(&index->nparts_removed,
+         (char *)index->index.map + logger_index_data_offset + count +
+             logger_index_npart_size + count_new,
+         logger_index_npart_size);
+
   /* Close the file */
   logger_index_free(index);
 }
@@ -104,6 +129,9 @@ void logger_index_write_sorted(struct logger_index *index) {
 /**
  * @brief Get the #index_data of a particle type.
  *
+ * The #index_data contains the ids and offset of the particle.
+ * This function should be used when looking for the last known particles.
+ *
  * @param index The #logger_index.
  * @param type The particle type.
  */
@@ -121,6 +149,60 @@ struct index_data *logger_index_get_data(struct logger_index *index, int type) {
   return (struct index_data *)ret;
 }
 
+/**
+ * @brief Get the #index_data for the particles created.
+ *
+ * The #index_data contains the ids and offset of the particle.
+ * This function should be used when looking for the particles created.
+ *
+ * @param index The #logger_index.
+ * @param type The particle type.
+ */
+struct index_data *logger_index_get_created_history(struct logger_index *index,
+                                                    int type) {
+
+  /* Get the position after the previous array. */
+  char *ret = (char *)logger_index_get_data(index, swift_type_count);
+
+  /* Get the offset of particles of this type by skipping entries of lower
+   * types. */
+  size_t count = 0;
+  for (int i = 0; i < type; i++) {
+    count += index->nparts_created[i];
+  }
+  const size_t type_offset = count * sizeof(struct index_data);
+
+  ret += type_offset + logger_index_npart_size;
+  return (struct index_data *)ret;
+}
+
+/**
+ * @brief Get the #index_data for the particles removed.
+ *
+ * The #index_data contains the ids and offset of the particle.
+ * This function should be used when looking for the particles removed.
+ *
+ * @param index The #logger_index.
+ * @param type The particle type.
+ */
+struct index_data *logger_index_get_removed_history(struct logger_index *index,
+                                                    int type) {
+
+  /* Get the position after the previous array. */
+  char *ret = (char *)logger_index_get_created_history(index, swift_type_count);
+
+  /* Get the offset of particles of this type by skipping entries of lower
+   * types. */
+  size_t count = 0;
+  for (int i = 0; i < type; i++) {
+    count += index->nparts_removed[i];
+  }
+  const size_t type_offset = count * sizeof(struct index_data);
+
+  ret += type_offset + logger_index_npart_size;
+  return (struct index_data *)ret;
+}
+
 /**
  * @brief Map the file and if required sort it.
  *
diff --git a/logger/logger_index.h b/logger/logger_index.h
index 8419e0aaa18e00846e2c3ad9f1218780bf44f431..1a50ed812acd3b317c52f4ba7c040e55f131a03d 100644
--- a/logger/logger_index.h
+++ b/logger/logger_index.h
@@ -68,6 +68,12 @@ struct logger_index {
 
   /* The mapped file */
   struct mapped_file index;
+
+  /* Number of particles created. */
+  uint64_t nparts_created[swift_type_count];
+
+  /* Number of particles removed. */
+  uint64_t nparts_removed[swift_type_count];
 };
 
 void logger_index_write_sorted(struct logger_index *index);
@@ -81,5 +87,9 @@ size_t logger_index_get_particle_offset(struct logger_index *index,
 void logger_index_free(struct logger_index *index);
 void logger_index_sort_file(struct logger_index *index);
 struct index_data *logger_index_get_data(struct logger_index *index, int type);
+struct index_data *logger_index_get_created_history(struct logger_index *index,
+                                                    int type);
+struct index_data *logger_index_get_removed_history(struct logger_index *index,
+                                                    int type);
 
 #endif  // LOGGER_LOGGER_INDEX_H
diff --git a/logger/logger_interpolation.h b/logger/logger_interpolation.h
new file mode 100644
index 0000000000000000000000000000000000000000..c573e8395217a44049c215174514fcd4b57e2d4d
--- /dev/null
+++ b/logger/logger_interpolation.h
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#ifndef LOGGER_LOGGER_INTERPOLATION_H
+#define LOGGER_LOGGER_INTERPOLATION_H
+
+#include "logger_tools.h"
+
+/**
+ * @brief Compute the quintic hermite spline interpolation.
+ * See https://en.wikipedia.org/wiki/Hermite_interpolation for more information.
+ * @f$ p(x) = f(x_0) + f'(x_0) (x - x_0) + \frac{1}{2}f''(x_0) (x - x_0)^2 +
+ \frac{f(x_1) - f(x_0) - f'(x_0) (x_1 - x_0) - \frac{1}{2} f''(x_0) (x_1 -
+ x_0)^2}{(x_1 - x_0)^3} (x - x_0)^3
+  + \frac{3 f(x_0) - 3 f(x_1) + \left( 2 f'(x_0) + f'(x_1) \right) (x_1 - x_0) +
+ \frac{1}{2} f''(x_0) (x_1 - x_0)^2}{(x_1 - x_0)^4} (x - x_0)^3 (x - x_1)
+  + \frac{6 f(x_1) - 6 f(x_0) - 3 \left( f'(x_0) + f'(x_1) \right) (x_1 - x_0) +
+ \frac{1}{2}\left( f''(x_1) - f''(x_0) \right) (x_1 - x_0)^2}{(x_1 - x_0)^5} (x
+ - x_0)^3 (x - x_1)^2 @f$
+ *
+ * @param t0 The time at the left of the interval.
+ * @param x0 The function at the left of the interval.
+ * @param v0 The first derivative at the left of the interval.
+ * @param a0 The second derivative at the left of the interval.
+ * @param t1 The time at the right of the interval.
+ * @param x1 The function at the right of the interval.
+ * @param v1 The first derivative at the right of the interval.
+ * @param a1 The second derivative at the right of the interval.
+ * @param t The time of the interpolation.
+ *
+ * @return The function evaluated at t.
+ */
+__attribute__((always_inline)) INLINE static double
+interpolate_quintic_hermite_spline(const double t0, const double x0,
+                                   const float v0, const float a0,
+                                   const double t1, const double x1,
+                                   const float v1, const float a1,
+                                   const double t) {
+
+  /* Generates recurring variables  */
+  /* Time differences */
+  const double dt = t1 - t0;
+  const double dt2 = dt * dt;
+  const double dt3 = dt2 * dt;
+  const double dt4 = dt3 * dt;
+  const double dt5 = dt4 * dt;
+
+  const double t_t0 = t - t0;
+  const double t_t0_2 = t_t0 * t_t0;
+  const double t_t0_3 = t_t0_2 * t_t0;
+  const double t_t1 = t - t1;
+  const double t_t1_2 = t_t1 * t_t1;
+
+  /* Derivatives */
+  const double v0_dt = v0 * dt;
+  const double a0_dt2 = 0.5 * a0 * dt2;
+  const double v1_dt = v1 * dt;
+  const double a1_dt2 = 0.5 * a1 * dt2;
+
+  /* Do the first 3 terms of the hermite spline */
+  double x = x0 + v0 * t_t0 + 0.5 * a0 * t_t0_2;
+
+  /* Cubic term */
+  x += (x1 - x0 - v0_dt - a0_dt2) * t_t0_3 / dt3;
+
+  /* Quartic term */
+  x += (3. * x0 - 3. * x1 + v1_dt + 2. * v0_dt + a0_dt2) * t_t0_3 * t_t1 / dt4;
+
+  /* Quintic term */
+  x += (6. * x1 - 6. * x0 - 3. * v0_dt - 3. * v1_dt + a1_dt2 - a0_dt2) *
+       t_t0_3 * t_t1_2 / dt5;
+
+  return x;
+}
+
+/**
+ * @brief Compute the cubic hermite spline interpolation.
+ * See https://en.wikipedia.org/wiki/Hermite_interpolation for more information.
+ * @f$ p(x) = f(x_0) + f'(x_0) (x - x_0) + \frac{f(x_1) - f(x_0) - f'(x_0) (x_1
+ - x_0)}{(x_1 - x_0)^2} (x - x_0)^2
+  + \frac{2 f(x_0) - 2 f(x_1) + f'(x_0) (x_1 - x_0) + f'(x_1) (x_1 - x_0)}{(x_1
+ - x_0)^3} (x - x_0)^2 (x - x_1) @f$
+ *
+ * @param t0 The time at the left of the interval.
+ * @param v0 The first derivative at the left of the interval.
+ * @param a0 The second derivative at the left of the interval.
+ * @param t1 The time at the right of the interval.
+ * @param v1 The first derivative at the right of the interval.
+ * @param a1 The second derivative at the right of the interval.
+ * @param t The time of the interpolation.
+ *
+ * @return The function evaluated at t.
+ */
+__attribute__((always_inline)) INLINE static float
+interpolate_cubic_hermite_spline(const double t0, const float v0,
+                                 const float a0, const double t1,
+                                 const float v1, const float a1,
+                                 const double t) {
+
+  /* Generates recurring variables  */
+  /* Time differences */
+  const float dt = t1 - t0;
+  const float dt2 = dt * dt;
+  const float dt3 = dt2 * dt;
+
+  const float t_t0 = t - t0;
+  const float t_t0_2 = t_t0 * t_t0;
+  const float t_t1 = t - t1;
+
+  /* Derivatives */
+  const float a0_dt = a0 * dt;
+  const float a1_dt = a1 * dt;
+
+  /* Do the first 2 terms of the hermite spline */
+  float x = v0 + a0 * t_t0;
+
+  /* Square term */
+  x += (v1 - v0 - a0_dt) * t_t0_2 / dt2;
+
+  /* Cubic term */
+  x += (2. * v0 - 2. * v1 + a1_dt + a0_dt) * t_t0_2 * t_t1 / dt3;
+
+  return x;
+}
+
+/**
+ * @brief Interpolates a field in N dimension using the first and second
+ * derivatives if possible.
+ *
+ * The field is in double and both derivatives in float.
+ *
+ * @param before Pointer to the #logger_field at a time < t.
+ * @param after Pointer to the #logger_field at a time > t.
+ * @param otuput Pointer to the output value.
+ * @param t_before Time of field_before (< t).
+ * @param t_after Time of field_after (> t).
+ * @param t Requested time.
+ */
+__attribute__((always_inline)) INLINE static void
+interpolate_quintic_double_float_ND(const double t_before,
+                                    const struct logger_field *restrict before,
+                                    const double t_after,
+                                    const struct logger_field *restrict after,
+                                    void *restrict output, const double t,
+                                    const int dimension) {
+  /* Compute the interpolation scaling. */
+  const double wa = (t - t_before) / (t_after - t_before);
+  const double wb = 1. - wa;
+
+  for (int i = 0; i < dimension; i++) {
+    double *x = (double *)output;
+    const double *x_bef = (double *)before->field;
+    const float *v_bef = (float *)before->first_deriv;
+    const float *a_bef = (float *)before->second_deriv;
+
+    const double *x_aft = (double *)after->field;
+    const float *v_aft = (float *)after->first_deriv;
+    const float *a_aft = (float *)after->second_deriv;
+
+    /* Use quintic hermite spline. */
+    if (v_bef && v_aft && a_bef && a_aft) {
+      x[i] = interpolate_quintic_hermite_spline(t_before, x_bef[i], v_bef[i],
+                                                a_bef[i], t_after, x_aft[i],
+                                                v_aft[i], a_aft[i], t);
+    }
+    /* Use cubic hermite spline. */
+    else if (v_bef && v_aft) {
+      x[i] = interpolate_cubic_hermite_spline(t_before, x_bef[i], v_bef[i],
+                                              t_after, x_aft[i], v_aft[i], t);
+    }
+    /* Use linear interpolation. */
+    else {
+      x[i] = wa * x_aft[i] + wb * x_bef[i];
+    }
+  }
+}
+
+/**
+ * @brief Interpolates a field in N dimension using the first derivative if
+ * possible.
+ *
+ * The field and the first derivatives are floats.
+ *
+ * @param before Pointer to the #logger_field at a time < t.
+ * @param after Pointer to the #logger_field at a time > t.
+ * @param otuput Pointer to the output value.
+ * @param t_before Time of field_before (< t).
+ * @param t_after Time of field_after (> t).
+ * @param t Requested time.
+ */
+__attribute__((always_inline)) INLINE static void interpolate_cubic_float_ND(
+    const double t_before, const struct logger_field *restrict before,
+    const double t_after, const struct logger_field *restrict after,
+    void *restrict output, const double t, const int dimension) {
+
+  /* Compute the interpolation scaling. */
+  const float wa = (t - t_before) / (t_after - t_before);
+  const float wb = 1. - wa;
+
+  for (int i = 0; i < dimension; i++) {
+    float *v = (float *)output;
+    const float *v_bef = (float *)before->field;
+    const float *a_bef = (float *)before->first_deriv;
+
+    const float *v_aft = (float *)after->field;
+    const float *a_aft = (float *)after->first_deriv;
+
+    /* Use a cubic hermite spline. */
+    if (a_bef && a_aft) {
+      v[i] = interpolate_cubic_hermite_spline(t_before, v_bef[i], a_bef[i],
+                                              t_after, v_aft[i], a_aft[i], t);
+    }
+    /* Use linear interpolation. */
+    else {
+      v[i] = wa * v_aft[i] + wb * v_bef[i];
+    }
+  }
+}
+
+/**
+ * @brief Interpolates a field in N dimension.
+ *
+ * The field is in float.
+ *
+ * @param before Pointer to the #logger_field at a time < t.
+ * @param after Pointer to the #logger_field at a time > t.
+ * @param otuput Pointer to the output value.
+ * @param t_before Time of field_before (< t).
+ * @param t_after Time of field_after (> t).
+ * @param t Requested time.
+ */
+__attribute__((always_inline)) INLINE static void interpolate_linear_float_ND(
+    const double t_before, const struct logger_field *restrict before,
+    const double t_after, const struct logger_field *restrict after,
+    void *restrict output, const double t, const int dimension) {
+
+  /* Compute the interpolation scaling. */
+  const float wa = (t - t_before) / (t_after - t_before);
+  const float wb = 1. - wa;
+
+  /* interpolate vectors. */
+  for (int i = 0; i < dimension; i++) {
+    float *a = (float *)output;
+    const float *a_bef = (float *)before->field;
+    const float *a_aft = (float *)after->field;
+    a[i] = wa * a_aft[i] + wb * a_bef[i];
+  }
+}
+
+/**
+ * @brief Interpolates a field stored as a float.
+ *
+ * @param before Pointer to the #logger_field at a time < t.
+ * @param after Pointer to the #logger_field at a time > t.
+ * @param otuput Pointer to the output value.
+ * @param t_before Time of field_before (< t).
+ * @param t_after Time of field_after (> t).
+ * @param t Requested time.
+ */
+__attribute__((always_inline)) INLINE static void interpolate_linear_float(
+    const double t_before, const struct logger_field *restrict before,
+    const double t_after, const struct logger_field *restrict after,
+    void *restrict output, const double t) {
+
+  /* Compute the interpolation scaling. */
+  const float wa = (t - t_before) / (t_after - t_before);
+  const float wb = 1. - wa;
+  ((float *)output)[0] =
+      wa * ((float *)after->field)[0] + wb * ((float *)before->field)[0];
+}
+
+/**
+ * @brief Interpolation function for the ids.
+ *
+ * As the IDs should not change during the simulation, we ensure
+ * that the IDs are the same between two records.
+ *
+ * @param before Pointer to the #logger_field at a time < t.
+ * @param after Pointer to the #logger_field at a time > t.
+ * @param otuput Pointer to the output value.
+ * @param t_before Time of field_before (< t).
+ * @param t_after Time of field_after (> t).
+ * @param t Requested time.
+ */
+__attribute__((always_inline)) INLINE static void interpolate_ids(
+    const double t_before, const struct logger_field *restrict before,
+    const double t_after, const struct logger_field *restrict after,
+    void *restrict output, const double t) {
+  if (*(long long *)after->field != *(long long *)before->field) {
+    error("Interpolating different particles");
+  }
+  *(long long *)output = *(long long *)after->field;
+}
+#endif  // LOGGER_LOGGER_INTERPOLATION_H
diff --git a/logger/logger_particle.c b/logger/logger_particle.c
index 331fd74190d603ffc379df8d7a6abf4712fbfa50..4e01c38fd942a2ec356207940730aa7bbf730a5d 100644
--- a/logger/logger_particle.c
+++ b/logger/logger_particle.c
@@ -66,7 +66,12 @@ __attribute__((always_inline)) INLINE size_t logger_particle_read_field(
 
   /* Check if it is not a time record. */
   if (*mask == h->timestamp_mask) {
-    error_python("Cannot particle from timestep record.");
+    error_python("Cannot read a particle from timestep record.");
+  }
+
+  /* Skip the special field. */
+  if (*mask & h->masks[logger_index_special_flags].mask) {
+    map += h->masks[logger_index_special_flags].size;
   }
 
   /* Read the record and copy it to a particle. */
@@ -86,5 +91,50 @@ __attribute__((always_inline)) INLINE size_t logger_particle_read_field(
       map += h->masks[global].size;
     }
   }
+
   return map - reader->log.log.map;
 }
+
+/**
+ * @brief Read the special flag of a particle (of any type) in the log file.
+ *
+ * @param reader The #logger_reader.
+ * @param offset offset of the record to read.
+ * @param mask (out) The mask of the record.
+ * @param h_offset (out) Difference of offset with the next record.
+ * @param data (out) The data of the flag.
+ *
+ * @return The special flag.
+ */
+__attribute__((always_inline)) INLINE enum logger_special_flags
+logger_particle_read_special_flag(const struct logger_reader *reader,
+                                  size_t offset, size_t *mask, size_t *h_offset,
+                                  int *data) {
+
+  /* Get a few pointers. */
+  const struct header *h = &reader->log.header;
+  void *map = reader->log.log.map;
+
+  *mask = 0;
+  *h_offset = 0;
+
+  /* Read the record's mask. */
+  map = logger_loader_io_read_mask(h, (char *)map + offset, mask, h_offset);
+
+  /* Check that the mask is within the limits. */
+  if (*mask > (unsigned int)(1 << h->masks_count)) {
+    error_python("Found an unexpected mask %zi", *mask);
+  }
+
+  /* Check if it is not a time record. */
+  if (*mask == h->timestamp_mask) {
+    error_python("Cannot read a particle from timestep record.");
+  }
+
+  /* Read the special flag */
+  uint32_t packed_data = 0;
+  map = logger_loader_io_read_data(
+      map, h->masks[logger_index_special_flags].size, &packed_data);
+
+  return logger_unpack_flags_and_data(packed_data, data);
+}
diff --git a/logger/logger_particle.h b/logger/logger_particle.h
index d76dfe917190d3aa3c8c98b7aa13768b79654358..22dc6460b05275ae50419d93371ae827641cafc2 100644
--- a/logger/logger_particle.h
+++ b/logger/logger_particle.h
@@ -45,6 +45,11 @@ size_t logger_particle_read_field(const struct logger_reader *reader,
                                   const int *local_to_global,
                                   const int local_count, int field,
                                   size_t *mask, size_t *h_offset);
+
+enum logger_special_flags logger_particle_read_special_flag(
+    const struct logger_reader *reader, size_t offset, size_t *mask,
+    size_t *h_offset, int *data);
+
 /**
  * @brief Generate the data for the special flags.
  *
diff --git a/logger/logger_python_wrapper.c b/logger/logger_python_wrapper.c
index 9c7336dacd09e868cab2f879a398f38e2ec6a4bd..29d6852c4c908a9192471bc7e9b75f7fd38ab5ea 100644
--- a/logger/logger_python_wrapper.c
+++ b/logger/logger_python_wrapper.c
@@ -428,14 +428,45 @@ static PyObject *pyGetParticleData(__attribute__((unused)) PyObject *self,
   /* input variables. */
   PyObject *fields = NULL;
   double time = 0;
+  PyObject *types = Py_None;
+
   /* parse the arguments. */
-  if (!PyArg_ParseTuple(args, "Od", &fields, &time)) return NULL;
+  if (!PyArg_ParseTuple(args, "Od|O", &fields, &time, &types)) return NULL;
 
   /* Check the inputs. */
   if (!PyList_Check(fields)) {
     error_python("Expecting a list of fields");
   }
 
+  /* Get the type of particles to read. */
+  int read_types[swift_type_count] = {0};
+  /* By default, we read everything */
+  if (types == Py_None) {
+    for (int i = 0; i < swift_type_count; i++) {
+      read_types[i] = 1;
+    }
+  }
+  /* Deal with the case of a single int. */
+  else if (PyLong_Check(types)) {
+    const size_t type = PyLong_AsSize_t(types);
+    if (type >= swift_type_count) {
+      error_python("Unexpected particle type %zi", type);
+    }
+    read_types[type] = 1;
+  }
+  /* Deal with the case of a list */
+  else if (PyList_Check(types)) {
+    const size_t size = PyList_Size(types);
+    for (size_t i = 0; i < size; i++) {
+      PyObject *cur = PyList_GetItem(types, i);
+      const size_t type = PyLong_AsSize_t(cur);
+      if (type >= swift_type_count) {
+        error_python("Unexpected particle type %zi", type);
+      }
+      read_types[type] = 1;
+    }
+  }
+
   /* initialize the reader. */
   struct logger_reader *reader = &self_reader->reader;
   const struct header *h = &reader->log.header;
@@ -474,10 +505,10 @@ static PyObject *pyGetParticleData(__attribute__((unused)) PyObject *self,
   logger_reader_set_time(reader, time);
 
   /* Get the number of particles. */
-  int n_type = 0;
-  const uint64_t *n_part = logger_reader_get_number_particles(reader, &n_type);
+  uint64_t n_part[swift_type_count];
+  logger_reader_get_number_particles(reader, n_part, read_types);
   uint64_t n_tot = 0;
-  for (int i = 0; i < n_type; i++) {
+  for (int i = 0; i < swift_type_count; i++) {
     n_tot += n_part[i];
   }
 
diff --git a/logger/logger_reader.c b/logger/logger_reader.c
index feb757fd264cba983134754d873839c57dddd38b..493ba6d6d81ae781baf5ee61b1cd07b88d20b56f 100644
--- a/logger/logger_reader.c
+++ b/logger/logger_reader.c
@@ -72,7 +72,8 @@ void logger_reader_init(struct logger_reader *reader, const char *basename,
  */
 void logger_reader_init_index(struct logger_reader *reader) {
   /* Initialize the logger_index */
-  logger_index_init(&reader->index.index, reader);
+  logger_index_init(&reader->index.index_prev, reader);
+  logger_index_init(&reader->index.index_next, reader);
 
   /* Count the number of files */
   int count = 0;
@@ -106,11 +107,11 @@ void logger_reader_init_index(struct logger_reader *reader) {
     sprintf(filename, "%s_%04i.index", reader->basename, i);
 
     /* Read the header */
-    logger_index_read_header(&reader->index.index, filename);
+    logger_index_read_header(&reader->index.index_prev, filename);
 
     /* Save the required information */
-    reader->index.times[i] = reader->index.index.time;
-    reader->index.int_times[i] = reader->index.index.integer_time;
+    reader->index.times[i] = reader->index.index_prev.time;
+    reader->index.int_times[i] = reader->index.index_prev.integer_time;
   }
 }
 
@@ -124,7 +125,7 @@ void logger_reader_free(struct logger_reader *reader) {
   logger_logfile_free(&reader->log);
 
   if (reader->time.time != -1.) {
-    logger_index_free(&reader->index.index);
+    logger_index_free(&reader->index.index_prev);
   }
 
   free(reader->index.int_times);
@@ -156,17 +157,27 @@ void logger_reader_set_time(struct logger_reader *reader, double time) {
   }
 
   /* Generate the filename */
-  char filename[STRING_SIZE + 50];
-  sprintf(filename, "%s_%04u.index", reader->basename, left);
+  char filename_prev[STRING_SIZE + 50];
+  sprintf(filename_prev, "%s_%04u.index", reader->basename, left);
+  char filename_next[STRING_SIZE + 50];
+  sprintf(filename_next, "%s_%04u.index", reader->basename, left + 1);
 
   /* Check if the file is already mapped */
-  if (reader->index.index.index.map != NULL) {
-    logger_index_free(&reader->index.index);
+  if (reader->index.index_prev.index.map != NULL) {
+    logger_index_free(&reader->index.index_prev);
+  }
+  if (reader->index.index_next.index.map != NULL) {
+    logger_index_free(&reader->index.index_next);
   }
 
   /* Read the file */
-  logger_index_read_header(&reader->index.index, filename);
-  logger_index_map_file(&reader->index.index, filename, /* sorted */ 1);
+  logger_index_read_header(&reader->index.index_prev, filename_prev);
+  logger_index_map_file(&reader->index.index_prev, filename_prev,
+                        /* sorted */ 1);
+
+  logger_index_read_header(&reader->index.index_next, filename_next);
+  logger_index_map_file(&reader->index.index_next, filename_next,
+                        /* sorted */ 1);
 
   /* Get the offset of the time chunk */
   size_t ind = time_array_get_index_from_time(&reader->log.times, time);
@@ -189,17 +200,133 @@ void logger_reader_set_time(struct logger_reader *reader, double time) {
 }
 
 /**
- * @brief Provides the number of particle (per type) from the index file.
+ * @brief Count the number of new particles at the time set since last index
+ * file.
+ *
+ * @param reader The #logger_reader.
+ * @param part_type The index corresponding to the particle type.
+ *
+ * @param The number of new particles.
+ */
+size_t logger_reader_count_number_new_particles(struct logger_reader *reader,
+                                                enum part_type part_type) {
+
+  const size_t threshold = reader->time.time_offset;
+
+  /* Get the history of created particles. */
+  struct index_data *data =
+      logger_index_get_created_history(&reader->index.index_next, part_type);
+
+  /* Do we have any new particle? */
+  if (reader->index.index_next.nparts_created[part_type] == 0 ||
+      threshold < data[0].offset) {
+    return 0;
+  }
+
+  /* Perform a binary search */
+  size_t right = reader->index.index_next.nparts_created[part_type] - 1;
+  size_t left = 0;
+  while (left <= right) {
+    size_t m = (left + right) / 2;
+    if (data[m].offset < threshold) {
+      left = m + 1;
+    } else if (data[m].offset > threshold) {
+      right = m - 1;
+    } else {
+      return m;
+    }
+  }
+
+  /* Compute the return value. */
+  size_t ret = (left + right) / 2;
+
+  /* Check if the binary search is correct. */
+  if (data[ret].offset > threshold) {
+    error_python("The binary search has failed.");
+  }
+
+  /* We need the count, not the index. */
+  return ret + 1;
+}
+
+/**
+ * @brief Count the number of removed particles at the time set since last index
+ * file.
  *
  * @param reader The #logger_reader.
  * @param n_type (output) The number of particle type possible.
+ * @param part_type The index corresponding to the particle type.
  *
- * @return For each type possible, the number of particle.
+ * @param The number of removed particles.
  */
-const uint64_t *logger_reader_get_number_particles(struct logger_reader *reader,
-                                                   int *n_type) {
-  *n_type = swift_type_count;
-  return reader->index.index.nparts;
+size_t logger_reader_count_number_removed_particles(
+    struct logger_reader *reader, enum part_type part_type) {
+
+  const size_t threshold = reader->time.time_offset;
+
+  /* Get the history of created particles. */
+  struct index_data *data =
+      logger_index_get_removed_history(&reader->index.index_next, part_type);
+
+  /* Do we have any new particle? */
+  if (reader->index.index_next.nparts_removed[part_type] == 0 ||
+      threshold < data[0].offset) {
+    return 0;
+  }
+
+  /* Perform a binary search */
+  size_t right = reader->index.index_next.nparts_removed[part_type] - 1;
+  size_t left = 0;
+  while (left <= right) {
+    size_t m = (left + right) / 2;
+    if (data[m].offset < threshold) {
+      left = m + 1;
+    } else if (data[m].offset > threshold) {
+      right = m - 1;
+    } else {
+      return m;
+    }
+  }
+
+  /* Compute the return value. */
+  size_t ret = (left + right) / 2;
+
+  /* Check if the binary search is correct. */
+  if (data[ret].offset > threshold) {
+    error_python("The binary search has failed.");
+  }
+
+  /* We need the count, not the index. */
+  return ret + 1;
+}
+
+/**
+ * @brief Provides the number of particle (per type) from the index file.
+ *
+ * @param reader The #logger_reader.
+ * @param n_parts (out) Number of particles at the time set in the reader.
+ * @param read_types Should we read this type of particles?
+ */
+void logger_reader_get_number_particles(struct logger_reader *reader,
+                                        uint64_t *n_parts,
+                                        const int *read_types) {
+  for (int i = 0; i < swift_type_count; i++) {
+    /* Should we skip this type of particles? */
+    if (read_types[i] == 0) {
+      n_parts[i] = 0;
+      continue;
+    }
+
+    /* Count the number of particles present in the last index file. */
+    const uint64_t count_prev = reader->index.index_prev.nparts[i];
+    /* Count the number of particles that have been created since last index. */
+    const uint64_t count_new =
+        logger_reader_count_number_new_particles(reader, i);
+    /* Count the number of particles that have been removed since last index. */
+    const uint64_t count_removed =
+        logger_reader_count_number_removed_particles(reader, i);
+    n_parts[i] = (count_prev + count_new) - count_removed;
+  }
 }
 
 /**
@@ -227,18 +354,24 @@ const uint64_t *logger_reader_get_number_particles(struct logger_reader *reader,
  (-1 if none)
  * @param output Pointers to the output array
  * @param type The #part_type.
+ *
+ * @return Is the particle removed from the logfile?
  */
-void logger_reader_read_field(struct logger_reader *reader, double time,
-                              size_t offset_time,
-                              enum logger_reader_type interp_type,
-                              const size_t offset_last_full_record,
-                              const int field, const int first,
-                              const int second, void *output,
-                              enum part_type type) {
+int logger_reader_read_field(struct logger_reader *reader, double time,
+                             size_t offset_time,
+                             enum logger_reader_type interp_type,
+                             const size_t offset_last_full_record,
+                             const int field, const int first, const int second,
+                             void *output, enum part_type type) {
 
   const struct header *h = &reader->log.header;
   size_t offset = offset_last_full_record;
 
+  /* Check if the offsets are correct. */
+  if (offset > offset_time) {
+    error_python("Last offset is larger than the requested time.");
+  }
+
   /* Get the particle type variables. */
   int *local_to_global = NULL;
   int field_count = 0;
@@ -248,6 +381,7 @@ void logger_reader_read_field(struct logger_reader *reader, double time,
       field_count = hydro_logger_field_count;
       break;
     case swift_type_dark_matter:
+    case swift_type_dark_matter_background:
       local_to_global = gravity_logger_local_to_global;
       field_count = gravity_logger_field_count;
       break;
@@ -285,6 +419,22 @@ void logger_reader_read_field(struct logger_reader *reader, double time,
     logger_loader_io_read_mask(h, reader->log.log.map + offset, &mask,
                                &h_offset);
 
+    /* Is the particle removed from the logfile? */
+    if (mask & h->masks[logger_index_special_flags].mask) {
+      int data = 0;
+      enum logger_special_flags flag = logger_particle_read_special_flag(
+          reader, offset, &mask, &h_offset, &data);
+      if (flag == logger_flag_change_type || flag == logger_flag_mpi_exit ||
+          flag == logger_flag_delete) {
+        return 1;
+      }
+    }
+
+    /* Check if there is a next record (avoid infinite loop). */
+    if (h_offset == 0) {
+      error_python("No next record found.");
+    }
+
     /* Check if the field is present */
     if (mask & mask_field->mask) {
       offset_before = offset;
@@ -405,6 +555,7 @@ void logger_reader_read_field(struct logger_reader *reader, double time,
                                        output, time, field);
         break;
       case swift_type_dark_matter:
+      case swift_type_dark_matter_background:
         gravity_logger_interpolate_field(time_before, &before, time_after,
                                          &after, output, time, field);
         break;
@@ -416,6 +567,7 @@ void logger_reader_read_field(struct logger_reader *reader, double time,
         error_python("Particle type not implemented");
     }
   }
+  return 0;
 }
 
 /**
@@ -443,22 +595,19 @@ void logger_reader_global_to_local(
   /* Get the correct variables. */
   int n_max = 0;
   int *local_to_global = NULL;
-  const char **local_names = NULL;
   switch (type) {
     case swift_type_gas:
       n_max = hydro_logger_field_count;
       local_to_global = hydro_logger_local_to_global;
-      local_names = hydro_logger_field_names;
       break;
     case swift_type_dark_matter:
+    case swift_type_dark_matter_background:
       n_max = gravity_logger_field_count;
       local_to_global = gravity_logger_local_to_global;
-      local_names = gravity_logger_field_names;
       break;
     case swift_type_stars:
       n_max = stars_logger_field_count;
       local_to_global = stars_logger_local_to_global;
-      local_names = stars_logger_field_names;
       break;
     default:
       error_python("Particle type not implemented yet.");
@@ -496,7 +645,9 @@ void logger_reader_global_to_local(
   /* Check that we found the fields */
   for (int local = 0; local < n_fields_wanted; local++) {
     if (local_fields_wanted[local] < 0) {
-      error_python("Field %s not found in particle type %s", local_names[local],
+      const int global_field = global_fields_wanted[local];
+      const char *name = h->masks[global_field].name;
+      error_python("Field %s not found in particle type %s", name,
                    part_type_names[type]);
     }
   }
@@ -546,61 +697,185 @@ void logger_reader_read_all_particles(struct logger_reader *reader, double time,
   /* Do the hydro. */
   if (n_part[swift_type_gas] != 0) {
     struct index_data *data =
-        logger_index_get_data(&reader->index.index, swift_type_gas);
+        logger_index_get_data(&reader->index.index_prev, swift_type_gas);
+    struct index_data *data_created = logger_index_get_created_history(
+        &reader->index.index_next, swift_type_gas);
 
     /* Sort the fields in order to read the correct bits. */
     logger_reader_global_to_local(
         reader, global_fields_wanted, local_fields_wanted, local_first_deriv,
         local_second_deriv, n_fields_wanted, swift_type_gas);
 
+    size_t current_in_index = 0;
+    int reading_history = 0;
+    const size_t size_index = reader->index.index_prev.nparts[swift_type_gas];
+    const size_t size_history =
+        logger_reader_count_number_new_particles(reader, swift_type_gas);
+
     /* Read the particles */
     for (size_t i = 0; i < n_part[swift_type_gas]; i++) {
-      /* Get the offset */
-      size_t offset = data[i].offset;
-
-      /* Sort the output into output_single. */
-      for (int field = 0; field < n_fields_wanted; field++) {
-        const int global = global_fields_wanted[field];
-        const int local = local_fields_wanted[field];
-        const int first = local_first_deriv[field];
-        const int second = local_second_deriv[field];
-        void *output_single = output[field] + i * h->masks[global].size;
-
-        /* Read the field. */
-        logger_reader_read_field(reader, time, reader->time.time_offset,
-                                 interp_type, offset, local, first, second,
-                                 output_single, swift_type_gas);
+      int particle_removed = 1;
+      /* Do it until finding a particle not removed. */
+      while (particle_removed) {
+        /* Should we start to read the history? */
+        if (!reading_history && current_in_index == size_index) {
+          current_in_index = 0;
+          reading_history = 1;
+        }
+
+        /* Check if we still have some particles available. */
+        if (reading_history && current_in_index == size_history) {
+          error_python("The logger was not able to find enough particles.");
+        }
+
+        /* Get the offset */
+        size_t offset = reading_history ? data_created[current_in_index].offset
+                                        : data[current_in_index].offset;
+
+        /* Sort the output into output_single. */
+        for (int field = 0; field < n_fields_wanted; field++) {
+          const int global = global_fields_wanted[field];
+          const int local = local_fields_wanted[field];
+          const int first = local_first_deriv[field];
+          const int second = local_second_deriv[field];
+          void *output_single = output[field] + i * h->masks[global].size;
+
+          /* Read the field. */
+          particle_removed = logger_reader_read_field(
+              reader, time, reader->time.time_offset, interp_type, offset,
+              local, first, second, output_single, swift_type_gas);
+
+          /* Should we continue to read the fields of this particle? */
+          if (particle_removed) {
+            break;
+          }
+        }
+        current_in_index++;
       }
     }
   }
 
   /* Do the dark matter. */
   if (n_part[swift_type_dark_matter] != 0) {
-    struct index_data *data =
-        logger_index_get_data(&reader->index.index, swift_type_dark_matter);
+    struct index_data *data = logger_index_get_data(&reader->index.index_prev,
+                                                    swift_type_dark_matter);
+    struct index_data *data_created = logger_index_get_created_history(
+        &reader->index.index_next, swift_type_dark_matter);
 
     /* Sort the fields in order to read the correct bits. */
     logger_reader_global_to_local(
         reader, global_fields_wanted, local_fields_wanted, local_first_deriv,
         local_second_deriv, n_fields_wanted, swift_type_dark_matter);
 
+    size_t current_in_index = 0;
+    int reading_history = 0;
+    const size_t size_index =
+        reader->index.index_prev.nparts[swift_type_dark_matter];
+    const size_t size_history = logger_reader_count_number_new_particles(
+        reader, swift_type_dark_matter);
+
     /* Read the particles */
     for (size_t i = 0; i < n_part[swift_type_dark_matter]; i++) {
-      /* Get the offset */
-      size_t offset = data[i].offset;
-
-      /* Sort the output into output_single. */
-      for (int field = 0; field < n_fields_wanted; field++) {
-        const int global = global_fields_wanted[field];
-        const int local = local_fields_wanted[field];
-        const int first = local_first_deriv[field];
-        const int second = local_second_deriv[field];
-        void *output_single = output[field] + i * h->masks[global].size;
-
-        /* Read the field. */
-        logger_reader_read_field(reader, time, reader->time.time_offset,
-                                 interp_type, offset, local, first, second,
-                                 output_single, swift_type_dark_matter);
+      int particle_removed = 1;
+      /* Do it until finding a particle not removed. */
+      while (particle_removed) {
+        /* Should we start to read the history? */
+        if (!reading_history && current_in_index == size_index) {
+          current_in_index = 0;
+          reading_history = 1;
+        }
+
+        /* Check if we still have some particles available. */
+        if (reading_history && current_in_index == size_history) {
+          error_python("The logger was not able to find enough particles.");
+        }
+
+        /* Get the offset */
+        size_t offset = reading_history ? data_created[current_in_index].offset
+                                        : data[current_in_index].offset;
+
+        /* Sort the output into output_single. */
+        for (int field = 0; field < n_fields_wanted; field++) {
+          const int global = global_fields_wanted[field];
+          const int local = local_fields_wanted[field];
+          const int first = local_first_deriv[field];
+          const int second = local_second_deriv[field];
+          void *output_single = output[field] + i * h->masks[global].size;
+
+          /* Read the field. */
+          particle_removed = logger_reader_read_field(
+              reader, time, reader->time.time_offset, interp_type, offset,
+              local, first, second, output_single, swift_type_dark_matter);
+
+          /* Should we continue to read the fields of this particle? */
+          if (particle_removed) {
+            break;
+          }
+        }
+        current_in_index++;
+      }
+    }
+  }
+
+  /* Do the dark matter background. */
+  if (n_part[swift_type_dark_matter_background] != 0) {
+    struct index_data *data = logger_index_get_data(
+        &reader->index.index_prev, swift_type_dark_matter_background);
+    struct index_data *data_created = logger_index_get_created_history(
+        &reader->index.index_next, swift_type_dark_matter_background);
+
+    /* Sort the fields in order to read the correct bits. */
+    logger_reader_global_to_local(
+        reader, global_fields_wanted, local_fields_wanted, local_first_deriv,
+        local_second_deriv, n_fields_wanted, swift_type_dark_matter_background);
+
+    size_t current_in_index = 0;
+    int reading_history = 0;
+    const size_t size_index =
+        reader->index.index_prev.nparts[swift_type_dark_matter_background];
+    const size_t size_history = logger_reader_count_number_new_particles(
+        reader, swift_type_dark_matter_background);
+
+    /* Read the particles */
+    for (size_t i = 0; i < n_part[swift_type_dark_matter_background]; i++) {
+      int particle_removed = 1;
+      /* Do it until finding a particle not removed. */
+      while (particle_removed) {
+        /* Should we start to read the history? */
+        if (!reading_history && current_in_index == size_index) {
+          current_in_index = 0;
+          reading_history = 1;
+        }
+
+        /* Check if we still have some particles available. */
+        if (reading_history && current_in_index == size_history) {
+          error_python("The logger was not able to find enough particles.");
+        }
+
+        /* Get the offset */
+        size_t offset = reading_history ? data_created[current_in_index].offset
+                                        : data[current_in_index].offset;
+
+        /* Sort the output into output_single. */
+        for (int field = 0; field < n_fields_wanted; field++) {
+          const int global = global_fields_wanted[field];
+          const int local = local_fields_wanted[field];
+          const int first = local_first_deriv[field];
+          const int second = local_second_deriv[field];
+          void *output_single = output[field] + i * h->masks[global].size;
+
+          /* Read the field. */
+          particle_removed = logger_reader_read_field(
+              reader, time, reader->time.time_offset, interp_type, offset,
+              local, first, second, output_single,
+              swift_type_dark_matter_background);
+
+          /* Should we continue to read the fields of this particle? */
+          if (particle_removed) {
+            break;
+          }
+        }
+        current_in_index++;
       }
     }
   }
@@ -608,30 +883,60 @@ void logger_reader_read_all_particles(struct logger_reader *reader, double time,
   /* Do the stars. */
   if (n_part[swift_type_stars] != 0) {
     struct index_data *data =
-        logger_index_get_data(&reader->index.index, swift_type_stars);
+        logger_index_get_data(&reader->index.index_prev, swift_type_stars);
+    struct index_data *data_created = logger_index_get_created_history(
+        &reader->index.index_next, swift_type_stars);
 
     /* Sort the fields in order to read the correct bits. */
     logger_reader_global_to_local(
         reader, global_fields_wanted, local_fields_wanted, local_first_deriv,
         local_second_deriv, n_fields_wanted, swift_type_stars);
 
+    size_t current_in_index = 0;
+    int reading_history = 0;
+    const size_t size_index = reader->index.index_prev.nparts[swift_type_stars];
+    const size_t size_history =
+        logger_reader_count_number_new_particles(reader, swift_type_stars);
+
     /* Read the particles */
     for (size_t i = 0; i < n_part[swift_type_stars]; i++) {
-      /* Get the offset */
-      size_t offset = data[i].offset;
-
-      /* Sort the output into output_single. */
-      for (int field = 0; field < n_fields_wanted; field++) {
-        const int global = global_fields_wanted[field];
-        const int local = local_fields_wanted[field];
-        const int first = local_first_deriv[field];
-        const int second = local_second_deriv[field];
-        void *output_single = output[field] + i * h->masks[global].size;
-
-        /* Read the field. */
-        logger_reader_read_field(reader, time, reader->time.time_offset,
-                                 interp_type, offset, local, first, second,
-                                 output_single, swift_type_stars);
+      int particle_removed = 1;
+      /* Do it until finding a particle not removed. */
+      while (particle_removed) {
+        /* Should we start to read the history? */
+        if (!reading_history && current_in_index == size_index) {
+          current_in_index = 0;
+          reading_history = 1;
+        }
+
+        /* Check if we still have some particles available. */
+        if (reading_history && current_in_index == size_history) {
+          error_python("The logger was not able to find enough particles.");
+        }
+
+        /* Get the offset */
+        size_t offset = reading_history ? data_created[current_in_index].offset
+                                        : data[current_in_index].offset;
+
+        /* Sort the output into output_single. */
+        for (int field = 0; field < n_fields_wanted; field++) {
+          const int global = global_fields_wanted[field];
+          const int local = local_fields_wanted[field];
+          const int first = local_first_deriv[field];
+          const int second = local_second_deriv[field];
+          void *output_single = output[field] + i * h->masks[global].size;
+
+          /* Read the field. */
+          particle_removed = logger_reader_read_field(
+              reader, time, reader->time.time_offset, interp_type, offset,
+              local, first, second, output_single, swift_type_stars);
+
+          /* Should we continue to read the fields of this particle? */
+          if (particle_removed) {
+            break;
+          }
+        }
+        current_in_index++;
       }
     }
   }
diff --git a/logger/logger_reader.h b/logger/logger_reader.h
index dc74850188a2ba3b3def6b7adccda3a2734778fd..44bb5e6b62d02916611641f9759a757f4f2f66af 100644
--- a/logger/logger_reader.h
+++ b/logger/logger_reader.h
@@ -67,8 +67,11 @@ struct logger_reader {
   char basename[STRING_SIZE];
 
   struct {
-    /* Information contained in the index file */
-    struct logger_index index;
+    /* Information contained in the previous index file. */
+    struct logger_index index_prev;
+
+    /* Information contained in the next index file. */
+    struct logger_index index_next;
 
     /* Number of index files */
     int n_files;
@@ -119,8 +122,9 @@ double logger_reader_get_time_begin(struct logger_reader *reader);
 double logger_reader_get_time_end(struct logger_reader *reader);
 size_t logger_reader_get_next_offset_from_time(struct logger_reader *reader,
                                                double time);
-const uint64_t *logger_reader_get_number_particles(struct logger_reader *reader,
-                                                   int *n_type);
+void logger_reader_get_number_particles(struct logger_reader *reader,
+                                        uint64_t *n_parts,
+                                        const int *read_types);
 
 void logger_reader_read_all_particles(struct logger_reader *reader, double time,
                                       enum logger_reader_type interp_type,
diff --git a/logger/logger_tools.c b/logger/logger_tools.c
index 34fb0b5185bd3220ada2f657a0ef4f6cf23b8cd6..bef86f7207d70bf069b6de2db17ba559209a15ee 100644
--- a/logger/logger_tools.c
+++ b/logger/logger_tools.c
@@ -139,7 +139,6 @@ size_t tools_reverse_offset(const struct header *h, void *file_map,
 
   /* first records do not have a previous partner. */
   if (prev_offset == cur_offset) return after_current_record;
-
   if (prev_offset > cur_offset)
     error_python("Unexpected offset: header %lu, current %lu.", prev_offset,
                  cur_offset);
@@ -187,9 +186,21 @@ size_t tools_check_record_consistency(const struct logger_reader *reader,
   size_t mask;
   size_t pointed_offset;
 
+  const size_t mask_special_flag =
+      h->masks[header_get_field_index(h, "SpecialFlags")].mask;
+
   /* read mask + offset. */
   map = logger_loader_io_read_mask(h, map, &mask, &pointed_offset);
 
+  /* set offset after current record. */
+  map = (char *)map + header_get_record_size_from_mask(h, mask);
+  const size_t offset_ret = (size_t)((char *)map - (char *)file_init);
+
+  /* If something happened, skip the check. */
+  if (mask & mask_special_flag) {
+    return offset_ret;
+  }
+
   /* get absolute offset. */
   if (header_is_forward(h))
     pointed_offset += offset;
@@ -202,11 +213,7 @@ size_t tools_check_record_consistency(const struct logger_reader *reader,
     error_python("Offset are corrupted.");
   }
 
-  /* set offset after current record. */
-  map = (char *)map + header_get_record_size_from_mask(h, mask);
-
-  if (pointed_offset == offset || pointed_offset == 0)
-    return (size_t)((char *)map - (char *)file_init);
+  if (pointed_offset == offset || pointed_offset == 0) return offset_ret;
 
   /* read mask of the pointed record. */
   size_t pointed_mask = 0;
@@ -219,103 +226,5 @@ size_t tools_check_record_consistency(const struct logger_reader *reader,
     error_python("Error in the offset (mask %lu at %lu != %lu at %lu).", mask,
                  offset, pointed_mask, pointed_offset);
 
-  return (size_t)((char *)map - (char *)file_init);
-}
-
-/**
- * @brief Compute the quintic hermite spline interpolation.
- *
- * @param t0 The time at the left of the interval.
- * @param x0 The function at the left of the interval.
- * @param v0 The first derivative at the left of the interval.
- * @param a0 The second derivative at the left of the interval.
- * @param t1 The time at the right of the interval.
- * @param x1 The function at the right of the interval.
- * @param v1 The first derivative at the right of the interval.
- * @param a1 The second derivative at the right of the interval.
- * @param t The time of the interpolation.
- *
- * @return The function evaluated at t.
- */
-double logger_tools_quintic_hermite_spline(double t0, double x0, float v0,
-                                           float a0, double t1, double x1,
-                                           float v1, float a1, double t) {
-
-  /* Generates recurring variables  */
-  /* Time differences */
-  const double dt = t1 - t0;
-  const double dt2 = dt * dt;
-  const double dt3 = dt2 * dt;
-  const double dt4 = dt3 * dt;
-  const double dt5 = dt4 * dt;
-
-  const double t_t0 = t - t0;
-  const double t_t0_2 = t_t0 * t_t0;
-  const double t_t0_3 = t_t0_2 * t_t0;
-  const double t_t1 = t - t1;
-  const double t_t1_2 = t_t1 * t_t1;
-
-  /* Derivatives */
-  const double v0_dt = v0 * dt;
-  const double a0_dt2 = 0.5 * a0 * dt2;
-  const double v1_dt = v1 * dt;
-  const double a1_dt2 = 0.5 * a1 * dt2;
-
-  /* Do the first 3 terms of the hermite spline */
-  double x = x0 + v0 * t_t0 + 0.5 * a0 * t_t0_2;
-
-  /* Cubic term */
-  x += (x1 - x0 - v0_dt - a0_dt2) * t_t0_3 / dt3;
-
-  /* Quartic term */
-  x += (3. * x0 - 3. * x1 + v1_dt + 2. * v0_dt + a0_dt2) * t_t0_3 * t_t1 / dt4;
-
-  /* Quintic term */
-  x += (6. * x1 - 6. * x0 - 3. * v0_dt - 3. * v1_dt + a1_dt2 - a0_dt2) *
-       t_t0_3 * t_t1_2 / dt5;
-
-  return x;
-}
-
-/**
- * @brief Compute the cubic hermite spline interpolation.
- *
- * @param t0 The time at the left of the interval.
- * @param v0 The first derivative at the left of the interval.
- * @param a0 The second derivative at the left of the interval.
- * @param t1 The time at the right of the interval.
- * @param v1 The first derivative at the right of the interval.
- * @param a1 The second derivative at the right of the interval.
- * @param t The time of the interpolation.
- *
- * @return The function evaluated at t.
- */
-float logger_tools_cubic_hermite_spline(double t0, float v0, float a0,
-                                        double t1, float v1, float a1,
-                                        double t) {
-
-  /* Generates recurring variables  */
-  /* Time differences */
-  const float dt = t1 - t0;
-  const float dt2 = dt * dt;
-  const float dt3 = dt2 * dt;
-
-  const float t_t0 = t - t0;
-  const float t_t0_2 = t_t0 * t_t0;
-  const float t_t1 = t - t1;
-
-  /* Derivatives */
-  const float a0_dt = a0 * dt;
-  const float a1_dt = a1 * dt;
-
-  /* Do the first 2 terms of the hermite spline */
-  float x = v0 + a0 * t_t0;
-
-  /* Square term */
-  x += (v1 - v0 - a0_dt) * t_t0_2 / dt2;
-
-  /* Cubic term */
-  x += (2. * v0 - 2. * v1 + a1_dt + a0_dt) * t_t0_2 * t_t1 / dt3;
-
-  return x;
+  return offset_ret;
 }
diff --git a/logger/logger_tools.h b/logger/logger_tools.h
index 1b5a031019d2cd0dbdf05d46fc56d52615588ec7..1e1037c016d11b7929bd49dd58b5452216510840 100644
--- a/logger/logger_tools.h
+++ b/logger/logger_tools.h
@@ -71,13 +71,6 @@ size_t tools_reverse_offset(const struct header *h, void *map, size_t offset);
 size_t tools_check_record_consistency(const struct logger_reader *reader,
                                       size_t offset);
 
-double logger_tools_quintic_hermite_spline(double t0, double x0, float v0,
-                                           float a0, double t1, double x1,
-                                           float v1, float a1, double t);
-float logger_tools_cubic_hermite_spline(double t0, float v0, float a0,
-                                        double t1, float v1, float a1,
-                                        double t);
-
 #ifndef HAVE_PYTHON
 #define error_python(s, ...) error(s, ##__VA_ARGS__);
 #else
diff --git a/logger/stars/Default/logger_stars.h b/logger/stars/Default/logger_stars.h
index 63ad7d7fffc32a06ce40834cd847d8efb9d91eda..8f35039183cc975e51df091372ea514bfa7a0a69 100644
--- a/logger/stars/Default/logger_stars.h
+++ b/logger/stars/Default/logger_stars.h
@@ -22,6 +22,7 @@
 #include "../config.h"
 
 /* local includes */
+#include "logger_interpolation.h"
 #include "logger_loader_io.h"
 #include "logger_python_tools.h"
 #include "stars_logger.h"
@@ -90,78 +91,25 @@ stars_logger_interpolate_field(const double t_before,
   }
 #endif
 
-  /* Compute the interpolation scaling. */
-  const double wa = (t - t_before) / (t_after - t_before);
-  const double wb = 1. - wa;
-
   switch (field) {
     case stars_logger_field_coordinates:
-      for (int i = 0; i < 3; i++) {
-        double *x = (double *)output;
-        const double *x_bef = (double *)before->field;
-        const float *v_bef = (float *)before->first_deriv;
-        const float *a_bef = (float *)before->second_deriv;
-
-        const double *x_aft = (double *)after->field;
-        const float *v_aft = (float *)after->first_deriv;
-        const float *a_aft = (float *)after->second_deriv;
-
-        /* Use quintic hermite spline. */
-        if (v_bef && v_aft && a_bef && a_aft) {
-          x[i] = logger_tools_quintic_hermite_spline(
-              t_before, x_bef[i], v_bef[i], a_bef[i], t_after, x_aft[i],
-              v_aft[i], a_aft[i], t);
-        }
-        /* Use cubic hermite spline. */
-        else if (v_bef && v_aft) {
-          x[i] = logger_tools_cubic_hermite_spline(
-              t_before, x_bef[i], v_bef[i], t_after, x_aft[i], v_aft[i], t);
-        }
-        /* Use linear interpolation. */
-        else {
-          x[i] = wa * x_aft[i] + wb * x_bef[i];
-        }
-      }
+      interpolate_quintic_double_float_ND(t_before, before, t_after, after,
+                                          output, t, /* dimension= */ 3);
       break;
     case stars_logger_field_velocities:
-      for (int i = 0; i < 3; i++) {
-        float *v = (float *)output;
-        const float *v_bef = (float *)before->field;
-        const float *a_bef = (float *)before->first_deriv;
-
-        const float *v_aft = (float *)after->field;
-        const float *a_aft = (float *)after->first_deriv;
-
-        /* Use a cubic hermite spline. */
-        if (a_bef && a_aft) {
-          v[i] = logger_tools_cubic_hermite_spline(
-              t_before, v_bef[i], a_bef[i], t_after, v_aft[i], a_aft[i], t);
-        }
-        /* Use linear interpolation. */
-        else {
-          v[i] = wa * v_aft[i] + wb * v_bef[i];
-        }
-      }
+      interpolate_cubic_float_ND(t_before, before, t_after, after, output, t,
+                                 /* dimension= */ 3);
       break;
     case stars_logger_field_accelerations:
-      /* interpolate vectors. */
-      for (int i = 0; i < 3; i++) {
-        float *a = (float *)output;
-        const float *a_bef = (float *)before->field;
-        const float *a_aft = (float *)after->field;
-        a[i] = wa * a_aft[i] + wb * a_bef[i];
-      }
+      interpolate_linear_float_ND(t_before, before, t_after, after, output, t,
+                                  /* dimension= */ 3);
       break;
     case stars_logger_field_smoothing_lengths:
     case stars_logger_field_masses:
-      ((float *)output)[0] =
-          wa * ((float *)after->field)[0] + wb * ((float *)before->field)[0];
+      interpolate_linear_float(t_before, before, t_after, after, output, t);
       break;
     case stars_logger_field_particle_ids:
-      if (*(long long *)after->field != *(long long *)before->field) {
-        error("Interpolating different particles");
-      }
-      *(long long *)output = *(long long *)after->field;
+      interpolate_ids(t_before, before, t_after, after, output, t);
       break;
     default:
       error("Not implemented");
diff --git a/src/Makefile.am b/src/Makefile.am
index 300b844a8240dea2ba8ae746e612d3f0d61a53d6..b9d9ff5cf46a568b538321687ec6844a198aab04 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -174,7 +174,7 @@ nobase_noinst_HEADERS += hydro/AnarchyPU/hydro.h hydro/AnarchyPU/hydro_iact.h hy
 nobase_noinst_HEADERS += hydro/AnarchyPU/hydro_debug.h hydro/AnarchyPU/hydro_part.h 
 nobase_noinst_HEADERS += hydro/AnarchyPU/hydro_parameters.h 
 nobase_noinst_HEADERS += hydro/SPHENIX/hydro.h hydro/SPHENIX/hydro_iact.h hydro/SPHENIX/hydro_io.h 
-nobase_noinst_HEADERS += hydro/SPHENIX/hydro_debug.h hydro/SPHENIX/hydro_part.h 
+nobase_noinst_HEADERS += hydro/SPHENIX/hydro_debug.h hydro/SPHENIX/hydro_part.h hydro/SPHENIX/hydro_logger.h
 nobase_noinst_HEADERS += hydro/SPHENIX/hydro_parameters.h 
 nobase_noinst_HEADERS += hydro/Gizmo/hydro_parameters.h 
 nobase_noinst_HEADERS += hydro/Gizmo/hydro_io.h hydro/Gizmo/hydro_debug.h 
diff --git a/src/engine.c b/src/engine.c
index 064a21b6679cb320954225de753670deddd91556..f2e5c3d4c6629a662488012dcbfa742f38c7b104 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -1742,8 +1742,13 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs,
 #ifdef WITH_LOGGER
   if (e->policy & engine_policy_logger) {
     /* Mark the first time step in the particle logger file. */
-    logger_log_timestamp(e->logger, e->ti_current, e->time,
-                         &e->logger->timestamp_offset);
+    if (e->policy & engine_policy_cosmology) {
+      logger_log_timestamp(e->logger, e->ti_current, e->cosmology->a,
+                           &e->logger->timestamp_offset);
+    } else {
+      logger_log_timestamp(e->logger, e->ti_current, e->time,
+                           &e->logger->timestamp_offset);
+    }
     /* Make sure that we have enough space in the particle logger file
      * to store the particles in current time step. */
     logger_ensure_size(e->logger, s->nr_parts, s->nr_gparts, s->nr_sparts);
@@ -2117,8 +2122,13 @@ void engine_step(struct engine *e) {
 #ifdef WITH_LOGGER
   if (e->policy & engine_policy_logger) {
     /* Mark the current time step in the particle logger file. */
-    logger_log_timestamp(e->logger, e->ti_current, e->time,
-                         &e->logger->timestamp_offset);
+    if (e->policy & engine_policy_cosmology) {
+      logger_log_timestamp(e->logger, e->ti_current, e->cosmology->a,
+                           &e->logger->timestamp_offset);
+    } else {
+      logger_log_timestamp(e->logger, e->ti_current, e->time,
+                           &e->logger->timestamp_offset);
+    }
     /* Make sure that we have enough space in the particle logger file
      * to store the particles in current time step. */
     logger_ensure_size(e->logger, e->s->nr_parts, e->s->nr_gparts,
diff --git a/src/hydro/Gadget2/hydro_logger.h b/src/hydro/Gadget2/hydro_logger.h
index e7a12a5b0b3defec623aca3101ef879e6fba5ba6..907259cb699e86f7646966349ccd1d0bbcd5cd2b 100644
--- a/src/hydro/Gadget2/hydro_logger.h
+++ b/src/hydro/Gadget2/hydro_logger.h
@@ -19,6 +19,7 @@
 #ifndef SWIFT_GADGET2_HYDRO_LOGGER_H
 #define SWIFT_GADGET2_HYDRO_LOGGER_H
 
+#include "hydro.h"
 #include "logger_io.h"
 
 #ifdef WITH_LOGGER
@@ -180,9 +181,14 @@ INLINE static char *hydro_logger_write_particle(
 
     /* Compute the acceleration due to hydro and gravity */
     float *acc = (float *)buff;
-    acc[0] = p->a_hydro[0] + p->gpart->a_grav[0];
-    acc[1] = p->a_hydro[1] + p->gpart->a_grav[1];
-    acc[2] = p->a_hydro[2] + p->gpart->a_grav[2];
+    acc[0] = p->a_hydro[0];
+    acc[1] = p->a_hydro[1];
+    acc[2] = p->a_hydro[2];
+    if (p->gpart) {
+      acc[0] += p->gpart->a_grav[0];
+      acc[1] += p->gpart->a_grav[1];
+      acc[2] += p->gpart->a_grav[2];
+    }
 
     memcpy(buff, acc, 3 * sizeof(float));
     buff += 3 * sizeof(float);
diff --git a/src/hydro/SPHENIX/hydro_logger.h b/src/hydro/SPHENIX/hydro_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..44f9274e6a6a352aea789d3eaab2f24fc86825b5
--- /dev/null
+++ b/src/hydro/SPHENIX/hydro_logger.h
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_SPHENIX_HYDRO_LOGGER_H
+#define SWIFT_SPHENIX_HYDRO_LOGGER_H
+
+#include "hydro.h"
+#include "logger_io.h"
+
+#ifdef WITH_LOGGER
+
+/*
+ * List of all possible mask.
+ * Outside the module, only hydro_logger_field_count is used.
+ */
+enum hydro_logger_fields {
+  hydro_logger_field_coordinates = 0,
+  hydro_logger_field_velocities,
+  hydro_logger_field_accelerations,
+  hydro_logger_field_masses,
+  hydro_logger_field_smoothing_lengths,
+  hydro_logger_field_internal_energies,
+  hydro_logger_field_particle_ids,
+  hydro_logger_field_densities,
+  hydro_logger_field_entropies,
+  hydro_logger_field_pressures,
+  hydro_logger_field_viscosity_diffusion,
+  hydro_logger_field_velocity_divergences,
+  hydro_logger_field_count,
+};
+
+/* Name of each possible mask. */
+static const char *hydro_logger_field_names[hydro_logger_field_count] = {
+    "Coordinates", "Velocities",         "Accelerations",
+    "Masses",      "SmoothingLengths",   "InternalEnergies",
+    "ParticleIDs", "Densities",          "Entropies",
+    "Pressures",   "ViscosityDiffusion", "VelocityDivergences",
+};
+
+/**
+ * @brief Initialize the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int hydro_logger_writer_populate_mask_data(
+    struct mask_data *mask_data) {
+  mask_data[hydro_logger_field_coordinates] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_coordinates],
+      3 * sizeof(double));
+
+  mask_data[hydro_logger_field_velocities] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_velocities],
+      3 * sizeof(float));
+
+  mask_data[hydro_logger_field_accelerations] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_accelerations],
+      3 * sizeof(float));
+
+  mask_data[hydro_logger_field_masses] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_masses], sizeof(float));
+
+  mask_data[hydro_logger_field_smoothing_lengths] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_smoothing_lengths],
+      sizeof(float));
+
+  mask_data[hydro_logger_field_internal_energies] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_internal_energies],
+      sizeof(float));
+
+  mask_data[hydro_logger_field_particle_ids] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_particle_ids],
+      sizeof(long long));
+
+  mask_data[hydro_logger_field_densities] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_densities], sizeof(float));
+
+  mask_data[hydro_logger_field_entropies] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_entropies], sizeof(float));
+
+  mask_data[hydro_logger_field_pressures] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_pressures], sizeof(float));
+
+  mask_data[hydro_logger_field_viscosity_diffusion] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_viscosity_diffusion],
+      3 * sizeof(float));
+
+  mask_data[hydro_logger_field_velocity_divergences] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_velocity_divergences],
+      2 * sizeof(float));
+
+  return hydro_logger_field_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields!
+ *
+ * @param masks The list of masks (same order than in #hydro_logger_init).
+ * @param part The #part that will be written.
+ * @param xpart The #xpart that will be written.
+ * @param write_all Are we forcing to write all the fields?
+ *
+ * @param buffer_size (out) The requested size for the buffer.
+ * @param mask (out) The mask that will be written.
+ */
+INLINE static void hydro_logger_compute_size_and_mask(
+    const struct mask_data *masks, const struct part *part,
+    const struct xpart *xpart, const int write_all, size_t *buffer_size,
+    unsigned int *mask) {
+
+  /* Here you can decide your own writing logic */
+
+  /* Add the coordinates. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_coordinates],
+                                    buffer_size);
+
+  /* Add the velocities. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_velocities],
+                                    buffer_size);
+
+  /* Add the accelerations. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_accelerations],
+                                    buffer_size);
+
+  /* Add the masses. */
+  *mask |=
+      logger_add_field_to_mask(masks[hydro_logger_field_masses], buffer_size);
+
+  /* Add the smoothing lengths. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_smoothing_lengths],
+                                    buffer_size);
+
+  /* Add the energies. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_internal_energies],
+                                    buffer_size);
+
+  /* Add the ID. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_particle_ids],
+                                    buffer_size);
+
+  /* Add the density. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_densities],
+                                    buffer_size);
+
+  /* Add the entropies. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_entropies],
+                                    buffer_size);
+
+  /* Add the pressures. */
+  *mask |= logger_add_field_to_mask(masks[hydro_logger_field_pressures],
+                                    buffer_size);
+
+  /* Add the viscosity / diffusion. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_viscosity_diffusion], buffer_size);
+
+  /* Add the velocity divergences + derivative. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_velocity_divergences], buffer_size);
+}
+
+/**
+ * @brief Write a particle to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields!
+ *
+ * @param masks The list of masks (same order than in #hydro_logger_init).
+ * @param p The #part to write.
+ * @param xp The #xpart to write.
+ * @param mask The mask to use for this record.
+ * @param buff The buffer where to write the particle.
+ *
+ * @return The buffer after the data.
+ */
+INLINE static char *hydro_logger_write_particle(
+    const struct mask_data *mask_data, const struct part *p,
+    const struct xpart *xp, unsigned int *mask, char *buff) {
+
+  /* Write the coordinate. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_coordinates],
+                                mask)) {
+    memcpy(buff, p->x, 3 * sizeof(double));
+    buff += 3 * sizeof(double);
+  }
+
+  /* Write the velocity. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_velocities],
+                                mask)) {
+    memcpy(buff, p->v, 3 * sizeof(float));
+    buff += 3 * sizeof(float);
+  }
+
+  /* Write the acceleration. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_accelerations],
+                                mask)) {
+
+    /* Compute the acceleration due to hydro and gravity */
+    float *acc = (float *)buff;
+    acc[0] = p->a_hydro[0];
+    acc[1] = p->a_hydro[1];
+    acc[2] = p->a_hydro[2];
+    if (p->gpart) {
+      acc[0] += p->gpart->a_grav[0];
+      acc[1] += p->gpart->a_grav[1];
+      acc[2] += p->gpart->a_grav[2];
+    }
+
+    memcpy(buff, acc, 3 * sizeof(float));
+    buff += 3 * sizeof(float);
+  }
+
+  /* Write the mass. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_masses], mask)) {
+    memcpy(buff, &p->mass, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the smoothing length. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_smoothing_lengths],
+                                mask)) {
+    memcpy(buff, &p->h, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the energy. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_internal_energies],
+                                mask)) {
+    memcpy(buff, &p->u, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the Id. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_particle_ids],
+                                mask)) {
+    memcpy(buff, &p->id, sizeof(long long));
+    buff += sizeof(long long);
+  }
+
+  /* Write the density. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_densities],
+                                mask)) {
+    memcpy(buff, &p->rho, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the entropy. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_entropies],
+                                mask)) {
+    const float entropy = hydro_get_comoving_entropy(p, xp);
+    memcpy(buff, &entropy, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the pressures. */
+  if (logger_should_write_field(mask_data[hydro_logger_field_pressures],
+                                mask)) {
+    const float pressure = hydro_get_comoving_pressure(p);
+    memcpy(buff, &pressure, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the viscosity / diffusion. */
+  if (logger_should_write_field(
+          mask_data[hydro_logger_field_viscosity_diffusion], mask)) {
+    const float coef[3] = {p->viscosity.alpha * p->force.balsara,
+                           p->diffusion.alpha, p->diffusion.laplace_u};
+    memcpy(buff, coef, sizeof(coef));
+    buff += sizeof(coef);
+  }
+
+  /* Write the velocity divergence. */
+  if (logger_should_write_field(
+          mask_data[hydro_logger_field_velocity_divergences], mask)) {
+    const float div[2] = {
+        p->viscosity.div_v,
+        p->viscosity.div_v_dt,
+    };
+    memcpy(buff, div, sizeof(div));
+    buff += sizeof(div);
+  }
+
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_SPHENIX_HYDRO_LOGGER_H
diff --git a/src/hydro/SPHENIX/hydro_part.h b/src/hydro/SPHENIX/hydro_part.h
index 5904dfadeb1403181a6b6040795b3fc49d9bc433..836d5166c679b08085ba74fc69b39cba165e7d5c 100644
--- a/src/hydro/SPHENIX/hydro_part.h
+++ b/src/hydro/SPHENIX/hydro_part.h
@@ -30,6 +30,7 @@
 #include "chemistry_struct.h"
 #include "cooling_struct.h"
 #include "feedback_struct.h"
+#include "logger.h"
 #include "particle_splitting_struct.h"
 #include "pressure_floor_struct.h"
 #include "star_formation_struct.h"
@@ -75,6 +76,11 @@ struct xpart {
   /* Additional data used by the feedback */
   struct feedback_part_data feedback_data;
 
+#ifdef WITH_LOGGER
+  /* Additional data for the particle logger */
+  struct logger_part_data logger_data;
+#endif
+
 } SWIFT_STRUCT_ALIGN;
 
 /**
diff --git a/src/hydro_io.h b/src/hydro_io.h
index 60934acb41a7da337efc68b2f2d77de1f35533c5..75bb63cb9b7dba157b2069347046842e733d91d2 100644
--- a/src/hydro_io.h
+++ b/src/hydro_io.h
@@ -27,7 +27,6 @@
 #include "./hydro/Minimal/hydro_io.h"
 #elif defined(GADGET2_SPH)
 #include "./hydro/Gadget2/hydro_io.h"
-#include "./hydro/Gadget2/hydro_logger.h"
 #elif defined(HOPKINS_PE_SPH)
 #include "./hydro/PressureEntropy/hydro_io.h"
 #elif defined(HOPKINS_PU_SPH)
diff --git a/src/hydro_logger.h b/src/hydro_logger.h
index 503a3b4acab6dae349694009943088e4056945b0..a4fef3617ef6c76fc7bdfcee37ad492392a351ca 100644
--- a/src/hydro_logger.h
+++ b/src/hydro_logger.h
@@ -48,7 +48,7 @@
 #elif defined(PLANETARY_SPH)
 #error TODO
 #elif defined(SPHENIX_SPH)
-#error TODO
+#include "./hydro/SPHENIX/hydro_logger.h"
 #elif defined(ANARCHY_PU_SPH)
 #error TODO
 #else
diff --git a/src/logger.c b/src/logger.c
index be462bcfe58bf78c3f571bb1c03648604789cbd6..f9c0b407ac3e5d521f092bb213b17ddbfc74b3d1 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -38,13 +38,14 @@
 #include "logger.h"
 
 /* Local headers. */
+#include "active.h"
 #include "atomic.h"
 #include "dump.h"
 #include "engine.h"
 #include "error.h"
 #include "gravity_logger.h"
-#include "hydro_io.h"
-#include "stars_io.h"
+#include "hydro_logger.h"
+#include "stars_logger.h"
 #include "units.h"
 
 /*
@@ -127,6 +128,7 @@ void logger_write_data(struct dump *d, size_t *offset, size_t size,
 /**
  * @brief log all particles in the engine.
  *
+ * TODO use threadpool + logger function for multiple particles.
  * @param log The #logger_writer
  * @param e The #engine
  */
@@ -140,18 +142,37 @@ void logger_log_all_particles(struct logger_writer *log,
   const struct space *s = e->s;
 
   /* log the parts. */
-  logger_log_parts(log, s->parts, s->xparts, s->nr_parts, e,
-                   /* log_all_fields= */ 1, /* flag= */ 0, /* flag_data= */ 0);
+  for (size_t i = 0; i < s->nr_parts; i++) {
+    struct part *p = &s->parts[i];
+    struct xpart *xp = &s->xparts[i];
+    if (!part_is_inhibited(p, e) && p->time_bin != time_bin_not_created) {
+      logger_log_part(log, p, xp, e,
+                      /* log_all_fields */ 1, /* Special flags */ 0,
+                      /* data */ 0);
+    }
+  }
 
   /* log the gparts */
-  logger_log_gparts(log, s->gparts, s->nr_gparts, e,
-                    /* log_all_fields= */ 1, /* flag= */ 0,
-                    /* flag_data= */ 0);
+  for (size_t i = 0; i < s->nr_gparts; i++) {
+    struct gpart *gp = &s->gparts[i];
+    if (!gpart_is_inhibited(gp, e) && gp->time_bin != time_bin_not_created &&
+        (gp->type == swift_type_dark_matter ||
+         gp->type == swift_type_dark_matter_background)) {
+      logger_log_gpart(log, gp, e,
+                       /* log_all_fields */ 1, /* Special flags */ 0,
+                       /* data */ 0);
+    }
+  }
 
   /* log the parts */
-  logger_log_sparts(log, s->sparts, s->nr_sparts, e,
-                    /* log_all_fields= */ 1, /* flag= */ 0,
-                    /* flag_data= */ 0);
+  for (size_t i = 0; i < s->nr_sparts; i++) {
+    struct spart *sp = &s->sparts[i];
+    if (!spart_is_inhibited(sp, e) && sp->time_bin != time_bin_not_created) {
+      logger_log_spart(log, sp, e,
+                       /* log_all_fields */ 1, /* Special flags */ 0,
+                       /* data */ 0);
+    }
+  }
 
   if (e->total_nr_bparts > 0) error("Not implemented");
 }
@@ -184,10 +205,6 @@ void logger_copy_part_fields(const struct logger_writer *log,
   /* Write the header. */
   buff = logger_write_record_header(buff, &mask, offset, offset_new);
 
-  /* Write the hydro fields */
-  buff = hydro_logger_write_particle(log->mask_data_pointers.hydro, p, xp,
-                                     &mask, buff);
-
   /* Special flags */
   if (mask & log->logger_mask_data[logger_index_special_flags].mask) {
     memcpy(buff, &special_flags,
@@ -196,6 +213,10 @@ void logger_copy_part_fields(const struct logger_writer *log,
     mask &= ~log->logger_mask_data[logger_index_special_flags].mask;
   }
 
+  /* Write the hydro fields */
+  buff = hydro_logger_write_particle(log->mask_data_pointers.hydro, p, xp,
+                                     &mask, buff);
+
 #ifdef SWIFT_DEBUG_CHECKS
   if (mask) {
     error("Requested logging of values not present in parts. %u", mask);
@@ -243,18 +264,27 @@ void logger_log_parts(struct logger_writer *log, const struct part *p,
                       const int flag_data) {
 
   /* Build the special flag */
+  const int size_special_flag =
+      log->logger_mask_data[logger_index_special_flags].size;
   const uint32_t special_flags = logger_pack_flags_and_data(flag, flag_data);
 
   /* Compute the size of the buffer. */
   size_t size_total = 0;
   if (log_all_fields) {
-    size_total = count * (log->max_size_record_part + logger_header_bytes);
+    size_t size = log->max_size_record_part + logger_header_bytes;
+    if (flag != 0) {
+      size += size_special_flag;
+    }
+    size_total = count * size;
   } else {
     for (int i = 0; i < count; i++) {
       unsigned int mask = 0;
       size_t size = 0;
       hydro_logger_compute_size_and_mask(log->mask_data_pointers.hydro, &p[i],
                                          &xp[i], log_all_fields, &size, &mask);
+      if (flag != 0) {
+        size += size_special_flag;
+      }
       size_total += size + logger_header_bytes;
     }
   }
@@ -272,8 +302,14 @@ void logger_log_parts(struct logger_writer *log, const struct part *p,
                                        &xp[i], log_all_fields, &size, &mask);
     size += logger_header_bytes;
 
-    if (special_flags != 0) {
+    /* Add the special flag. */
+    if (flag != 0) {
       mask |= log->logger_mask_data[logger_index_special_flags].mask;
+      size += size_special_flag;
+      /* reset the offset of the previous log */
+      if (flag == logger_flag_create || flag == logger_flag_mpi_enter) {
+        xp[i].logger_data.last_offset = 0;
+      }
     }
 
     /* Copy everything into the buffer */
@@ -281,22 +317,21 @@ void logger_log_parts(struct logger_writer *log, const struct part *p,
                             &xp[i].logger_data.last_offset, offset_new, buff,
                             special_flags);
 
-    /* Write the particle into the history if needed. */
-    if (flag & logger_flag_create || flag & logger_flag_mpi_enter) {
-      logger_history_log(&log->history_new[swift_type_gas], p->id,
-                         xp->logger_data.last_offset);
-
-    } else if (flag & logger_flag_change_type || flag & logger_flag_delete ||
-               flag & logger_flag_mpi_exit) {
-      logger_history_log(&log->history_removed[swift_type_gas], p->id,
-                         xp->logger_data.last_offset);
-    }
-
     /* Update the pointers */
     xp[i].logger_data.last_offset = offset_new;
     xp[i].logger_data.steps_since_last_output = 0;
     buff += size;
     offset_new += size;
+
+    /* Write the particle into the history if needed. */
+    if (flag == logger_flag_create || flag == logger_flag_mpi_enter) {
+      logger_history_log(&log->history_new[swift_type_gas], p[i].id,
+                         xp[i].logger_data.last_offset);
+    } else if (flag == logger_flag_change_type || flag == logger_flag_delete ||
+               flag == logger_flag_mpi_exit) {
+      logger_history_log(&log->history_removed[swift_type_gas], p[i].id,
+                         xp[i].logger_data.last_offset);
+    }
   }
 }
 
@@ -327,10 +362,6 @@ void logger_copy_spart_fields(const struct logger_writer *log,
   /* Write the header. */
   buff = logger_write_record_header(buff, &mask, offset, offset_new);
 
-  /* Write the stellar fields */
-  buff = stars_logger_write_particle(log->mask_data_pointers.stars, sp, &mask,
-                                     buff);
-
   /* Special flags */
   if (mask & log->logger_mask_data[logger_index_special_flags].mask) {
     memcpy(buff, &special_flags,
@@ -339,6 +370,9 @@ void logger_copy_spart_fields(const struct logger_writer *log,
     mask &= ~log->logger_mask_data[logger_index_special_flags].mask;
   }
 
+  /* Write the stellar fields */
+  buff = stars_logger_write_particle(log->mask_data_pointers.stars, sp, &mask,
+                                     buff);
 #ifdef SWIFT_DEBUG_CHECKS
   if (mask) {
     error("Requested logging of values not present in sparts. %u", mask);
@@ -380,18 +414,27 @@ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
                        const enum logger_special_flags flag,
                        const int flag_data) {
   /* Build the special flag */
+  const int size_special_flag =
+      log->logger_mask_data[logger_index_special_flags].size;
   const uint32_t special_flags = logger_pack_flags_and_data(flag, flag_data);
 
   /* Compute the size of the buffer. */
   size_t size_total = 0;
   if (log_all_fields) {
-    size_total = count * (log->max_size_record_spart + logger_header_bytes);
+    size_t size = log->max_size_record_spart + logger_header_bytes;
+    if (flag != 0) {
+      size += size_special_flag;
+    }
+    size_total = count * size;
   } else {
     for (int i = 0; i < count; i++) {
       unsigned int mask = 0;
       size_t size = 0;
       stars_logger_compute_size_and_mask(log->mask_data_pointers.stars, &sp[i],
                                          log_all_fields, &size, &mask);
+      if (flag != 0) {
+        size += size_special_flag;
+      }
       size_total += size + logger_header_bytes;
     }
   }
@@ -408,8 +451,15 @@ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
                                        log_all_fields, &size, &mask);
     size += logger_header_bytes;
 
-    if (special_flags != 0) {
+    /* Add the special flag. */
+    if (flag != 0) {
       mask |= log->logger_mask_data[logger_index_special_flags].mask;
+      size += size_special_flag;
+
+      /* reset the offset of the previous log */
+      if (flag == logger_flag_create || flag == logger_flag_mpi_enter) {
+        sp[i].logger_data.last_offset = 0;
+      }
     }
 
     /* Copy everything into the buffer */
@@ -417,22 +467,21 @@ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
                              &sp[i].logger_data.last_offset, offset_new, buff,
                              special_flags);
 
-    /* Write the particle into the history if needed. */
-    if (flag & logger_flag_create || flag & logger_flag_mpi_enter) {
-      logger_history_log(&log->history_new[swift_type_stars], sp->id,
-                         sp->logger_data.last_offset);
-
-    } else if (flag & logger_flag_change_type || flag & logger_flag_delete ||
-               flag & logger_flag_mpi_exit) {
-      logger_history_log(&log->history_removed[swift_type_stars], sp->id,
-                         sp->logger_data.last_offset);
-    }
-
     /* Update the pointers */
     sp[i].logger_data.last_offset = offset_new;
     sp[i].logger_data.steps_since_last_output = 0;
     buff += size;
     offset_new += size;
+
+    /* Write the particle into the history if needed. */
+    if (flag == logger_flag_create || flag == logger_flag_mpi_enter) {
+      logger_history_log(&log->history_new[swift_type_stars], sp[i].id,
+                         sp[i].logger_data.last_offset);
+    } else if (flag == logger_flag_change_type || flag == logger_flag_delete ||
+               flag == logger_flag_mpi_exit) {
+      logger_history_log(&log->history_removed[swift_type_stars], sp[i].id,
+                         sp[i].logger_data.last_offset);
+    }
   }
 }
 
@@ -463,10 +512,6 @@ void logger_copy_gpart_fields(const struct logger_writer *log,
   /* Write the header. */
   buff = logger_write_record_header(buff, &mask, offset, offset_new);
 
-  /* Write the hydro fields */
-  buff = gravity_logger_write_particle(log->mask_data_pointers.gravity, gp,
-                                       &mask, buff);
-
   /* Special flags */
   if (mask & log->logger_mask_data[logger_index_special_flags].mask) {
     memcpy(buff, &special_flags,
@@ -475,6 +520,10 @@ void logger_copy_gpart_fields(const struct logger_writer *log,
     mask &= ~log->logger_mask_data[logger_index_special_flags].mask;
   }
 
+  /* Write the gravity fields */
+  buff = gravity_logger_write_particle(log->mask_data_pointers.gravity, gp,
+                                       &mask, buff);
+
 #ifdef SWIFT_DEBUG_CHECKS
   if (mask) {
     error("Requested logging of values not present in gparts. %u", mask);
@@ -515,21 +564,32 @@ void logger_log_gparts(struct logger_writer *log, struct gpart *p, int count,
                        const enum logger_special_flags flag,
                        const int flag_data) {
   /* Build the special flag */
+  const int size_special_flag =
+      log->logger_mask_data[logger_index_special_flags].size;
   const uint32_t special_flags = logger_pack_flags_and_data(flag, flag_data);
 
   /* Compute the size of the buffer. */
   size_t size_total = 0;
   if (log_all_fields) {
-    size_total = count * (log->max_size_record_gpart + logger_header_bytes);
+    size_t size = log->max_size_record_gpart + logger_header_bytes;
+    if (flag != 0) {
+      size += size_special_flag;
+    }
+    size_total = count * size;
   } else {
     for (int i = 0; i < count; i++) {
       /* Log only the dark matter */
-      if (p[i].type != swift_type_dark_matter) continue;
+      if (p[i].type != swift_type_dark_matter &&
+          p[i].type != swift_type_dark_matter_background)
+        continue;
 
       unsigned int mask = 0;
       size_t size = 0;
       gravity_logger_compute_size_and_mask(log->mask_data_pointers.gravity,
                                            &p[i], log_all_fields, &size, &mask);
+      if (flag != 0) {
+        size += size_special_flag;
+      }
       size_total += size + logger_header_bytes;
     }
   }
@@ -540,7 +600,9 @@ void logger_log_gparts(struct logger_writer *log, struct gpart *p, int count,
 
   for (int i = 0; i < count; i++) {
     /* Log only the dark matter */
-    if (p[i].type != swift_type_dark_matter) continue;
+    if (p[i].type != swift_type_dark_matter &&
+        p[i].type != swift_type_dark_matter_background)
+      continue;
 
     /* Get the masks */
     size_t size = 0;
@@ -549,30 +611,36 @@ void logger_log_gparts(struct logger_writer *log, struct gpart *p, int count,
                                          log_all_fields, &size, &mask);
     size += logger_header_bytes;
 
-    if (special_flags != 0) {
+    /* Add the special flag. */
+    if (flag != 0) {
       mask |= log->logger_mask_data[logger_index_special_flags].mask;
+      size += size_special_flag;
+
+      /* reset the offset of the previous log */
+      if (flag == logger_flag_create || flag == logger_flag_mpi_enter) {
+        p[i].logger_data.last_offset = 0;
+      }
     }
 
     /* Copy everything into the buffer */
     logger_copy_gpart_fields(log, &p[i], e, mask, &p[i].logger_data.last_offset,
                              offset_new, buff, special_flags);
 
-    /* Write the particle into the history if needed. */
-    if (flag & logger_flag_create || flag & logger_flag_mpi_enter) {
-      logger_history_log(&log->history_new[swift_type_dark_matter],
-                         p->id_or_neg_offset, p->logger_data.last_offset);
-
-    } else if (flag & logger_flag_change_type || flag & logger_flag_delete ||
-               flag & logger_flag_mpi_exit) {
-      logger_history_log(&log->history_removed[swift_type_dark_matter],
-                         p->id_or_neg_offset, p->logger_data.last_offset);
-    }
-
     /* Update the pointers */
     p[i].logger_data.last_offset = offset_new;
     p[i].logger_data.steps_since_last_output = 0;
     buff += size;
     offset_new += size;
+
+    /* Write the particle into the history if needed. */
+    if (flag == logger_flag_create || flag == logger_flag_mpi_enter) {
+      logger_history_log(&log->history_new[swift_type_dark_matter],
+                         p[i].id_or_neg_offset, p[i].logger_data.last_offset);
+    } else if (flag == logger_flag_change_type || flag == logger_flag_delete ||
+               flag == logger_flag_mpi_exit) {
+      logger_history_log(&log->history_removed[swift_type_dark_matter],
+                         p[i].id_or_neg_offset, p[i].logger_data.last_offset);
+    }
   }
 }
 
@@ -873,7 +941,7 @@ void logger_init(struct logger_writer *log, const struct engine *e,
   const float max_memory_size =
       parser_get_opt_param_float(params, "Logger:maximal_memory_size", 1.);
   log->maximal_size_history =
-      max_memory_size / sizeof(struct logger_index_data);
+      1e9 * max_memory_size / sizeof(struct logger_index_data);
 
   if (e->nodeID == 0) {
     message("Maximal memory size for the logger history: %g GB",
diff --git a/src/logger.h b/src/logger.h
index c2810219f7f8dc4ba695ab1df6edf433a442be65..646fc901842176882761292d88fa000a01553fad 100644
--- a/src/logger.h
+++ b/src/logger.h
@@ -44,6 +44,15 @@ struct engine;
 /* Size of the strings. */
 #define logger_string_length 200
 
+/*
+ * The two following defines need to correspond to the list's order
+ * in logger_init_masks.
+ */
+/* Index of the special flags in the list of masks */
+#define logger_index_special_flags 0
+/* Index of the timestamp in the list of masks */
+#define logger_index_timestamp 1
+
 /**
  * Logger entries contain messages representing the particle data at a given
  * point in time during the simulation.
diff --git a/src/logger_io.c b/src/logger_io.c
index 178df2a9b7384c8e64f789368390ffdf4a005a02..6e444aeae904a6511244fcdc4f55760a044471c8 100644
--- a/src/logger_io.c
+++ b/src/logger_io.c
@@ -167,6 +167,8 @@ void logger_write_history(struct logger_history* history, struct engine* e,
  */
 void logger_write_index_file(struct logger_writer* log, struct engine* e) {
 
+  const int with_DM_background = e->s->with_DM_background;
+
   struct part* parts = e->s->parts;
   struct xpart* xparts = e->s->xparts;
   struct gpart* gparts = e->s->gparts;
@@ -178,6 +180,15 @@ void logger_write_index_file(struct logger_writer* log, struct engine* e) {
   const size_t Nstars = e->s->nr_sparts;
   /* const size_t Nblackholes = e->s->nr_bparts; */
 
+  if (e->s->nr_sinks != 0) {
+    error("Sink particles are not implemented");
+  }
+
+  size_t Ndm_background = 0;
+  if (with_DM_background) {
+    Ndm_background = io_count_dm_background_gparts(gparts, Ntot);
+  }
+
   /* Number of particles that we will write */
   const size_t Ntot_written =
       e->s->nr_gparts - e->s->nr_inhibited_gparts - e->s->nr_extra_gparts;
@@ -190,11 +201,12 @@ void logger_write_index_file(struct logger_writer* log, struct engine* e) {
   const size_t Nbaryons_written =
       Ngas_written + Nstars_written + Nblackholes_written;
   const size_t Ndm_written =
-      Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0;
+      Ntot_written > 0 ? Ntot_written - Nbaryons_written - Ndm_background : 0;
 
   /* Format things in a Gadget-friendly array */
   uint64_t N_total[swift_type_count] = {
-      (uint64_t)Ngas_written,   (uint64_t)Ndm_written,        0, 0,
+      (uint64_t)Ngas_written,   (uint64_t)Ndm_written,
+      (uint64_t)Ndm_background, 0,
       (uint64_t)Nstars_written, (uint64_t)Nblackholes_written};
 
   /* File name */
@@ -212,7 +224,11 @@ void logger_write_index_file(struct logger_writer* log, struct engine* e) {
   }
 
   /* Write double time */
-  fwrite(&e->time, sizeof(double), 1, f);
+  if (e->policy & engine_policy_cosmology) {
+    fwrite(&e->cosmology->a, sizeof(double), 1, f);
+  } else {
+    fwrite(&e->time, sizeof(double), 1, f);
+  }
 
   /* Write integer time */
   fwrite(&e->ti_current, sizeof(integertime_t), 1, f);
@@ -314,6 +330,27 @@ void logger_write_index_file(struct logger_writer* log, struct engine* e) {
         }
         break;
 
+      case swift_type_dark_matter_background: {
+
+        /* Ok, we need to fish out the particles we want */
+        N = Ndm_background;
+
+        /* Allocate temporary array */
+        if (swift_memalign("gparts_written", (void**)&gparts_written,
+                           gpart_align,
+                           Ndm_background * sizeof(struct gpart)) != 0)
+          error("Error while allocating temporary memory for gparts");
+
+        /* Collect the non-inhibited DM particles from gpart */
+        const int with_stf = 0;
+        io_collect_gparts_background_to_write(
+            gparts, e->s->gpart_group_data, gparts_written,
+            gpart_group_data_written, Ntot, Ndm_background, with_stf);
+
+        /* Select the fields to write */
+        num_fields += darkmatter_write_index(gparts_written, list);
+      } break;
+
       case swift_type_stars:
         if (Nstars == Nstars_written) {
 
diff --git a/src/runner_others.c b/src/runner_others.c
index 479da517a7e435d91161ba4397d7acda9dbd76fe..e0420324d5b9c2ccb9505918bc6667cfbe66c821 100644
--- a/src/runner_others.c
+++ b/src/runner_others.c
@@ -278,14 +278,6 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) {
           if (star_formation_should_convert_to_star(p, xp, sf_props, e,
                                                     dt_star)) {
 
-#ifdef WITH_LOGGER
-            /* Write the particle */
-            /* Logs all the fields request by the user */
-            // TODO select only the requested fields
-            logger_log_part(e->logger, p, xp, e, /* log_all */ 1,
-                            logger_flag_change_type, swift_type_stars);
-#endif
-
             /* Convert the gas particle to a star particle */
             struct spart *sp = NULL;
             const int spawn_spart =
@@ -301,6 +293,13 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) {
               } else {
                 /* Convert the gas particle to a star particle */
                 sp = cell_convert_part_to_spart(e, c, p, xp);
+#ifdef WITH_LOGGER
+                /* Write the particle */
+                /* Logs all the fields request by the user */
+                // TODO select only the requested fields
+                logger_log_part(e->logger, p, xp, e, /* log_all */ 1,
+                                logger_flag_change_type, swift_type_stars);
+#endif
               }
 
             } else {
@@ -343,8 +342,13 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) {
               }
 
 #ifdef WITH_LOGGER
-              /* Copy the properties back to the stellar particle */
-              sp->logger_data = xp->logger_data;
+              if (spawn_spart) {
+                /* Set to zero the logger data. */
+                logger_part_data_init(&sp->logger_data);
+              } else {
+                /* Copy the properties back to the stellar particle */
+                sp->logger_data = xp->logger_data;
+              }
 
               /* Write the s-particle */
               logger_log_spart(e->logger, sp, e, /* log_all */ 1,
@@ -769,7 +773,9 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) {
       struct gpart *restrict gp = &gparts[k];
 
       /* Write only the dark matter particles */
-      if (gp->type != swift_type_dark_matter) continue;
+      if (gp->type != swift_type_dark_matter &&
+          gp->type != swift_type_dark_matter_background)
+        continue;
 
       /* If particle needs to be log */
       if (gpart_is_active(gp, e)) {
diff --git a/src/stars_io.h b/src/stars_io.h
index 6cf92eac91c2eca09070864a8410ac720cc2ee5b..18224b1ef9a189c719d3674a037eb4b26cd14d4e 100644
--- a/src/stars_io.h
+++ b/src/stars_io.h
@@ -27,7 +27,6 @@
 #include "./stars/const/stars_io.h"
 #elif defined(STARS_NONE)
 #include "./stars/Default/stars_io.h"
-#include "./stars/Default/stars_logger.h"
 #elif defined(STARS_EAGLE)
 #include "./stars/EAGLE/stars_io.h"
 #elif defined(STARS_GEAR)
diff --git a/tools/read_index_file.py b/tools/read_index_file.py
index 96ab1df2e7e8426b5c84e3822b8fb6a05aabfd46..51fdec59208e10e62ba5293f23e72674866cffe1 100644
--- a/tools/read_index_file.py
+++ b/tools/read_index_file.py
@@ -51,7 +51,6 @@ with open(filename, "rb") as f:
             continue
 
         data = np.fromfile(f, dtype=dt, count=n)
-
         print("\t", data)
 
     # print the history of particles removed
@@ -63,5 +62,4 @@ with open(filename, "rb") as f:
             continue
 
         data = np.fromfile(f, dtype=dt, count=n)
-
         print("\t", data)