diff --git a/configure.ac b/configure.ac
index d119cfa3a99c1c85456056eab5d73b334ec86d15..84c4eb3c6fb9e3faf8ba108df0e26992dd581812 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2388,6 +2388,27 @@ AM_CONDITIONAL([HAVE_SPHENIX], [test "$with_hydro" = "sphenix"])
 # check if using GADGET2 SPH
 AM_CONDITIONAL([HAVE_GADGET2], [test "$with_hydro" = "gadget2"])
 
+# check if using none chemistry
+AM_CONDITIONAL([HAVE_CHEMISTRY_NONE], [test "$with_chemistry" = "none"])
+
+# check if using GEAR chemistry
+AM_CONDITIONAL([HAVE_CHEMISTRY_GEAR], [test "${with_chemistry:0:5}" = "GEAR_"])
+
+# check if using default stars
+AM_CONDITIONAL([HAVE_STARS_DEFAULT], [test "$with_stars" = "none"])
+
+# check if using GEAR stars
+AM_CONDITIONAL([HAVE_STARS_GEAR], [test "$with_stars" = "GEAR"])
+
+# check if using default star formation
+AM_CONDITIONAL([HAVE_STAR_FORMATION_DEFAULT], [test "$with_star_formation" = "none"])
+
+# check if using GEAR star formation
+AM_CONDITIONAL([HAVE_STAR_FORMATION_GEAR], [test "$with_star_formation" = "GEAR"])
+
+# check if using multi softening gravity
+AM_CONDITIONAL([HAVE_GRAVITY_MULTISOFTENING], [test "$with_gravity" = "with-multi-softening"])
+
 # Handle .in files.
 AC_CONFIG_FILES([Makefile src/Makefile examples/Makefile examples/Cooling/CoolingRates/Makefile doc/Makefile doc/Doxyfile tests/Makefile])
 AC_CONFIG_FILES([argparse/Makefile tools/Makefile logger/Makefile logger/tests/Makefile])
diff --git a/doc/RTD/source/AnalysisTools/index.rst b/doc/RTD/source/AnalysisTools/index.rst
index e908b378350c208635335728de4f8accc8024cfa..bf827d1b4a6a74f6171aef733627e8584fa50929 100644
--- a/doc/RTD/source/AnalysisTools/index.rst
+++ b/doc/RTD/source/AnalysisTools/index.rst
@@ -10,7 +10,7 @@ Analysis Tools
 Task dependencies
 -----------------
 
-At the beginning of each simulation the file ``dependency_graph.csv`` is generated and can be transformed into a ``dot`` and a ``png`` file with the script ``tools/plot_task_dependencies.py``.
+At the beginning of each simulation the file ``dependency_graph_0.csv`` is generated and can be transformed into a ``dot`` and a ``png`` file with the script ``tools/plot_task_dependencies.py``.
 It requires the ``dot`` package that is available in the library graphviz.
 This script has also the possibility to generate a list of function calls for each task with the option ``--with-calls`` (this list may be incomplete) and to describe at which level each task are run ``--with-levels`` (a larger simulation will provide more accurate levels).
 You can convert the ``dot`` file into a ``png`` with the following command
@@ -19,6 +19,24 @@ If you wish to have more dependency graphs, you can use the parameter ``Schedule
 While the initial graph is showing all the tasks/dependencies, the next ones are only showing the active tasks/dependencies.
 
 
+
+Task levels
+-----------------
+
+At the beginning of each simulation the file ``task_level_0.txt`` is generated. 
+It contains the counts of all tasks at all levels (depths) in the tree.
+The depths and counts of the tasks can be plotted with the script ``tools/plot_task_levels.py``.
+It will display the individual tasks at the x-axis, the number of each task at a given level on the y-axis, and the level is shown as the colour of the plotted point.
+Additionally, the script can write out in brackets next to each tasks's name on the x-axis on how many different levels the task exists using the ``--count`` flag.
+Finally, in some cases the counts for different levels of a task may be very close to each other and overlap on the plot, making them barely visible.
+This can be alleviated by using the ``--displace`` flag: 
+It will displace the plot points w.r.t. the y-axis in an attempt to make them better visible, however the counts won't be exact in that case.
+If you wish to have more task level plots, you can use the parameter ``Scheduler:task_level_output_frequency``. 
+It defines how many steps are done in between two task level output dumps.
+
+
+
+
 Cell graph
 ----------
 
diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml
index 5eec165ede647f7ccb7a69f41bc1ab86ead122e8..8933395fa6f28778beb6b00ff110c07c6950c4c0 100644
--- a/examples/parameter_example.yml
+++ b/examples/parameter_example.yml
@@ -134,6 +134,7 @@ Scheduler:
   engine_max_sparts_per_ghost:   1000  # (Optional) Maximum number of sparts per ghost.
   engine_max_parts_per_cooling: 10000  # (Optional) Maximum number of parts per cooling task.
   dependency_graph_frequency:       0  # (Optional) Dumping frequency of the dependency graph. By default, writes only at the first step.
+  task_level_output_frequency:      0  # (Optional) Dumping frequency of the task level data. By default, writes only at the first step.
 
 # Parameters governing the time integration (Set dt_min and dt_max to the same value for a fixed time-step run.)
 TimeIntegration:
diff --git a/logger/examples/create_snapshot.py b/logger/examples/create_snapshot.py
new file mode 100644
index 0000000000000000000000000000000000000000..79d42202e5a43b819b8c4c0d329cef769069015c
--- /dev/null
+++ b/logger/examples/create_snapshot.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+"""
+Read a logger file by using an index file and then write a snapshot.
+Example: python3 create_snapshot -t 0.1 -o out.hdf5 ../../examples/SedovBlast_3D/index_*dump
+"""
+import sys
+import h5py
+import numpy as np
+from glob import glob
+import argparse
+sys.path.append("../.libs/")
+
+import liblogger as logger
+
+
+def parse_arguments():
+    parser = argparse.ArgumentParser(
+        description='Read a logfile and plots some basic properties')
+
+    default_files = "../../examples/HydroTests/SedovBlast_3D/index_*dump"
+    default_files = glob(default_files)
+
+    parser.add_argument("-o", '--output', dest='out',
+                        type=str, default="out.hdf5",
+                        help='Output filename')
+    parser.add_argument("-t", '--time', dest='time',
+                        type=float, default=0.01,
+                        help='Simulation time')
+    parser.add_argument('files', metavar='filenames', type=str, nargs="*",
+                        help='The filenames of the logfiles')
+    args = parser.parse_args()
+    if len(args.files) == 0:
+        args.files = default_files
+    return args
+
+
+def write_particle_type(snap, part_type, args):
+    """
+    Write a particle type inside an HDF5 file.
+
+    Parameters
+    ----------
+
+    snap: h5py.File
+        The output file.
+
+    part_type: int
+        The particle type to write
+
+    args: ArgumentParser
+        The argument parser
+
+    Returns
+    -------
+
+    npart: int
+        The number of particles of the given type.
+    """
+    fields = None
+    fields_name = None
+
+    # Read all the fields
+    for f in args.files:
+        if f.endswith(".dump"):
+            filename = f[:-5]
+        else:
+            raise Exception("It seems that you are not providing a logfile (.dump)")
+
+        # Open the logger
+        with logger.Reader(filename, verbose=0) as reader:
+
+            # Get the list of fields
+            if fields_name is None:
+                fields_name = reader.get_list_fields(part_type)
+
+            # Abort if only requesting a type not implemented
+            if "SpecialFlags" in fields_name:
+                print("Part type %i not implemented, skipping it" % part_type)
+                continue
+
+            # Read the fields
+            fields_tmp = reader.get_particle_data(fields_name, args.time, part_type)
+            if fields is None:
+                fields = fields_tmp
+            else:
+                for i, field in enumerate(fields):
+                    fields[i] = np.append(fields[i], fields_tmp[i], axis=0)
+
+    # Do we have this particle type?
+    if fields is None or fields[0].shape[0] == 0:
+        return 0
+
+    # Get the number of particles
+    npart = fields[0].shape[0]
+
+    # Create the group
+    name = "PartType%i" % part_type
+    grp = snap.create_group(name)
+
+    # Save the data
+    for i, field in enumerate(fields_name):
+        grp.create_dataset(field, data=fields[i])
+
+    return npart
+
+
+if __name__ == "__main__":
+    args = parse_arguments()
+    print("Output: %s" % args.out)
+    print("basename: %s" % args.files)
+    print("time: %g" % args.time)
+
+    # read the logger
+    n_types = 6
+
+    # Create a snapshot
+    with h5py.File(args.out, "w") as snap:
+        npart = np.zeros(n_types)
+        for part_type in range(n_types):
+            npart[part_type] = write_particle_type(snap, part_type, args)
+
+
+        # Write the header
+        grp = snap.create_group("Header")
+        grp.attrs["NumPart_Total"] = npart
+        grp.attrs["NumPart_Total_HighWord"] = [0] * n_types
+        grp.attrs["NumPart_ThisFile"] = npart
+        grp.attrs["Time"] = args.time
+        grp.attrs["NumFilesPerSnapshot"] = 1
+        grp.attrs["MassTable"] = [0.0] * n_types
+
diff --git a/logger/examples/reader_example.py b/logger/examples/reader_example.py
index e3518cf61914ba6916075433c90b1f0877f0e4f8..5c2ef10602b6eac20ba71d4a9f137446ed9d2004 100644
--- a/logger/examples/reader_example.py
+++ b/logger/examples/reader_example.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 """
 Read a logger file by using an index file.
-Example: ./reader_example.py ../../examples/SedovBlast_3D/index 0.1
+Example: ./reader_example.py -t 0.1 ../../examples/SedovBlast_3D/index_*dump
 """
 import sys
 import numpy as np
