diff --git a/configure.ac b/configure.ac
index ac4a3e8f19c27b157ab0522862de645d2882e03d..9a287fdeee304274d084ace0457da2fe022f1132 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1129,6 +1129,7 @@ if test "x$with_python" != "xno"; then
       AC_MSG_RESULT([$PYTHON_INCS])
   ])
   have_python="yes"
+  AC_DEFINE([HAVE_PYTHON],1,[Python appears to be present.])
 fi
 AC_SUBST([PYTHON_INCS])
 AM_CONDITIONAL([HAVEPYTHON],[test -n "$PYTHON_INCS"])
diff --git a/examples/main.c b/examples/main.c
index 63a7aa511559282e5e68406673132927e7770b4b..cb9b0b273cc0cd759831805ead7dfcf2e83b92ff 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -1362,7 +1362,7 @@ int main(int argc, char *argv[]) {
     /* Write the state of the system before starting time integration. */
 #ifdef WITH_LOGGER
     if (e.policy & engine_policy_logger) {
-      logger_log_all(e.logger, &e);
+      logger_log_all_particles(e.logger, &e);
       engine_dump_index(&e);
     }
 #endif
@@ -1568,7 +1568,7 @@ int main(int argc, char *argv[]) {
     }
 #ifdef WITH_LOGGER
     if (e.policy & engine_policy_logger) {
-      logger_log_all(e.logger, &e);
+      logger_log_all_particles(e.logger, &e);
 
       /* Write a final index file */
       engine_dump_index(&e);
diff --git a/logger/logger_python_wrapper.c b/logger/logger_python_wrapper.c
index 48973daf969b605b1deed4c55739ad008dbe6df6..b8fd89b17e555cbc0ed6b03c2e46c645a5780da1 100644
--- a/logger/logger_python_wrapper.c
+++ b/logger/logger_python_wrapper.c
@@ -22,6 +22,7 @@
 #include "logger_reader.h"
 #include "logger_time.h"
 
+#ifdef HAVE_PYTHON
 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
 
 #include <Python.h>
@@ -447,3 +448,5 @@ PyMODINIT_FUNC PyInit_liblogger(void) {
 
   return m;
 }
+
+#endif // HAVE_PYTHON
diff --git a/logger/logger_tools.h b/logger/logger_tools.h
index 21a59e42fca144a0381b15e8771ca14ceed46b33..6974f9888d3ebbd9a8f2922ff24d23db4d68f6aa 100644
--- a/logger/logger_tools.h
+++ b/logger/logger_tools.h
@@ -29,6 +29,7 @@
 #include "../src/error.h"
 #include "../src/inline.h"
 #include "../src/logger.h"
+#include "../src/logger_io.h"
 #include "../src/part_type.h"
 
 #ifdef HAVE_PYTHON
diff --git a/src/Makefile.am b/src/Makefile.am
index 80ee17d5f03d6b00dd769c5e500a66520026d465..50dc74ce1df54426d79a9d58a881b27c91c4ab03 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -135,7 +135,8 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
 		 gravity/Potential/gravity.h gravity/Potential/gravity_iact.h gravity/Potential/gravity_io.h \
 		 gravity/Potential/gravity_debug.h gravity/Potential/gravity_part.h  \
 		 gravity/MultiSoftening/gravity.h gravity/MultiSoftening/gravity_iact.h gravity/MultiSoftening/gravity_io.h \
-		 gravity/MultiSoftening/gravity_debug.h gravity/MultiSoftening/gravity_part.h  \
+		 gravity/MultiSoftening/gravity_debug.h gravity/MultiSoftening/gravity_part.h \
+     gravity/MultiSoftening/gravity_logger.h \
 		 equation_of_state.h \
 		 equation_of_state/ideal_gas/equation_of_state.h equation_of_state/isothermal/equation_of_state.h \
 	 	 hydro.h hydro_io.h hydro_parameters.h \
@@ -147,7 +148,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
 		 hydro/Default/hydro_parameters.h \
 		 hydro/Gadget2/hydro.h hydro/Gadget2/hydro_iact.h hydro/Gadget2/hydro_io.h \
                  hydro/Gadget2/hydro_debug.h hydro/Gadget2/hydro_part.h \
-		 hydro/Gadget2/hydro_parameters.h \
+     hydro/Gadget2/hydro_parameters.h hydro/Gadget2/hydro_logger.h \
 		 hydro/PressureEntropy/hydro.h hydro/PressureEntropy/hydro_iact.h hydro/PressureEntropy/hydro_io.h \
                  hydro/PressureEntropy/hydro_debug.h hydro/PressureEntropy/hydro_part.h \
 		 hydro/PressureEntropy/hydro_parameters.h \
@@ -209,7 +210,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
                  riemann/riemann_checks.h \
 	 	 stars.h stars_io.h \
 		 stars/Default/stars.h stars/Default/stars_iact.h stars/Default/stars_io.h \
-		 stars/Default/stars_debug.h stars/Default/stars_part.h  \
+     stars/Default/stars_debug.h stars/Default/stars_part.h stars/Default/stars_logger.h  \
 		 stars/EAGLE/stars.h stars/EAGLE/stars_iact.h stars/EAGLE/stars_io.h \
 		 stars/EAGLE/stars_debug.h stars/EAGLE/stars_part.h \
 		 stars/GEAR/stars.h stars/GEAR/stars_iact.h stars/GEAR/stars_io.h \
@@ -293,7 +294,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
 		 pressure_floor/GEAR/pressure_floor_iact.h pressure_floor/none/pressure_floor_iact.h \
 		 pressure_floor/GEAR/pressure_floor_struct.h pressure_floor/none/pressure_floor_struct.h \
 	         task_order/GEAR/task_order.h task_order/EAGLE/task_order.h task_order/default/task_order.h \
-		 sink/Default/sink.h sink/Default/sink_io.h sink/Default/sink_part.h \
+     sink/Default/sink.h sink/Default/sink_io.h sink/Default/sink_part.h \
 		 sink.h sink_io.h
 
 
diff --git a/src/cell.c b/src/cell.c
index fdc787a21a2caf178c5bbfd91ee6a5c4d7a51e01..784d9e08aa5cee81a89658644c59dd6807840101 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -4883,6 +4883,15 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
            * by another thread before we do the deed. */
           if (!part_is_inhibited(p, e)) {
 
+#ifdef WITH_LOGGER
+            if (e->policy & engine_policy_logger) {
+              /* Log the particle one last time. */
+              logger_log_part(
+                  e->logger, p, xp, e, /* log_all */ 1,
+                  logger_pack_flags_and_data(logger_flag_delete, 0));
+            }
+#endif
+
             /* One last action before death? */
             hydro_remove_part(p, xp);
 
@@ -5053,6 +5062,17 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
 
             /* Remove the particle entirely */
             if (gp->type == swift_type_dark_matter) {
+
+#ifdef WITH_LOGGER
+              if (e->policy & engine_policy_logger) {
+                /* Log the particle one last time. */
+                logger_log_gpart(
+                    e->logger, gp, e, /* log_all */ 1,
+                    logger_pack_flags_and_data(logger_flag_delete, 0));
+              }
+#endif
+
+              /* Remove the particle */
               cell_remove_gpart(e, c, gp);
             }
           }
@@ -5194,6 +5214,15 @@ void cell_drift_spart(struct cell *c, const struct engine *e, int force) {
            * by another thread before we do the deed. */
           if (!spart_is_inhibited(sp, e)) {
 
+#ifdef WITH_LOGGER
+            if (e->policy & engine_policy_logger) {
+              /* Log the particle one last time. */
+              logger_log_spart(
+                  e->logger, sp, e, /* log_all */ 1,
+                  logger_pack_flags_and_data(logger_flag_delete, 0));
+            }
+#endif
+
             /* Remove the particle entirely */
             cell_remove_spart(e, c, sp);
           }
@@ -5365,6 +5394,12 @@ void cell_drift_bpart(struct cell *c, const struct engine *e, int force) {
            * by another thread before we do the deed. */
           if (!bpart_is_inhibited(bp, e)) {
 
+#ifdef WITH_LOGGER
+            if (e->policy & engine_policy_logger) {
+              error("Logging of black hole particles is not yet implemented.");
+            }
+#endif
+
             /* Remove the particle entirely */
             cell_remove_bpart(e, c, bp);
           }
diff --git a/src/engine.c b/src/engine.c
index 2786a62a5daf108a3eb71c58b1e2f4fdaacd2382..cf37c80c9090568d9f626002c18ff6e6b31512ad 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -562,14 +562,11 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
 
 #ifdef WITH_LOGGER
     if (e->policy & engine_policy_logger) {
-      const uint32_t logger_flag =
-          logger_pack_flags_and_data(logger_flag_mpi_exit, node_id);
-
       /* Log the particle when leaving a rank. */
       logger_log_part(
           e->logger, &s->parts[offset_parts + k], &s->xparts[offset_parts + k],
-          logger_masks_all_part | logger_mask_data[logger_special_flags].mask,
-          logger_flag);
+          e, /* log_all_fields */ 1,
+          logger_pack_flags_and_data(logger_flag_mpi_exit, node_id));
     }
 #endif
   }
@@ -610,14 +607,11 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
 
 #ifdef WITH_LOGGER
     if (e->policy & engine_policy_logger) {
-      const uint32_t logger_flag =
-          logger_pack_flags_and_data(logger_flag_mpi_exit, node_id);
-
       /* Log the particle when leaving a rank. */
       logger_log_spart(
-          e->logger, &s->sparts[offset_sparts + k],
-          logger_masks_all_spart | logger_mask_data[logger_special_flags].mask,
-          logger_flag);
+          e->logger, &s->sparts[offset_sparts + k], e,
+          /* log_all_fields */ 1,
+          logger_pack_flags_and_data(logger_flag_mpi_exit, node_id));
     }
 #endif
   }
@@ -696,14 +690,11 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
     if ((e->policy & engine_policy_logger) &&
         s->gparts[offset_gparts + k].type == swift_type_dark_matter) {
 
-      const uint32_t logger_flag =
-          logger_pack_flags_and_data(logger_flag_mpi_exit, node_id);
-
       /* Log the particle when leaving a rank. */
       logger_log_gpart(
-          e->logger, &s->gparts[offset_gparts + k],
-          logger_masks_all_gpart | logger_mask_data[logger_special_flags].mask,
-          logger_flag);
+          e->logger, &s->gparts[offset_gparts + k], e,
+          /* log_all_fields */ 1,
+          logger_pack_flags_and_data(logger_flag_mpi_exit, node_id));
     }
 #endif
   }
@@ -937,22 +928,16 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
         struct gpart *gparts = &s->gparts[offset_gparts + count_gparts];
 
         /* Log the gas particles */
-        logger_log_parts(
-            e->logger, parts, xparts, prox->nr_parts_in,
-            logger_masks_all_part | logger_mask_data[logger_special_flags].mask,
-            flag);
+        logger_log_parts(e->logger, parts, xparts, prox->nr_parts_in, e,
+                         /* log_all_fields */ 1, flag);
 
         /* Log the stellar particles */
-        logger_log_sparts(e->logger, sparts, prox->nr_sparts_in,
-                          logger_masks_all_spart |
-                              logger_mask_data[logger_special_flags].mask,
-                          flag);
+        logger_log_sparts(e->logger, sparts, prox->nr_sparts_in, e,
+                          /* log_all_fields */ 1, flag);
 
         /* Log the gparts */
