diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000000000000000000000000000000000000..4f6ca2a9861c060d40e3b6fef53072ea3bc311ed
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Loic Hausammann
\ No newline at end of file
diff --git a/COPYING b/COPYING
new file mode 120000
index 0000000000000000000000000000000000000000..28ecdc8a0ed9fa7416e2998749e6cac8964ca501
--- /dev/null
+++ b/COPYING
@@ -0,0 +1 @@
+/usr/share/automake-1.16/COPYING
\ No newline at end of file
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/INSTALL b/INSTALL
new file mode 120000
index 0000000000000000000000000000000000000000..e3f22c0e1ea44ac687aee8d986a0c9eac7cc2a63
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1 @@
+/usr/share/automake-1.16/INSTALL
\ No newline at end of file
diff --git a/Makefile.am b/Makefile.am
index a0d309572afa08b9d0a356c3d91f3f03af6aa274..b9805af5eb2b30748da41e0782ed7fc4e8f936c5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-# This file is part of SWIFT.
+# This file is part of CSDS.
 # Copyright (c) 2021 Loic Hausammann (loic.hausammann@epfl.ch)
 #
 # This program is free software: you can redistribute it and/or modify
@@ -14,9 +14,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# subdirectories
-SUBDIRS = src
+# Automake stuff
+ACLOCAL_AMFLAGS = -I m4
 
-if !HAVEPYTHON
-SUBDIRS += tests
-endif
+# subdirectories
+SUBDIRS = src tests
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/README b/README
new file mode 120000
index 0000000000000000000000000000000000000000..42061c01a1c70097d1e4579f29a5adf40abdec95
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+README.md
\ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8e52b9aefd508034ef68e6988bdbfa17b1b12e12
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+#  Update generated configuration files, i.e. do work so that a
+#  developer checkout can be configured.
+
+autoreconf --install --symlink
+exit
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000000000000000000000000000000000000..bb670d865adb65d2c0b89524ee60adf93889d505
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,300 @@
+# This file is part of CSDS.
+# Copyright (C) 2021 loic.hausammann@epfl.ch.
+#               SWIFT
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Define the version
+m4_define([major_version], [1])
+m4_define([minor_version], [5])
+
+# Init the project.
+AC_INIT([CSDS],[major_version.minor_version],
+    [https://gitlab.cosma.dur.ac.uk/lhausammann/csds-reader])
+csds_config_flags="$*"
+
+# Save the version
+AC_SUBST([MAJOR_VERSION],[major_version])
+AC_SUBST([MINOR_VERSION],[minor_version])
+
+#  We want to stop when given unrecognised options. No subdirs so this is safe.
+enable_option_checking=${enable_option_checking:-fatal}
+if test -n "$ac_unrecognized_opts"; then
+    case $enable_option_checking in
+        no)
+        ;;
+        fatal)
+            { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
+              { (exit 1); exit 1; }; }
+        ;;
+        *)
+            $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2
+        ;;
+    esac
+fi
+
+AC_COPYRIGHT
+AC_CONFIG_SRCDIR([src/csds_header.c])
+AC_CONFIG_AUX_DIR([.])
+AM_INIT_AUTOMAKE([subdir-objects])
+
+# Add local macro collection.
+AC_CONFIG_MACRO_DIR([m4])
+
+# Stop default CFLAGS from anyone except the environment.
+: ${CFLAGS=""}
+
+# Generate header file.
+AM_CONFIG_HEADER(config.h)
+
+# Find and test the compiler.
+AX_CHECK_ENABLE_DEBUG
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_OPENMP
+
+# Check if openmp is disabled
+with_openmp="yes"
+if [[ -z "$ac_cv_prog_c_openmp" ]]
+then
+  CFLAGS="$CFLAGS -Wno-unknown-pragmas"
+  with_openmp="no"
+else
+  AC_DEFINE([CSDS_WITH_OPENMP], 1, [Compile the code with OpenMP])
+fi
+
+# Check for compiler version and vendor.
+AX_COMPILER_VENDOR
+AX_COMPILER_VERSION
+
+#  Restrict support.
+AC_C_RESTRICT
+
+# Add libtool support (now that CC is defined).
+LT_INIT
+
+# Need C99 and inline support.
+AC_PROG_CC_C99
+AC_C_INLINE
+
+# If debugging try to show inlined functions.
+if test "x$enable_debug" = "xyes"; then
+   #  Show inlined functions.
+   if test "$ax_cv_c_compiler_vendor" = "gnu"; then
+      # Would like to use -gdwarf and let the compiler pick a good version
+      # but that doesn't always work.
+      AX_CHECK_COMPILE_FLAG([-gdwarf -fvar-tracking-assignments],
+        [inline_EXTRA_FLAGS="-gdwarf -fvar-tracking-assignments"],
+        [inline_EXTRA_FLAGS="-gdwarf-2 -fvar-tracking-assignments"])
+      CFLAGS="$CFLAGS $inline_EXTRA_FLAGS"
+   elif test "$ax_cv_c_compiler_vendor" = "intel"; then
+      CFLAGS="$CFLAGS -debug inline-debug-info"
+   fi
+fi
+
+# Check if expensive debugging is on.
+AC_ARG_ENABLE([debugging-checks],
+   [AS_HELP_STRING([--enable-debugging-checks],
+     [Activate expensive consistency checks @<:@yes/no@:>@]
+   )],
+   [enable_debugging_checks="$enableval"],
+   [enable_debugging_checks="no"]
+)
+if test "$enable_debugging_checks" = "yes"; then
+   AC_DEFINE([CSDS_DEBUG_CHECKS],1,[Enable expensive debugging])
+fi
+
+# Add address sanitizer options to flags, if requested. Only useful for GCC
+# version 4.8 and later and clang.
+AC_ARG_ENABLE([sanitizer],
+   [AS_HELP_STRING([--enable-sanitizer],
+     [Enable memory error detection using address sanitizer @<:@no/yes@:>@]
+   )],
+   [enable_san="$enableval"],
+   [enable_san="no"]
+)
+
+if test "$enable_san" = "yes"; then
+   if test "$ax_cv_c_compiler_vendor" = "gnu"; then
+      AX_COMPARE_VERSION( $ax_cv_c_compiler_version, [ge], [4.8.0],
+                          [enable_san="yes"], [enable_san="no"] )
+   elif test "$ax_cv_c_compiler_vendor" = "clang"; then
+      AX_COMPARE_VERSION( $ax_cv_c_compiler_version, [ge], [3.2.0],
+                          [enable_san="yes"], [enable_san="no"] )
+   fi
+   if test "$enable_san" = "yes"; then
+      CFLAGS="$CFLAGS -fsanitize=address -fno-omit-frame-pointer"
+      AC_MSG_RESULT([added address sanitizer support])
+   else
+      AC_MSG_WARN([Compiler does not support address sanitizer option])
+   fi
+fi
+
+# Add the undefined sanitizer option to flags. Only useful for GCC
+# version 4.9 and later and clang to detected undefined code behaviour
+# such as integer overflow and memory alignment issues.
+AC_ARG_ENABLE([undefined-sanitizer],
+   [AS_HELP_STRING([--enable-undefined-sanitizer],
+     [Enable detection of code that causes undefined behaviour @<:@no/yes@:>@]
+   )],
+   [enable_ubsan="$enableval"],
+   [enable_ubsan="no"]
+)
+
+if test "$enable_ubsan" = "yes"; then
+   if test "$ax_cv_c_compiler_vendor" = "gnu"; then
+      AX_COMPARE_VERSION( $ax_cv_c_compiler_version, [ge], [4.9.0],
+                          [enable_ubsan="yes"], [enable_ubsan="no"] )
+   elif test "$ax_cv_c_compiler_vendor" = "clang"; then
+      AX_COMPARE_VERSION( $ax_cv_c_compiler_version, [ge], [3.7.0],
+                          [enable_ubsan="yes"], [enable_ubsan="no"] )
+   fi
+   if test "$enable_ubsan" = "yes"; then
+      CFLAGS="$CFLAGS -fsanitize=undefined"
+      AC_MSG_RESULT([added undefined sanitizer support])
+   else
+      AC_MSG_WARN([Compiler does not support undefined sanitizer option])
+   fi
+fi
+
+# Autoconf stuff.
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_HEADER_STDC
+
+# Check for the libraries we will need.
+AC_CHECK_LIB(m,sqrt,,AC_MSG_ERROR(something is wrong with the math library!))
+
+# Check for python.
+have_python="no"
+AC_ARG_WITH([python],
+    [AS_HELP_STRING([--with-python=PATH],
+       [root directory where python is installed @<:@yes/no@:>@]
+    )],
+    [with_python="$withval"],
+    [with_python="no"]
+)
+if test "x$with_python" != "xno"; then
+   if test "$with_python" == ""; then
+      # use linux default python
+      with_python="/usr/"
+   fi
+   AM_PATH_PYTHON([3], [], [AC_MSG_ERROR(python not found)])   
+   AC_ARG_VAR([PYTHON_LIBS], [Linking flags for python, bypassing python-config])
+   AC_ARG_VAR([PYTHON_INCS], [Include flags for python, bypassing python-config])
+   AC_ARG_VAR([PYTHON_CONFIG], [Path to python-config])
+   AS_IF([test -z "$PYTHON_INCS"], [
+      AS_IF([test -z "$PYTHON_CONFIG"], [
+      	AC_PATH_PROGS([PYTHON_CONFIG],
+	          [python$PYTHON_VERSION-config python-config],
+                  [no],
+                  [`dirname $PYTHON`])
+    	AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON.])])
+      ])
+      AC_MSG_CHECKING([python include flags])
+      PYTHON_INCS=`$PYTHON_CONFIG --includes`
+      PYTHON_LIBS=`$PYTHON_CONFIG --ldflags --embed`
+  ])
+  have_python="yes"
+  AC_DEFINE([HAVE_PYTHON],1,[Python appears to be present.])
+fi
+AC_SUBST([PYTHON_INCS])
+AC_SUBST([PYTHON_LIBS])
+AM_CONDITIONAL([HAVEPYTHON],[test -n "$PYTHON_INCS"])
+
+
+# Check for timing functions needed by cycle.h.
+AC_HEADER_TIME
+AC_CHECK_HEADERS([sys/time.h c_asm.h intrinsics.h mach/mach_time.h])
+AC_CHECK_TYPE([hrtime_t],[AC_DEFINE(HAVE_HRTIME_T, 1, [Define to 1 if hrtime_t
+is defined in <sys/time.h>])],,
+[#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif])
+AC_CHECK_FUNCS([gethrtime read_real_time time_base_to_time clock_gettime mach_absolute_time])
+AC_MSG_CHECKING([for _rtc intrinsic])
+rtc_ok=yes
+AC_LINK_IFELSE([AC_LANG_PROGRAM(
+[[#ifdef HAVE_INTRINSICS_H
+#include <intrinsics.h>
+#endif]],
+[[_rtc()]])],
+[AC_DEFINE(HAVE__RTC,1,[Define if you have the UNICOS _rtc() intrinsic.])],[rtc_ok=no])
+AC_MSG_RESULT($rtc_ok)
+
+# Add warning flags by default, if these can be used. Option =error adds
+# -Werror to GCC, clang and Intel.  Note do this last as compiler tests may
+# become errors, if that's an issue don't use CFLAGS for these, use an AC_SUBST().
+AC_ARG_ENABLE([compiler-warnings],
+   [AS_HELP_STRING([--enable-compiler-warnings],
+     [Enable compile time warning flags, if compiler is known @<:@error/no/yes)@:>@]
+   )],
+   [enable_warn="$enableval"],
+   [enable_warn="error"]
+)
+if test "$enable_warn" != "no"; then
+
+    # AX_CFLAGS_WARN_ALL does not give good warning flags for the Intel compiler
+    # We will do this by hand instead and only default to the macro for unknown compilers
+    case "$ax_cv_c_compiler_vendor" in
+          gnu | clang)
+             CFLAGS="$CFLAGS -Wall -Wextra -Wshadow"
+          ;;
+	  intel)
+             CFLAGS="$CFLAGS -w2 -Wunused-variable -Wshadow"
+          ;;
+	  *)
+	     AX_CFLAGS_WARN_ALL
+	  ;;
+    esac
+
+    # Add a "choke on warning" flag if it exists
+    if test "$enable_warn" = "error"; then
+       case "$ax_cv_c_compiler_vendor" in
+          intel | gnu | clang)
+             CFLAGS="$CFLAGS -Werror"
+          ;;
+       esac
+    fi
+
+    # We want strict-prototypes, but this must still work even if warnings
+    # are an error.
+    AX_CHECK_COMPILE_FLAG([-Wstrict-prototypes],[CFLAGS="$CFLAGS -Wstrict-prototypes"],
+                          [CFLAGS="$CFLAGS"],[$CFLAGS],[AC_LANG_SOURCE([int main(void){return 0;}])])
+fi
+
+# Handle .in files.
+AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile])
+
+# Save the compilation options
+AC_DEFINE_UNQUOTED([CSDS_CONFIG_FLAGS],["$csds_config_flags"],[Flags passed to configure])
+
+# Generate output.
+AC_OUTPUT
+
+# Report general configuration.
+AC_MSG_RESULT([
+ ------- Summary --------
+
+   $PACKAGE_NAME v.$PACKAGE_VERSION
+
+   Compiler             : $CC
+    - vendor            : $ax_cv_c_compiler_vendor
+    - version           : $ax_cv_c_compiler_version
+    - flags             : $CFLAGS $OPENMP_CFLAGS
+   OpenMP enabled       : $with_openmp
+   Debugging checks     : $enable_debugging_checks
+   Python enabled       : $have_python
+
+------------------------])
diff --git a/doc/source/QuickStart/compiling_code.rst b/doc/source/QuickStart/compiling_code.rst
index 3d78b60a44278005b8e78c3f0f25772cd5f374dd..06a030cd62a27be6797891753cd8a55ff59439cd 100644
--- a/doc/source/QuickStart/compiling_code.rst
+++ b/doc/source/QuickStart/compiling_code.rst
@@ -6,23 +6,18 @@
 How to Compile the Code
 =======================
 
-To compile this code, you need to download `SWIFT's repository <www.swiftsim.com>`_
-and follow the instruction on how to compile it.
-Currently, the CSDS is implemented only within a few different scheme.
-If you wish to implement a new one, please follow the implementation
-within the other schems and :ref:`implementation`.
-During the configuration step, the CSDS needs to be enabled along with python wrapper if needed:
+To configure the CSDS (with the python wrapper), you need to use the following commands:
 
 .. code-block:: bash
 
    ./autogen.sh
-   ./configure --enable-csds --with-python=$PYTHON_PATH
+   ./configure --with-python=$PYTHON_PATH
 
 On a standard ubuntu, ``$PYTHON_PATH`` is given by ``/usr/``.
 It is worth to mention that the CSDS will not work with python 2.7.x
 and that the user should move to 3.0 as soon as possible.
 
-Then both SWIFT and the CSDS can be compiled:
+Then the CSDS can be compiled:
 
 .. code-block:: bash
 
diff --git a/doc/source/QuickStart/index.rst b/doc/source/QuickStart/index.rst
index ee70ca744a9dfab064241fd9982558079dcc300e..6c64792692f0cc547ce8b0f1203d5d127920f6d9 100644
--- a/doc/source/QuickStart/index.rst
+++ b/doc/source/QuickStart/index.rst
@@ -7,11 +7,13 @@ QuickStart
 ==========
 
 Here you will find how to compile the CSDS and run it on your first simulations.
-The CSDS is currently fully based on SWIFT and thus cannot be used directly without this code.
-Anyway, this code can still be used without running SWIFT at the condition that the output file
-correspond.
-In the future, we are planning to make this library fully independent from SWIFT.
-
+This code was initially designed for SWIFT, but can be used with other codes
+if the output files are correctly written.
+SWIFT is the reference implementation for the CSDS writer.
+Due to the large number of schemes, not all of them have a CSDS implementation.
+Therefore you should try with the default ones first.
+If you wish to implement a new one, please follow the implementation
+within the other schems and :ref:`implementation`.
 
 .. toctree::
    :maxdepth: 2
diff --git a/doc/source/QuickStart/running_first.rst b/doc/source/QuickStart/running_first.rst
index 043bfdd27a2979268b3e283b66c44c2cb776bf40..82530468b5e08684edaf60ae955123fc2a910e01 100644
--- a/doc/source/QuickStart/running_first.rst
+++ b/doc/source/QuickStart/running_first.rst
@@ -19,7 +19,7 @@ Let's start with the compilation of SWIFT and running our first example.
    cd examples/HydroTests/SedovBlast_3D
    ./run.sh
 
-The file ``run.sh`` is not running with the CSDS by default and needs to add
+The file ``run.sh`` is not running with the CSDS by default and you will need to add
 the runtime parameter ``--csds`` to the command calling SWIFT
 (e.g. ``../../swift --csds --hydro --limiter --threads=4 sedov.yml``).
 If everything is fine, the last message from SWIFT should be ``Done``
diff --git a/doc/source/QuickStart/using_python.rst b/doc/source/QuickStart/using_python.rst
index ebd3280ad2ae5c0d45b75943af7f002ddfb1047e..0f3a975d2e332ac8266e2d90f06cbf9d5a360b38 100644
--- a/doc/source/QuickStart/using_python.rst
+++ b/doc/source/QuickStart/using_python.rst
@@ -8,13 +8,13 @@ Python API
 
 The python API is relatively simple and fully self documented.
 Here, I will explain the main features and how they work.
-As the CSDS is currently depend on SWIFT and the scheme used,
-the library should be manually imported:
+If you do not wish to install the CSDS as a python library,
+you will need be manually import it:
 
 .. code-block:: python
 
    import sys
-   sys.path.append("SWIFT_PATH/csds/src/.libs/")
+   sys.path.append("CSDS_PATH/src/.libs/")
    import libcsds as csds
 
 This module contains a single object (``Reader``) that fully deals with
@@ -23,13 +23,13 @@ To open a logfile, this object is call in a with statement:
 
 .. code-block:: python
 