diff --git a/src/Makefile.am b/src/Makefile.am
index b9d9ff5cf46a568b538321687ec6844a198aab04..ad1a3b8c331730442f59bae1f4b53c9649fc84a7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,8 +62,8 @@ include_HEADERS += black_holes.h black_holes_io.h black_holes_properties.h black
 include_HEADERS += feedback.h feedback_struct.h feedback_properties.h 
 include_HEADERS += space_unique_id.h line_of_sight.h io_compression.h
 include_HEADERS += rays.h rays_struct.h
-include_HEADERS += logger_history.h
 include_HEADERS += particle_splitting.h particle_splitting_struct.h
+include_HEADERS += logger_history.h chemistry_logger.h star_formation_particle_logger.h
 
 # source files for EAGLE cooling
 QLA_COOLING_SOURCES =
@@ -102,6 +102,48 @@ GEAR_FEEDBACK_SOURCES += feedback/GEAR/stellar_evolution.c feedback/GEAR/feedbac
 	feedback/GEAR/initial_mass_function.c feedback/GEAR/supernovae_ia.c feedback/GEAR/supernovae_ii.c
 endif
 
+# source files for the logger (chemistry)
+CHEMISTRY_LOGGER =
+if HAVE_CHEMISTRY_NONE
+CHEMISTRY_LOGGER += chemistry/none/chemistry_logger.c
+endif
+if HAVE_CHEMISTRY_GEAR
+CHEMISTRY_LOGGER += chemistry/GEAR/chemistry_logger.c
+endif
+
+# source files for the logger (hydro)
+HYDRO_LOGGER =
+if HAVE_GADGET2
+HYDRO_LOGGER += hydro/Gadget2/hydro_logger.c
+endif
+if HAVE_SPHENIX
+HYDRO_LOGGER += hydro/SPHENIX/hydro_logger.c
+endif
+
+# source files for the logger (stars)
+STARS_LOGGER =
+if HAVE_STARS_DEFAULT
+STARS_LOGGER += stars/Default/stars_logger.c
+endif
+if HAVE_STARS_GEAR
+STARS_LOGGER += stars/GEAR/stars_logger.c
+endif
+
+# source files for the logger (stars)
+STAR_FORMATION_LOGGER =
+if HAVE_STAR_FORMATION_DEFAULT
+STAR_FORMATION_LOGGER += star_formation/none/star_formation_particle_logger.c
+endif
+if HAVE_STAR_FORMATION_GEAR
+STAR_FORMATION_LOGGER += star_formation/GEAR/star_formation_particle_logger.c
+endif
+
+# source files for the logger (gravity)
+GRAVITY_LOGGER =
+if HAVE_GRAVITY_MULTISOFTENING
+GRAVITY_LOGGER += gravity/MultiSoftening/gravity_logger.c
+endif
+
 # Common source files
 AM_SOURCES = space.c space_rebuild.c space_regrid.c space_unique_id.c 
 AM_SOURCES += space_sort.c space_split.c space_extras.c space_first_init.c space_init.c 
@@ -133,6 +175,8 @@ AM_SOURCES += $(QLA_COOLING_SOURCES)
 AM_SOURCES += $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES) 
 AM_SOURCES += $(GRACKLE_COOLING_SOURCES) $(GEAR_FEEDBACK_SOURCES) 
 AM_SOURCES += $(COLIBRE_COOLING_SOURCES)
+AM_SOURCES += $(CHEMISTRY_LOGGER) $(HYDRO_LOGGER) $(STARS_LOGGER) $(GRAVITY_LOGGER)
+AM_SOURCES += $(STAR_FORMATION_LOGGER)
 
 # Include files for distribution, not installation.
 nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h 
@@ -241,7 +285,7 @@ nobase_noinst_HEADERS += stars/Default/stars_debug.h stars/Default/stars_part.h
 nobase_noinst_HEADERS += stars/EAGLE/stars.h stars/EAGLE/stars_iact.h stars/EAGLE/stars_io.h 
 nobase_noinst_HEADERS += stars/EAGLE/stars_debug.h stars/EAGLE/stars_part.h 
 nobase_noinst_HEADERS += stars/GEAR/stars.h stars/GEAR/stars_iact.h stars/GEAR/stars_io.h 
-nobase_noinst_HEADERS += stars/GEAR/stars_debug.h stars/GEAR/stars_part.h 
+nobase_noinst_HEADERS += stars/GEAR/stars_debug.h stars/GEAR/stars_logger.h stars/GEAR/stars_part.h
 nobase_noinst_HEADERS += potential/none/potential.h potential/point_mass/potential.h 
 nobase_noinst_HEADERS += potential/isothermal/potential.h potential/disc_patch/potential.h 
 nobase_noinst_HEADERS += potential/sine_wave/potential.h potential/constant/potential.h 
@@ -249,13 +293,15 @@ nobase_noinst_HEADERS += potential/hernquist/potential.h potential/nfw/potential
 nobase_noinst_HEADERS += potential/nfw_mn/potential.h potential/point_mass_softened/potential.h 
 nobase_noinst_HEADERS += potential/point_mass_ring/potential.h 
 nobase_noinst_HEADERS += star_formation/none/star_formation.h star_formation/none/star_formation_struct.h 
-nobase_noinst_HEADERS += star_formation/none/star_formation_io.h star_formation/none/star_formation_iact.h 
+nobase_noinst_HEADERS += star_formation/none/star_formation_io.h star_formation/none/star_formation_iact.h
+nobase_noinst_HEADERS += star_formation/none/star_formation_particle_logger.h
 nobase_noinst_HEADERS += star_formation/QLA/star_formation.h star_formation/QLA/star_formation_struct.h 
 nobase_noinst_HEADERS += star_formation/QLA/star_formation_io.h star_formation/QLA/star_formation_iact.h 
 nobase_noinst_HEADERS += star_formation/EAGLE/star_formation.h star_formation/EAGLE/star_formation_struct.h 
 nobase_noinst_HEADERS += star_formation/EAGLE/star_formation_io.h star_formation/EAGLE/star_formation_iact.h 
 nobase_noinst_HEADERS += star_formation/GEAR/star_formation.h star_formation/GEAR/star_formation_struct.h 
 nobase_noinst_HEADERS += star_formation/GEAR/star_formation_io.h star_formation/GEAR/star_formation_iact.h 
+nobase_noinst_HEADERS += star_formation/GEAR/star_formation_particle_logger.h
 nobase_noinst_HEADERS += star_formation/EAGLE/star_formation_logger.h star_formation/EAGLE/star_formation_logger_struct.h 
 nobase_noinst_HEADERS += star_formation/GEAR/star_formation_logger.h star_formation/GEAR/star_formation_logger_struct.h 
 nobase_noinst_HEADERS += star_formation/none/star_formation_logger.h star_formation/none/star_formation_logger_struct.h 
@@ -279,10 +325,12 @@ nobase_noinst_HEADERS += cooling/COLIBRE/cooling_tables.h cooling/COLIBRE/coolin
 nobase_noinst_HEADERS += cooling/COLIBRE/cooling_properties.h 
 nobase_noinst_HEADERS += chemistry/none/chemistry.h 
 nobase_noinst_HEADERS += chemistry/none/chemistry_io.h 
+nobase_noinst_HEADERS += chemistry/none/chemistry_logger.h
 nobase_noinst_HEADERS += chemistry/none/chemistry_struct.h 
 nobase_noinst_HEADERS += chemistry/none/chemistry_iact.h 
 nobase_noinst_HEADERS += chemistry/GEAR/chemistry.h 
 nobase_noinst_HEADERS += chemistry/GEAR/chemistry_io.h 