-        logger_log_gparts(e->logger, gparts, prox->nr_gparts_in,
-                          logger_masks_all_gpart |
-                              logger_mask_data[logger_special_flags].mask,
-                          flag);
+        logger_log_gparts(e->logger, gparts, prox->nr_gparts_in, e,
+                          /* log_all_fields */ 1, flag);
 
         /* Log the bparts */
         if (prox->nr_bparts_in > 0) {
@@ -3980,7 +3965,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params,
 #if defined(WITH_LOGGER)
   if (e->policy & engine_policy_logger) {
     e->logger = (struct logger_writer *)malloc(sizeof(struct logger_writer));
-    logger_init(e->logger, params);
+    logger_init(e->logger, e, params);
   }
 #endif
 
diff --git a/src/engine_redistribute.c b/src/engine_redistribute.c
index 7246f71ee0a0d7620e6750c3706069720acce7ac..35354ec848d8890b9157c5c3a6825f84094cdd89 100644
--- a/src/engine_redistribute.c
+++ b/src/engine_redistribute.c
@@ -1004,22 +1004,16 @@ void engine_redistribute(struct engine *e) {
       const uint32_t flag = logger_pack_flags_and_data(logger_flag_mpi_exit, i);
 
       /* Log the hydro parts. */
-      logger_log_parts(
-          e->logger, &parts[part_offset], &xparts[part_offset], counts[c_ind],
-          logger_masks_all_part | logger_mask_data[logger_special_flags].mask,
-          flag);
+      logger_log_parts(e->logger, &parts[part_offset], &xparts[part_offset],
+                       counts[c_ind], e, /* log_all_fields */ 1, flag);
 
       /* Log the stellar parts. */
-      logger_log_sparts(
-          e->logger, &sparts[spart_offset], s_counts[c_ind],
-          logger_masks_all_spart | logger_mask_data[logger_special_flags].mask,
-          flag);
+      logger_log_sparts(e->logger, &sparts[spart_offset], s_counts[c_ind], e,
+                        /* log_all_fields */ 1, flag);
 
       /* Log the gparts */
-      logger_log_gparts(
-          e->logger, &gparts[gpart_offset], g_counts[c_ind],
-          logger_masks_all_gpart | logger_mask_data[logger_special_flags].mask,
-          flag);
+      logger_log_gparts(e->logger, &gparts[gpart_offset], g_counts[c_ind], e,
+                        /* log_all_fields */ 1, flag);
 
       /* Log the bparts */
       if (b_counts[c_ind] > 0) {
@@ -1110,23 +1104,17 @@ void engine_redistribute(struct engine *e) {
           logger_pack_flags_and_data(logger_flag_mpi_enter, i);
 
       /* Log the hydro parts. */
-      logger_log_parts(
-          e->logger, &s->parts[part_offset], &s->xparts[part_offset],
-          counts[c_ind],
-          logger_masks_all_part | logger_mask_data[logger_special_flags].mask,
-          flag);
+      logger_log_parts(e->logger, &s->parts[part_offset],
+                       &s->xparts[part_offset], counts[c_ind], e,
+                       /* log_all_fields */ 1, flag);
 
       /* Log the stellar parts. */
-      logger_log_sparts(
-          e->logger, &s->sparts[spart_offset], s_counts[c_ind],
-          logger_masks_all_spart | logger_mask_data[logger_special_flags].mask,
-          flag);
+      logger_log_sparts(e->logger, &s->sparts[spart_offset], s_counts[c_ind], e,
+                        /* log_all_fields */ 1, flag);
 
       /* Log the gparts */
-      logger_log_gparts(
-          e->logger, &s->gparts[gpart_offset], g_counts[c_ind],
-          logger_masks_all_gpart | logger_mask_data[logger_special_flags].mask,
-          flag);
+      logger_log_gparts(e->logger, &s->gparts[gpart_offset], g_counts[c_ind], e,
+                        /* log_all_fields */ 1, flag);
 
       /* Log the bparts */
       if (b_counts[c_ind] > 0) {
diff --git a/src/gravity/MultiSoftening/gravity_logger.h b/src/gravity/MultiSoftening/gravity_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..65035aceac081cdb6c84282e34eca16142b43db0
--- /dev/null
+++ b/src/gravity/MultiSoftening/gravity_logger.h
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * 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_MULTISOFTENING_GRAVITY_LOGGER_H
+#define SWIFT_MULTISOFTENING_GRAVITY_LOGGER_H
+
+#include "logger_io.h"
+
+#ifdef WITH_LOGGER
+
+/*
+ * List of all possible mask.
+ * Outside the module, only logger_gravity_count is used.
+ */
+enum gravity_logger_fields {
+  gravity_logger_field_coordinates = 0,
+  gravity_logger_field_velocities,
+  gravity_logger_field_accelerations,
+  gravity_logger_field_masses,
+  gravity_logger_field_particle_ids,
+  gravity_logger_field_count,
+};
+
+/* Name of each possible mask. */
+static const char *gravity_logger_field_names[gravity_logger_field_count] = {
+    "Coordinates", "Velocities", "Accelerations", "Masses", "ParticleIDs",
+};
+
+/**
+ * @brief Initialize the logger.
+ *
+ * WARNING: this should be done in the same order than
+ * #gravity_logger_write_particle.
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int gravity_logger_populate_mask_data(
+    struct mask_data *mask_data) {
+  mask_data[gravity_logger_field_coordinates] = logger_create_mask_entry(
+      gravity_logger_field_names[gravity_logger_field_coordinates],
+      3 * sizeof(double));
+
+  mask_data[gravity_logger_field_velocities] = logger_create_mask_entry(
+      gravity_logger_field_names[gravity_logger_field_velocities],
+      3 * sizeof(float));
+
+  mask_data[gravity_logger_field_accelerations] = logger_create_mask_entry(
+      gravity_logger_field_names[gravity_logger_field_accelerations],
+      3 * sizeof(float));
+
+  mask_data[gravity_logger_field_masses] = logger_create_mask_entry(
+      gravity_logger_field_names[gravity_logger_field_masses], sizeof(float));
+
+  mask_data[gravity_logger_field_particle_ids] = logger_create_mask_entry(
+      gravity_logger_field_names[gravity_logger_field_particle_ids],
+      sizeof(long long));
+
+  return gravity_logger_field_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record.
+ *
+ * @param masks The list of masks (same order than in #gravity_logger_init).
+ * @param part The #gpart 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 gravity_logger_compute_size_and_mask(
+    const struct mask_data *masks, const struct gpart *part,
+    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[gravity_logger_field_coordinates],
+      gravity_logger_field_names[gravity_logger_field_coordinates],
+      buffer_size);
+
+  /* Add the velocities. */
+  *mask |= logger_add_field_to_mask(
+      masks[gravity_logger_field_velocities],
+      gravity_logger_field_names[gravity_logger_field_velocities], buffer_size);
+
+  /* Add the accelerations. */
+  *mask |= logger_add_field_to_mask(
+      masks[gravity_logger_field_accelerations],
+      gravity_logger_field_names[gravity_logger_field_accelerations],
+      buffer_size);
+
+  /* Add the masses. */
+  *mask |= logger_add_field_to_mask(
+      masks[gravity_logger_field_masses],
+      gravity_logger_field_names[gravity_logger_field_masses], buffer_size);
+
+  /* Add the ID. */
+  *mask |= logger_add_field_to_mask(
+      masks[gravity_logger_field_particle_ids],
+      gravity_logger_field_names[gravity_logger_field_particle_ids],
+      buffer_size);
+}
+
+/**
+ * @brief Write a particle to the logger.
+ *
+ * @param masks The list of masks (same order than in #gravity_logger_init).
+ * @param p The #gpart 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 *gravity_logger_write_particle(
+    const struct mask_data *mask_data, const struct gpart *p,
+    unsigned int *mask, char *buff) {
+
+  /* Write the coordinate. */
+  if (logger_should_write_field(
+          mask_data[gravity_logger_field_coordinates], mask,
+          gravity_logger_field_names[gravity_logger_field_coordinates])) {
+    memcpy(buff, p->x, 3 * sizeof(double));
+    buff += 3 * sizeof(double);
+  }
+
+  /* Write the velocity. */
+  if (logger_should_write_field(
+          mask_data[gravity_logger_field_velocities], mask,
+          gravity_logger_field_names[gravity_logger_field_velocities])) {
+    memcpy(buff, p->v_full, 3 * sizeof(float));
+    buff += 3 * sizeof(float);
+  }
+
+  /* Write the acceleration. */
+  if (logger_should_write_field(
+          mask_data[gravity_logger_field_accelerations], mask,
+          gravity_logger_field_names[gravity_logger_field_accelerations])) {
+    memcpy(buff, p->a_grav, 3 * sizeof(float));
+    buff += 3 * sizeof(float);
+  }
+
+  /* Write the mass. */
+  if (logger_should_write_field(
+          mask_data[gravity_logger_field_masses], mask,
+          gravity_logger_field_names[gravity_logger_field_masses])) {
+    memcpy(buff, &p->mass, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the Id. */
+  if (logger_should_write_field(
+          mask_data[gravity_logger_field_particle_ids], mask,
+          gravity_logger_field_names[gravity_logger_field_particle_ids])) {
+    memcpy(buff, &p->id_or_neg_offset, sizeof(long long));
+    buff += sizeof(long long);
+  }
+
+  return buff;
+}
+#endif  // WITH_LOGGER
+#endif  // SWIFT_MULTISOFTENING_GRAVITY_LOGGER_H
diff --git a/src/gravity_io.h b/src/gravity_io.h
index 44f392ee06d43228f7aa46faa5c7d9015fde790b..b5d8f1ec2d2fc8a3a65cc42ae22acf720e04e322 100644
--- a/src/gravity_io.h
+++ b/src/gravity_io.h
@@ -32,6 +32,7 @@
 #include "./gravity/Potential/gravity_io.h"
 #elif defined(MULTI_SOFTENING_GRAVITY)
 #include "./gravity/MultiSoftening/gravity_io.h"
+#include "./gravity/MultiSoftening/gravity_logger.h"
 #else
 #error "Invalid choice of gravity variant"
 #endif
diff --git a/src/hydro/Gadget2/hydro_logger.h b/src/hydro/Gadget2/hydro_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..17f1a702e6095c16e189fe93daf1a83e9d3b3490
--- /dev/null
+++ b/src/hydro/Gadget2/hydro_logger.h
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * 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_GADGET2_HYDRO_LOGGER_H
+#define SWIFT_GADGET2_HYDRO_LOGGER_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_mask {
+  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_entropies,
+  hydro_logger_field_particle_ids,
+  hydro_logger_field_densities,
+  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", "Entropies",  "ParticleIDs",   "Densities"};
+
+/**
+ * @brief Initialize the logger.
+ *
+ * WARNING: this should be done in the same order than
+ * #hydro_logger_write_particle.
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int hydro_logger_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_entropies] = logger_create_mask_entry(
+      hydro_logger_field_names[hydro_logger_field_entropies], 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));
+
+  return hydro_logger_field_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record.
+ *
+ * @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],
+      hydro_logger_field_names[hydro_logger_field_coordinates], buffer_size);
+
+  /* Add the velocities. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_velocities],
+      hydro_logger_field_names[hydro_logger_field_velocities], buffer_size);
+
+  /* Add the accelerations. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_accelerations],
+      hydro_logger_field_names[hydro_logger_field_accelerations], buffer_size);
+
+  /* Add the masses. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_masses],
+      hydro_logger_field_names[hydro_logger_field_masses], buffer_size);
+
+  /* Add the smoothing lengths. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_smoothing_lengths],
+      hydro_logger_field_names[hydro_logger_field_smoothing_lengths],
+      buffer_size);
+
+  /* Add the entropies. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_entropies],
+      hydro_logger_field_names[hydro_logger_field_entropies], buffer_size);
+
+  /* Add the ID. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_particle_ids],
+      hydro_logger_field_names[hydro_logger_field_particle_ids], buffer_size);
+
+  /* Add the density. */
+  *mask |= logger_add_field_to_mask(
+      masks[hydro_logger_field_densities],
+      hydro_logger_field_names[hydro_logger_field_densities], buffer_size);
+}
+
+/**
+ * @brief Write a particle to the logger.
+ *
+ * @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,
+          hydro_logger_field_names[hydro_logger_field_coordinates])) {
+    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,
+          hydro_logger_field_names[hydro_logger_field_velocities])) {
+    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,
+          hydro_logger_field_names[hydro_logger_field_accelerations])) {
+
+    /* Compute the acceleration due to hydro and gravity */
+    float *acc = (float *)buff;
+    acc[0] = p->a_hydro[0] + xp->a_grav[0];
+    acc[1] = p->a_hydro[1] + xp->a_grav[1];
+    acc[2] = p->a_hydro[2] + xp->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,
+          hydro_logger_field_names[hydro_logger_field_masses])) {
+    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,
+          hydro_logger_field_names[hydro_logger_field_smoothing_lengths])) {
+    memcpy(buff, &p->h, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the entropy. */
+  if (logger_should_write_field(
+          mask_data[hydro_logger_field_entropies], mask,
+          hydro_logger_field_names[hydro_logger_field_entropies])) {
+    memcpy(buff, &p->entropy, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the Id. */
+  if (logger_should_write_field(
+          mask_data[hydro_logger_field_particle_ids], mask,
+          hydro_logger_field_names[hydro_logger_field_particle_ids])) {
+    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,
+          hydro_logger_field_names[hydro_logger_field_densities])) {
+    memcpy(buff, &p->rho, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_GADGET2_HYDRO_LOGGER_H
diff --git a/src/hydro_io.h b/src/hydro_io.h
index d3e98771898f6cfdd8b7758932fd65b8534b5f27..dc0bf3af054f2751c9a9198da8893f15bed17b69 100644
--- a/src/hydro_io.h
+++ b/src/hydro_io.h
@@ -27,6 +27,7 @@
 #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/logger.c b/src/logger.c
index c970385e27b561dc466c89bcf41a4845843f69bb..349ccf02d24fce973382260ec65e6926447a81ac 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -30,6 +30,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+/* Define the particles first */
+#include "part.h"
+
 /* This object's header. */
 #include "logger.h"
 
@@ -38,7 +41,9 @@
 #include "dump.h"
 #include "engine.h"
 #include "error.h"
-#include "part.h"
+#include "gravity_io.h"
+#include "hydro_io.h"
+#include "stars_io.h"
 #include "units.h"
 
 /*
@@ -48,7 +53,7 @@
 // TODO change this to number of bits
 #define logger_mask_size 2
 
-/* Number of bits for chunk header. */
+/* Number of bits for record header. */
 #define logger_header_bytes 8
 
 /* Number bytes for an offset. */
@@ -62,43 +67,30 @@
 
 char logger_file_format[logger_format_size] = "SWIFT_LOGGER";
 
-const struct mask_data logger_mask_data[logger_count_mask] = {
-    /* Particle's position. */
-    {3 * sizeof(double), 1 << logger_x, "positions"},
-    /* Particle's velocity. */
-    {3 * sizeof(float), 1 << logger_v, "velocities"},
-    /* Particle's acceleration. */
-    {3 * sizeof(float), 1 << logger_a, "accelerations"},
-    /* Particle's entropy. */
-    {sizeof(float), 1 << logger_u, "entropy"},
-    /* Particle's smoothing length. */
-    {sizeof(float), 1 << logger_h, "smoothing length"},
-    /* Particle's density. */
-    {sizeof(float), 1 << logger_rho, "density"},
-    /* Particle's constants: mass (float) and ID (long long). */
-    {sizeof(float) + sizeof(long long), 1 << logger_consts, "consts"},
-    /* Flag for special cases (e.g. change of MPI rank, star formation, ...) */
-    {sizeof(uint32_t), 1 << logger_special_flags, "special flags"},
-    /* Simulation time stamp: integertime and double time (e.g. scale
-       factor or time). */
-    {sizeof(integertime_t) + sizeof(double), 1 << logger_timestamp,
-     "timestamp"},
-};
+/*
+ * 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
 
 /**
- * @brief Write the header of a chunk (offset + mask).
+ * @brief Write the header of a record (offset + mask).
  *
  * This is maybe broken for big(?) endian.
  *
- * @param buff The writing buffer
- * @param mask The mask to write
- * @param offset The old offset
- * @param offset_new The new offset
+ * @param buff The buffer where to write the mask and offset.
+ * @param mask The mask to write inside the buffer.
+ * @param offset The offset of the previous record.
+ * @param offset_new The offset of the current record.
  *
  * @return updated buff
  */
-char *logger_write_chunk_header(char *buff, const unsigned int *mask,
-                                const size_t *offset, const size_t offset_new) {
+char *logger_write_record_header(char *buff, const unsigned int *mask,
+                                 const size_t *offset,
+                                 const size_t offset_new) {
   /* write mask. */
   memcpy(buff, mask, logger_mask_size);
   buff += logger_mask_size;
@@ -127,51 +119,18 @@ void logger_write_data(struct dump *d, size_t *offset, size_t size,
   /* write data to the buffer. */
   memcpy(buff, p, size);
 
-  /* Update offset to end of chunk. */
+  /* Update offset to end of record. */
   *offset += size;
 }
 
-/**
- * @brief Compute the size of a message given its mask.
- *
- * @param mask The mask that will be used to dump a #part or #gpart.
- *
- * @return The size of the logger message in bytes.
- */
-int logger_compute_chunk_size(unsigned int mask) {
-
-  /* Start with 8 bytes for the header. */
-  int size = logger_mask_size + logger_offset_size;
-
-  /* Is this a particle or a timestep? */
-  if (mask & logger_mask_data[logger_timestamp].mask) {
-
-    /* The timestamp should not contain any other bits. */
-    if (mask != logger_mask_data[logger_timestamp].mask)
-      error("Timestamps should not include any other data.");
-
-    /* A timestamp consists of an unsigned long long int. */
-    size += logger_mask_data[logger_timestamp].size;
-
-  } else {
-
-    for (int i = 0; i < logger_count_mask; i++) {
-      if (mask & logger_mask_data[i].mask) {
-        size += logger_mask_data[i].size;
-      }
-    }
-  }
-
-  return size;
-}
-
 /**
  * @brief log all particles in the engine.
  *
  * @param log The #logger_writer
  * @param e The #engine
  */
-void logger_log_all(struct logger_writer *log, const struct engine *e) {
+void logger_log_all_particles(struct logger_writer *log,
+                              const struct engine *e) {
 
   /* Ensure that enough space is available. */
   logger_ensure_size(log, e->s->nr_parts, e->s->nr_gparts, e->s->nr_sparts);
@@ -179,26 +138,17 @@ void logger_log_all(struct logger_writer *log, const struct engine *e) {
   /* some constants. */
   const struct space *s = e->s;
 
-  /* loop over all parts. */
-  for (size_t i = 0; i < s->nr_parts; i++) {
-    logger_log_part(log, &s->parts[i], &s->xparts[i], logger_masks_all_part,
-                    /* Special flags */ 0);
-  }
+  /* log the parts. */
+  logger_log_parts(log, s->parts, s->xparts, s->nr_parts, e,
+                   /* log_all_fields */ 1, /* Special flags */ 0);
 
-  /* loop over all gparts */
-  for (size_t i = 0; i < s->nr_gparts; i++) {
-    /* Log only the dark matter */
-    if (s->gparts[i].type != swift_type_dark_matter) continue;
+  /* log the gparts */
+  logger_log_gparts(log, s->gparts, s->nr_gparts, e,
+                    /* log_all_fields */ 1, /* Special flags */ 0);
 
-    logger_log_gpart(log, &s->gparts[i], logger_masks_all_gpart,
-                     /* Special flags */ 0);
-  }
-
-  /* loop over all sparts */
-  for (size_t i = 0; i < s->nr_sparts; i++) {
-    logger_log_spart(log, &s->sparts[i], logger_masks_all_spart,
-                     /* Special flags */ 0);
-  }
+  /* log the parts */
+  logger_log_sparts(log, s->sparts, s->nr_sparts, e,
+                    /* log_all_fields */ 1, /* Special flags */ 0);
 
   if (e->total_nr_bparts > 0) error("Not implemented");
 }
@@ -206,81 +156,41 @@ void logger_log_all(struct logger_writer *log, const struct engine *e) {
 /**
  * @brief Copy the particle fields into a given buffer.
  *
+ * @param log The #logger_writer
  * @param p The #part to copy.
+ * @param xp The #xpart to copy.
+ * @param e The #engine.
  * @param mask The mask for the fields to write.
  * @param offset The offset to the previous log.
  * @param offset_new The offset of the current record.
  * @param buff The buffer to use when writing.
  * @param special_flags The data for the special flags.
  */
-void logger_copy_part_fields(const struct part *p, unsigned int mask,
+void logger_copy_part_fields(const struct logger_writer *log,
+                             const struct part *p, const struct xpart *xp,
+                             const struct engine *e, unsigned int mask,
                              size_t *offset, size_t offset_new, char *buff,
                              const uint32_t special_flags) {
 
-  /* Write the header. */
-  buff = logger_write_chunk_header(buff, &mask, offset, offset_new);
-
-  /* Particle position as three doubles. */
-  if (mask & logger_mask_data[logger_x].mask) {
-    memcpy(buff, p->x, logger_mask_data[logger_x].size);
-    buff += logger_mask_data[logger_x].size;
-    mask &= ~logger_mask_data[logger_x].mask;
-  }
-
-  /* Particle velocity as three floats. */
-  if (mask & logger_mask_data[logger_v].mask) {
-    memcpy(buff, p->v, logger_mask_data[logger_v].size);
-    buff += logger_mask_data[logger_v].size;
-    mask &= ~logger_mask_data[logger_v].mask;
-  }
-
-  /* Particle accelleration as three floats. */
-  if (mask & logger_mask_data[logger_a].mask) {
-    memcpy(buff, p->a_hydro, logger_mask_data[logger_a].size);
-    buff += logger_mask_data[logger_a].size;
-    mask &= ~logger_mask_data[logger_a].mask;
-  }
-
-#if defined(GADGET2_SPH)
-
-  /* Particle internal energy as a single float. */
-  if (mask & logger_mask_data[logger_u].mask) {
-    memcpy(buff, &p->entropy, logger_mask_data[logger_u].size);
-    buff += logger_mask_data[logger_u].size;
-    mask &= ~logger_mask_data[logger_u].mask;
+#ifdef SWIFT_DEBUG_CHECKS
+  if (mask == 0) {
+    error("You should always log at least one field.");
   }
 #endif
 
-  /* Particle smoothing length as a single float. */
-  if (mask & logger_mask_data[logger_h].mask) {
-    memcpy(buff, &p->h, logger_mask_data[logger_h].size);
-    buff += logger_mask_data[logger_h].size;
-    mask &= ~logger_mask_data[logger_h].mask;
-  }
-
-  /* Particle density as a single float. */
-  if (mask & logger_mask_data[logger_rho].mask) {
-    memcpy(buff, &p->rho, logger_mask_data[logger_rho].size);
-    buff += logger_mask_data[logger_rho].size;
-    mask &= ~logger_mask_data[logger_rho].mask;
-  }
+  /* Write the header. */
+  buff = logger_write_record_header(buff, &mask, offset, offset_new);
 
-  /* Particle constants, which is a bit more complicated. */
-  if (mask & logger_mask_data[logger_consts].mask) {
-    // TODO make it dependent of logger_mask_data
-    memcpy(buff, &p->mass, sizeof(float));
-    buff += sizeof(float);
-    const int64_t id = p->id;
-    memcpy(buff, &id, sizeof(int64_t));
-    buff += sizeof(int64_t);
-    mask &= ~logger_mask_data[logger_consts].mask;
-  }
+  /* Write the hydro fields */
+  buff = hydro_logger_write_particle(log->mask_data_pointers.hydro, p, xp,
+                                     &mask, buff);
 
   /* Special flags */
-  if (mask & logger_mask_data[logger_special_flags].mask) {
-    memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size);
-    buff += logger_mask_data[logger_special_flags].size;
-    mask &= ~logger_mask_data[logger_special_flags].mask;
+  if (mask & log->logger_mask_data[logger_index_special_flags].mask) {
+    memcpy(buff, &special_flags,
+           log->logger_mask_data[logger_index_special_flags].size);
+    buff += log->logger_mask_data[logger_index_special_flags].size;
+    mask &= ~log->logger_mask_data[logger_index_special_flags].mask;
   }
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -296,39 +206,67 @@ void logger_copy_part_fields(const struct part *p, unsigned int mask,
  * @param log The #logger_writer
  * @param p The #part to dump.
  * @param xp The #xpart to dump.
- * @param mask The mask of the data to dump.
+ * @param e The #engine.
+ * @param log_all_fields Should we log all the fields?
  * @param special_flags The value of the special flag.
  */
 void logger_log_part(struct logger_writer *log, const struct part *p,
-                     struct xpart *xp, unsigned int mask,
-                     const uint32_t special_flags) {
+                     struct xpart *xp, const struct engine *e,
+                     const int log_all_fields, const uint32_t special_flags) {
 
-  logger_log_parts(log, p, xp, /* count */ 1, mask, special_flags);
+  logger_log_parts(log, p, xp, /* count */ 1, e, log_all_fields, special_flags);
 }
 
 /**
  * @brief Dump a group of #part to the log.
  *
- * @param log The #logger_writer
- * @param sp The #part to dump.
- * @param mask The mask of the data to dump.
+ * @param log The #logger_writer.
+ * @param p The #part to dump.
+ * @param xp The #xpart to dump.
  * @param count The number of particle to dump.
+ * @param e The #engine.
+ * @param log_all_fields Should we log all the fields?
  * @param special_flags The value of the special flags.
  */
 void logger_log_parts(struct logger_writer *log, const struct part *p,
-                      struct xpart *xp, int count, unsigned int mask,
-                      const uint32_t special_flags) {
-  /* Start by computing the size of the message. */
-  const int size = logger_compute_chunk_size(mask);
+                      struct xpart *xp, int count, const struct engine *e,
+                      const int log_all_fields, const uint32_t special_flags) {
+
+  /* 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);
+  } 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);
+      size_total += size + logger_header_bytes;
+    }
+  }
 
   /* Allocate a chunk of memory in the dump of the right size. */
   size_t offset_new;
-  char *buff = (char *)dump_get(&log->dump, count * size, &offset_new);
+  char *buff = (char *)dump_get(&log->dump, size_total, &offset_new);
 
+  /* Write the particles */
   for (int i = 0; i < count; i++) {
+    /* Get the masks */
+    size_t size = 0;
+    unsigned int mask = 0;
+    hydro_logger_compute_size_and_mask(log->mask_data_pointers.hydro, &p[i],
+                                       &xp[i], log_all_fields, &size, &mask);
+    size += logger_header_bytes;
+
+    if (special_flags != 0) {
+      mask |= log->logger_mask_data[logger_index_special_flags].mask;
+    }
+
     /* Copy everything into the buffer */
-    logger_copy_part_fields(&p[i], mask, &xp[i].logger_data.last_offset,
-                            offset_new, buff, special_flags);
+    logger_copy_part_fields(log, &p[i], &xp[i], e, mask,
+                            &xp[i].logger_data.last_offset, offset_new, buff,
+                            special_flags);
 
     /* Update the pointers */
     xp[i].logger_data.last_offset = offset_new;
@@ -341,50 +279,40 @@ void logger_log_parts(struct logger_writer *log, const struct part *p,
 /**
  * @brief Copy the particle fields into a given buffer.
  *
+ * @param log The #logger_writer.
  * @param sp The #spart to copy.
+ * @param e The #engine.
  * @param mask The mask for the fields to write.
  * @param offset The offset to the previous log.
  * @param offset_new The offset of the current record.
  * @param buff The buffer to use when writing.
  * @param special_flags The data for the special flags.
  */
-void logger_copy_spart_fields(const struct spart *sp, unsigned int mask,
-                              size_t *offset, size_t offset_new, char *buff,
+void logger_copy_spart_fields(const struct logger_writer *log,
+                              const struct spart *sp, const struct engine *e,
+                              unsigned int mask, size_t *offset,
+                              size_t offset_new, char *buff,
                               const uint32_t special_flags) {
 
-  /* Write the header. */
-  buff = logger_write_chunk_header(buff, &mask, offset, offset_new);
-
-  /* Particle position as three doubles. */
-  if (mask & logger_mask_data[logger_x].mask) {
-    memcpy(buff, sp->x, logger_mask_data[logger_x].size);
-    buff += logger_mask_data[logger_x].size;
-    mask &= ~logger_mask_data[logger_x].mask;
+#ifdef SWIFT_DEBUG_CHECKS
+  if (mask == 0) {
+    error("You should always log at least one field.");
   }
+#endif
 
-  /* Particle velocity as three floats. */
-  if (mask & logger_mask_data[logger_v].mask) {
-    memcpy(buff, sp->v, logger_mask_data[logger_v].size);
-    buff += logger_mask_data[logger_v].size;
-    mask &= ~logger_mask_data[logger_v].mask;
-  }
+  /* Write the header. */
+  buff = logger_write_record_header(buff, &mask, offset, offset_new);
 
-  /* Particle constants, which is a bit more complicated. */
-  if (mask & logger_mask_data[logger_consts].mask) {
-    // TODO make it dependent of logger_mask_data
-    memcpy(buff, &sp->mass, sizeof(float));
-    buff += sizeof(float);
-    const int64_t id = sp->id;
-    memcpy(buff, &id, sizeof(int64_t));
-    buff += sizeof(int64_t);
-    mask &= ~logger_mask_data[logger_consts].mask;
-  }
+  /* Write the stellar fields */
+  buff = stars_logger_write_particle(log->mask_data_pointers.stars, sp, &mask,
+                                     buff);
 
   /* Special flags */
-  if (mask & logger_mask_data[logger_special_flags].mask) {
-    memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size);
-    buff += logger_mask_data[logger_special_flags].size;
-    mask &= ~logger_mask_data[logger_special_flags].mask;
+  if (mask & log->logger_mask_data[logger_index_special_flags].mask) {
+    memcpy(buff, &special_flags,
+           log->logger_mask_data[logger_index_special_flags].size);
+    buff += log->logger_mask_data[logger_index_special_flags].size;
+    mask &= ~log->logger_mask_data[logger_index_special_flags].mask;
   }
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -399,13 +327,15 @@ void logger_copy_spart_fields(const struct spart *sp, unsigned int mask,
  *
  * @param log The #logger_writer
  * @param sp The #spart to dump.
- * @param mask The mask of the data to dump.
+ * @param e The #engine.
+ * @param log_all_fields Should we log all the fields?
  * @param special_flags The value of the special flag.
  */
 void logger_log_spart(struct logger_writer *log, struct spart *sp,
-                      unsigned int mask, const uint32_t special_flags) {
+                      const struct engine *e, const int log_all_fields,
+                      const uint32_t special_flags) {
 
-  logger_log_sparts(log, sp, /* count */ 1, mask, special_flags);
+  logger_log_sparts(log, sp, /* count */ 1, e, log_all_fields, special_flags);
 }
 
 /**
@@ -413,23 +343,49 @@ void logger_log_spart(struct logger_writer *log, struct spart *sp,
  *
  * @param log The #logger_writer
  * @param sp The #spart to dump.
- * @param mask The mask of the data to dump.
+ * @param e The #engine.
+ * @param log_all_fields Should we log all the fields?
  * @param count The number of particle to dump.
  * @param special_flags The value of the special flags.
  */
 void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
-                       unsigned int mask, const uint32_t special_flags) {
-  /* Start by computing the size of the message. */
-  const int size = logger_compute_chunk_size(mask);
+                       const struct engine *e, const int log_all_fields,
+                       const uint32_t special_flags) {
+
+  /* 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);
+  } 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);
+      size_total += size + logger_header_bytes;
+    }
+  }
 
   /* Allocate a chunk of memory in the dump of the right size. */
   size_t offset_new;
-  char *buff = (char *)dump_get(&log->dump, count * size, &offset_new);
+  char *buff = (char *)dump_get(&log->dump, size_total, &offset_new);
 
   for (int i = 0; i < count; i++) {
+    /* Get the masks */
+    size_t size = 0;
+    unsigned int mask = 0;
+    stars_logger_compute_size_and_mask(log->mask_data_pointers.stars, &sp[i],
+                                       log_all_fields, &size, &mask);
+    size += logger_header_bytes;
+
+    if (special_flags != 0) {
+      mask |= log->logger_mask_data[logger_index_special_flags].mask;
+    }
+
     /* Copy everything into the buffer */
-    logger_copy_spart_fields(&sp[i], mask, &sp[i].logger_data.last_offset,
-                             offset_new, buff, special_flags);
+    logger_copy_spart_fields(log, &sp[i], e, mask,
+                             &sp[i].logger_data.last_offset, offset_new, buff,
+                             special_flags);
 
     /* Update the pointers */
     sp[i].logger_data.last_offset = offset_new;
@@ -442,57 +398,40 @@ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
 /**
  * @brief Copy the particle fields into a given buffer.
  *
+ * @param log The #logger_writer.
  * @param gp The #gpart to copy.
+ * @param e The #engine.
  * @param mask The mask for the fields to write.
  * @param offset The offset to the previous log.
  * @param offset_new The offset of the current record.
  * @param buff The buffer to use when writing.
  * @param special_flags The data of the special flag.
  */
-void logger_copy_gpart_fields(const struct gpart *gp, unsigned int mask,
-                              size_t *offset, size_t offset_new, char *buff,
+void logger_copy_gpart_fields(const struct logger_writer *log,
+                              const struct gpart *gp, const struct engine *e,
+                              unsigned int mask, size_t *offset,
+                              size_t offset_new, char *buff,
                               const uint32_t special_flags) {
 
-  /* Write the header. */
-  buff = logger_write_chunk_header(buff, &mask, offset, offset_new);
-
-  /* Particle position as three doubles. */
-  if (mask & logger_mask_data[logger_x].mask) {
-    memcpy(buff, gp->x, logger_mask_data[logger_x].size);
-    buff += logger_mask_data[logger_x].size;
-    mask &= ~logger_mask_data[logger_x].mask;
-  }
-
-  /* Particle velocity as three floats. */
-  if (mask & logger_mask_data[logger_v].mask) {
-    memcpy(buff, gp->v_full, logger_mask_data[logger_v].size);
-    buff += logger_mask_data[logger_v].size;
-    mask &= ~logger_mask_data[logger_v].mask;
+#ifdef SWIFT_DEBUG_CHECKS
+  if (mask == 0) {
+    error("You should always log at least one field.");
   }
+#endif
 
-  /* Particle accelleration as three floats. */
-  if (mask & logger_mask_data[logger_a].mask) {
-    memcpy(buff, gp->a_grav, logger_mask_data[logger_a].size);
-    buff += logger_mask_data[logger_a].size;
-    mask &= ~logger_mask_data[logger_a].mask;
-  }
+  /* Write the header. */
+  buff = logger_write_record_header(buff, &mask, offset, offset_new);
 
-  /* Particle constants, which is a bit more complicated. */
-  if (mask & logger_mask_data[logger_consts].mask) {
-    // TODO make it dependent of logger_mask_data.
-    memcpy(buff, &gp->mass, sizeof(float));
-    buff += sizeof(float);
-    const int64_t id = gp->id_or_neg_offset;
-    memcpy(buff, &id, sizeof(int64_t));
-    buff += sizeof(int64_t);
-    mask &= ~logger_mask_data[logger_consts].mask;
-  }
+  /* Write the hydro fields */
+  buff = gravity_logger_write_particle(log->mask_data_pointers.gravity, gp,
+                                       &mask, buff);
 
   /* Special flags */
-  if (mask & logger_mask_data[logger_special_flags].mask) {
-    memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size);
-    buff += logger_mask_data[logger_special_flags].size;
-    mask &= ~logger_mask_data[logger_special_flags].mask;
+  if (mask & log->logger_mask_data[logger_index_special_flags].mask) {
+    memcpy(buff, &special_flags,
+           log->logger_mask_data[logger_index_special_flags].size);
+    buff += log->logger_mask_data[logger_index_special_flags].size;
+    mask &= ~log->logger_mask_data[logger_index_special_flags].mask;
   }
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -507,12 +446,14 @@ void logger_copy_gpart_fields(const struct gpart *gp, unsigned int mask,
  *
  * @param log The #logger_writer
  * @param p The #gpart to dump.
- * @param mask The mask of the data to dump.
+ * @param e The #engine.
+ * @param log_all_fields Should we log all the fields?
  * @param special_flags The value of the special flags.
  */
 void logger_log_gpart(struct logger_writer *log, struct gpart *p,
-                      unsigned int mask, const uint32_t special_flags) {
-  logger_log_gparts(log, p, /* count */ 1, mask, special_flags);
+                      const struct engine *e, const int log_all_fields,
+                      const uint32_t special_flags) {
+  logger_log_gparts(log, p, /* count */ 1, e, log_all_fields, special_flags);
 }
 
 /**
@@ -520,25 +461,53 @@ void logger_log_gpart(struct logger_writer *log, struct gpart *p,
  *
  * @param log The #logger_writer
  * @param p The #gpart to dump.
- * @param mask The mask of the data to dump.
  * @param count The number of particle to dump.
+ * @param e The #engine.
+ * @param log_all_fields Should we log all the fields?
  * @param special_flags The value of the special flags.
  */
 void logger_log_gparts(struct logger_writer *log, struct gpart *p, int count,
-                       unsigned int mask, const uint32_t special_flags) {
-  /* Start by computing the size of the message. */
-  const int size = logger_compute_chunk_size(mask);
+                       const struct engine *e, const int log_all_fields,
+                       const uint32_t special_flags) {
+
+  /* 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);
+  } else {
+    for (int i = 0; i < count; i++) {
+      /* Log only the dark matter */
+      if (p[i].type != swift_type_dark_matter) 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);
+      size_total += size + logger_header_bytes;
+    }
+  }
 
   /* Allocate a chunk of memory in the dump of the right size. */
   size_t offset_new;
-  char *buff = (char *)dump_get(&log->dump, count * size, &offset_new);
+  char *buff = (char *)dump_get(&log->dump, size_total, &offset_new);
 
   for (int i = 0; i < count; i++) {
     /* Log only the dark matter */
     if (p[i].type != swift_type_dark_matter) continue;
 
+    /* Get the masks */
+    size_t size = 0;
+    unsigned int mask = 0;
+    gravity_logger_compute_size_and_mask(log->mask_data_pointers.gravity, &p[i],
+                                         log_all_fields, &size, &mask);
+    size += logger_header_bytes;
+
+    if (special_flags != 0) {
+      mask |= log->logger_mask_data[logger_index_special_flags].mask;
+    }
+
     /* Copy everything into the buffer */
-    logger_copy_gpart_fields(&p[i], mask, &p[i].logger_data.last_offset,
+    logger_copy_gpart_fields(log, &p[i], e, mask, &p[i].logger_data.last_offset,
                              offset_new, buff, special_flags);
 
     /* Update the pointers */
@@ -561,21 +530,19 @@ void logger_log_gparts(struct logger_writer *log, struct gpart *p, int count,
 void logger_log_timestamp(struct logger_writer *log, integertime_t timestamp,
                           double time, size_t *offset) {
   struct dump *dump = &log->dump;
-
   /* Start by computing the size of the message. */
   const int size =
-      logger_compute_chunk_size(logger_mask_data[logger_timestamp].mask);
+      log->logger_mask_data[logger_index_timestamp].size + logger_header_bytes;
 
   /* Allocate a chunk of memory in the dump of the right size. */
   size_t offset_new;
   char *buff = (char *)dump_get(dump, size, &offset_new);
 
   /* Write the header. */
-  unsigned int mask = logger_mask_data[logger_timestamp].mask;
-  buff = logger_write_chunk_header(buff, &mask, offset, offset_new);
+  unsigned int mask = log->logger_mask_data[logger_index_timestamp].mask;
+  buff = logger_write_record_header(buff, &mask, offset, offset_new);
 
   /* Store the timestamp. */
-  // TODO make it dependent of logger_mask_data.
   memcpy(buff, &timestamp, sizeof(integertime_t));
   buff += sizeof(integertime_t);
 
@@ -613,7 +580,7 @@ void logger_ensure_size(struct logger_writer *log, size_t total_nr_parts,
   limit += total_nr_sparts;
 
   // TODO improve estimate with the size of each particle
-  limit *= log->max_chunk_size;
+  limit *= log->max_record_size;
 
   /* ensure enough space in dump */
   dump_ensure(&log->dump, limit, log->buffer_scale * limit);
@@ -628,13 +595,200 @@ void logger_get_dump_name(struct logger_writer *log, char *filename) {
   sprintf(filename, "%s_%04i.dump", log->base_name, engine_rank);
 }
 
+/**
+ * @brief Initialize the variable logger_mask_data.
+ *
+ * @param log The #logger_writer.
+ * @param e The #engine.
+ */
+void logger_init_masks(struct logger_writer *log, const struct engine *e) {
+  /* Set the pointers to 0 */
+  log->mask_data_pointers.hydro = NULL;
+  log->mask_data_pointers.stars = NULL;
+  log->mask_data_pointers.gravity = NULL;
+
+  /* Get the policies */
+  const int with_hydro = e->policy & engine_policy_hydro;
+  const int with_grav = (e->policy & engine_policy_self_gravity) ||
+                        (e->policy & engine_policy_external_gravity);
+  const int with_stars = e->policy & engine_policy_stars;
+
+  struct mask_data list[100];
+  int num_fields = 0;
+
+  /* The next fields must be the two first ones. */
+  /* Add the special flags (written manually => no need of offset) */
+  if (logger_index_special_flags != 0) {
+    error("Expecting the special flags to be the first element.");
+  }
+  list[logger_index_special_flags] =
+      logger_create_mask_entry("SpecialFlags", sizeof(int));
+  num_fields += 1;
+
+  /* Add the timestamp */
+  if (logger_index_timestamp != 1) {
+    error("Expecting the timestamp to be the first element.");
+  }
+  list[logger_index_timestamp] = logger_create_mask_entry(
+      "Timestamp", sizeof(integertime_t) + sizeof(double));
+  list[num_fields].type = mask_type_timestep;  // flag it as timestamp
+  num_fields += 1;
+
+  // TODO add chemistry, cooling, ... + xpart + spart
+
+  /* Get all the fields that need to be written for the hydro. */
+  if (with_hydro) {
+    struct mask_data *tmp = &list[num_fields];
+
+    /* Set the mask_data_pointers */
+    log->mask_data_pointers.hydro = tmp;
+
+    /* Set the masks */
+    num_fields = hydro_logger_populate_mask_data(tmp);
+    /* Set the particle type */
+    for (int i = 0; i < num_fields; i++) {
+      tmp[i].type = mask_type_gas;
+    }
+  }
+
+  /* Get all the fields that need to be written for the stars. */
+  if (with_stars) {
+    struct mask_data *tmp = &list[num_fields];
+
+    /* Set the mask_data_pointers */
+    log->mask_data_pointers.stars = tmp;
+
+    /* Set the masks */
+    int tmp_num_fields = stars_logger_populate_mask_data(tmp);
+    /* Set the particle type */
+    for (int i = 0; i < tmp_num_fields; i++) {
+      tmp[i].type = mask_type_stars;
+    }
+    num_fields += tmp_num_fields;
+  }
+
+  /* Get all the fields that need to be written for the gravity. */
+  if (with_grav) {
+    struct mask_data *tmp = &list[num_fields];
+
+    /* Set the mask_data_pointers */
+    log->mask_data_pointers.gravity = tmp;
+
+    /* Set the masks */
+    int tmp_num_fields = gravity_logger_populate_mask_data(tmp);
+    /* Set the particle type */
+    for (int i = 0; i < tmp_num_fields; i++) {
+      tmp[i].type = mask_type_dark_matter;
+    }
+    num_fields += tmp_num_fields;
+  }
+
+  /* Set the masks and ensure to have only one for the common fields
+     (e.g. Coordinates).
+     Initially we have (Name, mask, part_type):
+      - Coordinates, 0, 0
+      - Velocity, 0, 0
+      - Coordinates, 0, 1
+
+      And get:
+      - Coordinates, 1, 0
+      - Velocity, 2, 0
+      - Coordinates, 1, 1
+  */
+  int mask = 0;
+  for (int i = 0; i < num_fields; i++) {
+    /* Skip the elements already processed. */
+    if (list[i].mask != 0) {
+      continue;
+    }
+    const char *name = list[i].name;
+    list[i].mask = 1 << mask;
+
+    /* Check if the field exists in the other particle type. */
+    for (int j = i + 1; j < num_fields; j++) {
+      /* Check if the name is the same */
+      if (strcmp(name, list[j].name) == 0) {
+        /* Check if the data are the same */
+        if (list[i].size != list[j].size) {
+          error("Found two same fields but with different data size (%s).",
+                name);
+        }
+
+        list[j].mask = 1 << mask;
+      }
+    }
+    mask += 1;
+  }
+
+  /* Check that we have enough available flags. */
+  if (mask >= 8 * logger_mask_size) {
+    error(
+        "Not enough available flags for all the fields. "
+        "Please reduce the number of output fields.");
+  }
+
+  /* Save the data */
+  size_t size_list = sizeof(struct mask_data) * num_fields;
+  log->logger_mask_data = (struct mask_data *)malloc(size_list);
+  memcpy(log->logger_mask_data, list, size_list);
+
+  /* Update the pointers */
+  if (log->mask_data_pointers.hydro != NULL) {
+    log->mask_data_pointers.hydro =
+        log->logger_mask_data + (log->mask_data_pointers.hydro - list);
+  }
+  if (log->mask_data_pointers.stars != NULL) {
+    log->mask_data_pointers.stars =
+        log->logger_mask_data + (log->mask_data_pointers.stars - list);
+  }
+  if (log->mask_data_pointers.gravity != NULL) {
+    log->mask_data_pointers.gravity =
+        log->logger_mask_data + (log->mask_data_pointers.gravity - list);
+  }
+
+  /* Compute the maximal size of the records. */
+  log->max_size_record_part = 0;
+  if (with_hydro) {
+    for (int i = 0; i < hydro_logger_field_count; i++) {
+      log->max_size_record_part += log->mask_data_pointers.hydro[i].size;
+    }
+  }
+
+  log->max_size_record_gpart = 0;
+  if (with_grav) {
+    for (int i = 0; i < gravity_logger_field_count; i++) {
+      log->max_size_record_gpart += log->mask_data_pointers.gravity[i].size;
+    }
+  }
+
+  log->max_size_record_spart = 0;
+  if (with_stars) {
+    for (int i = 0; i < stars_logger_field_count; i++) {
+      log->max_size_record_spart += log->mask_data_pointers.stars[i].size;
+    }
+  }
+
+  /* Set the counter */
+  log->logger_count_mask = num_fields;
+
+#ifdef SWIFT_DEBUG_CHECKS
+  message("The logger contains the following masks:");
+  for (int i = 0; i < log->logger_count_mask; i++) {
+    message("%20s:\t mask=%03u\t size=%i", log->logger_mask_data[i].name,
+            log->logger_mask_data[i].mask, log->logger_mask_data[i].size);
+  }
+#endif
+}
+
 /**
  * @brief intialize the logger structure
  *
  * @param log The #logger_writer
+ * @param e The #engine.
  * @param params The #swift_params
  */
-void logger_init(struct logger_writer *log, struct swift_params *params) {
+void logger_init(struct logger_writer *log, const struct engine *e,
+                 struct swift_params *params) {
   /* read parameters. */
   log->delta_step = parser_get_param_int(params, "Logger:delta_step");
   size_t buffer_size =
@@ -647,6 +801,9 @@ void logger_init(struct logger_writer *log, struct swift_params *params) {
   log->index.mem_frac =
       parser_get_opt_param_float(params, "Logger:index_mem_frac", 0.05);
 
+  /* Initialize the logger_mask_data */
+  logger_init_masks(log, e);
+
   /* set initial value of parameters. */
   log->timestamp_offset = 0;
   log->index.dump_size_last_output = 0;
@@ -655,14 +812,17 @@ void logger_init(struct logger_writer *log, struct swift_params *params) {
   char logger_name_file[PARSER_MAX_LINE_SIZE];
   logger_get_dump_name(log, logger_name_file);
 
-  /* Compute max size for a particle chunk. */
+  /* Compute max size for a particle record. */
   int max_size = logger_offset_size + logger_mask_size;
 
   /* Loop over all fields except timestamp. */
-  for (int i = 0; i < logger_count_mask - 1; i++) {
-    max_size += logger_mask_data[i].size;
+  for (int i = 0; i < log->logger_count_mask; i++) {
+    /* Skip the timestamp */
+    if (i == logger_index_timestamp) continue;
+
+    max_size += log->logger_mask_data[i].size;
   }
-  log->max_chunk_size = max_size;
+  log->max_record_size = max_size;
 
   /* init dump. */
   dump_init(&log->dump, logger_name_file, buffer_size);
@@ -673,7 +833,13 @@ void logger_init(struct logger_writer *log, struct swift_params *params) {
  *
  * @param log The #logger_writer
  */
-void logger_free(struct logger_writer *log) { dump_close(&log->dump); }
+void logger_free(struct logger_writer *log) {
+  dump_close(&log->dump);
+
+  free(log->logger_mask_data);
+  log->logger_mask_data = NULL;
+  log->logger_count_mask = 0;
+}
 
 /**
  * @brief Write a file header to a logger file
@@ -716,37 +882,53 @@ void logger_write_file_header(struct logger_writer *log) {
   const unsigned int label_size = logger_label_size;
   logger_write_data(dump, &file_offset, sizeof(unsigned int), &label_size);
 
-  /* write number of masks. */
-  const unsigned int count_mask = logger_count_mask;
-  logger_write_data(dump, &file_offset, sizeof(unsigned int), &count_mask);
+  /* placeholder to write the number of unique masks. */
+  char *skip_unique_masks = dump_get(dump, sizeof(unsigned int), &file_offset);
 
   /* write masks. */
   // loop over all mask type.
-  for (int i = 0; i < logger_count_mask; i++) {
+  unsigned int unique_mask = 0;
+  for (int i = 0; i < log->logger_count_mask; i++) {
+    /* Check if the mask was not already written */
+    int is_written = 0;
+    for (int j = 0; j < i; j++) {
+      if (log->logger_mask_data[i].mask == log->logger_mask_data[j].mask) {
+        is_written = 1;
+        break;
+      }
+    }
+
+    if (is_written) {
+      continue;
+    }
+
+    unique_mask += 1;
+
     // mask name.
     logger_write_data(dump, &file_offset, logger_label_size,
-                      &logger_mask_data[i].name);
+                      &log->logger_mask_data[i].name);
 
     // mask size.
     logger_write_data(dump, &file_offset, sizeof(unsigned int),
-                      &logger_mask_data[i].size);
+                      &log->logger_mask_data[i].size);
   }
+  memcpy(skip_unique_masks, &unique_mask, sizeof(unsigned int));
 
   /* last step: write first offset. */
   memcpy(skip_header, &file_offset, logger_offset_size);
 }
 
 /**
- * @brief read chunk header
+ * @brief read record header
  *
  * @param buff The reading buffer
  * @param mask The mask to read
- * @param offset (return) the offset pointed by this chunk (absolute)
- * @param cur_offset The current chunk offset
+ * @param offset (return) the offset pointed by this record (absolute)
+ * @param cur_offset The current record offset
  *
  * @return Number of bytes read
  */
-__attribute__((always_inline)) INLINE static int logger_read_chunk_header(
+__attribute__((always_inline)) INLINE static int logger_read_record_header(
     const char *buff, unsigned int *mask, size_t *offset, size_t cur_offset) {
   memcpy(mask, buff, logger_mask_size);
   buff += logger_mask_size;
@@ -768,7 +950,8 @@ __attribute__((always_inline)) INLINE static int logger_read_chunk_header(
  *
  * @return The mask containing the values read.
  */
-int logger_read_part(struct part *p, size_t *offset, const char *buff) {
+int logger_read_part(const struct logger_writer *log, struct part *p,
+                     size_t *offset, const char *buff) {
 
   /* Jump to the offset. */
   buff = &buff[*offset];
@@ -776,62 +959,46 @@ int logger_read_part(struct part *p, size_t *offset, const char *buff) {
   /* Start by reading the logger mask for this entry. */
   const size_t cur_offset = *offset;
   unsigned int mask = 0;
-  buff += logger_read_chunk_header(buff, &mask, offset, cur_offset);
-
-  /* We are only interested in particle data. */
-  if (mask & logger_mask_data[logger_timestamp].mask)
-    error("Trying to read timestamp as particle.");
-
-  /* Particle position as three doubles. */
-  if (mask & logger_mask_data[logger_x].mask) {
-    memcpy(p->x, buff, logger_mask_data[logger_x].size);
-    buff += logger_mask_data[logger_x].size;
-  }
-
-  /* Particle velocity as three floats. */
-  if (mask & logger_mask_data[logger_v].mask) {
-    memcpy(p->v, buff, logger_mask_data[logger_v].size);
-    buff += logger_mask_data[logger_v].size;
-  }
-
-  /* Particle accelleration as three floats. */
-  if (mask & logger_mask_data[logger_a].mask) {
-    memcpy(p->a_hydro, buff, logger_mask_data[logger_a].size);
-    buff += logger_mask_data[logger_a].size;
-  }
-
+  buff += logger_read_record_header(buff, &mask, offset, cur_offset);
+
+  for (int i = 0; i < log->logger_count_mask; i++) {
+    if ((mask & log->logger_mask_data[i].mask) &&
+        (log->logger_mask_data[i].type == mask_type_gas)) {
+
+      const char *name = log->logger_mask_data[i].name;
+      if (strcmp("Coordinates", name) == 0) {
+        memcpy(p->x, buff, 3 * sizeof(double));
+        buff += 3 * sizeof(double);
+      } else if (strcmp("Velocities", name) == 0) {
+        memcpy(p->v, buff, 3 * sizeof(float));
+        buff += 3 * sizeof(float);
+      } else if (strcmp("Accelerations", name) == 0) {
+        memcpy(p->a_hydro, buff, 3 * sizeof(float));
+        buff += 3 * sizeof(float);
+      } else if (strcmp("SmoothingLengths", name) == 0) {
+        memcpy(&p->h, buff, sizeof(float));
+        buff += sizeof(float);
+      }
 #if defined(GADGET2_SPH)
-
-  /* Particle internal energy as a single float. */
-  if (mask & logger_mask_data[logger_u].mask) {
-    memcpy(&p->entropy, buff, logger_mask_data[logger_u].size);
-    buff += logger_mask_data[logger_u].size;
-  }
-
-  /* Particle smoothing length as a single float. */
-  if (mask & logger_mask_data[logger_h].mask) {
-    memcpy(&p->h, buff, logger_mask_data[logger_h].size);
-    buff += logger_mask_data[logger_h].size;
-  }
-
-  /* Particle density as a single float. */
-  if (mask & logger_mask_data[logger_rho].mask) {
-    memcpy(&p->rho, buff, logger_mask_data[logger_rho].size);
-    buff += logger_mask_data[logger_rho].size;
-  }
-
-  /* Particle constants, which is a bit more complicated. */
-  if (mask & logger_mask_data[logger_rho].mask) {
-    // TODO make it dependent of logger_mask_data.
-    memcpy(&p->mass, buff, sizeof(float));
-    buff += sizeof(float);
-    int64_t id = 0;
-    memcpy(&id, buff, sizeof(int64_t));
-    p->id = id;
-    buff += sizeof(int64_t);
-  }
-
+      else if (strcmp("Entropies", name) == 0) {
+        memcpy(&p->entropy, buff, sizeof(float));
+        buff += sizeof(float);
+      } else if (strcmp("Masses", name) == 0) {
+        memcpy(&p->mass, buff, sizeof(float));
+        buff += sizeof(float);
+      } else if (strcmp("Densities", name) == 0) {
+        memcpy(&p->rho, buff, sizeof(float));
+        buff += sizeof(float);
+      } else if (strcmp("ParticleIDs", name) == 0) {
+        memcpy(&p->id, buff, sizeof(long long));
+        buff += sizeof(long long);
+      }
 #endif
+      else {
+        error("Field '%s' not found", name);
+      }
+    }
+  }
 
   /* Finally, return the mask of the values we just read. */
   return mask;
@@ -847,7 +1014,8 @@ int logger_read_part(struct part *p, size_t *offset, const char *buff) {
  *
  * @return The mask containing the values read.
  */
-int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) {
+int logger_read_gpart(const struct logger_writer *log, struct gpart *p,
+                      size_t *offset, const char *buff) {
 
   /* Jump to the offset. */
   buff = &buff[*offset];
@@ -855,43 +1023,32 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) {
   /* Start by reading the logger mask for this entry. */
   const size_t cur_offset = *offset;
   unsigned int mask = 0;
-  buff += logger_read_chunk_header(buff, &mask, offset, cur_offset);
-
-  /* We are only interested in particle data. */
-  if (mask & logger_mask_data[logger_timestamp].mask)
-    error("Trying to read timestamp as particle.");
-
-  /* We can't store all part fields in a gpart. */
-  if (mask &
-      (logger_mask_data[logger_u].mask | logger_mask_data[logger_rho].mask))
-    error("Trying to read SPH quantities into a gpart.");
-
-  /* Particle position as three doubles. */
-  if (mask & logger_mask_data[logger_x].mask) {
-    memcpy(p->x, buff, logger_mask_data[logger_x].size);
-    buff += logger_mask_data[logger_x].size;
-  }
-
-  /* Particle velocity as three floats. */
-  if (mask & logger_mask_data[logger_v].mask) {
-    memcpy(p->v_full, buff, logger_mask_data[logger_v].size);
-    buff += logger_mask_data[logger_v].size;
-  }
-
-  /* Particle accelleration as three floats. */
-  if (mask & logger_mask_data[logger_a].mask) {
-    memcpy(p->a_grav, buff, logger_mask_data[logger_a].size);
-    buff += logger_mask_data[logger_a].size;
-  }
-
-  /* Particle constants, which is a bit more complicated. */
-  if (mask & logger_mask_data[logger_rho].mask) {
-    // TODO make it dependent of logger_mask_data
-    memcpy(&p->mass, buff, sizeof(float));
-    buff += sizeof(float);
-    int64_t id = p->id_or_neg_offset;
-    memcpy(&id, buff, sizeof(int64_t));
-    buff += sizeof(int64_t);
+  buff += logger_read_record_header(buff, &mask, offset, cur_offset);
+
+  for (int i = 0; i < log->logger_count_mask; i++) {
+    if ((mask & log->logger_mask_data[i].mask) &&
+        (log->logger_mask_data[i].type == mask_type_dark_matter)) {
+
+      const char *name = log->logger_mask_data[i].name;
+      if (strcmp("Coordinates", name) == 0) {
+        memcpy(p->x, buff, 3 * sizeof(double));
+        buff += 3 * sizeof(double);
+      } else if (strcmp("Velocities", name) == 0) {
+        memcpy(p->v_full, buff, 3 * sizeof(float));
+        buff += 3 * sizeof(float);
+      } else if (strcmp("Accelerations", name) == 0) {
+        memcpy(p->a_grav, buff, 3 * sizeof(float));
+        buff += 3 * sizeof(float);
+      } else if (strcmp("ParticleIDs", name) == 0) {
+        memcpy(&p->id_or_neg_offset, buff, sizeof(long long));
+        buff += sizeof(long long);
+      } else if (strcmp("Masses", name) == 0) {
+        memcpy(&p->mass, buff, sizeof(float));
+        buff += sizeof(float);
+      } else {
+        error("Field '%s' not found", name);
+      }
+    }
   }
 
   /* Finally, return the mask of the values we just read. */
@@ -901,6 +1058,7 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) {
 /**
  * @brief Read a logger message for a timestamp.
  *
+ * @param log The #logger_writer.
  * @param t The timestamp in which to store the value.
  * @param time The time in which to store the value.
  * @param offset Pointer to the offset of the logger message in the buffer,
@@ -909,8 +1067,8 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) {
  *
  * @return The mask containing the values read.
  */
-int logger_read_timestamp(unsigned long long int *t, double *time,
-                          size_t *offset, const char *buff) {
+int logger_read_timestamp(const struct logger_writer *log, integertime_t *t,
+                          double *time, size_t *offset, const char *buff) {
 
   /* Jump to the offset. */
   buff = &buff[*offset];
@@ -918,20 +1076,19 @@ int logger_read_timestamp(unsigned long long int *t, double *time,
   /* Start by reading the logger mask for this entry. */
   const size_t cur_offset = *offset;
   unsigned int mask = 0;
-  buff += logger_read_chunk_header(buff, &mask, offset, cur_offset);
+  buff += logger_read_record_header(buff, &mask, offset, cur_offset);
 
   /* We are only interested in timestamps. */
-  if (!(mask & logger_mask_data[logger_timestamp].mask))
+  if (!(mask & log->logger_mask_data[logger_index_timestamp].mask))
     error("Trying to read timestamp from a particle.");
 
   /* Make sure we don't have extra fields. */
-  if (mask != logger_mask_data[logger_timestamp].mask)
+  if (mask != log->logger_mask_data[logger_index_timestamp].mask)
     error("Timestamp message contains extra fields.");
 
   /* Copy the timestamp value from the buffer. */
-  // TODO make it dependent of logger_mask_data.
-  memcpy(t, buff, sizeof(unsigned long long int));
-  buff += sizeof(unsigned long long int);
+  memcpy(t, buff, sizeof(integertime_t));
+  buff += sizeof(integertime_t);
 
   /* Copy the timestamp value from the buffer. */
   memcpy(time, buff, sizeof(double));
@@ -949,6 +1106,11 @@ int logger_read_timestamp(unsigned long long int *t, double *time,
 void logger_struct_dump(const struct logger_writer *log, FILE *stream) {
   restart_write_blocks((void *)log, sizeof(struct logger_writer), 1, stream,
                        "logger", "logger");
+
+  /* Write the masks */
+  restart_write_blocks((void *)log->logger_mask_data, sizeof(struct mask_data),
+                       log->logger_count_mask, stream, "logger_masks",
+                       "logger_masks");
 }
 
 /**
@@ -963,6 +1125,13 @@ void logger_struct_restore(struct logger_writer *log, FILE *stream) {
   restart_read_blocks((void *)log, sizeof(struct logger_writer), 1, stream,
                       NULL, "logger");
 
+  /* Read the masks */
+  log->logger_mask_data = (struct mask_data *)malloc(sizeof(struct mask_data) *
+                                                     log->logger_count_mask);
+
+  restart_read_blocks((void *)log->logger_mask_data, sizeof(struct mask_data),
+                      log->logger_count_mask, stream, NULL, "logger_masks");
+
   /* generate dump filename */
   char logger_name_file[PARSER_MAX_LINE_SIZE];
   logger_get_dump_name(log, logger_name_file);
diff --git a/src/logger.h b/src/logger.h
index 036106cead6ef2c9057ff785348fc1c6fcbab386..78d8bbeabeaca191de1ec3dc928f5a7cc1a2a96f 100644
--- a/src/logger.h
+++ b/src/logger.h
@@ -39,7 +39,9 @@ struct part;
 struct engine;
 
 #define logger_major_version 0
-#define logger_minor_version 3
+#define logger_minor_version 4
+/* Size of the strings. */
+#define logger_string_length 200
 
 /**
  * Logger entries contain messages representing the particle data at a given
@@ -75,35 +77,10 @@ struct engine;
  * The offset refers to the relative location of the previous message for the
  * same particle or for the previous timestamp (if mask bit 7 is set). I.e.
  * the previous log entry will be at the address of the current mask byte minus
- * the unsigned value stored in the offset. An offset equal to the chunk offset
+ * the unsigned value stored in the offset. An offset equal to the record offset
  * indicated that this is the first message for the given particle/timestamp.
  */
 
-/* Some constants. */
-enum logger_masks_number {
-  logger_x = 0,
-  logger_v = 1,
-  logger_a = 2,
-  logger_u = 3,
-  logger_h = 4,
-  logger_rho = 5,
-  logger_consts = 6,
-  logger_special_flags = 7, /* Flag for special cases */
-  logger_timestamp = 8,     /* expect it to be before count. */
-  logger_count_mask = 9,    /* Need to be the last. */
-} __attribute__((packed));
-
-/* Defines some mask for logging all the fields */
-enum logger_masks_all {
-  logger_masks_all_part = (1 << logger_x) | (1 << logger_v) | (1 << logger_a) |
-                          (1 << logger_u) | (1 << logger_h) |
-                          (1 << logger_rho) | (1 << logger_consts),
-  logger_masks_all_gpart = (1 << logger_x) | (1 << logger_v) | (1 << logger_a) |
-                           (1 << logger_consts),
-  logger_masks_all_spart =
-      (1 << logger_x) | (1 << logger_v) | (1 << logger_consts),
-} __attribute__((packed));
-
 enum logger_special_flags {
   logger_flag_change_type = 1, /* Flag for a change of particle type */
   logger_flag_mpi_enter, /* Flag for a particle received from another  MPI rank
@@ -113,27 +90,11 @@ enum logger_special_flags {
   logger_flag_create,    /* Flag for a created particle */
 } __attribute__((packed));
 
-struct mask_data {
-  /* Number of bytes for a mask. */
-  int size;
-
-  /* Mask value. */
-  unsigned int mask;
-
-  /* Name of the mask. */
-  char name[100];
-};
-
-extern const struct mask_data logger_mask_data[logger_count_mask];
-
-/* Size of the strings. */
-#define logger_string_length 200
-
 /**
  * @brief structure containing global data for the particle logger.
  */
 struct logger_writer {
-  /* Number of particle steps between dumping a chunk of data. */
+  /* Number of particle updates between log entries. */
   short int delta_step;
 
   /* Logger basename. */
@@ -157,8 +118,35 @@ struct logger_writer {
   /* scaling factor when buffer is too small. */
   float buffer_scale;
 
-  /* Size of a chunk if every mask are activated. */
-  int max_chunk_size;
+  /* Size of a record if every mask are activated. */
+  int max_record_size;
+
+  /* Description of all the fields that can be written. */
+  struct mask_data *logger_mask_data;
+
+  /* Pointer to the variable logger_mask_data for each module. */
+  struct {
+    /* pointer for the hydro */
+    struct mask_data *hydro;
+
+    /* pointer for the gravity */
+    struct mask_data *gravity;
+
+    /* pointer for the stars */
+    struct mask_data *stars;
+  } mask_data_pointers;
+
+  /* Number of elements in logger_mask_data. */
+  int logger_count_mask;
+
+  /* Maximum size for a hydro record. */
+  int max_size_record_part;
+
+  /* Maximum size for a gravity record. */
+  int max_size_record_gpart;
+
+  /* Maximum size for a star record. */
+  int max_size_record_spart;
 
 } SWIFT_STRUCT_ALIGN;
 
@@ -172,23 +160,28 @@ struct logger_part_data {
 };
 
 /* Function prototypes. */
-int logger_compute_chunk_size(unsigned int mask);
-void logger_log_all(struct logger_writer *log, const struct engine *e);
+void logger_log_all_particles(struct logger_writer *log,
+                              const struct engine *e);
 void logger_log_part(struct logger_writer *log, const struct part *p,
-                     struct xpart *xp, unsigned int mask,
-                     const uint32_t special_flags);
+                     struct xpart *xp, const struct engine *e,
+                     const int log_all_fields, const uint32_t special_flags);
 void logger_log_parts(struct logger_writer *log, const struct part *p,
-                      struct xpart *xp, int count, unsigned int mask,
-                      const uint32_t special_flags);
+                      struct xpart *xp, int count, const struct engine *e,
+                      const int log_all_fields, const uint32_t special_flags);
 void logger_log_spart(struct logger_writer *log, struct spart *p,
-                      unsigned int mask, const uint32_t special_flags);
+                      const struct engine *e, const int log_all_fields,
+                      const uint32_t special_flags);
 void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
-                       unsigned int mask, const uint32_t special_flags);
+                       const struct engine *e, const int log_all_fields,
+                       const uint32_t special_flags);
 void logger_log_gpart(struct logger_writer *log, struct gpart *p,
-                      unsigned int mask, const uint32_t special_flags);
+                      const struct engine *e, const int log_all_fields,
+                      const uint32_t special_flags);
 void logger_log_gparts(struct logger_writer *log, struct gpart *gp, int count,
-                       unsigned int mask, const uint32_t special_flags);
-void logger_init(struct logger_writer *log, struct swift_params *params);
+                       const struct engine *e, const int log_all_fields,
+                       const uint32_t special_flags);
+void logger_init(struct logger_writer *log, const struct engine *e,
+                 struct swift_params *params);
 void logger_free(struct logger_writer *log);
 void logger_log_timestamp(struct logger_writer *log, integertime_t t,
                           double time, size_t *offset);
@@ -196,10 +189,12 @@ void logger_ensure_size(struct logger_writer *log, size_t total_nr_parts,
                         size_t total_nr_gparts, size_t total_nr_sparts);
 void logger_write_file_header(struct logger_writer *log);
 
-int logger_read_part(struct part *p, size_t *offset, const char *buff);
-int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff);
-int logger_read_timestamp(unsigned long long int *t, double *time,
-                          size_t *offset, const char *buff);
+int logger_read_part(const struct logger_writer *log, struct part *p,
+                     size_t *offset, const char *buff);
+int logger_read_gpart(const struct logger_writer *log, struct gpart *p,
+                      size_t *offset, const char *buff);
+int logger_read_timestamp(const struct logger_writer *log, integertime_t *t,
+                          double *time, size_t *offset, const char *buff);
 void logger_struct_dump(const struct logger_writer *log, FILE *stream);
 void logger_struct_restore(struct logger_writer *log, FILE *stream);
 
diff --git a/src/logger_io.h b/src/logger_io.h
index f1a0415ab6967f04e85375f26dd9b080530cc05e..495e4754202ac9969a46e6697b1a8a421740c5c4 100644
--- a/src/logger_io.h
+++ b/src/logger_io.h
@@ -30,6 +30,104 @@
 #include "part.h"
 #include "units.h"
 
+/* This enum defines the type of particle to use
+   with a given mask.
+   The values should be the same than in part_type.h. */
+enum mask_type {
+  mask_type_gas = 0,
+  mask_type_dark_matter = 1,
+  /* Only need a single type of dm. */
+  mask_type_stars = 4,
+  mask_type_black_hole = 5,
+  mask_type_timestep = -1,
+} __attribute__((packed));
+
+struct mask_data {
+  /* Number of bytes for a mask. */
+  int size;
+
+  /* Mask value. */
+  unsigned int mask;
+
+  /* Type of particle (follow part_type.h and -1 for timestamp). */
+  enum mask_type type;
+
+  /* Name of the mask. */
+  char name[100];
+};
+
+/**
+ * @brief Initialize the mask_data with a given field.
+ *
+ * @param name The name of the field.
+ * @param size The size of the field.
+ *
+ * @return The new mask_data.
+ */
+INLINE static struct mask_data logger_create_mask_entry(const char* name,
+                                                        int size) {
+  struct mask_data mask;
+  /* Copy the fields */
+  strcpy(mask.name, name);
+  mask.size = size;
+  mask.mask = 0;
+
+  return mask;
+}
+
+/**
+ * @brief Add a given field to the current mask.
+ *
+ * @param mask_data The mask_data corresponding to the field that we wish to
+ * write.
+ * @param name The name of the field.
+ * @param buffer_size (in) The current size of the future buffer. (out) The
+ * updated size.
+ *
+ * @return The mask of the current field.
+ */
+INLINE static size_t logger_add_field_to_mask(struct mask_data mask_data,
+                                              const char* name,
+                                              size_t* buffer_size) {
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Check that we are writing the requested field. */
+  if (strcmp(name, mask_data.name) != 0) {
+    error("Mismatch between the requested field (%s) and the mask (%s)", name,
+          mask_data.name);
+  }
+#endif
+
+  *buffer_size += mask_data.size;
+  return mask_data.mask;
+}
+
+/**
+ * @brief Check if a field should be written according to the mask set in
+ * #logger_add_field_to_mask.
+ *
+ * @param mask_data The mask_data corresponding to the current field.
+ * @param name The name of the field that we are checking.
+ * @param mask The mask used for the current record.
+ */
+INLINE static int logger_should_write_field(struct mask_data mask_data,
+                                            unsigned int* mask,
+                                            const char* name) {
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Check that we are writing the requested field. */
+  if (strcmp(name, mask_data.name) != 0) {
+    error("Mismatch between the requested field (%s) and the mask (%s)", name,
+          mask_data.name);
+  }
+#endif
+
+  const int test = mask_data.mask & *mask;
+  if (test) {
+    *mask &= ~mask_data.mask;
+  }
+
+  return test;
+}
+
 void logger_write_index_file(struct logger_writer* log, struct engine* e);
 void logger_write_description(struct logger_writer* log, struct engine* e);
 
diff --git a/src/runner_others.c b/src/runner_others.c
index 324b0ccf97ce9f9fc95c2094ff619ddbe8bb9a69..083a73069c9f92b41eb35d2c28855e8714ee8ed6 100644
--- a/src/runner_others.c
+++ b/src/runner_others.c
@@ -49,6 +49,7 @@
 #include "gravity.h"
 #include "hydro.h"
 #include "logger.h"
+#include "logger_io.h"
 #include "pressure_floor.h"
 #include "space.h"
 #include "star_formation.h"
@@ -328,15 +329,7 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) {
             /* Write the particle */
             /* Logs all the fields request by the user */
             // TODO select only the requested fields
-            logger_log_part(e->logger, p, xp,
-                            logger_mask_data[logger_x].mask |
-                                logger_mask_data[logger_v].mask |
-                                logger_mask_data[logger_a].mask |
-                                logger_mask_data[logger_u].mask |
-                                logger_mask_data[logger_h].mask |
-                                logger_mask_data[logger_rho].mask |
-                                logger_mask_data[logger_consts].mask |
-                                logger_mask_data[logger_special_flags].mask,
+            logger_log_part(e->logger, p, xp, e, /* log_all */ 1,
                             logger_pack_flags_and_data(logger_flag_change_type,
                                                        swift_type_stars));
 #endif
@@ -396,10 +389,8 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) {
               sp->logger_data = xp->logger_data;
 
               /* Write the s-particle */
-              logger_log_spart(e->logger, sp,
-                               logger_mask_data[logger_x].mask |
-                                   logger_mask_data[logger_v].mask |
-                                   logger_mask_data[logger_consts].mask,
+              logger_log_spart(e->logger, sp, e,
+                               /* log_all */ 1,
                                /* special flags */ 0);
 #endif
             } else {
@@ -689,14 +680,7 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) {
         if (logger_should_write(&xp->logger_data, e->logger)) {
           /* Write particle */
           /* Currently writing everything, should adapt it through time */
-          logger_log_part(e->logger, p, xp,
-                          logger_mask_data[logger_x].mask |
-                              logger_mask_data[logger_v].mask |
-                              logger_mask_data[logger_a].mask |
-                              logger_mask_data[logger_u].mask |
-                              logger_mask_data[logger_h].mask |
-                              logger_mask_data[logger_rho].mask |
-                              logger_mask_data[logger_consts].mask,
+          logger_log_part(e->logger, p, xp, e, /* log_all */ 0,
                           /* special flags */ 0);
         } else
           /* Update counter */
@@ -719,11 +703,7 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) {
         if (logger_should_write(&gp->logger_data, e->logger)) {
           /* Write particle */
           /* Currently writing everything, should adapt it through time */
-          logger_log_gpart(e->logger, gp,
-                           logger_mask_data[logger_x].mask |
-                               logger_mask_data[logger_v].mask |
-                               logger_mask_data[logger_a].mask |
-                               logger_mask_data[logger_consts].mask,
+          logger_log_gpart(e->logger, gp, e, /* log_all */ 0,
                            /* Special flags */ 0);
 
         } else
@@ -744,10 +724,7 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) {
         if (logger_should_write(&sp->logger_data, e->logger)) {
           /* Write particle */
           /* Currently writing everything, should adapt it through time */
-          logger_log_spart(e->logger, sp,
-                           logger_mask_data[logger_x].mask |
-                               logger_mask_data[logger_v].mask |
-                               logger_mask_data[logger_consts].mask,
+          logger_log_spart(e->logger, sp, e, /* Log_all */ 0,
                            /* Special flags */ 0);
         } else
           /* Update counter */
diff --git a/src/stars/Default/stars_io.h b/src/stars/Default/stars_io.h
index 88444726329bad9baf797aaa8437c48d4fbc1516..02538449191a24bf2f9dd82a928fe51d3b883245 100644
--- a/src/stars/Default/stars_io.h
+++ b/src/stars/Default/stars_io.h
@@ -265,5 +265,4 @@ INLINE static void stars_props_struct_restore(const struct stars_props *p,
   restart_read_blocks((void *)p, sizeof(struct stars_props), 1, stream, NULL,
                       "stars props");
 }
-
 #endif /* SWIFT_DEFAULT_STAR_IO_H */
diff --git a/src/stars/Default/stars_logger.h b/src/stars/Default/stars_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f6e07060f10095cdbd86ae7ecf87b4930853e26
--- /dev/null
+++ b/src/stars/Default/stars_logger.h
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * 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_DEFAULT_STARS_LOGGER_H
+#define SWIFT_DEFAULT_STARS_LOGGER_H
+
+#ifdef WITH_LOGGER
+
+/*
+ * List of all possible mask.
+ * Outside the module, only stars_logger_field_count is used.
+ */
+enum stars_logger_fields_mask {
+  stars_logger_field_coordinates = 0,
+  stars_logger_field_velocities,
+  stars_logger_field_accelerations,
+  stars_logger_field_masses,
+  stars_logger_field_smoothing_lengths,
+  stars_logger_field_particle_ids,
+  stars_logger_field_count,
+};
+
+/* Name of each possible mask. */
+static const char *stars_logger_field_names[stars_logger_field_count] = {
+    "Coordinates", "Velocities",       "Accelerations",
+    "Masses",      "SmoothingLengths", "ParticleIDs",
+};
+
+/**
+ * @brief Initialize the logger.
+ *
+ * WARNING: this should be done in the same order than
+ * #stars_logger_write_particle.
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int stars_logger_populate_mask_data(struct mask_data *mask_data) {
+  mask_data[stars_logger_field_coordinates] = logger_create_mask_entry(
+      stars_logger_field_names[stars_logger_field_coordinates],
+      3 * sizeof(double));
+
+  mask_data[stars_logger_field_velocities] = logger_create_mask_entry(
+      stars_logger_field_names[stars_logger_field_velocities],
+      3 * sizeof(float));
+
+  mask_data[stars_logger_field_accelerations] = logger_create_mask_entry(
+      stars_logger_field_names[stars_logger_field_accelerations],
+      3 * sizeof(float));
+
+  mask_data[stars_logger_field_masses] = logger_create_mask_entry(
+      stars_logger_field_names[stars_logger_field_masses], sizeof(float));
+
+  mask_data[stars_logger_field_smoothing_lengths] = logger_create_mask_entry(
+      stars_logger_field_names[stars_logger_field_smoothing_lengths],
+      sizeof(float));
+
+  mask_data[stars_logger_field_particle_ids] = logger_create_mask_entry(
+      stars_logger_field_names[stars_logger_field_particle_ids],
+      sizeof(long long));
+
+  return stars_logger_field_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record.
+ *
+ * @param masks The list of masks (same order than in #stars_logger_init).
+ * @param part The #spart 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 stars_logger_compute_size_and_mask(
+    const struct mask_data *masks, const struct spart *part,
+    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[stars_logger_field_coordinates],
+      stars_logger_field_names[stars_logger_field_coordinates], buffer_size);
+
+  /* Add the velocities. */
+  *mask |= logger_add_field_to_mask(
+      masks[stars_logger_field_velocities],
+      stars_logger_field_names[stars_logger_field_velocities], buffer_size);
+
+  /* Add the accelerations. */
+  *mask |= logger_add_field_to_mask(
+      masks[stars_logger_field_accelerations],
+      stars_logger_field_names[stars_logger_field_accelerations], buffer_size);
+
+  /* Add the masses. */
+  *mask |= logger_add_field_to_mask(
+      masks[stars_logger_field_masses],
+      stars_logger_field_names[stars_logger_field_masses], buffer_size);
+
+  /* Add the smoothing lengths. */
+  *mask |= logger_add_field_to_mask(
+      masks[stars_logger_field_smoothing_lengths],
+      stars_logger_field_names[stars_logger_field_smoothing_lengths],
+      buffer_size);
+
+  /* Add the ID. */
+  *mask |= logger_add_field_to_mask(
+      masks[stars_logger_field_particle_ids],
+      stars_logger_field_names[stars_logger_field_particle_ids], buffer_size);
+}
+
+/**
+ * @brief Write a particle to the logger.
+ *
+ * @param masks The list of masks (same order than in #stars_logger_init).
+ * @param p The #spart 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 *stars_logger_write_particle(
+    const struct mask_data *mask_data, const struct spart *p,
+    unsigned int *mask, char *buff) {
+
+  /* Write the coordinate. */
+  if (logger_should_write_field(
+          mask_data[stars_logger_field_coordinates], mask,
+          stars_logger_field_names[stars_logger_field_coordinates])) {
+    memcpy(buff, p->x, 3 * sizeof(double));
+    buff += 3 * sizeof(double);
+  }
+
+  /* Write the velocity. */
+  if (logger_should_write_field(
+          mask_data[stars_logger_field_velocities], mask,
+          stars_logger_field_names[stars_logger_field_velocities])) {
+    memcpy(buff, p->v, 3 * sizeof(float));
+    buff += 3 * sizeof(float);
+  }
+
+  /* Write the acceleration. */
+  if (logger_should_write_field(
+          mask_data[stars_logger_field_accelerations], mask,
+          stars_logger_field_names[stars_logger_field_accelerations])) {
+    memcpy(buff, p->gpart->a_grav, 3 * sizeof(float));
+    buff += 3 * sizeof(float);
+  }
+
+  /* Write the mass. */
+  if (logger_should_write_field(
+          mask_data[stars_logger_field_masses], mask,
+          stars_logger_field_names[stars_logger_field_masses])) {
+    memcpy(buff, &p->mass, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the smoothing length. */
+  if (logger_should_write_field(
+          mask_data[stars_logger_field_smoothing_lengths], mask,
+          stars_logger_field_names[stars_logger_field_smoothing_lengths])) {
+    memcpy(buff, &p->h, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  /* Write the Id. */
+  if (logger_should_write_field(
+          mask_data[stars_logger_field_particle_ids], mask,
+          stars_logger_field_names[stars_logger_field_particle_ids])) {
+    memcpy(buff, &p->id, sizeof(long long));
+    buff += sizeof(long long);
+  }
+
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_DEFAULT_STARS_LOGGER_H
diff --git a/src/stars_io.h b/src/stars_io.h
index 18224b1ef9a189c719d3674a037eb4b26cd14d4e..6cf92eac91c2eca09070864a8410ac720cc2ee5b 100644
--- a/src/stars_io.h
+++ b/src/stars_io.h
@@ -27,6 +27,7 @@
 #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/tests/testLogger.c b/tests/testLogger.c
index 5976597054c639a65f827876f1f244bc1a6024ce..d0f40522ed3a4df5de9d25a314dec85d01f6093b 100644
--- a/tests/testLogger.c
+++ b/tests/testLogger.c
@@ -34,45 +34,38 @@
 
 void test_log_parts(struct logger_writer *log) {
   struct dump *d = &log->dump;
+  struct engine e;
 
   /* Write several copies of a part to the dump. */
   struct part p;
+  struct xpart xp;
   bzero(&p, sizeof(struct part));
+  bzero(&xp, sizeof(struct xpart));
   p.x[0] = 1.0;
   p.v[0] = 0.1;
-
-  /* Start with an offset at the end of the dump. */
-  size_t offset = d->count;
+  xp.logger_data.last_offset = 0;
 
   /* Write the full part. */
-  logger_log_part(
-      log, &p,
-      logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask |
-          logger_mask_data[logger_a].mask | logger_mask_data[logger_u].mask |
-          logger_mask_data[logger_h].mask | logger_mask_data[logger_rho].mask |
-          logger_mask_data[logger_consts].mask,
-      &offset, /* special flags */ 0);
-  printf("Wrote part at offset %#016zx.\n", offset);
+  logger_log_part(log, &p, &xp, &e, /* log_all */ 1, /* special flags */ 0);
+  printf("Wrote part at offset %#016zx.\n", xp.logger_data.last_offset);
 
   /* Write only the position. */
   p.x[0] = 2.0;
-  logger_log_part(log, &p, logger_mask_data[logger_x].mask, &offset,
-                  /* special flags */ 0);
-  printf("Wrote part at offset %#016zx.\n", offset);
+  p.v[0] = 0.;
+  logger_log_part(log, &p, &xp, &e, /* log_all */ 0, /* special flags */ 0);
+  printf("Wrote part at offset %#016zx.\n", xp.logger_data.last_offset);
 
   /* Write the position and velocity. */
   p.x[0] = 3.0;
   p.v[0] = 0.3;
-  logger_log_part(
-      log, &p,
-      logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask,
-      &offset, /* special flags */ 0);
-  printf("Wrote part at offset %#016zx.\n", offset);
+  logger_log_part(log, &p, &xp, &e, /* log_all */ 0, /* special flags */ 0);
+  printf("Wrote part at offset %#016zx.\n", xp.logger_data.last_offset);
 
   /* Recover the last part from the dump. */
   bzero(&p, sizeof(struct part));
+  size_t offset = xp.logger_data.last_offset;
   size_t offset_old = offset;
-  int mask = logger_read_part(&p, &offset, (const char *)d->data);
+  unsigned int mask = logger_read_part(log, &p, &offset, (const char *)d->data);
   printf(
       "Recovered part at offset %#016zx with mask %#04x: p.x[0]=%e, "
       "p.v[0]=%e.\n",
@@ -85,7 +78,7 @@ void test_log_parts(struct logger_writer *log) {
   /* Recover the second part from the dump (only position). */
   bzero(&p, sizeof(struct part));
   offset_old = offset;
-  mask = logger_read_part(&p, &offset, (const char *)d->data);
+  mask = logger_read_part(log, &p, &offset, (const char *)d->data);
   printf(
       "Recovered part at offset %#016zx with mask %#04x: p.x[0]=%e, "
       "p.v[0]=%e.\n",
@@ -98,7 +91,7 @@ void test_log_parts(struct logger_writer *log) {
   /* Recover the first part from the dump. */
   bzero(&p, sizeof(struct part));
   offset_old = offset;
-  mask = logger_read_part(&p, &offset, (const char *)d->data);
+  mask = logger_read_part(log, &p, &offset, (const char *)d->data);
   printf(
       "Recovered part at offset %#016zx with mask %#04x: p.x[0]=%e, "
       "p.v[0]=%e.\n",
@@ -111,44 +104,37 @@ void test_log_parts(struct logger_writer *log) {
 
 void test_log_gparts(struct logger_writer *log) {
   struct dump *d = &log->dump;
+  struct engine e;
 
   /* Write several copies of a part to the dump. */
   struct gpart p;
   bzero(&p, sizeof(struct gpart));
   p.x[0] = 1.0;
   p.v_full[0] = 0.1;
-
-  /* Start with an offset at the end of the dump. */
-  size_t offset = d->count;
+  p.type = swift_type_dark_matter;
+  p.logger_data.last_offset = 0;
 
   /* Write the full part. */
-  logger_log_gpart(
-      log, &p,
-      logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask |
-          logger_mask_data[logger_a].mask | logger_mask_data[logger_h].mask |
-          logger_mask_data[logger_consts].mask,
-      &offset, /* special flags */ 0);
-  printf("Wrote gpart at offset %#016zx.\n", offset);
+  logger_log_gpart(log, &p, &e, /* log_all */ 1, /* special flags */ 0);
+  printf("Wrote gpart at offset %#016zx.\n", p.logger_data.last_offset);
 
   /* Write only the position. */
   p.x[0] = 2.0;
-  logger_log_gpart(log, &p, logger_mask_data[logger_x].mask, &offset,
-                   /* special flags */ 0);
-  printf("Wrote gpart at offset %#016zx.\n", offset);
+  p.v_full[0] = 0.;
+  logger_log_gpart(log, &p, &e, /* log_all */ 0, /* special flags */ 0);
+  printf("Wrote gpart at offset %#016zx.\n", p.logger_data.last_offset);
 
   /* Write the position and velocity. */
   p.x[0] = 3.0;
   p.v_full[0] = 0.3;
-  logger_log_gpart(
-      log, &p,
-      logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask,
-      &offset, /* special flags */ 0);
-  printf("Wrote gpart at offset %#016zx.\n", offset);
+  logger_log_gpart(log, &p, &e, /* log_all */ 0, /* special flags */ 0);
+  printf("Wrote gpart at offset %#016zx.\n", p.logger_data.last_offset);
 
   /* Recover the last part from the dump. */
+  size_t offset = p.logger_data.last_offset;
   bzero(&p, sizeof(struct gpart));
   size_t offset_old = offset;
-  int mask = logger_read_gpart(&p, &offset, (const char *)d->data);
+  int mask = logger_read_gpart(log, &p, &offset, (const char *)d->data);
   printf(
       "Recovered gpart at offset %#016zx with mask %#04x: p.x[0]=%e, "
       "p.v[0]=%e.\n",
@@ -161,7 +147,7 @@ void test_log_gparts(struct logger_writer *log) {
   /* Recover the second part from the dump. */
   bzero(&p, sizeof(struct gpart));
   offset_old = offset;
-  mask = logger_read_gpart(&p, &offset, (const char *)d->data);
+  mask = logger_read_gpart(log, &p, &offset, (const char *)d->data);
   printf(
       "Recovered gpart at offset %#016zx with mask %#04x: p.x[0]=%e, "
       "p.v[0]=%e.\n",
@@ -174,7 +160,7 @@ void test_log_gparts(struct logger_writer *log) {
   /* Recover the first part from the dump. */
   bzero(&p, sizeof(struct gpart));
   offset_old = offset;
-  mask = logger_read_gpart(&p, &offset, (const char *)d->data);
+  mask = logger_read_gpart(log, &p, &offset, (const char *)d->data);
   printf(
       "Recovered gpart at offset %#016zx with mask %#04x: p.x[0]=%e, "
       "p.v[0]=%e.\n",
@@ -189,7 +175,7 @@ void test_log_timestamps(struct logger_writer *log) {
   struct dump *d = &log->dump;
 
   /* The timestamp to log. */
-  unsigned long long int t = 10;
+  integertime_t t = 10;
   double time = 0.1;
 
   /* Start with an offset at the end of the dump. */
@@ -211,24 +197,29 @@ void test_log_timestamps(struct logger_writer *log) {
   size_t offset_old = offset;
   t = 0;
   time = 0;
-  int mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data);
-  printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t,
-         offset_old, mask);
+  int mask =
+      logger_read_timestamp(log, &t, &time, &offset, (const char *)d->data);
+  printf(
+      "Recovered timestamp %020llu with time %g at offset %#016zx with mask "
+      "%#04x.\n",
+      t, time, offset_old, mask);
   if (t != 30) {
     printf("FAIL: could not recover correct timestamp.\n");
     abort();
   }
   if (time != 0.3) {
-    printf("FAIL: could not recover correct time %g.\n", time);
+    printf("FAIL: could not recover correct time.\n");
     abort();
   }
 
   offset_old = offset;
   t = 0;
   time = 0;
-  mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data);
-  printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t,
-         offset_old, mask);
+  mask = logger_read_timestamp(log, &t, &time, &offset, (const char *)d->data);
+  printf(
+      "Recovered timestamp %020llu with time %g at offset %#016zx with mask "
+      "%#04x.\n",
+      t, time, offset_old, mask);
   if (t != 20) {
     printf("FAIL: could not recover correct timestamp.\n");
     abort();
@@ -241,9 +232,11 @@ void test_log_timestamps(struct logger_writer *log) {
   offset_old = offset;
   t = 0;
   time = 0;
-  mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data);
-  printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t,
-         offset_old, mask);
+  mask = logger_read_timestamp(log, &t, &time, &offset, (const char *)d->data);
+  printf(
+      "Recovered timestamp %020llu with time %g at offset %#016zx with mask "
+      "%#04x.\n",
+      t, time, offset_old, mask);
   if (t != 10) {
     printf("FAIL: could not recover correct timestamp.\n");
     abort();
@@ -259,8 +252,11 @@ int main(int argc, char *argv[]) {
   /* Prepare a logger. */
   struct logger_writer log;
   struct swift_params params;
+  struct engine e;
+  e.policy = engine_policy_hydro | engine_policy_self_gravity;
+
   parser_read_file("logger.yml", &params);
-  logger_init(&log, &params);
+  logger_init(&log, &e, &params);
 
   /* Test writing/reading parts. */
   test_log_parts(&log);