-   with csds.Reader(filename, verbose=0, number_threads=1, number_index=10,
+   with csds.Reader(filename, verbose=0, number_index=10,
                     restart_init=False) as reader:
        # Use the Reader
 
 In this example, all the parameters are set with their default values.
 The Reader is able to make some operations in parallel and
-will use the number of threads given by ``number_threads``.
+will openmp to make them.
 The index files are used to speedup the reading and are set at
 regular interval of simulation time (e.g. every :math:`(t_e - t_b) / (N - 1)`
 where :math:`t_b` (:math:`t_e`) is the initial (final) time and :math:`N` the number of index file.
@@ -87,7 +87,7 @@ Obviously, the parameter ``time`` is the requested time (in internal units)
 that should be within the limits provided by ``get_time_limits``.
 ``filter_by_ids`` allows to pick only a subset of the particles.
 This parameter takes a list containing an array for each type of particle (or None).
-The list should have the same size than the number of particle types in SWIFT.
+The list should have the same size than the number of particle types in the CSDS.
 The last parameter allows to read only some type of particles (e.g. ``part_type=0`` or
 ``part_type=[0, 1]``).
 The two last parameters cannot be used together.
diff --git a/examples/SimpleOrbits/makeIC.py b/examples/SimpleOrbits/makeIC.py
index a2418492584d0c79fa6eb900ca2b0f758c4c6084..a278db36369dc4beecc923eade2c5c1dd806fa0c 100644
--- a/examples/SimpleOrbits/makeIC.py
+++ b/examples/SimpleOrbits/makeIC.py
@@ -1,5 +1,5 @@
 ###############################################################################
-# This file is part of SWIFT.
+# This file is part of CSDS.
 # Copyright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch)
 #
 # This program is free software: you can redistribute it and/or modify
diff --git a/examples/SimpleOrbits/plotSolution.py b/examples/SimpleOrbits/plotSolution.py
index db4a8cceb25fa3df36378a17afa07eab4a3347e1..64c5d679e5e2613cfdbabfea5137822d68d4914f 100644
--- a/examples/SimpleOrbits/plotSolution.py
+++ b/examples/SimpleOrbits/plotSolution.py
@@ -1,5 +1,5 @@
 ###############################################################################
-# This file is part of SWIFT.
+# This file is part of CSDS.
 # Copyright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch)
 #
 # This program is free software: you can redistribute it and/or modify
diff --git a/examples/reader_example.py b/examples/reader_example.py
index a28e68bf0bf5ffc6ab03ea74ed086af5513c49df..b0e694422d550b3bc54224adf9da1b6399264a64 100644
--- a/examples/reader_example.py
+++ b/examples/reader_example.py
@@ -62,7 +62,7 @@ for f in args.files:
         filename = f[:-5]
     else:
         raise Exception("It seems that you are not providing a logfile (.dump)")
-    with csds.Reader(filename, verbose=0, number_threads=1, number_index=10,
+    with csds.Reader(filename, verbose=0, number_index=10,
                      restart_init=False) as reader:
 
         # Ensure that the fields are present
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
new file mode 100644
index 0000000000000000000000000000000000000000..89d3b93b527a717a8901584144f55f4475e503f6
--- /dev/null
+++ b/m4/ax_check_compile_flag.m4
@@ -0,0 +1,74 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+#   Check whether the given FLAG works with the current language's compiler
+#   or gives an error.  (Warnings, however, are ignored)
+#
+#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+#   success/failure.
+#
+#   If EXTRA-FLAGS is defined, it is added to the current language's default
+#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
+#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
+#   force the compiler to issue an error when a bad flag is given.
+#
+#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   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 General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 4
+
+AC_DEFUN([AX_CHECK_COMPILE_FLAG],
+[AC_PREREQ(2.63)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
+  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+  _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
+  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+    [AS_VAR_SET(CACHEVAR,[yes])],
+    [AS_VAR_SET(CACHEVAR,[no])])
+  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+  [m4_default([$2], :)],
+  [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/m4/ax_check_enable_debug.m4 b/m4/ax_check_enable_debug.m4
new file mode 100644
index 0000000000000000000000000000000000000000..c9e28db0ee5b2a1623280404f0776576cff7c780
--- /dev/null
+++ b/m4/ax_check_enable_debug.m4
@@ -0,0 +1,125 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_check_enable_debug.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_ENABLE_DEBUG([enable by default=yes/info/profile/no], [ENABLE DEBUG VARIABLES ...], [DISABLE DEBUG VARIABLES NDEBUG ...], [IS-RELEASE])
+#
+# DESCRIPTION
+#
+#   Check for the presence of an --enable-debug option to configure, with
+#   the specified default value used when the option is not present.  Return
+#   the value in the variable $ax_enable_debug.
+#
+#   Specifying 'yes' adds '-g -O0' to the compilation flags for all
+#   languages. Specifying 'info' adds '-g' to the compilation flags.
+#   Specifying 'profile' adds '-g -pg' to the compilation flags and '-pg' to
+#   the linking flags. Otherwise, nothing is added.
+#
+#   Define the variables listed in the second argument if debug is enabled,
+#   defaulting to no variables.  Defines the variables listed in the third
+#   argument if debug is disabled, defaulting to NDEBUG.  All lists of
+#   variables should be space-separated.
+#
+#   If debug is not enabled, ensure AC_PROG_* will not add debugging flags.
+#   Should be invoked prior to any AC_PROG_* compiler checks.
+#
+#   IS-RELEASE can be used to change the default to 'no' when making a
+#   release.  Set IS-RELEASE to 'yes' or 'no' as appropriate. By default, it
+#   uses the value of $ax_is_release, so if you are using the AX_IS_RELEASE
+#   macro, there is no need to pass this parameter.
+#
+#     AX_IS_RELEASE([git-directory])
+#     AX_CHECK_ENABLE_DEBUG()
+#
+# LICENSE
+#
+#   Copyright (c) 2011 Rhys Ulerich <rhys.ulerich@gmail.com>
+#   Copyright (c) 2014, 2015 Philip Withnall <philip@tecnocode.co.uk>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.
+
+#serial 5
+
+AC_DEFUN([AX_CHECK_ENABLE_DEBUG],[
+    AC_BEFORE([$0],[AC_PROG_CC])dnl
+    AC_BEFORE([$0],[AC_PROG_CXX])dnl
+    AC_BEFORE([$0],[AC_PROG_F77])dnl
+    AC_BEFORE([$0],[AC_PROG_FC])dnl
+
+    AC_MSG_CHECKING(whether to enable debugging)
+
+    ax_enable_debug_default=m4_tolower(m4_normalize(ifelse([$1],,[no],[$1])))
+    ax_enable_debug_is_release=m4_tolower(m4_normalize(ifelse([$4],,
+                                                              [$ax_is_release],
+                                                              [$4])))
+
+    # If this is a release, override the default.
+    AS_IF([test "$ax_enable_debug_is_release" = "yes"],
+      [ax_enable_debug_default="no"])
+
+    m4_define(ax_enable_debug_vars,[m4_normalize(ifelse([$2],,,[$2]))])
+    m4_define(ax_disable_debug_vars,[m4_normalize(ifelse([$3],,[NDEBUG],[$3]))])
+
+    AC_ARG_ENABLE(debug,
+	[AS_HELP_STRING([--enable-debug=]@<:@yes/info/profile/no@:>@,[compile with debugging])],
+	[],enable_debug=$ax_enable_debug_default)
+
+    # empty mean debug yes
+    AS_IF([test "x$enable_debug" = "x"],
+      [enable_debug="yes"])
+
+    # case of debug
+    AS_CASE([$enable_debug],
+      [yes],[
+	AC_MSG_RESULT(yes)
+	CFLAGS="-g -O0 ${CFLAGS}"
+	CXXFLAGS="-g -O0 ${CXXFLAGS}"
+	FFLAGS="-g -O0 ${FFLAGS}"
+	FCFLAGS="-g -O0 ${FCFLAGS}"
+	OBJCFLAGS="-g -O0 ${OBJCFLAGS}"
+      ],
+      [info],[
+	AC_MSG_RESULT(info)
+	CFLAGS="${CFLAGS} -g"
+	CXXFLAGS="${CXXFLAGS} -g"
+	FFLAGS="${FFLAGS} -g"
+	FCFLAGS="${FCFLAGS} -g"
+	OBJCFLAGS="${OBJCFLAGS} -g"
+      ],
+      [profile],[
+	AC_MSG_RESULT(profile)
+	CFLAGS="${CFLAGS} -g -pg"
+	CXXFLAGS="${CXXFLAGS} -g -pg"
+	FFLAGS="${FFLAGS} -g -pg"
+	FCFLAGS="${FCFLAGS} -g -pg"
+	OBJCFLAGS="${OBJCFLAGS} -g -pg"
+	LDFLAGS="${LDFLAGS} -pg"
+      ],
+      [
+	AC_MSG_RESULT(no)
+	dnl Ensure AC_PROG_CC/CXX/F77/FC/OBJC will not enable debug flags
+	dnl by setting any unset environment flag variables
+	AS_IF([test "x${CFLAGS+set}" != "xset"],
+	  [CFLAGS=""])
+	AS_IF([test "x${CXXFLAGS+set}" != "xset"],
+	  [CXXFLAGS=""])
+	AS_IF([test "x${FFLAGS+set}" != "xset"],
+	  [FFLAGS=""])
+	AS_IF([test "x${FCFLAGS+set}" != "xset"],
+	  [FCFLAGS=""])
+	AS_IF([test "x${OBJCFLAGS+set}" != "xset"],
+	  [OBJCFLAGS=""])
+      ])
+
+    dnl Define various variables if debugging is disabled.
+    dnl assert.h is a NOP if NDEBUG is defined, so define it by default.
+    dnl XXX disabled as m4_map_args_w requires 2.64, and COSMA has 2.63.
+    dnl AS_IF([test "x$enable_debug" = "xyes"],
+    dnl  [m4_map_args_w(ax_enable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is enabled])])],
+    dnl  [m4_map_args_w(ax_disable_debug_vars, [AC_DEFINE(], [,,[Define if debugging is disabled])])])
+    ax_enable_debug=$enable_debug
+])
diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4
new file mode 100644
index 0000000000000000000000000000000000000000..6df1c5301aab7da3e937932703b14d71417b917e
--- /dev/null
+++ b/m4/ax_compare_version.m4
@@ -0,0 +1,178 @@
+# ===========================================================================
+#    https://www.gnu.org/software/autoconf-archive/ax_compare_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+#
+# DESCRIPTION
+#
+#   This macro compares two version strings. Due to the various number of
+#   minor-version numbers that can exist, and the fact that string
+#   comparisons are not compatible with numeric comparisons, this is not
+#   necessarily trivial to do in a autoconf script. This macro makes doing
+#   these comparisons easy.
+#
+#   The six basic comparisons are available, as well as checking equality
+#   limited to a certain number of minor-version levels.
+#
+#   The operator OP determines what type of comparison to do, and can be one
+#   of:
+#
+#    eq  - equal (test A == B)
+#    ne  - not equal (test A != B)
+#    le  - less than or equal (test A <= B)
+#    ge  - greater than or equal (test A >= B)
+#    lt  - less than (test A < B)
+#    gt  - greater than (test A > B)
+#
+#   Additionally, the eq and ne operator can have a number after it to limit
+#   the test to that number of minor versions.
+#
+#    eq0 - equal up to the length of the shorter version
+#    ne0 - not equal up to the length of the shorter version
+#    eqN - equal up to N sub-version levels
+#    neN - not equal up to N sub-version levels
+#
+#   When the condition is true, shell commands ACTION-IF-TRUE are run,
+#   otherwise shell commands ACTION-IF-FALSE are run. The environment
+#   variable 'ax_compare_version' is always set to either 'true' or 'false'
+#   as well.
+#
+#   Examples:
+#
+#     AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
+#     AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
+#
+#   would both be true.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
+#     AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
+#
+#   would both be false.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
+#
+#   would be true because it is only comparing two minor versions.
+#
+#     AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
+#
+#   would be true because it is only comparing the lesser number of minor
+#   versions of the two values.
+#
+#   Note: The characters that separate the version numbers do not matter. An
+#   empty string is the same as version 0. OP is evaluated by autoconf, not
+#   configure, so must be a string, not a variable.
+#
+#   The author would like to acknowledge Guido Draheim whose advice about
+#   the m4_case and m4_ifvaln functions make this macro only include the
+#   portions necessary to perform the specific comparison specified by the
+#   OP argument in the final configure script.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Tim Toolan <toolan@ele.uri.edu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 13
+
+dnl #########################################################################
+AC_DEFUN([AX_COMPARE_VERSION], [
+  AC_REQUIRE([AC_PROG_AWK])
+
+  # Used to indicate true or false condition
+  ax_compare_version=false
+
+  # Convert the two version strings to be compared into a format that
+  # allows a simple string comparison.  The end result is that a version
+  # string of the form 1.12.5-r617 will be converted to the form
+  # 0001001200050617.  In other words, each number is zero padded to four
+  # digits, and non digits are removed.
+  AS_VAR_PUSHDEF([A],[ax_compare_version_A])
+  A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/[[^0-9]]//g'`
+
+  AS_VAR_PUSHDEF([B],[ax_compare_version_B])
+  B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
+                     -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
+                     -e 's/[[^0-9]]//g'`
+
+  dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
+  dnl # then the first line is used to determine if the condition is true.
+  dnl # The sed right after the echo is to remove any indented white space.
+  m4_case(m4_tolower($2),
+  [lt],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+  ],
+  [gt],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
+  ],
+  [le],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+  ],
+  [ge],[
+    ax_compare_version=`echo "x$A
+x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
+  ],[
+    dnl Split the operator from the subversion count if present.
+    m4_bmatch(m4_substr($2,2),
+    [0],[
+      # A count of zero means use the length of the shorter version.
+      # Determine the number of characters in A and B.
+      ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'`
+      ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'`
+
+      # Set A to no more than B's length and B to no more than A's length.
+      A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
+      B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
+    ],
+    [[0-9]+],[
+      # A count greater than zero means use only that many subversions
+      A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+      B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
+    ],
+    [.+],[
+      AC_WARNING(
+        [invalid OP numeric parameter: $2])
+    ],[])
+
+    # Pad zeros at end of numbers to make same length.
+    ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
+    B="$B`echo $A | sed 's/./0/g'`"
+    A="$ax_compare_version_tmp_A"
+
+    # Check for equality or inequality as necessary.
+    m4_case(m4_tolower(m4_substr($2,0,2)),
+    [eq],[
+      test "x$A" = "x$B" && ax_compare_version=true
+    ],
+    [ne],[
+      test "x$A" != "x$B" && ax_compare_version=true
+    ],[
+      AC_WARNING([invalid OP parameter: $2])
+    ])
+  ])
+
+  AS_VAR_POPDEF([A])dnl
+  AS_VAR_POPDEF([B])dnl
+
+  dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
+  if test "$ax_compare_version" = "true" ; then
+    m4_ifvaln([$4],[$4],[:])dnl
+    m4_ifvaln([$5],[else $5])dnl
+  fi
+]) dnl AX_COMPARE_VERSION
+
diff --git a/m4/ax_compiler_vendor.m4 b/m4/ax_compiler_vendor.m4
new file mode 100644
index 0000000000000000000000000000000000000000..6b67c4f93116916943d1abd92a485bb33330515f
--- /dev/null
+++ b/m4/ax_compiler_vendor.m4
@@ -0,0 +1,118 @@
+# ===========================================================================
+#    https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_COMPILER_VENDOR
+#
+# DESCRIPTION
+#
+#   Determine the vendor of the C, C++ or Fortran compiler.  The vendor is
+#   returned in the cache variable $ax_cv_c_compiler_vendor for C,
+#   $ax_cv_cxx_compiler_vendor for C++ or $ax_cv_fc_compiler_vendor for
+#   (modern) Fortran.  The value is one of "intel", "ibm", "pathscale",
+#   "clang" (LLVM), "cray", "fujitsu", "sdcc", "sx", "portland" (PGI), "gnu"
+#   (GCC), "sun" (Oracle Developer Studio), "hp", "dec", "borland",
+#   "comeau", "kai", "lcc", "sgi", "microsoft", "metrowerks", "watcom",
+#   "tcc" (Tiny CC) or "unknown" (if the compiler cannot be determined).
+#
+#   To check for a Fortran compiler, you must first call AC_FC_PP_SRCEXT
+#   with an appropriate preprocessor-enabled extension.  For example:
+#
+#     AC_LANG_PUSH([Fortran])
+#     AC_PROG_FC
+#     AC_FC_PP_SRCEXT([F])
+#     AX_COMPILER_VENDOR
+#     AC_LANG_POP([Fortran])
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2008 Matteo Frigo
+#   Copyright (c) 2018-19 John Zaitseff <J.Zaitseff@zap.org.au>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   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 General Public License along
+#   with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 30
+
+AC_DEFUN([AX_COMPILER_VENDOR], [dnl
+    AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, [dnl
+	dnl  If you modify this list of vendors, please add similar support
+	dnl  to ax_compiler_version.m4 if at all possible.
+	dnl
+	dnl  Note: Do NOT check for GCC first since some other compilers
+	dnl  define __GNUC__ to remain compatible with it.  Compilers that
+	dnl  are very slow to start (such as Intel) are listed first.
+
+	vendors="
+		intel:		__ICC,__ECC,__INTEL_COMPILER
+		ibm:		__xlc__,__xlC__,__IBMC__,__IBMCPP__,__ibmxl__
+		pathscale:	__PATHCC__,__PATHSCALE__
+		clang:		__clang__
+		cray:		_CRAYC
+		fujitsu:	__FUJITSU
+		sdcc:		SDCC,__SDCC
+		sx:		_SX
+		portland:	__PGI
+		gnu:		__GNUC__
+		sun:		__SUNPRO_C,__SUNPRO_CC,__SUNPRO_F90,__SUNPRO_F95
+		hp:		__HP_cc,__HP_aCC
+		dec:		__DECC,__DECCXX,__DECC_VER,__DECCXX_VER
+		borland:	__BORLANDC__,__CODEGEARC__,__TURBOC__
+		comeau:		__COMO__
+		kai:		__KCC
+		lcc:		__LCC__
+		sgi:		__sgi,sgi
+		microsoft:	_MSC_VER
+		metrowerks:	__MWERKS__
+		watcom:		__WATCOMC__
+		tcc:		__TINYC__
+		unknown:	UNKNOWN
+	"
+	for ventest in $vendors; do
+	    case $ventest in
+		*:)
+		    vendor=$ventest
+		    continue
+		    ;;
+		*)
+		    vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")"
+		    ;;
+	    esac
+
+	    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[
+#if !($vencpp)
+      thisisanerror;
+#endif
+	    ]])], [break])
+	done
+
+	ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1`
+    ])
+])dnl
+
diff --git a/m4/ax_compiler_version.m4 b/m4/ax_compiler_version.m4
new file mode 100644
index 0000000000000000000000000000000000000000..4995beb6032e792c209b1e045c7f58b8712f89a2
--- /dev/null
+++ b/m4/ax_compiler_version.m4
@@ -0,0 +1,530 @@
+# ===========================================================================
+#   https://www.gnu.org/software/autoconf-archive/ax_compiler_version.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_COMPILER_VERSION
+#
+# DESCRIPTION
+#
+#   This macro retrieves the compiler version and returns it in the cache
+#   variable $ax_cv_c_compiler_version for C and $ax_cv_cxx_compiler_version
+#   for C++.
+#
+#   Version is returned as epoch:major.minor.patchversion
+#
+#   Epoch is used in order to have an increasing version number in case of
+#   marketing change.
+#
+#   Epoch use: * borland compiler use chronologically 0turboc for turboc
+#   era,
+#
+#     1borlanc BORLANDC++ before 5, 2cppbuilder for cppbuilder era,
+#     3borlancpp for return of BORLANDC++ (after version 5.5),
+#     4cppbuilder for cppbuilder with year version,
+#     and 5xe for XE era.
+#
+#   An empty string is returned otherwise.
+#
+# LICENSE
+#
+#   Copyright (c) 2014 Bastien ROUCARIES <roucaries.bastien+autoconf@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 12
+
+# for intel
+AC_DEFUN([_AX_COMPILER_VERSION_INTEL],
+  [ dnl
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    [__INTEL_COMPILER/100],,
+    AC_MSG_FAILURE([[[$0]] unknown intel compiler version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    [(__INTEL_COMPILER%100)/10],,
+    AC_MSG_FAILURE([[[$0]] unknown intel compiler version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [(__INTEL_COMPILER%10)],,
+    AC_MSG_FAILURE([[[$0]] unknown intel compiler version]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# for IBM
+AC_DEFUN([_AX_COMPILER_VERSION_IBM],
+  [ dnl
+  dnl check between z/OS C/C++  and XL C/C++
+  AC_COMPILE_IFELSE([
+    AC_LANG_PROGRAM([],
+      [
+        #if defined(__COMPILER_VER__)
+        choke me;
+        #endif
+      ])],
+    [
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+        [__xlC__/100],,
+      	AC_MSG_FAILURE([[[$0]] unknown IBM compiler major version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+        [__xlC__%100],,
+      	AC_MSG_FAILURE([[[$0]] unknown IBM compiler minor version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+        [__xlC_ver__/0x100],,
+      	AC_MSG_FAILURE([[[$0]] unknown IBM compiler patch version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_build,
+        [__xlC_ver__%0x100],,
+      	AC_MSG_FAILURE([[[$0]] unknown IBM compiler build version]))
+      ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_build"
+    ],
+    [
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+        [__xlC__%1000],,
+      	AC_MSG_FAILURE([[[$0]] unknown IBM compiler patch version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+        [(__xlC__/10000)%10],,
+      	AC_MSG_FAILURE([[[$0]] unknown IBM compiler minor version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+        [(__xlC__/100000)%10],,
+      	AC_MSG_FAILURE([[[$0]] unknown IBM compiler major version]))
+      ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+    ])
+])
+
+# for pathscale
+AC_DEFUN([_AX_COMPILER_VERSION_PATHSCALE],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    __PATHCC__,,
+    AC_MSG_FAILURE([[[$0]] unknown pathscale major]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    __PATHCC_MINOR__,,
+    AC_MSG_FAILURE([[[$0]] unknown pathscale minor]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [__PATHCC_PATCHLEVEL__],,
+    AC_MSG_FAILURE([[[$0]] unknown pathscale patch level]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# for clang
+AC_DEFUN([_AX_COMPILER_VERSION_CLANG],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    __clang_major__,,
+    AC_MSG_FAILURE([[[$0]] unknown clang major]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    __clang_minor__,,
+    AC_MSG_FAILURE([[[$0]] unknown clang minor]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [__clang_patchlevel__],,0)
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# for crayc
+AC_DEFUN([_AX_COMPILER_VERSION_CRAY],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    _RELEASE,,
+    AC_MSG_FAILURE([[[$0]] unknown crayc release]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    _RELEASE_MINOR,,
+    AC_MSG_FAILURE([[[$0]] unknown crayc minor]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor"
+  ])
+
+# for fujitsu
+AC_DEFUN([_AX_COMPILER_VERSION_FUJITSU],[
+  AC_COMPUTE_INT(ax_cv_[]_AC_LANG_ABBREV[]_compiler_version,
+                 __FCC_VERSION,,
+		 AC_MSG_FAILURE([[[$0]]unknown fujitsu release]))
+  ])
+
+# for GNU
+AC_DEFUN([_AX_COMPILER_VERSION_GNU],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    __GNUC__,,
+    AC_MSG_FAILURE([[[$0]] unknown gcc major]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    __GNUC_MINOR__,,
+    AC_MSG_FAILURE([[[$0]] unknown gcc minor]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [__GNUC_PATCHLEVEL__],,
+    AC_MSG_FAILURE([[[$0]] unknown gcc patch level]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# For sun
+AC_DEFUN([_AX_COMPILER_VERSION_SUN],[
+  m4_define([_AX_COMPILER_VERSION_SUN_NUMBER],
+            [
+	     #if defined(__SUNPRO_CC)
+	     __SUNPRO_CC
+	     #else
+	     __SUNPRO_C
+	     #endif
+	    ])
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_until59,
+    !!(_AX_COMPILER_VERSION_SUN_NUMBER < 0x1000),,
+    AC_MSG_FAILURE([[[$0]] unknown sun release version]))
+  AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_until59" = X1],
+    [dnl
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+        _AX_COMPILER_VERSION_SUN_NUMBER % 0x10,,
+	AC_MSG_FAILURE([[[$0]] unknown sun patch version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+        (_AX_COMPILER_VERSION_SUN_NUMBER / 0x10) % 0x10,,
+        AC_MSG_FAILURE([[[$0]] unknown sun minor version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+        (_AX_COMPILER_VERSION_SUN_NUMBER / 0x100),,
+        AC_MSG_FAILURE([[[$0]] unknown sun major version]))
+    ],
+    [dnl
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+        _AX_COMPILER_VERSION_SUN_NUMBER % 0x10,,
+        AC_MSG_FAILURE([[[$0]] unknown sun patch version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+        (_AX_COMPILER_VERSION_SUN_NUMBER / 0x100) % 0x100,,
+        AC_MSG_FAILURE([[[$0]] unknown sun minor version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+        (_AX_COMPILER_VERSION_SUN_NUMBER / 0x1000),,
+        AC_MSG_FAILURE([[[$0]] unknown sun major version]))
+    ])
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+])
+
+AC_DEFUN([_AX_COMPILER_VERSION_HP],[
+  m4_define([_AX_COMPILER_VERSION_HP_NUMBER],
+            [
+	     #if defined(__HP_cc)
+	     __HP_cc
+	     #else
+	     __HP_aCC
+	     #endif
+	    ])
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_untilA0121,
+    !!(_AX_COMPILER_VERSION_HP_NUMBER <= 1),,
+    AC_MSG_FAILURE([[[$0]] unknown hp release version]))
+  AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_untilA0121" = X1],
+    [dnl By default output last version with this behavior.
+     dnl it is so old
+      ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="01.21.00"
+    ],
+    [dnl
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+        (_AX_COMPILER_VERSION_HP_NUMBER % 100),,
+        AC_MSG_FAILURE([[[$0]] unknown hp release version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+        ((_AX_COMPILER_VERSION_HP_NUMBER / 100)%100),,
+        AC_MSG_FAILURE([[[$0]] unknown hp minor version]))
+      AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+        ((_AX_COMPILER_VERSION_HP_NUMBER / 10000)%100),,
+        AC_MSG_FAILURE([[[$0]] unknown hp major version]))
+      ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+    ])
+])
+
+AC_DEFUN([_AX_COMPILER_VERSION_DEC],[dnl
+  m4_define([_AX_COMPILER_VERSION_DEC_NUMBER],
+            [
+	     #if defined(__DECC_VER)
+	     __DECC_VER
+	     #else
+	     __DECCXX_VER
+	     #endif
+	    ])
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    (_AX_COMPILER_VERSION_DEC_NUMBER % 10000),,
+    AC_MSG_FAILURE([[[$0]] unknown dec release version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    ((_AX_COMPILER_VERSION_DEC_NUMBER / 100000UL)%100),,
+    AC_MSG_FAILURE([[[$0]] unknown dec minor version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    ((_AX_COMPILER_VERSION_DEC_NUMBER / 10000000UL)%100),,
+    AC_MSG_FAILURE([[[$0]] unknown dec major version]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# borland
+AC_DEFUN([_AX_COMPILER_VERSION_BORLAND],[dnl
+  m4_define([_AX_COMPILER_VERSION_TURBOC_NUMBER],
+            [
+	     #if defined(__TURBOC__)
+	     __TURBOC__
+	     #else
+	     choke me
+	     #endif
+	    ])
+  m4_define([_AX_COMPILER_VERSION_BORLANDC_NUMBER],
+            [
+	     #if defined(__BORLANDC__)
+	     __BORLANDC__
+	     #else
+	     __CODEGEARC__
+	     #endif
+	    ])
+ AC_COMPILE_IFELSE(
+   [AC_LANG_PROGRAM(,
+     _AX_COMPILER_VERSION_TURBOC_NUMBER)],
+   [dnl TURBOC
+     AC_COMPUTE_INT(
+       _ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw,
+       _AX_COMPILER_VERSION_TURBOC_NUMBER,,
+       AC_MSG_FAILURE([[[$0]] unknown turboc version]))
+     AS_IF(
+       [test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw -lt 661 || test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw -gt 1023],
+       [dnl compute normal version
+        AC_COMPUTE_INT(
+	  _ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+	  _AX_COMPILER_VERSION_TURBOC_NUMBER % 0x100,,
+	  AC_MSG_FAILURE([[[$0]] unknown turboc minor version]))
+	AC_COMPUTE_INT(
+	  _ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+	  (_AX_COMPILER_VERSION_TURBOC_NUMBER/0x100)%0x100,,
+	  AC_MSG_FAILURE([[[$0]] unknown turboc major version]))
+	ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor"],
+      [dnl special version
+       AS_CASE([$_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw],
+         [661],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:1.00"],
+	 [662],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:1.01"],
+         [663],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:2.00"],
+	 [
+	 AC_MSG_WARN([[[$0]] unknown turboc version between 0x295 and 0x400 please report bug])
+	 ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=""
+	 ])
+      ])
+    ],
+    # borlandc
+    [
+    AC_COMPUTE_INT(
+      _ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw,
+      _AX_COMPILER_VERSION_BORLANDC_NUMBER,,
+      AC_MSG_FAILURE([[[$0]] unknown borlandc version]))
+    AS_CASE([$_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw],
+      dnl BORLANDC++ before 5.5
+      [512] ,[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:2.00"],
+      [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"],
+      [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"],
+      [1040],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.1"],
+      [1106],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:4.0"],
+      [1280],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:5.0"],
+      [1312],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:5.02"],
+      dnl C++ Builder era
+      [1328],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:3.0"],
+      [1344],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:4.0"],
+      dnl BORLANDC++ after 5.5
+      [1360],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.5"],
+      [1361],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.51"],
+      [1378],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.6.4"],
+      dnl C++ Builder with year number
+      [1392],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2006"],
+      [1424],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2007"],
+      [1555],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2009"],
+      [1569],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2010"],
+      dnl XE version
+      [1584],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe"],
+      [1600],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:2"],
+      [1616],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:3"],
+      [1632],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:4"],
+      [
+      AC_MSG_WARN([[[$0]] Unknown borlandc compiler version $_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw please report bug])
+      ])
+    ])
+  ])
+
+# COMO
+AC_DEFUN([_AX_COMPILER_VERSION_COMEAU],
+  [ dnl
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    [__COMO_VERSION__%100],,
+    AC_MSG_FAILURE([[[$0]] unknown comeau compiler minor version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    [(__COMO_VERSION__/100)%10],,
+    AC_MSG_FAILURE([[[$0]] unknown comeau compiler major version]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor"
+  ])
+
+# KAI
+AC_DEFUN([_AX_COMPILER_VERSION_KAI],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [__KCC_VERSION%100],,
+    AC_MSG_FAILURE([[[$0]] unknown kay compiler patch version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    [(__KCC_VERSION/100)%10],,
+    AC_MSG_FAILURE([[[$0]] unknown kay compiler minor version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    [(__KCC_VERSION/1000)%10],,
+    AC_MSG_FAILURE([[[$0]] unknown kay compiler major version]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+dnl LCC
+dnl LCC does not output version...
+
+# SGI
+AC_DEFUN([_AX_COMPILER_VERSION_SGI],[
+   m4_define([_AX_COMPILER_VERSION_SGI_NUMBER],
+            [
+	     #if defined(_COMPILER_VERSION)
+	     _COMPILER_VERSION
+	     #else
+	     _SGI_COMPILER_VERSION
+	     #endif
+	    ])
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [_AX_COMPILER_VERSION_SGI_NUMBER%10],,
+    AC_MSG_FAILURE([[[$0]] unknown SGI compiler patch version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    [(_AX_COMPILER_VERSION_SGI_NUMBER/10)%10],,
+    AC_MSG_FAILURE([[[$0]] unknown SGI compiler minor version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    [(_AX_COMPILER_VERSION_SGI_NUMBER/100)%10],,
+    AC_MSG_FAILURE([[[$0]] unknown SGI compiler major version]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# microsoft
+AC_DEFUN([_AX_COMPILER_VERSION_MICROSOFT],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    _MSC_VER%100,,
+    AC_MSG_FAILURE([[[$0]] unknown microsoft compiler minor version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    (_MSC_VER/100)%100,,
+    AC_MSG_FAILURE([[[$0]] unknown microsoft compiler major version]))
+  dnl could be overridden
+  _ax_[]_AC_LANG_ABBREV[]_compiler_version_patch=0
+  _ax_[]_AC_LANG_ABBREV[]_compiler_version_build=0
+  # special case for version 6
+  AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major" = "X12"],
+    [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+       _MSC_FULL_VER%1000,,
+       _ax_[]_AC_LANG_ABBREV[]_compiler_version_patch=0)])
+  # for version 7
+  AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major" = "X13"],
+    [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+       _MSC_FULL_VER%1000,,
+       AC_MSG_FAILURE([[[$0]] unknown microsoft compiler patch version]))
+    ])
+  # for version > 8
+ AS_IF([test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_major -ge 14],
+    [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+       _MSC_FULL_VER%10000,,
+       AC_MSG_FAILURE([[[$0]] unknown microsoft compiler patch version]))
+    ])
+ AS_IF([test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_major -ge 15],
+    [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_build,
+       _MSC_BUILD,,
+       AC_MSG_FAILURE([[[$0]] unknown microsoft compiler build version]))
+    ])
+ ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_build"
+ ])
+
+# for metrowerks
+AC_DEFUN([_AX_COMPILER_VERSION_METROWERKS],[dnl
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    __MWERKS__%0x100,,
+    AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler patch version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    (__MWERKS__/0x100)%0x10,,
+    AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler minor version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    (__MWERKS__/0x1000)%0x10,,
+    AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler major version]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# for watcom
+AC_DEFUN([_AX_COMPILER_VERSION_WATCOM],[dnl
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    __WATCOMC__%100,,
+    AC_MSG_FAILURE([[[$0]] unknown watcom compiler minor version]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    (__WATCOMC__/100)%100,,
+    AC_MSG_FAILURE([[[$0]] unknown watcom compiler major version]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor"
+  ])
+
+# for PGI
+AC_DEFUN([_AX_COMPILER_VERSION_PORTLAND],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    __PGIC__,,
+    AC_MSG_FAILURE([[[$0]] unknown pgi major]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    __PGIC_MINOR__,,
+    AC_MSG_FAILURE([[[$0]] unknown pgi minor]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [__PGIC_PATCHLEVEL__],,
+    AC_MSG_FAILURE([[[$0]] unknown pgi patch level]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# tcc
+AC_DEFUN([_AX_COMPILER_VERSION_TCC],[
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=[`tcc -v | $SED 's/^[ ]*tcc[ ]\+version[ ]\+\([0-9.]\+\).*/\1/g'`]
+  ])
+
+# for GNU
+AC_DEFUN([_AX_COMPILER_VERSION_SDCC],[
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major,
+    /* avoid parse error with comments */
+    #if(defined(__SDCC_VERSION_MAJOR))
+	__SDCC_VERSION_MAJOR
+    #else
+	SDCC/100
+    #endif
+    ,,
+    AC_MSG_FAILURE([[[$0]] unknown sdcc major]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor,
+    /* avoid parse error with comments */
+    #if(defined(__SDCC_VERSION_MINOR))
+	__SDCC_VERSION_MINOR
+    #else
+	(SDCC%100)/10
+    #endif
+    ,,
+    AC_MSG_FAILURE([[[$0]] unknown sdcc minor]))
+  AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch,
+    [
+    /* avoid parse error with comments */
+    #if(defined(__SDCC_VERSION_PATCH))
+	__SDCC_VERSION_PATCH
+    #elsif(defined(_SDCC_VERSION_PATCHLEVEL))
+	__SDCC_VERSION_PATCHLEVEL
+    #else
+	SDCC%10
+    #endif
+    ],,
+    AC_MSG_FAILURE([[[$0]] unknown sdcc patch level]))
+  ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch"
+  ])
+
+# main entry point
+AC_DEFUN([AX_COMPILER_VERSION],[dnl
+  AC_REQUIRE([AX_COMPILER_VENDOR])
+  AC_REQUIRE([AC_PROG_SED])
+  AC_CACHE_CHECK([for _AC_LANG compiler version],
+    ax_cv_[]_AC_LANG_ABBREV[]_compiler_version,
+    [ dnl
+      AS_CASE([$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor],
+        [intel],[_AX_COMPILER_VERSION_INTEL],
+	[ibm],[_AX_COMPILER_VERSION_IBM],
+	[pathscale],[_AX_COMPILER_VERSION_PATHSCALE],
+	[clang],[_AX_COMPILER_VERSION_CLANG],
+	[cray],[_AX_COMPILER_VERSION_CRAY],
+	[fujitsu],[_AX_COMPILER_VERSION_FUJITSU],
+        [gnu],[_AX_COMPILER_VERSION_GNU],
+	[sun],[_AX_COMPILER_VERSION_SUN],
+	[hp],[_AX_COMPILER_VERSION_HP],
+	[dec],[_AX_COMPILER_VERSION_DEC],
+	[borland],[_AX_COMPILER_VERSION_BORLAND],
+	[comeau],[_AX_COMPILER_VERSION_COMEAU],
+	[kai],[_AX_COMPILER_VERSION_KAI],
+	[sgi],[_AX_COMPILER_VERSION_SGI],
+	[microsoft],[_AX_COMPILER_VERSION_MICROSOFT],
+	[metrowerks],[_AX_COMPILER_VERSION_METROWERKS],
+	[watcom],[_AX_COMPILER_VERSION_WATCOM],
+	[portland],[_AX_COMPILER_VERSION_PORTLAND],
+	[tcc],[_AX_COMPILER_VERSION_TCC],
+	[sdcc],[_AX_COMPILER_VERSION_SDCC],
+  	[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=""])
+    ])
+])
+
diff --git a/m4/ax_prog_doxygen.m4 b/m4/ax_prog_doxygen.m4
new file mode 100644
index 0000000000000000000000000000000000000000..b0238c10ed0afbb2e8a39197ce0e7e1dd6a7d0d2
--- /dev/null
+++ b/m4/ax_prog_doxygen.m4
@@ -0,0 +1,587 @@
+# ===========================================================================
+#     https://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...)
+#   DX_DOXYGEN_FEATURE(ON|OFF)
+#   DX_DOT_FEATURE(ON|OFF)
+#   DX_HTML_FEATURE(ON|OFF)
+#   DX_CHM_FEATURE(ON|OFF)
+#   DX_CHI_FEATURE(ON|OFF)
+#   DX_MAN_FEATURE(ON|OFF)
+#   DX_RTF_FEATURE(ON|OFF)
+#   DX_XML_FEATURE(ON|OFF)
+#   DX_PDF_FEATURE(ON|OFF)
+#   DX_PS_FEATURE(ON|OFF)
+#
+# DESCRIPTION
+#
+#   The DX_*_FEATURE macros control the default setting for the given
+#   Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for
+#   generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML
+#   help (for MS users), 'CHI' for generating a separate .chi file by the
+#   .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate
+#   output formats. The environment variable DOXYGEN_PAPER_SIZE may be
+#   specified to override the default 'a4wide' paper size.
+#
+#   By default, HTML, PDF and PS documentation is generated as this seems to
+#   be the most popular and portable combination. MAN pages created by
+#   Doxygen are usually problematic, though by picking an appropriate subset
+#   and doing some massaging they might be better than nothing. CHM and RTF
+#   are specific for MS (note that you can't generate both HTML and CHM at
+#   the same time). The XML is rather useless unless you apply specialized
+#   post-processing to it.
+#
+#   The macros mainly control the default state of the feature. The use can
+#   override the default by specifying --enable or --disable. The macros
+#   ensure that contradictory flags are not given (e.g.,
+#   --enable-doxygen-html and --enable-doxygen-chm,
+#   --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each
+#   feature will be automatically disabled (with a warning) if the required
+#   programs are missing.
+#
+#   Once all the feature defaults have been specified, call DX_INIT_DOXYGEN
+#   with the following parameters: a one-word name for the project for use
+#   as a filename base etc., an optional configuration file name (the
+#   default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an
+#   optional output directory name (the default is 'doxygen-doc'). To run
+#   doxygen multiple times for different configuration files and output
+#   directories provide more parameters: the second, forth, sixth, etc
+#   parameter are configuration file names and the third, fifth, seventh,
+#   etc parameter are output directories. No checking is done to catch
+#   duplicates.
+#
+#   Automake Support
+#
+#   The DX_RULES substitution can be used to add all needed rules to the
+#   Makefile. Note that this is a substitution without being a variable:
+#   only the @DX_RULES@ syntax will work.
+#
+#   The provided targets are:
+#
+#     doxygen-doc: Generate all doxygen documentation.
+#
+#     doxygen-run: Run doxygen, which will generate some of the
+#                  documentation (HTML, CHM, CHI, MAN, RTF, XML)
+#                  but will not do the post processing required
+#                  for the rest of it (PS, PDF).
+#
+#     doxygen-ps:  Generate doxygen PostScript documentation.
+#
+#     doxygen-pdf: Generate doxygen PDF documentation.
+#
+#   Note that by default these are not integrated into the automake targets.
+#   If doxygen is used to generate man pages, you can achieve this
+#   integration by setting man3_MANS to the list of man pages generated and
+#   then adding the dependency:
+#
+#     $(man3_MANS): doxygen-doc
+#
+#   This will cause make to run doxygen and generate all the documentation.
+#
+#   The following variable is intended for use in Makefile.am:
+#
+#     DX_CLEANFILES = everything to clean.
+#
+#   Then add this variable to MOSTLYCLEANFILES.
+#
+# LICENSE
+#
+#   Copyright (c) 2009 Oren Ben-Kiki <oren@ben-kiki.org>
+#   Copyright (c) 2015 Olaf Mandel <olaf@mandel.name>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 24
+
+## ----------##
+## Defaults. ##
+## ----------##
+
+DX_ENV=""
+AC_DEFUN([DX_FEATURE_doc],  ON)
+AC_DEFUN([DX_FEATURE_dot],  OFF)
+AC_DEFUN([DX_FEATURE_man],  OFF)
+AC_DEFUN([DX_FEATURE_html], ON)
+AC_DEFUN([DX_FEATURE_chm],  OFF)
+AC_DEFUN([DX_FEATURE_chi],  OFF)
+AC_DEFUN([DX_FEATURE_rtf],  OFF)
+AC_DEFUN([DX_FEATURE_xml],  OFF)
+AC_DEFUN([DX_FEATURE_pdf],  ON)
+AC_DEFUN([DX_FEATURE_ps],   ON)
+
+## --------------- ##
+## Private macros. ##
+## --------------- ##
+
+# DX_ENV_APPEND(VARIABLE, VALUE)
+# ------------------------------
+# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it
+# as a substitution (but not a Makefile variable). The substitution
+# is skipped if the variable name is VERSION.
+AC_DEFUN([DX_ENV_APPEND],
+[AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl
+m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl
+AM_SUBST_NOTMAKE([$1])])dnl
+])
+
+# DX_DIRNAME_EXPR
+# ---------------
+# Expand into a shell expression prints the directory part of a path.
+AC_DEFUN([DX_DIRNAME_EXPR],
+         [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
+
+# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
+# -------------------------------------
+# Expands according to the M4 (static) status of the feature.
+AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
+
+# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
+# ----------------------------------
+# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
+AC_DEFUN([DX_REQUIRE_PROG], [
+AC_PATH_TOOL([$1], [$2])
+if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
+    AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
+    AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
+fi
+])
+
+# DX_TEST_FEATURE(FEATURE)
+# ------------------------
+# Expand to a shell expression testing whether the feature is active.
+AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
+
+# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
+# -------------------------------------------------
+# Verify that a required features has the right state before trying to turn on
+# the DX_CURRENT_FEATURE.
+AC_DEFUN([DX_CHECK_DEPEND], [
+test "$DX_FLAG_$1" = "$2" \
+|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
+                            requires, contradicts) doxygen-$1])
+])
+
+# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
+# ----------------------------------------------------------
+# Turn off the DX_CURRENT_FEATURE if the required feature is off.
+AC_DEFUN([DX_CLEAR_DEPEND], [
+test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
+])
+
+# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
+#                CHECK_DEPEND, CLEAR_DEPEND,
+#                REQUIRE, DO-IF-ON, DO-IF-OFF)
+# --------------------------------------------
+# Parse the command-line option controlling a feature. CHECK_DEPEND is called
+# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
+# otherwise CLEAR_DEPEND is called to turn off the default state if a required
+# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
+# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
+# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
+AC_DEFUN([DX_ARG_ABLE], [
+    AC_DEFUN([DX_CURRENT_FEATURE], [$1])
+    AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
+    AC_ARG_ENABLE(doxygen-$1,
+                  [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
+                                                      [--enable-doxygen-$1]),
+                                  DX_IF_FEATURE([$1], [don't $2], [$2]))],
+                  [
+case "$enableval" in
+#(
+y|Y|yes|Yes|YES)
+    AC_SUBST([DX_FLAG_$1], 1)
+    $3
+;; #(
+n|N|no|No|NO)
+    AC_SUBST([DX_FLAG_$1], 0)
+;; #(
+*)
+    AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
+;;
+esac
+], [
+AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
+$4
+])
+if DX_TEST_FEATURE([$1]); then
+    $5
+    :
+fi
+if DX_TEST_FEATURE([$1]); then
+    $6
+    :
+else
+    $7
+    :
+fi
+])
+
+## -------------- ##
+## Public macros. ##
+## -------------- ##
+
+# DX_XXX_FEATURE(DEFAULT_STATE)
+# -----------------------------
+AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc],  [$1])])
+AC_DEFUN([DX_DOT_FEATURE],     [AC_DEFUN([DX_FEATURE_dot], [$1])])
+AC_DEFUN([DX_MAN_FEATURE],     [AC_DEFUN([DX_FEATURE_man],  [$1])])
+AC_DEFUN([DX_HTML_FEATURE],    [AC_DEFUN([DX_FEATURE_html], [$1])])
+AC_DEFUN([DX_CHM_FEATURE],     [AC_DEFUN([DX_FEATURE_chm],  [$1])])
+AC_DEFUN([DX_CHI_FEATURE],     [AC_DEFUN([DX_FEATURE_chi],  [$1])])
+AC_DEFUN([DX_RTF_FEATURE],     [AC_DEFUN([DX_FEATURE_rtf],  [$1])])
+AC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])
+AC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])
+AC_DEFUN([DX_PDF_FEATURE],     [AC_DEFUN([DX_FEATURE_pdf],  [$1])])
+AC_DEFUN([DX_PS_FEATURE],      [AC_DEFUN([DX_FEATURE_ps],   [$1])])
+
+# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...)
+# --------------------------------------------------------------
+# PROJECT also serves as the base name for the documentation files.
+# The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is
+# "doxygen-doc".
+# More arguments are interpreted as interleaved CONFIG-FILE and
+# OUTPUT-DOC-DIR values.
+AC_DEFUN([DX_INIT_DOXYGEN], [
+
+# Files:
+AC_SUBST([DX_PROJECT], [$1])
+AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])'])
+AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])'])
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2,
+      [AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]),
+                'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+                                          [$(srcdir)/Doxyfile])')])])dnl
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2,
+      [AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]),
+                'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+                                          [doxygen-doc])')])])dnl
+m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1,
+          [m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])],
+          [])))dnl
+
+# Environment variables used inside doxygen.cfg:
+DX_ENV_APPEND(SRCDIR, $srcdir)
+DX_ENV_APPEND(PROJECT, $DX_PROJECT)
+DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
+
+# Doxygen itself:
+DX_ARG_ABLE(doc, [generate any doxygen documentation],
+            [],
+            [],
+            [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
+             DX_REQUIRE_PROG([DX_PERL], perl)],
+            [DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
+
+# Dot for graphics:
+DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_DOT], dot)],
+            [DX_ENV_APPEND(HAVE_DOT, YES)
+             DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
+            [DX_ENV_APPEND(HAVE_DOT, NO)])
+
+# Man pages generation:
+DX_ARG_ABLE(man, [generate doxygen manual pages],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_MAN, YES)],
+            [DX_ENV_APPEND(GENERATE_MAN, NO)])
+
+# RTF file generation:
+DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_RTF, YES)],
+            [DX_ENV_APPEND(GENERATE_RTF, NO)])
+
+# XML file generation:
+DX_ARG_ABLE(xml, [generate doxygen XML documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_XML, YES)],
+            [DX_ENV_APPEND(GENERATE_XML, NO)])
+
+# (Compressed) HTML help generation:
+DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_HHC], hhc)],
+            [DX_ENV_APPEND(HHC_PATH, $DX_HHC)
+             DX_ENV_APPEND(GENERATE_HTML, YES)
+             DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
+            [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
+
+# Separate CHI file generation.
+DX_ARG_ABLE(chi, [generate doxygen separate compressed HTML help index file],
+            [DX_CHECK_DEPEND(chm, 1)],
+            [DX_CLEAR_DEPEND(chm, 1)],
+            [],
+            [DX_ENV_APPEND(GENERATE_CHI, YES)],
+            [DX_ENV_APPEND(GENERATE_CHI, NO)])
+
+# Plain HTML pages generation:
+DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
+            [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
+            [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
+            [],
+            [DX_ENV_APPEND(GENERATE_HTML, YES)],
+            [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
+
+# PostScript file generation:
+DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_LATEX], latex)
+             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+             DX_REQUIRE_PROG([DX_DVIPS], dvips)
+             DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# PDF file generation:
+DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
+            [DX_CHECK_DEPEND(doc, 1)],
+            [DX_CLEAR_DEPEND(doc, 1)],
+            [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
+             DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
+             DX_REQUIRE_PROG([DX_EGREP], egrep)])
+
+# LaTeX generation for PS and/or PDF:
+if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
+    DX_ENV_APPEND(GENERATE_LATEX, YES)
+else
+    DX_ENV_APPEND(GENERATE_LATEX, NO)
+fi
+
+# Paper size for PS and/or PDF:
+AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
+           [a4wide (default), a4, letter, legal or executive])
+case "$DOXYGEN_PAPER_SIZE" in
+#(
+"")
+    AC_SUBST(DOXYGEN_PAPER_SIZE, "")
+;; #(
+a4wide|a4|letter|legal|executive)
+    DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
+;; #(
+*)
+    AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
+;;
+esac
+
+# Rules:
+AS_IF([[test $DX_FLAG_html -eq 1]],
+[[DX_SNIPPET_html="## ------------------------------- ##
+## Rules specific for HTML output. ##
+## ------------------------------- ##
+
+DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+                \$(DX_DOCDIR]DX_i[)/html]])[
+
+"]],
+[[DX_SNIPPET_html=""]])
+AS_IF([[test $DX_FLAG_chi -eq 1]],
+[[DX_SNIPPET_chi="
+DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]],
+[[DX_SNIPPET_chi=""]])
+AS_IF([[test $DX_FLAG_chm -eq 1]],
+[[DX_SNIPPET_chm="## ------------------------------ ##
+## Rules specific for CHM output. ##
+## ------------------------------ ##
+
+DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/chm]])[\
+${DX_SNIPPET_chi}
+
+"]],
+[[DX_SNIPPET_chm=""]])
+AS_IF([[test $DX_FLAG_man -eq 1]],
+[[DX_SNIPPET_man="## ------------------------------ ##
+## Rules specific for MAN output. ##
+## ------------------------------ ##
+
+DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/man]])[
+
+"]],
+[[DX_SNIPPET_man=""]])
+AS_IF([[test $DX_FLAG_rtf -eq 1]],
+[[DX_SNIPPET_rtf="## ------------------------------ ##
+## Rules specific for RTF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/rtf]])[
+
+"]],
+[[DX_SNIPPET_rtf=""]])
+AS_IF([[test $DX_FLAG_xml -eq 1]],
+[[DX_SNIPPET_xml="## ------------------------------ ##
+## Rules specific for XML output. ##
+## ------------------------------ ##
+
+DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/xml]])[
+
+"]],
+[[DX_SNIPPET_xml=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1]],
+[[DX_SNIPPET_ps="## ----------------------------- ##
+## Rules specific for PS output. ##
+## ----------------------------- ##
+
+DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+              \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[
+
+DX_PS_GOAL = doxygen-ps
+
+doxygen-ps: \$(DX_CLEAN_PS)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+	\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+	rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+	\$(DX_LATEX) refman.tex; \\
+	\$(DX_MAKEINDEX) refman.idx; \\
+	\$(DX_LATEX) refman.tex; \\
+	countdown=5; \\
+	while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+	                  refman.log > /dev/null 2>&1 \\
+	   && test \$\$countdown -gt 0; do \\
+	    \$(DX_LATEX) refman.tex; \\
+            countdown=\`expr \$\$countdown - 1\`; \\
+	done; \\
+	\$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi
+
+]])["]],
+[[DX_SNIPPET_ps=""]])
+AS_IF([[test $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_pdf="## ------------------------------ ##
+## Rules specific for PDF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[
+
+DX_PDF_GOAL = doxygen-pdf
+
+doxygen-pdf: \$(DX_CLEAN_PDF)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+	\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+	rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+	\$(DX_PDFLATEX) refman.tex; \\
+	\$(DX_MAKEINDEX) refman.idx; \\
+	\$(DX_PDFLATEX) refman.tex; \\
+	countdown=5; \\
+	while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+	                  refman.log > /dev/null 2>&1 \\
+	   && test \$\$countdown -gt 0; do \\
+	    \$(DX_PDFLATEX) refman.tex; \\
+	    countdown=\`expr \$\$countdown - 1\`; \\
+	done; \\
+	mv refman.pdf ../\$(PACKAGE).pdf
+
+]])["]],
+[[DX_SNIPPET_pdf=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_latex="## ------------------------------------------------- ##
+## Rules specific for LaTeX (shared for PS and PDF). ##
+## ------------------------------------------------- ##
+
+DX_V_LATEX = \$(_DX_v_LATEX_\$(V))
+_DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_LATEX_0 = @echo \"  LATEX \" \$][@;
+
+DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+                 \$(DX_DOCDIR]DX_i[)/latex]])[
+
+"]],
+[[DX_SNIPPET_latex=""]])
+
+AS_IF([[test $DX_FLAG_doc -eq 1]],
+[[DX_SNIPPET_doc="## --------------------------------- ##
+## Format-independent Doxygen rules. ##
+## --------------------------------- ##
+
+${DX_SNIPPET_html}\
+${DX_SNIPPET_chm}\
+${DX_SNIPPET_man}\
+${DX_SNIPPET_rtf}\
+${DX_SNIPPET_xml}\
+${DX_SNIPPET_ps}\
+${DX_SNIPPET_pdf}\
+${DX_SNIPPET_latex}\
+DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V))
+_DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_DXGEN_0 = @echo \"  DXGEN \" \$<;
+
+.PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+.INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+doxygen-run:]m4_foreach([DX_i], [DX_loop],
+                         [[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[
+
+doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS)
+	\$(A""M_V_at)rm -rf \$(DX_DOCDIR]DX_i[)
+	\$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[)
+	\$(A""M_V_at)echo Timestamp >\$][@
+
+]])dnl
+[DX_CLEANFILES = \\]
+m4_foreach([DX_i], [DX_loop],
+[[	\$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\
+	\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\
+]])dnl
+[	-r \\
+	\$(DX_CLEAN_HTML) \\
+	\$(DX_CLEAN_CHM) \\
+	\$(DX_CLEAN_CHI) \\
+	\$(DX_CLEAN_MAN) \\
+	\$(DX_CLEAN_RTF) \\
+	\$(DX_CLEAN_XML) \\
+	\$(DX_CLEAN_PS) \\
+	\$(DX_CLEAN_PDF) \\
+	\$(DX_CLEAN_LATEX)"]],
+[[DX_SNIPPET_doc=""]])
+AC_SUBST([DX_RULES],
+["${DX_SNIPPET_doc}"])dnl
+AM_SUBST_NOTMAKE([DX_RULES])
+
+#For debugging:
+#echo DX_FLAG_doc=$DX_FLAG_doc
+#echo DX_FLAG_dot=$DX_FLAG_dot
+#echo DX_FLAG_man=$DX_FLAG_man
+#echo DX_FLAG_html=$DX_FLAG_html
+#echo DX_FLAG_chm=$DX_FLAG_chm
+#echo DX_FLAG_chi=$DX_FLAG_chi
+#echo DX_FLAG_rtf=$DX_FLAG_rtf
+#echo DX_FLAG_xml=$DX_FLAG_xml
+#echo DX_FLAG_pdf=$DX_FLAG_pdf
+#echo DX_FLAG_ps=$DX_FLAG_ps
+#echo DX_ENV=$DX_ENV
+])
+
diff --git a/src/Makefile.am b/src/Makefile.am
index e534d2fb9e90e59eec33fb8330d7e59a433356d1..3be935ce07cdea375835302552035d4225db26a4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,5 @@
-# This file is part of SWIFT.
-# Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk),
-#                    Matthieu Schaller (matthieu.schaller@durham.ac.uk).
-#                    Loic Hausammann (loic.hausammann@epfl.ch)
+# This file is part of CSDS.
+# Copyright (c) 2021 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 General Public License as published by
@@ -17,48 +15,53 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 # Add the non-standard paths to the included library headers
-AM_CFLAGS = $(PYTHON_INCS) -I$(top_srcdir)/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(GRACKLE_INCS)
-
-
-AM_LDFLAGS = $(HDF5_LDFLAGS)
-
-# Assign a "safe" version number
-BIN_LDFLAGS = -version-info 0:0:0
-
-# The git command, if available.
-GIT_CMD = @GIT_CMD@
-
-# Additional dependencies for shared libraries.
-EXTRA_LIBS = $(PROFILER_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(HDF5_LIBS) $(FFTW_LIBS) $(GRACKLE_LIBS) \
-	$(VELOCIRAPTOR_LIBS) $(GSL_LIBS) -L../../src/.libs -lswiftsim
+AM_CFLAGS = $(OPENMP_CFLAGS) $(PYTHON_INCS)
+AM_LDFLAGS =
 
 # Build the libcsds library
 lib_LTLIBRARIES = libcsds.la
-GRAVITY_SRC = gravity/MultiSoftening/csds_gravity.c
+lib_LTLIBRARIES += libcsds_writer.la
 
 # List required headers
 include_HEADERS = csds_header.h csds_loader_io.h csds_particle.h csds_time.h csds_tools.h
 include_HEADERS += csds_reader.h csds_logfile.h csds_index.h quick_sort.h csds_python_tools.h
 include_HEADERS += csds_interpolation.h csds_parameters.h csds_cosmology.h csds_fields.h
-include_HEADERS += csds_hashmap.h
+include_HEADERS += csds_hashmap.h csds_error.h csds_clocks.h csds_cycle.h csds_definitions.h
+include_HEADERS += csds_parser.h csds_inline.h csds_part_type.h csds_openmp.h
+include_HEADERS += csds_logfile_writer.h csds_version.h
 
-# Common source files
+# Source files for the reader
 AM_SOURCES = csds_header.c csds_loader_io.c csds_time.c csds_tools.c csds_reader.c
 AM_SOURCES += csds_logfile.c csds_index.c quick_sort.c csds_parameters.c csds_reader_generate_index.c
-AM_SOURCES += csds_cosmology.c csds_fields.c csds_hashmap.c
+AM_SOURCES += csds_cosmology.c csds_fields.c csds_hashmap.c csds_clocks.c
+AM_SOURCES += csds_parser.c csds_part_type.c
 
 if HAVEPYTHON
 AM_SOURCES += csds_python_wrapper.c
 endif
 
+# Source files for writer
+AM_SOURCES_WRITER = csds_logfile_writer.c
 
 if HAVEPYTHON
 # The main python structure is dependent on the version, thus we need to
 # remove this one in order to be safe.
-PYTHON_EXTRA_COMPILER_FLAG = -Wno-missing-field-initializers -Wno-cast-function-type -Wno-unused-function -Wno-unused-function
+PYTHON_EXTRA_COMPILER_FLAG = -Wno-missing-field-initializers -Wno-cast-function-type -Wno-unused-function
 endif
 
+AM_CFLAGS += $(PYTHON_EXTRA_COMPILER_FLAG)
+
 # Sources and flags for regular library
 libcsds_la_SOURCES = $(AM_SOURCES)
-libcsds_la_CFLAGS = $(AM_CFLAGS) $(PYTHON_EXTRA_COMPILER_FLAG)
-libcsds_la_LDFLAGS = $(AM_LDFLAGS) $(EXTRA_LIBS) $(BIN_LDFLAGS)
+libcsds_la_CFLAGS = $(AM_CFLAGS)
+libcsds_la_LDFLAGS = $(AM_LDFLAGS)
+
+# Now for the writer
+libcsds_writer_la_SOURCES = $(AM_SOURCES_WRITER)
+libcsds_writer_la_CFLAGS = $(AM_CFLAGS)
+libcsds_writer_la_LDFLAGS = $(AM_LDFLAGS)
+
+# Generate the version file
+csds_version.h: csds_version.h.in Makefile $(AM_SOURCES_WRITER) $(AM_SOURCES) $(include_HEADERS)
+	  sed -e "s,@major_version\@,$(MAJOR_VERSION)," \
+        -e "s,@minor_version\@,$(MINOR_VERSION)," $< > csds_version.h
diff --git a/src/csds_clocks.c b/src/csds_clocks.c
new file mode 100644
index 0000000000000000000000000000000000000000..e026bf7d5df2c10385ba114509941b0b0d00d0a0
--- /dev/null
+++ b/src/csds_clocks.c
@@ -0,0 +1,318 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2021 loic.hausammann@epfl.ch
+ *               SWIFT
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+/**
+ *  @file clocks.c
+ *  @brief support for measuring intervals in milli seconds, when that
+ *  is possible, otherwise ticks.
+ *
+ *  Use cycle.h or timers.h for relative times.
+ */
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Standard headers. */
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* Local headers. */
+#include "csds_clocks.h"
+
+/* 0.25 of a second in nanoseconds. */
+#define SLEEPTIME 250000000
+
+/* The CPU frequency used to convert ticks to seconds. */
+static unsigned long long clocks_cpufreq = 0;
+
+/* Ticks when the CPU frequency was initialised, this marks the start of
+ * time. */
+ticks clocks_start_ticks = 0;
+
+/* The units of any returned times. */
+static const char *clocks_units[] = {"ms", "~ms"};
+static int clocks_units_index = 0;
+static double clocks_units_scale = 1000.0;
+
+/* Local prototypes. */
+static void clocks_estimate_cpufreq(void);
+
+/**
+ * @brief Get the current time.
+ *
+ * @param time the current time.
+ */
+void clocks_gettime(struct clocks_time *time) {
+
+#ifdef HAVE_CLOCK_GETTIME
+  clock_gettime(CLOCK_REALTIME, &time->time);
+#else
+  time->time = getticks();
+#endif
+}
+
+/**
+ * @brief Get difference in between two times.
+ *
+ * @param start the start time.
+ * @param end the end time.
+ *
+ * @return the difference.
+ */
+double clocks_diff(struct clocks_time *start, struct clocks_time *end) {
+#ifdef HAVE_CLOCK_GETTIME
+  struct timespec temp;
+  if ((end->time.tv_nsec - start->time.tv_nsec) < 0) {
+    temp.tv_sec = end->time.tv_sec - start->time.tv_sec - 1;
+    temp.tv_nsec = 1000000000 + end->time.tv_nsec - start->time.tv_nsec;
+  } else {
+    temp.tv_sec = end->time.tv_sec - start->time.tv_sec;
+    temp.tv_nsec = end->time.tv_nsec - start->time.tv_nsec;
+  }
+  return (double)temp.tv_sec * 1000.0 + (double)temp.tv_nsec * 1.0E-6;
+#else
+  return elapsed(end->time, start->time) / clocks_get_cpufreq() *
+         clocks_units_scale;
+#endif
+}
+
+/**
+ * @brief Set the CPU frequency.
+ *
+ * This function should be called at least once to set the CPU frequency.
+ * To use the builtin estimation techniques give a value of 0.
+ *
+ * @param freq the CPU frequency in Hz or 0 to estimate one.
+ */
+void clocks_set_cpufreq(unsigned long long freq) {
+  if (freq > 0) {
+    clocks_cpufreq = freq;
+  } else {
+    clocks_estimate_cpufreq();
+  }
+  clocks_start_ticks = getticks();
+}
+
+/**
+ * @brief Get the CPU frequency in Hz.
+ *
+ * @result the CPU frequency.
+ */
+unsigned long long clocks_get_cpufreq(void) {
+
+  if (clocks_cpufreq > 0) return clocks_cpufreq;
+
+  /* It not already set estimate it. */
+  clocks_estimate_cpufreq();
+  return clocks_cpufreq;
+}
+
+/**
+ * @brief Estimate the CPU frequency in Hz.
+ *
+ * If already set return the CPU frequency, then estimate the CPU frequency.
+ *
+ * The technique is either use a clock timed nanosleep (this was the best
+ * method on i7), to read the value from the cpuinfo_max_freq
+ * file (probably a overestimate) or finally just use a value of 1 with
+ * time units of ticks.
+ */
+static void clocks_estimate_cpufreq(void) {
+
+#ifdef HAVE_CLOCK_GETTIME
+  /* Try to time a nanosleep() in ticks. */
+  struct clocks_time time1;
+  struct clocks_time time2;
+
+  struct timespec sleep;
+  sleep.tv_sec = 0;
+  sleep.tv_nsec = SLEEPTIME;
+
+  clocks_gettime(&time1);
+  ticks tic = getticks();
+
+  /* Could do some calculation, but constant_tsc should protect us. */
+  nanosleep(&sleep, NULL);
+
+  clocks_gettime(&time2);
+  ticks toc = getticks();
+  double realsleep = clocks_diff(&time1, &time2);
+
+  clocks_cpufreq =
+      (signed long long)(double)(toc - tic) * 1.0 / realsleep * 1000.0;
+  clocks_units_index = 0;
+  clocks_units_scale = 1000.0;
+#endif
+
+/* Look for the system value, if available. Tends to be too large. */
+#ifdef __linux__
+  if (clocks_cpufreq == 0) {
+    FILE *file =
+        fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
+    if (file != NULL) {
+      unsigned long long maxfreq;
+      if (fscanf(file, "%llu", &maxfreq) == 1) {
+        clocks_cpufreq = maxfreq * 1000;
+        clocks_units_index = 0;
+        clocks_units_scale = 1000.0;
+      }
+      fclose(file);
+    }
+  }
+#endif
+
+  /* If all fails just report ticks for a notional 2.6GHz machine. */
+  if (clocks_cpufreq == 0) {
+    unsigned long long maxfreq = 2600000;
+    clocks_cpufreq = maxfreq * 1000;
+    clocks_units_index = 1;
+    clocks_units_scale = 1000.0;
+  }
+}
+
+/**
+ * @brief Return the difference between two ticks.
+ *
+ * Only an approximation as based on how well we have estimated the
+ * rtc frequency. Should be good for machines that support constant_rtc
+ * and clock_gettime().
+ *
+ * @param tic a number of ticks returned by the cycle.h getticks() function.
+ * @param toc a number of ticks returned by the cycle.h getticks() function.
+ *
+ * @result the difference.
+ */
+double clocks_diff_ticks(ticks tic, ticks toc) {
+  return clocks_from_ticks(tic - toc);
+}
+
+/**
+ * @brief Convert a number of ticks into milli seconds, if possible.
+ *
+ * Only an approximation as based on how well we have estimated the
+ * rtc frequency. Should be good for machines that support constant_rtc
+ * and clock_gettime(), and reasonable for most Linux machines, otherwise
+ * ticks will just be returned. See clocks_getunit() for the actual units.
+ *
+ * @param tics a number of ticks returned by the cycle.h getticks() function.
+ *
+ * @result the milli seconds, if possible.
+ */
+double clocks_from_ticks(ticks tics) {
+  return ((double)tics / (double)clocks_get_cpufreq() * clocks_units_scale);
+}
+
+/**
+ * @brief Convert a number of milli seconds into ticks, if possible.
+ *
+ * Only an approximation as based on how well we have estimated the
+ * rtc frequency. Should be good for machines that support constant_rtc
+ * and clock_gettime(), and reasonable for most Linux machines, otherwise
+ * a guess will just be returned. See clocks_getunit() for the actual units.
+ *
+ * @param ms a number of "milliseconds" to convert to ticks
+ *
+ * @result the number of ticks, if possible.
+ */
+ticks clocks_to_ticks(double ms) {
+  return (ticks)(ms * (double)clocks_get_cpufreq() / clocks_units_scale);
+}
+
+/**
+ * @brief return the time units.
+ *
+ * Normally "ms" for milliseconds, but can be "ticks" when no conversion
+ * factor is available.
+ *
+ * @result the current time units.
+ */
+const char *clocks_getunit(void) { return clocks_units[clocks_units_index]; }
+
+/**
+ * @brief returns the time since the start of the execution in seconds
+ *
+ * Need to call clocks_set_cpufreq() to mark the start of execution.
+ *
+ * The time is return in the format [sssss.s].
+ *
+ * @result the time since the start of the execution
+ */
+const char *clocks_get_timesincestart(void) {
+
+  static char buffer[40];
+
+  sprintf(buffer, "[%07.1f]",
+          clocks_diff_ticks(getticks(), clocks_start_ticks) / 1000.0);
+
+  return buffer;
+}
+
+/**
+ * Returns the wall-clock time since the start of execution in hours.
+ *
+ * Need to call clocks_set_cpufreq() to mark the start of execution.
+ *
+ * @result the time since the start of the execution
+ */
+double clocks_get_hours_since_start(void) {
+  return clocks_diff_ticks(getticks(), clocks_start_ticks) / (3600. * 1000.0);
+}
+
+/**
+ * @brief return the cpu times used.
+ *
+ * Uses the times(2) function to access the user and system cpu times and
+ * returns the sum of these for the process tree, i.e. current process plus
+ * "waited-for" children. This may be pthread implementation specific as to
+ * what that exactly means.
+ *
+ * Note cpu times are reported in sysconf(_SC_CLK_TCK) ticks, usually 100/s
+ * not our usual ticks.
+ *
+ * @param usertime the user time.
+ * @param systime the system time.
+ */
+void clocks_get_cputimes_used(double *usertime, double *systime) {
+  struct tms tmstic;
+  times(&tmstic);
+  *usertime = (tmstic.tms_utime + tmstic.tms_cutime);
+  *systime = (tmstic.tms_stime + tmstic.tms_cstime);
+}
+
+/**
+ * @brief Return an integer based on the current time.
+ *
+ * Normally this will be the remainder of the current number of nanoseconds
+ * so not very dissimilar in the most significant figures unless the time
+ * between calls is greater than INT_MAX nanoseconds. For faster calls use
+ * fewer figures, if that matters.
+ *
+ * @result an integer.
+ */
+int clocks_random_seed(void) {
+#ifdef HAVE_CLOCK_GETTIME
+  struct timespec timespec;
+  clock_gettime(CLOCK_REALTIME, &timespec);
+  return (timespec.tv_nsec % INT_MAX);
+#else
+  return (getticks() % INT_MAX);
+#endif
+}
diff --git a/src/csds_clocks.h b/src/csds_clocks.h
new file mode 100644
index 0000000000000000000000000000000000000000..b9c50e4f260a6ed5559e3b07d45f12ba5c932e6e
--- /dev/null
+++ b/src/csds_clocks.h
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2021 loic.hausammann@epfl.ch
+ *               SWIFT
+ *
+ * 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 CSDS_CLOCKS_H
+#define CSDS_CLOCKS_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* System includes. */
+#include <sys/times.h>
+
+/* Local includes */
+#include "csds_cycle.h"
+
+/* Struct to record a time for the clocks functions. */
+struct clocks_time {
+#ifdef HAVE_CLOCK_GETTIME
+  struct timespec time;
+#else
+  ticks time;
+#endif
+};
+
+/* Ticks used as the start of time. */
+extern ticks clocks_start_ticks;
+
+void clocks_gettime(struct clocks_time *time);
+double clocks_diff(struct clocks_time *start, struct clocks_time *end);
+const char *clocks_getunit(void);
+
+void clocks_set_cpufreq(unsigned long long freq);
+unsigned long long clocks_get_cpufreq(void);
+double clocks_from_ticks(ticks tics);
+ticks clocks_to_ticks(double interval);
+double clocks_diff_ticks(ticks tic, ticks toc);
+const char *clocks_get_timesincestart(void);
+double clocks_get_hours_since_start(void);
+
+void clocks_get_cputimes_used(double *usertime, double *systime);
+int clocks_random_seed(void);
+
+#endif /* CSDS_CLOCKS_H */
diff --git a/src/csds_cosmology.c b/src/csds_cosmology.c
index 6f1a4e167cc371bf3a2d502b3c6451968a27f525..c0926ace730e1b9f94bb4afa893ea8dc7a01fb12 100644
--- a/src/csds_cosmology.c
+++ b/src/csds_cosmology.c
@@ -21,11 +21,9 @@
 #include "csds_cosmology.h"
 
 /* Include CSDS */
+#include "csds_parser.h"
 #include "csds_tools.h"
 
-/* Include SWIFT */
-#include "parser.h"
-
 /**
  * @brief Compute the first time derivative of the scale factor
  *
@@ -35,7 +33,7 @@
  * @return The first derivative of the scale factor.
  */
 void csds_cosmology_init(struct csds_cosmology *cosmo,
-                         struct swift_params *params) {
+                         struct csds_params *params) {
 
   /* Read Omega_cdm */
   cosmo->Omega_cdm = parser_get_param_double(params, "Cosmology:Omega_cdm");
diff --git a/src/csds_cosmology.h b/src/csds_cosmology.h
index 7fe7be47a56dfe3f16d5c5b1b21883bc7466c953..62027d9d03635f454445e79537bd34753e960a29 100644
--- a/src/csds_cosmology.h
+++ b/src/csds_cosmology.h
@@ -25,13 +25,13 @@
 #ifndef CSDS_COSMOLOGY_H
 #define CSDS_COSMOLOGY_H
 
-/* SWIFT includes */
-#include "inline.h"
+/* local includes */
+#include "csds_inline.h"
 
 /* Some standard headers */
 #include <math.h>
 
-struct swift_params;
+struct csds_params;
 
 /**
  * @brief Structure containing the cosmological parameters.
@@ -192,5 +192,5 @@ csds_cosmology_add_factor_velocity(const struct csds_cosmology *cosmo,
 }
 
 void csds_cosmology_init(struct csds_cosmology *cosmo,
-                         struct swift_params *params);
+                         struct csds_params *params);
 #endif  // CSDS_CSDS_PARAMETERS_H
diff --git a/src/csds_cycle.h b/src/csds_cycle.h
new file mode 100644
index 0000000000000000000000000000000000000000..0ba1277893fe7be7d8b62cdcb9a8873d5709eb60
--- /dev/null
+++ b/src/csds_cycle.h
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2003, 2007-14 Matteo Frigo
+ * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* machine-dependent cycle counters code. Needs to be inlined. */
+
+/***************************************************************************/
+/* To use the cycle counters in your code, simply #include "cycle.h" (this
+   file), and then use the functions/macros:
+
+                 ticks getticks(void);
+
+   ticks is an opaque typedef defined below, representing the current time.
+   You extract the elapsed time between two calls to gettick() via:
+
+                 double elapsed(ticks t1, ticks t0);
+
+   which returns a double-precision variable in arbitrary units.  You
+   are not expected to convert this into human units like seconds; it
+   is intended only for *comparisons* of time intervals.
+
+   (In order to use some of the OS-dependent timer routines like
+   Solaris' gethrtime, you need to paste the autoconf snippet below
+   into your configure.ac file and #include "config.h" before cycle.h,
+   or define the relevant macros manually if you are not using autoconf.)
+*/
+
+/***************************************************************************/
+/* This file uses macros like HAVE_GETHRTIME that are assumed to be
+   defined according to whether the corresponding function/type/header
+   is available on your system.  The necessary macros are most
+   conveniently defined if you are using GNU autoconf, via the tests:
+
+   dnl ---------------------------------------------------------------------
+
+   AC_C_INLINE
+   AC_HEADER_TIME
+   AC_CHECK_HEADERS([sys/time.h c_asm.h intrinsics.h mach/mach_time.h])
+
+   AC_CHECK_TYPE([hrtime_t],[AC_DEFINE(HAVE_HRTIME_T, 1, [Define to 1 if
+hrtime_t is defined in <sys/time.h>])],,[#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif])
+
+   AC_CHECK_FUNCS([gethrtime read_real_time time_base_to_time clock_gettime
+mach_absolute_time])
+
+   dnl Cray UNICOS _rtc() (real-time clock) intrinsic
+   AC_MSG_CHECKING([for _rtc intrinsic])
+   rtc_ok=yes
+   AC_TRY_LINK([#ifdef HAVE_INTRINSICS_H
+#include <intrinsics.h>
+#endif], [_rtc()], [AC_DEFINE(HAVE__RTC,1,[Define if you have the UNICOS _rtc()
+intrinsic.])], [rtc_ok=no])
+   AC_MSG_RESULT($rtc_ok)
+
+   dnl ---------------------------------------------------------------------
+*/
+
+/***************************************************************************/
+
+#include <stdint.h>
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#define INLINE_ELAPSED(INL)                       \
+  static INL double elapsed(ticks t1, ticks t0) { \
+    return (double)t1 - (double)t0;               \
+  }
+
+/*----------------------------------------------------------------*/
+/* Solaris */
+#if defined(HAVE_GETHRTIME) && defined(HAVE_HRTIME_T) && \
+    !defined(HAVE_TICK_COUNTER)
+typedef hrtime_t ticks;
+
+#define getticks gethrtime
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* AIX v. 4+ routines to read the real-time clock or time-base register */
+#if defined(HAVE_READ_REAL_TIME) && defined(HAVE_TIME_BASE_TO_TIME) && \
+    !defined(HAVE_TICK_COUNTER)
+typedef timebasestruct_t ticks;
+
+static __inline ticks getticks(void) {
+  ticks t;
+  read_real_time(&t, TIMEBASE_SZ);
+  return t;
+}
+
+static __inline double elapsed(ticks t1, ticks t0) /* time in nanoseconds */
+{
+  time_base_to_time(&t1, TIMEBASE_SZ);
+  time_base_to_time(&t0, TIMEBASE_SZ);
+  return (((double)t1.tb_high - (double)t0.tb_high) * 1.0e9 +
+          ((double)t1.tb_low - (double)t0.tb_low));
+}
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * PowerPC ``cycle'' counter using the time base register.
+ */
+#if ((((defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))) || \
+       (defined(__MWERKS__) && defined(macintosh)))) ||                     \
+     (defined(__IBM_GCC_ASM) &&                                             \
+      (defined(__powerpc__) || defined(__ppc__)))) &&                       \
+    !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void) {
+  unsigned int tbl, tbu0, tbu1;
+
+  do {
+    __asm__ __volatile__("mftbu %0" : "=r"(tbu0));
+    __asm__ __volatile__("mftb %0" : "=r"(tbl));
+    __asm__ __volatile__("mftbu %0" : "=r"(tbu1));
+  } while (tbu0 != tbu1);
+
+  return (((unsigned long long)tbu0) << 32) | tbl;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* MacOS/Mach (Darwin) time-base register interface (unlike UpTime,
+   from Carbon, requires no additional libraries to be linked). */
+#if defined(HAVE_MACH_ABSOLUTE_TIME) && defined(HAVE_MACH_MACH_TIME_H) && \
+    !defined(HAVE_TICK_COUNTER)
+#include <mach/mach_time.h>
+typedef uint64_t ticks;
+#define getticks mach_absolute_time
+INLINE_ELAPSED(__inline__)
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * Pentium cycle counter
+ */
+#if (defined(__GNUC__) || defined(__ICC)) && defined(__i386__) && \
+    !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void) {
+  ticks ret;
+
+  __asm__ __volatile__("rdtsc" : "=A"(ret));
+  /* no input, nothing else clobbered */
+  return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0 /* unreliable pentium IV cycle counter */
+#endif
+
+/* Visual C++ -- thanks to Morten Nissov for his help with this */
+#if _MSC_VER >= 1200 && _M_IX86 >= 500 && !defined(HAVE_TICK_COUNTER)
+#include <windows.h>
+typedef LARGE_INTEGER ticks;
+#define RDTSC __asm __emit 0fh __asm __emit 031h /* hack for VC++ 5.0 */
+
+static __inline ticks getticks(void) {
+  ticks retval;
+
+  __asm {
+	  RDTSC
+	  mov retval.HighPart, edx
+	  mov retval.LowPart, eax
+  }
+  return retval;
+}
+
+static __inline double elapsed(ticks t1, ticks t0) {
+  return (double)t1.QuadPart - (double)t0.QuadPart;
+}
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0 /* unreliable pentium IV cycle counter */
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * X86-64 cycle counter
+ */
+#if (defined(__GNUC__) || defined(__ICC) || defined(__SUNPRO_C)) && \
+    defined(__x86_64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void) {
+  unsigned a, d;
+  __asm__ __volatile__("rdtsc" : "=a"(a), "=d"(d));
+  return ((ticks)a) | (((ticks)d) << 32);
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0
+#endif
+
+/* PGI compiler, courtesy Cristiano Calonaci, Andrea Tarsi, & Roberto Gori.
+   NOTE: this code will fail to link unless you use the -Masmkeyword compiler
+   option (grrr). */
+#if defined(__PGI) && defined(__x86_64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+static ticks getticks(void) {
+  asm(" rdtsc; shl    $0x20,%rdx; mov    %eax,%eax; or     %rdx,%rax;    ");
+}
+INLINE_ELAPSED(__inline__)
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0
+#endif
+
+/* Visual C++, courtesy of Dirk Michaelis */
+#if _MSC_VER >= 1400 && (defined(_M_AMD64) || defined(_M_X64)) && \
+    !defined(HAVE_TICK_COUNTER)
+
+#include <intrin.h>
+#pragma intrinsic(__rdtsc)
+typedef unsigned __int64 ticks;
+#define getticks __rdtsc
+INLINE_ELAPSED(__inline)
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * IA64 cycle counter
+ */
+
+/* intel's icc/ecc compiler */
+#if (defined(__EDG_VERSION) || defined(__ECC)) && defined(__ia64__) && \
+    !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+#include <ia64intrin.h>
+
+static __inline__ ticks getticks(void) { return __getReg(_IA64_REG_AR_ITC); }
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* gcc */
+#if defined(__GNUC__) && defined(__ia64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+
+static __inline__ ticks getticks(void) {
+  ticks ret;
+
+  __asm__ __volatile__("mov %0=ar.itc" : "=r"(ret));
+  return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* HP/UX IA64 compiler, courtesy Teresa L. Johnson: */
+#if defined(__hpux) && defined(__ia64) && !defined(HAVE_TICK_COUNTER)
+#include <machine/sys/inline.h>
+typedef unsigned long ticks;
+
+static inline ticks getticks(void) {
+  ticks ret;
+
+  ret = _Asm_mov_from_ar(_AREG_ITC);
+  return ret;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* Microsoft Visual C++ */
+#if defined(_MSC_VER) && defined(_M_IA64) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned __int64 ticks;
+
+#ifdef __cplusplus
+extern "C"
+#endif
+    ticks
+    __getReg(int whichReg);
+#pragma intrinsic(__getReg)
+
+static __inline ticks getticks(void) {
+  volatile ticks temp;
+  temp = __getReg(3116);
+  return temp;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * PA-RISC cycle counter
+ */
+#if (defined(__hppa__) || defined(__hppa)) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+
+#ifdef __GNUC__
+static __inline__ ticks getticks(void) {
+  ticks ret;
+
+  __asm__ __volatile__("mfctl 16, %0" : "=r"(ret));
+  /* no input, nothing else clobbered */
+  return ret;
+}
+#else
+#include <machine/inline.h>
+static inline unsigned long getticks(void) {
+  register ticks ret;
+  _MFCTL(16, ret);
+  return ret;
+}
+#endif
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* S390, courtesy of James Treacy */
+#if defined(__GNUC__) && defined(__s390__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void) {
+  ticks cycles;
+  __asm__("stck 0(%0)" : : "a"(&(cycles)) : "memory", "cc");
+  return cycles;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+/*----------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__alpha__) && !defined(HAVE_TICK_COUNTER)
+/*
+ * The 32-bit cycle counter on alpha overflows pretty quickly,
+ * unfortunately.  A 1GHz machine overflows in 4 seconds.
+ */
+typedef unsigned int ticks;
+
+static __inline__ ticks getticks(void) {
+  unsigned long cc;
+  __asm__ __volatile__("rpcc %0" : "=r"(cc));
+  return (cc & 0xFFFFFFFF);
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__sparc_v9__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+
+static __inline__ ticks getticks(void) {
+  ticks ret;
+  __asm__ __volatile__("rd %%tick, %0" : "=r"(ret));
+  return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+#if (defined(__DECC) || defined(__DECCXX)) && defined(__alpha) && \
+    defined(HAVE_C_ASM_H) && !defined(HAVE_TICK_COUNTER)
+#include <c_asm.h>
+typedef unsigned int ticks;
+
+static __inline ticks getticks(void) {
+  unsigned long cc;
+  cc = asm("rpcc %v0");
+  return (cc & 0xFFFFFFFF);
+}
+
+INLINE_ELAPSED(__inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+/*----------------------------------------------------------------*/
+/* SGI/Irix */
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE) && \
+    !defined(HAVE_TICK_COUNTER) && !defined(__ANDROID__)
+typedef struct timespec ticks;
+
+static inline ticks getticks(void) {
+  struct timespec t;
+  clock_gettime(CLOCK_SGI_CYCLE, &t);
+  return t;
+}
+
+static inline double elapsed(ticks t1, ticks t0) {
+  return ((double)t1.tv_sec - (double)t0.tv_sec) * 1.0E9 +
+         ((double)t1.tv_nsec - (double)t0.tv_nsec);
+}
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* Cray UNICOS _rtc() intrinsic function */
+#if defined(HAVE__RTC) && !defined(HAVE_TICK_COUNTER)
+#ifdef HAVE_INTRINSICS_H
+#include <intrinsics.h>
+#endif
+
+typedef long long ticks;
+
+#define getticks _rtc
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* MIPS ZBus */
+#if HAVE_MIPS_ZBUS_TIMER
+#if defined(__mips__) && !defined(HAVE_TICK_COUNTER)
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+typedef uint64_t ticks;
+
+static inline ticks getticks(void) {
+  static uint64_t* addr = 0;
+
+  if (addr == 0) {
+    uint32_t rq_addr = 0x10030000;
+    int fd;
+    int pgsize;
+
+    pgsize = getpagesize();
+    fd = open("/dev/mem", O_RDONLY | O_SYNC, 0);
+    if (fd < 0) {
+      perror("open");
+      return NULL;
+    }
+    addr = mmap(0, pgsize, PROT_READ, MAP_SHARED, fd, rq_addr);
+    close(fd);
+    if (addr == (uint64_t*)-1) {
+      perror("mmap");
+      return NULL;
+    }
+  }
+
+  return *addr;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+#endif /* HAVE_MIPS_ZBUS_TIMER */
+
+#if defined(HAVE_ARMV7A_CNTVCT)
+typedef uint64_t ticks;
+static inline ticks getticks(void) {
+  uint32_t Rt, Rt2 = 0;
+  asm volatile("mrrc p15, 1, %0, %1, c14" : "=r"(Rt), "=r"(Rt2));
+  return ((uint64_t)Rt) | (((uint64_t)Rt2) << 32);
+}
+INLINE_ELAPSED(inline)
+#define HAVE_TICK_COUNTER
+#endif
+
+#if defined(HAVE_ARMV7A_PMCCNTR)
+typedef uint64_t ticks;
+static inline ticks getticks(void) {
+  uint32_t r;
+  asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(r));
+  return r;
+}
+INLINE_ELAPSED(inline)
+#define HAVE_TICK_COUNTER
+#endif
+
+#if defined(__aarch64__) && defined(HAVE_ARMV8_CNTVCT_EL0) && \
+    !defined(HAVE_TICK_COUNTER)
+typedef uint64_t ticks;
+static inline ticks getticks(void) {
+  uint64_t Rt;
+  asm volatile("mrs %0,  CNTVCT_EL0" : "=r"(Rt));
+  return Rt;
+}
+INLINE_ELAPSED(inline)
+#define HAVE_TICK_COUNTER
+#endif
+
+#if defined(__aarch64__) && defined(HAVE_ARMV8_PMCCNTR_EL0) && \
+    !defined(HAVE_TICK_COUNTER)
+typedef uint64_t ticks;
+static inline ticks getticks(void) {
+  uint64_t cc = 0;
+  asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(cc));
+  return cc;
+}
+INLINE_ELAPSED(inline)
+#define HAVE_TICK_COUNTER
+#endif
diff --git a/src/csds_definitions.h b/src/csds_definitions.h
new file mode 100644
index 0000000000000000000000000000000000000000..aaebf954a7a12a587ffeea11febc89b83bedc03a
--- /dev/null
+++ b/src/csds_definitions.h
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * This file is part of CSDS.
+ * Copyright (c) 2021 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/>.
+ *
+ ******************************************************************************/
+/**
+ * @brief This file contains a few definitions useful for
+ * both the reader and writer.
+ */
+#ifndef CSDS_SPECIAL_FLAGS_H
+#define CSDS_SPECIAL_FLAGS_H
+
+/* WARNING THIS FILE SHOULD NOT INCLUDE CONFIG.H*/
+#include "csds_version.h"
+
+/* Size of the strings. */
+#define CSDS_STRING_SIZE 200
+#define CSDS_FORMAT_STRING "CSDS"
+
+/* Defines the special flags */
+#define SPECIAL_FLAGS_NAME "SpecialFlags"
+// The fields arrays are constructed such as the special
+// flag is always first (see csds_header.c)
+#define SPECIAL_FLAGS_INDEX 0
+#define SPECIAL_FLAGS_SIZE sizeof(uint32_t)
+#define SPECIAL_FLAGS_MASK (1 << SPECIAL_FLAGS_INDEX)
+
+/* Number of bytes for the mask information in the headers
+   (need to be large enough for the larges mask) */
+#define CSDS_HEADER_SIZE 8
+#define CSDS_MASK_SIZE 2
+/* Number of bytes for the offset size in the headers */
+#define CSDS_OFFSET_SIZE (CSDS_HEADER_SIZE - CSDS_MASK_SIZE)
+
+/** @brief type to use for the masks */
+typedef short int mask_type;
+
+/* Defines the timestamp */
+typedef long long integertime_t;
+#define TIMESTAMP_INDEX 1
+#define TIMESTAMP_MASK (1 << TIMESTAMP_INDEX)
+#define TIMESTAMP_NAME "Timestamp"
+#define TIMESTAMP_SIZE sizeof(integertime_t) + sizeof(double)
+
+/** @brief Value of the special flag */
+enum csds_special_flags {
+    csds_flag_none = 0,        /* No flag */
+    csds_flag_change_type = 1, /* Flag for a change of particle type */
+    csds_flag_mpi_enter, /* Flag for a particle received from another  MPI rank
+                          */
+    csds_flag_mpi_exit,  /* Flag for a particle sent to another MPI rank */
+    csds_flag_delete,    /* Flag for a deleted particle */
+    csds_flag_create,    /* Flag for a created particle */
+} __attribute__((packed));
+
+
+/*
+ * @brief Direction of the offsets.
+ */
+enum csds_offset_direction {
+    csds_offset_backward = 0,
+    csds_offset_forward,
+    csds_offset_corrupted,
+    /* Number of offset type. */
+    csds_offset_count,
+};
+
+#endif  // CSDS_SPECIAL_FLAGS_H
diff --git a/src/csds_error.h b/src/csds_error.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c85460431e8df8d7593a978a0f7979d03da8a27
--- /dev/null
+++ b/src/csds_error.h
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch)
+ *               SWIFT
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+/**
+ * @brief This file contains functions that help to deal with messages.
+ */
+#ifndef CSDS_ERROR_H
+#define CSDS_ERROR_H
+
+#include "../config.h"
+#include "csds_clocks.h"
+#include "csds_inline.h"
+
+#ifdef HAVE_PYTHON
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+#include <Python.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Use exit when not developing, avoids core dumps. */
+#ifdef CSDS_DEBUG_CHECKS
+#define csds_abort(errcode) abort()
+#else
+#define csds_abort(errcode) exit(errcode)
+#endif
+
+/**
+ * @brief Error macro. Prints the message given in argument and aborts.
+ *
+ */
+#define error(s, ...)                                                      \
+  ({                                                                       \
+    fflush(stdout);                                                        \
+    fprintf(stderr, "%s %s:%s():%i: " s "\n", clocks_get_timesincestart(), \
+            __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);              \
+    csds_abort(1);                                                         \
+  })
+
+/**
+ * @brief Macro to print a localized message with variable arguments.
+ *
+ */
+#define message(s, ...)                                                 \
+  ({                                                                    \
+    printf("%s %s: " s "\n", clocks_get_timesincestart(), __FUNCTION__, \
+           ##__VA_ARGS__);                                              \
+  })
+
+#ifndef HAVE_PYTHON
+#define error_python(s, ...) error(s, ##__VA_ARGS__);
+#else
+#include "frameobject.h"
+
+/**
+ * @brief Print the python trace back
+ */
+__attribute__((always_inline)) INLINE static void csds_loader_print_traceback(
+    void) {
+
+  PyGILState_STATE gstate = PyGILState_Ensure();
+
+  PyFrameObject *frame = PyEval_GetFrame();
+  int lineno = PyFrame_GetLineNumber(frame);
+  PyObject *py_filename = frame->f_code->co_filename;
+  const char *filename = PyUnicode_AsUTF8(py_filename);
+  message("File %s, line: %i", filename, lineno);
+
+  Py_DECREF(py_filename);
+  Py_DECREF(frame);
+  PyGILState_Release(gstate);
+}
+
+#define error_python(s, ...)       \
+  ({                               \
+    csds_loader_print_traceback(); \
+    error(s, ##__VA_ARGS__);       \
+  })
+#endif
+
+#endif  // CSDS_ERROR_H
diff --git a/src/csds_fields.c b/src/csds_fields.c
index 861b1a90cb3380494dfdc1caef0c3ed181eaf8a3..4813228f521690a761b627776cc49101abc3ec45 100644
--- a/src/csds_fields.c
+++ b/src/csds_fields.c
@@ -21,19 +21,19 @@
 #include "csds_fields.h"
 
 /* Task type names. */
-const char *fields_names[task_type_count] = {SPECIAL_FLAGS_NAME,
-                                             "Coordinates",
-                                             "Velocities",
-                                             "Accelerations",
-                                             "Masses",
-                                             "SmoothingLengths",
-                                             "InternalEnergies",
-                                             "Entropies",
-                                             "ParticleIDs",
-                                             "Densities",
-                                             "SPHENIXSecondaryFields",
-                                             "BirthTimes",
-                                             "GEARStarFormation",
-                                             "GEARChemistryParts",
-                                             "GEARChemistrySparts",
-                                             "None"};
+const char *fields_names[field_enum_count] = {SPECIAL_FLAGS_NAME,
+                                              "Coordinates",
+                                              "Velocities",
+                                              "Accelerations",
+                                              "Masses",
+                                              "SmoothingLengths",
+                                              "InternalEnergies",
+                                              "Entropies",
+                                              "ParticleIDs",
+                                              "Densities",
+                                              "SPHENIXSecondaryFields",
+                                              "BirthTimes",
+                                              "GEARStarFormation",
+                                              "GEARChemistryParts",
+                                              "GEARChemistrySparts",
+                                              "None"};
diff --git a/src/csds_fields.h b/src/csds_fields.h
index 43094475b4cba0abf89629e074728cfae0695f85..ff62e24fb2e2d081ee9d1547fecf795dd053debe 100644
--- a/src/csds_fields.h
+++ b/src/csds_fields.h
@@ -23,27 +23,14 @@
 #define CSDS_FIELDS_H
 
 /* Include CSDS headers */
+#include "csds_definitions.h"
 #include "csds_python_tools.h"
 #include "csds_tools.h"
 
-#define SPECIAL_FLAGS_NAME "SpecialFlags"
-// The fields arrays are constructed such as the special
-// flag is always first (see csds_header.c)
-#define SPECIAL_FLAGS_INDEX 0
-#define SPECIAL_FLAGS_SIZE sizeof(uint32_t)
-#define SPECIAL_FLAGS_MASK (1 << 0)
-
-#define TIMESTAMP_MASK (1 << 1)
-#define TIMESTAMP_NAME "Timestamp"
-#define TIMESTAMP_SIZE sizeof(integertime_t) + sizeof(double)
-
 #ifndef GEAR_CHEMISTRY_ELEMENT_COUNT
 #define GEAR_CHEMISTRY_ELEMENT_COUNT 10
 #endif
 
-/** @brief type to use for the masks */
-typedef short int mask_type;
-
 /**
  * @brief All the fields that are implemented */
 enum field_enum {
@@ -310,7 +297,7 @@ struct mask_data {
   mask_type mask;
 
   /* Name of the mask. */
-  char name[STRING_SIZE];
+  char name[CSDS_STRING_SIZE];
 };
 
 /**
diff --git a/src/csds_hashmap.c b/src/csds_hashmap.c
index 66cc61d87b651db8c340138ad6e66feca0581d74..163f88d41d665e364da4bb7e06755e22a18f5ba2 100644
--- a/src/csds_hashmap.c
+++ b/src/csds_hashmap.c
@@ -6,11 +6,9 @@
 #include <string.h>
 
 /* CSDS headers */
+#include "csds_error.h"
 #include "csds_hashmap.h"
 
-/* SWIFT headers */
-#include "error.h"
-
 /**
  * @brief returns a new hash map.
  *
@@ -166,7 +164,7 @@ void *csds_hashmap_set(struct csds_hashmap *map, struct index_data *item) {
 
   /* Create a bucket from the item */
   struct bucket *entry = map->edata;
-  entry->hash = get_hash(map, item->id);
+  entry->hash = get_hash(item->id);
   entry->dib = 1;
   memcpy(bucket_item(entry), item, sizeof(struct index_data));
 
@@ -205,7 +203,7 @@ void *csds_hashmap_set(struct csds_hashmap *map, struct index_data *item) {
  * found then NULL is returned.
  */
 struct index_data *csds_hashmap_get(struct csds_hashmap *map, id_type key) {
-  uint64_t hash = get_hash(map, key);
+  uint64_t hash = get_hash(key);
   size_t i = hash & map->mask;
   while (1) {
     struct bucket *bucket = bucket_at(map, i);
@@ -228,7 +226,7 @@ struct index_data *csds_hashmap_get(struct csds_hashmap *map, id_type key) {
  * item is not found then NULL is returned.
  */
 void *csds_hashmap_delete(struct csds_hashmap *map, id_type key) {
-  uint64_t hash = get_hash(map, key);
+  uint64_t hash = get_hash(key);
   size_t i = hash & map->mask;
   while (1) {
     struct bucket *bucket = bucket_at(map, i);
diff --git a/src/csds_hashmap.h b/src/csds_hashmap.h
index fb0dc27ee2bb6cdfdeb6411a9bb0941840793b26..b44be0822528ca2e5e2e6f6ea72afb0947f4fd13 100644
--- a/src/csds_hashmap.h
+++ b/src/csds_hashmap.h
@@ -13,8 +13,8 @@
 #include <stdint.h>
 #include <stdio.h>
 
-/* SWIFT headers */
-#include "inline.h"
+/* CSDS headers */
+#include "csds_inline.h"
 
 #define id_type int64_t
 #define hashmap_overallocation 4. / 3.
@@ -214,8 +214,7 @@ static uint64_t SIP64(const id_type *key) {
 }
 
 // hashmap_sip returns a hash value for `data` using SipHash-2-4.
-__attribute__((always_inline)) INLINE static uint64_t get_hash(
-    struct csds_hashmap *map, id_type x) {
+__attribute__((always_inline)) INLINE static uint64_t get_hash(id_type x) {
   return SIP64(&x) & ((1LU << 48) - 1);
 }
 
diff --git a/src/csds_header.c b/src/csds_header.c
index 442c33065f5e30f3b165b0fe70830a0a610c0bca..813196b7c2c38200b4450d1243a9613f7fc31503 100644
--- a/src/csds_header.c
+++ b/src/csds_header.c
@@ -40,13 +40,13 @@ const char *csds_offset_name[csds_offset_count] = {
  * @param h The #header.
  */
 void header_print(const struct header *h) {
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   message("Debug checks enabled.");
 #endif
   message("First Offset:     %lu.", h->offset_first_record);
   message("Offset direction: %s.", csds_offset_name[h->offset_direction]);
 
-  for (int type = 0; type < swift_type_count; type++) {
+  for (int type = 0; type < csds_type_count; type++) {
     message("Masks for particle type %i:", type);
     for (int k = 0; k < h->number_fields[type]; k++) {
       /* Do the field */
@@ -76,7 +76,7 @@ void header_print(const struct header *h) {
  * @param h The #header.
  */
 void header_free(struct header *h) {
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     if (h->fields[i]) {
       free(h->fields[i]);
       h->fields[i] = NULL;
@@ -96,7 +96,7 @@ void header_change_offset_direction(struct header *h,
                                     enum csds_offset_direction new_value) {
   h->offset_direction = new_value;
   /* Skip file format and version numbers. */
-  size_t offset = CSDS_VERSION_SIZE + 2 * sizeof(int);
+  size_t offset = CSDS_STRING_SIZE + 2 * sizeof(int);
 
   csds_loader_io_write_data(h->log->log.map + offset, sizeof(unsigned int),
                             &new_value);
@@ -115,9 +115,9 @@ void header_read(struct header *h, struct csds_logfile *log) {
   h->log = log;
 
   /* read the file format. */
-  char file_format[STRING_SIZE];
-  map = csds_loader_io_read_data(map, CSDS_VERSION_SIZE, &file_format);
-  if (strcmp(file_format, "SWIFT_CSDS"))
+  char file_format[CSDS_STRING_SIZE];
+  map = csds_loader_io_read_data(map, CSDS_STRING_SIZE, &file_format);
+  if (strcmp(file_format, CSDS_FORMAT_STRING))
     error_python("Wrong file format (%s).", file_format);
 
   /* Read the major version number. */
@@ -154,7 +154,7 @@ void header_read(struct header *h, struct csds_logfile *log) {
   map = csds_loader_io_read_data(map, sizeof(unsigned int), &string_length);
 
   /* Check if value defined in this file is large enough. */
-  if (STRING_SIZE < string_length) {
+  if (CSDS_STRING_SIZE < string_length) {
     error_python("Name too large in log file %i.", string_length);
   }
 
@@ -226,7 +226,7 @@ void header_read(struct header *h, struct csds_logfile *log) {
       csds_loader_io_read_data(map, sizeof(h->number_fields), h->number_fields);
 
   /* Read the order of the fields */
-  for (int type = 0; type < swift_type_count; type++) {
+  for (int type = 0; type < csds_type_count; type++) {
     if (h->number_fields[type] == 0) {
       h->fields[type] = NULL;
       continue;
@@ -292,7 +292,7 @@ size_t header_get_record_size_from_mask(const struct header *h,
   }
 
   /* Loop over each masks. */
-  for (int part_type = 0; part_type < swift_type_count; part_type++) {
+  for (int part_type = 0; part_type < csds_type_count; part_type++) {
     for (int i = 0; i < h->number_fields[part_type]; i++) {
       if (mask & h->fields[part_type][i].field.mask) {
         count += h->fields[part_type][i].field.size;
@@ -300,7 +300,7 @@ size_t header_get_record_size_from_mask(const struct header *h,
 
         /* Early exit */
         if (mask == 0) {
-          part_type = swift_type_count;
+          part_type = csds_type_count;
           break;
         }
       }
diff --git a/src/csds_header.h b/src/csds_header.h
index 0231ce3fb8265edfd91ff2ae8cad6852f6bf701e..d301c43c79b88c06b032bd8ff610d72cc3ad5a18 100644
--- a/src/csds_header.h
+++ b/src/csds_header.h
@@ -20,27 +20,12 @@
 #define CSDS_CSDS_HEADER_H
 
 #include "csds_fields.h"
+#include "csds_part_type.h"
 #include "csds_tools.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 
-/* Number of character for the version information */
-#define CSDS_VERSION_SIZE 20
-/* Number of bytes for the mask information in the headers
-   (need to be large enough for the larges mask) */
-#define CSDS_MASK_SIZE 2
-/* Number of bytes for the offset size in the headers */
-#define CSDS_OFFSET_SIZE (8 - CSDS_MASK_SIZE)
-
-enum csds_offset_direction {
-  csds_offset_backward = 0,
-  csds_offset_forward,
-  csds_offset_corrupted,
-  /* Number of offset type. */
-  csds_offset_count,
-};
-
 /**
  * @brief Names of the offset directions.
  */
@@ -76,11 +61,11 @@ struct header {
   struct csds_logfile *log;
 
   /* Number of mask per particle type */
-  int number_fields[swift_type_count];
+  int number_fields[csds_type_count];
 
   /* The fields for each particle type in the correct order.
      By construction, the special flag is the first element in each array. */
-  struct field_information *fields[swift_type_count];
+  struct field_information *fields[csds_type_count];
 };
 
 void header_print(const struct header *h);
diff --git a/src/csds_index.c b/src/csds_index.c
index dca33ccd54a1e709dcc112447e99888fb0a877a0..07bcb40a44911360d5e07061835bb2bd36217715 100644
--- a/src/csds_index.c
+++ b/src/csds_index.c
@@ -40,7 +40,7 @@
 /* The number of particle (for each type). */
 #define csds_index_npart_offset \
   csds_index_integer_time_offset + csds_index_integer_time_size
-#define csds_index_npart_size sizeof(uint64_t) * swift_type_count
+#define csds_index_npart_size sizeof(uint64_t) * csds_type_count
 /* The flag used for checking if the file is sorted or not. */
 #define csds_index_is_sorted_offset \
   csds_index_npart_offset + csds_index_npart_size
@@ -81,7 +81,7 @@ void csds_index_read_header(struct csds_index *index, const char *filename) {
 
   /* Compute the position of the history of new particles. */
   size_t count = 0;
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     count += index->nparts[i];
   }
   count *= sizeof(struct index_data);
@@ -93,7 +93,7 @@ void csds_index_read_header(struct csds_index *index, const char *filename) {
 
   /* Compute the position of the history of particles removed. */
   size_t count_new = 0;
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     count_new += index->nparts_created[i];
   }
   count_new *= sizeof(struct index_data);
@@ -159,7 +159,7 @@ struct index_data *csds_index_get_created_history(struct csds_index *index,
                                                   int type) {
 
   /* Get the position after the previous array. */
-  char *ret = (char *)csds_index_get_data(index, swift_type_count);
+  char *ret = (char *)csds_index_get_data(index, csds_type_count);
 
   /* Get the offset of particles of this type by skipping entries of lower
    * types. */
@@ -186,7 +186,7 @@ struct index_data *csds_index_get_removed_history(struct csds_index *index,
                                                   int type) {
 
   /* Get the position after the previous array. */
-  char *ret = (char *)csds_index_get_created_history(index, swift_type_count);
+  char *ret = (char *)csds_index_get_created_history(index, csds_type_count);
 
   /* Get the offset of particles of this type by skipping entries of lower
    * types. */
@@ -215,7 +215,7 @@ int csds_index_contains_time_array(struct csds_index *index) {
   const size_t file_size = index->index.mmap_size;
 
   /* Get the position after the previous array. */
-  char *ret = (char *)csds_index_get_removed_history(index, swift_type_count);
+  char *ret = (char *)csds_index_get_removed_history(index, csds_type_count);
   const size_t before_time_array = ret - index->index.map;
 
   return file_size != before_time_array;
@@ -244,7 +244,7 @@ void csds_index_map_file(struct csds_index *index, const char *filename,
     csds_loader_io_mmap_file(&index->index, filename,
                              /* read_only */ 0);
     /* Sort the file */
-    for (int i = 0; i < swift_type_count; i++) {
+    for (int i = 0; i < csds_type_count; i++) {
       if (index->nparts[i] != 0) {
         struct index_data *data = csds_index_get_data(index, i);
         quick_sort(data, index->nparts[i]);
diff --git a/src/csds_index.h b/src/csds_index.h
index 2f040c613b63fd5f00cd82879a88f902a17560cc..e9db6b8c5c50dfcaa4627e5d61c846cc8c39a592 100644
--- a/src/csds_index.h
+++ b/src/csds_index.h
@@ -51,7 +51,7 @@ struct csds_index {
   integertime_t integer_time;
 
   /* Number of particles in the file */
-  uint64_t nparts[swift_type_count];
+  uint64_t nparts[csds_type_count];
 
   /* Is the file sorted ? */
   char is_sorted;
@@ -60,10 +60,10 @@ struct csds_index {
   struct mapped_file index;
 
   /* Number of particles created. */
-  uint64_t nparts_created[swift_type_count];
+  uint64_t nparts_created[csds_type_count];
 
   /* Number of particles removed. */
-  uint64_t nparts_removed[swift_type_count];
+  uint64_t nparts_removed[csds_type_count];
 };
 
 int csds_index_contains_time_array(struct csds_index *index);
diff --git a/src/csds_inline.h b/src/csds_inline.h
new file mode 100644
index 0000000000000000000000000000000000000000..e2a41fffaf2b1b095ddf2507ae31bc4b2d7b71fa
--- /dev/null
+++ b/src/csds_inline.h
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2021 loic.hausammann@epfl.ch
+ *               SWIFT
+ *
+ * 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 CSDS_INLINE_H
+#define CSDS_INLINE_H
+
+/* WARNING THIS FILE SHOULD NOT INCLUDE CONFIG.H*/
+
+/**
+ * @brief Defines inline
+ */
+#ifndef INLINE
+#ifdef __cplusplus
+#define INLINE inline
+#else
+#if __GNUC__ && !__GNUC_STDC_INLINE__
+#define INLINE extern inline
+#else
+#define INLINE inline
+#endif
+#endif
+#endif
+
+/**
+ * @brief Defines unused
+ */
+#define ATTR_UNUSED __attribute__((unused))
+
+#endif /* CSDS_INLINE_H */
diff --git a/src/csds_interpolation.h b/src/csds_interpolation.h
index 97e94191b0b68ae43855eadcb7aa06a539222dfb..d522731d7e418209cdd4a52e6993114c250331d9 100644
--- a/src/csds_interpolation.h
+++ b/src/csds_interpolation.h
@@ -23,6 +23,20 @@
 #include "csds_parameters.h"
 #include "csds_tools.h"
 
+/**
+ * @brief Limits the value of x to be between a and b
+ *
+ * Only wraps once. If x > a + 2(b - a), the returned value will be larger than
+ * b. Similarly for x < a - (b - a), the value will be smaller than a.
+ */
+#define box_wrap(x, a, b)                                              \
+  ({                                                                   \
+    const __typeof__(x) _x = (x);                                      \
+    const __typeof__(a) _a = (a);                                      \
+    const __typeof__(b) _b = (b);                                      \
+    _x < _a ? (_x + (_b - _a)) : ((_x >= _b) ? (_x - (_b - _a)) : _x); \
+  })
+
 /**
  * @brief Compute the quintic hermite spline interpolation.
  * See https://en.wikipedia.org/wiki/Hermite_interpolation for more information.
@@ -224,7 +238,7 @@ interpolate_quintic_double_float_ND(
          otherwise something really bad happened */
       x[i] = box_wrap(x[i], 0., params->box_size[i]);
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
       /* Check if the periodic box is correctly applied */
       if (x[i] >= params->box_size[i] || x[i] < 0) {
         error_python(
@@ -255,10 +269,10 @@ interpolate_quintic_double_float_ND(
 __attribute__((always_inline)) INLINE static void interpolate_cubic_float_ND(
     const double t_before, const struct csds_reader_field *restrict before,
     const double t_after, const struct csds_reader_field *restrict after,
-    void *restrict output, const double t, const int dimension, int periodic,
-    const struct csds_parameters *params) {
+    void *restrict output, const double t, const int dimension,
+    ATTR_UNUSED int periodic, const struct csds_parameters *params) {
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   /* The position is expected to be a double => error with periodic */
   if (periodic) {
     error_python("Not implemented yet");
@@ -314,10 +328,11 @@ __attribute__((always_inline)) INLINE static void interpolate_cubic_float_ND(
 __attribute__((always_inline)) INLINE static void interpolate_linear_float_ND(
     const double t_before, const struct csds_reader_field *restrict before,
     const double t_after, const struct csds_reader_field *restrict after,
-    void *restrict output, const double t, const int dimension, int periodic,
-    const struct csds_parameters *params) {
+    void *restrict output, const double t, const int dimension,
+    ATTR_UNUSED int periodic,
+    ATTR_UNUSED const struct csds_parameters *params) {
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   /* The position is expected to be a double => error with periodic */
   if (periodic) {
     error_python("Not implemented yet");
@@ -354,10 +369,11 @@ __attribute__((always_inline)) INLINE static void interpolate_linear_float_ND(
 __attribute__((always_inline)) INLINE static void interpolate_linear_double_ND(
     const double t_before, const struct csds_reader_field *restrict before,
     const double t_after, const struct csds_reader_field *restrict after,
-    void *restrict output, const double t, const int dimension, int periodic,
-    const struct csds_parameters *params) {
+    void *restrict output, const double t, const int dimension,
+    ATTR_UNUSED int periodic,
+    ATTR_UNUSED const struct csds_parameters *params) {
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   /* The velocity and acceleration are supposed to be provided => quintic =>
    * error here */
   if (periodic) {
@@ -393,10 +409,10 @@ __attribute__((always_inline)) INLINE static void interpolate_linear_double_ND(
 __attribute__((always_inline)) INLINE static void interpolate_linear_float(
     const double t_before, const struct csds_reader_field *restrict before,
     const double t_after, const struct csds_reader_field *restrict after,
-    void *restrict output, const double t, int periodic,
-    const struct csds_parameters *params) {
+    void *restrict output, const double t, ATTR_UNUSED int periodic,
+    ATTR_UNUSED const struct csds_parameters *params) {
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   /* The position is expected to be a double => error with periodic */
   if (periodic) {
     error_python("Not implemented yet");
diff --git a/src/csds_loader_io.h b/src/csds_loader_io.h
index ca7ae26b93a29442dca3a95ccb55db619abbfb1c..e546bb59249313f272411c3a35392b52acbd1390 100644
--- a/src/csds_loader_io.h
+++ b/src/csds_loader_io.h
@@ -20,8 +20,8 @@
  * @file csds_loader_io.h
  * @brief This file contains basic IO function.
  */
-#ifndef CSDS_CSDS_LOADER_IO_H
-#define CSDS_CSDS_LOADER_IO_H
+#ifndef CSDS_LOADER_IO_H
+#define CSDS_LOADER_IO_H
 
 #include "csds_fields.h"
 #include "csds_header.h"
@@ -141,4 +141,4 @@ __attribute__((always_inline)) INLINE static char *csds_loader_io_write_data(
     }                                                                     \
   }
 
-#endif  // CSDS_CSDS_LOADER_IO_H
+#endif  // CSDS_LOADER_IO_H
diff --git a/src/csds_logfile.c b/src/csds_logfile.c
index 55c596ded5bb3b726a72536c92c9fae686490631..82f6c38335bb575f8ce0218acc153e8d21d1d15c 100644
--- a/src/csds_logfile.c
+++ b/src/csds_logfile.c
@@ -102,8 +102,9 @@ void csds_logfile_free(struct csds_logfile *log) {
  *
  * @return position after the record.
  */
-void csds_logfile_check_record_consistency(struct csds_logfile *log) {
-#ifdef SWIFT_DEBUG_CHECKS
+void csds_logfile_check_record_consistency(
+    ATTR_UNUSED struct csds_logfile *log) {
+#ifdef CSDS_DEBUG_CHECKS
   struct header *header = &log->header;
   const struct csds_reader *reader = log->reader;
 
@@ -176,7 +177,7 @@ void csds_logfile_reverse_offset(struct csds_logfile *log, char *filename) {
     error_python("The offsets are already reversed.");
   }
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   csds_logfile_check_record_consistency(log);
 #endif
 
@@ -230,7 +231,7 @@ void csds_logfile_reverse_offset(struct csds_logfile *log, char *filename) {
 
   message("WARNING: Modification done, you can now safely kill the job.");
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   csds_logfile_check_record_consistency(log);
 #endif
 
diff --git a/src/csds_logfile_writer.c b/src/csds_logfile_writer.c
new file mode 100644
index 0000000000000000000000000000000000000000..618b26864bc88c570b20c56d0f792bdf8ab0bcef
--- /dev/null
+++ b/src/csds_logfile_writer.c
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * This file is part of CSDS.
+ * Copyright (c) 2021 loic.hausammann@epfl.ch
+ *               2016 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+/* Config parameters. */
+#include "../config.h"
+
+/* This object's header. */
+#include "csds_logfile_writer.h"
+
+/* Include local headers */
+#include "csds_error.h"
+
+/* Some standard headers. */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/**
+ * @brief Provide the current size used by the CSDS in GB (not the allocated
+ * one).
+ *
+ * @param log The #csds_logfile_writer.
+ */
+float csds_logfile_writer_get_current_filesize_used_gb(
+    const struct csds_logfile_writer *log) {
+  return log->count / (1024.f * 1024.f * 1024.f);
+}
+
+/**
+ * @brief Ensure that at least size bytes are available in the
+ * #csds_logfile_writer.
+ *
+ * @param d The #csds_logfile_writer.
+ * @param required_size The required size for the #csds_logfile_writer
+ * @param increase_size If not enough size, increase by this amount
+ */
+void csds_logfile_writer_ensure(struct csds_logfile_writer *d,
+                                size_t required_size, size_t increase_size) {
+
+  /* If we have enough space already, just bail. */
+  if (d->size - d->count > required_size) return;
+
+  /* Unmap the current data. */
+  if (munmap(d->data, d->size) != 0) {
+    error("Failed to unmap %zi bytes (%s).", d->size, strerror(errno));
+  }
+
+  /* Update the size and count. */
+  const size_t trunc_count = d->count & d->page_mask;
+  d->file_offset += trunc_count;
+  d->count -= trunc_count;
+  d->size = (d->count + increase_size + ~d->page_mask) & d->page_mask;
+
+  /* Re-allocate the file size. */
+  if (posix_fallocate(d->fd, d->file_offset, d->size) != 0) {
+    error("Failed to pre-allocate the logfile.");
+  }
+
+  /* Re-map starting at the end of the file. */
+  if ((d->data = mmap(NULL, d->size, PROT_WRITE, MAP_SHARED, d->fd,
+                      d->file_offset)) == MAP_FAILED) {
+    error("Failed to allocate map of size %zi bytes (%s).", d->size,
+          strerror(errno));
+  }
+}
+
+/**
+ * @brief Flush the #csds_logfile_writer to disk.
+ */
+void csds_logfile_writer_sync(struct csds_logfile_writer *d) {
+  if (msync(d->data, d->count, MS_SYNC) != 0)
+    error("Failed to sync memory-mapped data.");
+}
+
+/**
+ * @brief Finalize the #csds_logfile_writer.
+ */
+void csds_logfile_writer_close(struct csds_logfile_writer *d) {
+  /* Unmap the data in memory. */
+  if (munmap(d->data, d->count) != 0) {
+    error("Failed to unmap the logfile (%s).", strerror(errno));
+  }
+
+  /* Truncate the file to the correct length. */
+  if (ftruncate(d->fd, d->file_offset + d->count) != 0) {
+    error("Failed to truncate the logfile (%s).", strerror(errno));
+  }
+
+  /* Close the memory-mapped file. */
+  if (close(d->fd) != 0) error("Failed to close memory-mapped file.");
+}
+
+/**
+ * @brief Initialize a file csds_logfile_writer.
+ *
+ * @param d The #csds_logfile_writer to initialize.
+ * @param filename The fully qualified name of the file in which to
+ * csds_logfile_writer, note that it will be overwritten.
+ * @param size The initial buffer size for this #csds_logfile_writer.
+ */
+void csds_logfile_writer_init(struct csds_logfile_writer *d,
+                              const char *filename, size_t size) {
+
+  /* Create the output file.
+     The option O_RDWR seems to be required by mmap.
+  */
+  if ((d->fd = open(filename, O_CREAT | O_RDWR, 0660)) == -1) {
+    error("Failed to create the logfile '%s' (%s).", filename, strerror(errno));
+  }
+
+  /* Adjust the size to be at least the page size. */
+  const size_t page_mask = ~(sysconf(_SC_PAGE_SIZE) - 1);
+  size = (size + ~page_mask) & page_mask;
+
+  /* Pre-allocate the file size. */
+  if (posix_fallocate(d->fd, 0, size) != 0) {
+    error("Failed to pre-allocate the logfile.");
+  }
+
+  /* Map memory to the created file. */
+  if ((d->data = mmap(NULL, size, PROT_WRITE, MAP_SHARED, d->fd, 0)) ==
+      MAP_FAILED) {
+    error("Failed to allocate map of size %zi bytes (%s).", size,
+          strerror(errno));
+  }
+
+  /* Init some counters. */
+  d->size = size;
+  d->count = 0;
+  d->file_offset = 0;
+  d->page_mask = page_mask;
+}
+
+/**
+ * @brief Restart a file csds_logfile_writer.
+ *
+ * @param d The #csds_logfile_writer to restart.
+ * @param filename The fully qualified name of the file in which to
+ * csds_logfile_writer, note that it will be overwritten.
+ */
+void csds_logfile_writer_restart(struct csds_logfile_writer *d,
+                                 const char *filename) {
+  /* Create the output file.
+     The option O_RDWR seems to be required by mmap.
+  */
+  if ((d->fd = open(filename, O_RDWR, 0660)) == -1) {
+    error("Failed to open the logfile '%s' (%s).", filename, strerror(errno));
+  }
+
+  /* Adjust the size to be at least the page size. */
+  const size_t page_mask = ~(sysconf(_SC_PAGE_SIZE) - 1);
+  size_t size = (d->size + ~page_mask) & page_mask;
+
+  /* Pre-allocate the file size. */
+  if (posix_fallocate(d->fd, 0, size) != 0) {
+    error("Failed to pre-allocate the logfile.");
+  }
+
+  /* Map memory to the created file. */
+  if ((d->data = mmap(NULL, size, PROT_WRITE, MAP_SHARED, d->fd,
+                      d->file_offset)) == MAP_FAILED) {
+    error("Failed to allocate map of size %zi bytes (%s).", d->size,
+          strerror(errno));
+  }
+}
+
+/**
+ * @brief Write the first part of the header.
+ * The next part should be all the informations about the
+ * masks.
+ *
+ * @param logfile The empty #csds_logfile_writer
+ *
+ * @return The buffer where to write the missing information
+ * (should not be modified and simply provided to
+ * #csds_logfile_writer_write_end_header).
+ */
+char *csds_logfile_writer_write_begining_header(
+    struct csds_logfile_writer *logfile) {
+
+  /* Check if the logfile is empty */
+  uint64_t file_offset = logfile->file_offset;
+  if (file_offset != 0)
+    error(
+        "The CSDS is not empty."
+        "This function should be called before writing anything in the CSDS");
+
+  /* Write format information. */
+  char file_format[CSDS_STRING_SIZE] = CSDS_FORMAT_STRING;
+  csds_write_data(logfile, &file_offset, CSDS_STRING_SIZE, &file_format);
+
+  /* Write the major version number. */
+  int major = CSDS_MAJOR_VERSION;
+  csds_write_data(logfile, &file_offset, sizeof(int), &major);
+
+  /* Write the minor version number. */
+  int minor = CSDS_MINOR_VERSION;
+  csds_write_data(logfile, &file_offset, sizeof(int), &minor);
+
+  /* write offset direction. */
+  const int reversed = csds_offset_backward;
+  csds_write_data(logfile, &file_offset, sizeof(int), &reversed);
+
+  /* placeholder to write the offset of the first log here. */
+  char *skip_header =
+      csds_logfile_writer_get(logfile, CSDS_OFFSET_SIZE, &file_offset);
+
+  /* write number of bytes used for names. */
+  const unsigned int label_size = CSDS_STRING_SIZE;
+  csds_write_data(logfile, &file_offset, sizeof(unsigned int), &label_size);
+
+  return skip_header;
+}
+
+/**
+ * @brief Conclude the logfile header.
+ *
+ * @param logfile The #csds_logfile_writer.
+ * @param offset The place where to write the offset
+ * to the first record (provided by
+ * #csds_logfile_writer_write_beginning_header)
+ */
+void csds_logfile_writer_write_end_header(
+    ATTR_UNUSED struct csds_logfile_writer *logfile, char *offset) {
+  /* last step: write first offset. */
+  size_t file_offset = logfile->file_offset + logfile->count;
+  memcpy(offset, &file_offset, CSDS_OFFSET_SIZE);
+}
diff --git a/src/csds_logfile_writer.h b/src/csds_logfile_writer.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c5d6fe258884972636f8c9691e3e8ddce7dee13
--- /dev/null
+++ b/src/csds_logfile_writer.h
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * This file is part of CSDS
+ * Copyright (c) 2021 loic.hausammann@epfl.ch
+ *               2016 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
+ *
+ * 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 CSDS_LOGFILE_WRITER_H
+#define CSDS_LOGFILE_WRITER_H
+
+/* WARNING THIS FILE SHOULD NOT INCLUDE CONFIG.H*/
+
+/* Include local headers */
+#include "csds_definitions.h"
+#include "csds_inline.h"
+
+/* Standard headers */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** The structure for writing the logfile. */
+struct csds_logfile_writer {
+
+  /* The memory-mapped data of this dump. */
+  void *data;
+
+  /* The size of the memory-mapped data, in bytes. */
+  size_t size;
+
+  /* The number of bytes that have been dumped. */
+  size_t count;
+
+  /* The offset of the data within the current file. */
+  size_t file_offset;
+
+  /* The file with which this memory is associated. */
+  int fd;
+
+  /* Mask containing the significant bits for page addresses. */
+  size_t page_mask;
+};
+
+/* Function prototypes. */
+void csds_logfile_writer_init(struct csds_logfile_writer *d,
+                              const char *filename, size_t size);
+void csds_logfile_writer_restart(struct csds_logfile_writer *d,
+                                 const char *filename);
+void csds_logfile_writer_ensure(struct csds_logfile_writer *d,
+                                size_t required_size, size_t increase_size);
+void csds_logfile_writer_sync(struct csds_logfile_writer *d);
+void csds_logfile_writer_close(struct csds_logfile_writer *d);
+float csds_logfile_writer_get_current_filesize_used_gb(
+    const struct csds_logfile_writer *log);
+void csds_logfile_writer_write_end_header(struct csds_logfile_writer *logfile,
+                                          char *offset);
+char *csds_logfile_writer_write_begining_header(
+    struct csds_logfile_writer *logfile);
+
+/**
+ * @brief Write the header of a record (offset + mask).
+ *
+ * This is maybe broken for big(?) endian.
+ *
+ * @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
+ */
+__attribute__((always_inline)) INLINE static char *csds_write_record_header(
+    char *buff, const unsigned int *mask, const size_t *offset,
+    const size_t offset_new) {
+  /* write mask. */
+  memcpy(buff, mask, CSDS_MASK_SIZE);
+  buff += CSDS_MASK_SIZE;
+
+  /* write offset. */
+  uint64_t diff_offset = offset_new - *offset;
+  memcpy(buff, &diff_offset, CSDS_OFFSET_SIZE);
+  buff += CSDS_OFFSET_SIZE;
+
+  return buff;
+}
+
+/**
+ * @brief Obtain a chunk of memory from a csds_logfile_writer.
+ *
+ * @param d The #csds_logfile_writer.
+ * @param count The number of bytes requested.
+ * @param offset The offset of the returned memory address within the
+ * csds_logfile_writer file.
+ * @return A pointer to the memory-mapped chunk of data.
+ */
+__attribute__((always_inline)) INLINE static void *csds_logfile_writer_get(
+    struct csds_logfile_writer *d, size_t count, size_t *offset) {
+  size_t local_offset = 0;
+
+  // Without OMP, this is strongly thread unsafe
+#pragma omp atomic capture
+  {
+    local_offset = d->count;
+    d->count += count;
+  }
+
+  if (d->count > d->size) {
+    printf("The logfile is too small.\n");
+    exit(1);
+  }
+  *offset = local_offset + d->file_offset;
+  return (char *)d->data + local_offset;
+}
+
+/**
+ * @brief Generate the data for the special flags.
+ *
+ * @param flag The special flag to use.
+ * @param flag_data The data to write in the record.
+ * @param type The type of the particle.
+ */
+INLINE static uint32_t csds_pack_flags_and_data(enum csds_special_flags flag,
+                                                int flag_data, int type) {
+  if (flag & 0xFFFFFF00) {
+    printf(
+        "The special flag in the particle CSDS cannot"
+        "be larger than 1 byte.\n");
+    exit(1);
+  }
+  if (flag_data & ~0xFFFF) {
+    printf(
+        "The data for the special flag in the particle "
+        "CSDS cannot be larger than 2 bytes.");
+    exit(1);
+  }
+  return ((uint32_t)flag << (3 * 8)) | ((flag_data & 0xFFFF) << 8) |
+         (type & 0xFF);
+}
+
+/**
+ * @brief Write to the logfile.
+ *
+ * @param d #csds_logfile_writer file
+ * @param offset (return) offset of the data
+ * @param size number of bytes to write
+ * @param p pointer to the data
+ */
+__attribute__((always_inline)) INLINE static void csds_write_data(
+    struct csds_logfile_writer *d, size_t *offset, size_t size, const void *p) {
+  /* get buffer. */
+  char *buff = csds_logfile_writer_get(d, size, offset);
+
+  /* write data to the buffer. */
+  memcpy(buff, p, size);
+
+  /* Update offset to end of record. */
+  *offset += size;
+}
+
+#endif /* CSDS_LOGFILE_WRITER_H */
diff --git a/src/csds_openmp.h b/src/csds_openmp.h
new file mode 100644
index 0000000000000000000000000000000000000000..119c4c5e19720264874553022e995513b2eb5d4d
--- /dev/null
+++ b/src/csds_openmp.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * This file is part of CSDS.
+ * Copyright (c) 2021 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/>.
+ *
+ ******************************************************************************/
+/**
+ * @brief This file contains functions related to openmp.
+ */
+#ifndef CSDS_OPENMP_H
+#define CSDS_OPENMP_H
+
+#include "../config.h"
+
+/* Include standard headers */
+#ifdef CSDS_WITH_OPENMP
+#include <omp.h>
+#endif
+
+/**
+ * @brief Wrapper for omp_get_thread_num
+ */
+__attribute__((always_inline)) INLINE static int csds_get_thread_num(void) {
+#ifdef CSDS_WITH_OPENMP
+  return omp_get_thread_num();
+#else
+  return 0;
+#endif
+}
+
+#endif  // CSDS_OPENMP_H
diff --git a/src/csds_parameters.c b/src/csds_parameters.c
index e33a680eaebfc63ce6d6bae3fbaea8923dba8fce..3ecd12cfb310cc1a0970845a7be74a0466e74f14 100644
--- a/src/csds_parameters.c
+++ b/src/csds_parameters.c
@@ -21,27 +21,22 @@
 #include "csds_parameters.h"
 
 /* Include the csds */
+#include "csds_parser.h"
 #include "csds_reader.h"
 #include "csds_tools.h"
 
-/* Include swift */
-#include "parser.h"
-
 /**
  * @brief Initialize the parameters from the yaml file.
  *
  * @param reader The #csds_reader.
  * @param params The #csds_parameters to initialize.
- * @param number_threads The number of threads for the threadpool
- * (-1 in order to use the default value).
  *
  */
 void csds_parameters_init(struct csds_parameters *params,
-                          const struct csds_reader *reader,
-                          int number_threads) {
+                          const struct csds_reader *reader) {
 
   /* Generate filename */
-  char filename[STRING_SIZE];
+  char filename[CSDS_STRING_SIZE];
   strcpy(filename, reader->basename);
   size_t len = strlen(filename);
   /* Remove the rank number */
@@ -49,50 +44,39 @@ void csds_parameters_init(struct csds_parameters *params,
   strcat(filename, ".yml");
 
   /* Initialize the parser */
-  struct swift_params swift_params;
-  parser_read_file(filename, &swift_params);
+  struct csds_params csds_params;
+  parser_read_file(filename, &csds_params);
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   /* Print the parameters */
-  if (reader->verbose > 0) parser_print_params(&swift_params);
+  if (reader->verbose > 0) parser_print_params(&csds_params);
 #endif
 
   /* Read the number of dimension */
-  params->dimension = parser_get_param_int(&swift_params, "Header:Dimension");
+  params->dimension = parser_get_param_int(&csds_params, "Header:Dimension");
 
   /* Read the box size */
-  parser_get_param_double_array(&swift_params, "Header:BoxSize", 3,
+  parser_get_param_double_array(&csds_params, "Header:BoxSize", 3,
                                 params->box_size);
 
   /* Read the periodicity */
-  params->periodic = parser_get_param_int(&swift_params, "Header:Periodic");
+  params->periodic = parser_get_param_int(&csds_params, "Header:Periodic");
 
   /* Read if we are running with cosmology */
   params->with_cosmology =
-      parser_get_param_int(&swift_params, "Policy:cosmological integration");
+      parser_get_param_int(&csds_params, "Policy:cosmological integration");
 
   /* Initialize the cosmology */
-  if (params->with_cosmology)
-    csds_cosmology_init(&params->cosmo, &swift_params);
-
-  /* Save the number of threads */
-  params->number_threads = number_threads;
-  if (reader->verbose > 0) {
-    message("Running with %i threads", params->number_threads);
-  }
+  if (params->with_cosmology) csds_cosmology_init(&params->cosmo, &csds_params);
 
   /* Read the initial number of particles. */
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     params->approximate_number_particles[i] = 0;
   }
-  params->approximate_number_particles[swift_type_gas] =
-      parser_get_param_longlong(&swift_params, "Header:NumberParts");
-  params->approximate_number_particles[swift_type_stars] =
-      parser_get_param_longlong(&swift_params, "Header:NumberSParts");
-  params->approximate_number_particles[swift_type_dark_matter] =
-      parser_get_param_longlong(&swift_params, "Header:NumberGParts");
-
-  /* Read the maximal fraction of tagged elements */
-  params->arrays_maximal_tagged_fraction = parser_get_opt_param_float(
-      &swift_params, "ReaderOptions:arrays_maximal_tagged_fraction", 0.15);
+  params->approximate_number_particles[csds_type_gas] =
+      parser_get_param_longlong(&csds_params, "Header:NumberParts");
+  params->approximate_number_particles[csds_type_stars] =
+      parser_get_param_longlong(&csds_params, "Header:NumberSParts");
+  params->approximate_number_particles[csds_type_dark_matter] =
+      parser_get_param_longlong(&csds_params, "Header:NumberGParts");
 }
diff --git a/src/csds_parameters.h b/src/csds_parameters.h
index 431fcf53d78a004b7887e38ba871915f84a44ec5..1591b48abed3a29c3df316263c8999e67bb67140 100644
--- a/src/csds_parameters.h
+++ b/src/csds_parameters.h
@@ -27,9 +27,7 @@
 
 /* Local include */
 #include "csds_cosmology.h"
-
-/* SWIFT include */
-#include "part_type.h"
+#include "csds_part_type.h"
 
 struct csds_reader;
 
@@ -50,11 +48,8 @@ struct csds_parameters {
   /* Are we doing a cosmological simulation? */
   int with_cosmology;
 
-  /* Number of threads to use in the threadpools */
-  int number_threads;
-
   /* Number of particles initially present. */
-  long long approximate_number_particles[swift_type_count];
+  long long approximate_number_particles[csds_type_count];
 
   /* Maximal fraction of tagged for removal element within an array. */
   float arrays_maximal_tagged_fraction;
@@ -64,6 +59,6 @@ struct csds_parameters {
 };
 
 void csds_parameters_init(struct csds_parameters *params,
-                          const struct csds_reader *reader, int number_threads);
+                          const struct csds_reader *reader);
 
 #endif  // CSDS_CSDS_PARAMETERS_H
diff --git a/src/csds_parser.c b/src/csds_parser.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0fcf95e6b25ba78350cfcb7d4eb64b14aab91b0
--- /dev/null
+++ b/src/csds_parser.c
@@ -0,0 +1,1051 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2021 loic.hausammann@epfl.ch
+ *               SWIFT
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+/* Needs to be included so that strtok returns char * instead of a int *. */
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* This object's header. */
+#include "csds_parser.h"
+
+/* Local headers. */
+#include "csds_error.h"
+
+#define FIELD_BUFFER_SIZE 64
+#define PARSER_COMMENT_STRING "#"
+#define PARSER_COMMENT_CHAR '#'
+#define PARSER_VALUE_CHAR ':'
+#define PARSER_VALUE_STRING ":"
+#define PARSER_START_OF_FILE "---"
+#define PARSER_END_OF_FILE "..."
+
+#define CHUNK 10
+
+/* Alias of long long needed and used only for the preprocessor definitions */
+typedef long long longlong;
+
+/* Private functions. */
+static int is_empty(const char *str);
+static int count_indentation(const char *str);
+static void parse_line(char *line, struct csds_params *params);
+static void parse_value(char *line, struct csds_params *params);
+static void parse_section_param(char *line, int *isFirstParam,
+                                char *sectionName, struct csds_params *params);
+static void find_duplicate_params(const struct csds_params *params,
+                                  const char *param_name);
+static void find_duplicate_section(const struct csds_params *params,
+                                   const char *section_name);
+static int lineNumber = 0;
+
+/**
+ * @brief trim leading white space from a string.
+ *
+ * Returns pointer to first character.
+ *
+ * @param s the string.
+ * @result the result.
+ */
+char *trim_leading(char *s) {
+  if (s == NULL || strlen(s) < 2) return s;
+  while (isspace(*s)) s++;
+  return s;
+}
+
+/**
+ * @brief trim trailing white space from a string.
+ *
+ * Modifies the string by adding a NULL to the end.
+ *
+ * @param s the string.
+ * @result the result.
+ */
+char *trim_trailing(char *s) {
+  if (s == NULL || strlen(s) < 2) return s;
+  char *end = s + strlen(s) - 1;
+  while (isspace(*end)) end--;
+  *(end + 1) = '\0';
+  return s;
+}
+
+/**
+ * @brief trim leading and trailing white space from a string.
+ *
+ * Can modify the string by adding a NULL to the end.
+ *
+ * @param s the string.
+ * @result the result.
+ */
+char *trim_both(char *s) {
+  if (s == NULL || strlen(s) < 2) return s;
+  return trim_trailing(trim_leading(s));
+}
+
+/**
+ * @brief Initialize the parser structure.
+ *
+ * @param file_name Name of file to be read
+ * @param params Structure to be populated from file
+ */
+void parser_init(const char *file_name, struct csds_params *params) {
+  params->paramCount = 0;
+  params->sectionCount = 0;
+  strcpy(params->fileName, file_name);
+}
+
+/**
+ * @brief Reads an input file and stores each parameter in a structure.
+ *
+ * @param file_name Name of file to be read
+ * @param params Structure to be populated from file
+ */
+void parser_read_file(const char *file_name, struct csds_params *params) {
+  /* Open file for reading */
+  FILE *file = fopen(file_name, "r");
+
+  /* Line to parsed. */
+  char line[PARSER_MAX_LINE_SIZE];
+
+  /* Initialise parameter count. */
+  parser_init(file_name, params);
+
+  /* Check if parameter file exits. */
+  if (file == NULL) {
+    error("Error opening parameter file: %s", file_name);
+  }
+
+  /* Read until the end of the file is reached.*/
+  while (!feof(file)) {
+    if (fgets(line, PARSER_MAX_LINE_SIZE, file) != NULL) {
+      lineNumber++;
+      parse_line(line, params);
+    }
+  }
+
+  fclose(file);
+}
+
+/**
+ * @brief Set or update a parameter using a compressed format.
+ *
+ * The compressed format allows a value to be given as a single
+ * string and has the format "section:parameter:value", with all
+ * names as would be given in the parameter file.
+ *
+ * @param params Structure that holds the parameters.
+ * @param namevalue the parameter name and value as described.
+ */
+void parser_set_param(struct csds_params *params, const char *namevalue) {
+
+  /* Get the various parts. */
+  char name[PARSER_MAX_LINE_SIZE];
+  char value[PARSER_MAX_LINE_SIZE];
+  char section[PARSER_MAX_LINE_SIZE];
+  name[0] = '\0';
+  value[0] = '\0';
+
+  /* Name is part until second colon. */
+  const char *p1 = strchr(namevalue, ':');
+  if (p1 != NULL) {
+
+    /* Section is first part until a colon. */
+    memcpy(section, namevalue, p1 - namevalue);
+    section[p1 - namevalue] = ':';
+    section[p1 - namevalue + 1] = '\0';
+
+    const char *p2 = strchr(p1 + 1, ':');
+    if (p2 != NULL) {
+      memcpy(name, namevalue, p2 - namevalue);
+      name[p2 - namevalue] = '\0';
+
+      /* Value is rest after second colon. */
+      p2++;
+      strcpy(value, p2);
+    }
+  }
+
+  /* Sanity check. */
+  if (strlen(name) == 0 || strlen(value) == 0 || strchr(value, ':') != NULL)
+    error(
+        "Cannot parse compressed parameter string: '%s', check syntax "
+        "should be section:parameter:value",
+        namevalue);
+
+  /* And update or set. */
+  int updated = 0;
+  for (int i = 0; i < params->paramCount; i++) {
+    if (strcmp(name, params->data[i].name) == 0) {
+      message("Value of '%s' changed from '%s' to '%s'", params->data[i].name,
+              params->data[i].value, value);
+      strcpy(params->data[i].value, trim_both(value));
+      updated = 1;
+    }
+  }
+  if (!updated) {
+    /* Is this a new section? */
+    int newsection = 1;
+    for (int i = 0; i < params->sectionCount; i++) {
+      if (strcmp(section, params->section[i].name) == 0) {
+        newsection = 0;
+        break;
+      }
+    }
+    if (newsection) {
+      strcpy(params->section[params->sectionCount].name, section);
+      params->sectionCount++;
+      if (params->sectionCount == PARSER_MAX_NO_OF_SECTIONS)
+        error("Too many sections, current maximum is %d.",
+              params->sectionCount);
+    }
+
+    strcpy(params->data[params->paramCount].name, name);
+    strcpy(params->data[params->paramCount].value, value);
+    params->data[params->paramCount].used = 0;
+    params->data[params->paramCount].is_default = 0;
+    params->paramCount++;
+    if (params->paramCount == PARSER_MAX_NO_OF_PARAMS)
+      error("Too many parameters, current maximum is %d.", params->paramCount);
+  }
+}
+
+/**
+ * @brief Counts the number of white spaces that prefix a string.
+ *
+ * @param str String to be checked
+ *
+ * @return Number of white spaces prefixing str
+ */
+
+static int count_indentation(const char *str) {
+  int count = 0;
+
+  /* Check if the line contains the character */
+  while (*(++str) == ' ') {
+    count++;
+  }
+  return count;
+}
+
+/**
+ * @brief Checks if a string is empty.
+ *
+ * @param str String to be checked
+ *
+ * @return Returns 1 if str is empty, 0 otherwise
+ */
+
+static int is_empty(const char *str) {
+  int retParam = 1;
+  while (*str != '\0') {
+    if (!isspace(*str)) {
+      retParam = 0;
+      break;
+    }
+    str++;
+  }
+
+  return retParam;
+}
+
+/**
+ * @brief Look for duplicate parameters.
+ *
+ * @param params Structure that holds the parameters
+ * @param param_name Name of parameter to be searched for
+ */
+
+static void find_duplicate_params(const struct csds_params *params,
+                                  const char *param_name) {
+  for (int i = 0; i < params->paramCount; i++) {
+    if (!strcmp(param_name, params->data[i].name)) {
+      error("Invalid line:%d '%s', parameter is a duplicate.", lineNumber,
+            param_name);
+    }
+  }
+}
+
+/**
+ * @brief Look for duplicate sections.
+ *
+ * @param params Structure that holds the parameters
+ * @param section_name Name of section to be searched for
+ */
+
+static void find_duplicate_section(const struct csds_params *params,
+                                   const char *section_name) {
+  for (int i = 0; i < params->sectionCount; i++) {
+    if (!strcmp(section_name, params->section[i].name)) {
+      error("Invalid line:%d '%s', section is a duplicate.", lineNumber,
+            section_name);
+    }
+  }
+}
+/**
+ * @brief Parses a line from a file and stores any parameters in a structure.
+ *
+ * @param line Line to be parsed.
+ * @param params Structure to be populated from file.
+ */
+
+static void parse_line(char *line, struct csds_params *params) {
+  /* Parse line if it doesn't begin with a comment. */
+  if (line[0] != PARSER_COMMENT_CHAR) {
+    char trim_line[PARSER_MAX_LINE_SIZE];
+    char tmp_str[PARSER_MAX_LINE_SIZE];
+    char *token;
+
+    /* Remove comments at the end of a line. */
+    token = strtok(line, PARSER_COMMENT_STRING);
+    strcpy(tmp_str, token);
+
+    /* Check if the line is just white space. */
+    if (!is_empty(tmp_str)) {
+      /* Trim '\n' characters from string. */
+      token = strtok(tmp_str, "\n");
+      strcpy(trim_line, token);
+
+      /* Check if the line contains a value and parse it. */
+      if (strchr(trim_line, PARSER_VALUE_CHAR)) {
+
+        /* Trim trailing space before parsing line for a value. */
+        char no_space_line[PARSER_MAX_LINE_SIZE];
+        strcpy(no_space_line, trim_trailing(trim_line));
+
+        parse_value(no_space_line, params);
+      }
+      /* Check for invalid lines,not including the start and end of file. */
+      else if (strcmp(trim_line, PARSER_START_OF_FILE) &&
+               strcmp(trim_line, PARSER_END_OF_FILE)) {
+        error("Invalid line:%d '%s'.", lineNumber, trim_line);
+      }
+    }
+  }
+}
+
+/**
+ * @brief Performs error checking and stores a parameter in a structure.
+ *
+ * @param line Line containing the parameter
+ * @param params Structure to be written to
+ *
+ */
+
+static void parse_value(char *line, struct csds_params *params) {
+  static int inSection = 0;
+  static char section[PARSER_MAX_LINE_SIZE]; /* Keeps track of current section
+                                                name. */
+  static int isFirstParam = 1;
+  char tmpStr[PARSER_MAX_LINE_SIZE];
+  char tmpSectionName[PARSER_MAX_LINE_SIZE];
+
+  char *token;
+
+  /* Check that standalone parameters have correct indentation. */
+  if (!inSection && line[0] == ' ') {
+    error(
+        "Invalid line:%d '%s', standalone parameter defined with incorrect "
+        "indentation.",
+        lineNumber, line);
+  }
+
+  /* Check that it is a parameter inside a section.*/
+  if (line[0] == ' ' || line[0] == '\t') {
+    parse_section_param(line, &isFirstParam, section, params);
+  } else {
+    /* It is the start of a new section or standalone parameter.
+     * Take first token as the parameter name. */
+    token = strtok(line, ":\t");
+    strcpy(tmpStr, trim_trailing(token));
+
+    /* Take second token as the parameter value. */
+    token = trim_both(strtok(NULL, "#\n"));
+
+    /* If second token is NULL or empty then the line must be a section
+     * heading. */
+    if (token == NULL || strlen(token) == 0) {
+      strcpy(tmpSectionName, tmpStr);
+      strcat(tmpSectionName, PARSER_VALUE_STRING);
+
+      /* Check for duplicate section name. */
+      find_duplicate_section(params, tmpSectionName);
+
+      /* Check for duplicate standalone parameter name used as a section name.
+       */
+      find_duplicate_params(params, tmpStr);
+
+      strcpy(section, tmpSectionName);
+      strcpy(params->section[params->sectionCount].name, tmpSectionName);
+      if (params->sectionCount == PARSER_MAX_NO_OF_SECTIONS - 1) {
+        error(
+            "Maximal number of sections in parameter file reached. Aborting !");
+      } else {
+        params->sectionCount++;
+      }
+      inSection = 1;
+      isFirstParam = 1;
+    } else {
+      /* Create string with standalone parameter name appended with ":" to aid
+       * duplicate search as section names are stored with ":" at the end.*/
+      strcpy(tmpSectionName, tmpStr);
+      strcat(tmpSectionName, PARSER_VALUE_STRING);
+
+      /* Check for duplicate parameter name. */
+      find_duplicate_params(params, tmpStr);
+
+      /* Check for duplicate section name used as standalone parameter name. */
+      find_duplicate_section(params, tmpSectionName);
+
+      /* Must be a standalone parameter so no need to prefix name with a
+       * section. */
+      strcpy(params->data[params->paramCount].name, tmpStr);
+      strcpy(params->data[params->paramCount].value, token);
+      params->data[params->paramCount].used = 0;
+      params->data[params->paramCount].is_default = 0;
+      if (params->paramCount == PARSER_MAX_NO_OF_PARAMS - 1) {
+        error(
+            "Maximal number of parameters in parameter file reached. Aborting "
+            "!");
+      } else {
+        params->paramCount++;
+      }
+      inSection = 0;
+      isFirstParam = 1;
+    }
+  }
+}
+
+/**
+ * @brief Parses a parameter that appears in a section and stores it in a
+ *structure.
+ *
+ * @param line Line containing the parameter
+ * @param isFirstParam Shows if the first parameter of a section has been found
+ * @param sectionName String containing the current section name
+ * @param params Structure to be written to
+ *
+ */
+
+static void parse_section_param(char *line, int *isFirstParam,
+                                char *sectionName, struct csds_params *params) {
+  static int sectionIndent = 0;
+  char tmpStr[PARSER_MAX_LINE_SIZE];
+  char paramName[PARSER_MAX_LINE_SIZE];
+  char *token;
+
+  /* Count indentation of each parameter and check that it
+   * is consistent with the first parameter in the section. */
+  if (*isFirstParam) {
+    sectionIndent = count_indentation(line);
+    *isFirstParam = 0;
+  } else if (count_indentation(line) != sectionIndent) {
+    error("Invalid line:%d '%s', parameter has incorrect indentation.",
+          lineNumber, line);
+  }
+
+  /* Take first token as the parameter name and trim leading white space. */
+  token = trim_both(strtok(line, ":\t"));
+  strcpy(tmpStr, token);
+
+  /* Take second token as the parameter value. */
+  token = trim_both(strtok(NULL, "#\n"));
+
+  /* Prefix the parameter name with its section name and
+   * copy it into the parameter structure. */
+  strcpy(paramName, sectionName);
+  strcat(paramName, tmpStr);
+
+  /* Check for duplicate parameter name. */
+  find_duplicate_params(params, paramName);
+
+  strcpy(params->data[params->paramCount].name, paramName);
+  strcpy(params->data[params->paramCount].value, token);
+  params->data[params->paramCount].used = 0;
+  params->data[params->paramCount].is_default = 0;
+  if (params->paramCount == PARSER_MAX_NO_OF_PARAMS - 1) {
+    error("Maximal number of parameters in parameter file reached. Aborting !");
+  } else {
+    params->paramCount++;
+  }
+}
+
+// Retrieve parameter value from structure. TYPE is the data type, float, int
+// etc. FMT the format required for that data type, i.e. %f, %d etc. and DESC
+// a one word description of the type, "float", "int" etc.
+#define PARSER_GET_VALUE(TYPE, FMT, DESC)                                      \
+  static int get_param_##TYPE(struct csds_params *params, const char *name,    \
+                              TYPE *def, TYPE *result) {                       \
+    char str[PARSER_MAX_LINE_SIZE];                                            \
+    for (int i = 0; i < params->paramCount; i++) {                             \
+      if (strcmp(name, params->data[i].name) == 0) {                           \
+        /* Check that exactly one number is parsed, capture junk. */           \
+        if (sscanf(params->data[i].value, " " FMT "%s ", result, str) != 1) {  \
+          error("Tried parsing " DESC                                          \
+                " '%s' but found '%s' with "                                   \
+                "illegal trailing characters '%s'.",                           \
+                params->data[i].name, params->data[i].value, str);             \
+        }                                                                      \
+        /* Ensure same behavior if called multiple times for same parameter */ \
+        if (params->data[i].is_default && def == NULL)                         \
+          error(                                                               \
+              "Tried parsing %s again but cannot parse a default "             \
+              "parameter as mandatory",                                        \
+              name);                                                           \
+        if (params->data[i].is_default && *def != *result)                     \
+          error(                                                               \
+              "Tried parsing %s again but cannot parse a parameter with "      \
+              "two different default value (" FMT "!=" FMT ")",                \
+              name, *def, *result);                                            \
+        /* This parameter has been used */                                     \
+        params->data[i].used = 1;                                              \
+        return 1;                                                              \
+      }                                                                        \
+    }                                                                          \
+    if (def == NULL)                                                           \
+      error("Cannot find '%s' in the structure, in file '%s'.", name,          \
+            params->fileName);                                                 \
+    return 0;                                                                  \
+  }
+
+// Set a parameter to a value and save for dumping.
+#define PARSER_SAVE_VALUE(PREFIX, TYPE, FMT)                      \
+  static void save_param_##PREFIX(struct csds_params *params,     \
+                                  const char *name, TYPE value) { \
+    char str[PARSER_MAX_LINE_SIZE];                               \
+    sprintf(str, "%s:" FMT, name, value);                         \
+    parser_set_param(params, str);                                \
+    params->data[params->paramCount - 1].used = 1;                \
+    params->data[params->paramCount - 1].is_default = 0;          \
+  }
+
+/* Instantiations. */
+PARSER_GET_VALUE(char, "%c", "char");
+PARSER_GET_VALUE(int, "%d", "int");
+PARSER_GET_VALUE(float, "%f", "float");
+PARSER_GET_VALUE(double, "%lf", "double");
+PARSER_GET_VALUE(longlong, "%lld", "long long");
+PARSER_SAVE_VALUE(char, char, "%c");
+PARSER_SAVE_VALUE(int, int, "%d");
+PARSER_SAVE_VALUE(float, float, "%g");
+PARSER_SAVE_VALUE(double, double, "%g");
+PARSER_SAVE_VALUE(longlong, longlong, "%lld");
+PARSER_SAVE_VALUE(string, const char *, "%s");
+
+/**
+ * @brief Retrieve integer parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @return Value of the parameter found
+ */
+int parser_get_param_int(struct csds_params *params, const char *name) {
+  int result = 0;
+  get_param_int(params, name, NULL, &result);
+  return result;
+}
+
+/**
+ * @brief Retrieve char parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @return Value of the parameter found
+ */
+char parser_get_param_char(struct csds_params *params, const char *name) {
+  char result = 0;
+  get_param_char(params, name, NULL, &result);
+  return result;
+}
+
+/**
+ * @brief Retrieve float parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @return Value of the parameter found
+ */
+float parser_get_param_float(struct csds_params *params, const char *name) {
+  float result = 0;
+  get_param_float(params, name, NULL, &result);
+  return result;
+}
+
+/**
+ * @brief Retrieve double parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @return Value of the parameter found
+ */
+double parser_get_param_double(struct csds_params *params, const char *name) {
+  double result = 0;
+  get_param_double(params, name, NULL, &result);
+  return result;
+}
+
+/**
+ * @brief Retrieve long long parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @return Value of the parameter found
+ */
+long long parser_get_param_longlong(struct csds_params *params,
+                                    const char *name) {
+  long long result = 0;
+  get_param_longlong(params, name, NULL, &result);
+  return result;
+}
+
+/**
+ * @brief Retrieve string parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param retParam (return) Value of the parameter found
+ */
+void parser_get_param_string(struct csds_params *params, const char *name,
+                             char *retParam) {
+
+  for (int i = 0; i < params->paramCount; i++) {
+    if (!strcmp(name, params->data[i].name)) {
+      if (params->data[i].is_default)
+        error(
+            "Tried parsing %s again but cannot parse a "
+            "default parameter as mandatory",
+            name);
+      strcpy(retParam, params->data[i].value);
+      /* this parameter has been used */
+      params->data[i].used = 1;
+      return;
+    }
+  }
+
+  error("Cannot find '%s' in the structure.", name);
+}
+
+/**
+ * @brief Retrieve optional integer parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param def Default value of the parameter of not found.
+ * @return Value of the parameter found
+ */
+int parser_get_opt_param_int(struct csds_params *params, const char *name,
+                             int def) {
+  int result = 0;
+  if (get_param_int(params, name, &def, &result)) return result;
+  save_param_int(params, name, def);
+  params->data[params->paramCount - 1].is_default = 1;
+  return def;
+}
+
+/**
+ * @brief Retrieve optional char parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param def Default value of the parameter of not found.
+ * @return Value of the parameter found
+ */
+char parser_get_opt_param_char(struct csds_params *params, const char *name,
+                               char def) {
+  char result = 0;
+  if (get_param_char(params, name, &def, &result)) return result;
+  save_param_char(params, name, def);
+  params->data[params->paramCount - 1].is_default = 1;
+  return def;
+}
+
+/**
+ * @brief Retrieve optional float parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param def Default value of the parameter of not found.
+ * @return Value of the parameter found
+ */
+float parser_get_opt_param_float(struct csds_params *params, const char *name,
+                                 float def) {
+  float result = 0;
+  if (get_param_float(params, name, &def, &result)) return result;
+  save_param_float(params, name, def);
+  params->data[params->paramCount - 1].is_default = 1;
+  return def;
+}
+
+/**
+ * @brief Retrieve optional double parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param def Default value of the parameter of not found.
+ * @return Value of the parameter found
+ */
+double parser_get_opt_param_double(struct csds_params *params, const char *name,
+                                   double def) {
+  double result = 0;
+  if (get_param_double(params, name, &def, &result)) return result;
+  save_param_double(params, name, def);
+  params->data[params->paramCount - 1].is_default = 1;
+  return def;
+}
+
+/**
+ * @brief Retrieve optional long long parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param def Default value of the parameter of not found.
+ * @return Value of the parameter found
+ */
+long long parser_get_opt_param_longlong(struct csds_params *params,
+                                        const char *name, long long def) {
+  long long result = 0;
+  if (get_param_longlong(params, name, &def, &result)) return result;
+  save_param_longlong(params, name, def);
+  params->data[params->paramCount - 1].is_default = 1;
+  return def;
+}
+
+/**
+ * @brief Retrieve string parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param def Default value of the parameter of not found.
+ * @param retParam (return) Value of the parameter found
+ */
+void parser_get_opt_param_string(struct csds_params *params, const char *name,
+                                 char *retParam, const char *def) {
+
+  for (int i = 0; i < params->paramCount; i++) {
+    if (!strcmp(name, params->data[i].name)) {
+      strcpy(retParam, params->data[i].value);
+
+      /* Ensure same behavior if called multiple times for same parameter */
+      if (params->data[i].is_default && strcmp(def, retParam) != 0)
+        error(
+            "Tried parsing %s again but cannot parse a parameter with "
+            "two different default values ('%s' != '%s')",
+            name, def, retParam);
+      /* this parameter has been used */
+      params->data[i].used = 1;
+      return;
+    }
+  }
+  save_param_string(params, name, def);
+  params->data[params->paramCount - 1].is_default = 1;
+  strcpy(retParam, def);
+}
+
+/* Macro defining functions that get primitive types as simple one-line YAML
+ * arrays, that is SEC: [v1,v2,v3...] format, with the extension that the []
+ * are optional. TYPE is the data type, float etc. FMT a format to parse a
+ * single value, so "%f" for a float and DESC the type description
+ * i.e. "float".
+ */
+#define PARSER_GET_ARRAY(TYPE, FMT, DESC)                             \
+  static int get_param_##TYPE##_array(struct csds_params *params,     \
+                                      const char *name, int required, \
+                                      int nval, TYPE *values) {       \
+    char str[PARSER_MAX_LINE_SIZE];                                   \
+    char cpy[PARSER_MAX_LINE_SIZE];                                   \
+                                                                      \
+    for (int i = 0; i < params->paramCount; i++) {                    \
+      if (!strcmp(name, params->data[i].name)) {                      \
+        if (params->data[i].is_default && required)                   \
+          error(                                                      \
+              "Tried parsing %s again but cannot parse a default "    \
+              "parameter as mandatory",                               \
+              name);                                                  \
+        char *cp = cpy;                                               \
+        strcpy(cp, params->data[i].value);                            \
+        cp = trim_both(cp);                                           \
+                                                                      \
+        /* Strip off [], if present. */                               \
+        if (cp[0] == '[') cp++;                                       \
+        int l = strlen(cp);                                           \
+        if (cp[l - 1] == ']') cp[l - 1] = '\0';                       \
+        cp = trim_both(cp);                                           \
+                                                                      \
+        /* Format that captures spaces and trailing junk. */          \
+        char fmt[20];                                                 \
+        sprintf(fmt, " %s%%s ", FMT);                                 \
+                                                                      \
+        /* Parse out values which should now be "v, v, v" with        \
+         * internal     whitespace variations. */                     \
+        char *p = strtok(cp, ",");                                    \
+        for (int k = 0; k < nval; k++) {                              \
+          if (p != NULL) {                                            \
+            TYPE tmp_value;                                           \
+            if (sscanf(p, fmt, &tmp_value, str) != 1) {               \
+              error("Tried parsing " DESC                             \
+                    " '%s' but found '%s' with "                      \
+                    "illegal " DESC " characters '%s'.",              \
+                    name, p, str);                                    \
+            }                                                         \
+            if (params->data[i].is_default && tmp_value != values[k]) \
+              error(                                                  \
+                  "Tried parsing %s again but cannot parse a "        \
+                  "parameter with two different default value "       \
+                  "(" FMT "!=" FMT ")",                               \
+                  name, tmp_value, values[k]);                        \
+            values[k] = tmp_value;                                    \
+          } else {                                                    \
+            error(                                                    \
+                "Array '%s' with value '%s' has too few values, "     \
+                "expected %d",                                        \
+                name, params->data[i].value, nval);                   \
+          }                                                           \
+          if (k < nval - 1) p = strtok(NULL, ",");                    \
+        }                                                             \
+        params->data[i].used = 1;                                     \
+        return 1;                                                     \
+      }                                                               \
+    }                                                                 \
+    if (required)                                                     \
+      error("Cannot find '%s' in the structure, in file '%s'.", name, \
+            params->fileName);                                        \
+    return 0;                                                         \
+  }
+
+// Set values of a default parameter so they will be saved correctly.
+#define PARSER_SAVE_ARRAY(TYPE, FMT)                                          \
+  static int save_param_##TYPE##_array(                                       \
+      struct csds_params *params, const char *name, int nval, TYPE *values) { \
+    /* Save values against the parameter. */                                  \
+    char str[PARSER_MAX_LINE_SIZE];                                           \
+    int k = sprintf(str, "%s: [", name);                                      \
+    for (int i = 0; i < nval - 1; i++)                                        \
+      k += sprintf(&str[k], FMT ", ", values[i]);                             \
+    sprintf(&str[k], FMT "]", values[nval - 1]);                              \
+    parser_set_param(params, str);                                            \
+    params->data[params->paramCount - 1].used = 1;                            \
+    params->data[params->paramCount - 1].is_default = 0;                      \
+    return 0;                                                                 \
+  }
+
+/* Instantiations. */
+PARSER_GET_ARRAY(char, "%c", "char");
+PARSER_GET_ARRAY(int, "%d", "int");
+PARSER_GET_ARRAY(float, "%f", "float");
+PARSER_GET_ARRAY(double, "%lf", "double");
+PARSER_GET_ARRAY(longlong, "%lld", "long long");
+PARSER_SAVE_ARRAY(char, "%c");
+PARSER_SAVE_ARRAY(int, "%d");
+PARSER_SAVE_ARRAY(float, "%g");
+PARSER_SAVE_ARRAY(double, "%g");
+PARSER_SAVE_ARRAY(longlong, "%lld");
+
+/**
+ * @brief Retrieve char array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals.
+ */
+void parser_get_param_char_array(struct csds_params *params, const char *name,
+                                 int nval, char *values) {
+  get_param_char_array(params, name, 1, nval, values);
+}
+
+/**
+ * @brief Retrieve optional char array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals. If the
+ *               parameter is not found these values will be returned
+ *               unmodified, so should be set to the default values.
+ * @return whether the parameter has been found.
+ */
+int parser_get_opt_param_char_array(struct csds_params *params,
+                                    const char *name, int nval, char *values) {
+  if (get_param_char_array(params, name, 0, nval, values) != 1) {
+    save_param_char_array(params, name, nval, values);
+    params->data[params->paramCount - 1].is_default = 1;
+    return 0;
+  }
+  return 1;
+}
+
+/**
+ * @brief Retrieve int array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals.
+ */
+void parser_get_param_int_array(struct csds_params *params, const char *name,
+                                int nval, int *values) {
+  get_param_int_array(params, name, 1, nval, values);
+}
+
+/**
+ * @brief Retrieve optional int array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals. If the
+ *               parameter is not found these values will be returned
+ *               unmodified, so should be set to the default values.
+ * @return whether the parameter has been found.
+ */
+int parser_get_opt_param_int_array(struct csds_params *params, const char *name,
+                                   int nval, int *values) {
+  if (get_param_int_array(params, name, 0, nval, values) != 1) {
+    save_param_int_array(params, name, nval, values);
+    params->data[params->paramCount - 1].is_default = 1;
+    return 0;
+  }
+  return 1;
+}
+
+/**
+ * @brief Retrieve float array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals.
+ */
+void parser_get_param_float_array(struct csds_params *params, const char *name,
+                                  int nval, float *values) {
+  get_param_float_array(params, name, 1, nval, values);
+}
+
+/**
+ * @brief Retrieve optional float array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals. If the
+ *               parameter is not found these values will be returned
+ *               unmodified, so should be set to the default values.
+ * @return whether the parameter has been found.
+ */
+int parser_get_opt_param_float_array(struct csds_params *params,
+                                     const char *name, int nval,
+                                     float *values) {
+  if (get_param_float_array(params, name, 0, nval, values) != 1) {
+    save_param_float_array(params, name, nval, values);
+    params->data[params->paramCount - 1].is_default = 1;
+    return 0;
+  }
+  return 1;
+}
+
+/**
+ * @brief Retrieve double array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals.
+ */
+void parser_get_param_double_array(struct csds_params *params, const char *name,
+                                   int nval, double *values) {
+  get_param_double_array(params, name, 1, nval, values);
+}
+
+/**
+ * @brief Retrieve optional double array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals. If the
+ *               parameter is not found these values will be returned
+ *               unmodified, so should be set to the default values.
+ * @return whether the parameter has been found.
+ */
+int parser_get_opt_param_double_array(struct csds_params *params,
+                                      const char *name, int nval,
+                                      double *values) {
+  if (get_param_double_array(params, name, 0, nval, values) != 1) {
+    save_param_double_array(params, name, nval, values);
+    params->data[params->paramCount - 1].is_default = 1;
+    return 0;
+  }
+  return 1;
+}
+
+/**
+ * @brief Retrieve long long array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals.
+ */
+void parser_get_param_longlong_array(struct csds_params *params,
+                                     const char *name, int nval,
+                                     long long *values) {
+  get_param_longlong_array(params, name, 1, nval, values);
+}
+
+/**
+ * @brief Retrieve optional long long array parameter from structure.
+ *
+ * @param params Structure that holds the parameters
+ * @param name Name of the parameter to be found
+ * @param nval number of values expected.
+ * @param values Values of the parameter found, of size at least nvals. If the
+ *               parameter is not found these values will be returned
+ *               unmodified, so should be set to the default values.
+ * @return whether the parameter has been found.
+ */
+int parser_get_opt_param_longlong_array(struct csds_params *params,
+                                        const char *name, int nval,
+                                        long long *values) {
+  if (get_param_longlong_array(params, name, 0, nval, values) != 1) {
+    save_param_longlong_array(params, name, nval, values);
+    params->data[params->paramCount - 1].is_default = 1;
+    return 0;
+  }
+  return 1;
+}
+
+/**
+ * @brief Prints the contents of the parameter structure.
+ *
+ * @param params Structure that holds the parameters
+ */
+void parser_print_params(const struct csds_params *params) {
+  printf("\n--------------------------\n");
+  printf("|   CSDS Parameter File  |\n");
+  printf("--------------------------\n");
+
+  for (int i = 0; i < params->paramCount; i++) {
+    printf("Parameter name: %s\n", params->data[i].name);
+    printf("Parameter value: %s\n", params->data[i].value);
+    printf("Parameter used: %i\n", params->data[i].used);
+  }
+}
diff --git a/src/csds_parser.h b/src/csds_parser.h
new file mode 100644
index 0000000000000000000000000000000000000000..f1eb42bd5666d6e072e3868292169ce4037048ed
--- /dev/null
+++ b/src/csds_parser.h
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2021 loic.hausammann@epfl.ch
+ *               SWIFT
+ *
+ * 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 CSDS_PARSER_H
+#define CSDS_PARSER_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Standard headers */
+#include <stdio.h>
+
+#if defined(HAVE_HDF5)
+#include <hdf5.h>
+#endif
+
+/* Some constants. */
+#define PARSER_MAX_LINE_SIZE 256
+#define PARSER_MAX_NO_OF_PARAMS 600
+#define PARSER_MAX_NO_OF_SECTIONS 64
+
+/* A parameter in the input file */
+struct parameter {
+  char name[PARSER_MAX_LINE_SIZE];
+  char value[PARSER_MAX_LINE_SIZE];
+  int used;
+  int is_default;
+};
+
+struct section {
+  char name[PARSER_MAX_LINE_SIZE];
+};
+
+/* The array of parameters read from a file */
+struct csds_params {
+  struct section section[PARSER_MAX_NO_OF_SECTIONS];
+  struct parameter data[PARSER_MAX_NO_OF_PARAMS];
+  int sectionCount;
+  int paramCount;
+  char fileName[PARSER_MAX_LINE_SIZE];
+};
+
+/* Public API. */
+void parser_init(const char *file_name, struct csds_params *params);
+void parser_read_file(const char *file_name, struct csds_params *params);
+void parser_print_params(const struct csds_params *params);
+void parser_set_param(struct csds_params *params, const char *desc);
+
+char parser_get_param_char(struct csds_params *params, const char *name);
+int parser_get_param_int(struct csds_params *params, const char *name);
+float parser_get_param_float(struct csds_params *params, const char *name);
+double parser_get_param_double(struct csds_params *params, const char *name);
+long long parser_get_param_longlong(struct csds_params *params,
+                                    const char *name);
+void parser_get_param_string(struct csds_params *params, const char *name,
+                             char *retParam);
+
+char parser_get_opt_param_char(struct csds_params *params, const char *name,
+                               char def);
+int parser_get_opt_param_int(struct csds_params *params, const char *name,
+                             int def);
+float parser_get_opt_param_float(struct csds_params *params, const char *name,
+                                 float def);
+double parser_get_opt_param_double(struct csds_params *params, const char *name,
+                                   double def);
+long long parser_get_opt_param_longlong(struct csds_params *params,
+                                        const char *name, long long def);
+void parser_get_opt_param_string(struct csds_params *params, const char *name,
+                                 char *retParam, const char *def);
+void parser_get_param_char_array(struct csds_params *params, const char *name,
+                                 int nval, char *values);
+void parser_get_param_int_array(struct csds_params *params, const char *name,
+                                int nval, int *values);
+void parser_get_param_float_array(struct csds_params *params, const char *name,
+                                  int nval, float *values);
+void parser_get_param_double_array(struct csds_params *params, const char *name,
+                                   int nval, double *values);
+void parser_get_param_longlong_array(struct csds_params *params,
+                                     const char *name, int nval,
+                                     long long *values);
+int parser_get_opt_param_char_array(struct csds_params *params,
+                                    const char *name, int nval, char *values);
+int parser_get_opt_param_int_array(struct csds_params *params, const char *name,
+                                   int nval, int *values);
+int parser_get_opt_param_float_array(struct csds_params *params,
+                                     const char *name, int nval, float *values);
+int parser_get_opt_param_double_array(struct csds_params *params,
+                                      const char *name, int nval,
+                                      double *values);
+int parser_get_opt_param_longlong_array(struct csds_params *params,
+                                        const char *name, int nval,
+                                        long long *values);
+
+#endif /* CSDS_PARSER_H */
diff --git a/src/csds_part_type.c b/src/csds_part_type.c
new file mode 100644
index 0000000000000000000000000000000000000000..8d7c770bf43a48f72888bcd8c3271019f31f4c87
--- /dev/null
+++ b/src/csds_part_type.c
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2021 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/>.
+ *
+ ******************************************************************************/
+
+/* This object's header. */
+#include "csds_part_type.h"
+
+const char* part_type_names[csds_type_count] = {
+    "Gas", "DM", "DMBackground", "Sink", "Stars", "BH", "Neutrino"};
diff --git a/src/csds_part_type.h b/src/csds_part_type.h
new file mode 100644
index 0000000000000000000000000000000000000000..e9a3572d0c97b43cae6307fd355c0c47647d8217
--- /dev/null
+++ b/src/csds_part_type.h
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * This file is part of CSDS and was copied from SWIFT.
+ * Copyright (c) 2021 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 CSDS_PART_TYPES_H
+#define CSDS_PART_TYPES_H
+
+/**
+ * @brief The different types of particles a #gpart can link to.
+ *
+ * Note we use the historical values from Gadget for these fields.
+ */
+enum part_type {
+  csds_type_gas = 0,
+  csds_type_dark_matter = 1,
+  csds_type_dark_matter_background = 2,
+  csds_type_sink = 3,
+  csds_type_stars = 4,
+  csds_type_black_hole = 5,
+  csds_type_neutrino = 6,
+  csds_type_count
+} __attribute__((packed));
+
+extern const char* part_type_names[];
+
+#endif /* CSDS_PART_TYPES_H */
diff --git a/src/csds_particle.h b/src/csds_particle.h
index f085bdc17f05ee226e7ff92328596d21fc729abe..ae443a24c74daa9f4e2546f080b2108b19370656 100644
--- a/src/csds_particle.h
+++ b/src/csds_particle.h
@@ -23,6 +23,7 @@
 #include "csds_tools.h"
 
 /* Include the other local files. */
+#include "csds_definitions.h"
 #include "csds_header.h"
 #include "csds_interpolation.h"
 #include "csds_loader_io.h"
@@ -73,7 +74,7 @@ __attribute__((always_inline)) INLINE static size_t csds_particle_read_field(
     error_python("Cannot read a particle from timestep record.");
   }
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   if (derivative == 1 && field_read->first.field == field_enum_none) {
     error("Trying to read the non existing first derivative.");
   }
@@ -88,7 +89,7 @@ __attribute__((always_inline)) INLINE static size_t csds_particle_read_field(
                            : derivative == 1 ? field_read->first.position
                                              : field_read->second.position;
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   if (position < 0) {
     error("Position not set (derivative %i of %s)", derivative,
           field_enum_get_name(field_read->field.field));
@@ -135,8 +136,8 @@ INLINE static enum csds_special_flags csds_unpack_flags_and_data(
 
   const enum csds_special_flags flag = ((logfile_data & 0xFF000000) >> 24);
 
-#ifdef SWIFT_DEBUG_CHECKS
-  if (*part_type >= swift_type_count || *part_type < 0) {
+#ifdef CSDS_DEBUG_CHECKS
+  if (*part_type >= csds_type_count || *part_type < 0) {
     error("Invalid particle type found (%i)", *part_type);
   }
 #endif
@@ -196,7 +197,6 @@ csds_particle_interpolate_field(const double time_before,
                                 const struct csds_reader_field *restrict after,
                                 void *restrict output, const double time,
                                 const struct field_information *field,
-                                enum part_type type,
                                 const struct csds_parameters *params) {
 
   switch (field->field.field) {
diff --git a/src/csds_python_tools.h b/src/csds_python_tools.h
index 755c196bd836b73baefc6c98f801b114c300a0d6..868ca9062b0fcbd28a1c06b46f7fb3e083295a2f 100644
--- a/src/csds_python_tools.h
+++ b/src/csds_python_tools.h
@@ -16,8 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#ifndef SWIFT_CSDS_PYTHON_TOOLS_H
-#define SWIFT_CSDS_PYTHON_TOOLS_H
+#ifndef CSDS_PYTHON_TOOLS_H
+#define CSDS_PYTHON_TOOLS_H
 
 #include "../config.h"
 
@@ -34,7 +34,7 @@
    subfield in a numpy array */
 struct csds_python_subfield {
   /* Name of the subfield */
-  char name[STRING_SIZE];
+  char name[CSDS_STRING_SIZE];
 
   /* Offset in the bytes */
   size_t offset;
@@ -181,7 +181,7 @@ csds_python_tools_get_format_string(int typenum, int dimension) {
   }
 
   /* Now construct the complete string */
-  char format[STRING_SIZE];
+  char format[CSDS_STRING_SIZE];
   if (dimension == 1) {
     strcpy(format, type_format);
   } else {
@@ -194,4 +194,4 @@ csds_python_tools_get_format_string(int typenum, int dimension) {
 
 #endif  // HAVE_PYTHON
 
-#endif  // SWIFT_CSDS_PYTHON_TOOLS_H
+#endif  // CSDS_PYTHON_TOOLS_H
diff --git a/src/csds_python_wrapper.c b/src/csds_python_wrapper.c
index 0fc382a98fcb16639e80af215e142f6f99852b7e..81d812318533c8f3a2ece9fe9f9893975a0563d1 100644
--- a/src/csds_python_wrapper.c
+++ b/src/csds_python_wrapper.c
@@ -68,9 +68,6 @@ typedef struct {
   /* Verbose level */
   int verbose;
 
-  /* Number of threads to use */
-  int number_threads;
-
   /* Number of index file to write */
   int number_index;
 
@@ -78,7 +75,7 @@ typedef struct {
   int restart_init;
 
   /* Reader for each type of particles */
-  PyParticleReader *part_reader[swift_type_count];
+  PyParticleReader *part_reader[csds_type_count];
 
 } PyObjectReader;
 
@@ -105,7 +102,8 @@ static void Reader_dealloc(PyObjectReader *self) {
  * @brief Allocate the memory of a particle reader.
  */
 __attribute__((always_inline)) INLINE static PyObject *particle_reader_new(
-    PyTypeObject *type, PyObject *args, PyObject *kwds) {
+    PyTypeObject *type, ATTR_UNUSED PyObject *args,
+    ATTR_UNUSED PyObject *kwds) {
   PyParticleReader *self = (PyParticleReader *)type->tp_alloc(type, 0);
   return (PyObject *)self;
 }
@@ -113,15 +111,15 @@ __attribute__((always_inline)) INLINE static PyObject *particle_reader_new(
 /**
  * @brief Allocate the memory.
  */
-static PyObject *Reader_new(PyTypeObject *type, PyObject *args,
-                            PyObject *kwds) {
+static PyObject *Reader_new(PyTypeObject *type, ATTR_UNUSED PyObject *args,
+                            ATTR_UNUSED PyObject *kwds) {
   PyObjectReader *self;
 
   self = (PyObjectReader *)type->tp_alloc(type, 0);
   self->ready = 0;
   self->basename = NULL;
 
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     self->part_reader[i] = NULL;
   }
 
@@ -140,23 +138,20 @@ static int Reader_init(PyObjectReader *self, PyObject *args, PyObject *kwds) {
   /* input variables. */
   char *basename = NULL;
   int verbose = 0;
-  int number_threads = 1;
   int number_index = 10;
   int restart_init = 0;
 
   /* List of keyword arguments. */
-  static char *kwlist[] = {"basename",     "verbose",      "number_threads",
-                           "number_index", "restart_init", NULL};
+  static char *kwlist[] = {"basename", "verbose", "number_index",
+                           "restart_init", NULL};
 
   /* parse the arguments. */
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iiip", kwlist, &basename,
-                                   &verbose, &number_threads, &number_index,
-                                   &restart_init))
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iip", kwlist, &basename,
+                                   &verbose, &number_index, &restart_init))
     return -1;
 
   /* Copy the arguments */
   self->verbose = verbose;
-  self->number_threads = number_threads;
   self->number_index = number_index;
   self->restart_init = restart_init;
 
@@ -175,7 +170,7 @@ static int Reader_init(PyObjectReader *self, PyObject *args, PyObject *kwds) {
  *
  * <b>returns</b> tuple containing min and max time.
  */
-static PyObject *getTimeLimits(PyObject *self, PyObject *Py_UNUSED(ignored)) {
+static PyObject *getTimeLimits(PyObject *self, ATTR_UNUSED PyObject *args) {
   if (!((PyObjectReader *)self)->ready) {
     error_python(
         "The CSDS is not ready yet."
@@ -204,7 +199,7 @@ static PyObject *getTimeLimits(PyObject *self, PyObject *Py_UNUSED(ignored)) {
  *
  * <b>returns</b> tuple containing the box size.
  */
-static PyObject *get_box_size(PyObject *self, PyObject *Py_UNUSED(ignored)) {
+static PyObject *get_box_size(PyObject *self, ATTR_UNUSED PyObject *args) {
   if (!((PyObjectReader *)self)->ready) {
     error_python(
         "The CSDS is not ready yet."
@@ -236,8 +231,7 @@ static PyObject *get_box_size(PyObject *self, PyObject *Py_UNUSED(ignored)) {
  */
 __attribute__((always_inline)) INLINE static PyObject *
 csds_loader_create_output(void **output, const enum field_enum *fields,
-                          const int n_fields, const uint64_t *n_part,
-                          uint64_t n_tot) {
+                          const int n_fields, uint64_t n_tot) {
 
   /* Create the python dictionary */
   PyObject *dict = PyDict_New();
@@ -324,18 +318,18 @@ csds_loader_create_output(void **output, const enum field_enum *fields,
   return dict;
 }
 
-static PyObject *pyEnter(__attribute__((unused)) PyObject *self,
-                         PyObject *args) {
+static PyObject *pyEnter(ATTR_UNUSED PyObject *self,
+                         ATTR_UNUSED PyObject *args) {
 
   PyObjectReader *self_reader = (PyObjectReader *)self;
   csds_reader_init(&self_reader->reader, self_reader->basename,
-                   self_reader->verbose, self_reader->number_threads,
-                   self_reader->number_index, self_reader->restart_init);
+                   self_reader->verbose, self_reader->number_index,
+                   self_reader->restart_init);
   self_reader->ready = 1;
 
   /* Allocate the particle readers */
   PyObject *args_init = PyTuple_New(0);
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     PyParticleReader *part_reader = (PyParticleReader *)PyObject_CallObject(
         (PyObject *)&PyParticleReader_Type, args_init);
 
@@ -353,8 +347,8 @@ static PyObject *pyEnter(__attribute__((unused)) PyObject *self,
   return self;
 }
 
-static PyObject *pyExit(__attribute__((unused)) PyObject *self,
-                        PyObject *args) {
+static PyObject *pyExit(ATTR_UNUSED PyObject *self,
+                        ATTR_UNUSED PyObject *args) {
   PyObjectReader *self_reader = (PyObjectReader *)self;
   if (!self_reader->ready) {
     error_python("It seems that the reader was not initialized");
@@ -363,7 +357,7 @@ static PyObject *pyExit(__attribute__((unused)) PyObject *self,
   self_reader->ready = 0;
 
   /* Do the same for the particle readers */
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     self_reader->part_reader[i]->reader = NULL;
     Py_DecRef((PyObject *)self_reader->part_reader[i]);
   }
@@ -371,8 +365,8 @@ static PyObject *pyExit(__attribute__((unused)) PyObject *self,
   Py_RETURN_NONE;
 }
 
-static PyObject *pyGetListFields(__attribute__((unused)) PyObject *self,
-                                 PyObject *args, PyObject *kwds) {
+static PyObject *pyGetListFields(ATTR_UNUSED PyObject *self, PyObject *args,
+                                 PyObject *kwds) {
   PyObjectReader *self_reader = (PyObjectReader *)self;
   if (!self_reader->ready) {
     error_python(
@@ -391,17 +385,17 @@ static PyObject *pyGetListFields(__attribute__((unused)) PyObject *self,
     return NULL;
 
   /* Get the type of particles to read. */
-  int read_types[swift_type_count] = {0};
+  int read_types[csds_type_count] = {0};
   /* By default, we read everything */
   if (types == Py_None) {
-    for (int i = 0; i < swift_type_count; i++) {
+    for (int i = 0; i < csds_type_count; i++) {
       read_types[i] = 1;
     }
   }
   /* Deal with the case of a single int. */
   else if (PyLong_Check(types)) {
     const size_t type = PyLong_AsSize_t(types);
-    if (type >= swift_type_count) {
+    if (type >= csds_type_count) {
       error_python("Unexpected particle type %zi", type);
     }
     read_types[type] = 1;
@@ -412,7 +406,7 @@ static PyObject *pyGetListFields(__attribute__((unused)) PyObject *self,
     for (size_t i = 0; i < size; i++) {
       PyObject *cur = PyList_GetItem(types, i);
       const size_t type = PyLong_AsSize_t(cur);
-      if (type >= swift_type_count) {
+      if (type >= csds_type_count) {
         error_python("Unexpected particle type %zi", type);
       }
       read_types[type] = 1;
@@ -434,7 +428,7 @@ static PyObject *pyGetListFields(__attribute__((unused)) PyObject *self,
     field_present[i] = 1;
 
     /* Check all the types */
-    for (int type = 0; type < swift_type_count; type++) {
+    for (int type = 0; type < csds_type_count; type++) {
       /* Skip the types that are not required
          and the field not found */
       if (read_types[type] == 0 || field_present[i] == 0) continue;
@@ -484,7 +478,7 @@ static PyObject *pyGetListFields(__attribute__((unused)) PyObject *self,
 /**
  * @brief shortcut to PyGetListFields for a single particle type
  */
-static PyObject *pyParticleGetListFields(__attribute__((unused)) PyObject *self,
+static PyObject *pyParticleGetListFields(ATTR_UNUSED PyObject *self,
                                          PyObject *args, PyObject *kwds) {
   PyParticleReader *part_reader = (PyParticleReader *)self;
   PyObject *reader = (PyObject *)part_reader->reader;
@@ -548,11 +542,11 @@ void pyGetData_CheckInput(PyObject *fields, PyObject *types, PyObject *part_ids,
 
     /* Check each element */
     const size_t size = PyList_Size(part_ids);
-    if (size != swift_type_count) {
+    if (size != csds_type_count) {
       error_python(
           "The list of ids should contain %i elements (one for each particle "
           "type)",
-          swift_type_count);
+          csds_type_count);
     }
     for (size_t i = 0; i < size; i++) {
       PyArrayObject *el = (PyArrayObject *)PyList_GetItem(part_ids, i);
@@ -575,14 +569,14 @@ void pyGetData_CheckInput(PyObject *fields, PyObject *types, PyObject *part_ids,
   /* Get the type of particles to read. */
   /* By default, we read everything */
   if (types == Py_None) {
-    for (int i = 0; i < swift_type_count; i++) {
+    for (int i = 0; i < csds_type_count; i++) {
       read_types[i] = 1;
     }
   }
   /* Deal with the case of a single int. */
   else if (PyLong_Check(types)) {
     const size_t type = PyLong_AsSize_t(types);
-    if (type >= swift_type_count) {
+    if (type >= csds_type_count) {
       error_python("Unexpected particle type %zi", type);
     }
     read_types[type] = 1;
@@ -593,7 +587,7 @@ void pyGetData_CheckInput(PyObject *fields, PyObject *types, PyObject *part_ids,
     for (size_t i = 0; i < size; i++) {
       PyObject *cur = PyList_GetItem(types, i);
       const size_t type = PyLong_AsSize_t(cur);
-      if (type >= swift_type_count) {
+      if (type >= csds_type_count) {
         error_python("Unexpected particle type %zi", type);
       }
       read_types[type] = 1;
@@ -612,8 +606,8 @@ void pyGetData_CheckInput(PyObject *fields, PyObject *types, PyObject *part_ids,
  *
  * @return Dictionary of numpy array containing the fields requested.
  */
-static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
-                           PyObject *args, PyObject *kwds) {
+static PyObject *pyGetData(ATTR_UNUSED PyObject *self, PyObject *args,
+                           PyObject *kwds) {
 
   PyObjectReader *self_reader = (PyObjectReader *)self;
   if (!self_reader->ready) {
@@ -637,7 +631,7 @@ static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
                                    &part_ids, &types))
     return NULL;
 
-  int read_types[swift_type_count] = {0};
+  int read_types[csds_type_count] = {0};
   pyGetData_CheckInput(fields, types, part_ids, read_types);
 
   /* initialize the reader. */
@@ -666,14 +660,14 @@ static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
   csds_reader_set_time(reader, time);
 
   /* Get the number of particles. */
-  uint64_t n_part[swift_type_count];
+  uint64_t n_part[csds_type_count];
   if (part_ids == Py_None) {
     /* If no ids provided, read everything from the index files */
     csds_reader_get_number_particles(reader, n_part, read_types);
   }
   /* If the ids are provided, use them to get the number of particles */
   else {
-    for (int i = 0; i < swift_type_count; i++) {
+    for (int i = 0; i < csds_type_count; i++) {
       PyObject *el = PyList_GetItem(part_ids, i);
       n_part[i] = el == Py_None ? 0 : PyArray_Size(el);
     }
@@ -681,7 +675,7 @@ static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
 
   /* Count the total number of particles. */
   uint64_t n_tot = 0;
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     n_tot += n_part[i];
   }
 
@@ -711,9 +705,9 @@ static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
   } else {
 
     /* Get the arrays in a C compatible way */
-    PyObject *list[swift_type_count] = {NULL};
-    long long *c_part_ids[swift_type_count];
-    for (int i = 0; i < swift_type_count; i++) {
+    PyObject *list[csds_type_count] = {NULL};
+    long long *c_part_ids[csds_type_count];
+    for (int i = 0; i < csds_type_count; i++) {
       PyObject *el = PyList_GetItem(part_ids, i);
 
       /* Check if a list is provided */
@@ -740,7 +734,7 @@ static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
 
     /* Free the memory and recompute n_tot */
     n_tot = 0;
-    for (int i = 0; i < swift_type_count; i++) {
+    for (int i = 0; i < csds_type_count; i++) {
       if (list[i] != NULL) Py_DECREF(list[i]);
 
       n_tot += n_part[i];
@@ -749,7 +743,7 @@ static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
 
   /* Create the python output. */
   PyObject *array =
-      csds_loader_create_output(output, fields_wanted, n_fields, n_part, n_tot);
+      csds_loader_create_output(output, fields_wanted, n_fields, n_tot);
 
   /* Free the reader. */
   free(fields_wanted);
@@ -760,8 +754,8 @@ static PyObject *pyGetData(__attribute__((unused)) PyObject *self,
 /**
  * @brief Shortcut to #pyGetData for a single particle type.
  */
-static PyObject *pyParticleGetData(__attribute__((unused)) PyObject *self,
-                                   PyObject *args, PyObject *kwds) {
+static PyObject *pyParticleGetData(ATTR_UNUSED PyObject *self, PyObject *args,
+                                   PyObject *kwds) {
 
   PyParticleReader *part_reader = (PyParticleReader *)self;
   PyObject *reader = (PyObject *)part_reader->reader;
@@ -792,8 +786,8 @@ static PyObject *pyParticleGetData(__attribute__((unused)) PyObject *self,
       error("You need to provide a numpy array of ids");
     }
 
-    part_ids_list = PyList_New(swift_type_count);
-    for (int i = 0; i < swift_type_count; i++) {
+    part_ids_list = PyList_New(csds_type_count);
+    for (int i = 0; i < csds_type_count; i++) {
       PyList_SetItem(part_ids_list, i, Py_None);
     }
     PyList_SetItem(part_ids_list, part_reader->type, part_ids);
@@ -918,8 +912,6 @@ static PyTypeObject PyObjectReader_Type = {
         "    Basename of the logfile.\n"
         "verbose: int (optional)\n"
         "    Verbose level\n\n"
-        "number_threads: int (optional)\n"
-        "    Number of threads to use.\n\n"
         "number_index: int (optional)\n"
         "    Number of index files to generate\n\n"
         "restart_init: bool (optional)\n"
@@ -997,7 +989,7 @@ PyMODINIT_FUNC PyInit_libcsds(void) {
   m = PyModule_Create(&libcsdsmodule);
   if (m == NULL) return NULL;
 
-  /* Deal with SWIFT clock */
+  /* Deal with CSDS clock */
   clocks_set_cpufreq(0);
 
   /* Prepare the classes */
@@ -1015,13 +1007,13 @@ PyMODINIT_FUNC PyInit_libcsds(void) {
 
   /* Add the reader object */
   PyModule_AddObject(m, "Reader", (PyObject *)&PyObjectReader_Type);
-  PyModule_AddIntConstant(m, "gas", swift_type_gas);
-  PyModule_AddIntConstant(m, "dark_matter", swift_type_dark_matter);
+  PyModule_AddIntConstant(m, "gas", csds_type_gas);
+  PyModule_AddIntConstant(m, "dark_matter", csds_type_dark_matter);
   PyModule_AddIntConstant(m, "dark_matter_background",
-                          swift_type_dark_matter_background);
-  PyModule_AddIntConstant(m, "sinks", swift_type_sink);
-  PyModule_AddIntConstant(m, "stars", swift_type_stars);
-  PyModule_AddIntConstant(m, "black_holes", swift_type_black_hole);
+                          csds_type_dark_matter_background);
+  PyModule_AddIntConstant(m, "sinks", csds_type_sink);
+  PyModule_AddIntConstant(m, "stars", csds_type_stars);
+  PyModule_AddIntConstant(m, "black_holes", csds_type_black_hole);
 
   /* Import numpy. */
   import_array();
diff --git a/src/csds_reader.c b/src/csds_reader.c
index 03613b3192bd7c1ed574a4650d36c166cbdea6b9..a0e20be77ae9971679b5e75af7f57ff503c9d57b 100644
--- a/src/csds_reader.c
+++ b/src/csds_reader.c
@@ -22,30 +22,24 @@
 
 /* Include CSDS headers */
 #include "csds_fields.h"
+#include "csds_openmp.h"
 #include "csds_parameters.h"
 
 /* Include standard library */
 #include <sys/sysinfo.h>
 #include <unistd.h>
 
-/* Include local headers */
-#include "threadpool.h"
-
-#define nr_threads get_nprocs()
-
 /**
  * @brief Initialize the reader.
  *
  * @param reader The #csds_reader.
  * @param basename The basename of the csds files.
  * @param verbose The verbose level.
- * @param number_threads The number of threads to use.
  * @param number_index The number of index files to write.
  * @param restart_init Are we restarting the initial reading?
  */
 void csds_reader_init(struct csds_reader *reader, const char *basename,
-                      int verbose, int number_threads, int number_index,
-                      int restart_init) {
+                      int verbose, int number_index, int restart_init) {
   if (verbose > 1) message("Initializing the reader.");
 
   /* Set the variable to the default values */
@@ -58,10 +52,10 @@ void csds_reader_init(struct csds_reader *reader, const char *basename,
 
   /* Initialize the reader variables. */
   reader->verbose = verbose;
-  csds_parameters_init(&reader->params, reader, number_threads);
+  csds_parameters_init(&reader->params, reader);
 
   /* Generate the logfile filename */
-  char logfile_name[STRING_SIZE];
+  char logfile_name[CSDS_STRING_SIZE];
   sprintf(logfile_name, "%s.dump", basename);
 
   /* Initialize the log file. */
@@ -93,7 +87,7 @@ void csds_reader_init_index(struct csds_reader *reader, int number_index,
   /* Count the number of files */
   int count = 0;
   while (1) {
-    char filename[STRING_SIZE + 50];
+    char filename[CSDS_STRING_SIZE + 50];
     sprintf(filename, "%s_%04i.index", reader->basename, count);
 
     /* Check if file exists */
@@ -136,7 +130,7 @@ void csds_reader_init_index(struct csds_reader *reader, int number_index,
 
   /* Get the information contained in the headers */
   for (int i = 0; i < reader->index.n_files; i++) {
-    char filename[STRING_SIZE + 50];
+    char filename[CSDS_STRING_SIZE + 50];
     sprintf(filename, "%s_%04i.index", reader->basename, i);
 
     /* Read the header */
@@ -200,9 +194,9 @@ void csds_reader_set_time(struct csds_reader *reader, double time) {
   }
 
   /* Generate the filename */
-  char filename_prev[STRING_SIZE + 50];
+  char filename_prev[CSDS_STRING_SIZE + 50];
   sprintf(filename_prev, "%s_%04u.index", reader->basename, left);
-  char filename_next[STRING_SIZE + 50];
+  char filename_next[CSDS_STRING_SIZE + 50];
   sprintf(filename_next, "%s_%04u.index", reader->basename, left + 1);
 
   /* Check if the file is already mapped */
@@ -353,7 +347,7 @@ size_t csds_reader_count_number_removed_particles(struct csds_reader *reader,
 void csds_reader_get_number_particles(struct csds_reader *reader,
                                       uint64_t *n_parts,
                                       const int *read_types) {
-  for (enum part_type i = (enum part_type)0; i < swift_type_count; i++) {
+  for (enum part_type i = (enum part_type)0; i < csds_type_count; i++) {
     /* Should we skip this type of particles? */
     if (read_types[i] == 0) {
       n_parts[i] = 0;
@@ -397,7 +391,7 @@ void csds_reader_get_number_particles(struct csds_reader *reader,
  *
  * @return Is the particle removed from the logfile?
  */
-int csds_reader_read_field(struct csds_reader *reader, double time,
+int csds_reader_read_field(const struct csds_reader *reader, double time,
                            size_t offset_time,
                            enum csds_reader_type interp_type,
                            const size_t offset_last_full_record,
@@ -437,7 +431,7 @@ int csds_reader_read_field(struct csds_reader *reader, double time,
       enum csds_special_flags flag = csds_particle_read_special_flag(
           offset, &mask, &h_offset, &data, &part_type, reader->log.log.map);
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
       if (part_type != type) {
         error("Found particles that do not correspond.");
       }
@@ -578,7 +572,7 @@ int csds_reader_read_field(struct csds_reader *reader, double time,
 
     /* Interpolate the data. */
     csds_particle_interpolate_field(time_before, &before, time_after, &after,
-                                    output, time, field_wanted, type,
+                                    output, time, field_wanted,
                                     &reader->params);
   }
   return 0;
@@ -630,162 +624,44 @@ void csds_reader_get_fields_wanted(
 }
 
 /**
- * @brief Structure for the mapper function
- * #csds_reader_read_all_particles_single_type_mapper.
- */
-struct extra_data_read_all {
-
-  /*! The #csds_reader. */
-  struct csds_reader *reader;
-
-  /*! The requested time. */
-  double time;
-
-  /*! The interpolation type. */
-  enum csds_reader_type interp_type;
-
-  /*! The #field_information for all the fields requested. */
-  const struct field_information **fields_wanted;
-
-  /*! The number of fields requested. */
-  int n_fields_wanted;
-
-  /*! The array of output arrays. */
-  void **output;
-
-  /*! The number of particles at the requested time.  */
-  const uint64_t *n_part;
-
-  /*! The type of particle to read. */
-  enum part_type type;
-
-  /*! The current position in the index file. */
-  size_t current_index;
-
-  /*! The current position in the output arrays. */
-  size_t current_output;
-
-  /*! The number of jumps done in order to find the particles */
-  long int total_number_jumps;
-};
-
-/**
- * @brief Mapper function of #csds_reader_read_all_particles_single_type.
+ * @brief Read a single particle.
  *
- * @param map_data (size_t) The current position (not used)
- * @param num_elements The number of elements to process with the current
- * thread.
- * @param extra_data Pointer to a #extra_data_read_all.
+ * @param reader The #csds_reader
+ * @param interp_type The type of interpolation
+ * @param fields_wanted The list of fields to return.
+ * @param n_fields_wanted The number of fields to return
+ * @param output The pointers to the output arrays
+ * @param offset The offset of the particle to read
+ * @param output_index The index of the particle within the output arrays
+ * @param type The type of particle
+ * @parma number_jumps (out) The number of jumps required to get the particle
  */
-void csds_reader_read_all_particles_single_type_mapper(void *map_data,
-                                                       int num_elements,
-                                                       void *extra_data) {
-
-  /* Extract the data */
-  struct extra_data_read_all *data_tp =
-      (struct extra_data_read_all *)extra_data;
-  struct csds_reader *reader = data_tp->reader;
-  double time = data_tp->time;
-  enum csds_reader_type interp_type = data_tp->interp_type;
-  const struct field_information **fields_wanted = data_tp->fields_wanted;
-  int n_fields_wanted = data_tp->n_fields_wanted;
-  void **output = data_tp->output;
-  const uint64_t *n_part = data_tp->n_part;
-  enum part_type type = data_tp->type;
-
-  /* Create a few variables for later */
-  const size_t size_index = reader->index.index_prev.nparts[type];
-  const size_t size_history =
-      csds_reader_count_number_new_particles(reader, type);
-
-  struct index_data *data =
-      csds_index_get_data(&reader->index.index_prev, type);
-  struct index_data *data_created =
-      csds_index_get_created_history(&reader->index.index_next, type);
-
-  /* Count the number of previous parts for the shift in output */
-  uint64_t prev_npart = 0;
-  for (int i = 0; i < type; i++) {
-    prev_npart += n_part[i];
-  }
-
-  /* Allocate the temporary memory. */
-  void **output_tmp = malloc(n_fields_wanted * sizeof(void *));
-  if (output_tmp == NULL) {
-    error_python("Failed to allocate the temporary output buffer");
-  }
-  for (int i = 0; i < n_fields_wanted; i++) {
-    output_tmp[i] = malloc(fields_wanted[i]->field.size);
-    if (output_tmp[i] == NULL) {
-      error_python("Failed to allocate the temporary output buffer");
-    }
-  }
-
-  /* Read the particles */
-  long int total_number_jumps = 0;
-  for (int i = 0; i < num_elements; i++) {
-
-    /* Get the next index. */
-    size_t current_index = atomic_inc(&data_tp->current_index);
-
-    /* Are we reading the history? */
-    int reading_history = current_index >= size_index;
-
-    /* Check if we still have some particles available. */
-    if (reading_history && current_index == size_history + size_index) {
-      error_python("The CSDS was not able to find enough particles.");
-    }
-
-    /* Get the offset */
-    const size_t current =
-        reading_history ? current_index - size_index : current_index;
-    size_t offset =
-        reading_history ? data_created[current].offset : data[current].offset;
-
-    /* Loop over each field. */
-    int particle_removed = 0;
-    for (int field = 0; field < n_fields_wanted; field++) {
-
-      /* Read the field. */
-      int number_jumps = 0;
-      particle_removed = csds_reader_read_field(
-          reader, time, reader->time.time_offset, interp_type, offset,
-          fields_wanted[field], output_tmp[field], type, &number_jumps);
-
-      /* Should we continue to read the fields of this particle? */
-      if (particle_removed) {
-        i--;
-        break;
-      }
-
-      total_number_jumps += number_jumps;
-    }
-
-    /* Write the particle into the output if it was not removed */
-    if (!particle_removed) {
-      size_t current_output = atomic_inc(&data_tp->current_output);
-      for (int field = 0; field < n_fields_wanted; field++) {
-
-        /* Get the array */
-        const size_t size = fields_wanted[field]->field.size;
-        void *output_single =
-            (char *)output[field] + (current_output + prev_npart) * size;
-
-        /* Copy the temporary buffer into the global one */
-        memcpy(output_single, output_tmp[field], size);
-      }
+int csds_reader_read_particle(const struct csds_reader *reader, double time,
+                              enum csds_reader_type interp_type,
+                              const struct field_information **fields_wanted,
+                              int n_fields_wanted, void **output, size_t offset,
+                              size_t output_index, enum part_type type,
+                              int *number_jumps) {
+
+  /* Loop over each field. */
+  // TODO cache the last full offset
+  for (int field = 0; field < n_fields_wanted; field++) {
+    const struct field_information *current_field = fields_wanted[field];
+    void *current_output =
+        output[field] + output_index * current_field->field.size;
+
+    /* Read the field. */
+    int particle_removed = csds_reader_read_field(
+        reader, time, reader->time.time_offset, interp_type, offset,
+        current_field, current_output, type, number_jumps);
+
+    /* Should we continue to read the fields of this particle? */
+    if (particle_removed) {
+      return 1;
     }
   }
 
-  /* Free the allocated memory */
-  for (int i = 0; i < n_fields_wanted; i++) {
-    free(output_tmp[i]);
-  }
-  free(output_tmp);
-
-  /* Write the number of jumps */
-  __atomic_add_fetch(&data_tp->total_number_jumps, total_number_jumps,
-                     __ATOMIC_RELAXED);
+  return 0;
 }
 
 /**
@@ -818,41 +694,102 @@ void csds_reader_read_all_particles_single_type(
   csds_reader_get_fields_wanted(reader, fields_wanted, fields_info_wanted,
                                 n_fields_wanted, type);
 
-  /* Compact the data */
-  struct extra_data_read_all extra = {reader,
-                                      time,
-                                      interp_type,
-                                      fields_info_wanted,
-                                      n_fields_wanted,
-                                      output,
-                                      n_part,
-                                      type,
-                                      /* current_index */ 0,
-                                      /* current_output */ 0,
-                                      /* total_number_jumps */ 0};
-
-  /* Create the threadpool */
-  struct threadpool tp;
-  threadpool_init(&tp, reader->params.number_threads);
+  /* Count the number of previous parts for the shift in output */
+  uint64_t prev_npart = 0;
+  for (int i = 0; i < type; i++) {
+    prev_npart += n_part[i];
+  }
+
+  /* Create some information from the index files */
+  const size_t size_index = reader->index.index_prev.nparts[type];
+  const size_t size_history =
+      csds_reader_count_number_new_particles(reader, type);
+
+  struct index_data *data =
+      csds_index_get_data(&reader->index.index_prev, type);
+  struct index_data *data_created =
+      csds_index_get_created_history(&reader->index.index_next, type);
+
+  /* Current index to read */
+  size_t current_index = 0;
+  size_t particles_read = 0;
+  int local_counter = 0;
+  size_t total_number_jumps = 0;
+  const int local_update_limit = 1000;
+  const ticks tic2 = getticks();
 
   /* Read the particles */
-  threadpool_map(&tp, csds_reader_read_all_particles_single_type_mapper, NULL,
-                 n_part[type], 1, threadpool_auto_chunk_size, &extra);
+#pragma omp parallel for firstprivate(local_counter) reduction(+:total_number_jumps)
+  for (size_t i = 0; i < n_part[type]; i++) {
+
+    /* Try to find a particle that is not removed */
+    int particle_removed = 1;
+    while (particle_removed) {
+
+      size_t local_index = 0;
+#pragma omp atomic capture
+      local_index = current_index++;
+
+      /* Are we reading the history? */
+      int reading_history = local_index >= size_index;
+
+      /* Check if we still have some particles available. */
+      if (reading_history && local_index == size_history + size_index) {
+        error_python("The CSDS was not able to find enough particles.");
+      }
+
+      /* Get the offset */
+      const size_t current =
+          reading_history ? local_index - size_index : local_index;
+      size_t offset =
+          reading_history ? data_created[current].offset : data[current].offset;
+
+      /* Get the offset of the particle */
+      int number_jumps = 0;
+      particle_removed = csds_reader_read_particle(
+          reader, time, interp_type, fields_info_wanted, n_fields_wanted,
+          output, offset, i, type, &number_jumps);
+
+      /* Update the number of jumps */
+      if (!particle_removed) {
+        total_number_jumps += number_jumps;
+      }
+    }
 
-  /* Check if we have all the expected particles. */
-  if (n_part[type] != extra.current_output) {
-    error("The reader was not able to find all the expected particles.");
+    /* Do we need to print something? */
+    if (!(reader->verbose > 0)) continue;
+
+    /* Update the counters */
+    local_counter++;
+    if (local_counter < local_update_limit) continue;
+
+      /* Add the local counter to the global one */
+#pragma omp atomic
+    particles_read += local_counter;
+    local_counter = 0;
+
+    /* Only the master is printing */
+    int current_thread = csds_get_thread_num();
+    if (current_thread != 0) continue;
+
+    float ratio = (float)particles_read / (float)n_part[type];
+
+    /* Compute the remaining time */
+    const int delta_time = clocks_diff_ticks(getticks(), tic2) / 1000.0;
+    const int remaining_time = delta_time * (1. - ratio) / ratio;
+
+    /* Print the message */
+    tools_print_progress(100 * ratio, remaining_time, "Reading particles");
   }
 
   /* Print the number of jumps if required */
-  if (reader->verbose > 1 || reader->verbose == CSDS_VERBOSE_TIMERS) {
-    float avg = (float)extra.total_number_jumps /
-                (float)(n_fields_wanted * n_part[type]);
+  if (reader->verbose > 0 || reader->verbose == CSDS_VERBOSE_TIMERS) {
+    float avg =
+        (float)total_number_jumps / (float)(n_fields_wanted * n_part[type]);
     message("Average number of jumps for %s: %.1f", part_type_names[type], avg);
   }
 
   /* Free the memory */
-  threadpool_clean(&tp);
   free(fields_info_wanted);
 }
 
@@ -876,35 +813,35 @@ void csds_reader_read_all_particles(struct csds_reader *reader, double time,
   const ticks tic = getticks();
 
   /* Read the gas */
-  if (n_part[swift_type_gas] != 0) {
+  if (n_part[csds_type_gas] != 0) {
     csds_reader_read_all_particles_single_type(reader, time, interp_type,
                                                fields_wanted, n_fields_wanted,
-                                               output, n_part, swift_type_gas);
+                                               output, n_part, csds_type_gas);
   }
 
   /* Read the dark matter. */
-  if (n_part[swift_type_dark_matter] != 0) {
+  if (n_part[csds_type_dark_matter] != 0) {
     csds_reader_read_all_particles_single_type(
         reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_dark_matter);
+        n_part, csds_type_dark_matter);
   }
   /* Read the dark matter background. */
-  if (n_part[swift_type_dark_matter_background] != 0) {
+  if (n_part[csds_type_dark_matter_background] != 0) {
     csds_reader_read_all_particles_single_type(
         reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_dark_matter_background);
+        n_part, csds_type_dark_matter_background);
   }
   /* Read the neutrino dark matter. */
-  if (n_part[swift_type_neutrino] != 0) {
+  if (n_part[csds_type_neutrino] != 0) {
     csds_reader_read_all_particles_single_type(
         reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_neutrino);
+        n_part, csds_type_neutrino);
   }
   /* Read the stars. */
-  if (n_part[swift_type_stars] != 0) {
-    csds_reader_read_all_particles_single_type(
-        reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_stars);
+  if (n_part[csds_type_stars] != 0) {
+    csds_reader_read_all_particles_single_type(reader, time, interp_type,
+                                               fields_wanted, n_fields_wanted,
+                                               output, n_part, csds_type_stars);
   }
 
   /* Print the time */
@@ -1026,30 +963,30 @@ void csds_reader_read_particles_from_ids(
   const ticks tic = getticks();
 
   /* Read the gas */
-  if (n_part[swift_type_gas] != 0) {
+  if (n_part[csds_type_gas] != 0) {
     csds_reader_read_particles_from_ids_single_type(
         reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_gas, ids[swift_type_gas]);
+        n_part, csds_type_gas, ids[csds_type_gas]);
   }
 
   /* Read the dark matter. */
-  if (n_part[swift_type_dark_matter] != 0) {
+  if (n_part[csds_type_dark_matter] != 0) {
     csds_reader_read_particles_from_ids_single_type(
         reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_dark_matter, ids[swift_type_dark_matter]);
+        n_part, csds_type_dark_matter, ids[csds_type_dark_matter]);
   }
   /* Read the dark matter background. */
-  if (n_part[swift_type_dark_matter_background] != 0) {
+  if (n_part[csds_type_dark_matter_background] != 0) {
     csds_reader_read_particles_from_ids_single_type(
         reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_dark_matter_background,
-        ids[swift_type_dark_matter_background]);
+        n_part, csds_type_dark_matter_background,
+        ids[csds_type_dark_matter_background]);
   }
   /* Read the stars. */
-  if (n_part[swift_type_stars] != 0) {
+  if (n_part[csds_type_stars] != 0) {
     csds_reader_read_particles_from_ids_single_type(
         reader, time, interp_type, fields_wanted, n_fields_wanted, output,
-        n_part, swift_type_stars, ids[swift_type_stars]);
+        n_part, csds_type_stars, ids[csds_type_stars]);
   }
 
   /* Print the time */
@@ -1131,11 +1068,11 @@ size_t csds_reader_read_record(struct csds_reader *reader, void **output,
   /* The record is a particle. */
   if (*is_particle) {
     size_t offset_tmp = offset;
-    for (int i = 0; i < h->number_fields[swift_type_gas]; i++) {
+    for (int i = 0; i < h->number_fields[csds_type_gas]; i++) {
       offset = csds_particle_read_field(
-          offset_tmp, output[i], &h->fields[swift_type_gas][i],
-          /* derivative */ 0, &mask, &h_offset, h->fields[swift_type_gas],
-          h->number_fields[swift_type_gas], reader->log.log.map);
+          offset_tmp, output[i], &h->fields[csds_type_gas][i],
+          /* derivative */ 0, &mask, &h_offset, h->fields[csds_type_gas],
+          h->number_fields[csds_type_gas], reader->log.log.map);
     }
   }
   /* The record is a timestamp. */
diff --git a/src/csds_reader.h b/src/csds_reader.h
index 4b8ab14b047b1c71028d0aab211864bc301f11db..a185315cd55698450aa2cb627b5594e84555d4bd 100644
--- a/src/csds_reader.h
+++ b/src/csds_reader.h
@@ -65,7 +65,7 @@
 struct csds_reader {
 
   /* Base name of the files */
-  char basename[STRING_SIZE];
+  char basename[CSDS_STRING_SIZE];
 
   struct {
     /* Information contained in the previous index file. */
@@ -118,8 +118,7 @@ enum csds_reader_event {
 void csds_reader_init_index(struct csds_reader *reader, int number_index,
                             int current_index);
 void csds_reader_init(struct csds_reader *reader, const char *basename,
-                      int verbose, int number_threads, int number_index,
-                      int restart_init);
+                      int verbose, int number_index, int restart_init);
 void csds_reader_free(struct csds_reader *reader);
 
 void csds_reader_set_time(struct csds_reader *reader, double time);
diff --git a/src/csds_reader_generate_index.c b/src/csds_reader_generate_index.c
index 19e05f5ad4de337025b982dc1210efd5856eee8e..dbe4e3231e9019a1dce8a20ef1c935be229d8cca 100644
--- a/src/csds_reader_generate_index.c
+++ b/src/csds_reader_generate_index.c
@@ -24,6 +24,8 @@
 #include "csds_hashmap.h"
 #include "csds_index.h"
 #include "csds_logfile.h"
+#include "csds_openmp.h"
+#include "csds_part_type.h"
 
 /**
  * @brief Structure that contains all the information
@@ -126,7 +128,7 @@ void index_writer_log(struct index_writer *writer, const int64_t id,
         "please increase the value of ReaderOptions:Number*.");
   }
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   if (id < 0) {
     error("Negative ID for a particle.");
   }
@@ -163,9 +165,9 @@ void index_writer_log(struct index_writer *writer, const int64_t id,
  *@brief Check if we have some unimplemented particles.
  */
 void index_writer_check_implemented(const struct index_writer *writers) {
-  if (writers[swift_type_sink].size != 0 ||
-      writers[swift_type_black_hole].size != 0 ||
-      writers[swift_type_neutrino].size != 0) {
+  if (writers[csds_type_sink].size != 0 ||
+      writers[csds_type_black_hole].size != 0 ||
+      writers[csds_type_neutrino].size != 0) {
     error("TODO implement additional particle types");
   }
 }
@@ -176,14 +178,14 @@ void index_writer_check_implemented(const struct index_writer *writers) {
 void index_writer_write_in_index(const struct index_writer *writers, FILE *f) {
 
   /* Write the number of particles */
-  uint64_t N_total[swift_type_count];
-  for (int type = 0; type < swift_type_count; type++) {
+  uint64_t N_total[csds_type_count];
+  for (int type = 0; type < csds_type_count; type++) {
     N_total[type] = writers[type].size;
   }
-  fwrite(N_total, sizeof(uint64_t), swift_type_count, f);
+  fwrite(N_total, sizeof(uint64_t), csds_type_count, f);
 
   /* Write the index data */
-  for (int type = 0; type < swift_type_count; type++) {
+  for (int type = 0; type < csds_type_count; type++) {
     if (N_total[type] == 0) continue;
 
     fwrite(writers[type].data, sizeof(struct index_data), writers[type].size,
@@ -196,13 +198,13 @@ void index_writer_write_in_index(const struct index_writer *writers, FILE *f) {
  *
  * @param reader The #csds_reader.
  * @param current_state The arrays containing the current
- * state with the last full offset (size given by swift_type_count).
+ * state with the last full offset (size given by csds_type_count).
  * @param parts_created The arrays containing the first reference
  * (since last index file) of created particles
- * (size given by swift_type_count).
+ * (size given by csds_type_count).
  * @param parts_removed The arrays containing the last reference
  * (since last index file) of removed particles (size given by
- * swift_type_count).
+ * csds_type_count).
  * @param time The time corresponding to the current index file.
  * @param file_number The current file number.
  */
@@ -213,13 +215,13 @@ void csds_reader_write_index(const struct csds_reader *reader,
                              const struct time_record *time, int file_number) {
 
   /* Get the filename */
-  char filename[STRING_SIZE + 15];
+  char filename[CSDS_STRING_SIZE + 15];
   sprintf(filename, "%s_%04i.index", reader->basename, file_number);
 
   /* Check that we have only implemented particles */
-  if (csds_hashmap_count(current_state[swift_type_sink]) != 0 ||
-      csds_hashmap_count(current_state[swift_type_black_hole]) != 0 ||
-      csds_hashmap_count(current_state[swift_type_neutrino]) != 0)
+  if (csds_hashmap_count(current_state[csds_type_sink]) != 0 ||
+      csds_hashmap_count(current_state[csds_type_black_hole]) != 0 ||
+      csds_hashmap_count(current_state[csds_type_neutrino]) != 0)
     error("Not implemented");
   index_writer_check_implemented(parts_created);
   index_writer_check_implemented(parts_removed);
@@ -238,11 +240,11 @@ void csds_reader_write_index(const struct csds_reader *reader,
   fwrite(&time->int_time, sizeof(integertime_t), 1, f);
 
   /* Write number of particles */
-  uint64_t N_total[swift_type_count];
-  for (int type = 0; type < swift_type_count; type++) {
+  uint64_t N_total[csds_type_count];
+  for (int type = 0; type < csds_type_count; type++) {
     N_total[type] = csds_hashmap_count(current_state[type]);
   }
-  fwrite(N_total, sizeof(uint64_t), swift_type_count, f);
+  fwrite(N_total, sizeof(uint64_t), csds_type_count, f);
 
   /* Write if the file is sorted */
   // TODO change it if the array is sorted
@@ -259,7 +261,7 @@ void csds_reader_write_index(const struct csds_reader *reader,
   }
 
   /* Write the current state */
-  for (int type = 0; type < swift_type_count; type++) {
+  for (int type = 0; type < csds_type_count; type++) {
     if (N_total[type] == 0) continue;
 
     // TODO memory map the file
@@ -274,7 +276,7 @@ void csds_reader_write_index(const struct csds_reader *reader,
   fclose(f);
 
   /* Cleanup the arrays */
-  for (int type = 0; type < swift_type_count; type++) {
+  for (int type = 0; type < csds_type_count; type++) {
     index_writer_reset(&parts_created[type]);
     index_writer_reset(&parts_removed[type]);
   }
@@ -285,7 +287,7 @@ void csds_reader_write_index(const struct csds_reader *reader,
  *
  * @param reader The #csds_reader.
  * @param current_state The arrays that will be updated with (size
- * swift_type_count).
+ * csds_type_count).
  * @param time_record (output) The first #time_record in the logfile (for
  * writing the index file).
  *
@@ -336,8 +338,8 @@ size_t csds_reader_get_initial_state(const struct csds_reader *reader,
     }
 
     /* TODO Implement missing particle types */
-    if (part_type == swift_type_neutrino || part_type == swift_type_sink ||
-        part_type == swift_type_black_hole) {
+    if (part_type == csds_type_neutrino || part_type == csds_type_sink ||
+        part_type == csds_type_black_hole) {
       error("Particle type not implemented (%s)", part_type_names[part_type]);
     }
 
@@ -381,135 +383,68 @@ size_t csds_reader_get_initial_state(const struct csds_reader *reader,
 }
 
 /**
- * @brief Structure for #csds_reader_update_particles_to_next_index_mapper
- */
-struct update_particle_data {
-
-  /* The reader */
-  const struct csds_reader *reader;
-
-  /* The time offset to reach */
-  size_t time_offset;
-
-  /* Current percentage */
-  float percentage;
-
-  /* Total number of particles */
-  size_t number_particles;
-
-  /* Lock for printing */
-  swift_lock_type print_lock;
-
-  /* Time when starting the update. */
-  int init_time;
-
-  /* The hashmap to udpate */
-  struct csds_hashmap *current_state;
-};
-
-/**
- * @brief Mapper function of #csds_reader_update_particles_to_next_index.
+ * @brief Get the last offset of a record before a given offset.
  *
- * This function loops over all the known particles and updates their offset
- * until reaching the required one.
+ * @param reader The #csds_reader.
+ * @param data The #index_data of the particle.
+ * @param offset_limit The upper limit of the offset to get.
  *
- * @param map_data The #index_data to process
- * @param num_elements The number of elements in map_data.
- * @param extra_data The extra parameters (#update_particle_data)
+ * @return The last offset before an index file.
  */
-void csds_reader_update_particles_to_next_index_mapper(void *map_data,
-                                                       int num_elements,
-                                                       void *extra_data) {
+size_t csds_reader_get_last_offset_before(const struct csds_reader *reader,
+                                          const struct index_data *data,
+                                          size_t offset_limit) {
 
-  /* Get a few pointers */
-  struct update_particle_data *data = (struct update_particle_data *)extra_data;
-  const struct csds_reader *reader = data->reader;
+  /* Get a the logfile */
   const struct csds_logfile *log = &reader->log;
-  struct csds_hashmap *current_state = data->current_state;
 
-  /* Loop over the particles */
-  for (int local = 0; local < num_elements; local++) {
-    size_t i = (size_t)map_data + local;
-    struct index_data *index_data =
-        csds_hashmap_get_from_position(current_state, i);
+  size_t current_offset = data->offset;
 
-    /* Did we get an item? */
-    if (index_data == NULL) {
-      continue;
-    }
-
-    size_t current_offset = index_data->offset;
+  /* Get the full mask */
+  mask_type full_mask = 0;
+  size_t h_offset = 0;
+  csds_loader_io_read_mask(log->log.map + current_offset, &full_mask,
+                           &h_offset);
 
-    /* Get the full mask */
-    mask_type full_mask = 0;
-    size_t h_offset = 0;
-    csds_loader_io_read_mask(log->log.map + current_offset, &full_mask,
-                             &h_offset);
+  /* Ensures that a special flag is present in the mask */
+  full_mask |= SPECIAL_FLAGS_MASK;
 
-    /* Ensures that a special flag is present in the mask */
-    full_mask |= SPECIAL_FLAGS_MASK;
+  /* Now remove it */
+  full_mask = full_mask ^ SPECIAL_FLAGS_MASK;
 
-    /* Now remove it */
-    full_mask = full_mask ^ SPECIAL_FLAGS_MASK;
+  /* Find the last offset before the current time */
+  size_t last_full_offset = current_offset;
+  current_offset += h_offset;
+  while (1) {
+    /* Get the mask */
+    mask_type mask = 0;
+    h_offset = 0;
+    csds_loader_io_read_mask(log->log.map + current_offset, &mask, &h_offset);
 
-    /* Find the last offset before the current time */
-    size_t last_full_offset = current_offset;
+    /* update the offset */
     current_offset += h_offset;
-    while (1) {
-      /* Get the mask */
-      mask_type mask = 0;
-      h_offset = 0;
-      csds_loader_io_read_mask(log->log.map + current_offset, &mask, &h_offset);
-
-      /* update the offset */
-      current_offset += h_offset;
-      if (current_offset > data->time_offset) {
-        break;
-      }
-
-      /* The particle should not have a special flag
-         due to the previous loop */
-      if (mask & SPECIAL_FLAGS_MASK) {
-        error("Found a special flag when updating the particles.");
-      }
-
-      /* Update the last full offset */
-      if (full_mask == mask) {
-        last_full_offset = current_offset;
-      }
-
-      /* Are we at the end of the file? */
-      if (h_offset == 0) {
-        break;
-      }
+    if (current_offset > offset_limit) {
+      break;
     }
 
-    /* Update the offset */
-    index_data->offset = last_full_offset;
-  }
-
-  if (reader->verbose > 0) {
-    /* Update the counter */
-    atomic_add_f(&data->percentage,
-                 num_elements / (float)data->number_particles);
-
-    /* Update the message */
-    if (lock_trylock(&data->print_lock)) {
-      /* Get the current state */
-      float percent = 0;
-      __atomic_load(&data->percentage, &percent, __ATOMIC_RELAXED);
-      percent *= 100.f;
+    /* The particle should not have a special flag
+       due to the previous loop */
+    if (mask & SPECIAL_FLAGS_MASK) {
+      error("Found a special flag when updating the particles");
+    }
 
-      /* Compute the remaining time */
-      const int current_time =
-          clocks_diff_ticks(getticks(), clocks_start_ticks) / 1000.0;
-      const int remaining_time =
-          (current_time - data->init_time) * (100. - percent) / percent;
+    /* Update the last full offset */
+    if (full_mask == mask) {
+      last_full_offset = current_offset;
+    }
 
-      /* Print the message */
-      tools_print_progress(percent, remaining_time, "Updating offsets");
+    /* Are we at the end of the file? */
+    if (h_offset == 0) {
+      break;
     }
   }
+
+  return last_full_offset;
 }
 
 /**
@@ -520,11 +455,11 @@ void csds_reader_update_particles_to_next_index_mapper(void *map_data,
  * @param init_offset The initial offset to read.
  * @param time_record The #time_record of the next index file.
  * @param current_state The arrays containing the state of the simulation (size
- * swift_type_count).
+ * csds_type_count).
  * @param parts_created The arrays containing the particles created since last
- * index (size swift_type_count).
+ * index (size csds_type_count).
  * @param parts_removed The arrays containing the particles removed since last
- * index (size swift_type_count).
+ * index (size csds_type_count).
  *
  * @return The starting offset for the update.
  */
@@ -595,7 +530,7 @@ size_t csds_reader_update_state_to_next_index(
     enum csds_special_flags flag = csds_particle_read_special_flag(
         old_offset, &mask, &h_offset, &data, &part_type, log->log.map);
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
     if (flag == csds_flag_none) {
       error(
           "A record should not have a mask "
@@ -648,40 +583,63 @@ size_t csds_reader_update_state_to_next_index(
     message("Finding new/removed particles took %.3f %s",
             clocks_from_ticks(getticks() - tic), clocks_getunit());
 
-  /* Create the threadpool */
-  struct threadpool tp;
-  threadpool_init(&tp, reader->params.number_threads);
-
-  /* Create the input */
-  struct update_particle_data extra_data;
-  extra_data.reader = reader;
-  extra_data.time_offset = time_record.offset;
-  extra_data.init_time =
-      clocks_diff_ticks(getticks(), clocks_start_ticks) / 1000.0;
-  extra_data.percentage = 0.f;
-  extra_data.number_particles = 0;
-
-  /* Initialize variables */
-  if (lock_init(&extra_data.print_lock) != 0)
-    error("Failed to initialize the lock");
-
-  for (int type = 0; type < swift_type_count; type++) {
-    extra_data.number_particles +=
-        csds_hashmap_get_number_buckets(current_state[type]);
+  /* Initialize the total number of particles for the progress bar */
+  size_t total_number_particles = 0;
+  for (int type = 0; type < csds_type_count; type++) {
+    total_number_particles += csds_hashmap_count(current_state[type]);
   }
 
   /* Record the time */
   const ticks tic2 = getticks();
+  size_t current_number = 0;
+  int local_counter = 0;
+  const int local_update_limit = 1000;
 
   /* Update the offsets of current_state
    * No need to update the others as they contain
    * data about when particles are removed/created*/
-  for (int type = 0; type < swift_type_count; type++) {
-    /* Update the offsets */
-    extra_data.current_state = current_state[type];
-    threadpool_map(&tp, csds_reader_update_particles_to_next_index_mapper, NULL,
-                   csds_hashmap_get_number_buckets(extra_data.current_state), 1,
-                   threadpool_auto_chunk_size, &extra_data);
+#pragma omp parallel for firstprivate(local_counter)
+  for (int type = 0; type < csds_type_count; type++) {
+    /* Loop over the buckets ~ particles */
+    size_t n_buckets = csds_hashmap_get_number_buckets(current_state[type]);
+    for (size_t i = 0; i < n_buckets; i++) {
+      struct index_data *index_data =
+          csds_hashmap_get_from_position(current_state[type], i);
+
+      /* Did we get an item? */
+      if (index_data == NULL) {
+        continue;
+      }
+
+      /* Update the offset */
+      index_data->offset = csds_reader_get_last_offset_before(
+          reader, index_data, time_record.offset);
+
+      /* Are we done or should we print something? */
+      if (!(reader->verbose > 0)) continue;
+
+      /* Update the counters */
+      local_counter++;
+      if (local_counter < local_update_limit) continue;
+
+        /* Add the local counter to the global one */
+#pragma omp atomic
+      current_number += local_counter;
+      local_counter = 0;
+
+      /* Only the master is printing */
+      int current_thread = csds_get_thread_num();
+      if (current_thread != 0) continue;
+
+      float ratio = (float)current_number / (float)total_number_particles;
+
+      /* Compute the remaining time */
+      const int delta_time = clocks_diff_ticks(getticks(), tic2) / 1000.0;
+      const int remaining_time = delta_time * (1. - ratio) / ratio;
+
+      /* Print the message */
+      tools_print_progress(100 * ratio, remaining_time, "Updating offsets");
+    }
   }
 
   /* Cleanup the output */
@@ -692,12 +650,6 @@ size_t csds_reader_update_state_to_next_index(
     message("Updating particles took %.3f %s",
             clocks_from_ticks(getticks() - tic2), clocks_getunit());
 
-  /* Free the memory */
-  threadpool_clean(&tp);
-  if (lock_destroy(&extra_data.print_lock) != 0) {
-    error("Failed to destroy the lock");
-  }
-
   return offset;
 }
 
@@ -733,13 +685,13 @@ void csds_reader_generate_index_files(const struct csds_reader *reader,
   }
 
   /* Create the different arrays that will store the information */
-  struct csds_hashmap *current_state[swift_type_count];
-  struct index_writer parts_created[swift_type_count];
-  struct index_writer parts_removed[swift_type_count];
+  struct csds_hashmap *current_state[csds_type_count];
+  struct index_writer parts_created[csds_type_count];
+  struct index_writer parts_removed[csds_type_count];
   const size_t default_size = 1024;
 
   /* Allocate the arrays for new / removed particles */
-  for (int i = 0; i < swift_type_count; i++) {
+  for (int i = 0; i < csds_type_count; i++) {
     index_writer_init(&parts_created[i], default_size,
                       reader->params.arrays_maximal_tagged_fraction);
     index_writer_init(&parts_removed[i], default_size,
@@ -758,7 +710,7 @@ void csds_reader_generate_index_files(const struct csds_reader *reader,
   if (current_index == 0) {
 
     /* Allocate the arrays for the current state */
-    for (int i = 0; i < swift_type_count; i++) {
+    for (int i = 0; i < csds_type_count; i++) {
       current_state[i] =
           csds_hashmap_new(hashmap_overallocation *
                            reader->params.approximate_number_particles[i]);
@@ -783,7 +735,7 @@ void csds_reader_generate_index_files(const struct csds_reader *reader,
     csds_index_init(&index, reader);
 
     /* Get its name */
-    char filename[STRING_SIZE + 50];
+    char filename[CSDS_STRING_SIZE + 50];
     sprintf(filename, "%s_%04u.index", reader->basename, current_index - 1);
 
     /* Read it */
@@ -791,7 +743,7 @@ void csds_reader_generate_index_files(const struct csds_reader *reader,
     csds_index_map_file(&index, filename, /* sorted */ 1);
 
     /* Loop over all the particle types */
-    for (int i = 0; i < swift_type_count; i++) {
+    for (int i = 0; i < csds_type_count; i++) {
       /* Allocate the array for the current state */
       current_state[i] =
           csds_hashmap_new(hashmap_overallocation * index.nparts[i]);
@@ -855,7 +807,7 @@ void csds_reader_generate_index_files(const struct csds_reader *reader,
   }
 
   /* Free the memory */
-  for (int type = 0; type < swift_type_count; type++) {
+  for (int type = 0; type < csds_type_count; type++) {
     csds_hashmap_free(current_state[type]);
     index_writer_free(&parts_created[type]);
     index_writer_free(&parts_removed[type]);
diff --git a/src/csds_time.c b/src/csds_time.c
index 7875af497c0cc190add18cd7d60745d8575a81f3..9853a899ff6d9c8e1f9e265d93c216cc83a7b636 100644
--- a/src/csds_time.c
+++ b/src/csds_time.c
@@ -171,7 +171,7 @@ int time_array_get_filename_savefile(const struct csds_logfile *log,
  */
 void time_array_save(struct time_array *t, const struct csds_logfile *log) {
   /* Get the filename of the saved file. */
-  char filename[STRING_SIZE + 50];
+  char filename[CSDS_STRING_SIZE + 50];
   int savefile = time_array_get_filename_savefile(log, filename);
 
   if (!savefile) {
@@ -207,7 +207,7 @@ void time_array_load(struct time_array *t, struct csds_index *index) {
   if (t->capacity != 0) time_array_free(t);
 
   /* Get the position of the time array. */
-  char *map = (char *)csds_index_get_removed_history(index, swift_type_count);
+  char *map = (char *)csds_index_get_removed_history(index, csds_type_count);
 
   /* Read the array */
   uint64_t size = 0;
@@ -232,7 +232,7 @@ void time_array_load(struct time_array *t, struct csds_index *index) {
  */
 int time_array_restore(struct time_array *t, struct csds_logfile *log) {
   /* Get the filename of the saved file. */
-  char filename[STRING_SIZE + 50];
+  char filename[CSDS_STRING_SIZE + 50];
   int savefile = time_array_get_filename_savefile(log, filename);
 
   if (!savefile) return 0;
@@ -330,7 +330,7 @@ double time_array_get_time(const struct time_array *t, const size_t offset) {
  */
 size_t time_array_get_index(const struct time_array *t, const size_t offset) {
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   if (!t) error_python("NULL pointer.");
 
   if (offset < t->records[0].offset || offset > t->records[t->size - 1].offset)
@@ -362,7 +362,7 @@ size_t time_array_get_index(const struct time_array *t, const size_t offset) {
     right = right - 1;
   }
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   if (t->records[right].offset > offset ||
       t->records[right + 1].offset <= offset) {
     error_python("Found the wrong element");
@@ -384,7 +384,7 @@ size_t time_array_get_index(const struct time_array *t, const size_t offset) {
 size_t time_array_get_index_from_time(const struct time_array *t,
                                       const double time) {
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   if (!t) error_python("NULL pointer.");
 
   if (time < t->records[0].time || time > t->records[t->size - 1].time)
@@ -415,7 +415,7 @@ size_t time_array_get_index_from_time(const struct time_array *t,
     right = right - 1;
   }
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   if (t->records[right].time > time || t->records[right + 1].time <= time) {
     error_python("Found the wrong element");
   }
diff --git a/src/csds_tools.c b/src/csds_tools.c
index a1f796d92c9e553abe006613aa46082c6875dd06..0f16c8b1f60bbd3f0e69d52b461cbc9420fe6901 100644
--- a/src/csds_tools.c
+++ b/src/csds_tools.c
@@ -37,8 +37,7 @@
  */
 int tools_get_next_record(const struct header *h, char *map, size_t *offset,
                           size_t file_size) {
-  if (header_is_forward(h))
-    return _tools_get_next_record_forward(h, map, offset);
+  if (header_is_forward(h)) return _tools_get_next_record_forward(map, offset);
   if (header_is_backward(h))
     return _tools_get_next_record_backward(h, map, offset, file_size);
   else
@@ -49,14 +48,12 @@ int tools_get_next_record(const struct header *h, char *map, size_t *offset,
  * @brief internal function of #tools_get_next_record. Should not be used
  * outside.
  *
- * @param h #header structure of the file
  * @param map file mapping
  * @param offset (Out) offset of the next record
  *
  * @return error code, -1 if no next record
  */
-int _tools_get_next_record_forward(const struct header *h, char *map,
-                                   size_t *offset) {
+int _tools_get_next_record_forward(char *map, size_t *offset) {
   size_t diff_offset = 0;
 
   /* Read the offset. */
@@ -82,7 +79,7 @@ int _tools_get_next_record_forward(const struct header *h, char *map,
  */
 int _tools_get_next_record_backward(const struct header *h, char *map,
                                     size_t *offset, size_t file_size) {
-#ifndef SWIFT_DEBUG_CHECKS
+#ifndef CSDS_DEBUG_CHECKS
   error_python("Should not be used, method too slow");
 #endif
   size_t current_offset = *offset;
@@ -144,7 +141,7 @@ size_t tools_reverse_offset(const struct header *h, char *file_map,
   map = file_map + cur_offset - prev_offset + CSDS_MASK_SIZE;
   map = csds_loader_io_write_data(map, CSDS_OFFSET_SIZE, &prev_offset);
 
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef CSDS_DEBUG_CHECKS
   mask_type prev_mask = 0;
   map = map - CSDS_MASK_SIZE - CSDS_OFFSET_SIZE;
   csds_loader_io_read_mask(map, &prev_mask, NULL);
@@ -152,9 +149,9 @@ size_t tools_reverse_offset(const struct header *h, char *file_map,
   /* Check if we are not mixing timestamp and particles */
   if ((prev_mask != TIMESTAMP_MASK && mask == TIMESTAMP_MASK) ||
       (prev_mask == TIMESTAMP_MASK && mask != TIMESTAMP_MASK))
-    error_python("Unexpected mask: %lu, got %lu.", mask, prev_mask);
+    error_python("Unexpected mask: %i, got %i.", mask, prev_mask);
 
-#endif  // SWIFT_DEBUG_CHECKS
+#endif  // CSDS_DEBUG_CHECKS
 
   return after_current_record;
 }
@@ -172,7 +169,7 @@ size_t tools_reverse_offset(const struct header *h, char *file_map,
  */
 size_t tools_check_record_consistency(const struct csds_reader *reader,
                                       size_t offset) {
-#ifndef SWIFT_DEBUG_CHECKS
+#ifndef CSDS_DEBUG_CHECKS
   error_python("Should not check in non debug mode.");
 #endif
 
@@ -262,6 +259,6 @@ void tools_print_progress(float percentage, int remaining_time,
   current += sprintf(current, "%.2is", sec);
 
   /* Print the string */
-  printf("\r%s", output);
+  printf("\r%s %s", clocks_get_timesincestart(), output);
   fflush(stdout);
 }
diff --git a/src/csds_tools.h b/src/csds_tools.h
index 4b01f6a826f4bc220079c2893f15c492d61fbab1..3012f0594709ea00354558c84e526a77b73e224e 100644
--- a/src/csds_tools.h
+++ b/src/csds_tools.h
@@ -23,26 +23,9 @@
 #define CSDS_CSDS_TOOLS_H
 
 #include "../config.h"
-
-/* Swift include */
-#include "../src/csds.h"
-#include "../src/csds_io.h"
-#include "../src/dimension.h"
-#include "../src/error.h"
-#include "../src/inline.h"
-#include "../src/part_type.h"
-
-#ifdef HAVE_PYTHON
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
-#include <Python.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define STRING_SIZE 200
+#include "csds_error.h"
+#include "csds_inline.h"
+#include "csds_logfile_writer.h"
 
 /* Define the size of all the fields. */
 #define member_size(type, member) sizeof(((type *)0)->member)
@@ -68,8 +51,7 @@ int tools_get_next_record(const struct header *h, char *map, size_t *offset,
                           size_t file_size);
 int _tools_get_next_record_backward(const struct header *h, char *map,
                                     size_t *offset, size_t file_size);
-int _tools_get_next_record_forward(const struct header *h, char *map,
-                                   size_t *offset);
+int _tools_get_next_record_forward(char *map, size_t *offset);
 size_t tools_reverse_offset(const struct header *h, char *map, size_t offset);
 size_t tools_check_record_consistency(const struct csds_reader *reader,
                                       size_t offset);
@@ -77,35 +59,4 @@ size_t tools_check_record_consistency(const struct csds_reader *reader,
 void tools_print_progress(float percentage, int remaining_time,
                           const char *message);
 
-#ifndef HAVE_PYTHON
-#define error_python(s, ...) error(s, ##__VA_ARGS__);
-#else
-#include "frameobject.h"
-
-/**
- * @brief Print the python trace back
- */
-__attribute__((always_inline)) INLINE static void csds_loader_print_traceback(
-    void) {
-
-  PyGILState_STATE gstate = PyGILState_Ensure();
-
-  PyFrameObject *frame = PyEval_GetFrame();
-  int lineno = PyFrame_GetLineNumber(frame);
-  PyObject *py_filename = frame->f_code->co_filename;
-  const char *filename = PyUnicode_AsUTF8(py_filename);
-  message("File %s, line: %i", filename, lineno);
-
-  Py_DECREF(py_filename);
-  Py_DECREF(frame);
-  PyGILState_Release(gstate);
-}
-
-#define error_python(s, ...)       \
-  ({                               \
-    csds_loader_print_traceback(); \
-    error(s, ##__VA_ARGS__);       \
-  })
-#endif
-
 #endif  // CSDS_CSDS_TOOLS_H
diff --git a/src/csds_version.h.in b/src/csds_version.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..31b3eed504536f1ba770b3ea7f6be3f57abcca6a
--- /dev/null
+++ b/src/csds_version.h.in
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * This file is part of CSDS.
+ * Copyright (c) 2021 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/>.
+ *
+ ******************************************************************************/
+/**
+ * @brief This file only contains the information about the version.
+ */
+#ifndef CSDS_VERSION_H
+#define CSDS_VERSION_H
+
+/* WARNING THIS FILE SHOULD NOT INCLUDE CONFIG.H*/
+
+/* Version numbers */
+#define CSDS_MAJOR_VERSION @major_version@
+#define CSDS_MINOR_VERSION @minor_version@
+
+#endif  // CSDS_VERSION_H
diff --git a/src/quick_sort.c b/src/quick_sort.c
index c9946755d39c5bc840f43ebd1881143b1bad0f7c..a5e364522680d05d4de4836d1520e9176108172b 100644
--- a/src/quick_sort.c
+++ b/src/quick_sort.c
@@ -23,6 +23,9 @@
 /* Include local headers */
 #include "csds_index.h"
 
+/* Include standard headers */
+#include <math.h>
+
 struct qstack {
   int64_t lo;
   int64_t hi;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 421ea551cae0fd351f5d8ba67770ed972f363e9b..215adbd2221d74712996ba83daab1c5b295e9600 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,4 @@
-# This file is part of SWIFT.
+# This file is part of CSDS.
 # Copyright (c) 2019 loic.hausammann@epfl.ch.
 #
 # This program is free software: you can redistribute it and/or modify
@@ -15,9 +15,16 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 # Add the source directory and the non-standard paths to the included library headers to CFLAGS
-AM_CFLAGS = $(PYTHON_INCS) -I$(top_srcdir)/src -I$(top_srcdir)/csds/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS)
+AM_CFLAGS = $(OPENMP_CFLAGS) $(PYTHON_INCS) -I$(top_srcdir)/src
 
-AM_LDFLAGS = -L../../src/.libs/ ../src/.libs/libcsds.a $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) $(PYTHON_LIBS) -lswiftsim
+AM_LDFLAGS = ../src/.libs/libcsds.a ../src/.libs/libcsds_writer.a $(PYTHON_LIBS)
+
+if HAVEPYTHON
+# The main python structure is dependent on the version, thus we need to
+# remove this one in order to be safe.
+PYTHON_EXTRA_COMPILER_FLAG = -Wno-missing-field-initializers -Wno-cast-function-type -Wno-unused-function
+endif
+AM_CFLAGS += $(PYTHON_EXTRA_COMPILER_FLAG)
 
 # List of programs and scripts to run in the test suite
 TESTS = testLogfileHeader testLogfileReader testTimeArray testQuickSort testVirtualReality
@@ -27,8 +34,8 @@ TESTS += testHashmap
 check_PROGRAMS = testLogfileHeader testLogfileReader testTimeArray testQuickSort testVirtualReality
 check_PROGRAMS += testHashmap
 
-# Rebuild tests when SWIFT is updated.
-$(check_PROGRAMS): ../../src/.libs/libswiftsim.a ../src/.libs/libcsds.a
+# Rebuild tests when CSDS is updated.
+$(check_PROGRAMS): ../src/.libs/libcsds.a ../src/.libs/libcsds_writer.a
 
 # Sources for the individual programs
 testLogfileHeader_SOURCES = testLogfileHeader.c
@@ -39,4 +46,4 @@ testVirtualReality_SOURCES = testVirtualReality.c
 testHashmap_SOURCES = testHashmap.c
 
 # Files necessary for distribution
-EXTRA_DIST = testLogfileHeader.yml testLogfileReader.yml
+EXTRA_DIST = 
diff --git a/tests/generate_log.h b/tests/generate_log.h
index 8a0ca0d2acd5da8d38e427c0f7567f731610256d..b2161ca71fef27812c2cdcfafe9afd8082dec11e 100644
--- a/tests/generate_log.h
+++ b/tests/generate_log.h
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * This file is part of SWIFT.
+ * This file is part of CSDS.
  * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch)
  *
  * This program is free software: you can redistribute it and/or modify
@@ -18,63 +18,153 @@
  ******************************************************************************/
 
 /* Include config */
-#include "../../config.h"
+#include "config.h"
 
 /* Local headers */
-#include "csds.h"
-#include "csds_io.h"
-#include "engine.h"
-#include "hydro.h"
+#include "csds_logfile_writer.h"
 
-/* Not all the fields are written at every step.
- * Here we define how often a few fields are written.
- */
-#define period_rho 2
-#define period_h 4
-#define const_time_base 1e-4
+/* Define the masks */
+// The two first are already picked (special flags + timestamp)
+#define MASK_POSITION (1 << 2)
+#define MASK_ID (1 << 3)
+
+#define TEST_NUMBER_MASKS 2
+#define number_steps 100
+
+struct csds_part {
+  /* Position */
+  double x[3];
+
+  /* IDs of the particle */
+  long long id;
+
+  /* Offset of the last record */
+  uint64_t last_offset;
+
+  /* Time bin (number of steps skipped) */
+  int time_bin;
+};
 
 /**
  * @brief Generate the data of a bunch of particles.
  *
  * @param parts The list of particles.
- * @param xparts The list of extra particles.
  * @param nparts The number of particles.
  */
-void generate_particles(struct part *parts, struct xpart *xparts,
-                        size_t nparts) {
-  struct hydro_space hs;
+void generate_particles(struct csds_part *parts, size_t nparts) {
 
   for (size_t i = 0; i < nparts; i++) {
-    /* Set internal energy. */
-    hydro_set_init_internal_energy(&parts[i], 100);
-
-    /* Initialize particle. */
-    hydro_first_init_part(&parts[i], &xparts[i]);
-    hydro_init_part(&parts[i], &hs);
-    csds_part_data_init(&xparts[i].csds_data);
-    parts[i].gpart = NULL;
+    parts[i].id = i;
+    parts[i].last_offset = 0;
 
     for (int j = 0; j < 3; j++) {
-      parts[i].x[j] = 0;
-      parts[i].v[j] = (j == 0) ? -1 : 0;
-      parts[i].a_hydro[j] = (j == 1) ? 1e-2 : 0;
-      xparts[i].a_grav[j] = 0;
+      parts[i].x[j] = j;
     }
-    parts[i].h = 15;
-    parts[i].rho = 50;
-    parts[i].id = i;
-    hydro_set_mass(&parts[i], 1.5);
 
     /* Add time bin in order to skip particles. */
     parts[i].time_bin = (i % 10) + 1;
   }
 }
 
-/** Provides a integer time given the step number.*/
-integertime_t get_integer_time(int step) { return step; }
+/** @brief Get a double value from an int */
+double get_double_time(int i) { return i * 0.12; }
+
+/** @brief Get an integertime_t from an int */
+integertime_t get_integer_time(int i) { return 100 * i; }
+
+/**
+ * @brief Write a timestamp into the logfile.
+ *
+ * @param log The #csds_logfile_writer.
+ * @param ti_int The time as an integertime_t
+ * @param ti_double The time as a double
+ * @param offset (in) The last offset of the timestamp. (out) The new offset.
+ */
+void csds_log_timestamp(struct csds_logfile_writer *log, integertime_t ti_int,
+                        double ti_double, size_t *offset) {
+
+  /* Start by computing the size of the message. */
+  const int size = TIMESTAMP_SIZE + CSDS_HEADER_SIZE;
+
+  /* Allocate a chunk of memory in the logfile of the right size. */
+  size_t offset_new;
+  char *buff = (char *)csds_logfile_writer_get(log, size, &offset_new);
+
+  /* Write the header. */
+  unsigned int mask = TIMESTAMP_MASK;
+  buff = csds_write_record_header(buff, &mask, offset, offset_new);
+
+  /* Store the timestamp. */
+  memcpy(buff, &ti_int, sizeof(integertime_t));
+  buff += sizeof(integertime_t);
+
+  /* Store the time. */
+  memcpy(buff, &ti_double, sizeof(double));
+
+  /* Update the log message offset. */
+  *offset = offset_new;
+}
+
+/**
+ * @brief Write a particle into the logfile.
+ *
+ * @param log The #csds_logfile_writer.
+ * @param part The #csds_part to log.
+ */
+void csds_log_part(struct csds_logfile_writer *log, struct csds_part *part,
+                   const enum csds_special_flags flag) {
+  const size_t size_flag = flag == csds_flag_none ? 0 : SPECIAL_FLAGS_SIZE;
+  const size_t size_total =
+      sizeof(part->x) + sizeof(part->id) + CSDS_HEADER_SIZE + size_flag;
+
+  // For performances, this should never be done on a single
+  // particle at a time.
+  size_t offset = 0;
+  char *buff = (char *)csds_logfile_writer_get(log, size_total, &offset);
+  const unsigned int mask_flag =
+      flag == csds_flag_none ? 0 : SPECIAL_FLAGS_MASK;
+  const unsigned int mask = MASK_POSITION | MASK_ID | mask_flag;
+
+  /* Write the header */
+  buff = csds_write_record_header(buff, &mask, &part->last_offset, offset);
+  part->last_offset = offset;
+
+  /* Write the special flag */
+  if (flag != csds_flag_none) {
+    const uint32_t data = csds_pack_flags_and_data(flag, 0, csds_type_gas);
+    memcpy(buff, &data, sizeof(uint32_t));
+    buff += sizeof(uint32_t);
+  }
+
+  /* Write the position */
+  memcpy(buff, part->x, sizeof(part->x));
+  buff += sizeof(part->x);
+
+  /* Write the ID */
+  memcpy(buff, &part->id, sizeof(part->id));
+  buff += sizeof(part->id);
+}
+
+/**
+ * @brief Write all the particles into the logfile.
+ *
+ * @param log The #csds_logfile_writer.
+ * @param parts The #csds_part to log.
+ * @param nparts The number of particles to log.
+ * @param first_log Is it the first or last log?
+ */
+void csds_log_all_particles(struct csds_logfile_writer *log,
+                            struct csds_part *part, size_t nparts,
+                            int first_log) {
+
+  const enum csds_special_flags flag =
+      first_log ? csds_flag_create : csds_flag_delete;
 
-/** Provides a double time given the step number. */
-double get_double_time(int step) { return step * const_time_base; }
+#pragma omp parallel for
+  for (size_t i = 0; i < nparts; i++) {
+    csds_log_part(log, &part[i], flag);
+  }
+}
 
 /**
  * @brief Write a few particles during multiple time steps.
@@ -82,31 +172,29 @@ double get_double_time(int step) { return step * const_time_base; }
  * As only the csds is tested, there is no need to really
  * evolve the particles.
  *
- * @param log The #csds_writer.
- * @param e The #engine.
+ * @param log The #csds_logfile_writer.
+ * @param parts The particles to "simulate".
+ * @param nparts The number of particles
  */
-void write_particles(struct csds_writer *log, struct engine *e) {
-
-  size_t nparts = e->total_nr_parts;
-  struct part *parts = e->s->parts;
-  struct xpart *xparts = e->s->xparts;
-
-  const int number_steps = 100;
+void write_particles(struct csds_logfile_writer *log, struct csds_part *parts,
+                     size_t nparts, size_t *timestamp_offset) {
 
   /* Loop over all the steps. */
   for (int i = 0; i < number_steps; i++) {
-    e->time = get_double_time(i);
-    e->ti_current = get_integer_time(i);
     integertime_t ti_int = get_integer_time(i);
     double ti_double = get_double_time(i);
 
     /* Mark the current time step in the particle csds file. */
-    csds_log_timestamp(log, ti_int, ti_double, &log->timestamp_offset);
+    csds_log_timestamp(log, ti_int, ti_double, timestamp_offset);
+
     /* Make sure that we have enough space in the particle csds file
      * to store the particles in current time step. */
-    csds_ensure_size(log, e);
+    // Here we need to have enough place for the part + the record header.
+    csds_logfile_writer_ensure(log, 1.2 * nparts * sizeof(struct csds_part),
+                               5 * nparts * sizeof(struct csds_part));
 
     /* Loop over all the particles. */
+#pragma omp parallel for
     for (size_t j = 0; j < nparts; j++) {
 
       /* Skip some particles. */
@@ -116,15 +204,26 @@ void write_particles(struct csds_writer *log, struct engine *e) {
       parts[j].x[0] = i;
 
       // TODO write only a few masks at the time
-
-      csds_log_part(log, &parts[j], &xparts[j], e, /* log_all */ 0,
-                    /* flag */ 0, /* flag_data */ 0);
+      csds_log_part(log, &parts[j], csds_flag_none);
     }
   }
 }
 
-void generate_log(struct swift_params *params, struct part *parts,
-                  struct xpart *xparts, size_t nparts) {
+#define max(a, b)           \
+  ({                        \
+    __typeof__(a) _a = (a); \
+    __typeof__(b) _b = (b); \
+    _a > _b ? _a : _b;      \
+  })
+
+/**
+ * @brief Generate a logfile.
+ *
+ * @param parts The array of #csds_part to use
+ * @param nparts The number of particles.
+ * @param filename The filename of the logfile.
+ */
+void generate_log(struct csds_part *parts, size_t nparts, char *filename) {
 
 #ifdef HAVE_PYTHON
   message(
@@ -132,72 +231,91 @@ void generate_log(struct swift_params *params, struct part *parts,
       "initialized. If you obtain a segmentation fault, please recompile "
       "without python");
 #endif
+
   /* Initialize the particles */
-  generate_particles(parts, xparts, nparts);
-
-  /* initialize the engine */
-  struct engine e;
-  e.policy = engine_policy_hydro;
-  e.total_nr_parts = nparts;
-  e.total_nr_gparts = 0;
-  e.total_nr_sparts = 0;
-  e.total_nr_bparts = 0;
-  e.verbose = 1;
-  e.ti_current = 0;
-  e.time = 0;
-  e.time_base = const_time_base;
-  e.time_begin = 0;
-  threadpool_init(&e.threadpool, 1);
-  struct space s;
-  e.s = &s;
-  s.xparts = xparts;
-  s.parts = parts;
-  s.gparts = NULL;
-  s.nr_parts = nparts;
-  s.nr_gparts = 0;
-  s.nr_sparts = 0;
-  s.nr_bparts = 0;
-  s.nr_sinks = 0;
-  s.nr_inhibited_parts = 0;
-  s.nr_inhibited_gparts = 0;
-  s.nr_inhibited_sparts = 0;
-  s.nr_inhibited_bparts = 0;
-  s.nr_inhibited_sinks = 0;
-  s.nr_extra_gparts = 0;
-  s.nr_extra_parts = 0;
-  s.nr_extra_sparts = 0;
-  s.nr_extra_bparts = 0;
-  s.nr_extra_sinks = 0;
-  struct csds_writer log;
-  e.csds = &log;
+  generate_particles(parts, nparts);
 
   /* Initialize the writer */
-  csds_init(&log, &e, params);
+  struct csds_logfile_writer log;
+  const size_t init_size = max(sizeof(struct csds_part) * 1000,
+                               1.5 * nparts * sizeof(struct csds_part));
+  csds_logfile_writer_init(&log, filename, init_size);
 
   /* Write file header */
-  csds_write_file_header(&log);
+  char *first_offset = csds_logfile_writer_write_begining_header(&log);
+
+  /* Write the number of masks */
+  size_t file_offset = 0;
+  // Add timestamp + special flags
+  const unsigned int number_masks = TEST_NUMBER_MASKS + 2;
+  csds_write_data(&log, &file_offset, sizeof(unsigned int), &number_masks);
+
+  /* Write the masks */
+  const char *names[TEST_NUMBER_MASKS + 2] = {
+      SPECIAL_FLAGS_NAME,
+      TIMESTAMP_NAME,
+      "Coordinates",
+      "ParticleIDs",
+  };
+  const unsigned int sizes[TEST_NUMBER_MASKS + 2] = {
+      SPECIAL_FLAGS_SIZE,
+      TIMESTAMP_SIZE,
+      sizeof(parts->x),
+      sizeof(parts->id),
+  };
+  for (unsigned int i = 0; i < number_masks; i++) {
+    char tmp[CSDS_STRING_SIZE];
+    strcpy(tmp, names[i]);
+    csds_write_data(&log, &file_offset, CSDS_STRING_SIZE, tmp);
+    csds_write_data(&log, &file_offset, sizeof(unsigned int), &sizes[i]);
+  }
+
+  /* Write the number of fields per particle types */
+  const int n_fields_type = 2;
+  int number_fields[csds_type_count];
+  for (int i = 0; i < csds_type_count; i++) {
+    number_fields[i] = n_fields_type;
+  }
+  csds_write_data(&log, &file_offset, csds_type_count * sizeof(int),
+                  number_fields);
+
+  /* Write the order for each particle type */
+  for (int i = 0; i < csds_type_count; i++) {
+    const int order[] = {2, 3};
+    csds_write_data(&log, &file_offset, n_fields_type * sizeof(int), order);
+  }
+
+  /* Write the end of the header */
+  csds_logfile_writer_write_end_header(&log, first_offset);
 
   /* Mark the current time step in the particle csds file. */
-  csds_log_timestamp(&log, e.ti_current, e.time, &log.timestamp_offset);
+  integertime_t ti_current = 0;
+  double time = 0;
+  size_t timestamp_offset = 0;
+  csds_log_timestamp(&log, ti_current, time, &timestamp_offset);
+
   /* Make sure that we have enough space in the particle csds file
    * to store the particles in current time step. */
-  csds_ensure_size(&log, &e);
+  csds_logfile_writer_ensure(&log, 1.2 * nparts * sizeof(struct csds_part),
+                             5 * nparts * sizeof(struct csds_part));
 
   /* Log all the particles before starting */
-  csds_log_all_particles(&log, &e, /* first_log */ 1);
+  csds_log_all_particles(&log, parts, nparts, /* first_log */ 1);
 
   /* Write particles */
-  write_particles(&log, &e);
+  write_particles(&log, parts, nparts, &timestamp_offset);
 
   /* Write a sentinel timestamp */
-  csds_log_timestamp(e.csds, e.ti_current, e.time, &e.csds->timestamp_offset);
+  ti_current = get_integer_time(number_steps);
+  time = get_double_time(number_steps);
+  csds_log_timestamp(&log, ti_current, time, &timestamp_offset);
 
   /* Write all the particles at the end */
-  csds_log_all_particles(e.csds, &e, /* first_log */ 0);
+  csds_log_all_particles(&log, parts, nparts, /* first_log */ 0);
 
   /* Write a sentinel timestamp */
-  csds_log_timestamp(e.csds, e.ti_current, e.time, &e.csds->timestamp_offset);
+  csds_log_timestamp(&log, ti_current, time, &timestamp_offset);
 
   /* Cleanup the memory */
-  csds_free(&log);
+  csds_logfile_writer_close(&log);
 }
diff --git a/tests/testHashmap.c b/tests/testHashmap.c
index 9592b13b9dd2a1558e0c86b9de6351ff28f98e16..4ce26bce16cf538268734325f6172ab4858a152b 100644
--- a/tests/testHashmap.c
+++ b/tests/testHashmap.c
@@ -6,17 +6,16 @@
 // Use of this source code is governed by an MIT-style
 // license that can be found in the LICENSE file
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
 /* CSDS header */
+#include "csds_error.h"
 #include "csds_hashmap.h"
 
-/* SWIFT headers */
-#include "error.h"
-
 #define N 10000
 
 static void shuffle(struct index_data *array, size_t numels) {
@@ -41,7 +40,7 @@ static size_t deepcount(struct csds_hashmap *map) {
 
 static void all(void) {
   struct index_data *vals;
-  vals = malloc(N * sizeof(struct index_data));
+  vals = (struct index_data *)malloc(N * sizeof(struct index_data));
   if (vals == NULL) {
     error("Failed to allocate the index array");
   }
@@ -108,6 +107,7 @@ static void all(void) {
 
   free(test);
   csds_hashmap_free(map);
+  free(vals);
 }
 
 #define bench(name, N, code)                                                  \
diff --git a/tests/testLogfileHeader.c b/tests/testLogfileHeader.c
index 6d1e0adcb89808511a834c4370d0ec4bebf7625f..60f29b4bded751aaa307f3ebc118e37435d7591a 100644
--- a/tests/testLogfileHeader.c
+++ b/tests/testLogfileHeader.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * This file is part of SWIFT.
+ * This file is part of CSDS.
  * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch)
  *
  * This program is free software: you can redistribute it and/or modify
@@ -17,12 +17,17 @@
  *
  ******************************************************************************/
 
+/* Include local headers */
 #include "csds_header.h"
 #include "csds_logfile.h"
+#include "csds_parser.h"
 #include "csds_reader.h"
-#include "swift.h"
+#include "generate_log.h"
 
-int main(int argc, char *argv[]) {
+/* Include standard headers */
+#include <assert.h>
+
+int main(void) {
 
   /*
     First generate the file.
@@ -30,38 +35,13 @@ int main(int argc, char *argv[]) {
 
   message("Generating the dump.");
   /* Create required structures. */
-  struct csds_writer log;
-  struct swift_params params;
-  char filename[200] = "testLogfileHeader.yml";
-
-  /* Read parameters. */
-  parser_read_file(filename, &params);
-
-  /* Initialize the engine */
-  struct engine e;
-  e.policy =
-      engine_policy_hydro | engine_policy_stars | engine_policy_self_gravity;
-
-  /* Initialize the csds. */
-  csds_init(&log, &e, &params);
-
-  /* get dump filename. */
-  char dump_filename[PARSER_MAX_LINE_SIZE];
-  strcpy(dump_filename, log.base_name);
-  strcat(dump_filename, "_0000.dump");
+  char filename[200] = "test_header_0000.dump";
 
   /* Write file header. */
-  csds_write_file_header(&log);
-
-  /* Copy the masks */
-  const int total_number_fields = log.total_number_fields;
-  struct csds_field *list_fields = (struct csds_field *)malloc(
-      total_number_fields * sizeof(struct csds_field));
-  memcpy(list_fields, log.list_fields,
-         total_number_fields * sizeof(struct csds_field));
+  struct csds_part *parts = NULL;
+  size_t nparts = 0;
+  generate_log(parts, nparts, filename);
 
-  /* clean memory. */
-  csds_free(&log);
   /*
     Then read the file.
   */
@@ -76,7 +56,7 @@ int main(int argc, char *argv[]) {
   reader.verbose = 1;
 
   /* Read the header */
-  csds_logfile_init_from_file(logfile, dump_filename, &reader,
+  csds_logfile_init_from_file(logfile, filename, &reader,
                               /* only_header */ 1);
   /*
     Finally check everything.
@@ -84,26 +64,23 @@ int main(int argc, char *argv[]) {
 
   struct header *h = &logfile->header;
   message("Checking versions.");
-  assert(h->major_version == csds_major_version);
-  assert(h->minor_version == csds_minor_version);
-
-  message("Checking offset of first record");
-  assert(h->offset_first_record == logfile->log.mmap_size);
+  assert(h->major_version == CSDS_MAJOR_VERSION);
+  assert(h->minor_version == CSDS_MINOR_VERSION);
 
   message("Checking number of masks");
   /* Compute the number of masks */
   int count_fields = 2;  // Timestamp + special flags
-  for (int type = 0; type < swift_type_count; type++) {
+  for (int type = 0; type < csds_type_count; type++) {
     count_fields += h->number_fields[type];
     /* Remove the copies of the special flags */
     if (h->number_fields[type] != 0) count_fields -= 1;
   }
-  assert(total_number_fields == count_fields);
+  const int number_masks_ref = csds_type_count * TEST_NUMBER_MASKS + 2;
+  assert(number_masks_ref == count_fields);
 
   message("Checking offset direction");
   assert(h->offset_direction == csds_offset_backward);
 
-  free(list_fields);
   csds_logfile_free(logfile);
   return 0;
 }
diff --git a/tests/testLogfileReader.c b/tests/testLogfileReader.c
index c30bc4b97949ab6c429cb33c6d65019df09be8c8..92000033fdc6ea029f3e0c21febffa58579af396 100644
--- a/tests/testLogfileReader.c
+++ b/tests/testLogfileReader.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * This file is part of SWIFT.
+ * This file is part of CSDS.
  * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch).
  *
  * This program is free software: you can redistribute it and/or modify
@@ -22,16 +22,16 @@
 #include "csds_loader_io.h"
 #include "csds_particle.h"
 #include "csds_reader.h"
-#include "swift.h"
 
 /* Tests header */
 #include "generate_log.h"
 
+#include <assert.h>
+
 #define number_parts 100
-#define max_step 99
 
 /** Count the number of active particles. */
-int get_number_active_particles(int step, struct part *p) {
+int get_number_active_particles(int step, struct csds_part *p) {
   int count = 0;
   for (int i = 0; i < number_parts; i++) {
     if (step % p[i].time_bin == 0) count += 1;
@@ -44,8 +44,7 @@ int get_number_active_particles(int step, struct part *p) {
  *
  * @param reader The #csds_reader.
  */
-void check_data(struct csds_reader *reader, struct part *parts,
-                struct xpart *xparts) {
+void check_data(struct csds_reader *reader, struct csds_part *parts) {
 
   /* No need to check the header, this is already done in testHeader.c */
 
@@ -54,11 +53,11 @@ void check_data(struct csds_reader *reader, struct part *parts,
   struct header *h = &reader->log.header;
 
   /* Create a particle */
-  void **output = malloc(h->number_fields[swift_type_gas] * sizeof(void *));
-  for (int i = 0; i < h->number_fields[swift_type_gas]; i++) {
-    output[i] = malloc(h->fields[swift_type_gas][i].field.size);
-    message("%i %i %i", i, h->fields[swift_type_gas][i].field.field,
-            h->fields[swift_type_gas][i].field.position);
+  void **output = malloc(h->number_fields[csds_type_gas] * sizeof(void *));
+  for (int i = 0; i < h->number_fields[csds_type_gas]; i++) {
+    output[i] = malloc(h->fields[csds_type_gas][i].field.size);
+    message("%i %i %i", i, h->fields[csds_type_gas][i].field.field,
+            h->fields[csds_type_gas][i].field.position);
   }
 
   /* Define a few variables */
@@ -75,21 +74,9 @@ void check_data(struct csds_reader *reader, struct part *parts,
 
   /* Get all the fields */
   const struct field_information *field_id =
-      header_get_field_from_name(h, "ParticleIDs", swift_type_gas);
+      header_get_field_from_name(h, "ParticleIDs", csds_type_gas);
   const struct field_information *field_pos =
-      header_get_field_from_name(h, "Coordinates", swift_type_gas);
-  const struct field_information *field_vel =
-      header_get_field_from_name(h, "Velocities", swift_type_gas);
-  const struct field_information *field_acc =
-      header_get_field_from_name(h, "Accelerations", swift_type_gas);
-  const struct field_information *field_mass =
-      header_get_field_from_name(h, "Masses", swift_type_gas);
-  const struct field_information *field_u =
-      header_get_field_from_name(h, "InternalEnergies", swift_type_gas);
-  const struct field_information *field_h =
-      header_get_field_from_name(h, "SmoothingLengths", swift_type_gas);
-  const struct field_information *field_rho =
-      header_get_field_from_name(h, "Densities", swift_type_gas);
+      header_get_field_from_name(h, "Coordinates", csds_type_gas);
 
   /* Loop over each record. */
   for (size_t offset =
@@ -107,7 +94,6 @@ void check_data(struct csds_reader *reader, struct part *parts,
         Check that we are really increasing the id in the logfile.
         See the writing part to see that we are always increasing the id.
       */
-
       const uint64_t current_id = *(uint64_t *)output[field_id->field.position];
       if (previous_id != id_flag && previous_id >= current_id) {
         error("Wrong particle found");
@@ -117,10 +103,8 @@ void check_data(struct csds_reader *reader, struct part *parts,
       /* Get the corresponding particle */
       if (current_id >= number_parts) error("Wrong id %li", current_id);
 
-      struct part *p = &parts[current_id];
+      struct csds_part *p = &parts[current_id];
       const double *pos = (double *)output[field_pos->field.position];
-      const float *vel = (float *)output[field_vel->field.position];
-      const float *acc = (float *)output[field_acc->field.position];
 
       /* Check the record's data. */
       for (int i = 0; i < 3; i++) {
@@ -128,38 +112,15 @@ void check_data(struct csds_reader *reader, struct part *parts,
         if (i == 0) {
           double tmp = step;
           /* At the end, we are not updating the particle */
-          if (step >= max_step) {
-            tmp = max_step - max_step % p->time_bin;
+          if (step >= number_steps) {
+            int n_1 = number_steps - 1;
+            tmp = n_1 - (n_1 % p->time_bin);
           }
           assert(tmp == pos[i]);
         } else
-          assert(p->x[i] == pos[i]);
-        assert(p->v[i] == vel[i]);
-        assert(p->a_hydro[i] == acc[i]);
+          assert(p->x[i] == i);
       }
 
-      const float energy = *(float *)output[field_u->field.position];
-      assert(p->u == energy);
-      const float mass = *(float *)output[field_mass->field.position];
-      assert(p->mass == mass);
-
-      /* Check optional fields. */
-      // int number_steps = step / p->time_bin;
-      // TODO check only every few steps
-      const float current_h = *(float *)output[field_h->field.position];
-      assert(p->h == current_h);
-      /* if (number_steps % period_h == 0 || step > max_step) { */
-      /*   assert(p->h == lp.h); */
-      /* } else { */
-      /*   assert(-1 == lp.h); */
-      /* } */
-      const float rho = *(float *)output[field_rho->field.position];
-      assert(p->rho == rho);
-      /* if (number_steps % period_rho == 0 || step > max_step) { */
-      /*   assert(p->rho == lp.rho); */
-      /* } else { */
-      /*   assert(-1 == lp.rho); */
-      /* } */
     }
     /* Time stamp case. */
     else {
@@ -183,19 +144,19 @@ void check_data(struct csds_reader *reader, struct part *parts,
       count = 0;
 
       /* Check the record's data. */
-      const int tmp_step = step >= max_step ? max_step : step;
+      const int tmp_step = step >= number_steps ? number_steps : step;
       assert(time == get_double_time(tmp_step));
     }
   }
 
   /* Cleanup */
-  for (int i = 0; i < h->number_fields[swift_type_gas]; i++) {
+  for (int i = 0; i < h->number_fields[csds_type_gas]; i++) {
     free(output[i]);
   }
   free(output);
 }
 
-int main(int argc, char *argv[]) {
+int main(void) {
 
   /*
     First generate the file.
@@ -204,25 +165,16 @@ int main(int argc, char *argv[]) {
   message("Generating the dump.");
 
   /* Create required structures. */
-  struct swift_params params;
-  char filename[200] = "testLogfileReader.yml";
-
-  /* Read parameters. */
-  parser_read_file(filename, &params);
+  char filename[200] = "test_reader_0000.dump";
 
   /* Initialize the particles. */
-  struct part *parts;
-  if ((parts = (struct part *)malloc(sizeof(struct part) * number_parts)) ==
-      NULL)
+  struct csds_part *parts;
+  if ((parts = (struct csds_part *)malloc(sizeof(struct csds_part) *
+                                          number_parts)) == NULL)
     error("Failed to allocate particles array.");
 
-  struct xpart *xparts;
-  if ((xparts = (struct xpart *)malloc(sizeof(struct xpart) * number_parts)) ==
-      NULL)
-    error("Failed to allocate xparticles array.");
-
   /* Write a 'simulation' */
-  generate_log(&params, parts, xparts, number_parts);
+  generate_log(parts, number_parts, filename);
 
   /*
     Then read the file.
@@ -237,11 +189,8 @@ int main(int argc, char *argv[]) {
   reader.verbose = 1;
 
   /* Read the header. */
-  char basename[200];
-  parser_get_param_string(&params, "CSDS:basename", basename);
-  strcat(basename, "_0000");
+  char basename[200] = "test_reader_0000";
   csds_reader_init(&reader, basename, /* verbose */ 1,
-                   /* number_threads */ 1,
                    /* number_index*/ 5,
                    /* restart */ 0);
 
@@ -249,11 +198,10 @@ int main(int argc, char *argv[]) {
     Finally check everything.
   */
 
-  check_data(&reader, parts, xparts);
+  check_data(&reader, parts);
 
   /* Do some cleanup. */
   free(parts);
-  free(xparts);
   csds_reader_free(&reader);
 
   return 0;
diff --git a/tests/testQuickSort.c b/tests/testQuickSort.c
index f8ad6d4968f21be516181d80582095f69c6617de..f2056bcb3eb3379127fc61bd801dc21037d0e047 100644
--- a/tests/testQuickSort.c
+++ b/tests/testQuickSort.c
@@ -1,6 +1,6 @@
 
 /*******************************************************************************
- * This file is part of SWIFT.
+ * This file is part of CSDS.
  * Copyright (c) 2019 Loic Hausammann (loic.hausammann@epfl.ch)
  *
  * This program is free software: you can redistribute it and/or modify
@@ -18,7 +18,6 @@
  *
  ******************************************************************************/
 
-#include "memswap.h"
 #include "quick_sort.h"
 
 #define N 10000
@@ -41,7 +40,9 @@ void init_array(struct index_data *data) {
     int j = rand() % N;
 
     /* Swap the two elements */
-    memswap(&data[i], &data[j], sizeof(struct index_data));
+    struct index_data tmp = data[i];
+    data[i] = data[j];
+    data[j] = tmp;
   }
 }
 
@@ -66,7 +67,7 @@ void print_array(struct index_data *data) {
   }
 }
 
-int main(int argc, char *argv[]) {
+int main(void) {
 
   /* Create the array */
   struct index_data *data =
diff --git a/tests/testTimeArray.c b/tests/testTimeArray.c
index a86db3ff4ea37f2ff088b2484050637ef4739985..48122c72fd01b86c992a0319cc3b386c37664573 100644
--- a/tests/testTimeArray.c
+++ b/tests/testTimeArray.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * This file is part of SWIFT.
+ * This file is part of CSDS.
  * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch)
  *
  * This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
 
 #include "csds_time.h"
 
+#include <assert.h>
 #include <stdlib.h>
 #include <time.h>
 
@@ -26,7 +27,7 @@
 #define TIME_BASE 0.04
 #define OFFSET_BASE 1000
 
-int main(int argc, char *argv[]) {
+int main(void) {
 
   /* Check that we are really testing the reallocation */
   if (NUMBER_OF_ELEMENT < CSDS_TIME_INIT_SIZE) {
diff --git a/tests/testVirtualReality.c b/tests/testVirtualReality.c
index d7ec8345a08f1c4fb54caffa5ec2ceb81e36f855..1f933cf820025ed3f1eb7b16082ac27c83fd3612 100644
--- a/tests/testVirtualReality.c
+++ b/tests/testVirtualReality.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * This file is part of SWIFT.
+ * This file is part of CSDS.
  * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch)
  *                    Florian Cabot (florian.cabot@epfl.ch)
  *
@@ -25,12 +25,10 @@
 #include <stdlib.h>
 
 /* Local include */
-#include "csds.h"
+#include "csds_logfile_writer.h"
 #include "csds_reader.h"
 #include "generate_log.h"
-#include "hydro.h"
 
-#define number_steps 10.
 #define number_parts 100
 
 /**
@@ -38,35 +36,24 @@
  * The idea is to simply read a snapshot at a given time and
  * then simply advance in time the particles.
  */
-int main(int argc, char *argv[]) {
+int main(void) {
   /* Create required structures. */
-  struct swift_params params;
-  char filename[200] = "testVirtualReality.yml";
-
-  /* Read parameters. */
-  parser_read_file(filename, &params);
+  char filename[200] = "testvr_0000.dump";
 
   /* Initialize the particles. */
-  struct part *parts;
-  if ((parts = (struct part *)malloc(sizeof(struct part) * number_parts)) ==
-      NULL)
+  struct csds_part *parts;
+  if ((parts = (struct csds_part *)malloc(sizeof(struct csds_part) *
+                                          number_parts)) == NULL)
     error("Failed to allocate particles array.");
 
-  struct xpart *xparts;
-  if ((xparts = (struct xpart *)malloc(sizeof(struct xpart) * number_parts)) ==
-      NULL)
-    error("Failed to allocate xparticles array.");
-
   /* Write a 'simulation' */
-  generate_log(&params, parts, xparts, number_parts);
+  generate_log(parts, number_parts, filename);
 
   /* Initialize the reader */
   struct csds_reader reader;
-  char basename[200];
-  parser_get_param_string(&params, "CSDS:basename", basename);
-  strcat(basename, "_0000");
+  char basename[200] = "testvr_0000";
   csds_reader_init(&reader, basename,
-                   /* Verbose */ 2, /* number_threads */ 1,
+                   /* Verbose */ 2,
                    /* number_index */ 5,
                    /* restart */ 0);
 
@@ -79,7 +66,7 @@ int main(int argc, char *argv[]) {
   csds_reader_set_time(&reader, begin);
 
   /* Create the variables for the number of particles */
-  const int n_type = swift_type_count;
+  const int n_type = csds_type_count;
   uint64_t *n_parts = (uint64_t *)malloc(n_type * sizeof(uint64_t));
   int *read_types = (int *)malloc(n_type * sizeof(int));
   if (read_types == NULL || n_parts == NULL) {
@@ -134,7 +121,6 @@ int main(int argc, char *argv[]) {
   free(ids);
   free(pos);
   free(parts);
-  free(xparts);
   free(n_parts);
   free(read_types);
   csds_reader_free(&reader);