+nobase_noinst_HEADERS += chemistry/GEAR/chemistry_logger.h
 nobase_noinst_HEADERS += chemistry/GEAR/chemistry_struct.h 
 nobase_noinst_HEADERS += chemistry/GEAR/chemistry_iact.h 
 nobase_noinst_HEADERS += chemistry/GEAR_DIFFUSION/chemistry.h
diff --git a/src/chemistry/GEAR/chemistry_logger.c b/src/chemistry/GEAR/chemistry_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..58b7fa3fc1627987e1097a34fe2654075487a72e
--- /dev/null
+++ b/src/chemistry/GEAR/chemistry_logger.c
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "chemistry_logger.h"
+
+const char
+    *chemistry_logger_field_names_part[chemistry_logger_field_part_count] = {
+        "ChemistryHydro",
+};
+const char
+    *chemistry_logger_field_names_spart[chemistry_logger_field_spart_count] = {
+        "MetalMassFractions",
+};
+
+#endif  // WITH_LOGGER
diff --git a/src/chemistry/GEAR/chemistry_logger.h b/src/chemistry/GEAR/chemistry_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c113a195d2f01ced0dea2ebc2cb408ad69b3179
--- /dev/null
+++ b/src/chemistry/GEAR/chemistry_logger.h
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * 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_CHEMISTRY_NONE_CHEMISTRY_LOGGER_H
+#define SWIFT_CHEMISTRY_NONE_CHEMISTRY_LOGGER_H
+
+#include "hydro.h"
+#include "logger_io.h"
+
+#ifdef WITH_LOGGER
+
+/*
+ * List of all possible mask.
+ * Outside the module, only chemistry_logger_field_count is used.
+ */
+// Here I am only using a single flag in order to free some flags to the other
+// modules.
+enum chemistry_logger_fields_part {
+  chemistry_logger_field_part_all = 0,
+  chemistry_logger_field_part_count,
+};
+enum chemistry_logger_fields_spart {
+  chemistry_logger_field_spart_metal_mass_fractions = 0,
+  chemistry_logger_field_spart_count,
+};
+
+/* Name of each possible mask. */
+extern const char
+    *chemistry_logger_field_names_part[chemistry_logger_field_part_count];
+extern const char
+    *chemistry_logger_field_names_spart[chemistry_logger_field_spart_count];
+
+/**
+ * @brief Initialize the logger for the #part.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_part!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int chemistry_logger_writer_populate_mask_data_part(
+    struct mask_data *mask_data) {
+
+  /* We store the metal mass fraction and the smoothed one. */
+  mask_data[chemistry_logger_field_part_all] = logger_create_mask_entry(
+      chemistry_logger_field_names_part[chemistry_logger_field_part_all],
+      2 * GEAR_CHEMISTRY_ELEMENT_COUNT * sizeof(double));
+  return chemistry_logger_field_part_count;
+}
+
+/**
+ * @brief Initialize the logger for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_spart!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int chemistry_logger_writer_populate_mask_data_spart(
+    struct mask_data *mask_data) {
+  /* We store the metal mass fraction. */
+  mask_data[chemistry_logger_field_spart_metal_mass_fractions] =
+      logger_create_mask_entry(
+          chemistry_logger_field_names_spart
+              [chemistry_logger_field_spart_metal_mass_fractions],
+          GEAR_CHEMISTRY_ELEMENT_COUNT * sizeof(double));
+
+  return chemistry_logger_field_spart_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record for the #part.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_part!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_part).
+ * @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 chemistry_logger_compute_size_and_mask_part(
+    const struct mask_data *masks, const struct part *part,
+    const struct xpart *xpart, const int write_all, size_t *buffer_size,
+    unsigned int *mask) {
+  /* Add the chemistry. */
+  *mask |= logger_add_field_to_mask(masks[chemistry_logger_field_part_all],
+                                    buffer_size);
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_spart).
+ * @param spart 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 chemistry_logger_compute_size_and_mask_spart(
+    const struct mask_data *masks, const struct spart *spart,
+    const int write_all, size_t *buffer_size, unsigned int *mask) {
+
+  /* Add the chemistry. */
+  *mask |= logger_add_field_to_mask(
+      masks[chemistry_logger_field_spart_metal_mass_fractions], buffer_size);
+}
+
+/**
+ * @brief Write a #part to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields_part!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_part).
+ * @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 *chemistry_logger_write_particle(
+    const struct mask_data *mask_data, const struct part *p,
+    const struct xpart *xp, unsigned int *mask, char *buff) {
+
+  /* Write the chemistry. */
+  if (logger_should_write_field(mask_data[chemistry_logger_field_part_all],
+                                mask)) {
+
+    /* Write the smoothed metal mass fraction */
+    memcpy(buff, p->chemistry_data.smoothed_metal_mass_fraction,
+           GEAR_CHEMISTRY_ELEMENT_COUNT * sizeof(double));
+    buff += GEAR_CHEMISTRY_ELEMENT_COUNT * sizeof(double);
+
+    /* Write the metal mass */
+    double *frac = (double *)buff;
+    const float m = hydro_get_mass(p);
+    for (int i = 0; i < GEAR_CHEMISTRY_ELEMENT_COUNT; i++) {
+      *frac = p->chemistry_data.metal_mass[i] / m;
+      frac += 1;
+    }
+  }
+
+  return buff;
+}
+
+/**
+ * @brief Write a #spart to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_spart).
+ * @param sp 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 *chemistry_logger_write_sparticle(
+    const struct mask_data *mask_data, const struct spart *sp,
+    unsigned int *mask, char *buff) {
+
+  /* Write the metal mass fraction. */
+  if (logger_should_write_field(
+          mask_data[chemistry_logger_field_spart_metal_mass_fractions], mask)) {
+
+    /* Write the metal mass fraction */
+    memcpy(buff, sp->chemistry_data.metal_mass_fraction,
+           GEAR_CHEMISTRY_ELEMENT_COUNT * sizeof(double));
+    buff += GEAR_CHEMISTRY_ELEMENT_COUNT * sizeof(double);
+  }
+
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_CHEMISTRY_NONE_CHEMISTRY_LOGGER_H
diff --git a/src/chemistry/none/chemistry_logger.c b/src/chemistry/none/chemistry_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..707273d4d4a43f7c0b5bda5057e1b189c7c41a38
--- /dev/null
+++ b/src/chemistry/none/chemistry_logger.c
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "chemistry_logger.h"
+
+const char
+    *chemistry_logger_field_names_part[chemistry_logger_field_part_count] = {};
+const char *
+    chemistry_logger_field_names_spart[chemistry_logger_field_spart_count] = {};
+
+#endif  // WITH_LOGGER
diff --git a/src/chemistry/none/chemistry_logger.h b/src/chemistry/none/chemistry_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..caf005d29d3055f3eb7cd1ef9c7ff877fc94b11e
--- /dev/null
+++ b/src/chemistry/none/chemistry_logger.h
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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_CHEMISTRY_NONE_CHEMISTRY_LOGGER_H
+#define SWIFT_CHEMISTRY_NONE_CHEMISTRY_LOGGER_H
+
+#include "logger_io.h"
+
+#ifdef WITH_LOGGER
+
+/*
+ * List of all possible mask.
+ * Outside the module, only chemistry_logger_field_count is used.
+ */
+enum chemistry_logger_fields_part {
+  chemistry_logger_field_part_count = 0,
+};
+enum chemistry_logger_fields_spart {
+  chemistry_logger_field_spart_count = 0,
+};
+
+/* Name of each possible mask. */
+extern const char
+    *chemistry_logger_field_names_part[chemistry_logger_field_part_count];
+extern const char
+    *chemistry_logger_field_names_spart[chemistry_logger_field_spart_count];
+
+/**
+ * @brief Initialize the logger for the #part.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_part!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int chemistry_logger_writer_populate_mask_data_part(
+    struct mask_data *mask_data) {
+  return chemistry_logger_field_part_count;
+}
+
+/**
+ * @brief Initialize the logger for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_spart!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int chemistry_logger_writer_populate_mask_data_spart(
+    struct mask_data *mask_data) {
+  return chemistry_logger_field_spart_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record for the #part.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_part!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_part).
+ * @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 chemistry_logger_compute_size_and_mask_part(
+    const struct mask_data *masks, const struct part *part,
+    const struct xpart *xpart, const int write_all, size_t *buffer_size,
+    unsigned int *mask) {}
+
+/**
+ * @brief Generates the mask and compute the size of the record for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #chemistry_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_spart).
+ * @param spart 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 chemistry_logger_compute_size_and_mask_spart(
+    const struct mask_data *masks, const struct spart *spart,
+    const int write_all, size_t *buffer_size, unsigned int *mask) {}
+
+/**
+ * @brief Write a #part to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields_part!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_part).
+ * @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 *chemistry_logger_write_particle(
+    const struct mask_data *mask_data, const struct part *p,
+    const struct xpart *xp, unsigned int *mask, char *buff) {
+  return buff;
+}
+
+/**
+ * @brief Write a #spart to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #chemistry_logger_writer_populate_mask_data_spart).
+ * @param sp 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 *chemistry_logger_write_sparticle(
+    const struct mask_data *mask_data, const struct spart *sp,
+    unsigned int *mask, char *buff) {
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_CHEMISTRY_NONE_CHEMISTRY_LOGGER_H
diff --git a/src/chemistry_logger.h b/src/chemistry_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d17216391d2ec42b8613e635e9525ba7b2fb8a1
--- /dev/null
+++ b/src/chemistry_logger.h
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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_CHEMISTRY_LOGGER_H
+#define SWIFT_CHEMISTRY_LOGGER_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Local includes */
+#include "align.h"
+#include "logger.h"
+#include "part_type.h"
+#include "timeline.h"
+
+/* Import the right function */
+#if defined(CHEMISTRY_NONE)
+#include "./chemistry/none/chemistry_logger.h"
+#elif defined(CHEMISTRY_GEAR)
+#include "./chemistry/GEAR/chemistry_logger.h"
+#elif defined(CHEMISTRY_GEAR_DIFFUSION)
+#error TODO
+#elif defined(CHEMISTRY_QLA)
+#error TODO
+#elif defined(CHEMISTRY_EAGLE)
+#error TODO
+#else
+#error "Invalid choice of chemistry function."
+#endif
+
+#endif /* SWIFT_CHEMISTRY_LOGGER_H */
diff --git a/src/engine.c b/src/engine.c
index 2a0492ee2c55abd0d572b9cce100dd3a84c20ac7..a448bdfa49df0ecf103d9d406b0922111154137d 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -71,6 +71,7 @@
 #include "hydro.h"
 #include "line_of_sight.h"
 #include "logger.h"
+#include "logger_io.h"
 #include "map.h"
 #include "memuse.h"
 #include "minmax.h"
@@ -1824,7 +1825,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs,
 #endif
 
   scheduler_write_dependencies(&e->sched, e->verbose, e->step);
-  if (e->nodeID == 0) scheduler_write_task_level(&e->sched);
+  if (e->nodeID == 0) scheduler_write_task_level(&e->sched, e->step);
 
   /* Run the 0th time-step */
   TIMER_TIC2;
@@ -2242,6 +2243,11 @@ void engine_step(struct engine *e) {
       e->step % e->sched.frequency_dependency == 0)
     scheduler_write_dependencies(&e->sched, e->verbose, e->step);
 
+  /* Write the task levels */
+  if (e->sched.frequency_task_levels != 0 &&
+      e->step % e->sched.frequency_task_levels == 0)
+    scheduler_write_task_level(&e->sched, e->step);
+
   /* Start all the tasks. */
   TIMER_TIC;
   engine_launch(e, "tasks");
diff --git a/src/engine_config.c b/src/engine_config.c
index 02257355a702c9a5c2982bba74ac6858d3db3ac2..99e7b32a978f7920713f8f67484190c70bed5e55 100644
--- a/src/engine_config.c
+++ b/src/engine_config.c
@@ -193,6 +193,13 @@ void engine_config(int restart, int fof, struct engine *e,
     error("Scheduler:dependency_graph_frequency should be >= 0");
   }
 
+  /* Get the frequency of the task level dumping */
+  e->sched.frequency_task_levels = parser_get_opt_param_int(
+      params, "Scheduler:task_level_output_frequency", 0);
+  if (e->sched.frequency_task_levels < 0) {
+    error("Scheduler:task_level_output_frequency should be >= 0");
+  }
+
 /* Deal with affinity. For now, just figure out the number of cores. */
 #if defined(HAVE_SETAFFINITY)
   const int nr_cores = sysconf(_SC_NPROCESSORS_ONLN);
diff --git a/src/feedback/GEAR/feedback.c b/src/feedback/GEAR/feedback.c
index 6a8d15c4c4b6583bc7e14c6cf1868a11c33e8fa9..a895481c8cb6df8d7c122cc13279ecea2ac0b6a7 100644
--- a/src/feedback/GEAR/feedback.c
+++ b/src/feedback/GEAR/feedback.c
@@ -102,18 +102,18 @@ void feedback_update_part(struct part* restrict p, struct xpart* restrict xp,
  * @param time_base The time base.
  * @param time The current time (in double)
  */
-void compute_time(struct spart* sp, const struct engine* e,
-                  const int with_cosmology, const struct cosmology* cosmo,
-                  double* star_age_beg_of_step, double* dt_enrichment,
-                  integertime_t* ti_begin_star, const integertime_t ti_current,
-                  const double time_base, const double time) {
+void compute_time(struct spart* sp, const int with_cosmology,
+                  const struct cosmology* cosmo, double* star_age_beg_of_step,
+                  double* dt_enrichment, integertime_t* ti_begin_star,
+                  const integertime_t ti_current, const double time_base,
+                  const double time) {
   const integertime_t ti_step = get_integer_timestep(sp->time_bin);
   *ti_begin_star = get_integer_time_begin(ti_current, sp->time_bin);
 
   /* Get particle time-step */
   double dt_star;
   if (with_cosmology) {
-    dt_star = cosmology_get_delta_time(cosmology, *ti_begin_star,
+    dt_star = cosmology_get_delta_time(cosmo, *ti_begin_star,
                                        *ti_begin_star + ti_step);
   } else {
     dt_star = get_timestep(sp->time_bin, time_base);
@@ -163,7 +163,7 @@ void feedback_will_do_feedback(
   double star_age_beg_step = 0;
   double dt_enrichment = 0;
   integertime_t ti_begin = 0;
-  compute_time(sp, e, with_cosmology, cosmo, &star_age_beg_step, &dt_enrichment,
+  compute_time(sp, with_cosmology, cosmo, &star_age_beg_step, &dt_enrichment,
                &ti_begin, ti_current, time_base, time);
 
   /* Zero the energy of supernovae */
diff --git a/src/gravity/MultiSoftening/gravity_logger.c b/src/gravity/MultiSoftening/gravity_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..2622c747ee0d10b8b626acdfb85313e4ed49adfe
--- /dev/null
+++ b/src/gravity/MultiSoftening/gravity_logger.c
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "gravity_logger.h"
+
+const char *gravity_logger_field_names[gravity_logger_field_count] = {
+    "Coordinates", "Velocities", "Accelerations", "Masses", "ParticleIDs",
+};
+
+#endif  // WITH_LOGGER
diff --git a/src/gravity/MultiSoftening/gravity_logger.h b/src/gravity/MultiSoftening/gravity_logger.h
index f342e9ccc61a8310f3f39c2c5350518d1c6a5f93..0923e6127c52ec141f26c04649a33187cc47ecd5 100644
--- a/src/gravity/MultiSoftening/gravity_logger.h
+++ b/src/gravity/MultiSoftening/gravity_logger.h
@@ -38,9 +38,7 @@ enum gravity_logger_fields {
 };
 
 /* Name of each possible mask. */
-static const char *gravity_logger_field_names[gravity_logger_field_count] = {
-    "Coordinates", "Velocities", "Accelerations", "Masses", "ParticleIDs",
-};
+extern const char *gravity_logger_field_names[gravity_logger_field_count];
 
 /**
  * @brief Initialize the logger.
diff --git a/src/hydro/Gadget2/hydro_logger.c b/src/hydro/Gadget2/hydro_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..236e9cd3b592824444b33c6fd3d0dcd5cda2d350
--- /dev/null
+++ b/src/hydro/Gadget2/hydro_logger.c
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "hydro_logger.h"
+
+const char *hydro_logger_field_names[hydro_logger_field_count] = {
+    "Coordinates",      "Velocities", "Accelerations", "Masses",
+    "SmoothingLengths", "Entropies",  "ParticleIDs",   "Densities"};
+
+#endif
diff --git a/src/hydro/Gadget2/hydro_logger.h b/src/hydro/Gadget2/hydro_logger.h
index 907259cb699e86f7646966349ccd1d0bbcd5cd2b..6632e21b6e660228c1f2647d3bc62167374f5f8e 100644
--- a/src/hydro/Gadget2/hydro_logger.h
+++ b/src/hydro/Gadget2/hydro_logger.h
@@ -41,9 +41,7 @@ enum hydro_logger_fields {
 };
 
 /* Name of each possible mask. */
-static const char *hydro_logger_field_names[hydro_logger_field_count] = {
-    "Coordinates",      "Velocities", "Accelerations", "Masses",
-    "SmoothingLengths", "Entropies",  "ParticleIDs",   "Densities"};
+extern const char *hydro_logger_field_names[hydro_logger_field_count];
 
 /**
  * @brief Initialize the logger.
diff --git a/src/hydro/SPHENIX/hydro_logger.c b/src/hydro/SPHENIX/hydro_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..682585a469afe08c4cc53cf291a4418efc51f4cf
--- /dev/null
+++ b/src/hydro/SPHENIX/hydro_logger.c
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+/* Include the particles */
+#include "align.h"
+#include "hydro_part.h"
+
+/* Include the header */
+#include "hydro_logger.h"
+
+const char *hydro_logger_field_names[hydro_logger_field_count] = {
+    "Coordinates", "Velocities",         "Accelerations",
+    "Masses",      "SmoothingLengths",   "InternalEnergies",
+    "ParticleIDs", "Densities",          "Entropies",
+    "Pressures",   "ViscosityDiffusion", "VelocityDivergences",
+};
+
+#endif  // WITH_LOGGER
diff --git a/src/hydro/SPHENIX/hydro_logger.h b/src/hydro/SPHENIX/hydro_logger.h
index 44f9274e6a6a352aea789d3eaab2f24fc86825b5..d31493d16286d1b8e20782dca491590fcee0948a 100644
--- a/src/hydro/SPHENIX/hydro_logger.h
+++ b/src/hydro/SPHENIX/hydro_logger.h
@@ -19,6 +19,7 @@
 #ifndef SWIFT_SPHENIX_HYDRO_LOGGER_H
 #define SWIFT_SPHENIX_HYDRO_LOGGER_H
 
+/* Other Includes */
 #include "hydro.h"
 #include "logger_io.h"
 
@@ -45,12 +46,7 @@ enum hydro_logger_fields {
 };
 
 /* Name of each possible mask. */
-static const char *hydro_logger_field_names[hydro_logger_field_count] = {
-    "Coordinates", "Velocities",         "Accelerations",
-    "Masses",      "SmoothingLengths",   "InternalEnergies",
-    "ParticleIDs", "Densities",          "Entropies",
-    "Pressures",   "ViscosityDiffusion", "VelocityDivergences",
-};
+extern const char *hydro_logger_field_names[hydro_logger_field_count];
 
 /**
  * @brief Initialize the logger.
diff --git a/src/logger.c b/src/logger.c
index f9c0b407ac3e5d521f092bb213b17ddbfc74b3d1..a7cef1c47ef47b4083afbdf8b6bc59f5cc6c9cf1 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -40,11 +40,13 @@
 /* Local headers. */
 #include "active.h"
 #include "atomic.h"
+#include "chemistry_logger.h"
 #include "dump.h"
 #include "engine.h"
 #include "error.h"
 #include "gravity_logger.h"
 #include "hydro_logger.h"
+#include "star_formation_particle_logger.h"
 #include "stars_logger.h"
 #include "units.h"
 
@@ -216,6 +218,8 @@ void logger_copy_part_fields(const struct logger_writer *log,
   /* Write the hydro fields */
   buff = hydro_logger_write_particle(log->mask_data_pointers.hydro, p, xp,
                                      &mask, buff);
+  buff = chemistry_logger_write_particle(log->mask_data_pointers.chemistry_part,
+                                         p, xp, &mask, buff);
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (mask) {
@@ -282,6 +286,9 @@ void logger_log_parts(struct logger_writer *log, const struct part *p,
       size_t size = 0;
       hydro_logger_compute_size_and_mask(log->mask_data_pointers.hydro, &p[i],
                                          &xp[i], log_all_fields, &size, &mask);
+      chemistry_logger_compute_size_and_mask_part(
+          log->mask_data_pointers.chemistry_part, &p[i], &xp[i], log_all_fields,
+          &size, &mask);
       if (flag != 0) {
         size += size_special_flag;
       }
@@ -300,6 +307,9 @@ void logger_log_parts(struct logger_writer *log, const struct part *p,
     unsigned int mask = 0;
     hydro_logger_compute_size_and_mask(log->mask_data_pointers.hydro, &p[i],
                                        &xp[i], log_all_fields, &size, &mask);
+    chemistry_logger_compute_size_and_mask_part(
+        log->mask_data_pointers.chemistry_part, &p[i], &xp[i], log_all_fields,
+        &size, &mask);
     size += logger_header_bytes;
 
     /* Add the special flag. */
@@ -373,6 +383,10 @@ void logger_copy_spart_fields(const struct logger_writer *log,
   /* Write the stellar fields */
   buff = stars_logger_write_particle(log->mask_data_pointers.stars, sp, &mask,
                                      buff);
+  buff = chemistry_logger_write_sparticle(
+      log->mask_data_pointers.chemistry_spart, sp, &mask, buff);
+  buff = star_formation_logger_write_sparticle(
+      log->mask_data_pointers.star_formation, sp, &mask, buff);
 #ifdef SWIFT_DEBUG_CHECKS
   if (mask) {
     error("Requested logging of values not present in sparts. %u", mask);
@@ -432,6 +446,12 @@ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
       size_t size = 0;
       stars_logger_compute_size_and_mask(log->mask_data_pointers.stars, &sp[i],
                                          log_all_fields, &size, &mask);
+      chemistry_logger_compute_size_and_mask_spart(
+          log->mask_data_pointers.chemistry_spart, &sp[i], log_all_fields,
+          &size, &mask);
+      star_formation_logger_compute_size_and_mask(
+          log->mask_data_pointers.star_formation, &sp[i], log_all_fields, &size,
+          &mask);
       if (flag != 0) {
         size += size_special_flag;
       }
@@ -449,6 +469,12 @@ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count,
     unsigned int mask = 0;
     stars_logger_compute_size_and_mask(log->mask_data_pointers.stars, &sp[i],
                                        log_all_fields, &size, &mask);
+    chemistry_logger_compute_size_and_mask_spart(
+        log->mask_data_pointers.chemistry_spart, &sp[i], log_all_fields, &size,
+        &mask);
+    star_formation_logger_compute_size_and_mask(
+        log->mask_data_pointers.star_formation, &sp[i], log_all_fields, &size,
+        &mask);
     size += logger_header_bytes;
 
     /* Add the special flag. */
@@ -730,7 +756,10 @@ void logger_get_dump_name(struct logger_writer *log, char *filename) {
 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.chemistry_part = NULL;
+  log->mask_data_pointers.chemistry_spart = NULL;
   log->mask_data_pointers.stars = NULL;
+  log->mask_data_pointers.star_formation = NULL;
   log->mask_data_pointers.gravity = NULL;
 
   struct mask_data list[100];
@@ -754,7 +783,7 @@ void logger_init_masks(struct logger_writer *log, const struct engine *e) {
   list[num_fields].type = mask_type_timestep;  // flag it as timestamp
   num_fields += 1;
 
-  // TODO add chemistry, cooling, ... + xpart + spart
+  // TODO add cooling, ... + xpart + spart
 
   /* Get all the fields that need to be written for the hydro. */
   struct mask_data *tmp = &list[num_fields];
@@ -770,6 +799,20 @@ void logger_init_masks(struct logger_writer *log, const struct engine *e) {
   }
   num_fields += tmp_num_fields;
 
+  /* Get all the fields that need to be written for the chemistry (part). */
+  tmp = &list[num_fields];
+
+  /* Set the mask_data_pointers */
+  log->mask_data_pointers.chemistry_part = tmp;
+
+  /* Set the masks */
+  tmp_num_fields = chemistry_logger_writer_populate_mask_data_part(tmp);
+  /* Set the particle type */
+  for (int i = 0; i < tmp_num_fields; i++) {
+    tmp[i].type = mask_type_gas;
+  }
+  num_fields += tmp_num_fields;
+
   /* Get all the fields that need to be written for the stars. */
   tmp = &list[num_fields];
 
@@ -784,6 +827,34 @@ void logger_init_masks(struct logger_writer *log, const struct engine *e) {
   }
   num_fields += tmp_num_fields;
 
+  /* Get all the fields that need to be written for the chemistry (spart). */
+  tmp = &list[num_fields];
+
+  /* Set the mask_data_pointers */
+  log->mask_data_pointers.chemistry_spart = tmp;
+
+  /* Set the masks */
+  tmp_num_fields = chemistry_logger_writer_populate_mask_data_spart(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 star_formation. */
+  tmp = &list[num_fields];
+
+  /* Set the mask_data_pointers */
+  log->mask_data_pointers.star_formation = tmp;
+
+  /* Set the masks */
+  tmp_num_fields = star_formation_logger_writer_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. */
   tmp = &list[num_fields];
 
@@ -852,10 +923,23 @@ void logger_init_masks(struct logger_writer *log, const struct engine *e) {
     log->mask_data_pointers.hydro =
         log->logger_mask_data + (log->mask_data_pointers.hydro - list);
   }
+  if (log->mask_data_pointers.chemistry_part != NULL) {
+    log->mask_data_pointers.chemistry_part =
+        log->logger_mask_data + (log->mask_data_pointers.chemistry_part - 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.chemistry_spart != NULL) {
+    log->mask_data_pointers.chemistry_spart =
+        log->logger_mask_data +
+        (log->mask_data_pointers.chemistry_spart - list);
+  }
+  if (log->mask_data_pointers.star_formation != NULL) {
+    log->mask_data_pointers.star_formation =
+        log->logger_mask_data + (log->mask_data_pointers.star_formation - list);
+  }
   if (log->mask_data_pointers.gravity != NULL) {
     log->mask_data_pointers.gravity =
         log->logger_mask_data + (log->mask_data_pointers.gravity - list);
@@ -866,6 +950,9 @@ void logger_init_masks(struct logger_writer *log, const struct engine *e) {
   for (int i = 0; i < hydro_logger_field_count; i++) {
     log->max_size_record_part += log->mask_data_pointers.hydro[i].size;
   }
+  for (int i = 0; i < chemistry_logger_field_part_count; i++) {
+    log->max_size_record_part += log->mask_data_pointers.chemistry_part[i].size;
+  }
 
   log->max_size_record_gpart = 0;
   for (int i = 0; i < gravity_logger_field_count; i++) {
@@ -876,6 +963,14 @@ void logger_init_masks(struct logger_writer *log, const struct engine *e) {
   for (int i = 0; i < stars_logger_field_count; i++) {
     log->max_size_record_spart += log->mask_data_pointers.stars[i].size;
   }
+  for (int i = 0; i < chemistry_logger_field_spart_count; i++) {
+    log->max_size_record_spart +=
+        log->mask_data_pointers.chemistry_spart[i].size;
+  }
+  for (int i = 0; i < star_formation_logger_field_count; i++) {
+    log->max_size_record_spart +=
+        log->mask_data_pointers.star_formation[i].size;
+  }
 
   /* Set the counter */
   log->logger_count_mask = num_fields;
@@ -1275,12 +1370,21 @@ void logger_struct_restore(struct logger_writer *log, FILE *stream) {
   log->mask_data_pointers.hydro =
       log->logger_mask_data +
       (log->mask_data_pointers.hydro - old_logger_mask_data);
+  log->mask_data_pointers.chemistry_part =
+      log->logger_mask_data +
+      (log->mask_data_pointers.chemistry_part - old_logger_mask_data);
   log->mask_data_pointers.gravity =
       log->logger_mask_data +
       (log->mask_data_pointers.gravity - old_logger_mask_data);
   log->mask_data_pointers.stars =
       log->logger_mask_data +
       (log->mask_data_pointers.stars - old_logger_mask_data);
+  log->mask_data_pointers.chemistry_spart =
+      log->logger_mask_data +
+      (log->mask_data_pointers.chemistry_spart - old_logger_mask_data);
+  log->mask_data_pointers.star_formation =
+      log->logger_mask_data +
+      (log->mask_data_pointers.star_formation - old_logger_mask_data);
 
   /* Restart the dump file. */
   char logger_name_file[PARSER_MAX_LINE_SIZE];
diff --git a/src/logger.h b/src/logger.h
index 646fc901842176882761292d88fa000a01553fad..dd0b988b9c1dee3661ec13d1d5157eced39a76f7 100644
--- a/src/logger.h
+++ b/src/logger.h
@@ -39,8 +39,8 @@ struct gpart;
 struct part;
 struct engine;
 
-#define logger_major_version 0
-#define logger_minor_version 5
+#define logger_major_version 1
+#define logger_minor_version 0
 /* Size of the strings. */
 #define logger_string_length 200
 
@@ -151,11 +151,20 @@ struct logger_writer {
     /* pointer for the hydro */
     struct mask_data *hydro;
 
+    /* pointer for the chemistry */
+    struct mask_data *chemistry_part;
+
+    /* pointer for the chemistry */
+    struct mask_data *chemistry_spart;
+
     /* pointer for the gravity */
     struct mask_data *gravity;
 
     /* pointer for the stars */
     struct mask_data *stars;
+
+    /* pointer for the star formation */
+    struct mask_data *star_formation;
   } mask_data_pointers;
 
   /* Number of elements in logger_mask_data. */
diff --git a/src/logger_history.c b/src/logger_history.c
index f75686e748e81f1783b87dc7173b11396a7787d7..f0034f8dd1cae0a3bcbed61f7334661354b56d69 100644
--- a/src/logger_history.c
+++ b/src/logger_history.c
@@ -41,7 +41,7 @@ void logger_history_init(struct logger_history *hist) {
   /* Set the counters to their initial value */
   hist->size = 0;
   hist->capacity = LOGGER_HISTORY_INIT_SIZE;
-  lock_init(hist->lock);
+  lock_init(&hist->lock);
 
   hist->data = (struct logger_index_data *)swift_malloc(
       "logger_history",
@@ -74,7 +74,7 @@ void logger_history_free(struct logger_history *hist) {
   /* Set the counters to 0 */
   hist->size = 0;
   hist->capacity = 0;
-  lock_destroy(hist->lock);
+  if (lock_destroy(&hist->lock) != 0) error("Error destroying lock");
 
   /* Free the memory */
   if (hist->data != NULL) {
@@ -102,7 +102,7 @@ void logger_history_log(struct logger_history *hist, const long long id,
   const struct logger_index_data data = {id, last_offset};
 
   /* Lock the history */
-  lock_lock(hist->lock);
+  lock_lock(&hist->lock);
 
   /* Check if enough space is left */
   if (hist->size == hist->capacity) {
@@ -130,7 +130,8 @@ void logger_history_log(struct logger_history *hist, const long long id,
   hist->size += 1;
 
   /* Unlock the history. */
-  lock_unlock(hist->lock);
+  if (lock_unlock(&hist->lock) != 0)
+    error("Impossible to unlock logger history.");
 }
 
 /**
diff --git a/src/logger_history.h b/src/logger_history.h
index 05df5044c89cd081137dfba71a094a58b2aa778f..43ab36583975b6828cc496542a7b242aa9fcafea 100644
--- a/src/logger_history.h
+++ b/src/logger_history.h
@@ -26,6 +26,7 @@
 
 /* Local include */
 #include "error.h"
+#include "lock.h"
 #include "part_type.h"
 
 #if defined(WITH_LOGGER)
diff --git a/src/scheduler.c b/src/scheduler.c
index bb0c43bb3cb173dc91b8d238ded879787bf3d0a1..f107c653fc1beb7ae6710c5c3f4d9a6c3824b4a1 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -369,7 +369,7 @@ void task_dependency_sum(void *in_p, void *out_p, int *len,
 /**
  * @brief Write a csv file with the task dependencies.
  *
- * Run plot_task_dependencies.sh for an example of how to use it
+ * Run plot_task_dependencies.py for an example of how to use it
  * to generate the figure.
  *
  * @param s The #scheduler we are working in.
@@ -2489,9 +2489,16 @@ void scheduler_free_tasks(struct scheduler *s) {
 }
 
 /**
- * @brief write down each task level
+ * @brief write down the levels and the number of tasks at that level.
+ *
+ * Run plot_task_level.py for an example of how to use it
+ * to generate the figure.
+ *
+ * @param s The #scheduler we are working in.
+ * @param step The current step number.
  */
-void scheduler_write_task_level(const struct scheduler *s) {
+void scheduler_write_task_level(const struct scheduler *s, int step) {
+
   /* init */
   const int max_depth = 30;
   const struct task *tasks = s->tasks;
@@ -2519,8 +2526,18 @@ void scheduler_write_task_level(const struct scheduler *s) {
     }
   }
 
+  /* Generate filename */
+  char filename[200] = "task_level_\0";
+#ifdef WITH_MPI
+  char rankstr[6];
+  sprintf(rankstr, "%04d_", s->nodeID);
+  strcat(filename, rankstr);
+#endif
+  char stepstr[100];
+  sprintf(stepstr, "%d.txt", step);
+  strcat(filename, stepstr);
+
   /* Open file */
-  char filename[200] = "task_level.txt";
   FILE *f = fopen(filename, "w");
   if (f == NULL) error("Error opening task level file.");
 
diff --git a/src/scheduler.h b/src/scheduler.h
index 13c7395d26c85bfe166a678f56f7fd6370f4d4ca..d7fc9ad38a6c68afa8b72097e73bd207831683e1 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -114,6 +114,9 @@ struct scheduler {
 
   /* Frequency of the dependency graph dumping. */
   int frequency_dependency;
+
+  /* Frequency of the task levels dumping. */
+  int frequency_task_levels;
 };
 
 /* Inlined functions (for speed). */
@@ -207,7 +210,7 @@ void scheduler_print_tasks(const struct scheduler *s, const char *fileName);
 void scheduler_clean(struct scheduler *s);
 void scheduler_free_tasks(struct scheduler *s);
 void scheduler_write_dependencies(struct scheduler *s, int verbose, int step);
-void scheduler_write_task_level(const struct scheduler *s);
+void scheduler_write_task_level(const struct scheduler *s, int step);
 void scheduler_dump_queues(struct engine *e);
 void scheduler_report_task_times(const struct scheduler *s,
                                  const int nr_threads);
diff --git a/src/space.c b/src/space.c
index 1b60d924742df427f57a9df8350deae953b41e54..67c3494dd892f864910e7d7bca0eeb1c18a45018 100644
--- a/src/space.c
+++ b/src/space.c
@@ -1071,6 +1071,17 @@ void space_init(struct space *s, struct swift_params *params,
   s->sum_bpart_vel_norm = 0.f;
   s->nr_queues = 1; /* Temporary value until engine construction */
 
+  /* do a quick check that the box size has valid values */
+#if defined HYDRO_DIMENSION_1D
+  if (dim[0] <= 0.) error("Invalid box size: [%f]", dim[0]);
+#elif defined HYDRO_DIMENSION_2D
+  if (dim[0] <= 0. || dim[1] <= 0.)
+    error("Invalid box size: [%f, %f]", dim[0], dim[1]);
+#else
+  if (dim[0] <= 0. || dim[1] <= 0. || dim[2] <= 0.)
+    error("Invalid box size: [%f, %f, %f]", dim[0], dim[1], dim[2]);
+#endif
+
   /* Initiate some basic randomness */
   srand(42);
 
diff --git a/src/star_formation/GEAR/star_formation_particle_logger.c b/src/star_formation/GEAR/star_formation_particle_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..506d7004b7b0bf9ca9582712c3ee38ff02cc76a3
--- /dev/null
+++ b/src/star_formation/GEAR/star_formation_particle_logger.c
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "star_formation_particle_logger.h"
+
+/* Name of each possible mask. */
+const char
+    *star_formation_logger_field_names[star_formation_logger_field_count] = {
+        "StarFormation",
+};
+
+#endif  // WITH_LOGGER
diff --git a/src/star_formation/GEAR/star_formation_particle_logger.h b/src/star_formation/GEAR/star_formation_particle_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..938d6cbbdffa7398f3863251944a14fc186669b1
--- /dev/null
+++ b/src/star_formation/GEAR/star_formation_particle_logger.h
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 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_STAR_FORMATION_GEAR_STAR_FORMATION_PARTICLE_LOGGER_H
+#define SWIFT_STAR_FORMATION_GEAR_STAR_FORMATION_PARTICLE_LOGGER_H
+
+#include "logger_io.h"
+
+#ifdef WITH_LOGGER
+
+/*
+ * List of all possible mask.
+ * Outside the module, only star_formation_logger_field_count is used.
+ */
+enum star_formation_logger_fields_spart {
+  star_formation_logger_field_all = 0,
+  star_formation_logger_field_count,
+};
+
+/* Name of each possible mask. */
+extern const char
+    *star_formation_logger_field_names[star_formation_logger_field_count];
+
+/**
+ * @brief Initialize the logger for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #star_formation_logger_fields_spart!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int star_formation_logger_writer_populate_mask_data(
+    struct mask_data *mask_data) {
+  /* We store the birth density, mass and progenitor id. */
+  mask_data[star_formation_logger_field_all] = logger_create_mask_entry(
+      star_formation_logger_field_names[star_formation_logger_field_all],
+      2 * sizeof(float) + sizeof(long long));
+
+  return star_formation_logger_field_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #star_formation_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #star_formation_logger_writer_populate_mask_data_spart).
+ * @param spart 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 star_formation_logger_compute_size_and_mask(
+    const struct mask_data *masks, const struct spart *spart,
+    const int write_all, size_t *buffer_size, unsigned int *mask) {
+  /* Add the star formation. */
+  *mask |= logger_add_field_to_mask(masks[star_formation_logger_field_all],
+                                    buffer_size);
+}
+
+/**
+ * @brief Write a #spart to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #star_formation_logger_writer_populate_mask_data_spart).
+ * @param sp 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 *star_formation_logger_write_sparticle(
+    const struct mask_data *mask_data, const struct spart *sp,
+    unsigned int *mask, char *buff) {
+  /* Write the star formation. */
+  if (logger_should_write_field(mask_data[star_formation_logger_field_all],
+                                mask)) {
+
+    /* Write the birth density */
+    memcpy(buff, &sp->sf_data.birth_density, sizeof(float));
+    buff += sizeof(float);
+
+    /* Write the birth mass  */
+    memcpy(buff, &sp->sf_data.birth_mass, sizeof(float));
+    buff += sizeof(float);
+
+    /* Write the progenitor id  */
+    memcpy(buff, &sp->sf_data.progenitor_id, sizeof(long long));
+    buff += sizeof(long long);
+  }
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_STAR_FORMATION_NONE_STAR_FORMATION_PARTICLE_LOGGER_H
diff --git a/src/star_formation/none/star_formation_particle_logger.c b/src/star_formation/none/star_formation_particle_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..a48f7d9e9a0989c0f6a92b1bd6ae42c45a2192e8
--- /dev/null
+++ b/src/star_formation/none/star_formation_particle_logger.c
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "star_formation_particle_logger.h"
+
+const char
+    *star_formation_logger_field_names[star_formation_logger_field_count] = {};
+
+#endif  // WITH_LOGGER
diff --git a/src/star_formation/none/star_formation_particle_logger.h b/src/star_formation/none/star_formation_particle_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..b69df66d3d33a4dbf290cce1fd14af841ecbd2ed
--- /dev/null
+++ b/src/star_formation/none/star_formation_particle_logger.h
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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_STAR_FORMATION_NONE_STAR_FORMATION_PARTICLE_LOGGER_H
+#define SWIFT_STAR_FORMATION_NONE_STAR_FORMATION_PARTICLE_LOGGER_H
+
+#include "logger_io.h"
+
+#ifdef WITH_LOGGER
+
+/*
+ * List of all possible mask.
+ * Outside the module, only star_formation_logger_field_count is used.
+ */
+enum star_formation_logger_fields_spart {
+  star_formation_logger_field_count = 0,
+};
+
+/* Name of each possible mask. */
+extern const char
+    *star_formation_logger_field_names[star_formation_logger_field_count];
+
+/**
+ * @brief Initialize the logger for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #star_formation_logger_fields_spart!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int star_formation_logger_writer_populate_mask_data(
+    struct mask_data *mask_data) {
+  return star_formation_logger_field_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record for the #spart.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #star_formation_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #star_formation_logger_writer_populate_mask_data_spart).
+ * @param spart 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 star_formation_logger_compute_size_and_mask(
+    const struct mask_data *masks, const struct spart *spart,
+    const int write_all, size_t *buffer_size, unsigned int *mask) {}
+
+/**
+ * @brief Write a #spart to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #hydro_logger_fields_spart!
+ *
+ * @param masks The list of masks (same order than in
+ * #star_formation_logger_writer_populate_mask_data_spart).
+ * @param sp 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 *star_formation_logger_write_sparticle(
+    const struct mask_data *mask_data, const struct spart *sp,
+    unsigned int *mask, char *buff) {
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_STAR_FORMATION_NONE_STAR_FORMATION_PARTICLE_LOGGER_H
diff --git a/src/star_formation_particle_logger.h b/src/star_formation_particle_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..a3ced362d0c1e3700ad98ba8afc93c06428931f2
--- /dev/null
+++ b/src/star_formation_particle_logger.h
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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_STAR_FORMATION_PARTICLE_LOGGER_H
+#define SWIFT_STAR_FORMATION_PARTICLE_LOGGER_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Local includes */
+#include "align.h"
+#include "logger.h"
+#include "part_type.h"
+#include "timeline.h"
+
+/* Import the right function */
+#if defined(STAR_FORMATION_NONE)
+#include "./star_formation/none/star_formation_particle_logger.h"
+#elif defined(STAR_FORMATION_QLA)
+#error TODO
+#elif defined(STAR_FORMATION_EAGLE)
+#error TODO
+#elif defined(STAR_FORMATION_GEAR)
+#include "./star_formation/GEAR/star_formation_particle_logger.h"
+#else
+#error "Invalid choice of star formation law"
+#endif
+
+#endif /* SWIFT_STAR_FORMATION_PARTICLE_LOGGER_H */
diff --git a/src/stars/Default/stars_logger.c b/src/stars/Default/stars_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..f84360e740be2697e1861f26823f7b1ee36d63c4
--- /dev/null
+++ b/src/stars/Default/stars_logger.c
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "stars_logger.h"
+
+const char *stars_logger_field_names[stars_logger_field_count] = {
+    "Coordinates", "Velocities",       "Accelerations",
+    "Masses",      "SmoothingLengths", "ParticleIDs",
+};
+
+#endif  // WITH_LOGGER
diff --git a/src/stars/Default/stars_logger.h b/src/stars/Default/stars_logger.h
index 2637cef126fa2ce4b8980b7f22265c80c463f7be..ebc7c7d13e9dd6de1999fffff75fa5b53dcd7bd9 100644
--- a/src/stars/Default/stars_logger.h
+++ b/src/stars/Default/stars_logger.h
@@ -38,10 +38,7 @@ enum stars_logger_fields {
 };
 
 /* Name of each possible mask. */
-static const char *stars_logger_field_names[stars_logger_field_count] = {
-    "Coordinates", "Velocities",       "Accelerations",
-    "Masses",      "SmoothingLengths", "ParticleIDs",
-};
+extern const char *stars_logger_field_names[stars_logger_field_count];
 
 /**
  * @brief Initialize the logger.
diff --git a/src/stars/GEAR/stars_logger.c b/src/stars/GEAR/stars_logger.c
new file mode 100644
index 0000000000000000000000000000000000000000..e12875bd3582f1fbe915355f039acbd8b4250448
--- /dev/null
+++ b/src/stars/GEAR/stars_logger.c
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#ifdef WITH_LOGGER
+
+#include "stars_logger.h"
+
+const char *stars_logger_field_names[stars_logger_field_count] = {
+    "Coordinates",      "Velocities",  "Accelerations",     "Masses",
+    "SmoothingLengths", "ParticleIDs", "BirthScaleFactors",
+};
+
+#endif  // WITH_LOGGER
diff --git a/src/stars/GEAR/stars_logger.h b/src/stars/GEAR/stars_logger.h
new file mode 100644
index 0000000000000000000000000000000000000000..365505c50c9278a1efec3f248231f97c14d971d5
--- /dev/null
+++ b/src/stars/GEAR/stars_logger.h
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * 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
+
+#include "logger_io.h"
+
+/*
+ * List of all possible mask.
+ * Outside the module, only stars_logger_field_count is used.
+ */
+enum stars_logger_fields {
+  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_birth_scale_factors,
+  stars_logger_field_count,
+};
+
+/* Name of each possible mask. */
+extern const char *stars_logger_field_names[stars_logger_field_count];
+
+/**
+ * @brief Initialize the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #stars_logger_fields!
+ *
+ * @param mask_data Data for each type of mask.
+ *
+ * @return Number of masks used.
+ */
+INLINE static int stars_logger_writer_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));
+
+  mask_data[stars_logger_field_birth_scale_factors] = logger_create_mask_entry(
+      stars_logger_field_names[stars_logger_field_birth_scale_factors],
+      sizeof(float));
+
+  return stars_logger_field_count;
+}
+
+/**
+ * @brief Generates the mask and compute the size of the record.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #stars_logger_fields!
+ *
+ * @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],
+                                    buffer_size);
+
+  /* Add the velocities. */
+  *mask |= logger_add_field_to_mask(masks[stars_logger_field_velocities],
+                                    buffer_size);
+
+  /* Add the accelerations. */
+  *mask |= logger_add_field_to_mask(masks[stars_logger_field_accelerations],
+                                    buffer_size);
+
+  /* Add the masses. */
+  *mask |=
+      logger_add_field_to_mask(masks[stars_logger_field_masses], buffer_size);
+
+  /* Add the smoothing lengths. */
+  *mask |= logger_add_field_to_mask(masks[stars_logger_field_smoothing_lengths],
+                                    buffer_size);
+
+  /* Add the ID. */
+  *mask |= logger_add_field_to_mask(masks[stars_logger_field_particle_ids],
+                                    buffer_size);
+
+  /* Add the birth scale factor. */
+  *mask |= logger_add_field_to_mask(
+      masks[stars_logger_field_birth_scale_factors], buffer_size);
+}
+
+/**
+ * @brief Write a particle to the logger.
+ *
+ * WARNING: The order should be the same in all the functions and
+ * #stars_logger_fields!
+ *
+ * @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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    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)) {
+    memcpy(buff, &p->id, sizeof(long long));
+    buff += sizeof(long long);
+  }
+
+  /* Write the birth scale factor. */
+  if (logger_should_write_field(
+          mask_data[stars_logger_field_birth_scale_factors], mask)) {
+    memcpy(buff, &p->birth_scale_factor, sizeof(float));
+    buff += sizeof(float);
+  }
+
+  return buff;
+}
+
+#endif  // WITH_LOGGER
+#endif  // SWIFT_DEFAULT_STARS_LOGGER_H
diff --git a/src/stars/GEAR/stars_part.h b/src/stars/GEAR/stars_part.h
index 5f5019d643df9d849aa1d50c627b236412a50fcc..ca3e56419c08a622bb97ff0ee06183772bd2bb41 100644
--- a/src/stars/GEAR/stars_part.h
+++ b/src/stars/GEAR/stars_part.h
@@ -96,6 +96,11 @@ struct spart {
   /*! Splitting structure */
   struct particle_splitting_data split_data;
 
+#ifdef WITH_LOGGER
+  /* Additional data for the particle logger */
+  struct logger_part_data logger_data;
+#endif
+
   /*! Radiative Transfer data */
   struct rt_spart_data rt_data;
 
diff --git a/src/stars_logger.h b/src/stars_logger.h
index 972c648ff95df5f811514465e97890c3c728bd10..a3d1dbb30962dcec9ad3ece094ea8e0289b5ec05 100644
--- a/src/stars_logger.h
+++ b/src/stars_logger.h
@@ -37,7 +37,7 @@
 #elif defined(STARS_EAGLE)
 #error TODO
 #elif defined(STARS_GEAR)
-#error TODO
+#include "./stars/GEAR/stars_logger.h"
 #else
 #error "Invalid choice of star model"
 #endif
diff --git a/tools/plot_task_level.py b/tools/plot_task_level.py
index 2fbe55c025db7f400aa009e488412475c9259630..668baaf895b66c73fb52545997f55596190f9632 100755
--- a/tools/plot_task_level.py
+++ b/tools/plot_task_level.py
@@ -3,7 +3,9 @@ description = """
 Plot the number of tasks for each depth level and each type of task.
 
 Usage:
-  ./plot_task_level.py task_level.txt
+  ./plot_task_level.py task_level_0.txt
+  or
+  ./plot_task_level.py task_level_*_0.txt
 
 """
 
@@ -61,43 +63,51 @@ def parse_args():
     parser.add_argument(
         "file",
         type=str,
-        help="Required file name of .csv file(s) of the task levels "
+        nargs="+",
+        help="Required file name(s) of .txt file(s) of the task levels "
         "generated by swift.",
     )
 
     args = parser.parse_args()
-    filename = args.file
-    print(filename)
+    files = args.file
 
-    if not path.exists(filename):
-        raise FileNotFoundError("File not found:'" + filename + "'")
+    for f in files:
+        if not path.exists(f):
+            raise FileNotFoundError("File not found:'" + f + "'")
 
-    return args, filename
+    return args, files
 
 
-def read_data(filename):
+def read_data(files):
     """
-    Reads in data from the csv file.
+    Reads in data from the .txt file.
 
     Parameters
     ----------
 
-    filename: str
-        filename to be read from
+    files: list
+        list of filenames to be read from
 
 
     Returns
     -------
 
-    data: pandas dataset
-        dataset containing read in data
+    data: pandas dataframe
+        dataframe containing read in data
     """
 
     # Column names
     names = ["type", "subtype", "depth", "count"]
 
-    # read file
-    data = pd.read_csv(filename, sep=" ", comment="#", names=names)
+    alldata = None
+    for f in files:
+        # read file
+        data = pd.read_csv(f, sep=" ", comment="#", names=names)
+        if alldata is None:
+            alldata = data
+        else:
+            concat = pd.concat([alldata, data])
+            alldata = concat.groupby(["type", "subtype", "depth"], as_index=False).sum()
 
     return data
 
@@ -237,9 +247,9 @@ def add_displacement(data):
 
 if __name__ == "__main__":
 
-    args, filename = parse_args()
+    args, files = parse_args()
 
-    data = read_data(filename)
+    data = read_data(files)
     cmap = get_discrete_cmap(data["depth"].max())
 
     # are we counting the levels?