diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8ef8a65e890507c0467a965405e488aeff8ecf36
--- /dev/null
+++ b/README.md
@@ -0,0 +1,93 @@
+SWIFT: SPH WIth Fine-grained inter-dependent Tasking
+====================================================
+
+[![Build Status](https://gitlab.cosma.dur.ac.uk/jenkins/job/GNU%20SWIFT%20build/badge/icon)](https://gitlab.cosma.dur.ac.uk/jenkins/job/GNU%20SWIFT%20build/)
+
+SWIFT is a gravity and SPH solver designed to run cosmological simulations
+on peta-scale machines, scaling well up to 10's of thousands of compute
+node.
+
+More general information about SWIFT is available on the project
+[webpages](http://www.swiftsim.com).
+
+For information on how to _run_ SWIFT, please consult the onboarding guide
+available [here](http://www.swiftsim.com/onboarding.pdf). This includes
+dependencies, and a few examples to get you going.
+
+We suggest that you use the latest release branch of SWIFT, rather than the
+current master branch as this will change rapidly. We do, however, like to
+ensure that the master branch will build and run.
+
+This GitHub repository is designed to be an issue tracker, and a space for
+the public to submit patches through pull requests. It is synchronised with
+the main development repository that is available on the
+[ICC](http://icc.dur.ac.uk)'s GitLab server which is available
+[here](https://gitlab.cosma.dur.ac.uk/swift/swiftsim).
+
+Please feel free to submit issues to this repository, or even pull
+requests. We will try to deal with them as soon as possible, but as the
+core development team is quite small this could take some time.
+
+Contribution Guidelines
+-----------------------
+
+The SWIFT source code uses a variation of the 'Google' formatting style.
+The script 'format.sh' in the root directory applies the clang-format-3.8
+tool with our style choices to all the SWIFT C source file. Please apply
+the formatting script to the files before submitting a pull request.
+
+Please check that the test suite still runs with your changes applied before
+submitting a pull request and add relevant unit tests probing the correctness
+of new modules. An example of how to add a test to the suite can be found by
+considering the tests/testGreeting case.
+
+Any contributions that fail any of the automated tests will not be accepted.
+Contributions that include tests of the proposed modules (or any current ones!)
+are highly encouraged.
+
+```
+ Welcome to the cosmological hydrodynamical code
+    ______       _________________
+   / ___/ |     / /  _/ ___/_  __/
+   \__ \| | /| / // // /_   / /   
+  ___/ /| |/ |/ // // __/  / /    
+ /____/ |__/|__/___/_/    /_/     
+ SPH With Inter-dependent Fine-grained Tasking
+
+ Website: www.swiftsim.com
+ Twitter: @SwiftSimulation
+
+See INSTALL.swift for install instructions.
+
+Usage: swift [OPTION]... PARAMFILE
+       swift_mpi [OPTION]... PARAMFILE
+
+Valid options are:
+  -a                Pin runners using processor affinity.
+  -c                Run with cosmological time integration.
+  -C                Run with cooling.
+  -d                Dry run. Read the parameter file, allocate memory but does not read
+                    the particles from ICs and exit before the start of time integration.
+                    Allows user to check validity of parameter and IC files as well as memory limits.
+  -D                Always drift all particles even the ones far from active particles. This emulates
+                    Gadget-[23] and GIZMO's default behaviours.
+  -e                Enable floating-point exceptions (debugging mode).
+  -f          {int} Overwrite the CPU frequency (Hz) to be used for time measurements.
+  -g                Run with an external gravitational potential.
+  -G                Run with self-gravity.
+  -M                Reconstruct the multipoles every time-step.
+  -n          {int} Execute a fixed number of time steps. When unset use the time_end parameter to stop.
+  -P  {sec:par:val} Set parameter value and overwrites values read from the parameters file. Can be used more than once.
+  -s                Run with hydrodynamics.
+  -S                Run with stars.
+  -t          {int} The number of threads to use on each MPI rank. Defaults to 1 if not specified.
+  -T                Print timers every time-step.
+  -v           [12] Increase the level of verbosity:
+                    1: MPI-rank 0 writes,
+                    2: All MPI-ranks write.
+  -y          {int} Time-step frequency at which task graphs are dumped.
+  -Y          {int} Time-step frequency at which threadpool tasks are dumped.
+  -h                Print this help message and exit.
+
+See the file examples/parameter_example.yml for an example of parameter file.
+```
diff --git a/examples/EAGLE_100/eagle_100.yml b/examples/EAGLE_100/eagle_100.yml
index 9cf1c9432ed6c79e4b91262cfdd30bad14833558..b3cbbccc7a89131fedc27aa1024ed8f460494582 100644
--- a/examples/EAGLE_100/eagle_100.yml
+++ b/examples/EAGLE_100/eagle_100.yml
@@ -37,15 +37,18 @@ Statistics:
 
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                   0.025    # Constant dimensionless multiplier for time integration. 
-  epsilon:               0.001   # Softening length (in internal units).
-  theta:                 0.85      # Opening angle (Multipole acceptance criterion)
-  
+  eta:                    0.025    # Constant dimensionless multiplier for time integration. 
+  theta:                  0.85      # Opening angle (Multipole acceptance criterion)
+  comoving_softening:     0.0026994 # Comoving softening length (in internal units).
+  max_physical_softening: 0.0007    # Physical softening length (in internal units).
+
 # Parameters for the hydrodynamics scheme
 SPH:
   resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
   CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  minimal_temperature:   100      # (internal units)
 
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  ./EAGLE_ICs_100.hdf5     # The file to read
+  cleanup_h_factors: 1                 # Remove the h-factors inherited from Gadget
diff --git a/examples/EAGLE_100/run.sh b/examples/EAGLE_100/run.sh
index 6ef47d5d98172cc8a318242923ede37332bd5590..9310fc370acb51256b46e6ba0fb739fb2728caf9 100755
--- a/examples/EAGLE_100/run.sh
+++ b/examples/EAGLE_100/run.sh
@@ -7,5 +7,5 @@ then
     ./getIC.sh
 fi
 
-../swift -s -t 16 eagle_100.yml 2>&1 | tee output.log
+../swift -c -s -t 16 eagle_100.yml 2>&1 | tee output.log
 
diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml
index d7aedf591a6988f89ad700f0a6729b3682bb6881..933f085ccd0bcbaf80a6ca83b7cb06c5763d4a20 100644
--- a/examples/EAGLE_12/eagle_12.yml
+++ b/examples/EAGLE_12/eagle_12.yml
@@ -38,16 +38,18 @@ Statistics:
 
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                   0.025    # Constant dimensionless multiplier for time integration.
-  epsilon:               0.001    # Softening length (in internal units).
-  theta:                 0.85     # Opening angle (Multipole acceptance criterion)
+  eta:                    0.025     # Constant dimensionless multiplier for time integration.
+  theta:                  0.85      # Opening angle (Multipole acceptance criterion)
+  comoving_softening:     0.0026994 # Comoving softening length (in internal units).
+  max_physical_softening: 0.0007    # Physical softening length (in internal units).
   
 # Parameters for the hydrodynamics scheme
 SPH:
   resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
   CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  minimal_temperature:   100      # (internal units)
 
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  ./EAGLE_ICs_12.hdf5     # The file to read
-
+  cleanup_h_factors: 1               # Remove the h-factors inherited from Gadget
diff --git a/examples/EAGLE_12/run.sh b/examples/EAGLE_12/run.sh
index 21b965050ab1c786fd08c0dfd28b1612ac09e9e5..82d0e3e4d4418f0d00851f1279587a1ed45144df 100755
--- a/examples/EAGLE_12/run.sh
+++ b/examples/EAGLE_12/run.sh
@@ -7,5 +7,5 @@ then
     ./getIC.sh
 fi
 
-../swift -s -t 16 eagle_12.yml 2>&1 | tee output.log
+../swift -c -s -t 16 eagle_12.yml 2>&1 | tee output.log
 
diff --git a/examples/EAGLE_25/eagle_25.yml b/examples/EAGLE_25/eagle_25.yml
index 24daa13e06c2058d8a93243e9838b6f6b2cfe9bb..37ad91a29442825fcc843084cbbc4224203cab87 100644
--- a/examples/EAGLE_25/eagle_25.yml
+++ b/examples/EAGLE_25/eagle_25.yml
@@ -38,16 +38,19 @@ Statistics:
 
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                   0.025    # Constant dimensionless multiplier for time integration. 
-  epsilon:               0.001    # Softening length (in internal units).
-  theta:                 0.85     # Opening angle (Multipole acceptance criterion)
-  
+  eta:                    0.025    # Constant dimensionless multiplier for time integration. 
+  theta:                  0.85     # Opening angle (Multipole acceptance criterion)
+  comoving_softening:     0.0026994 # Comoving softening length (in internal units).
+  max_physical_softening: 0.0007    # Physical softening length (in internal units).
+
 # Parameters for the hydrodynamics scheme
 SPH:
   resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
   CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  minimal_temperature:   100      # (internal units)
 
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  ./EAGLE_ICs_25.hdf5     # The file to read
+  cleanup_h_factors: 1               # Remove the h-factors inherited from Gadget
 
diff --git a/examples/EAGLE_25/run.sh b/examples/EAGLE_25/run.sh
index 21d0c7baf4482bdc6df83c552253a02d47432ba2..ae36e0d8e6ae6377682f259f506f720fbd585b29 100755
--- a/examples/EAGLE_25/run.sh
+++ b/examples/EAGLE_25/run.sh
@@ -7,5 +7,5 @@ then
     ./getIC.sh
 fi
 
-../swift -s -t 16 eagle_25.yml 2>&1 | tee output.log
+../swift -c -s -t 16 eagle_25.yml 2>&1 | tee output.log
 
diff --git a/examples/EAGLE_50/eagle_50.yml b/examples/EAGLE_50/eagle_50.yml
index adf64f6963e2a0bc545637757f5826efd0c027a9..021e6b8ab347d38b7ecaeddd5a198324ab57f31b 100644
--- a/examples/EAGLE_50/eagle_50.yml
+++ b/examples/EAGLE_50/eagle_50.yml
@@ -37,16 +37,19 @@ Statistics:
 
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                   0.025    # Constant dimensionless multiplier for time integration.
-  epsilon:               0.001    # Softening length (in internal units).
-  theta:                 0.85     # Opening angle (Multipole acceptance criterion)
+  eta:                    0.025    # Constant dimensionless multiplier for time integration.
+  theta:                  0.85     # Opening angle (Multipole acceptance criterion)
+  comoving_softening:     0.0026994 # Comoving softening length (in internal units).
+  max_physical_softening: 0.0007    # Physical softening length (in internal units).
 
 # Parameters for the hydrodynamics scheme
 SPH:
   resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
   CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  minimal_temperature:   100      # (internal units)
 
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  ./EAGLE_ICs_50.hdf5     # The file to read
+  cleanup_h_factors: 1                # Remove the h-factors inherited from Gadget
 
diff --git a/examples/EAGLE_50/run.sh b/examples/EAGLE_50/run.sh
index 253e7e6eb11a04e1731c605e9ea067ba2bd13221..c3b93e84192ff58e445d4e164a4d6f66d19f85fe 100755
--- a/examples/EAGLE_50/run.sh
+++ b/examples/EAGLE_50/run.sh
@@ -7,5 +7,5 @@ then
     ./getIC.sh
 fi
 
-../swift -s -t 16 eagle_50.yml 2>&1 | tee output.log
+../swift -c -s -t 16 eagle_50.yml 2>&1 | tee output.log
 
diff --git a/examples/EAGLE_6/eagle_6.yml b/examples/EAGLE_6/eagle_6.yml
index d0055607d3cd7c1453e3b93ed8b21cd5ff2673d5..839ccf7e429248f7b7eb81635e20e43df7d1af9d 100644
--- a/examples/EAGLE_6/eagle_6.yml
+++ b/examples/EAGLE_6/eagle_6.yml
@@ -28,7 +28,7 @@ TimeIntegration:
 # Parameters governing the snapshots
 Snapshots:
   basename:            eagle # Common part of the name of output files
-  time_first:          0.    # Time of the first output (in internal units)
+  time_first:          1.    # Time of the first output (in internal units)
   delta_time:          1e-3  # Time difference between consecutive outputs (in internal units)
   compression:         4
 
@@ -38,16 +38,19 @@ Statistics:
 
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                   0.025    # Constant dimensionless multiplier for time integration.
-  epsilon:               0.001    # Softening length (in internal units).
-  theta:                 0.85     # Opening angle (Multipole acceptance criterion)
+  eta:                    0.025    # Constant dimensionless multiplier for time integration.
+  theta:                  0.85     # Opening angle (Multipole acceptance criterion)
+  comoving_softening:     0.0026994 # Comoving softening length (in internal units).
+  max_physical_softening: 0.0007    # Physical softening length (in internal units).
   
 # Parameters for the hydrodynamics scheme
 SPH:
   resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
   CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  minimal_temperature:   100      # (internal units)
 
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  ./EAGLE_ICs_6.hdf5     # The file to read
+  cleanup_h_factors: 1               # Remove the h-factors inherited from Gadget
 
diff --git a/examples/EAGLE_6/run.sh b/examples/EAGLE_6/run.sh
index d8e5592467a115460bb455ab31bb5e1f4017a948..3e1d21954d8402c9e1929119db50708859332b6c 100755
--- a/examples/EAGLE_6/run.sh
+++ b/examples/EAGLE_6/run.sh
@@ -7,5 +7,5 @@ then
     ./getIC.sh
 fi
 
-../swift -s -t 16 eagle_6.yml 2>&1 | tee output.log
+../swift -c -s -t 16 eagle_6.yml 2>&1 | tee output.log
 
diff --git a/examples/EvrardCollapse_3D/evrard.yml b/examples/EvrardCollapse_3D/evrard.yml
index 94cd6e7a95d2671f7021ae3cd2ba40477cd8e7fd..a2b39fb1e7fa36098abe720945ece4b611eb4fe8 100644
--- a/examples/EvrardCollapse_3D/evrard.yml
+++ b/examples/EvrardCollapse_3D/evrard.yml
@@ -31,11 +31,10 @@ SPH:
 
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                   0.025    # Constant dimensionless multiplier for time integration.
-  epsilon:               0.001      # Softening length (in internal units).
-  theta:                 0.9
-  a_smooth:              1.25     # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value).
-  r_cut:                 4.5      # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value).
+  eta:                    0.025    # Constant dimensionless multiplier for time integration.
+  theta:                  0.9
+  comoving_softening:     0.001    # Comoving softening length (in internal units).
+  max_physical_softening: 0.001    # Physical softening length (in internal units).
 
 # Parameters related to the initial conditions
 InitialConditions:
diff --git a/examples/EvrardCollapse_3D/makeIC.py b/examples/EvrardCollapse_3D/makeIC.py
index b68f0da0e1869ce54ae7ab2ad3b33b8c3deb8b51..f4d3c4c5bf7f91e5f79cfcd4e9ae23388932144e 100644
--- a/examples/EvrardCollapse_3D/makeIC.py
+++ b/examples/EvrardCollapse_3D/makeIC.py
@@ -18,9 +18,24 @@
 ################################################################################
 
 import h5py
+import argparse as ap
 from numpy import *
 
-# Generates a swift IC file for the Evrard collapse
+parser = ap.ArgumentParser(
+    description="Generates a swift IC file for the Evrard collapse"
+)
+
+parser.add_argument(
+    "-n",
+    "--nparts",
+    help="""
+         Number of particles to be used in the Evrard collapse.
+         """,
+    required=False,
+    default=100000
+)
+
+args = vars(parser.parse_args())
 
 # Parameters
 gamma = 5. / 3.      # Gas adiabatic index
@@ -28,7 +43,7 @@ M = 1.  # total mass of the sphere
 R = 1.               # radius of the sphere
 u0 = 0.05 / M        # initial thermal energy
 fileName = "evrard.hdf5" 
-numPart = 100000
+numPart = int(args["nparts"])
 
 r = R * sqrt(random.random(numPart))
 phi = 2. * pi * random.random(numPart)
diff --git a/examples/SedovBlast_3D/sedov.yml b/examples/SedovBlast_3D/sedov.yml
index 057e5a18acba2a1e8211d40f15ffde35b2019a9b..2df2c432cef8afec49c687b643a872b06f9abb60 100644
--- a/examples/SedovBlast_3D/sedov.yml
+++ b/examples/SedovBlast_3D/sedov.yml
@@ -31,6 +31,6 @@ SPH:
 
 # Parameters related to the initial conditions
 InitialConditions:
-  file_name:  ./sedov.hdf5          # The file to read
-  h_scaling:           3.33
+  file_name:                    ./sedov.hdf5          
+  smoothing_length_scaling:     3.33
 
diff --git a/examples/SquareTest_2D/run.sh b/examples/SquareTest_2D/run.sh
index 242f1b8b729979b026cfe31002e84cd9ef741129..7d77e9c5bd89732970b47feb3a297ef92b345a01 100755
--- a/examples/SquareTest_2D/run.sh
+++ b/examples/SquareTest_2D/run.sh
@@ -11,4 +11,4 @@ fi
 ../swift -s -t 1 square.yml 2>&1 | tee output.log
 
 # Plot the solution
-python plotSolution.py 40
+python plotSolution.py 5
diff --git a/examples/analyse_dump_cells.py b/examples/analyse_dump_cells.py
index 3140e799566c75fe494a75895db0f4a8dcff4e57..2adfaf319e9c0da33f86a6158da68e6620c47361 100755
--- a/examples/analyse_dump_cells.py
+++ b/examples/analyse_dump_cells.py
@@ -39,9 +39,11 @@ zcol = 2
 xwcol = 3
 ywcol = 4
 zwcol = 5
-localcol = 18
 supercol = 15
-activecol = 16
+topcol = 16
+activecol = 17
+localcol = 19
+mpicol = 20
 
 #  Command-line arguments.
 if len(sys.argv) < 5:
@@ -59,11 +61,12 @@ for i in range(4, len(sys.argv)):
 
     #  Read the file.
     data = pl.loadtxt(sys.argv[i])
-    #print data
+    if len(data) == 0 or len(data) == 20:
+        continue
 
-    #  Select cells that are on the current rank and are super cells.
+    #  Select cells that are on the current rank and are top-level cells.
     rdata = data[data[:,localcol] == 1]
-    tdata = rdata[rdata[:,supercol] == 1]
+    tdata = rdata[rdata[:,topcol] == 1]
 
     #  Separation of the cells is in data.
     xwidth = tdata[0,xwcol]
diff --git a/examples/main.c b/examples/main.c
index 80e4dfb479172d9e2bca6fb19ee676371d130afe..ca91c9e718cca9f7f8d82fce2f5d237f9f5b98e4 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -484,7 +484,7 @@ int main(int argc, char *argv[]) {
 #endif
 
   /* Common variables for restart and IC sections. */
-  int clean_h_values = 0;
+  int clean_smoothing_length_values = 0;
   int flag_entropy_ICs = 0;
 
   /* Work out where we will read and write restart files. */
@@ -609,20 +609,32 @@ int main(int argc, char *argv[]) {
     if (myrank == 0 && with_cosmology) cosmology_print(&cosmo);
 
     /* Initialise the hydro properties */
-    if (with_hydro) hydro_props_init(&hydro_properties, params);
+    if (with_hydro)
+      hydro_props_init(&hydro_properties, &prog_const, &us, params);
     if (with_hydro) eos_init(&eos, params);
 
     /* Initialise the gravity properties */
-    if (with_self_gravity) gravity_props_init(&gravity_properties, params);
+    if (with_self_gravity)
+      gravity_props_init(&gravity_properties, params, &cosmo);
 
     /* Read particles and space information from (GADGET) ICs */
     char ICfileName[200] = "";
     parser_get_param_string(params, "InitialConditions:file_name", ICfileName);
     const int replicate =
         parser_get_opt_param_int(params, "InitialConditions:replicate", 1);
-    clean_h_values =
-        parser_get_opt_param_int(params, "InitialConditions:cleanup_h", 0);
+    clean_smoothing_length_values = parser_get_opt_param_int(
+        params, "InitialConditions:cleanup_smoothing_lengths", 0);
+    const int cleanup_h = parser_get_opt_param_int(
+        params, "InitialConditions:cleanup_h_factors", 0);
+    const int generate_gas_in_ics = parser_get_opt_param_int(
+        params, "InitialConditions:generate_gas_in_ics", 0);
+    if (generate_gas_in_ics && flag_entropy_ICs)
+      error("Can't generate gas if the entropy flag is set in the ICs.");
+    if (generate_gas_in_ics && !with_cosmology)
+      error("Can't generate gas if the run is not cosmological.");
     if (myrank == 0) message("Reading ICs from file '%s'", ICfileName);
+    if (myrank == 0 && cleanup_h)
+      message("Cleaning up h-factors (h=%f)", cosmo.h);
     fflush(stdout);
 
     /* Get ready to read particles of all kinds */
@@ -630,25 +642,27 @@ int main(int argc, char *argv[]) {
     double dim[3] = {0., 0., 0.};
     int periodic = 0;
     if (myrank == 0) clocks_gettime(&tic);
+#if defined(HAVE_HDF5)
 #if defined(WITH_MPI)
 #if defined(HAVE_PARALLEL_HDF5)
     read_ic_parallel(ICfileName, &us, dim, &parts, &gparts, &sparts, &Ngas,
                      &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, with_hydro,
                      (with_external_gravity || with_self_gravity), with_stars,
-                     myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL,
-                     nr_threads, dry_run);
+                     cleanup_h, cosmo.h, myrank, nr_nodes, MPI_COMM_WORLD,
+                     MPI_INFO_NULL, nr_threads, dry_run);
 #else
     read_ic_serial(ICfileName, &us, dim, &parts, &gparts, &sparts, &Ngas,
                    &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, with_hydro,
                    (with_external_gravity || with_self_gravity), with_stars,
-                   myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL, nr_threads,
-                   dry_run);
+                   cleanup_h, cosmo.h, myrank, nr_nodes, MPI_COMM_WORLD,
+                   MPI_INFO_NULL, nr_threads, dry_run);
 #endif
 #else
     read_ic_single(ICfileName, &us, dim, &parts, &gparts, &sparts, &Ngas,
                    &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, with_hydro,
                    (with_external_gravity || with_self_gravity), with_stars,
-                   nr_threads, dry_run);
+                   cleanup_h, cosmo.h, nr_threads, dry_run);
+#endif
 #endif
     if (myrank == 0) {
       clocks_gettime(&toc);
@@ -659,14 +673,18 @@ int main(int argc, char *argv[]) {
 
 #ifdef SWIFT_DEBUG_CHECKS
     /* Check once and for all that we don't have unwanted links */
-    if (!with_stars) {
+    if (!with_stars && !dry_run) {
       for (size_t k = 0; k < Ngpart; ++k)
         if (gparts[k].type == swift_type_star) error("Linking problem");
     }
-    if (!with_hydro) {
+    if (!with_hydro && !dry_run) {
       for (size_t k = 0; k < Ngpart; ++k)
         if (gparts[k].type == swift_type_gas) error("Linking problem");
     }
+
+    /* Check that the other links are correctly set */
+    if (!dry_run)
+      part_verify_links(parts, gparts, sparts, Ngas, Ngpart, Nspart, 1);
 #endif
 
     /* Get the total number of particles across all nodes. */
@@ -690,8 +708,9 @@ int main(int argc, char *argv[]) {
 
     /* Initialize the space with these data. */
     if (myrank == 0) clocks_gettime(&tic);
-    space_init(&s, params, dim, parts, gparts, sparts, Ngas, Ngpart, Nspart,
-               periodic, replicate, with_self_gravity, talking, dry_run);
+    space_init(&s, params, &cosmo, dim, parts, gparts, sparts, Ngas, Ngpart,
+               Nspart, periodic, replicate, generate_gas_in_ics,
+               with_self_gravity, talking, dry_run);
 
     if (myrank == 0) {
       clocks_gettime(&toc);
@@ -700,6 +719,11 @@ int main(int argc, char *argv[]) {
       fflush(stdout);
     }
 
+    /* Check that the matter content matches the cosmology given in the
+     * parameter file. */
+    if (with_cosmology && with_self_gravity && !dry_run)
+      space_check_cosmology(&s, &cosmo, myrank);
+
 /* Also update the total counts (in case of changes due to replication) */
 #if defined(WITH_MPI)
     N_long[0] = s.nr_parts;
@@ -819,7 +843,7 @@ int main(int argc, char *argv[]) {
 
 /* Initialise the table of Ewald corrections for the gravity checks */
 #ifdef SWIFT_GRAVITY_FORCE_CHECKS
-  if (periodic) gravity_exact_force_ewald_init(e.s->dim[0]);
+  if (s.periodic) gravity_exact_force_ewald_init(e.s->dim[0]);
 #endif
 
 /* Init the runner history. */
@@ -836,7 +860,7 @@ int main(int argc, char *argv[]) {
 #endif
 
     /* Initialise the particles */
-    engine_init_particles(&e, flag_entropy_ICs, clean_h_values);
+    engine_init_particles(&e, flag_entropy_ICs, clean_smoothing_length_values);
 
     /* Write the state of the system before starting time integration. */
     engine_dump_snapshot(&e);
@@ -845,10 +869,10 @@ int main(int argc, char *argv[]) {
 
   /* Legend */
   if (myrank == 0)
-    printf("# %6s %14s %14s %14s %9s %12s %12s %12s %16s [%s] %6s\n", "Step",
-           "Time", "Scale-factor", "Time-step", "Time-bins", "Updates",
-           "g-Updates", "s-Updates", "Wall-clock time", clocks_getunit(),
-           "Props");
+    printf("# %6s %14s %14s %10s %14s %9s %12s %12s %12s %16s [%s] %6s\n",
+           "Step", "Time", "Scale-factor", "Redshift", "Time-step", "Time-bins",
+           "Updates", "g-Updates", "s-Updates", "Wall-clock time",
+           clocks_getunit(), "Props");
 
   /* File for the timers */
   if (with_verbose_timers) timers_open_file(myrank);
@@ -1000,6 +1024,24 @@ int main(int argc, char *argv[]) {
            (double)runner_hist_bins[k]);
 #endif
 
+  /* Write final time information */
+  if (myrank == 0) {
+
+    /* Print some information to the screen */
+    printf("  %6d %14e %14e %10.5f %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n",
+           e.step, e.time, e.cosmology->a, e.cosmology->z, e.time_step,
+           e.min_active_bin, e.max_active_bin, e.updates, e.g_updates,
+           e.s_updates, e.wallclock_time, e.step_props);
+    fflush(stdout);
+
+    fprintf(e.file_timesteps,
+            "  %6d %14e %14e %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n",
+            e.step, e.time, e.cosmology->a, e.time_step, e.min_active_bin,
+            e.max_active_bin, e.updates, e.g_updates, e.s_updates,
+            e.wallclock_time, e.step_props);
+    fflush(e.file_timesteps);
+  }
+
   /* Write final output. */
   engine_drift_all(&e);
   engine_print_stats(&e);
diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml
index 4784a877a21e698af28f72aab473ac9c3cad605e..0a81716a3e34bbb305916b1148a9d8199b84fa5a 100644
--- a/examples/parameter_example.yml
+++ b/examples/parameter_example.yml
@@ -30,15 +30,19 @@ SPH:
   h_max:                 10.      # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified.
   max_volume_change:     1.4      # (Optional) Maximal allowed change of kernel volume over one time-step.
   max_ghost_iterations:  30       # (Optional) Maximal number of iterations allowed to converge towards the smoothing length.
-
+  initial_temperature:   0        # (Optional) Initial temperature (in internal units) to set the gas particles at start-up. Value is ignored if set to 0.
+  minimal_temperature:   0        # (Optional) Minimal temperature (in internal units) allowed for the gas particles. Value is ignored if set to 0.
+  H_mass_fraction:       0.76     # (Optional) Hydrogen mass fraction used for initial conversion from temp to internal energy.
+  
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:          0.025    # Constant dimensionless multiplier for time integration.
-  theta:        0.7      # Opening angle (Multipole acceptance criterion)
-  epsilon:      0.1      # Softening length (in internal units).
-  a_smooth:     1.25     # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value).
-  r_cut_max:    4.5      # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value).
-  r_cut_min:    0.1      # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value).
+  eta:          0.025               # Constant dimensionless multiplier for time integration.
+  theta:        0.7                 # Opening angle (Multipole acceptance criterion)
+  comoving_softening:     0.0026994 # Comoving softening length (in internal units).
+  max_physical_softening: 0.0007    # Physical softening length (in internal units).
+  a_smooth:     1.25                # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value).
+  r_cut_max:    4.5                 # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value).
+  r_cut_min:    0.1                 # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value).
 
 # Parameters for the task scheduling
 Scheduler:
@@ -81,12 +85,14 @@ Statistics:
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  SedovBlast/sedov.hdf5 # The file to read
-  cleanup_h:   0                    # (Optional) Clean the values of h that are read in. Set to 1 to activate.
-  h_scaling:  1.                    # (Optional) A scaling factor to apply to all smoothing lengths in the ICs.
+  generate_gas_in_ics:         0    # (Optional) Generate gas particles from the DM-only ICs (e.g. from panphasia).
+  cleanup_h_factors:           0    # (Optional) Clean up the h-factors used in the ICs (e.g. in Gadget files).
+  cleanup_smoothing_lengths:   0    # (Optional) Clean the values of the smoothing lengths that are read in to remove stupid values. Set to 1 to activate.
+  smoothing_length_scaling:    1.   # (Optional) A scaling factor to apply to all smoothing lengths in the ICs.
   shift_x:    0.                    # (Optional) A shift to apply to all particles read from the ICs (in internal units).
   shift_y:    0.
   shift_z:    0.
-  replicate:  2                     # (Optional) Replicate all particles along each axis a given number of times. Default 1.
+  replicate:  2                     # (Optional) Replicate all particles along each axis a given integer number of times. Default 1.
 
 # Parameters controlling restarts
 Restarts:
diff --git a/examples/process_cells b/examples/process_cells
index eead4572387f2732cf0b86265f14d20039f73ae1..b57ed9e73c76807707d158485e31a5b643d8dec0 100755
--- a/examples/process_cells
+++ b/examples/process_cells
@@ -48,7 +48,7 @@ echo "Number of steps = $steps"
 
 #  And process them,
 echo "Processing cell dumps files..."
-#echo $files | xargs -P $NPROCS -n 4 /bin/bash -c "${SCRIPTHOME}/process_cells_helper $NX $NY $NZ \$0 \$1 \$2 \$3"
+echo $files | xargs -P $NPROCS -n 4 /bin/bash -c "${SCRIPTHOME}/process_cells_helper $NX $NY $NZ \$0 \$1 \$2 \$3"
 
 #  Create summary.
 grep "top cells" step*-active-cells.dat | sort -h > active_cells.log
diff --git a/src/Makefile.am b/src/Makefile.am
index 6877cbe71f45d3efc5b77c72b70d8d0722bf3e13..a7bc4774ea3fb162a2b3af1ea825607659e34c6a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -65,11 +65,13 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \
 nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \
 		 kernel_long_gravity.h vector.h cache.h runner_doiact.h runner_doiact_vec.h runner_doiact_grav.h runner_doiact_fft.h \
                  runner_doiact_nosort.h units.h intrinsics.h minmax.h kick.h timestep.h drift.h adiabatic_index.h io_properties.h \
-		 dimension.h equation_of_state.h part_type.h periodic.h memswap.h dump.h logger.h \
+		 dimension.h part_type.h periodic.h memswap.h dump.h logger.h \
 		 gravity.h gravity_io.h gravity_cache.h \
 		 gravity/Default/gravity.h gravity/Default/gravity_iact.h gravity/Default/gravity_io.h \
 		 gravity/Default/gravity_debug.h gravity/Default/gravity_part.h  \
 		 sourceterms.h \
+		 equation_of_state.h \
+		 equation_of_state/ideal_gas/equation_of_state.h equation_of_state/isothermal/equation_of_state.h \
 	 	 hydro.h hydro_io.h \
 		 hydro/Minimal/hydro.h hydro/Minimal/hydro_iact.h hydro/Minimal/hydro_io.h \
                  hydro/Minimal/hydro_debug.h hydro/Minimal/hydro_part.h \
diff --git a/src/approx_math.h b/src/approx_math.h
index 48319ddfd7a86c132a1cd18b4a08fa849a36a15a..aa9ed2b4efa6e0542e2eb2432132f4b0232f7403 100644
--- a/src/approx_math.h
+++ b/src/approx_math.h
@@ -49,4 +49,16 @@ __attribute__((always_inline)) INLINE static float good_approx_expf(float x) {
                              x * ((1.f / 120.f) + (1.f / 720.f) * x)))));
 }
 
+/**
+ * @brief Approximate version of exp(x) using a 6th order Taylor expansion
+ */
+__attribute__((always_inline)) INLINE static double good_approx_exp(double x) {
+  return 1. +
+         x * (1. +
+              x * (0.5 +
+                   x * ((1. / 6.) +
+                        x * ((1. / 24.) +
+                             x * ((1. / 120.) + (1. / 720.) * x)))));
+}
+
 #endif /* SWIFT_APPROX_MATH_H */
diff --git a/src/common_io.c b/src/common_io.c
index 67326817397118568e060f5dff49421bb32fba4d..c235060b1008aef0aa157bfe6e41dea76357b7b5 100644
--- a/src/common_io.c
+++ b/src/common_io.c
@@ -21,21 +21,6 @@
 /* Config parameters. */
 #include "../config.h"
 
-#if defined(HAVE_HDF5)
-
-/* Some standard headers. */
-#include <hdf5.h>
-#include <math.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* MPI headers. */
-#ifdef WITH_MPI
-#include <mpi.h>
-#endif
-
 /* This object's header. */
 #include "common_io.h"
 
@@ -50,6 +35,22 @@
 #include "units.h"
 #include "version.h"
 
+/* Some standard headers. */
+#include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(HAVE_HDF5)
+
+#include <hdf5.h>
+
+/* MPI headers. */
+#ifdef WITH_MPI
+#include <mpi.h>
+#endif
+
 /**
  * @brief Converts a C data type to the HDF5 equivalent.
  *
@@ -84,36 +85,6 @@ hid_t io_hdf5_type(enum IO_DATA_TYPE type) {
   }
 }
 
-/**
- * @brief Returns the memory size of the data type
- */
-size_t io_sizeof_type(enum IO_DATA_TYPE type) {
-
-  switch (type) {
-    case INT:
-      return sizeof(int);
-    case UINT:
-      return sizeof(unsigned int);
-    case LONG:
-      return sizeof(long);
-    case ULONG:
-      return sizeof(unsigned long);
-    case LONGLONG:
-      return sizeof(long long);
-    case ULONGLONG:
-      return sizeof(unsigned long long);
-    case FLOAT:
-      return sizeof(float);
-    case DOUBLE:
-      return sizeof(double);
-    case CHAR:
-      return sizeof(char);
-    default:
-      error("Unknown type");
-      return 0;
-  }
-}
-
 /**
  * @brief Return 1 if the type has double precision
  *
@@ -429,6 +400,36 @@ void io_write_engine_policy(hid_t h_file, const struct engine* e) {
 
 #endif /* HAVE_HDF5 */
 
+/**
+ * @brief Returns the memory size of the data type
+ */
+size_t io_sizeof_type(enum IO_DATA_TYPE type) {
+
+  switch (type) {
+    case INT:
+      return sizeof(int);
+    case UINT:
+      return sizeof(unsigned int);
+    case LONG:
+      return sizeof(long);
+    case ULONG:
+      return sizeof(unsigned long);
+    case LONGLONG:
+      return sizeof(long long);
+    case ULONGLONG:
+      return sizeof(unsigned long long);
+    case FLOAT:
+      return sizeof(float);
+    case DOUBLE:
+      return sizeof(double);
+    case CHAR:
+      return sizeof(char);
+    default:
+      error("Unknown type");
+      return 0;
+  }
+}
+
 /**
  * @brief Mapper function to copy #part or #gpart fields into a buffer.
  */
@@ -457,6 +458,7 @@ void io_convert_part_f_mapper(void* restrict temp, int N,
 
   const struct io_props props = *((const struct io_props*)extra_data);
   const struct part* restrict parts = props.parts;
+  const struct xpart* restrict xparts = props.xparts;
   const struct engine* e = props.e;
   const size_t dim = props.dimension;
 
@@ -465,7 +467,8 @@ void io_convert_part_f_mapper(void* restrict temp, int N,
   const ptrdiff_t delta = (temp_f - props.start_temp_f) / dim;
 
   for (int i = 0; i < N; i++)
-    props.convert_part_f(e, parts + delta + i, &temp_f[i * dim]);
+    props.convert_part_f(e, parts + delta + i, xparts + delta + i,
+                         &temp_f[i * dim]);
 }
 
 /**
@@ -477,6 +480,7 @@ void io_convert_part_d_mapper(void* restrict temp, int N,
 
   const struct io_props props = *((const struct io_props*)extra_data);
   const struct part* restrict parts = props.parts;
+  const struct xpart* restrict xparts = props.xparts;
   const struct engine* e = props.e;
   const size_t dim = props.dimension;
 
@@ -485,7 +489,8 @@ void io_convert_part_d_mapper(void* restrict temp, int N,
   const ptrdiff_t delta = (temp_d - props.start_temp_d) / dim;
 
   for (int i = 0; i < N; i++)
-    props.convert_part_d(e, parts + delta + i, &temp_d[i * dim]);
+    props.convert_part_d(e, parts + delta + i, xparts + delta + i,
+                         &temp_d[i * dim]);
 }
 
 /**
@@ -704,7 +709,7 @@ void io_duplicate_hydro_gparts_mapper(void* restrict data, int Ngas,
     gparts[i + Ndm].type = swift_type_gas;
 
     /* Link the particles */
-    gparts[i + Ndm].id_or_neg_offset = -i;
+    gparts[i + Ndm].id_or_neg_offset = -(long long)(offset + i);
     parts[i].gpart = &gparts[i + Ndm];
   }
 }
@@ -760,7 +765,7 @@ void io_duplicate_hydro_sparts_mapper(void* restrict data, int Nstars,
     gparts[i + Ndm].type = swift_type_star;
 
     /* Link the particles */
-    gparts[i + Ndm].id_or_neg_offset = -i;
+    gparts[i + Ndm].id_or_neg_offset = -(long long)(offset + i);
     sparts[i].gpart = &gparts[i + Ndm];
   }
 }
diff --git a/src/common_io.h b/src/common_io.h
index 49358d8a374553d803de144f1135df6eee80cf15..4f6d75fad0482f62b8d5c3f80a632d7eb6f54d60 100644
--- a/src/common_io.h
+++ b/src/common_io.h
@@ -37,8 +37,6 @@ struct io_props;
 struct engine;
 struct threadpool;
 
-#if defined(HAVE_HDF5)
-
 /**
  * @brief The different types of data used in the GADGET IC files.
  *
@@ -56,9 +54,9 @@ enum IO_DATA_TYPE {
   CHAR
 };
 
+#if defined(HAVE_HDF5)
+
 hid_t io_hdf5_type(enum IO_DATA_TYPE type);
-size_t io_sizeof_type(enum IO_DATA_TYPE type);
-int io_is_double_precision(enum IO_DATA_TYPE type);
 
 void io_read_attribute(hid_t grp, const char* name, enum IO_DATA_TYPE type,
                        void* data);
@@ -86,6 +84,9 @@ void io_copy_temp_buffer(void* temp, const struct engine* e,
 
 #endif /* defined HDF5 */
 
+size_t io_sizeof_type(enum IO_DATA_TYPE type);
+int io_is_double_precision(enum IO_DATA_TYPE type);
+
 void io_collect_dm_gparts(const struct gpart* const gparts, size_t Ntot,
                           struct gpart* const dmparts, size_t Ndm);
 void io_prepare_dm_gparts(struct threadpool* tp, struct gpart* const gparts,
diff --git a/src/cosmology.c b/src/cosmology.c
index b1bf71ad25451d2185d911320fb757193e990945..a5034240d07b9b9bf401d470c0bacbf6962a8006 100644
--- a/src/cosmology.c
+++ b/src/cosmology.c
@@ -130,9 +130,11 @@ double cosmology_get_time_since_big_bang(const struct cosmology *c, double a) {
  * @brief Update the cosmological parameters to the current simulation time.
  *
  * @param c The #cosmology struct.
+ * @param phys_const The physical constants in the internal units.
  * @param ti_current The current (integer) time.
  */
-void cosmology_update(struct cosmology *c, integertime_t ti_current) {
+void cosmology_update(struct cosmology *c, const struct phys_const *phys_const,
+                      integertime_t ti_current) {
 
   /* Get scale factor and powers of it */
   const double a = c->a_begin * exp(ti_current * c->time_base);
@@ -173,6 +175,10 @@ void cosmology_update(struct cosmology *c, integertime_t ti_current) {
   /* Expansion rate */
   c->a_dot = c->H * c->a;
 
+  /* Critical density */
+  c->critical_density =
+      3. * c->H * c->H / (8. * M_PI * phys_const->const_newton_G);
+
   /* Time-step conversion factor */
   c->time_step_factor = c->H;
 
@@ -284,8 +290,6 @@ double time_integrand(double a, void *param) {
  */
 void cosmology_init_tables(struct cosmology *c) {
 
-  const ticks tic = getticks();
-
 #ifdef HAVE_LIBGSL
 
   /* Retrieve some constants */
@@ -373,9 +377,6 @@ void cosmology_init_tables(struct cosmology *c) {
   error("Code not compiled with GSL. Can't compute cosmology integrals.");
 
 #endif
-
-  message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
-          clocks_getunit());
 }
 
 /**
@@ -431,7 +432,7 @@ void cosmology_init(const struct swift_params *params,
   cosmology_init_tables(c);
 
   /* Set remaining variables to alid values */
-  cosmology_update(c, 0);
+  cosmology_update(c, phys_const, 0);
 
   /* Update the times */
   c->time_begin = cosmology_get_time_since_big_bang(c, c->a_begin);
@@ -454,7 +455,7 @@ void cosmology_init_no_cosmo(struct cosmology *c) {
   c->Omega_b = 0.;
   c->w_0 = 0.;
   c->w_a = 0.;
-  c->h = 0.;
+  c->h = 1.;
   c->w = 0.;
 
   c->a_begin = 1.;
@@ -474,6 +475,8 @@ void cosmology_init_no_cosmo(struct cosmology *c) {
   c->a_factor_hydro_accel = 1.;
   c->a_factor_grav_accel = 1.;
 
+  c->critical_density = 0.;
+
   c->time_step_factor = 1.;
 
   c->a_dot = 0.;
diff --git a/src/cosmology.h b/src/cosmology.h
index b541e20fa1dd4f55422f9ff1d0952783d8de0ad7..109b80a57d8dbc4eb942dd4ecbbc0db84198100b 100644
--- a/src/cosmology.h
+++ b/src/cosmology.h
@@ -70,6 +70,9 @@ struct cosmology {
   /*! Hubble constant at the current redshift (in internal units) */
   double H;
 
+  /*! The critical density at the current redshift (in internal units) */
+  double critical_density;
+
   /*! Conversion factor from internal time-step size to cosmological step */
   double time_step_factor;
 
@@ -160,7 +163,8 @@ struct cosmology {
   double universe_age_at_present_day;
 };
 
-void cosmology_update(struct cosmology *c, integertime_t ti_current);
+void cosmology_update(struct cosmology *c, const struct phys_const *phys_const,
+                      integertime_t ti_current);
 
 double cosmology_get_drift_factor(const struct cosmology *cosmo,
                                   integertime_t ti_start, integertime_t ti_end);
diff --git a/src/debug.c b/src/debug.c
index 77d791a31787c7997a9a56e3204dac1160178976..b1e2cb08bc7fa99330da3d9c9382dbef81b3215a 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -271,17 +271,17 @@ int checkCellhdxmax(const struct cell *c, int *depth) {
 }
 
 /**
- * @brief map function for dumping cells. In MPI mode locally active cells
- * only.
+ * @brief map function for dumping cells.
  */
 static void dumpCells_map(struct cell *c, void *data) {
   size_t *ldata = (size_t *)data;
   FILE *file = (FILE *)ldata[0];
   struct engine *e = (struct engine *)ldata[1];
   float ntasks = c->nr_tasks;
-  int active = (int)ldata[2];
-  int mpiactive = (int)ldata[3];
-  int pactive = (int)ldata[4];
+  int super = (int)ldata[2];
+  int active = (int)ldata[3];
+  int mpiactive = (int)ldata[4];
+  int pactive = (int)ldata[5];
 
 #if SWIFT_DEBUG_CHECKS
   /* The c->nr_tasks field does not include all the tasks. So let's check this
@@ -305,11 +305,13 @@ static void dumpCells_map(struct cell *c, void *data) {
   /* Only cells with particles are dumped. */
   if (c->count > 0 || c->gcount > 0 || c->scount > 0) {
 
-/* In MPI mode we may only output cells with foreign partners.
- * These define the edges of the partitions. */
+    /* In MPI mode we may only output cells with foreign partners.
+     * These define the edges of the partitions. */
+    int ismpiactive = 0;
 #if WITH_MPI
+    ismpiactive = (c->send_xv != NULL);
     if (mpiactive)
-      mpiactive = (c->send_xv != NULL);
+      mpiactive = ismpiactive;
     else
       mpiactive = 1;
 #else
@@ -322,9 +324,10 @@ static void dumpCells_map(struct cell *c, void *data) {
     else
       active = 1;
 
-    /* So output local super cells that are active and have MPI tasks as
-     * requested. */
-    if (c->nodeID == e->nodeID && (c->super == c) && active && mpiactive) {
+    /* So output local super cells that are active and have MPI
+     * tasks as requested. */
+    if (c->nodeID == e->nodeID && (!super || (super && c->super == c)) &&
+        active && mpiactive) {
 
       /* If requested we work out how many particles are active in this cell. */
       int pactcount = 0;
@@ -342,12 +345,13 @@ static void dumpCells_map(struct cell *c, void *data) {
 
       fprintf(file,
               "  %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6d %6d %6d %6d %6d %6d "
-              "%6.1f %20lld %6d %6d %6d %6d %6d\n",
+              "%6.1f %20lld %6d %6d %6d %6d %6d %6d %6d\n",
               c->loc[0], c->loc[1], c->loc[2], c->width[0], c->width[1],
               c->width[2], e->step, c->count, c->gcount, c->scount, pactcount,
               c->depth, ntasks, c->ti_hydro_end_min,
               get_time_bin(c->ti_hydro_end_min), (c->super == c),
-              cell_is_active_hydro(c, e), c->nodeID, c->nodeID == e->nodeID);
+              (c->parent == NULL), cell_is_active_hydro(c, e), c->nodeID,
+              c->nodeID == e->nodeID, ismpiactive);
     }
   }
 }
@@ -359,6 +363,7 @@ static void dumpCells_map(struct cell *c, void *data) {
  *
  * @param prefix base output filename, result is written to
  *               %prefix%_%rank%_%step%.dat
+ * @param super just output the super cells.
  * @param active just output active cells.
  * @param mpiactive just output MPI active cells, i.e. those with foreign cells.
  * @param pactive also output a count of active particles.
@@ -366,8 +371,8 @@ static void dumpCells_map(struct cell *c, void *data) {
  * @param rank node ID of MPI rank, or 0 if not relevant.
  * @param step the current engine step, or some unique integer.
  */
-void dumpCells(const char *prefix, int active, int mpiactive, int pactive,
-               struct space *s, int rank, int step) {
+void dumpCells(const char *prefix, int super, int active, int mpiactive,
+               int pactive, struct space *s, int rank, int step) {
 
   FILE *file = NULL;
 
@@ -379,17 +384,18 @@ void dumpCells(const char *prefix, int active, int mpiactive, int pactive,
   /* Header. */
   fprintf(file,
           "# %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s "
-          "%20s %6s %6s %6s %6s %6s\n",
+          "%20s %6s %6s %6s %6s %6s %6s %6s\n",
           "x", "y", "z", "xw", "yw", "zw", "step", "count", "gcount", "scount",
           "actcount", "depth", "tasks", "ti_end_min", "timebin", "issuper",
-          "active", "rank", "local");
+          "istop", "active", "rank", "local", "mpiactive");
 
-  size_t data[5];
+  size_t data[6];
   data[0] = (size_t)file;
   data[1] = (size_t)s->e;
-  data[2] = (size_t)active;
-  data[3] = (size_t)mpiactive;
-  data[4] = (size_t)pactive;
+  data[2] = (size_t)super;
+  data[3] = (size_t)active;
+  data[4] = (size_t)mpiactive;
+  data[5] = (size_t)pactive;
   space_map_cells_pre(s, 1, dumpCells_map, &data);
   fclose(file);
 }
diff --git a/src/debug.h b/src/debug.h
index 5a646948204cc809c66430bb01c9ee90e21d720a..1e482c05c5af2dfebff1a254018fb1802df6cc5d 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -36,8 +36,8 @@ void printgParticle_single(struct gpart *gp);
 
 int checkSpacehmax(struct space *s);
 int checkCellhdxmax(const struct cell *c, int *depth);
-void dumpCells(const char *prefix, int active, int mpiactive, int pactive,
-               struct space *s, int rank, int step);
+void dumpCells(const char *prefix, int super, int active, int mpiactive,
+               int pactive, struct space *s, int rank, int step);
 
 #if defined(WITH_MPI) && defined(HAVE_METIS)
 #include "metis.h"
diff --git a/src/engine.c b/src/engine.c
index 3e63166d3465c42ff5db21dac7308deb9cf96935..6f8c0e9937ee40912964b88a3be69cacf060a0ae 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -3654,7 +3654,7 @@ int engine_estimate_nr_tasks(struct engine *e) {
 #endif
 
   double ntasks = n1 * ntop + n2 * (ncells - ntop);
-  tasks_per_cell = ceil(ntasks / ncells);
+  if (ncells > 0) tasks_per_cell = ceil(ntasks / ncells);
 
   if (tasks_per_cell < 1.0) tasks_per_cell = 1.0;
   if (e->verbose)
@@ -3668,10 +3668,10 @@ int engine_estimate_nr_tasks(struct engine *e) {
  * @brief Rebuild the space and tasks.
  *
  * @param e The #engine.
- * @param clean_h_values Are we cleaning up the values of h before building
- * the tasks ?
+ * @param clean_smoothing_length_values Are we cleaning up the values of
+ * the smoothing lengths before building the tasks ?
  */
-void engine_rebuild(struct engine *e, int clean_h_values) {
+void engine_rebuild(struct engine *e, int clean_smoothing_length_values) {
 
   const ticks tic = getticks();
 
@@ -3687,7 +3687,7 @@ void engine_rebuild(struct engine *e, int clean_h_values) {
 #endif
 
   /* Initial cleaning up session ? */
-  if (clean_h_values) space_sanitize(e->s);
+  if (clean_smoothing_length_values) space_sanitize(e->s);
 
 /* If in parallel, exchange the cell structure, top-level and neighbouring
  * multipoles. */
@@ -4379,10 +4379,10 @@ void engine_step(struct engine *e) {
   if (e->nodeID == 0) {
 
     /* Print some information to the screen */
-    printf("  %6d %14e %14e %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n",
-           e->step, e->time, e->cosmology->a, e->time_step, e->min_active_bin,
-           e->max_active_bin, e->updates, e->g_updates, e->s_updates,
-           e->wallclock_time, e->step_props);
+    printf("  %6d %14e %14e %10.5f %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n",
+           e->step, e->time, e->cosmology->a, e->cosmology->z, e->time_step,
+           e->min_active_bin, e->max_active_bin, e->updates, e->g_updates,
+           e->s_updates, e->wallclock_time, e->step_props);
     fflush(stdout);
 
     fprintf(e->file_timesteps,
@@ -4403,7 +4403,7 @@ void engine_step(struct engine *e) {
 
   if (e->policy & engine_policy_cosmology) {
     e->time_old = e->time;
-    cosmology_update(e->cosmology, e->ti_current);
+    cosmology_update(e->cosmology, e->physical_constants, e->ti_current);
     e->time = e->cosmology->time;
     e->time_step = e->time - e->time_old;
   } else {
@@ -4412,6 +4412,10 @@ void engine_step(struct engine *e) {
     e->time_step = (e->ti_current - e->ti_old) * e->time_base;
   }
 
+  /* Update the softening lengths */
+  if (e->policy & engine_policy_self_gravity)
+    gravity_update(e->gravity_properties, e->cosmology);
+
   /* Prepare the tasks to be launched, rebuild or repartition if needed. */
   engine_prepare(e);
 
@@ -4436,7 +4440,7 @@ void engine_step(struct engine *e) {
   if (e->verbose) engine_print_task_counts(e);
 
 /* Dump local cells and active particle counts. */
-/* dumpCells("cells", 0, 0, 1, e->s, e->nodeID, e->step); */
+/* dumpCells("cells", 0, 0, 0, 0, e->s, e->nodeID, e->step); */
 
 #ifdef SWIFT_DEBUG_CHECKS
   /* Check that we have the correct total mass in the top-level multipoles */
@@ -5093,6 +5097,7 @@ void engine_dump_snapshot(struct engine *e) {
 #endif
 
 /* Dump... */
+#if defined(HAVE_HDF5)
 #if defined(WITH_MPI)
 #if defined(HAVE_PARALLEL_HDF5)
   write_output_parallel(e, e->snapshotBaseName, e->internal_units,
@@ -5106,6 +5111,7 @@ void engine_dump_snapshot(struct engine *e) {
 #else
   write_output_single(e, e->snapshotBaseName, e->internal_units,
                       e->snapshotUnits);
+#endif
 #endif
 
   e->dump_snapshot = 0;
@@ -5201,7 +5207,7 @@ void engine_init(
     long long Ngas, long long Ndm, int policy, int verbose,
     struct repartition *reparttype, const struct unit_system *internal_units,
     const struct phys_const *physical_constants, struct cosmology *cosmo,
-    const struct hydro_props *hydro, const struct gravity_props *gravity,
+    const struct hydro_props *hydro, struct gravity_props *gravity,
     const struct external_potential *potential,
     const struct cooling_function_data *cooling_func,
     const struct chemistry_data *chemistry, struct sourceterms *sourceterms) {
diff --git a/src/engine.h b/src/engine.h
index 0fa8ca93b84760d0d92d9494f6e8e6224e3d1d9a..4c37aab593fdffc5f68ea16cb83b29ad782debf0 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -278,7 +278,7 @@ struct engine {
   const struct hydro_props *hydro_properties;
 
   /* Properties of the self-gravity scheme */
-  const struct gravity_props *gravity_properties;
+  struct gravity_props *gravity_properties;
 
   /* Properties of external gravitational potential */
   const struct external_potential *external_potential;
@@ -335,7 +335,7 @@ void engine_init(
     long long Ngas, long long Ndm, int policy, int verbose,
     struct repartition *reparttype, const struct unit_system *internal_units,
     const struct phys_const *physical_constants, struct cosmology *cosmo,
-    const struct hydro_props *hydro, const struct gravity_props *gravity,
+    const struct hydro_props *hydro, struct gravity_props *gravity,
     const struct external_potential *potential,
     const struct cooling_function_data *cooling_func,
     const struct chemistry_data *chemistry, struct sourceterms *sourceterms);
diff --git a/src/equation_of_state.c b/src/equation_of_state.c
index a792bc58cf13fa5f710dc1cd80713ff90e700b18..0953ee7114314f3baf6e86a14a6ddb0e98442dd9 100644
--- a/src/equation_of_state.c
+++ b/src/equation_of_state.c
@@ -20,48 +20,6 @@
 /* This object's header. */
 #include "equation_of_state.h"
 
-/* local headers */
-#include "common_io.h"
-
 /* Equation of state for the physics model
  * (temporary ugly solution as a global variable) */
 struct eos_parameters eos;
-
-void eos_init(struct eos_parameters *e, const struct swift_params *params) {
-
-#if defined(EOS_IDEAL_GAS)
-/* nothing to do here */
-#elif defined(EOS_ISOTHERMAL_GAS)
-  e->isothermal_internal_energy =
-      parser_get_param_float(params, "EoS:isothermal_internal_energy");
-#endif
-}
-
-void eos_print(const struct eos_parameters *e) {
-
-#if defined(EOS_IDEAL_GAS)
-  message("Equation of state: Ideal gas.");
-#elif defined(EOS_ISOTHERMAL_GAS)
-  message(
-      "Equation of state: Isothermal with internal energy "
-      "per unit mass set to %f.",
-      e->isothermal_internal_energy);
-#endif
-
-  message("Adiabatic index gamma: %f.", hydro_gamma);
-}
-
-#if defined(HAVE_HDF5)
-void eos_print_snapshot(hid_t h_grpsph, const struct eos_parameters *e) {
-
-  io_write_attribute_f(h_grpsph, "Adiabatic index", hydro_gamma);
-
-#if defined(EOS_IDEAL_GAS)
-  io_write_attribute_s(h_grpsph, "Equation of state", "Ideal gas");
-#elif defined(EOS_ISOTHERMAL_GAS)
-  io_write_attribute_s(h_grpsph, "Equation of state", "Isothermal gas");
-  io_write_attribute_f(h_grpsph, "Thermal energy per unit mass",
-                       e->isothermal_internal_energy);
-#endif
-}
-#endif
diff --git a/src/equation_of_state.h b/src/equation_of_state.h
index 76b8bb922133c9c4f29453a14068fe3f9044d66f..195b52514f2acc0c40959e09c088a06f0a411869 100644
--- a/src/equation_of_state.h
+++ b/src/equation_of_state.h
@@ -29,315 +29,13 @@
 /* Config parameters. */
 #include "../config.h"
 
-/* Some standard headers. */
-#include <math.h>
-
-/* Local headers. */
-#include "adiabatic_index.h"
-#include "debug.h"
-#include "inline.h"
-
-extern struct eos_parameters eos;
-
-/* ------------------------------------------------------------------------- */
+/* Import the right functions */
 #if defined(EOS_IDEAL_GAS)
-
-struct eos_parameters {};
-
-/**
- * @brief Returns the internal energy given density and entropy
- *
- * Computes \f$u = \frac{S\rho^{\gamma-1} }{\gamma - 1}\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param entropy The entropy \f$S\f$.
- */
-__attribute__((always_inline)) INLINE static float
-gas_internal_energy_from_entropy(float density, float entropy) {
-
-  return entropy * pow_gamma_minus_one(density) *
-         hydro_one_over_gamma_minus_one;
-}
-
-/**
- * @brief Returns the pressure given density and entropy
- *
- * Computes \f$P = S\rho^\gamma\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param entropy The entropy \f$S\f$.
- */
-__attribute__((always_inline)) INLINE static float gas_pressure_from_entropy(
-    float density, float entropy) {
-
-  return entropy * pow_gamma(density);
-}
-
-/**
- * @brief Returns the entropy given density and pressure.
- *
- * Computes \f$A = \frac{P}{\rho^\gamma}\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param pressure The pressure \f$P\f$.
- * @return The entropy \f$A\f$.
- */
-__attribute__((always_inline)) INLINE static float gas_entropy_from_pressure(
-    float density, float pressure) {
-
-  return pressure * pow_minus_gamma(density);
-}
-
-/**
- * @brief Returns the sound speed given density and entropy
- *
- * Computes \f$c = \sqrt{\gamma S \rho^{\gamma-1}}\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param entropy The entropy \f$S\f$.
- */
-__attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy(
-    float density, float entropy) {
-
-  return sqrtf(hydro_gamma * pow_gamma_minus_one(density) * entropy);
-}
-
-/**
- * @brief Returns the entropy given density and internal energy
- *
- * Computes \f$S = \frac{(\gamma - 1)u}{\rho^{\gamma-1}}\f$.
- *
- * @param density The density \f$\rho\f$
- * @param u The internal energy \f$u\f$
- */
-__attribute__((always_inline)) INLINE static float
-gas_entropy_from_internal_energy(float density, float u) {
-
-  return hydro_gamma_minus_one * u * pow_minus_gamma_minus_one(density);
-}
-
-/**
- * @brief Returns the pressure given density and internal energy
- *
- * Computes \f$P = (\gamma - 1)u\rho\f$.
- *
- * @param density The density \f$\rho\f$
- * @param u The internal energy \f$u\f$
- */
-__attribute__((always_inline)) INLINE static float
-gas_pressure_from_internal_energy(float density, float u) {
-
-  return hydro_gamma_minus_one * u * density;
-}
-
-/**
- * @brief Returns the internal energy given density and pressure.
- *
- * Computes \f$u = \frac{1}{\gamma - 1}\frac{P}{\rho}\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param pressure The pressure \f$P\f$.
- * @return The internal energy \f$u\f$.
- */
-__attribute__((always_inline)) INLINE static float
-gas_internal_energy_from_pressure(float density, float pressure) {
-  return hydro_one_over_gamma_minus_one * pressure / density;
-}
-
-/**
- * @brief Returns the sound speed given density and internal energy
- *
- * Computes \f$c = \sqrt{\gamma (\gamma - 1) u }\f$.
- *
- * @param density The density \f$\rho\f$
- * @param u The internal energy \f$u\f$
- */
-__attribute__((always_inline)) INLINE static float
-gas_soundspeed_from_internal_energy(float density, float u) {
-
-  return sqrtf(u * hydro_gamma * hydro_gamma_minus_one);
-}
-
-/**
- * @brief Returns the sound speed given density and pressure
- *
- * Computes \f$c = \sqrt{\frac{\gamma P}{\rho} }\f$.
- *
- * @param density The density \f$\rho\f$
- * @param P The pressure \f$P\f$
- */
-__attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure(
-    float density, float P) {
-
-  const float density_inv = 1.f / density;
-  return sqrtf(hydro_gamma * P * density_inv);
-}
-
-/* ------------------------------------------------------------------------- */
+#include "./equation_of_state/ideal_gas/equation_of_state.h"
 #elif defined(EOS_ISOTHERMAL_GAS)
-
-struct eos_parameters {
-
-  /*! Thermal energy per unit mass */
-  float isothermal_internal_energy;
-};
-
-/**
- * @brief Returns the internal energy given density and entropy
- *
- * Since we are using an isothermal EoS, the entropy and density values are
- * ignored.
- * Computes \f$u = u_{cst}\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param entropy The entropy \f$S\f$.
- */
-__attribute__((always_inline)) INLINE static float
-gas_internal_energy_from_entropy(float density, float entropy) {
-
-  return eos.isothermal_internal_energy;
-}
-
-/**
- * @brief Returns the pressure given density and entropy
- *
- * Since we are using an isothermal EoS, the entropy value is ignored.
- * Computes \f$P = (\gamma - 1)u_{cst}\rho\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param entropy The entropy \f$S\f$.
- */
-__attribute__((always_inline)) INLINE static float gas_pressure_from_entropy(
-    float density, float entropy) {
-
-  return hydro_gamma_minus_one * eos.isothermal_internal_energy * density;
-}
-
-/**
- * @brief Returns the entropy given density and pressure.
- *
- * Since we are using an isothermal EoS, the pressure value is ignored.
- * Computes \f$A = (\gamma - 1)u_{cst}\rho^{-(\gamma-1)}\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param pressure The pressure \f$P\f$ (ignored).
- * @return The entropy \f$A\f$.
- */
-__attribute__((always_inline)) INLINE static float gas_entropy_from_pressure(
-    float density, float pressure) {
-
-  return hydro_gamma_minus_one * eos.isothermal_internal_energy *
-         pow_minus_gamma_minus_one(density);
-}
-
-/**
- * @brief Returns the sound speed given density and entropy
- *
- * Since we are using an isothermal EoS, the entropy and density values are
- * ignored.
- * Computes \f$c = \sqrt{u_{cst} \gamma (\gamma-1)}\f$.
- *
- * @param density The density \f$\rho\f$.
- * @param entropy The entropy \f$S\f$.
- */
-__attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy(
-    float density, float entropy) {
-
-  return sqrtf(eos.isothermal_internal_energy * hydro_gamma *
-               hydro_gamma_minus_one);
-}
-
-/**
- * @brief Returns the entropy given density and internal energy
- *
- * Since we are using an isothermal EoS, the energy value is ignored.
- * Computes \f$S = \frac{(\gamma - 1)u_{cst}}{\rho^{\gamma-1}}\f$.
- *
- * @param density The density \f$\rho\f$
- * @param u The internal energy \f$u\f$
- */
-__attribute__((always_inline)) INLINE static float
-gas_entropy_from_internal_energy(float density, float u) {
-
-  return hydro_gamma_minus_one * eos.isothermal_internal_energy *
-         pow_minus_gamma_minus_one(density);
-}
-
-/**
- * @brief Returns the pressure given density and internal energy
- *
- * Since we are using an isothermal EoS, the energy value is ignored.
- * Computes \f$P = (\gamma - 1)u_{cst}\rho\f$.
- *
- * @param density The density \f$\rho\f$
- * @param u The internal energy \f$u\f$
- */
-__attribute__((always_inline)) INLINE static float
-gas_pressure_from_internal_energy(float density, float u) {
-
-  return hydro_gamma_minus_one * eos.isothermal_internal_energy * density;
-}
-
-/**
- * @brief Returns the internal energy given density and pressure.
- *
- * Just returns the constant internal energy.
- *
- * @param density The density \f$\rho\f$ (ignored).
- * @param pressure The pressure \f$P\f$ (ignored).
- * @return The internal energy \f$u\f$ (which is constant).
- */
-__attribute__((always_inline)) INLINE static float
-gas_internal_energy_from_pressure(float density, float pressure) {
-  return eos.isothermal_internal_energy;
-}
-
-/**
- * @brief Returns the sound speed given density and internal energy
- *
- * Since we are using an isothermal EoS, the energy and density values are
- * ignored.
- * Computes \f$c = \sqrt{u_{cst} \gamma (\gamma-1)}\f$.
- *
- * @param density The density \f$\rho\f$
- * @param u The internal energy \f$u\f$
- */
-__attribute__((always_inline)) INLINE static float
-gas_soundspeed_from_internal_energy(float density, float u) {
-
-  return sqrtf(eos.isothermal_internal_energy * hydro_gamma *
-               hydro_gamma_minus_one);
-}
-
-/**
- * @brief Returns the sound speed given density and pressure
- *
- * Since we are using an isothermal EoS, the pressure and density values are
- * ignored.
- * Computes \f$c = \sqrt{u_{cst} \gamma (\gamma-1)}\f$.
- *
- * @param density The density \f$\rho\f$
- * @param P The pressure \f$P\f$
- */
-__attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure(
-    float density, float P) {
-
-  return sqrtf(eos.isothermal_internal_energy * hydro_gamma *
-               hydro_gamma_minus_one);
-}
-
-/* ------------------------------------------------------------------------- */
+#include "./equation_of_state/isothermal/equation_of_state.h"
 #else
-
-#error "An Equation of state needs to be chosen in const.h !"
-
-#endif
-
-void eos_init(struct eos_parameters *e, const struct swift_params *params);
-void eos_print(const struct eos_parameters *e);
-
-#if defined(HAVE_HDF5)
-void eos_print_snapshot(hid_t h_grpsph, const struct eos_parameters *e);
+#error "Invalid choice of equation of state"
 #endif
 
 #endif /* SWIFT_EQUATION_OF_STATE_H */
diff --git a/src/equation_of_state/ideal_gas/equation_of_state.h b/src/equation_of_state/ideal_gas/equation_of_state.h
new file mode 100644
index 0000000000000000000000000000000000000000..42314e0fd87cb5ee2b81bc8cf29029ab4951c869
--- /dev/null
+++ b/src/equation_of_state/ideal_gas/equation_of_state.h
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016   Matthieu Schaller (matthieu.schaller@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 SWIFT_IDEAL_GAS_EQUATION_OF_STATE_H
+#define SWIFT_IDEAL_GAS_EQUATION_OF_STATE_H
+
+/* Some standard headers. */
+#include <math.h>
+
+/* Local headers. */
+#include "adiabatic_index.h"
+#include "common_io.h"
+#include "debug.h"
+#include "inline.h"
+
+extern struct eos_parameters eos;
+/* ------------------------------------------------------------------------- */
+
+struct eos_parameters {};
+
+/**
+ * @brief Returns the internal energy given density and entropy
+ *
+ * Computes \f$u = \frac{S\rho^{\gamma-1} }{\gamma - 1}\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param entropy The entropy \f$S\f$.
+ */
+__attribute__((always_inline)) INLINE static float
+gas_internal_energy_from_entropy(float density, float entropy) {
+
+  return entropy * pow_gamma_minus_one(density) *
+         hydro_one_over_gamma_minus_one;
+}
+
+/**
+ * @brief Returns the pressure given density and entropy
+ *
+ * Computes \f$P = S\rho^\gamma\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param entropy The entropy \f$S\f$.
+ */
+__attribute__((always_inline)) INLINE static float gas_pressure_from_entropy(
+    float density, float entropy) {
+
+  return entropy * pow_gamma(density);
+}
+
+/**
+ * @brief Returns the entropy given density and pressure.
+ *
+ * Computes \f$A = \frac{P}{\rho^\gamma}\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param pressure The pressure \f$P\f$.
+ * @return The entropy \f$A\f$.
+ */
+__attribute__((always_inline)) INLINE static float gas_entropy_from_pressure(
+    float density, float pressure) {
+
+  return pressure * pow_minus_gamma(density);
+}
+
+/**
+ * @brief Returns the sound speed given density and entropy
+ *
+ * Computes \f$c = \sqrt{\gamma S \rho^{\gamma-1}}\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param entropy The entropy \f$S\f$.
+ */
+__attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy(
+    float density, float entropy) {
+
+  return sqrtf(hydro_gamma * pow_gamma_minus_one(density) * entropy);
+}
+
+/**
+ * @brief Returns the entropy given density and internal energy
+ *
+ * Computes \f$S = \frac{(\gamma - 1)u}{\rho^{\gamma-1}}\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param u The internal energy \f$u\f$
+ */
+__attribute__((always_inline)) INLINE static float
+gas_entropy_from_internal_energy(float density, float u) {
+
+  return hydro_gamma_minus_one * u * pow_minus_gamma_minus_one(density);
+}
+
+/**
+ * @brief Returns the pressure given density and internal energy
+ *
+ * Computes \f$P = (\gamma - 1)u\rho\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param u The internal energy \f$u\f$
+ */
+__attribute__((always_inline)) INLINE static float
+gas_pressure_from_internal_energy(float density, float u) {
+
+  return hydro_gamma_minus_one * u * density;
+}
+
+/**
+ * @brief Returns the internal energy given density and pressure.
+ *
+ * Computes \f$u = \frac{1}{\gamma - 1}\frac{P}{\rho}\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param pressure The pressure \f$P\f$.
+ * @return The internal energy \f$u\f$.
+ */
+__attribute__((always_inline)) INLINE static float
+gas_internal_energy_from_pressure(float density, float pressure) {
+  return hydro_one_over_gamma_minus_one * pressure / density;
+}
+
+/**
+ * @brief Returns the sound speed given density and internal energy
+ *
+ * Computes \f$c = \sqrt{\gamma (\gamma - 1) u }\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param u The internal energy \f$u\f$
+ */
+__attribute__((always_inline)) INLINE static float
+gas_soundspeed_from_internal_energy(float density, float u) {
+
+  return sqrtf(u * hydro_gamma * hydro_gamma_minus_one);
+}
+
+/**
+ * @brief Returns the sound speed given density and pressure
+ *
+ * Computes \f$c = \sqrt{\frac{\gamma P}{\rho} }\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param P The pressure \f$P\f$
+ */
+__attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure(
+    float density, float P) {
+
+  const float density_inv = 1.f / density;
+  return sqrtf(hydro_gamma * P * density_inv);
+}
+
+/**
+ * @brief Initialize the eos parameters
+ *
+ * @param e The #eos_paramters
+ * @param params The parsed parameters
+ */
+__attribute__((always_inline)) INLINE static void eos_init(
+    struct eos_parameters *e, const struct swift_params *params) {}
+
+/**
+ * @brief Print the equation of state
+ *
+ * @param e The #eos_parameters
+ */
+__attribute__((always_inline)) INLINE static void eos_print(
+    const struct eos_parameters *e) {
+
+  message("Equation of state: Ideal gas.");
+
+  message("Adiabatic index gamma: %f.", hydro_gamma);
+}
+
+#if defined(HAVE_HDF5)
+/**
+ * @brief Write equation of state information to the snapshot
+ *
+ * @param h_grpsph The HDF5 group in which to write
+ * @param e The #eos_parameters
+ */
+__attribute__((always_inline)) INLINE static void eos_print_snapshot(
+    hid_t h_grpsph, const struct eos_parameters *e) {
+
+  io_write_attribute_f(h_grpsph, "Adiabatic index", hydro_gamma);
+
+  io_write_attribute_s(h_grpsph, "Equation of state", "Ideal gas");
+}
+#endif
+
+#endif /* SWIFT_IDEAL_GAS_EQUATION_OF_STATE_H */
diff --git a/src/equation_of_state/isothermal/equation_of_state.h b/src/equation_of_state/isothermal/equation_of_state.h
new file mode 100644
index 0000000000000000000000000000000000000000..71890b4df656cb5f44d3cb0fbb3bd6005bd6ab6a
--- /dev/null
+++ b/src/equation_of_state/isothermal/equation_of_state.h
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016   Matthieu Schaller (matthieu.schaller@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 SWIFT_ISOTHERMAL_EQUATION_OF_STATE_H
+#define SWIFT_ISOTHERMAL_EQUATION_OF_STATE_H
+
+/* Some standard headers. */
+#include <math.h>
+
+/* Local headers. */
+#include "adiabatic_index.h"
+#include "common_io.h"
+#include "debug.h"
+#include "inline.h"
+
+extern struct eos_parameters eos;
+/* ------------------------------------------------------------------------- */
+
+struct eos_parameters {
+
+  /*! Thermal energy per unit mass */
+  float isothermal_internal_energy;
+};
+
+/**
+ * @brief Returns the internal energy given density and entropy
+ *
+ * Since we are using an isothermal EoS, the entropy and density values are
+ * ignored.
+ * Computes \f$u = u_{cst}\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param entropy The entropy \f$S\f$.
+ */
+__attribute__((always_inline)) INLINE static float
+gas_internal_energy_from_entropy(float density, float entropy) {
+
+  return eos.isothermal_internal_energy;
+}
+
+/**
+ * @brief Returns the pressure given density and entropy
+ *
+ * Since we are using an isothermal EoS, the entropy value is ignored.
+ * Computes \f$P = (\gamma - 1)u_{cst}\rho\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param entropy The entropy \f$S\f$.
+ */
+__attribute__((always_inline)) INLINE static float gas_pressure_from_entropy(
+    float density, float entropy) {
+
+  return hydro_gamma_minus_one * eos.isothermal_internal_energy * density;
+}
+
+/**
+ * @brief Returns the entropy given density and pressure.
+ *
+ * Since we are using an isothermal EoS, the pressure value is ignored.
+ * Computes \f$A = (\gamma - 1)u_{cst}\rho^{-(\gamma-1)}\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param pressure The pressure \f$P\f$ (ignored).
+ * @return The entropy \f$A\f$.
+ */
+__attribute__((always_inline)) INLINE static float gas_entropy_from_pressure(
+    float density, float pressure) {
+
+  return hydro_gamma_minus_one * eos.isothermal_internal_energy *
+         pow_minus_gamma_minus_one(density);
+}
+
+/**
+ * @brief Returns the sound speed given density and entropy
+ *
+ * Since we are using an isothermal EoS, the entropy and density values are
+ * ignored.
+ * Computes \f$c = \sqrt{u_{cst} \gamma (\gamma-1)}\f$.
+ *
+ * @param density The density \f$\rho\f$.
+ * @param entropy The entropy \f$S\f$.
+ */
+__attribute__((always_inline)) INLINE static float gas_soundspeed_from_entropy(
+    float density, float entropy) {
+
+  return sqrtf(eos.isothermal_internal_energy * hydro_gamma *
+               hydro_gamma_minus_one);
+}
+
+/**
+ * @brief Returns the entropy given density and internal energy
+ *
+ * Since we are using an isothermal EoS, the energy value is ignored.
+ * Computes \f$S = \frac{(\gamma - 1)u_{cst}}{\rho^{\gamma-1}}\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param u The internal energy \f$u\f$
+ */
+__attribute__((always_inline)) INLINE static float
+gas_entropy_from_internal_energy(float density, float u) {
+
+  return hydro_gamma_minus_one * eos.isothermal_internal_energy *
+         pow_minus_gamma_minus_one(density);
+}
+
+/**
+ * @brief Returns the pressure given density and internal energy
+ *
+ * Since we are using an isothermal EoS, the energy value is ignored.
+ * Computes \f$P = (\gamma - 1)u_{cst}\rho\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param u The internal energy \f$u\f$
+ */
+__attribute__((always_inline)) INLINE static float
+gas_pressure_from_internal_energy(float density, float u) {
+
+  return hydro_gamma_minus_one * eos.isothermal_internal_energy * density;
+}
+
+/**
+ * @brief Returns the internal energy given density and pressure.
+ *
+ * Just returns the constant internal energy.
+ *
+ * @param density The density \f$\rho\f$ (ignored).
+ * @param pressure The pressure \f$P\f$ (ignored).
+ * @return The internal energy \f$u\f$ (which is constant).
+ */
+__attribute__((always_inline)) INLINE static float
+gas_internal_energy_from_pressure(float density, float pressure) {
+  return eos.isothermal_internal_energy;
+}
+
+/**
+ * @brief Returns the sound speed given density and internal energy
+ *
+ * Since we are using an isothermal EoS, the energy and density values are
+ * ignored.
+ * Computes \f$c = \sqrt{u_{cst} \gamma (\gamma-1)}\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param u The internal energy \f$u\f$
+ */
+__attribute__((always_inline)) INLINE static float
+gas_soundspeed_from_internal_energy(float density, float u) {
+
+  return sqrtf(eos.isothermal_internal_energy * hydro_gamma *
+               hydro_gamma_minus_one);
+}
+
+/**
+ * @brief Returns the sound speed given density and pressure
+ *
+ * Since we are using an isothermal EoS, the pressure and density values are
+ * ignored.
+ * Computes \f$c = \sqrt{u_{cst} \gamma (\gamma-1)}\f$.
+ *
+ * @param density The density \f$\rho\f$
+ * @param P The pressure \f$P\f$
+ */
+__attribute__((always_inline)) INLINE static float gas_soundspeed_from_pressure(
+    float density, float P) {
+
+  return sqrtf(eos.isothermal_internal_energy * hydro_gamma *
+               hydro_gamma_minus_one);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief Initialize the eos parameters
+ *
+ * @param e The #eos_paramters
+ * @param params The parsed parameters
+ */
+__attribute__((always_inline)) INLINE static void eos_init(
+    struct eos_parameters *e, const struct swift_params *params) {
+
+  e->isothermal_internal_energy =
+      parser_get_param_float(params, "EoS:isothermal_internal_energy");
+}
+
+/**
+ * @brief Print the equation of state
+ *
+ * @param e The #eos_parameters
+ */
+__attribute__((always_inline)) INLINE static void eos_print(
+    const struct eos_parameters *e) {
+
+  message(
+      "Equation of state: Isothermal with internal energy "
+      "per unit mass set to %f.",
+      e->isothermal_internal_energy);
+
+  message("Adiabatic index gamma: %f.", hydro_gamma);
+}
+
+#if defined(HAVE_HDF5)
+/**
+ * @brief Write equation of state information to the snapshot
+ *
+ * @param h_grpsph The HDF5 group in which to write
+ * @param e The #eos_parameters
+ */
+__attribute__((always_inline)) INLINE static void eos_print_snapshot(
+    hid_t h_grpsph, const struct eos_parameters *e) {
+
+  io_write_attribute_f(h_grpsph, "Adiabatic index", hydro_gamma);
+
+  io_write_attribute_s(h_grpsph, "Equation of state", "Isothermal gas");
+  io_write_attribute_f(h_grpsph, "Thermal energy per unit mass",
+                       e->isothermal_internal_energy);
+}
+#endif
+
+#endif /* SWIFT_ISOTHERMAL_EQUATION_OF_STATE_H */
diff --git a/src/gravity.c b/src/gravity.c
index 0d951b4a9f8babb68d413e1183b1e2b52129abaf..1642d37f7a6e543c6e2f263253aebc213ad4b19f 100644
--- a/src/gravity.c
+++ b/src/gravity.c
@@ -372,7 +372,9 @@ int gravity_exact_force_file_exits(const struct engine *e) {
 
     /* Check whether it matches the current parameters */
     if (N == SWIFT_GRAVITY_FORCE_CHECKS && periodic == e->s->periodic &&
-        (fabs(epsilon - e->gravity_properties->epsilon) / epsilon < 1e-5) &&
+        (fabs(epsilon - gravity_get_softening(0, e->gravity_properties)) /
+             epsilon <
+         1e-5) &&
         (fabs(newton_G - e->physical_constants->const_newton_G) / newton_G <
          1e-5)) {
       return 1;
@@ -396,6 +398,8 @@ void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
   struct gpart *restrict gparts = (struct gpart *)map_data;
   struct exact_force_data *data = (struct exact_force_data *)extra_data;
   const struct space *s = data->s;
+  const struct part *parts = s->parts;
+  const struct spart *sparts = s->sparts;
   const struct engine *e = data->e;
   const int periodic = s->periodic;
   const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
@@ -406,13 +410,22 @@ void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
 
     struct gpart *gpi = &gparts[i];
 
+    long long id = 0;
+    if (gpi->type == swift_type_gas)
+      id = parts[-gpi->id_or_neg_offset].id;
+    else if (gpi->type == swift_type_star)
+      id = sparts[-gpi->id_or_neg_offset].id;
+    else if (gpi->type == swift_type_black_hole)
+      error("Unexisting type");
+    else
+      id = gpi->id_or_neg_offset;
+
     /* Is the particle active and part of the subset to be tested ? */
-    if (gpi->id_or_neg_offset % SWIFT_GRAVITY_FORCE_CHECKS == 0 &&
-        gpart_is_active(gpi, e)) {
+    if (id % SWIFT_GRAVITY_FORCE_CHECKS == 0 && gpart_is_active(gpi, e)) {
 
       /* Get some information about the particle */
       const double pix[3] = {gpi->x[0], gpi->x[1], gpi->x[2]};
-      const double hi = gpi->epsilon;
+      const double hi = gravity_get_softening(gpi, e->gravity_properties);
       const double hi_inv = 1. / hi;
       const double hi_inv3 = hi_inv * hi_inv * hi_inv;
 
@@ -556,17 +569,21 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
 
 #ifdef SWIFT_GRAVITY_FORCE_CHECKS
 
+  const struct part *parts = s->parts;
+  const struct spart *sparts = s->sparts;
+
   /* File name */
   char file_name_swift[100];
   sprintf(file_name_swift, "gravity_checks_swift_step%d_order%d.dat", e->step,
           SELF_GRAVITY_MULTIPOLE_ORDER);
 
   /* Creare files and write header */
+  const double epsilon = gravity_get_softening(0, e->gravity_properties);
   FILE *file_swift = fopen(file_name_swift, "w");
   fprintf(file_swift, "# Gravity accuracy test - SWIFT FORCES\n");
   fprintf(file_swift, "# G= %16.8e\n", e->physical_constants->const_newton_G);
   fprintf(file_swift, "# N= %d\n", SWIFT_GRAVITY_FORCE_CHECKS);
-  fprintf(file_swift, "# epsilon= %16.8e\n", e->gravity_properties->epsilon);
+  fprintf(file_swift, "# epsilon= %16.8e\n", epsilon);
   fprintf(file_swift, "# periodic= %d\n", s->periodic);
   fprintf(file_swift, "# theta= %16.8e\n", e->gravity_properties->theta_crit);
   fprintf(file_swift, "# Git Branch: %s\n", git_branch());
@@ -580,14 +597,23 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
 
     struct gpart *gpi = &s->gparts[i];
 
+    long long id = 0;
+    if (gpi->type == swift_type_gas)
+      id = parts[-gpi->id_or_neg_offset].id;
+    else if (gpi->type == swift_type_star)
+      id = sparts[-gpi->id_or_neg_offset].id;
+    else if (gpi->type == swift_type_black_hole)
+      error("Unexisting type");
+    else
+      id = gpi->id_or_neg_offset;
+
     /* Is the particle was active and part of the subset to be tested ? */
-    if (gpi->id_or_neg_offset % SWIFT_GRAVITY_FORCE_CHECKS == 0 &&
-        gpart_is_starting(gpi, e)) {
+    if (id % SWIFT_GRAVITY_FORCE_CHECKS == 0 && gpart_is_starting(gpi, e)) {
 
       fprintf(file_swift,
-              "%18lld %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e\n",
-              gpi->id_or_neg_offset, gpi->x[0], gpi->x[1], gpi->x[2],
-              gpi->a_grav[0], gpi->a_grav[1], gpi->a_grav[2], gpi->potential);
+              "%18lld %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e\n", id,
+              gpi->x[0], gpi->x[1], gpi->x[2], gpi->a_grav[0], gpi->a_grav[1],
+              gpi->a_grav[2], gpi->potential);
     }
   }
 
@@ -609,7 +635,7 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
     fprintf(file_exact, "# Gravity accuracy test - EXACT FORCES\n");
     fprintf(file_exact, "# G= %16.8e\n", e->physical_constants->const_newton_G);
     fprintf(file_exact, "# N= %d\n", SWIFT_GRAVITY_FORCE_CHECKS);
-    fprintf(file_exact, "# epsilon=%16.8e\n", e->gravity_properties->epsilon);
+    fprintf(file_exact, "# epsilon=%16.8e\n", epsilon);
     fprintf(file_exact, "# periodic= %d\n", s->periodic);
     fprintf(file_exact, "# Git Branch: %s\n", git_branch());
     fprintf(file_exact, "# Git Revision: %s\n", git_revision());
@@ -622,15 +648,24 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
 
       struct gpart *gpi = &s->gparts[i];
 
+      long long id = 0;
+      if (gpi->type == swift_type_gas)
+        id = parts[-gpi->id_or_neg_offset].id;
+      else if (gpi->type == swift_type_star)
+        id = sparts[-gpi->id_or_neg_offset].id;
+      else if (gpi->type == swift_type_black_hole)
+        error("Unexisting type");
+      else
+        id = gpi->id_or_neg_offset;
+
       /* Is the particle was active and part of the subset to be tested ? */
-      if (gpi->id_or_neg_offset % SWIFT_GRAVITY_FORCE_CHECKS == 0 &&
-          gpart_is_starting(gpi, e)) {
+      if (id % SWIFT_GRAVITY_FORCE_CHECKS == 0 && gpart_is_starting(gpi, e)) {
 
         fprintf(file_exact,
-                "%18lld %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e\n",
-                gpi->id_or_neg_offset, gpi->x[0], gpi->x[1], gpi->x[2],
-                gpi->a_grav_exact[0], gpi->a_grav_exact[1],
-                gpi->a_grav_exact[2], gpi->potential_exact);
+                "%18lld %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e\n", id,
+                gpi->x[0], gpi->x[1], gpi->x[2], gpi->a_grav_exact[0],
+                gpi->a_grav_exact[1], gpi->a_grav_exact[2],
+                gpi->potential_exact);
       }
     }
 
diff --git a/src/gravity.h b/src/gravity.h
index 85e42370bc456dceb577c42ee609e3f0724e14ea..33bef8ba329aa1264334e3319b6250c01b974338 100644
--- a/src/gravity.h
+++ b/src/gravity.h
@@ -24,16 +24,17 @@
 
 /* Local headers. */
 #include "const.h"
-#include "engine.h"
 #include "inline.h"
 #include "part.h"
-#include "space.h"
 
 /* So far only one model here */
 /* Straight-forward import */
 #include "./gravity/Default/gravity.h"
 #include "./gravity/Default/gravity_iact.h"
 
+struct engine;
+struct space;
+
 void gravity_exact_force_ewald_init(double boxSize);
 void gravity_exact_force_ewald_free();
 void gravity_exact_force_compute(struct space *s, const struct engine *e);
diff --git a/src/gravity/Default/gravity.h b/src/gravity/Default/gravity.h
index 099cbcd158436b414b9bc6a912727116b763cff9..eabc95fc7eb1e1d4039dc9cea6611f1d17451a37 100644
--- a/src/gravity/Default/gravity.h
+++ b/src/gravity/Default/gravity.h
@@ -21,8 +21,10 @@
 #define SWIFT_DEFAULT_GRAVITY_H
 
 #include <float.h>
+
 #include "cosmology.h"
 #include "gravity_properties.h"
+#include "kernel_gravity.h"
 #include "minmax.h"
 
 /**
@@ -40,11 +42,12 @@ __attribute__((always_inline)) INLINE static float gravity_get_mass(
  * @brief Returns the softening of a particle
  *
  * @param gp The particle of interest
+ * @param grav_props The global gravity properties.
  */
 __attribute__((always_inline)) INLINE static float gravity_get_softening(
-    const struct gpart* restrict gp) {
+    const struct gpart* gp, const struct gravity_props* restrict grav_props) {
 
-  return gp->epsilon;
+  return grav_props->epsilon_cur;
 }
 
 /**
@@ -102,12 +105,10 @@ gravity_compute_timestep_self(const struct gpart* const gp,
 
   const float ac_inv = (ac2 > 0.f) ? 1.f / sqrtf(ac2) : FLT_MAX;
 
-  // MATTHIEU cosmological evolution of the softening?
-  const float epsilon = gravity_get_softening(gp);
+  const float epsilon = gravity_get_softening(gp, grav_props);
 
-  /* Note that 0.66666667 = 2. (from Gadget) / 3. (Plummer softening) */
-  const float dt =
-      sqrtf(0.66666667f * cosmo->a * grav_props->eta * epsilon * ac_inv);
+  const float dt = sqrtf(2. * kernel_gravity_softening_plummer_equivalent_inv *
+                         cosmo->a * grav_props->eta * epsilon * ac_inv);
 
   return dt;
 }
@@ -183,7 +184,6 @@ __attribute__((always_inline)) INLINE static void gravity_first_init_gpart(
     struct gpart* gp, const struct gravity_props* grav_props) {
 
   gp->time_bin = 0;
-  gp->epsilon = grav_props->epsilon;
 
   gravity_init_gpart(gp);
 }
diff --git a/src/gravity/Default/gravity_debug.h b/src/gravity/Default/gravity_debug.h
index b83f8c73b4678145f2ecd6d94b136b5aadffccbd..dce038c58e1769446861bdf6c9a2a44415642c68 100644
--- a/src/gravity/Default/gravity_debug.h
+++ b/src/gravity/Default/gravity_debug.h
@@ -22,9 +22,9 @@
 __attribute__((always_inline)) INLINE static void gravity_debug_particle(
     const struct gpart* p) {
   printf(
-      "mass=%.3e epsilon=%.5e time_bin=%d\n"
+      "mass=%.3e time_bin=%d\n"
       "x=[%.5e,%.5e,%.5e], v_full=[%.5e,%.5e,%.5e], a=[%.5e,%.5e,%.5e]\n",
-      p->mass, p->epsilon, p->time_bin, p->x[0], p->x[1], p->x[2], p->v_full[0],
+      p->mass, p->time_bin, p->x[0], p->x[1], p->x[2], p->v_full[0],
       p->v_full[1], p->v_full[2], p->a_grav[0], p->a_grav[1], p->a_grav[2]);
 #ifdef SWIFT_DEBUG_CHECKS
   printf("num_interacted=%lld ti_drift=%lld ti_kick=%lld\n", p->num_interacted,
diff --git a/src/gravity/Default/gravity_io.h b/src/gravity/Default/gravity_io.h
index 26f7a6d15e11cf2e2d9ccd9978a1c67bab17d852..7b8ec2c8fef04cc4a4fc6836d8bb895b24d3c41f 100644
--- a/src/gravity/Default/gravity_io.h
+++ b/src/gravity/Default/gravity_io.h
@@ -35,6 +35,38 @@ void convert_gpart_pos(const struct engine* e, const struct gpart* gp,
   }
 }
 
+void convert_gpart_vel(const struct engine* e, const struct gpart* gp,
+                       float* ret) {
+
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const struct cosmology* cosmo = e->cosmology;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+
+  const integertime_t ti_beg = get_integer_time_begin(ti_current, gp->time_bin);
+  const integertime_t ti_end = get_integer_time_end(ti_current, gp->time_bin);
+
+  /* Get time-step since the last kick */
+  float dt_kick_grav;
+  if (with_cosmology) {
+    dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_grav -=
+        cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+  } else {
+    dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+  }
+
+  /* Extrapolate the velocites to the current time */
+  ret[0] = gp->v_full[0] + gp->a_grav[0] * dt_kick_grav;
+  ret[1] = gp->v_full[1] + gp->a_grav[1] * dt_kick_grav;
+  ret[2] = gp->v_full[2] + gp->a_grav[2] * dt_kick_grav;
+
+  /* Conversion from internal units to peculiar velocities */
+  ret[0] *= cosmo->a2_inv;
+  ret[1] *= cosmo->a2_inv;
+  ret[2] *= cosmo->a2_inv;
+}
+
 /**
  * @brief Specifies which g-particle fields to read from a dataset
  *
@@ -55,7 +87,7 @@ void darkmatter_read_particles(struct gpart* gparts, struct io_props* list,
                                 UNIT_CONV_SPEED, gparts, v_full);
   list[2] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS,
                                 gparts, mass);
-  list[3] = io_make_input_field("ParticleIDs", LONGLONG, 1, COMPULSORY,
+  list[3] = io_make_input_field("ParticleIDs", ULONGLONG, 1, COMPULSORY,
                                 UNIT_CONV_NO_UNITS, gparts, id_or_neg_offset);
 }
 
@@ -69,20 +101,20 @@ void darkmatter_read_particles(struct gpart* gparts, struct io_props* list,
 void darkmatter_write_particles(const struct gpart* gparts,
                                 struct io_props* list, int* num_fields) {
 
-  /* Say how much we want to read */
+  /* Say how much we want to write */
   *num_fields = 5;
 
-  /* List what we want to read */
+  /* List what we want to write */
   list[0] = io_make_output_field_convert_gpart(
       "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, gparts, convert_gpart_pos);
-  list[1] = io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED,
-                                 gparts, v_full);
+  list[1] = io_make_output_field_convert_gpart(
+      "Velocities", FLOAT, 3, UNIT_CONV_SPEED, gparts, convert_gpart_vel);
   list[2] =
       io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, gparts, mass);
   list[3] = io_make_output_field("ParticleIDs", ULONGLONG, 1,
                                  UNIT_CONV_NO_UNITS, gparts, id_or_neg_offset);
-  list[4] = io_make_output_field("Acceleration", FLOAT, 3,
-                                 UNIT_CONV_ACCELERATION, gparts, a_grav);
+  list[4] = io_make_output_field("Potential", FLOAT, 1, UNIT_CONV_POTENTIAL,
+                                 gparts, potential);
 }
 
 #endif /* SWIFT_DEFAULT_GRAVITY_IO_H */
diff --git a/src/gravity/Default/gravity_part.h b/src/gravity/Default/gravity_part.h
index 4c7a7b5d4af1c26ee96ac797963f5588d3303d77..06b9c52e14a655aa97b6c36ff9dca1f1cdd6e9a0 100644
--- a/src/gravity/Default/gravity_part.h
+++ b/src/gravity/Default/gravity_part.h
@@ -22,35 +22,32 @@
 /* Gravity particle. */
 struct gpart {
 
-  /* Particle ID. If negative, it is the negative offset of the #part with
+  /*! Particle ID. If negative, it is the negative offset of the #part with
      which this gpart is linked. */
   long long id_or_neg_offset;
 
-  /* Particle position. */
+  /*! Particle position. */
   double x[3];
 
-  /* Offset between current position and position at last tree rebuild. */
+  /*! Offset between current position and position at last tree rebuild. */
   float x_diff[3];
 
-  /* Particle velocity. */
+  /*! Particle velocity. */
   float v_full[3];
 
-  /* Particle acceleration. */
+  /*! Particle acceleration. */
   float a_grav[3];
 
-  /* Particle mass. */
+  /*! Particle mass. */
   float mass;
 
-  /* Gravitational potential */
+  /*! Gravitational potential */
   float potential;
 
-  /* Softening length */
-  float epsilon;
-
-  /* Time-step length */
+  /*! Time-step length */
   timebin_t time_bin;
 
-  /* Type of the #gpart (DM, gas, star, ...) */
+  /*! Type of the #gpart (DM, gas, star, ...) */
   enum part_type type;
 
 #ifdef SWIFT_DEBUG_CHECKS
diff --git a/src/gravity_cache.h b/src/gravity_cache.h
index be349cfd4a4583a493219eb020757341c98f540c..0012be193c657abccd5d83ed872e4d21764065a0 100644
--- a/src/gravity_cache.h
+++ b/src/gravity_cache.h
@@ -149,14 +149,16 @@ static INLINE void gravity_cache_init(struct gravity_cache *c, int count) {
  * @param shift A shift to apply to all the particles.
  * @param CoM The position of the multipole.
  * @param r_max2 The square of the multipole radius.
- * @param theta_crit2 The square of the opening angle.
  * @param cell The cell we play with (to get reasonable padding positions).
+ * @param grav_props The global gravity properties.
  */
 __attribute__((always_inline)) INLINE static void gravity_cache_populate(
     timebin_t max_active_bin, struct gravity_cache *c,
     const struct gpart *restrict gparts, int gcount, int gcount_padded,
-    const double shift[3], const float CoM[3], float r_max2, float theta_crit2,
-    const struct cell *cell) {
+    const double shift[3], const float CoM[3], float r_max2,
+    const struct cell *cell, const struct gravity_props *grav_props) {
+
+  const float theta_crit2 = grav_props->theta_crit2;
 
   /* Make the compiler understand we are in happy vectorization land */
   swift_declare_aligned_ptr(float, x, c->x, SWIFT_CACHE_ALIGNMENT);
@@ -174,7 +176,7 @@ __attribute__((always_inline)) INLINE static void gravity_cache_populate(
     x[i] = (float)(gparts[i].x[0] - shift[0]);
     y[i] = (float)(gparts[i].x[1] - shift[1]);
     z[i] = (float)(gparts[i].x[2] - shift[2]);
-    epsilon[i] = gparts[i].epsilon;
+    epsilon[i] = gravity_get_softening(&gparts[i], grav_props);
     m[i] = gparts[i].mass;
     active[i] = (int)(gparts[i].time_bin <= max_active_bin);
 
@@ -220,13 +222,15 @@ __attribute__((always_inline)) INLINE static void gravity_cache_populate(
  * multiple of the vector length.
  * @param shift A shift to apply to all the particles.
  * @param cell The cell we play with (to get reasonable padding positions).
+ * @param grav_props The global gravity properties.
  */
 __attribute__((always_inline)) INLINE static void
 gravity_cache_populate_no_mpole(timebin_t max_active_bin,
                                 struct gravity_cache *c,
                                 const struct gpart *restrict gparts, int gcount,
                                 int gcount_padded, const double shift[3],
-                                const struct cell *cell) {
+                                const struct cell *cell,
+                                const struct gravity_props *grav_props) {
 
   /* Make the compiler understand we are in happy vectorization land */
   swift_declare_aligned_ptr(float, x, c->x, SWIFT_CACHE_ALIGNMENT);
@@ -242,7 +246,7 @@ gravity_cache_populate_no_mpole(timebin_t max_active_bin,
     x[i] = (float)(gparts[i].x[0] - shift[0]);
     y[i] = (float)(gparts[i].x[1] - shift[1]);
     z[i] = (float)(gparts[i].x[2] - shift[2]);
-    epsilon[i] = gparts[i].epsilon;
+    epsilon[i] = gravity_get_softening(&gparts[i], grav_props);
     m[i] = gparts[i].mass;
     active[i] = (int)(gparts[i].time_bin <= max_active_bin);
   }
diff --git a/src/gravity_properties.c b/src/gravity_properties.c
index 1df421a8b21424dc99e52bc9dbc59560e54d14a5..79be11a8bab2389c19c58a59851379ea23d5fb3f 100644
--- a/src/gravity_properties.c
+++ b/src/gravity_properties.c
@@ -37,7 +37,8 @@
 #define gravity_props_default_r_cut_min 0.1f
 
 void gravity_props_init(struct gravity_props *p,
-                        const struct swift_params *params) {
+                        const struct swift_params *params,
+                        const struct cosmology *cosmo) {
 
   /* Tree-PM parameters */
   p->a_smooth = parser_get_opt_param_float(params, "Gravity:a_smooth",
@@ -56,11 +57,35 @@ void gravity_props_init(struct gravity_props *p,
   p->theta_crit2 = p->theta_crit * p->theta_crit;
   p->theta_crit_inv = 1. / p->theta_crit;
 
-  /* Softening lengths */
-  p->epsilon = 3. * parser_get_param_double(params, "Gravity:epsilon");
-  p->epsilon2 = p->epsilon * p->epsilon;
-  p->epsilon_inv = 1.f / p->epsilon;
-  p->epsilon_inv3 = p->epsilon_inv * p->epsilon_inv * p->epsilon_inv;
+  /* Softening parameters */
+  p->epsilon_comoving =
+      parser_get_param_double(params, "Gravity:comoving_softening");
+  p->epsilon_max_physical =
+      parser_get_param_double(params, "Gravity:max_physical_softening");
+
+  /* Set the softening to the current time */
+  gravity_update(p, cosmo);
+}
+
+void gravity_update(struct gravity_props *p, const struct cosmology *cosmo) {
+
+  /* Current softening lengths */
+  double softening;
+  if (p->epsilon_comoving * cosmo->a > p->epsilon_max_physical)
+    softening = p->epsilon_max_physical / cosmo->a;
+  else
+    softening = p->epsilon_comoving;
+
+  /* Plummer equivalent -> internal */
+  softening *= kernel_gravity_softening_plummer_equivalent;
+
+  /* Store things */
+  p->epsilon_cur = softening;
+
+  /* Other factors */
+  p->epsilon_cur2 = softening * softening;
+  p->epsilon_cur_inv = 1. / softening;
+  p->epsilon_cur_inv3 = 1. / (softening * softening * softening);
 }
 
 void gravity_props_print(const struct gravity_props *p) {
@@ -72,8 +97,17 @@ void gravity_props_print(const struct gravity_props *p) {
 
   message("Self-gravity opening angle:  theta=%.4f", p->theta_crit);
 
-  message("Self-gravity softening:    epsilon=%.4f (Plummer equivalent: %.4f)",
-          p->epsilon, p->epsilon / 3.);
+  message(
+      "Self-gravity comoving softening:    epsilon=%.4f (Plummer equivalent: "
+      "%.4f)",
+      p->epsilon_comoving * kernel_gravity_softening_plummer_equivalent,
+      p->epsilon_comoving);
+
+  message(
+      "Self-gravity maximal physical softening:    epsilon=%.4f (Plummer "
+      "equivalent: %.4f)",
+      p->epsilon_max_physical * kernel_gravity_softening_plummer_equivalent,
+      p->epsilon_max_physical);
 
   message("Self-gravity mesh smoothing-scale: a_smooth=%f", p->a_smooth);
 
@@ -86,9 +120,18 @@ void gravity_props_print_snapshot(hid_t h_grpgrav,
                                   const struct gravity_props *p) {
 
   io_write_attribute_f(h_grpgrav, "Time integration eta", p->eta);
-  io_write_attribute_f(h_grpgrav, "Softening length", p->epsilon);
-  io_write_attribute_f(h_grpgrav, "Softening length (Plummer equivalent)",
-                       p->epsilon / 3.);
+  io_write_attribute_f(
+      h_grpgrav, "Comoving softening length",
+      p->epsilon_comoving * kernel_gravity_softening_plummer_equivalent);
+  io_write_attribute_f(h_grpgrav,
+                       "Comoving Softening length (Plummer equivalent)",
+                       p->epsilon_comoving);
+  io_write_attribute_f(
+      h_grpgrav, "Maximal physical softening length",
+      p->epsilon_max_physical * kernel_gravity_softening_plummer_equivalent);
+  io_write_attribute_f(h_grpgrav,
+                       "Maximal physical softening length (Plummer equivalent)",
+                       p->epsilon_max_physical);
   io_write_attribute_f(h_grpgrav, "Opening angle", p->theta_crit);
   io_write_attribute_d(h_grpgrav, "MM order", SELF_GRAVITY_MULTIPOLE_ORDER);
   io_write_attribute_f(h_grpgrav, "Mesh a_smooth", p->a_smooth);
diff --git a/src/gravity_properties.h b/src/gravity_properties.h
index 826ffd0de05d376b930523c8a5d937e457c6d795..f36a39a6e187b8b397a5f597692f5a37c982aa7a 100644
--- a/src/gravity_properties.h
+++ b/src/gravity_properties.h
@@ -27,6 +27,7 @@
 #endif
 
 /* Local includes. */
+#include "cosmology.h"
 #include "parser.h"
 #include "restart.h"
 
@@ -58,22 +59,30 @@ struct gravity_props {
   /*! Inverse of opening angle */
   double theta_crit_inv;
 
-  /*! Softening length */
-  float epsilon;
+  /*! Comoving softening */
+  double epsilon_comoving;
 
-  /*! Square of softening length */
-  float epsilon2;
+  /*! Maxium physical softening */
+  double epsilon_max_physical;
 
-  /*! Inverse of softening length */
-  float epsilon_inv;
+  /*! Current sftening length */
+  float epsilon_cur;
 
-  /*! Cube of the inverse of softening length */
-  float epsilon_inv3;
+  /*! Square of current softening length */
+  float epsilon_cur2;
+
+  /*! Inverse of current softening length */
+  float epsilon_cur_inv;
+
+  /*! Cube of the inverse of current oftening length */
+  float epsilon_cur_inv3;
 };
 
 void gravity_props_print(const struct gravity_props *p);
 void gravity_props_init(struct gravity_props *p,
-                        const struct swift_params *params);
+                        const struct swift_params *params,
+                        const struct cosmology *cosmo);
+void gravity_update(struct gravity_props *p, const struct cosmology *cosmo);
 
 #if defined(HAVE_HDF5)
 void gravity_props_print_snapshot(hid_t h_grpsph,
diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h
index 1228aa69abfe812e5b2e73f066bb13be3292aa20..7da005456233b800e05e75389922395ea3c1702c 100644
--- a/src/hydro/Default/hydro.h
+++ b/src/hydro/Default/hydro.h
@@ -160,6 +160,18 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
   return p->mass;
 }
 
+/**
+ * @brief Sets the mass of a particle
+ *
+ * @param p The particle of interest
+ * @param m The mass to set.
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_mass(
+    struct part *restrict p, float m) {
+
+  p->mass = m;
+}
+
 /**
  * @brief Returns the velocities drifted to the current time of a particle.
  *
@@ -492,7 +504,8 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  * @param dt_therm The time-step for this kick (for thermodynamic quantities)
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {}
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm,
+    const struct cosmology *cosmo, const struct hydro_props *hydro_props) {}
 
 /**
  *  @brief Converts hydro quantity of a particle at the start of a run
@@ -500,9 +513,12 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
  * Requires the density to be known
  *
  * @param p The particle to act upon
+ * @param xp The extended data.
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part *restrict p, struct xpart *restrict xp) {}
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {}
 
 /**
  * @brief Initialises the particles for the first time
@@ -529,4 +545,21 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   hydro_init_part(p, NULL);
 }
 
+/**
+ * @brief Overwrite the initial internal energy of a particle.
+ *
+ * Note that in the cases where the thermodynamic variable is not
+ * internal energy but gets converted later, we must overwrite that
+ * field. The conversion to the actual variable happens later after
+ * the initial fake time-step.
+ *
+ * @param p The #part to write to.
+ * @param u_init The new initial internal energy.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_set_init_internal_energy(struct part *p, float u_init) {
+
+  p->u = u_init;
+}
+
 #endif /* SWIFT_DEFAULT_HYDRO_H */
diff --git a/src/hydro/Default/hydro_io.h b/src/hydro/Default/hydro_io.h
index bfff08dcdf061d86986ffdeabee6e7a84cba1c7b..e70a26f9edc3f7497dd4c548efd464726efe0e39 100644
--- a/src/hydro/Default/hydro_io.h
+++ b/src/hydro/Default/hydro_io.h
@@ -54,7 +54,7 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
-                      double* ret) {
+                      const struct xpart* xp, double* ret) {
 
   if (e->s->periodic) {
     ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]);
@@ -67,6 +67,49 @@ void convert_part_pos(const struct engine* e, const struct part* p,
   }
 }
 
+void convert_part_vel(const struct engine* e, const struct part* p,
+                      const struct xpart* xp, float* ret) {
+
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const struct cosmology* cosmo = e->cosmology;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+
+  const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin);
+  const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin);
+
+  /* Get time-step since the last kick */
+  float dt_kick_grav, dt_kick_hydro;
+  if (with_cosmology) {
+    dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_grav -=
+        cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_hydro -=
+        cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+  } else {
+    dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+  }
+
+  /* Extrapolate the velocites to the current time */
+  hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, ret);
+
+  /* Conversion from internal units to peculiar velocities */
+  ret[0] *= cosmo->a2_inv;
+  ret[1] *= cosmo->a2_inv;
+  ret[2] *= cosmo->a2_inv;
+}
+
+void convert_part_potential(const struct engine* e, const struct part* p,
+                            const struct xpart* xp, float* ret) {
+
+  if (p->gpart != NULL)
+    ret[0] = gravity_get_comoving_potential(p->gpart);
+  else
+    ret[0] = 0.f;
+}
+
 /**
  * @brief Specifies which particle fields to write to a dataset
  *
@@ -74,16 +117,17 @@ void convert_part_pos(const struct engine* e, const struct part* p,
  * @param list The list of i/o properties to write.
  * @param num_fields The number of i/o fields to write.
  */
-void hydro_write_particles(struct part* parts, struct io_props* list,
-                           int* num_fields) {
+void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
+                           struct io_props* list, int* num_fields) {
 
-  *num_fields = 7;
+  *num_fields = 8;
 
   /* List what we want to write */
-  list[0] = io_make_output_field_convert_part(
-      "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, parts, convert_part_pos);
-  list[1] =
-      io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, v);
+  list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3,
+                                              UNIT_CONV_LENGTH, parts, xparts,
+                                              convert_part_pos);
+  list[1] = io_make_output_field_convert_part(
+      "Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, xparts, convert_part_vel);
   list[2] =
       io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts, mass);
   list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH,
@@ -94,6 +138,9 @@ void hydro_write_particles(struct part* parts, struct io_props* list,
                                  UNIT_CONV_NO_UNITS, parts, id);
   list[6] =
       io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho);
+  list[7] = io_make_output_field_convert_part("Potential", FLOAT, 1,
+                                              UNIT_CONV_POTENTIAL, parts,
+                                              xparts, convert_part_potential);
 }
 
 /**
diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h
index 185a98b6d207bb851512a686be51414341fe7740..bc06a24e2a8245556a1042f2459273b8d750489e 100644
--- a/src/hydro/Gadget2/hydro.h
+++ b/src/hydro/Gadget2/hydro.h
@@ -170,6 +170,18 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
   return p->mass;
 }
 
+/**
+ * @brief Sets the mass of a particle
+ *
+ * @param p The particle of interest
+ * @param m The mass to set.
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_mass(
+    struct part *restrict p, float m) {
+
+  p->mass = m;
+}
+
 /**
  * @brief Returns the velocities drifted to the current time of a particle.
  *
@@ -513,19 +525,29 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  * @param p The particle to act upon
  * @param xp The particle extended data to act upon
  * @param dt_therm The time-step for this kick (for thermodynamic quantities)
+ * @param cosmo The cosmological model.
+ * @param hydro_props The constants used in the scheme
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm,
+    const struct cosmology *cosmo, const struct hydro_props *hydro_props) {
 
   /* Do not decrease the entropy by more than a factor of 2 */
   if (dt_therm > 0. && p->entropy_dt * dt_therm < -0.5f * xp->entropy_full) {
-    /* message("Warning! Limiting entropy_dt. Possible cooling error.\n
-     * entropy_full = %g \n entropy_dt * dt =%g \n", */
-    /* 	     xp->entropy_full,p->entropy_dt * dt); */
     p->entropy_dt = -0.5f * xp->entropy_full / dt_therm;
   }
   xp->entropy_full += p->entropy_dt * dt_therm;
 
+  /* Apply the minimal energy limit */
+  const float density = p->rho * cosmo->a3_inv;
+  const float min_energy = hydro_props->minimal_internal_energy;
+  const float min_entropy =
+      gas_entropy_from_internal_energy(density, min_energy);
+  if (xp->entropy_full < min_entropy) {
+    xp->entropy_full = min_entropy;
+    p->entropy_dt = 0.f;
+  }
+
   /* Compute the pressure */
   const float pressure = gas_pressure_from_entropy(p->rho, xp->entropy_full);
 
@@ -545,13 +567,18 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
  *
  * Requires the density to be known
  *
- * @param p The particle to act upon
+ * @param p The particle to act upon.
+ * @param xp The extended data.
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
-  /* We read u in the entropy field. We now get S from u */
-  xp->entropy_full = gas_entropy_from_internal_energy(p->rho, p->entropy);
+  /* We read u in the entropy field. We now get (comoving) S from (physical) u
+   * and (physical) rho. Note that comoving S == physical S */
+  xp->entropy_full =
+      gas_entropy_from_internal_energy(p->rho * cosmo->a3_inv, p->entropy);
   p->entropy = xp->entropy_full;
 
   /* Compute the pressure */
@@ -593,4 +620,21 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   hydro_init_part(p, NULL);
 }
 
+/**
+ * @brief Overwrite the initial internal energy of a particle.
+ *
+ * Note that in the cases where the thermodynamic variable is not
+ * internal energy but gets converted later, we must overwrite that
+ * field. The conversion to the actual variable happens later after
+ * the initial fake time-step.
+ *
+ * @param p The #part to write to.
+ * @param u_init The new initial internal energy.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_set_init_internal_energy(struct part *p, float u_init) {
+
+  p->entropy = u_init;
+}
+
 #endif /* SWIFT_GADGET2_HYDRO_H */
diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h
index b7fa7dd4aa00249d009037961888c89abc0d0313..b2af8909bed1780586a5130370222c9b8157d724 100644
--- a/src/hydro/Gadget2/hydro_iact.h
+++ b/src/hydro/Gadget2/hydro_iact.h
@@ -59,9 +59,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
   const float mi = pi->mass;
   const float mj = pj->mass;
 
-  /* Get r and r inverse. */
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Compute the kernel function for pi */
   const float hi_inv = 1.f / hi;
@@ -148,9 +148,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
   /* Get the masses. */
   const float mj = pj->mass;
 
-  /* Get r and r inverse. */
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Compute the kernel function */
   const float hi_inv = 1.0f / hi;
@@ -440,8 +440,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   const float fac_mu = pow_three_gamma_minus_five_over_two(a);
   const float a2_Hubble = a * a * H;
 
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Get some values in local variables. */
   const float mi = pi->mass;
@@ -559,8 +560,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   const float fac_mu = pow_three_gamma_minus_five_over_two(a);
   const float a2_Hubble = a * a * H;
 
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Get some values in local variables. */
   // const float mi = pi->mass;
diff --git a/src/hydro/Gadget2/hydro_io.h b/src/hydro/Gadget2/hydro_io.h
index 5c329e9d7297109c378e04f0e4931a0717e07278..28c0eea4772f51fab35a08d43c0564472694eeeb 100644
--- a/src/hydro/Gadget2/hydro_io.h
+++ b/src/hydro/Gadget2/hydro_io.h
@@ -55,18 +55,20 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
                                 UNIT_CONV_DENSITY, parts, rho);
 }
 
-void convert_u(const struct engine* e, const struct part* p, float* ret) {
+void convert_part_u(const struct engine* e, const struct part* p,
+                    const struct xpart* xp, float* ret) {
 
   ret[0] = hydro_get_comoving_internal_energy(p);
 }
 
-void convert_P(const struct engine* e, const struct part* p, float* ret) {
+void convert_part_P(const struct engine* e, const struct part* p,
+                    const struct xpart* xp, float* ret) {
 
   ret[0] = hydro_get_comoving_pressure(p);
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
-                      double* ret) {
+                      const struct xpart* xp, double* ret) {
 
   if (e->s->periodic) {
     ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]);
@@ -79,6 +81,49 @@ void convert_part_pos(const struct engine* e, const struct part* p,
   }
 }
 
+void convert_part_vel(const struct engine* e, const struct part* p,
+                      const struct xpart* xp, float* ret) {
+
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const struct cosmology* cosmo = e->cosmology;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+
+  const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin);
+  const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin);
+
+  /* Get time-step since the last kick */
+  float dt_kick_grav, dt_kick_hydro;
+  if (with_cosmology) {
+    dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_grav -=
+        cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_hydro -=
+        cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+  } else {
+    dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+  }
+
+  /* Extrapolate the velocites to the current time */
+  hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, ret);
+
+  /* Conversion from internal units to peculiar velocities */
+  ret[0] *= cosmo->a2_inv;
+  ret[1] *= cosmo->a2_inv;
+  ret[2] *= cosmo->a2_inv;
+}
+
+void convert_part_potential(const struct engine* e, const struct part* p,
+                            const struct xpart* xp, float* ret) {
+
+  if (p->gpart != NULL)
+    ret[0] = gravity_get_comoving_potential(p->gpart);
+  else
+    ret[0] = 0.f;
+}
+
 /**
  * @brief Specifies which particle fields to write to a dataset
  *
@@ -86,16 +131,17 @@ void convert_part_pos(const struct engine* e, const struct part* p,
  * @param list The list of i/o properties to write.
  * @param num_fields The number of i/o fields to write.
  */
-void hydro_write_particles(const struct part* parts, struct io_props* list,
-                           int* num_fields) {
+void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
+                           struct io_props* list, int* num_fields) {
 
-  *num_fields = 9;
+  *num_fields = 10;
 
   /* List what we want to write */
-  list[0] = io_make_output_field_convert_part(
-      "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, parts, convert_part_pos);
-  list[1] =
-      io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, v);
+  list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3,
+                                              UNIT_CONV_LENGTH, parts, xparts,
+                                              convert_part_pos);
+  list[1] = io_make_output_field_convert_part(
+      "Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, xparts, convert_part_vel);
   list[2] =
       io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts, mass);
   list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH,
@@ -108,9 +154,13 @@ void hydro_write_particles(const struct part* parts, struct io_props* list,
       io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho);
   list[7] = io_make_output_field_convert_part("InternalEnergy", FLOAT, 1,
                                               UNIT_CONV_ENERGY_PER_UNIT_MASS,
-                                              parts, convert_u);
+                                              parts, xparts, convert_part_u);
   list[8] = io_make_output_field_convert_part(
-      "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, convert_P);
+      "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, xparts, convert_part_P);
+
+  list[9] = io_make_output_field_convert_part("Potential", FLOAT, 1,
+                                              UNIT_CONV_POTENTIAL, parts,
+                                              xparts, convert_part_potential);
 
 #ifdef DEBUG_INTERACTIONS_SPH
 
diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h
index 0faa4bf39ae533ee9942898bdc08118ee4078868..bc90a6790fa8123b19badf63761a6dd1378197f6 100644
--- a/src/hydro/Gizmo/hydro.h
+++ b/src/hydro/Gizmo/hydro.h
@@ -517,7 +517,7 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
  * @param p The particle to act upon.
  */
 __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part* p, struct xpart* xp) {}
+    struct part* p, struct xpart* xp, const struct cosmology* cosmo) {}
 
 /**
  * @brief Extra operations to be done during the drift
@@ -611,7 +611,8 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  * @param half_dt Half the physical time step.
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part* p, struct xpart* xp, float dt) {
+    struct part* p, struct xpart* xp, float dt, const struct cosmology* cosmo,
+    const struct hydro_props* hydro_props) {
 
   float a_grav[3];
 
@@ -628,6 +629,14 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
   p->conserved.energy += p->conserved.flux.energy * dt;
 #endif
 
+  /* Apply the minimal energy limit */
+  const float min_energy =
+      hydro_props->minimal_internal_energy * cosmo->a_factor_internal_energy;
+  if (p->conserved.energy < min_energy) {
+    p->conserved.energy = min_energy;
+    p->conserved.flux.energy = 0.f;
+  }
+
   gizmo_check_physical_quantity("mass", p->conserved.mass);
   gizmo_check_physical_quantity("energy", p->conserved.energy);
 
@@ -812,6 +821,18 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
   return p->conserved.mass;
 }
 
+/**
+ * @brief Sets the mass of a particle
+ *
+ * @param p The particle of interest
+ * @param m The mass to set.
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_mass(
+    struct part* restrict p, float m) {
+
+  p->conserved.mass = m;
+}
+
 /**
  * @brief Returns the velocities drifted to the current time of a particle.
  *
@@ -917,4 +938,29 @@ __attribute__((always_inline)) INLINE static void hydro_set_entropy(
   p->primitives.P = S * pow_gamma(p->primitives.rho);
 }
 
+/**
+ * @brief Overwrite the initial internal energy of a particle.
+ *
+ * Note that in the cases where the thermodynamic variable is not
+ * internal energy but gets converted later, we must overwrite that
+ * field. The conversion to the actual variable happens later after
+ * the initial fake time-step.
+ *
+ * @param p The #part to write to.
+ * @param u_init The new initial internal energy.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_set_init_internal_energy(struct part* p, float u_init) {
+
+  p->conserved.energy = u_init * p->conserved.mass;
+#ifdef GIZMO_TOTAL_ENERGY
+  /* add the kinetic energy */
+  p->conserved.energy += 0.5f * p->conserved.mass *
+                         (p->conserved.momentum[0] * p->primitives.v[0] +
+                          p->conserved.momentum[1] * p->primitives.v[1] +
+                          p->conserved.momentum[2] * p->primitives.v[2]);
+#endif
+  p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u_init;
+}
+
 #endif /* SWIFT_GIZMO_HYDRO_H */
diff --git a/src/hydro/Gizmo/hydro_io.h b/src/hydro/Gizmo/hydro_io.h
index b8e2e30646c3aafb73d387010ab7ea0b0a663a77..7aa56b3bde5247f4839b8f4f60cdb3de67253392 100644
--- a/src/hydro/Gizmo/hydro_io.h
+++ b/src/hydro/Gizmo/hydro_io.h
@@ -72,7 +72,8 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
  * @param p Particle.
  * @param ret (return) Internal energy of the particle
  */
-void convert_u(const struct engine* e, const struct part* p, float* ret) {
+void convert_u(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
 
   ret[0] = hydro_get_comoving_internal_energy(p);
 }
@@ -84,7 +85,8 @@ void convert_u(const struct engine* e, const struct part* p, float* ret) {
  * @param p Particle.
  * @param ret (return) Entropic function of the particle
  */
-void convert_A(const struct engine* e, const struct part* p, float* ret) {
+void convert_A(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
   ret[0] = hydro_get_comoving_entropy(p);
 }
 
@@ -95,7 +97,8 @@ void convert_A(const struct engine* e, const struct part* p, float* ret) {
  * @param p Particle.
  * @return Total energy of the particle
  */
-void convert_Etot(const struct engine* e, const struct part* p, float* ret) {
+void convert_Etot(const struct engine* e, const struct part* p,
+                  const struct xpart* xp, float* ret) {
 #ifdef GIZMO_TOTAL_ENERGY
   ret[0] = p->conserved.energy;
 #else
@@ -110,7 +113,7 @@ void convert_Etot(const struct engine* e, const struct part* p, float* ret) {
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
-                      double* ret) {
+                      const struct xpart* xp, double* ret) {
 
   if (e->s->periodic) {
     ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]);
@@ -123,6 +126,49 @@ void convert_part_pos(const struct engine* e, const struct part* p,
   }
 }
 
+void convert_part_vel(const struct engine* e, const struct part* p,
+                      const struct xpart* xp, float* ret) {
+
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const struct cosmology* cosmo = e->cosmology;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+
+  const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin);
+  const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin);
+
+  /* Get time-step since the last kick */
+  float dt_kick_grav, dt_kick_hydro;
+  if (with_cosmology) {
+    dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_grav -=
+        cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_hydro -=
+        cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+  } else {
+    dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+  }
+
+  /* Extrapolate the velocites to the current time */
+  hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, ret);
+
+  /* Conversion from internal units to peculiar velocities */
+  ret[0] *= cosmo->a2_inv;
+  ret[1] *= cosmo->a2_inv;
+  ret[2] *= cosmo->a2_inv;
+}
+
+void convert_part_potential(const struct engine* e, const struct part* p,
+                            const struct xpart* xp, float* ret) {
+
+  if (p->gpart != NULL)
+    ret[0] = gravity_get_comoving_potential(p->gpart);
+  else
+    ret[0] = 0.f;
+}
+
 /**
  * @brief Specifies which particle fields to write to a dataset
  *
@@ -130,33 +176,39 @@ void convert_part_pos(const struct engine* e, const struct part* p,
  * @param list The list of i/o properties to write.
  * @param num_fields The number of i/o fields to write.
  */
-void hydro_write_particles(struct part* parts, struct io_props* list,
-                           int* num_fields) {
+void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
+                           struct io_props* list, int* num_fields) {
 
-  *num_fields = 10;
+  *num_fields = 11;
 
   /* List what we want to write */
-  list[0] = io_make_output_field_convert_part(
-      "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, parts, convert_part_pos);
-  list[1] = io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts,
-                                 primitives.v);
+  list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3,
+                                              UNIT_CONV_LENGTH, parts, xparts,
+                                              convert_part_pos);
+  list[1] = io_make_output_field_convert_part(
+      "Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, xparts, convert_part_vel);
+
   list[2] = io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts,
                                  conserved.mass);
   list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH,
                                  parts, h);
   list[4] = io_make_output_field_convert_part("InternalEnergy", FLOAT, 1,
                                               UNIT_CONV_ENERGY_PER_UNIT_MASS,
-                                              parts, convert_u);
+                                              parts, xparts, convert_u);
   list[5] = io_make_output_field("ParticleIDs", ULONGLONG, 1,
                                  UNIT_CONV_NO_UNITS, parts, id);
   list[6] = io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts,
                                  primitives.rho);
   list[7] = io_make_output_field_convert_part(
-      "Entropy", FLOAT, 1, UNIT_CONV_ENTROPY, parts, convert_A);
+      "Entropy", FLOAT, 1, UNIT_CONV_ENTROPY, parts, xparts, convert_A);
   list[8] = io_make_output_field("Pressure", FLOAT, 1, UNIT_CONV_PRESSURE,
                                  parts, primitives.P);
   list[9] = io_make_output_field_convert_part(
-      "TotEnergy", FLOAT, 1, UNIT_CONV_ENERGY, parts, convert_Etot);
+      "TotEnergy", FLOAT, 1, UNIT_CONV_ENERGY, parts, xparts, convert_Etot);
+
+  list[10] = io_make_output_field_convert_part("Potential", FLOAT, 1,
+                                               UNIT_CONV_POTENTIAL, parts,
+                                               xparts, convert_part_potential);
 }
 
 /**
diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h
index 97cd5ef577dcfd7b07c5183a92349313096a6412..3f9d99683bde4ed6db64d8aaa5b111e2f67f0969 100644
--- a/src/hydro/Minimal/hydro.h
+++ b/src/hydro/Minimal/hydro.h
@@ -197,6 +197,18 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
   return p->mass;
 }
 
+/**
+ * @brief Sets the mass of a particle
+ *
+ * @param p The particle of interest
+ * @param m The mass to set.
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_mass(
+    struct part *restrict p, float m) {
+
+  p->mass = m;
+}
+
 /**
  * @brief Returns the velocities drifted to the current time of a particle.
  *
@@ -510,9 +522,12 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  * @param p The particle to act upon.
  * @param xp The particle extended data to act upon.
  * @param dt_therm The time-step for this kick (for thermodynamic quantities).
+ * @param cosmo The cosmological model.
+ * @param hydro_props The constants used in the scheme
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm,
+    const struct cosmology *cosmo, const struct hydro_props *hydro_props) {
 
   /* Do not decrease the energy by more than a factor of 2*/
   if (dt_therm > 0. && p->u_dt * dt_therm < -0.5f * xp->u_full) {
@@ -520,6 +535,14 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
   }
   xp->u_full += p->u_dt * dt_therm;
 
+  /* Apply the minimal energy limit */
+  const float min_energy =
+      hydro_props->minimal_internal_energy * cosmo->a_factor_internal_energy;
+  if (xp->u_full < min_energy) {
+    xp->u_full = min_energy;
+    p->u_dt = 0.f;
+  }
+
   /* Compute the pressure */
   const float pressure = gas_pressure_from_internal_energy(p->rho, xp->u_full);
 
@@ -540,9 +563,11 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
  *
  * @param p The particle to act upon
  * @param xp The extended particle to act upon
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
   /* Compute the pressure */
   const float pressure = gas_pressure_from_internal_energy(p->rho, p->u);
@@ -580,4 +605,21 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   hydro_init_part(p, NULL);
 }
 
+/**
+ * @brief Overwrite the initial internal energy of a particle.
+ *
+ * Note that in the cases where the thermodynamic variable is not
+ * internal energy but gets converted later, we must overwrite that
+ * field. The conversion to the actual variable happens later after
+ * the initial fake time-step.
+ *
+ * @param p The #part to write to.
+ * @param u_init The new initial internal energy.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_set_init_internal_energy(struct part *p, float u_init) {
+
+  p->u = u_init;
+}
+
 #endif /* SWIFT_MINIMAL_HYDRO_H */
diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h
index bfd8f1dff5febbd14b8a1e3a1cb8c01d49bc85ba..42fd93d6062cbfcea5cf5297eeda0bb6525f3cad 100644
--- a/src/hydro/Minimal/hydro_iact.h
+++ b/src/hydro/Minimal/hydro_iact.h
@@ -53,7 +53,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
 
   float wi, wj, wi_dx, wj_dx;
 
-  const float r = sqrtf(r2);
+  /* Get r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Get the masses. */
   const float mi = pi->mass;
@@ -101,8 +103,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
   /* Get the masses. */
   const float mj = pj->mass;
 
-  /* Get r and r inverse. */
-  const float r = sqrtf(r2);
+  /* Get r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   const float h_inv = 1.f / hi;
   const float ui = r * h_inv;
@@ -134,8 +137,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   const float fac_mu = pow_three_gamma_minus_five_over_two(a);
   const float a2_Hubble = a * a * H;
 
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and r inverse. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Recover some data */
   const float mi = pi->mass;
@@ -246,8 +250,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   const float fac_mu = pow_three_gamma_minus_five_over_two(a);
   const float a2_Hubble = a * a * H;
 
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and r inverse. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Recover some data */
   // const float mi = pi->mass;
diff --git a/src/hydro/Minimal/hydro_io.h b/src/hydro/Minimal/hydro_io.h
index 2ff70fd2f7e95344c17ba0f3237c3b2ee131752c..380d6120e05acf2e015ece6f133df02fad3b761d 100644
--- a/src/hydro/Minimal/hydro_io.h
+++ b/src/hydro/Minimal/hydro_io.h
@@ -69,18 +69,20 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
                                 UNIT_CONV_DENSITY, parts, rho);
 }
 
-void convert_S(const struct engine* e, const struct part* p, float* ret) {
+void convert_S(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
 
   ret[0] = hydro_get_comoving_entropy(p);
 }
 
-void convert_P(const struct engine* e, const struct part* p, float* ret) {
+void convert_P(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
 
   ret[0] = hydro_get_comoving_pressure(p);
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
-                      double* ret) {
+                      const struct xpart* xp, double* ret) {
 
   if (e->s->periodic) {
     ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]);
@@ -93,23 +95,68 @@ void convert_part_pos(const struct engine* e, const struct part* p,
   }
 }
 
+void convert_part_vel(const struct engine* e, const struct part* p,
+                      const struct xpart* xp, float* ret) {
+
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const struct cosmology* cosmo = e->cosmology;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+
+  const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin);
+  const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin);
+
+  /* Get time-step since the last kick */
+  float dt_kick_grav, dt_kick_hydro;
+  if (with_cosmology) {
+    dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_grav -=
+        cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_hydro -=
+        cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+  } else {
+    dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+  }
+
+  /* Extrapolate the velocites to the current time */
+  hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, ret);
+
+  /* Conversion from internal units to peculiar velocities */
+  ret[0] *= cosmo->a2_inv;
+  ret[1] *= cosmo->a2_inv;
+  ret[2] *= cosmo->a2_inv;
+}
+
+void convert_part_potential(const struct engine* e, const struct part* p,
+                            const struct xpart* xp, float* ret) {
+
+  if (p->gpart != NULL)
+    ret[0] = gravity_get_comoving_potential(p->gpart);
+  else
+    ret[0] = 0.f;
+}
+
 /**
  * @brief Specifies which particle fields to write to a dataset
  *
  * @param parts The particle array.
+ * @param xparts The extended particle array.
  * @param list The list of i/o properties to write.
  * @param num_fields The number of i/o fields to write.
  */
-void hydro_write_particles(struct part* parts, struct io_props* list,
-                           int* num_fields) {
+void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
+                           struct io_props* list, int* num_fields) {
 
-  *num_fields = 9;
+  *num_fields = 10;
 
   /* List what we want to write */
-  list[0] = io_make_output_field_convert_part(
-      "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, parts, convert_part_pos);
-  list[1] =
-      io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, v);
+  list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3,
+                                              UNIT_CONV_LENGTH, parts, xparts,
+                                              convert_part_pos);
+  list[1] = io_make_output_field_convert_part(
+      "Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, xparts, convert_part_vel);
   list[2] =
       io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts, mass);
   list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH,
@@ -120,10 +167,15 @@ void hydro_write_particles(struct part* parts, struct io_props* list,
                                  UNIT_CONV_NO_UNITS, parts, id);
   list[6] =
       io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho);
-  list[7] = io_make_output_field_convert_part(
-      "Entropy", FLOAT, 1, UNIT_CONV_ENTROPY_PER_UNIT_MASS, parts, convert_S);
+  list[7] = io_make_output_field_convert_part("Entropy", FLOAT, 1,
+                                              UNIT_CONV_ENTROPY_PER_UNIT_MASS,
+                                              parts, xparts, convert_S);
   list[8] = io_make_output_field_convert_part(
-      "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, convert_P);
+      "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, xparts, convert_P);
+
+  list[9] = io_make_output_field_convert_part("Potential", FLOAT, 1,
+                                              UNIT_CONV_POTENTIAL, parts,
+                                              xparts, convert_part_potential);
 }
 
 /**
diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h
index 37de855b375a5ac11f8a33f3993f7d2101c58522..87d46c6d43f0d4f6de6d18f5400b38f0fc4d0f55 100644
--- a/src/hydro/PressureEntropy/hydro.h
+++ b/src/hydro/PressureEntropy/hydro.h
@@ -170,6 +170,18 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
   return p->mass;
 }
 
+/**
+ * @brief Sets the mass of a particle
+ *
+ * @param p The particle of interest
+ * @param m The mass to set.
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_mass(
+    struct part *restrict p, float m) {
+
+  p->mass = m;
+}
+
 /**
  * @brief Returns the velocities drifted to the current time of a particle.
  *
@@ -524,9 +536,12 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  * @param p The particle to act upon
  * @param xp The particle extended data to act upon
  * @param dt_therm The time-step for this kick (for thermodynamic quantities)
+ * @param cosmo The cosmological model.
+ * @param hydro_props The constants used in the scheme
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm,
+    const struct cosmology *cosmo, const struct hydro_props *hydro_props) {
 
   /* Do not decrease the entropy (temperature) by more than a factor of 2*/
   if (dt_therm > 0. && p->entropy_dt * dt_therm < -0.5f * xp->entropy_full) {
@@ -534,6 +549,16 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
   }
   xp->entropy_full += p->entropy_dt * dt_therm;
 
+  /* Apply the minimal energy limit */
+  const float density = p->rho_bar * cosmo->a3_inv;
+  const float min_energy = hydro_props->minimal_internal_energy;
+  const float min_entropy =
+      gas_entropy_from_internal_energy(density, min_energy);
+  if (xp->entropy_full < min_entropy) {
+    xp->entropy_full = min_entropy;
+    p->entropy_dt = 0.f;
+  }
+
   /* Compute the pressure */
   const float pressure =
       gas_pressure_from_entropy(p->rho_bar, xp->entropy_full);
@@ -556,12 +581,16 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
  * Requires the density to be known
  *
  * @param p The particle to act upon
+ * @param xp The extended data.
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
   /* We read u in the entropy field. We now get S from u */
-  xp->entropy_full = gas_entropy_from_internal_energy(p->rho_bar, p->entropy);
+  xp->entropy_full =
+      gas_entropy_from_internal_energy(p->rho_bar * cosmo->a3_inv, p->entropy);
   p->entropy = xp->entropy_full;
   p->entropy_one_over_gamma = pow_one_over_gamma(p->entropy);
 
@@ -605,4 +634,21 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   hydro_init_part(p, NULL);
 }
 
+/**
+ * @brief Overwrite the initial internal energy of a particle.
+ *
+ * Note that in the cases where the thermodynamic variable is not
+ * internal energy but gets converted later, we must overwrite that
+ * field. The conversion to the actual variable happens later after
+ * the initial fake time-step.
+ *
+ * @param p The #part to write to.
+ * @param u_init The new initial internal energy.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_set_init_internal_energy(struct part *p, float u_init) {
+
+  p->entropy = u_init;
+}
+
 #endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_H */
diff --git a/src/hydro/PressureEntropy/hydro_iact.h b/src/hydro/PressureEntropy/hydro_iact.h
index c9e3c4ec7728df8a8e7d59b8c21f22bd613463d8..b8f8c1983a3b1fb67781f7228194deb770273988 100644
--- a/src/hydro/PressureEntropy/hydro_iact.h
+++ b/src/hydro/PressureEntropy/hydro_iact.h
@@ -54,9 +54,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
   const float mi = pi->mass;
   const float mj = pj->mass;
 
-  /* Get r and r inverse. */
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Compute the kernel function for pi */
   const float hi_inv = 1.f / hi;
@@ -142,9 +142,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
   /* Get the masses. */
   const float mj = pj->mass;
 
-  /* Get r and r inverse. */
-  const float r = sqrtf(r2);
-  const float ri = 1.0f / r;
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Compute the kernel function */
   const float h_inv = 1.0f / hi;
@@ -164,7 +164,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
   pi->density.pressure_dh -=
       mj * pj->entropy_one_over_gamma * (hydro_dimension * wi + ui * wi_dx);
 
-  const float fac = mj * wi_dx * ri;
+  const float fac = mj * wi_dx * r_inv;
 
   /* Compute dv dot r */
   dv[0] = pi->v[0] - pj->v[0];
@@ -205,8 +205,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   const float fac_mu = pow_three_gamma_minus_five_over_two(a);
   const float a2_Hubble = a * a * H;
 
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and 1/r . */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Get some values in local variables. */
   const float mi = pi->mass;
@@ -318,8 +319,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   const float fac_mu = pow_three_gamma_minus_five_over_two(a);
   const float a2_Hubble = a * a * H;
 
-  const float r = sqrtf(r2);
-  const float r_inv = 1.0f / r;
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
 
   /* Get some values in local variables. */
   // const float mi = pi->mass;
diff --git a/src/hydro/PressureEntropy/hydro_io.h b/src/hydro/PressureEntropy/hydro_io.h
index ed8e0e45d240ea37ebfb7df6339afd454dc0e4c4..78371c1eb21fafed56e89d46690d0cf1e0f2a0f0 100644
--- a/src/hydro/PressureEntropy/hydro_io.h
+++ b/src/hydro/PressureEntropy/hydro_io.h
@@ -67,18 +67,20 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
                                 UNIT_CONV_DENSITY, parts, rho);
 }
 
-void convert_u(const struct engine* e, const struct part* p, float* ret) {
+void convert_u(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
 
   ret[0] = hydro_get_comoving_internal_energy(p);
 }
 
-void convert_P(const struct engine* e, const struct part* p, float* ret) {
+void convert_P(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
 
   ret[0] = hydro_get_comoving_pressure(p);
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
-                      double* ret) {
+                      const struct xpart* xp, double* ret) {
 
   if (e->s->periodic) {
     ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]);
@@ -91,6 +93,49 @@ void convert_part_pos(const struct engine* e, const struct part* p,
   }
 }
 
+void convert_part_vel(const struct engine* e, const struct part* p,
+                      const struct xpart* xp, float* ret) {
+
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const struct cosmology* cosmo = e->cosmology;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+
+  const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin);
+  const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin);
+
+  /* Get time-step since the last kick */
+  float dt_kick_grav, dt_kick_hydro;
+  if (with_cosmology) {
+    dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_grav -=
+        cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_hydro -=
+        cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+  } else {
+    dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+  }
+
+  /* Extrapolate the velocites to the current time */
+  hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, ret);
+
+  /* Conversion from internal units to peculiar velocities */
+  ret[0] *= cosmo->a2_inv;
+  ret[1] *= cosmo->a2_inv;
+  ret[2] *= cosmo->a2_inv;
+}
+
+void convert_part_potential(const struct engine* e, const struct part* p,
+                            const struct xpart* xp, float* ret) {
+
+  if (p->gpart != NULL)
+    ret[0] = gravity_get_comoving_potential(p->gpart);
+  else
+    ret[0] = 0.f;
+}
+
 /**
  * @brief Specifies which particle fields to write to a dataset
  *
@@ -98,16 +143,17 @@ void convert_part_pos(const struct engine* e, const struct part* p,
  * @param list The list of i/o properties to write.
  * @param num_fields The number of i/o fields to write.
  */
-void hydro_write_particles(struct part* parts, struct io_props* list,
-                           int* num_fields) {
+void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
+                           struct io_props* list, int* num_fields) {
 
-  *num_fields = 10;
+  *num_fields = 11;
 
   /* List what we want to write */
-  list[0] = io_make_output_field_convert_part(
-      "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, parts, convert_part_pos);
-  list[1] =
-      io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, v);
+  list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3,
+                                              UNIT_CONV_LENGTH, parts, xparts,
+                                              convert_part_pos);
+  list[1] = io_make_output_field_convert_part(
+      "Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, xparts, convert_part_vel);
   list[2] =
       io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts, mass);
   list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH,
@@ -120,11 +166,14 @@ void hydro_write_particles(struct part* parts, struct io_props* list,
       io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho);
   list[7] = io_make_output_field_convert_part("InternalEnergy", FLOAT, 1,
                                               UNIT_CONV_ENERGY_PER_UNIT_MASS,
-                                              parts, convert_u);
+                                              parts, xparts, convert_u);
   list[8] = io_make_output_field_convert_part(
-      "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, convert_P);
+      "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, xparts, convert_P);
   list[9] = io_make_output_field("WeightedDensity", FLOAT, 1, UNIT_CONV_DENSITY,
                                  parts, rho_bar);
+  list[10] = io_make_output_field_convert_part("Potential", FLOAT, 1,
+                                               UNIT_CONV_POTENTIAL, parts,
+                                               xparts, convert_part_potential);
 }
 
 /**
diff --git a/src/hydro_properties.c b/src/hydro_properties.c
index 31e18913b7414110db68c6202c512de5fb90a3c1..bd8328946d4bfd078bd10b439e96b35dce457c49 100644
--- a/src/hydro_properties.c
+++ b/src/hydro_properties.c
@@ -36,8 +36,13 @@
 #define hydro_props_default_volume_change 1.4f
 #define hydro_props_default_h_max FLT_MAX
 #define hydro_props_default_h_tolerance 1e-4
+#define hydro_props_default_init_temp 0.f
+#define hydro_props_default_min_temp 0.f
+#define hydro_props_default_H_fraction 0.76
 
 void hydro_props_init(struct hydro_props *p,
+                      const struct phys_const *phys_const,
+                      const struct unit_system *us,
                       const struct swift_params *params) {
 
   /* Kernel properties */
@@ -73,6 +78,53 @@ void hydro_props_init(struct hydro_props *p,
   const float max_volume_change = parser_get_opt_param_float(
       params, "SPH:max_volume_change", hydro_props_default_volume_change);
   p->log_max_h_change = logf(powf(max_volume_change, hydro_dimension_inv));
+
+  /* Initial temperature */
+  p->initial_temperature = parser_get_opt_param_float(
+      params, "SPH:initial_temperature", hydro_props_default_init_temp);
+
+  /* Initial temperature */
+  p->minimal_temperature = parser_get_opt_param_float(
+      params, "SPH:minimal_temperature", hydro_props_default_min_temp);
+
+  if ((p->initial_temperature != 0.) &&
+      (p->initial_temperature < p->minimal_temperature))
+    error("Initial temperature lower than minimal allowed temperature!");
+
+  /* Hydrogen mass fraction */
+  p->hydrogen_mass_fraction = parser_get_opt_param_double(
+      params, "SPH:H_mass_fraction", hydro_props_default_H_fraction);
+
+  /* Compute the initial energy (Note the temp. read is in internal units) */
+  double u_init = phys_const->const_boltzmann_k / phys_const->const_proton_mass;
+  u_init *= p->initial_temperature;
+  u_init *= hydro_one_over_gamma_minus_one;
+
+  /* Correct for hydrogen mass fraction */
+  double mean_molecular_weight;
+  if (p->initial_temperature *
+          units_cgs_conversion_factor(us, UNIT_CONV_TEMPERATURE) >
+      1e4)
+    mean_molecular_weight = 4. / (8. - 5. * (1. - p->hydrogen_mass_fraction));
+  else
+    mean_molecular_weight = 4. / (1. + 3. * p->hydrogen_mass_fraction);
+
+  p->initial_internal_energy = u_init / mean_molecular_weight;
+
+  /* Compute the minimal energy (Note the temp. read is in internal units) */
+  double u_min = phys_const->const_boltzmann_k / phys_const->const_proton_mass;
+  u_min *= p->initial_temperature;
+  u_min *= hydro_one_over_gamma_minus_one;
+
+  /* Correct for hydrogen mass fraction */
+  if (p->minimal_temperature *
+          units_cgs_conversion_factor(us, UNIT_CONV_TEMPERATURE) >
+      1e4)
+    mean_molecular_weight = 4. / (8. - 5. * (1. - p->hydrogen_mass_fraction));
+  else
+    mean_molecular_weight = 4. / (1. + 3. * p->hydrogen_mass_fraction);
+
+  p->minimal_internal_energy = u_min / mean_molecular_weight;
 }
 
 void hydro_props_print(const struct hydro_props *p) {
@@ -103,6 +155,12 @@ void hydro_props_print(const struct hydro_props *p) {
   if (p->max_smoothing_iterations != hydro_props_default_max_iterations)
     message("Maximal iterations in ghost task set to %d (default is %d)",
             p->max_smoothing_iterations, hydro_props_default_max_iterations);
+
+  if (p->initial_temperature != hydro_props_default_init_temp)
+    message("Initial gas temperature set to %f", p->initial_temperature);
+
+  if (p->minimal_temperature != hydro_props_default_min_temp)
+    message("Minimal gas temperature set to %f", p->minimal_temperature);
 }
 
 #if defined(HAVE_HDF5)
@@ -125,6 +183,12 @@ void hydro_props_print_snapshot(hid_t h_grpsph, const struct hydro_props *p) {
                        pow_dimension(expf(p->log_max_h_change)));
   io_write_attribute_i(h_grpsph, "Max ghost iterations",
                        p->max_smoothing_iterations);
+  io_write_attribute_f(h_grpsph, "Minimal temperature", p->minimal_temperature);
+  io_write_attribute_f(h_grpsph, "Initial temperature", p->initial_temperature);
+  io_write_attribute_f(h_grpsph, "Initial energy per unit mass",
+                       p->initial_internal_energy);
+  io_write_attribute_f(h_grpsph, "Hydrogen mass fraction",
+                       p->hydrogen_mass_fraction);
 }
 #endif
 
diff --git a/src/hydro_properties.h b/src/hydro_properties.h
index 6d325c35d6ae6a9bcddbfff9ccc4601e026fc4e6..2799f6c86eec7f0ebf140643c5ab7fa9b60e6273 100644
--- a/src/hydro_properties.h
+++ b/src/hydro_properties.h
@@ -33,7 +33,9 @@
 
 /* Local includes. */
 #include "parser.h"
+#include "physical_constants.h"
 #include "restart.h"
+#include "units.h"
 
 /**
  * @brief Contains all the constants and parameters of the hydro scheme
@@ -63,10 +65,28 @@ struct hydro_props {
 
   /*! Maximal change of h over one time-step */
   float log_max_h_change;
+
+  /*! Minimal temperature allowed */
+  float minimal_temperature;
+
+  /*! Minimal internal energy per unit mass */
+  float minimal_internal_energy;
+
+  /*! Initial temperature */
+  float initial_temperature;
+
+  /*! Initial internal energy per unit mass */
+  float initial_internal_energy;
+
+  /*! Primoridal hydrogen mass fraction for initial energy conversion */
+  float hydrogen_mass_fraction;
 };
 
 void hydro_props_print(const struct hydro_props *p);
-void hydro_props_init(struct hydro_props *p, const struct swift_params *params);
+void hydro_props_init(struct hydro_props *p,
+                      const struct phys_const *phys_const,
+                      const struct unit_system *us,
+                      const struct swift_params *params);
 
 #if defined(HAVE_HDF5)
 void hydro_props_print_snapshot(hid_t h_grpsph, const struct hydro_props *p);
diff --git a/src/io_properties.h b/src/io_properties.h
index 17db123ba8325ede0c7af4e4b005e359cace7a7f..55e128e890b75db2d01911bd3c3b46388b0c6597 100644
--- a/src/io_properties.h
+++ b/src/io_properties.h
@@ -34,9 +34,11 @@ enum DATA_IMPORTANCE { COMPULSORY = 1, OPTIONAL = 0, UNUSED = -1 };
 
 /* Helper typedefs */
 typedef void (*conversion_func_part_float)(const struct engine*,
-                                           const struct part*, float*);
+                                           const struct part*,
+                                           const struct xpart*, float*);
 typedef void (*conversion_func_part_double)(const struct engine*,
-                                            const struct part*, double*);
+                                            const struct part*,
+                                            const struct xpart*, double*);
 typedef void (*conversion_func_gpart_float)(const struct engine*,
                                             const struct gpart*, float*);
 typedef void (*conversion_func_gpart_double)(const struct engine*,
@@ -78,6 +80,7 @@ struct io_props {
 
   /* The particle arrays */
   const struct part* parts;
+  const struct xpart* xparts;
   const struct gpart* gparts;
 
   /* Are we converting? */
@@ -125,6 +128,7 @@ INLINE static struct io_props io_make_input_field_(
   r.field = field;
   r.partSize = partSize;
   r.parts = NULL;
+  r.xparts = NULL;
   r.gparts = NULL;
   r.conversion = 0;
   r.convert_part_f = NULL;
@@ -179,10 +183,10 @@ INLINE static struct io_props io_make_output_field_(
 /**
  * @brief Constructs an #io_props (with conversion) from its parameters
  */
-#define io_make_output_field_convert_part(name, type, dim, units, part, \
-                                          convert)                      \
-  io_make_output_field_convert_part_##type(name, type, dim, units,      \
-                                           sizeof(part[0]), part, convert)
+#define io_make_output_field_convert_part(name, type, dim, units, part, xpart, \
+                                          convert)                             \
+  io_make_output_field_convert_part_##type(                                    \
+      name, type, dim, units, sizeof(part[0]), part, xpart, convert)
 
 /**
  * @brief Construct an #io_props from its parameters
@@ -193,6 +197,7 @@ INLINE static struct io_props io_make_output_field_(
  * @param units The units of the dataset
  * @param partSize The size in byte of the particle
  * @param parts The particle array
+ * @param xparts The xparticle array
  * @param functionPtr The function used to convert a particle to a float
  *
  * Do not call this function directly. Use the macro defined above.
@@ -200,7 +205,8 @@ INLINE static struct io_props io_make_output_field_(
 INLINE static struct io_props io_make_output_field_convert_part_FLOAT(
     const char name[FIELD_BUFFER_SIZE], enum IO_DATA_TYPE type, int dimension,
     enum unit_conversion_factor units, size_t partSize,
-    const struct part* parts, conversion_func_part_float functionPtr) {
+    const struct part* parts, const struct xpart* xparts,
+    conversion_func_part_float functionPtr) {
 
   struct io_props r;
   strcpy(r.name, name);
@@ -211,6 +217,7 @@ INLINE static struct io_props io_make_output_field_convert_part_FLOAT(
   r.field = NULL;
   r.partSize = partSize;
   r.parts = parts;
+  r.xparts = xparts;
   r.gparts = NULL;
   r.conversion = 1;
   r.convert_part_f = functionPtr;
@@ -230,6 +237,7 @@ INLINE static struct io_props io_make_output_field_convert_part_FLOAT(
  * @param units The units of the dataset
  * @param partSize The size in byte of the particle
  * @param parts The particle array
+ * @param xparts The xparticle array
  * @param functionPtr The function used to convert a particle to a float
  *
  * Do not call this function directly. Use the macro defined above.
@@ -237,7 +245,8 @@ INLINE static struct io_props io_make_output_field_convert_part_FLOAT(
 INLINE static struct io_props io_make_output_field_convert_part_DOUBLE(
     const char name[FIELD_BUFFER_SIZE], enum IO_DATA_TYPE type, int dimension,
     enum unit_conversion_factor units, size_t partSize,
-    const struct part* parts, conversion_func_part_double functionPtr) {
+    const struct part* parts, const struct xpart* xparts,
+    conversion_func_part_double functionPtr) {
 
   struct io_props r;
   strcpy(r.name, name);
@@ -248,6 +257,7 @@ INLINE static struct io_props io_make_output_field_convert_part_DOUBLE(
   r.field = NULL;
   r.partSize = partSize;
   r.parts = parts;
+  r.xparts = xparts;
   r.gparts = NULL;
   r.conversion = 1;
   r.convert_part_f = NULL;
@@ -293,6 +303,7 @@ INLINE static struct io_props io_make_output_field_convert_gpart_FLOAT(
   r.field = NULL;
   r.partSize = gpartSize;
   r.parts = NULL;
+  r.xparts = NULL;
   r.gparts = gparts;
   r.conversion = 1;
   r.convert_part_f = NULL;
@@ -330,6 +341,7 @@ INLINE static struct io_props io_make_output_field_convert_gpart_DOUBLE(
   r.field = NULL;
   r.partSize = gpartSize;
   r.parts = NULL;
+  r.xparts = NULL;
   r.gparts = gparts;
   r.conversion = 1;
   r.convert_part_f = NULL;
diff --git a/src/kernel_gravity.h b/src/kernel_gravity.h
index 24d30136c8213dab6db424f2f459766c45ec6b1e..dc9db63f9d59ad0b3e72792b33b38a961ea6c30f 100644
--- a/src/kernel_gravity.h
+++ b/src/kernel_gravity.h
@@ -26,6 +26,10 @@
 #include "inline.h"
 #include "minmax.h"
 
+/*! Conversion factor between Plummer softening and internal softening */
+#define kernel_gravity_softening_plummer_equivalent 3.
+#define kernel_gravity_softening_plummer_equivalent_inv (1. / 3.)
+
 /**
  * @brief Computes the gravity softening function for potential.
  *
diff --git a/src/kernel_long_gravity.h b/src/kernel_long_gravity.h
index 77bc7c17e2ab8038a4860c74daebd19a2d785070..578d7c2154f6801e21c004c01cade8bf6bd728ae 100644
--- a/src/kernel_long_gravity.h
+++ b/src/kernel_long_gravity.h
@@ -49,7 +49,7 @@ __attribute__((always_inline)) INLINE static void kernel_long_grav_pot_eval(
 #else
 
   const float x = 2.f * u;
-  const float exp_x = expf(x);
+  const float exp_x = good_approx_expf(x);
   const float alpha = 1.f / (1.f + exp_x);
 
   /* We want 2 - 2 exp(x) * alpha */
@@ -83,7 +83,7 @@ __attribute__((always_inline)) INLINE static void kernel_long_grav_force_eval(
 #else
 
   const float arg = 2.f * u;
-  const float exp_arg = expf(arg);
+  const float exp_arg = good_approx_expf(arg);
   const float term = 1.f / (1.f + exp_arg);
 
   *W = arg * exp_arg * term * term - exp_arg * term + 1.f;
@@ -111,4 +111,4 @@ __attribute__((always_inline)) INLINE static void fourier_kernel_long_grav_eval(
 #endif
 }
 
-#endif  // SWIFT_KERNEL_LONG_GRAVITY_H
+#endif /* SWIFT_KERNEL_LONG_GRAVITY_H */
diff --git a/src/kick.h b/src/kick.h
index 9b1f4f18112a1cb2affcff70e7773ba4c48681b5..9d10f1e78d3934c4277c14217cbbc46514e87033 100644
--- a/src/kick.h
+++ b/src/kick.h
@@ -68,13 +68,16 @@ __attribute__((always_inline)) INLINE static void kick_gpart(
  * @param dt_kick_hydro The kick time-step for hydro accelerations.
  * @param dt_kick_grav The kick time-step for gravity accelerations.
  * @param dt_kick_therm The kick time-step for changes in thermal state.
+ * @param cosmo The cosmological model.
+ * @param hydro_props The constants used in the scheme
  * @param ti_start The starting (integer) time of the kick (for debugging
  * checks).
  * @param ti_end The ending (integer) time of the kick (for debugging checks).
  */
 __attribute__((always_inline)) INLINE static void kick_part(
     struct part *restrict p, struct xpart *restrict xp, double dt_kick_hydro,
-    double dt_kick_grav, double dt_kick_therm, integertime_t ti_start,
+    double dt_kick_grav, double dt_kick_therm, const struct cosmology *cosmo,
+    const struct hydro_props *hydro_props, integertime_t ti_start,
     integertime_t ti_end) {
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -107,7 +110,7 @@ __attribute__((always_inline)) INLINE static void kick_part(
   }
 
   /* Extra kick work */
-  hydro_kick_extra(p, xp, dt_kick_therm);
+  hydro_kick_extra(p, xp, dt_kick_therm, cosmo, hydro_props);
   if (p->gpart != NULL) gravity_kick_extra(p->gpart, dt_kick_grav);
 }
 
diff --git a/src/logger.c b/src/logger.c
index 38cb220b94dd14680584e9edca75883e1df16907..5fd4145aa1b042ed806dd3fe5487d094600b66c4 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -218,12 +218,6 @@ void logger_log_gpart(struct gpart *p, unsigned int mask, size_t *offset,
     buff += 3 * sizeof(float);
   }
 
-  /* Particle smoothing length as a single float. */
-  if (mask & logger_mask_h) {
-    memcpy(buff, &p->epsilon, sizeof(float));
-    buff += sizeof(float);
-  }
-
   /* Particle constants, which is a bit more complicated. */
   if (mask & logger_mask_rho) {
     memcpy(buff, &p->mass, sizeof(float));
@@ -385,12 +379,6 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) {
     buff += 3 * sizeof(float);
   }
 
-  /* Particle smoothing length as a single float. */
-  if (mask & logger_mask_h) {
-    memcpy(&p->epsilon, buff, sizeof(float));
-    buff += sizeof(float);
-  }
-
   /* Particle constants, which is a bit more complicated. */
   if (mask & logger_mask_rho) {
     memcpy(&p->mass, buff, sizeof(float));
diff --git a/src/multipole.h b/src/multipole.h
index 852976ad552b3ccf16f3e084612166c9212df2a6..dd74c4a40d79cc393e252bfe061591dd868f2a55 100644
--- a/src/multipole.h
+++ b/src/multipole.h
@@ -1524,8 +1524,8 @@ INLINE static void gravity_M2L(struct grav_tensor *l_b,
                                const double dim[3]) {
 
   /* Recover some constants */
-  const float eps = props->epsilon;
-  const float eps_inv = props->epsilon_inv;
+  const float eps = props->epsilon_cur;
+  const float eps_inv = props->epsilon_cur_inv;
 
   /* Compute distance vector */
   float dx = (float)(pos_b[0] - pos_a[0]);
@@ -2380,6 +2380,7 @@ INLINE static void gravity_L2P(const struct grav_tensor *lb,
   gp->a_grav[2] += a_grav[2];
   gp->potential += pot;
 }
+
 /**
  * @brief Checks whether a cell-cell interaction can be appromixated by a M-M
  * interaction using the distance and cell radius.
diff --git a/src/parallel_io.c b/src/parallel_io.c
index d3f5f8dc36dd63ad1b7cf4d65311751cd15f887b..51c88e95396eb6af1ab7f7eb2d1ed48eada59e0d 100644
--- a/src/parallel_io.c
+++ b/src/parallel_io.c
@@ -69,11 +69,14 @@
  * @param offset Offset in the array where this mpi task starts writing.
  * @param internal_units The #unit_system used internally.
  * @param ic_units The #unit_system used in the snapshots.
+ * @param cleanup_h Are we removing h-factors from the ICs?
+ * @param h The value of the reduced Hubble constant to use for cleaning.
  */
 void readArray_chunk(hid_t h_data, hid_t h_plist_id,
                      const struct io_props props, size_t N, long long offset,
                      const struct unit_system* internal_units,
-                     const struct unit_system* ic_units) {
+                     const struct unit_system* ic_units, int cleanup_h,
+                     double h) {
 
   const size_t typeSize = io_sizeof_type(props.type);
   const size_t copySize = typeSize * props.dimension;
@@ -136,6 +139,23 @@ void readArray_chunk(hid_t h_data, hid_t h_plist_id,
     }
   }
 
+  /* Clean-up h if necessary */
+  const float h_factor_exp = units_h_factor(internal_units, props.units);
+  if (cleanup_h && h_factor_exp != 0.f) {
+    const double h_factor = pow(h, h_factor_exp);
+
+    /* message("Multipltying '%s' by h^%f=%f", props.name, h_factor_exp,
+     * h_factor); */
+
+    if (io_is_double_precision(props.type)) {
+      double* temp_d = (double*)temp;
+      for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= h_factor;
+    } else {
+      float* temp_f = (float*)temp;
+      for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= h_factor;
+    }
+  }
+
   /* Copy temporary buffer to particle data */
   char* temp_c = (char*)temp;
   for (size_t i = 0; i < N; ++i)
@@ -158,11 +178,13 @@ void readArray_chunk(hid_t h_data, hid_t h_plist_id,
  * @param offset The offset in the array on disk for this rank.
  * @param internal_units The #unit_system used internally.
  * @param ic_units The #unit_system used in the ICs.
+ * @param cleanup_h Are we removing h-factors from the ICs?
+ * @param h The value of the reduced Hubble constant to use for cleaning.
  */
 void readArray(hid_t grp, struct io_props props, size_t N, long long N_total,
                int mpi_rank, long long offset,
                const struct unit_system* internal_units,
-               const struct unit_system* ic_units) {
+               const struct unit_system* ic_units, int cleanup_h, double h) {
 
   const size_t typeSize = io_sizeof_type(props.type);
   const size_t copySize = typeSize * props.dimension;
@@ -207,7 +229,7 @@ void readArray(hid_t grp, struct io_props props, size_t N, long long N_total,
     /* Write the first chunk */
     const size_t this_chunk = (N > max_chunk_size) ? max_chunk_size : N;
     readArray_chunk(h_data, h_plist_id, props, this_chunk, offset,
-                    internal_units, ic_units);
+                    internal_units, ic_units, cleanup_h, h);
 
     /* Compute how many items are left */
     if (N > max_chunk_size) {
@@ -309,8 +331,7 @@ void prepareArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile,
   io_write_attribute_d(
       h_data, "CGS conversion factor",
       units_cgs_conversion_factor(snapshot_units, props.units));
-  io_write_attribute_f(h_data, "h-scale exponent",
-                       units_h_factor(snapshot_units, props.units));
+  io_write_attribute_f(h_data, "h-scale exponent", 0);
   io_write_attribute_f(h_data, "a-scale exponent",
                        units_a_factor(snapshot_units, props.units));
   io_write_attribute_s(h_data, "Conversion factor", buffer);
@@ -541,6 +562,8 @@ void writeArray(struct engine* e, hid_t grp, char* fileName,
  * @param with_hydro Are we running with hydro ?
  * @param with_gravity Are we running with gravity ?
  * @param with_stars Are we running with stars ?
+ * @param cleanup_h Are we cleaning-up h-factors from the quantities we read?
+ * @param h The value of the reduced Hubble constant to use for correction.
  * @param mpi_rank The MPI rank of this node
  * @param mpi_size The number of MPI ranks
  * @param comm The MPI communicator
@@ -554,8 +577,9 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
                       struct spart** sparts, size_t* Ngas, size_t* Ngparts,
                       size_t* Nstars, int* periodic, int* flag_entropy,
                       int with_hydro, int with_gravity, int with_stars,
-                      int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info,
-                      int n_threads, int dry_run) {
+                      int cleanup_h, double h, int mpi_rank, int mpi_size,
+                      MPI_Comm comm, MPI_Info info, int n_threads,
+                      int dry_run) {
 
   hid_t h_file = 0, h_grp = 0;
   /* GADGET has only cubic boxes (in cosmological mode) */
@@ -626,6 +650,13 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
   else if (hydro_dimension == 1)
     dim[2] = dim[1] = dim[0];
 
+  /* Convert the box size if we want to clean-up h-factors */
+  if (cleanup_h) {
+    dim[0] /= h;
+    dim[1] /= h;
+    dim[2] /= h;
+  }
+
   /* message("Found %lld particles in a %speriodic box of size [%f %f %f].", */
   /* 	  N_total[0], (periodic ? "": "non-"), dim[0], */
   /* 	  dim[1], dim[2]); */
@@ -771,7 +802,7 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
     if (!dry_run)
       for (int i = 0; i < num_fields; ++i)
         readArray(h_grp, list[i], Nparticles, N_total[ptype], mpi_rank,
-                  offset[ptype], internal_units, ic_units);
+                  offset[ptype], internal_units, ic_units, cleanup_h, h);
 
     /* Close particle group */
     H5Gclose(h_grp);
@@ -821,9 +852,10 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
                   const struct unit_system* internal_units,
                   const struct unit_system* snapshot_units) {
 
-  struct part* parts = e->s->parts;
-  struct gpart* gparts = e->s->gparts;
-  struct spart* sparts = e->s->sparts;
+  const struct part* parts = e->s->parts;
+  const struct xpart* xparts = e->s->xparts;
+  const struct gpart* gparts = e->s->gparts;
+  const struct spart* sparts = e->s->sparts;
   FILE* xmfFile = 0;
   int periodic = e->s->periodic;
   int numFiles = 1;
@@ -980,7 +1012,7 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
     switch (ptype) {
 
       case swift_type_gas:
-        hydro_write_particles(parts, list, &num_fields);
+        hydro_write_particles(parts, xparts, list, &num_fields);
         num_fields += chemistry_write_particles(parts, list + num_fields);
         break;
 
@@ -1045,10 +1077,11 @@ void write_output_parallel(struct engine* e, const char* baseName,
   const size_t Ngas = e->s->nr_parts;
   const size_t Nstars = e->s->nr_sparts;
   const size_t Ntot = e->s->nr_gparts;
-  struct part* parts = e->s->parts;
-  struct gpart* gparts = e->s->gparts;
+  const struct part* parts = e->s->parts;
+  const struct xpart* xparts = e->s->xparts;
+  const struct gpart* gparts = e->s->gparts;
   struct gpart* dmparts = NULL;
-  struct spart* sparts = e->s->sparts;
+  const struct spart* sparts = e->s->sparts;
 
   /* Number of unassociated gparts */
   const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0;
@@ -1208,7 +1241,7 @@ void write_output_parallel(struct engine* e, const char* baseName,
 
       case swift_type_gas:
         Nparticles = Ngas;
-        hydro_write_particles(parts, list, &num_fields);
+        hydro_write_particles(parts, xparts, list, &num_fields);
         num_fields += chemistry_write_particles(parts, list + num_fields);
         break;
 
diff --git a/src/parallel_io.h b/src/parallel_io.h
index 207e478c341488deb056761b37fb9c7370744b38..5ad3b34cdc4320d6fe3eb860615db33958ad612f 100644
--- a/src/parallel_io.h
+++ b/src/parallel_io.h
@@ -22,6 +22,8 @@
 /* Config parameters. */
 #include "../config.h"
 
+#if defined(HAVE_HDF5) && defined(WITH_MPI) && defined(HAVE_PARALLEL_HDF5)
+
 /* MPI headers. */
 #ifdef WITH_MPI
 #include <mpi.h>
@@ -32,15 +34,14 @@
 #include "part.h"
 #include "units.h"
 
-#if defined(HAVE_HDF5) && defined(WITH_MPI) && defined(HAVE_PARALLEL_HDF5)
-
 void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
                       double dim[3], struct part** parts, struct gpart** gparts,
                       struct spart** sparts, size_t* Ngas, size_t* Ngparts,
                       size_t* Nsparts, int* periodic, int* flag_entropy,
                       int with_hydro, int with_gravity, int with_stars,
-                      int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info,
-                      int nr_threads, int dry_run);
+                      int cleanup_h, double h, int mpi_rank, int mpi_size,
+                      MPI_Comm comm, MPI_Info info, int nr_threads,
+                      int dry_run);
 
 void write_output_parallel(struct engine* e, const char* baseName,
                            const struct unit_system* internal_units,
diff --git a/src/parser.h b/src/parser.h
index 4e61b16ab53b3688e60f85a42e786c44b095120a..58f4a53ea2114dbed29f49e2b5ccca69239b45e3 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -23,6 +23,9 @@
 /* Config parameters. */
 #include "../config.h"
 
+/* Standard headers */
+#include <stdio.h>
+
 #if defined(HAVE_HDF5)
 #include <hdf5.h>
 #endif
diff --git a/src/part.c b/src/part.c
index b4c3a11bb0f7fbce4fbfbbbee198d1f88efdf6a3..1b696a8cbc135fd2c128b5ad705a0e6e24a2d5c8 100644
--- a/src/part.c
+++ b/src/part.c
@@ -139,8 +139,8 @@ void part_verify_links(struct part *parts, struct gpart *gparts,
     if (gparts[k].type == swift_type_dark_matter) {
 
       /* Check that it's not linked */
-      if (gparts[k].id_or_neg_offset < 0)
-        error("DM gpart particle linked to something!");
+      if (gparts[k].id_or_neg_offset <= 0)
+        error("DM gpart particle linked to something !");
     }
 
     /* We have a gas particle */
diff --git a/src/partition.c b/src/partition.c
index 8203c255d484672254b249042db22f5952579b4e..8feae3b7a8dce7c78310a3b35762d31b439c69e3 100644
--- a/src/partition.c
+++ b/src/partition.c
@@ -48,6 +48,7 @@
 
 /* Local headers. */
 #include "debug.h"
+#include "engine.h"
 #include "error.h"
 #include "partition.h"
 #include "restart.h"
diff --git a/src/runner.c b/src/runner.c
index 1b8f9a2fc84b08c590396f1251a6bf3c5cc3189e..35996a3ba9a760d5f019ede35abc207bbdcbe1b3 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -981,6 +981,7 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
 
   const struct engine *e = r->e;
   const struct cosmology *cosmo = e->cosmology;
+  const struct hydro_props *hydro_props = e->hydro_properties;
   const int with_cosmology = (e->policy & engine_policy_cosmology);
   struct part *restrict parts = c->parts;
   struct xpart *restrict xparts = c->xparts;
@@ -1044,8 +1045,8 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
         }
 
         /* do the kick */
-        kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, ti_begin,
-                  ti_begin + ti_step / 2);
+        kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, cosmo,
+                  hydro_props, ti_begin, ti_begin + ti_step / 2);
 
         /* Update the accelerations to be used in the drift for hydro */
         if (p->gpart != NULL) {
@@ -1150,6 +1151,7 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) {
 
   const struct engine *e = r->e;
   const struct cosmology *cosmo = e->cosmology;
+  const struct hydro_props *hydro_props = e->hydro_properties;
   const int with_cosmology = (e->policy & engine_policy_cosmology);
   const int count = c->count;
   const int gcount = c->gcount;
@@ -1209,8 +1211,8 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) {
         }
 
         /* Finish the time-step with a second half-kick */
-        kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm,
-                  ti_begin + ti_step / 2, ti_begin + ti_step);
+        kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, cosmo,
+                  hydro_props, ti_begin + ti_step / 2, ti_begin + ti_step);
 
 #ifdef SWIFT_DEBUG_CHECKS
         /* Check that kick and the drift are synchronized */
diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h
index cec450d84449d2b8cbb6790fcf9a596bb24649be..4f353a317e9f312f5ae6627cfaf0c06d176e8fad 100644
--- a/src/runner_doiact_grav.h
+++ b/src/runner_doiact_grav.h
@@ -466,7 +466,6 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci,
   struct space *s = e->s;
   const int periodic = s->periodic;
   const double cell_width = s->width[0];
-  const float theta_crit2 = e->gravity_properties->theta_crit2;
   const double a_smooth = e->gravity_properties->a_smooth;
   const double r_cut_min = e->gravity_properties->r_cut_min;
   const double rlr = cell_width * a_smooth;
@@ -532,11 +531,11 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci,
 
   /* Fill the caches */
   gravity_cache_populate(e->max_active_bin, ci_cache, ci->gparts, gcount_i,
-                         gcount_padded_i, shift_i, CoM_j, rmax2_j, theta_crit2,
-                         ci);
+                         gcount_padded_i, shift_i, CoM_j, rmax2_j, ci,
+                         e->gravity_properties);
   gravity_cache_populate(e->max_active_bin, cj_cache, cj->gparts, gcount_j,
-                         gcount_padded_j, shift_j, CoM_i, rmax2_i, theta_crit2,
-                         cj);
+                         gcount_padded_j, shift_j, CoM_i, rmax2_i, cj,
+                         e->gravity_properties);
 
   /* Can we use the Newtonian version or do we need the truncated one ? */
   if (!periodic) {
@@ -675,7 +674,7 @@ static INLINE void runner_doself_grav_pp_full(struct runner *r,
   const int gcount_padded = gcount - (gcount % VEC_SIZE) + VEC_SIZE;
 
   gravity_cache_populate_no_mpole(e->max_active_bin, ci_cache, gparts, gcount,
-                                  gcount_padded, loc, c);
+                                  gcount_padded, loc, c, e->gravity_properties);
 
   /* Ok... Here we go ! */
 
@@ -805,7 +804,7 @@ static INLINE void runner_doself_grav_pp_truncated(struct runner *r,
   const int gcount_padded = gcount - (gcount % VEC_SIZE) + VEC_SIZE;
 
   gravity_cache_populate_no_mpole(e->max_active_bin, ci_cache, gparts, gcount,
-                                  gcount_padded, loc, c);
+                                  gcount_padded, loc, c, e->gravity_properties);
 
   /* Ok... Here we go ! */
 
diff --git a/src/runner_doiact_vec.c b/src/runner_doiact_vec.c
index 0daea0cf8a8d868ccb14f7d9b27f04aca5a677c8..2e86280d64491ee1750f41c2cd22ab01c08e30b8 100644
--- a/src/runner_doiact_vec.c
+++ b/src/runner_doiact_vec.c
@@ -1689,7 +1689,7 @@ void runner_dopair_subset_density_vec(struct runner *r,
                                       struct cell *restrict cj, const int sid,
                                       const int flipped, const double *shift) {
 
-#ifdef WITH_VECTORIZATION
+#if defined(WITH_VECTORIZATION) && defined(GADGET2_SPH)
 
   TIMER_TIC;
 
diff --git a/src/serial_io.c b/src/serial_io.c
index aa8d126e4c6f3e19aed7d205c7ced39f7eded6f8..dd623f946ce6ec32415586e5048979de3adb58fa 100644
--- a/src/serial_io.c
+++ b/src/serial_io.c
@@ -67,6 +67,8 @@
  * @param offset The offset position where this rank starts reading.
  * @param internal_units The #unit_system used internally
  * @param ic_units The #unit_system used in the ICs
+ * @param cleanup_h Are we removing h-factors from the ICs?
+ * @param h The value of the reduced Hubble constant to use for cleaning.
  *
  * @todo A better version using HDF5 hyper-slabs to read the file directly into
  * the part array will be written once the structures have been stabilized.
@@ -74,7 +76,7 @@
 void readArray(hid_t grp, const struct io_props props, size_t N,
                long long N_total, long long offset,
                const struct unit_system* internal_units,
-               const struct unit_system* ic_units) {
+               const struct unit_system* ic_units, int cleanup_h, double h) {
 
   const size_t typeSize = io_sizeof_type(props.type);
   const size_t copySize = typeSize * props.dimension;
@@ -161,6 +163,23 @@ void readArray(hid_t grp, const struct io_props props, size_t N,
     }
   }
 
+  /* Clean-up h if necessary */
+  const float h_factor_exp = units_h_factor(internal_units, props.units);
+  if (cleanup_h && h_factor_exp != 0.f && exist != 0) {
+    const double h_factor = pow(h, h_factor_exp);
+
+    /* message("Multipltying '%s' by h^%f=%f", props.name, h_factor_exp,
+     * h_factor); */
+
+    if (io_is_double_precision(props.type)) {
+      double* temp_d = (double*)temp;
+      for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= h_factor;
+    } else {
+      float* temp_f = (float*)temp;
+      for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= h_factor;
+    }
+  }
+
   /* Copy temporary buffer to particle data */
   char* temp_c = temp;
   for (size_t i = 0; i < N; ++i)
@@ -256,8 +275,7 @@ void prepareArray(const struct engine* e, hid_t grp, char* fileName,
   io_write_attribute_d(
       h_data, "CGS conversion factor",
       units_cgs_conversion_factor(snapshot_units, props.units));
-  io_write_attribute_f(h_data, "h-scale exponent",
-                       units_h_factor(snapshot_units, props.units));
+  io_write_attribute_f(h_data, "h-scale exponent", 0);
   io_write_attribute_f(h_data, "a-scale exponent",
                        units_a_factor(snapshot_units, props.units));
   io_write_attribute_s(h_data, "Conversion factor", buffer);
@@ -382,6 +400,8 @@ void writeArray(const struct engine* e, hid_t grp, char* fileName,
  * @param with_hydro Are we reading gas particles ?
  * @param with_gravity Are we reading/creating #gpart arrays ?
  * @param with_stars Are we reading star particles ?
+ * @param cleanup_h Are we cleaning-up h-factors from the quantities we read?
+ * @param h The value of the reduced Hubble constant to use for correction.
  * @param mpi_rank The MPI rank of this node
  * @param mpi_size The number of MPI ranks
  * @param comm The MPI communicator
@@ -402,8 +422,8 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
                     struct spart** sparts, size_t* Ngas, size_t* Ngparts,
                     size_t* Nstars, int* periodic, int* flag_entropy,
                     int with_hydro, int with_gravity, int with_stars,
-                    int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info,
-                    int n_threads, int dry_run) {
+                    int cleanup_h, double h, int mpi_rank, int mpi_size,
+                    MPI_Comm comm, MPI_Info info, int n_threads, int dry_run) {
 
   hid_t h_file = 0, h_grp = 0;
   /* GADGET has only cubic boxes (in cosmological mode) */
@@ -476,6 +496,13 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
     else if (hydro_dimension == 1)
       dim[2] = dim[1] = dim[0];
 
+    /* Convert the box size if we want to clean-up h-factors */
+    if (cleanup_h) {
+      dim[0] /= h;
+      dim[1] /= h;
+      dim[2] /= h;
+    }
+
     /* message("Found %lld particles in a %speriodic box of size [%f %f %f].",
      */
     /* 	    N_total, (periodic ? "": "non-"), dim[0], dim[1], dim[2]); */
@@ -641,7 +668,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
         if (!dry_run)
           for (int i = 0; i < num_fields; ++i)
             readArray(h_grp, list[i], Nparticles, N_total[ptype], offset[ptype],
-                      internal_units, ic_units);
+                      internal_units, ic_units, cleanup_h, h);
 
         /* Close particle group */
         H5Gclose(h_grp);
@@ -712,10 +739,11 @@ void write_output_serial(struct engine* e, const char* baseName,
   const size_t Ntot = e->s->nr_gparts;
   int periodic = e->s->periodic;
   int numFiles = 1;
-  struct part* parts = e->s->parts;
-  struct gpart* gparts = e->s->gparts;
+  const struct part* parts = e->s->parts;
+  const struct xpart* xparts = e->s->xparts;
+  const struct gpart* gparts = e->s->gparts;
   struct gpart* dmparts = NULL;
-  struct spart* sparts = e->s->sparts;
+  const struct spart* sparts = e->s->sparts;
   FILE* xmfFile = 0;
 
   /* Number of unassociated gparts */
@@ -962,7 +990,7 @@ void write_output_serial(struct engine* e, const char* baseName,
 
           case swift_type_gas:
             Nparticles = Ngas;
-            hydro_write_particles(parts, list, &num_fields);
+            hydro_write_particles(parts, xparts, list, &num_fields);
             num_fields += chemistry_write_particles(parts, list + num_fields);
             break;
 
diff --git a/src/serial_io.h b/src/serial_io.h
index 025faffc0087a8b26d4149914e621a978e63c9be..cad428916f400bc9b144dcf4c23f9d38c75c1e9d 100644
--- a/src/serial_io.h
+++ b/src/serial_io.h
@@ -22,6 +22,8 @@
 /* Config parameters. */
 #include "../config.h"
 
+#if defined(HAVE_HDF5) && defined(WITH_MPI) && !defined(HAVE_PARALLEL_HDF5)
+
 /* MPI headers. */
 #ifdef WITH_MPI
 #include <mpi.h>
@@ -32,15 +34,13 @@
 #include "part.h"
 #include "units.h"
 
-#if defined(HAVE_HDF5) && defined(WITH_MPI) && !defined(HAVE_PARALLEL_HDF5)
-
 void read_ic_serial(char* fileName, const struct unit_system* internal_units,
                     double dim[3], struct part** parts, struct gpart** gparts,
                     struct spart** sparts, size_t* Ngas, size_t* Ngparts,
                     size_t* Nstars, int* periodic, int* flag_entropy,
                     int with_hydro, int with_gravity, int with_stars,
-                    int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info,
-                    int nr_threads, int dry_run);
+                    int cleanup_h, double h, int mpi_rank, int mpi_size,
+                    MPI_Comm comm, MPI_Info info, int nr_threads, int dry_run);
 
 void write_output_serial(struct engine* e, const char* baseName,
                          const struct unit_system* internal_units,
diff --git a/src/single_io.c b/src/single_io.c
index 0fecd724908f7ce2779526792ce8512b9236d58e..2170bcffc4ce3ab21f1edd168d1dc37b2b4af963 100644
--- a/src/single_io.c
+++ b/src/single_io.c
@@ -64,13 +64,15 @@
  * @param N The number of particles.
  * @param internal_units The #unit_system used internally
  * @param ic_units The #unit_system used in the ICs
+ * @param cleanup_h Are we removing h-factors from the ICs?
+ * @param The value of the reduced Hubble constant.
  *
  * @todo A better version using HDF5 hyper-slabs to read the file directly into
  * the part array will be written once the structures have been stabilized.
  */
 void readArray(hid_t h_grp, const struct io_props prop, size_t N,
                const struct unit_system* internal_units,
-               const struct unit_system* ic_units) {
+               const struct unit_system* ic_units, int cleanup_h, double h) {
 
   const size_t typeSize = io_sizeof_type(prop.type);
   const size_t copySize = typeSize * prop.dimension;
@@ -124,18 +126,35 @@ void readArray(hid_t h_grp, const struct io_props prop, size_t N,
   }
 
   /* Unit conversion if necessary */
-  const double factor =
+  const double unit_factor =
       units_conversion_factor(ic_units, internal_units, prop.units);
-  if (factor != 1. && exist != 0) {
+  if (unit_factor != 1. && exist != 0) {
 
     /* message("Converting ! factor=%e", factor); */
 
     if (io_is_double_precision(prop.type)) {
       double* temp_d = (double*)temp;
-      for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= factor;
+      for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= unit_factor;
     } else {
       float* temp_f = (float*)temp;
-      for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= factor;
+      for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= unit_factor;
+    }
+  }
+
+  /* Clean-up h if necessary */
+  const float h_factor_exp = units_h_factor(internal_units, prop.units);
+  if (cleanup_h && h_factor_exp != 0.f && exist != 0) {
+    const double h_factor = pow(h, h_factor_exp);
+
+    /* message("Multipltying '%s' by h^%f=%f", prop.name, h_factor_exp,
+     * h_factor); */
+
+    if (io_is_double_precision(prop.type)) {
+      double* temp_d = (double*)temp;
+      for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= h_factor;
+    } else {
+      float* temp_f = (float*)temp;
+      for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= h_factor;
     }
   }
 
@@ -270,8 +289,7 @@ void writeArray(const struct engine* e, hid_t grp, char* fileName,
   io_write_attribute_d(
       h_data, "CGS conversion factor",
       units_cgs_conversion_factor(snapshot_units, props.units));
-  io_write_attribute_f(h_data, "h-scale exponent",
-                       units_h_factor(snapshot_units, props.units));
+  io_write_attribute_f(h_data, "h-scale exponent", 0);
   io_write_attribute_f(h_data, "a-scale exponent",
                        units_a_factor(snapshot_units, props.units));
   io_write_attribute_s(h_data, "Conversion factor", buffer);
@@ -301,6 +319,9 @@ void writeArray(const struct engine* e, hid_t grp, char* fileName,
  * @param with_hydro Are we reading gas particles ?
  * @param with_gravity Are we reading/creating #gpart arrays ?
  * @param with_stars Are we reading star particles ?
+ * @param cleanup_h Are we cleaning-up h-factors from the quantities we read?
+ * @param h The value of the reduced Hubble constant to use for correction.
+ * @prarm n_threads The number of threads to use for the temporary threadpool.
  * @param dry_run If 1, don't read the particle. Only allocates the arrays.
  *
  * Opens the HDF5 file fileName and reads the particles contained
@@ -316,7 +337,7 @@ void read_ic_single(char* fileName, const struct unit_system* internal_units,
                     struct spart** sparts, size_t* Ngas, size_t* Ngparts,
                     size_t* Nstars, int* periodic, int* flag_entropy,
                     int with_hydro, int with_gravity, int with_stars,
-                    int n_threads, int dry_run) {
+                    int cleanup_h, double h, int n_threads, int dry_run) {
 
   hid_t h_file = 0, h_grp = 0;
   /* GADGET has only cubic boxes (in cosmological mode) */
@@ -384,6 +405,13 @@ void read_ic_single(char* fileName, const struct unit_system* internal_units,
   else if (hydro_dimension == 1)
     dim[2] = dim[1] = dim[0];
 
+  /* Convert the box size if we want to clean-up h-factors */
+  if (cleanup_h) {
+    dim[0] /= h;
+    dim[1] /= h;
+    dim[2] /= h;
+  }
+
   /* message("Found %d particles in a %speriodic box of size [%f %f %f].",  */
   /* 	  *N, (periodic ? "": "non-"), dim[0], dim[1], dim[2]);  */
 
@@ -517,7 +545,8 @@ void read_ic_single(char* fileName, const struct unit_system* internal_units,
     /* Read everything */
     if (!dry_run)
       for (int i = 0; i < num_fields; ++i)
-        readArray(h_grp, list[i], Nparticles, internal_units, ic_units);
+        readArray(h_grp, list[i], Nparticles, internal_units, ic_units,
+                  cleanup_h, h);
 
     /* Close particle group */
     H5Gclose(h_grp);
@@ -578,10 +607,11 @@ void write_output_single(struct engine* e, const char* baseName,
   const size_t Ntot = e->s->nr_gparts;
   int periodic = e->s->periodic;
   int numFiles = 1;
-  struct part* parts = e->s->parts;
-  struct gpart* gparts = e->s->gparts;
+  const struct part* parts = e->s->parts;
+  const struct xpart* xparts = e->s->xparts;
+  const struct gpart* gparts = e->s->gparts;
   struct gpart* dmparts = NULL;
-  struct spart* sparts = e->s->sparts;
+  const struct spart* sparts = e->s->sparts;
 
   /* Number of unassociated gparts */
   const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0;
@@ -779,7 +809,7 @@ void write_output_single(struct engine* e, const char* baseName,
 
       case swift_type_gas:
         N = Ngas;
-        hydro_write_particles(parts, list, &num_fields);
+        hydro_write_particles(parts, xparts, list, &num_fields);
         num_fields += chemistry_write_particles(parts, list + num_fields);
         break;
 
diff --git a/src/single_io.h b/src/single_io.h
index efed4ef27ade61f7726777d71a2fdc586ea26030..26b849716e3e018d9a10c5c5c513ad26c7ccb274 100644
--- a/src/single_io.h
+++ b/src/single_io.h
@@ -22,24 +22,24 @@
 /* Config parameters. */
 #include "../config.h"
 
+#if defined(HAVE_HDF5) && !defined(WITH_MPI)
+
 /* Includes. */
 #include "engine.h"
 #include "part.h"
 #include "units.h"
 
-#if defined(HAVE_HDF5) && !defined(WITH_MPI)
-
 void read_ic_single(char* fileName, const struct unit_system* internal_units,
                     double dim[3], struct part** parts, struct gpart** gparts,
                     struct spart** sparts, size_t* Ngas, size_t* Ndm,
                     size_t* Nstars, int* periodic, int* flag_entropy,
                     int with_hydro, int with_gravity, int with_stars,
-                    int nr_threads, int dry_run);
+                    int cleanup_h, double h, int nr_threads, int dry_run);
 
 void write_output_single(struct engine* e, const char* baseName,
                          const struct unit_system* internal_units,
                          const struct unit_system* snapshot_units);
 
-#endif
+#endif /* HAVE_HDF5 && !WITH_MPI */
 
 #endif /* SWIFT_SINGLE_IO_H */
diff --git a/src/space.c b/src/space.c
index 31e4250c83d86314d38c3dcf739ef179ef813235..bac6240512edbf2ad31a3216bcd518d56e3573a4 100644
--- a/src/space.c
+++ b/src/space.c
@@ -2321,8 +2321,20 @@ void space_first_init_parts(struct space *s,
   struct part *restrict p = s->parts;
   struct xpart *restrict xp = s->xparts;
 
+  const struct cosmology *cosmo = s->e->cosmology;
+  const float a_factor_vel = cosmo->a * cosmo->a;
+
+  const struct hydro_props *hydro_props = s->e->hydro_properties;
+  const float u_init = hydro_props->initial_internal_energy;
+  const float u_min = hydro_props->minimal_internal_energy;
+
   for (size_t i = 0; i < nr_parts; ++i) {
 
+    /* Convert velocities to internal units */
+    p[i].v[0] *= a_factor_vel;
+    p[i].v[1] *= a_factor_vel;
+    p[i].v[2] *= a_factor_vel;
+
 #ifdef HYDRO_DIMENSION_2D
     p[i].x[2] = 0.f;
     p[i].v[2] = 0.f;
@@ -2335,6 +2347,10 @@ void space_first_init_parts(struct space *s,
 
     hydro_first_init_part(&p[i], &xp[i]);
 
+    /* Overwrite the internal energy? */
+    if (u_init > 0.f) hydro_set_init_internal_energy(&p[i], u_init);
+    if (u_min > 0.f) hydro_set_init_internal_energy(&p[i], u_min);
+
     /* Also initialise the chemistry */
     chemistry_first_init_part(&p[i], &xp[i], chemistry);
 
@@ -2361,9 +2377,16 @@ void space_first_init_gparts(struct space *s,
 
   const size_t nr_gparts = s->nr_gparts;
   struct gpart *restrict gp = s->gparts;
+  const struct cosmology *cosmo = s->e->cosmology;
+  const float a_factor_vel = cosmo->a * cosmo->a;
 
   for (size_t i = 0; i < nr_gparts; ++i) {
 
+    /* Convert velocities to internal units */
+    gp[i].v_full[0] *= a_factor_vel;
+    gp[i].v_full[1] *= a_factor_vel;
+    gp[i].v_full[2] *= a_factor_vel;
+
 #ifdef HYDRO_DIMENSION_2D
     gp[i].x[2] = 0.f;
     gp[i].v_full[2] = 0.f;
@@ -2392,9 +2415,16 @@ void space_first_init_sparts(struct space *s) {
 
   const size_t nr_sparts = s->nr_sparts;
   struct spart *restrict sp = s->sparts;
+  const struct cosmology *cosmo = s->e->cosmology;
+  const float a_factor_vel = cosmo->a * cosmo->a;
 
   for (size_t i = 0; i < nr_sparts; ++i) {
 
+    /* Convert velocities to internal units */
+    sp[i].v[0] *= a_factor_vel;
+    sp[i].v[1] *= a_factor_vel;
+    sp[i].v[2] *= a_factor_vel;
+
 #ifdef HYDRO_DIMENSION_2D
     sp[i].x[2] = 0.f;
     sp[i].v[2] = 0.f;
@@ -2472,11 +2502,12 @@ void space_init_gparts(struct space *s, int verbose) {
 void space_convert_quantities_mapper(void *restrict map_data, int count,
                                      void *restrict extra_data) {
   struct space *s = (struct space *)extra_data;
+  const struct cosmology *cosmo = s->e->cosmology;
   struct part *restrict parts = (struct part *)map_data;
   const ptrdiff_t index = parts - s->parts;
   struct xpart *restrict xparts = s->xparts + index;
   for (int k = 0; k < count; k++)
-    hydro_convert_quantities(&parts[k], &xparts[k]);
+    hydro_convert_quantities(&parts[k], &xparts[k], cosmo);
 }
 
 /**
@@ -2504,6 +2535,7 @@ void space_convert_quantities(struct space *s, int verbose) {
  *
  * @param s The #space to initialize.
  * @param params The parsed parameter file.
+ * @param cosmo The current cosmological model.
  * @param dim Spatial dimensions of the domain.
  * @param parts Array of Gas particles.
  * @param gparts Array of Gravity particles.
@@ -2512,8 +2544,9 @@ void space_convert_quantities(struct space *s, int verbose) {
  * @param Ngpart The number of Gravity particles in the space.
  * @param Nspart The number of star particles in the space.
  * @param periodic flag whether the domain is periodic or not.
- * @param replicate How many replications along each direction do we want ?
- * @param gravity flag whether we are doing gravity or not.
+ * @param replicate How many replications along each direction do we want?
+ * @param generate_gas_in_ics Are we generating gas particles from the gparts?
+ * @param self_gravity flag whether we are doing gravity or not?
  * @param verbose Print messages to stdout or not.
  * @param dry_run If 1, just initialise stuff, don't do anything with the parts.
  *
@@ -2523,9 +2556,10 @@ void space_convert_quantities(struct space *s, int verbose) {
  * recursively.
  */
 void space_init(struct space *s, const struct swift_params *params,
-                double dim[3], struct part *parts, struct gpart *gparts,
-                struct spart *sparts, size_t Npart, size_t Ngpart,
-                size_t Nspart, int periodic, int replicate, int gravity,
+                const struct cosmology *cosmo, double dim[3],
+                struct part *parts, struct gpart *gparts, struct spart *sparts,
+                size_t Npart, size_t Ngpart, size_t Nspart, int periodic,
+                int replicate, int generate_gas_in_ics, int self_gravity,
                 int verbose, int dry_run) {
 
   /* Clean-up everything */
@@ -2536,7 +2570,7 @@ void space_init(struct space *s, const struct swift_params *params,
   s->dim[1] = dim[1];
   s->dim[2] = dim[2];
   s->periodic = periodic;
-  s->gravity = gravity;
+  s->gravity = self_gravity;
   s->nr_parts = Npart;
   s->size_parts = Npart;
   s->parts = parts;
@@ -2548,6 +2582,19 @@ void space_init(struct space *s, const struct swift_params *params,
   s->sparts = sparts;
   s->nr_queues = 1; /* Temporary value until engine construction */
 
+  /* Are we generating gas from the DM-only ICs? */
+  if (generate_gas_in_ics) {
+    space_generate_gas(s, cosmo, verbose);
+    parts = s->parts;
+    gparts = s->gparts;
+    Npart = s->nr_parts;
+    Ngpart = s->nr_gparts;
+
+#ifdef SWIFT_DEBUG_CHECKS
+    part_verify_links(parts, gparts, sparts, Npart, Ngpart, Nspart, 1);
+#endif
+  }
+
   /* Are we replicating the space ? */
   if (replicate < 1)
     error("Value of 'InitialConditions:replicate' (%d) is too small",
@@ -2560,6 +2607,10 @@ void space_init(struct space *s, const struct swift_params *params,
     Npart = s->nr_parts;
     Ngpart = s->nr_gparts;
     Nspart = s->nr_sparts;
+
+#ifdef SWIFT_DEBUG_CHECKS
+    part_verify_links(parts, gparts, sparts, Npart, Ngpart, Nspart, 1);
+#endif
   }
 
   /* Decide on the minimal top-level cell size */
@@ -2606,8 +2657,8 @@ void space_init(struct space *s, const struct swift_params *params,
   }
 
   /* Apply h scaling */
-  const double scaling =
-      parser_get_opt_param_double(params, "InitialConditions:h_scaling", 1.0);
+  const double scaling = parser_get_opt_param_double(
+      params, "InitialConditions:smoothing_length_scaling", 1.0);
   if (scaling != 1.0 && !dry_run) {
     message("Re-scaling smoothing lengths by a factor %e", scaling);
     for (size_t k = 0; k < Npart; k++) parts[k].h *= scaling;
@@ -2824,6 +2875,152 @@ void space_replicate(struct space *s, int replicate, int verbose) {
 #endif
 }
 
+void space_generate_gas(struct space *s, const struct cosmology *cosmo,
+                        int verbose) {
+
+  if (verbose) message("Generating gas particles from gparts");
+
+  /* Store the current values */
+  const size_t nr_parts = s->nr_parts;
+  const size_t nr_gparts = s->nr_gparts;
+
+  if (nr_parts != 0)
+    error("Generating gas particles from DM but gas already exists!");
+
+  s->size_parts = s->nr_parts = nr_gparts;
+  s->size_gparts = s->nr_gparts = 2 * nr_gparts;
+
+  /* Allocate space for new particles */
+  struct part *parts = NULL;
+  struct gpart *gparts = NULL;
+
+  if (posix_memalign((void **)&parts, part_align,
+                     s->nr_parts * sizeof(struct part)) != 0)
+    error("Failed to allocate new part array.");
+
+  if (posix_memalign((void **)&gparts, gpart_align,
+                     s->nr_gparts * sizeof(struct gpart)) != 0)
+    error("Failed to allocate new gpart array.");
+
+  /* Start by copying the gparts */
+  memcpy(gparts, s->gparts, nr_gparts * sizeof(struct gpart));
+  memcpy(gparts + nr_gparts, s->gparts, nr_gparts * sizeof(struct gpart));
+
+  /* And zero the parts */
+  bzero(parts, s->nr_parts * sizeof(struct part));
+
+  /* Compute some constants */
+  const double mass_ratio = cosmo->Omega_b / cosmo->Omega_m;
+  const double bg_density = cosmo->Omega_m * cosmo->critical_density;
+  const double bg_density_inv = 1. / bg_density;
+
+  /* Update the particle properties */
+  for (size_t i = 0; i < nr_gparts; ++i) {
+
+    struct part *p = &parts[i];
+    struct gpart *gp_gas = &gparts[i];
+    struct gpart *gp_dm = &gparts[nr_gparts + i];
+
+    /* Set the IDs */
+    p->id = gp_gas->id_or_neg_offset * 2 + 1;
+    gp_dm->id_or_neg_offset *= 2;
+
+    if (gp_dm->id_or_neg_offset <= 0) error("DM particle ID overflowd");
+
+    if (p->id <= 0) error("gas particle ID overflowd");
+
+    /* Set the links correctly */
+    p->gpart = gp_gas;
+    gp_gas->id_or_neg_offset = -i;
+    gp_gas->type = swift_type_gas;
+
+    /* Compute positions shift */
+    const double d = cbrt(gp_dm->mass * bg_density_inv);
+    const double shift_dm = d * mass_ratio;
+    const double shift_gas = d * (1. - mass_ratio);
+
+    /* Set the masses */
+    gp_dm->mass *= (1. - mass_ratio);
+    gp_gas->mass *= mass_ratio;
+    hydro_set_mass(p, gp_gas->mass);
+
+    /* Set the new positions */
+    gp_dm->x[0] += shift_dm;
+    gp_dm->x[1] += shift_dm;
+    gp_dm->x[2] += shift_dm;
+    gp_gas->x[0] += shift_gas;
+    gp_gas->x[1] += shift_gas;
+    gp_gas->x[2] += shift_gas;
+    p->x[0] = gp_gas->x[0];
+    p->x[1] = gp_gas->x[1];
+    p->x[2] = gp_gas->x[2];
+
+    /* Also copy the velocities */
+    p->v[0] = gp_gas->v_full[0];
+    p->v[1] = gp_gas->v_full[1];
+    p->v[2] = gp_gas->v_full[2];
+
+    /* Set the smoothing length to the mean inter-particle separation */
+    p->h = 30. * d;
+  }
+
+  /* Replace the content of the space */
+  free(s->gparts);
+  s->parts = parts;
+  s->gparts = gparts;
+}
+
+/**
+ * @brief Verify that the matter content matches the cosmology model.
+ *
+ * @param s The #space.
+ * @param cosmo The current cosmology model.
+ * @param rank The MPI rank of this #space.
+ */
+void space_check_cosmology(struct space *s, const struct cosmology *cosmo,
+                           int rank) {
+
+  struct gpart *gparts = s->gparts;
+  const size_t nr_gparts = s->nr_gparts;
+
+  /* Sum up the mass in this space */
+  double mass = 0.;
+  for (size_t i = 0; i < nr_gparts; ++i) {
+    mass += gparts[i].mass;
+  }
+
+/* Reduce the total mass */
+#ifdef WITH_MPI
+  double total_mass;
+  MPI_Reduce(&mass, &total_mass, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
+#else
+  double total_mass = mass;
+#endif
+
+  if (rank == 0) {
+
+    const double volume = s->dim[0] * s->dim[1] * s->dim[2];
+
+    /* Current Hubble constant */
+    const double H = cosmo->H;
+
+    /* z=0 Hubble parameter */
+    const double H0 = cosmo->H0;
+
+    /* Critical density at z=0 */
+    const double rho_crit0 = cosmo->critical_density * H0 * H0 / (H * H);
+
+    /* Compute the mass density */
+    const double Omega_m = (total_mass / volume) / rho_crit0;
+
+    if (fabs(Omega_m - cosmo->Omega_m) > 1e-3)
+      error(
+          "The matter content of the simulation does not match the cosmology "
+          "in the parameter file comso.Omega_m=%e Omega_m=%e",
+          cosmo->Omega_m, Omega_m);
+  }
+}
+
 /**
  * @brief Cleans-up all the cell links in the space
  *
diff --git a/src/space.h b/src/space.h
index c8277d51ed70204efbd52b8688888c83b05a6979..571b595eda8758c510a014bc784ae4bde85abaea 100644
--- a/src/space.h
+++ b/src/space.h
@@ -38,6 +38,7 @@
 
 /* Avoid cyclic inclusions */
 struct cell;
+struct cosmology;
 
 /* Some constants. */
 #define space_cellallocchunk 1000
@@ -184,9 +185,10 @@ void space_getcells(struct space *s, int nr_cells, struct cell **cells);
 int space_getsid(struct space *s, struct cell **ci, struct cell **cj,
                  double *shift);
 void space_init(struct space *s, const struct swift_params *params,
-                double dim[3], struct part *parts, struct gpart *gparts,
-                struct spart *sparts, size_t Npart, size_t Ngpart,
-                size_t Nspart, int periodic, int replicate, int gravity,
+                const struct cosmology *cosmo, double dim[3],
+                struct part *parts, struct gpart *gparts, struct spart *sparts,
+                size_t Npart, size_t Ngpart, size_t Nspart, int periodic,
+                int replicate, int generate_gas_in_ics, int gravity,
                 int verbose, int dry_run);
 void space_sanitize(struct space *s);
 void space_map_cells_pre(struct space *s, int full,
@@ -235,6 +237,10 @@ void space_check_top_multipoles_drift_point(struct space *s,
                                             integertime_t ti_drift);
 void space_check_timesteps(struct space *s);
 void space_replicate(struct space *s, int replicate, int verbose);
+void space_generate_gas(struct space *s, const struct cosmology *cosmo,
+                        int verbose);
+void space_check_cosmology(struct space *s, const struct cosmology *cosmo,
+                           int rank);
 void space_reset_task_counters(struct space *s);
 void space_clean(struct space *s);
 void space_free_cells(struct space *s);
diff --git a/src/stars/Default/star_io.h b/src/stars/Default/star_io.h
index 96bbdce6d83dc241d05e7dd1754f476dc0b8e5f9..c3dc31096383533e1e15fa65615d2c9aac0f43e3 100644
--- a/src/stars/Default/star_io.h
+++ b/src/stars/Default/star_io.h
@@ -52,7 +52,7 @@ void star_read_particles(struct spart* sparts, struct io_props* list,
  * @param list The list of i/o properties to write.
  * @param num_fields The number of i/o fields to write.
  */
-void star_write_particles(struct spart* sparts, struct io_props* list,
+void star_write_particles(const struct spart* sparts, struct io_props* list,
                           int* num_fields) {
 
   /* Say how much we want to read */
diff --git a/src/units.c b/src/units.c
index 5c50bb063b9411f47357407678458e6094f69e2b..4b632e735b7c6e1c12afe8aebc16aa44abc5b597 100644
--- a/src/units.c
+++ b/src/units.c
@@ -220,6 +220,11 @@ void units_get_base_unit_exponants_array(float baseUnitsExp[5],
       baseUnitsExp[UNIT_TIME] = -2.f;
       break;
 
+    case UNIT_CONV_POTENTIAL:
+      baseUnitsExp[UNIT_LENGTH] = 2.f;
+      baseUnitsExp[UNIT_TIME] = -2.f;
+      break;
+
     case UNIT_CONV_FORCE:
       baseUnitsExp[UNIT_MASS] = 1.f;
       baseUnitsExp[UNIT_LENGTH] = 1.f;
diff --git a/src/units.h b/src/units.h
index 5ac70a909a77146ba5f7a441d7747acfc80c3dfa..87c44cc6eb4934980027a60642dd135f03029f7c 100644
--- a/src/units.h
+++ b/src/units.h
@@ -73,6 +73,7 @@ enum unit_conversion_factor {
   UNIT_CONV_DENSITY,
   UNIT_CONV_SPEED,
   UNIT_CONV_ACCELERATION,
+  UNIT_CONV_POTENTIAL,
   UNIT_CONV_FORCE,
   UNIT_CONV_ENERGY,
   UNIT_CONV_ENERGY_PER_UNIT_MASS,
diff --git a/tests/fft_params.yml b/tests/fft_params.yml
index 05d6d8f0b0578d11645fc1d78c1a6322160ae87a..6938e3658148874e58f50ab768a5e1fbc41d9573 100644
--- a/tests/fft_params.yml
+++ b/tests/fft_params.yml
@@ -3,8 +3,9 @@ Scheduler:
   
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                   0.025    # Constant dimensionless multiplier for time integration. 
-  theta:                 0.7      # Opening angle (Multipole acceptance criterion)
-  epsilon:               0.00001  # Softening length (in internal units).
-  a_smooth:              0.
-  r_cut:                 0.
+  eta:                    0.025      # Constant dimensionless multiplier for time integration.
+  theta:                  0.7        # Opening angle (Multipole acceptance criterion)
+  comoving_softening:     0.00001    # Comoving softening length (in internal units).
+  max_physical_softening: 0.00001    # Physical softening length (in internal units).
+  a_smooth:               0.
+  r_cut:                  0.
diff --git a/tests/testFFT.c b/tests/testFFT.c
index ba737935afc4568a1509d2c43a3534b60a6ef867..7b67181ebd3e29bffbf564d00f702e6c15669fab 100644
--- a/tests/testFFT.c
+++ b/tests/testFFT.c
@@ -57,15 +57,18 @@ int main() {
   struct swift_params *params = malloc(sizeof(struct swift_params));
   parser_read_file("fft_params.yml", params);
 
+  struct cosmology cosmo;
+  cosmology_init_no_cosmo(&cosmo);
+
   /* Initialise the gravity properties */
   struct gravity_props gravity_properties;
-  gravity_props_init(&gravity_properties, params);
+  gravity_props_init(&gravity_properties, params, &cosmo);
 
   /* Build the infrastructure */
   struct space space;
   double dim[3] = {1., 1., 1.};
-  space_init(&space, params, dim, NULL, gparts, NULL, 0, nr_gparts, 0, 1, 1, 1,
-             0, 0);
+  space_init(&space, params, &cosmo, dim, NULL, gparts, NULL, 0, nr_gparts, 0,
+             1, 1, 0, 1, 0, 0);
 
   struct engine engine;
   engine.s = &space;
diff --git a/tests/testPotentialPair.c b/tests/testPotentialPair.c
index 5fbfb04ecd0b4a8c05c07d622dd77bd38af970ae..53fc54ccdd63a9a9150b6701c1a76ac20af91d4c 100644
--- a/tests/testPotentialPair.c
+++ b/tests/testPotentialPair.c
@@ -106,6 +106,7 @@ int main() {
   props.a_smooth = 1.25;
   props.r_cut_min = 0.;
   props.theta_crit2 = 0.;
+  props.epsilon_cur = eps;
   e.gravity_properties = &props;
 
   struct runner r;
@@ -178,7 +179,6 @@ int main() {
     gp->x[1] = 0.5;
     gp->x[2] = 0.5;
     gp->mass = 0.;
-    gp->epsilon = eps;
     gp->time_bin = 1;
     gp->type = swift_type_dark_matter;
     gp->id_or_neg_offset = n + 1;
@@ -196,7 +196,6 @@ int main() {
   ci.gparts[0].x[1] = 0.5;
   ci.gparts[0].x[2] = 0.5;
   ci.gparts[0].mass = 1.;
-  ci.gparts[0].epsilon = eps;
   ci.gparts[0].time_bin = 1;
   ci.gparts[0].type = swift_type_dark_matter;
   ci.gparts[0].id_or_neg_offset = 1;
@@ -211,11 +210,12 @@ int main() {
   for (int n = 0; n < num_tests; ++n) {
     const struct gpart *gp = &cj.gparts[n];
     const struct gpart *gp2 = &ci.gparts[0];
+    const double epsilon = gravity_get_softening(gp, &props);
 
     double pot_true =
-        potential(ci.gparts[0].mass, gp->x[0] - gp2->x[0], gp->epsilon, rlr);
+        potential(ci.gparts[0].mass, gp->x[0] - gp2->x[0], epsilon, rlr);
     double acc_true =
-        acceleration(ci.gparts[0].mass, gp->x[0] - gp2->x[0], gp->epsilon, rlr);
+        acceleration(ci.gparts[0].mass, gp->x[0] - gp2->x[0], epsilon, rlr);
 
     message("x=%e f=%e f_true=%e pot=%e pot_true=%e", gp->x[0] - gp2->x[0],
             gp->a_grav[0], acc_true, gp->potential, pot_true);
@@ -252,12 +252,12 @@ int main() {
   for (int n = 0; n < num_tests; ++n) {
     const struct gpart *gp = &cj.gparts[n];
     const struct gravity_tensors *mpole = ci.multipole;
+    const double epsilon = gravity_get_softening(gp, &props);
 
     double pot_true = potential(mpole->m_pole.M_000, gp->x[0] - mpole->CoM[0],
-                                gp->epsilon, rlr * FLT_MAX);
-    double acc_true =
-        acceleration(mpole->m_pole.M_000, gp->x[0] - mpole->CoM[0], gp->epsilon,
-                     rlr * FLT_MAX);
+                                epsilon, rlr * FLT_MAX);
+    double acc_true = acceleration(
+        mpole->m_pole.M_000, gp->x[0] - mpole->CoM[0], epsilon, rlr * FLT_MAX);
 
     message("x=%e f=%e f_true=%e pot=%e pot_true=%e", gp->x[0] - mpole->CoM[0],
             gp->a_grav[0], acc_true, gp->potential, pot_true);
@@ -304,7 +304,6 @@ int main() {
 
     ci.gparts[n].mass = 1. / 8.;
 
-    ci.gparts[n].epsilon = eps;
     ci.gparts[n].time_bin = 1;
     ci.gparts[n].type = swift_type_dark_matter;
     ci.gparts[n].id_or_neg_offset = 1;
@@ -333,18 +332,19 @@ int main() {
 
     for (int i = 0; i < 8; ++i) {
       const struct gpart *gp2 = &ci.gparts[i];
+      const double epsilon = gravity_get_softening(gp, &props);
 
       const double dx[3] = {gp2->x[0] - gp->x[0], gp2->x[1] - gp->x[1],
                             gp2->x[2] - gp->x[2]};
       const double d = sqrt(dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]);
 
-      pot_true += potential(gp2->mass, d, gp->epsilon, rlr * FLT_MAX);
+      pot_true += potential(gp2->mass, d, epsilon, rlr * FLT_MAX);
       acc_true[0] -=
-          acceleration(gp2->mass, d, gp->epsilon, rlr * FLT_MAX) * dx[0] / d;
+          acceleration(gp2->mass, d, epsilon, rlr * FLT_MAX) * dx[0] / d;
       acc_true[1] -=
-          acceleration(gp2->mass, d, gp->epsilon, rlr * FLT_MAX) * dx[1] / d;
+          acceleration(gp2->mass, d, epsilon, rlr * FLT_MAX) * dx[1] / d;
       acc_true[2] -=
-          acceleration(gp2->mass, d, gp->epsilon, rlr * FLT_MAX) * dx[2] / d;
+          acceleration(gp2->mass, d, epsilon, rlr * FLT_MAX) * dx[2] / d;
     }
 
     message("x=%e f=%e f_true=%e pot=%e pot_true=%e %e %e",
diff --git a/tests/testPotentialSelf.c b/tests/testPotentialSelf.c
index 33fe574e34bcc49ff8bac6f19f22b55fda19f186..6d31f079fa79f7463637ec71dc2c75f37a10b129 100644
--- a/tests/testPotentialSelf.c
+++ b/tests/testPotentialSelf.c
@@ -41,15 +41,18 @@ const double eps = 0.02;
  * @param s String used to identify this check in messages
  */
 void check_value(double a, double b, const char *s) {
-  if (fabs(a - b) / fabs(a + b) > 2e-6 && fabs(a - b) > 1.e-6)
+  if (fabs(a - b) / fabs(a + b) > 1e-6 && fabs(a - b) > 1.e-6)
     error("Values are inconsistent: %12.15e %12.15e (%s)!", a, b, s);
 }
 
 /* Definitions of the potential and force that match
    exactly the theory document */
-double S(double x) { return exp(x) / (1. + exp(x)); }
+double S(double x) { return good_approx_exp(x) / (1. + good_approx_exp(x)); }
 
-double S_prime(double x) { return exp(x) / ((1. + exp(x)) * (1. + exp(x))); }
+double S_prime(double x) {
+  return good_approx_exp(x) /
+         ((1. + good_approx_exp(x)) * (1. + good_approx_exp(x)));
+}
 
 double potential(double mass, double r, double H, double rlr) {
 
@@ -103,6 +106,7 @@ int main() {
 
   struct gravity_props props;
   props.a_smooth = 1.25;
+  props.epsilon_cur = eps;
   e.gravity_properties = &props;
 
   struct runner r;
@@ -139,7 +143,6 @@ int main() {
   c.gparts[0].x[1] = 0.5;
   c.gparts[0].x[2] = 0.5;
   c.gparts[0].mass = 1.;
-  c.gparts[0].epsilon = eps;
   c.gparts[0].time_bin = 1;
   c.gparts[0].type = swift_type_dark_matter;
   c.gparts[0].id_or_neg_offset = 1;
@@ -156,7 +159,6 @@ int main() {
     gp->x[1] = 0.5;
     gp->x[2] = 0.5;
     gp->mass = 0.;
-    gp->epsilon = eps;
     gp->time_bin = 1;
     gp->type = swift_type_dark_matter;
     gp->id_or_neg_offset = n + 1;
@@ -172,9 +174,10 @@ int main() {
   for (int n = 1; n < num_tests + 1; ++n) {
     const struct gpart *gp = &c.gparts[n];
 
-    double pot_true = potential(c.gparts[0].mass, gp->x[0], gp->epsilon, rlr);
-    double acc_true =
-        acceleration(c.gparts[0].mass, gp->x[0], gp->epsilon, rlr);
+    const double epsilon = gravity_get_softening(gp, &props);
+
+    double pot_true = potential(c.gparts[0].mass, gp->x[0], epsilon, rlr);
+    double acc_true = acceleration(c.gparts[0].mass, gp->x[0], epsilon, rlr);
 
     // message("x=%e f=%e f_true=%e", gp->x[0], gp->a_grav[0], acc_true);
 
diff --git a/tests/testReading.c b/tests/testReading.c
index f5e2757c2fe3bd507e877f134e8c768aba0ae645..ca1e0ef69078c5e384a9cd4eab1098923ce9f279 100644
--- a/tests/testReading.c
+++ b/tests/testReading.c
@@ -48,7 +48,8 @@ int main() {
 
   /* Read data */
   read_ic_single("input.hdf5", &us, dim, &parts, &gparts, &sparts, &Ngas,
-                 &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, 1, 1, 0, 1, 0);
+                 &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, 1, 1, 0, 0, 1.,
+                 1, 0);
 
   /* Check global properties read are correct */
   assert(dim[0] == boxSize);
diff --git a/tests/testSymmetry.c b/tests/testSymmetry.c
index 7a62f735b57b3a8fe5b91308b4dfe8ce00706e0e..6c6cd291dc4b919650d568354d7949f9ed4e0155 100644
--- a/tests/testSymmetry.c
+++ b/tests/testSymmetry.c
@@ -59,6 +59,8 @@ void test() {
   pj.h = 2.f;
   pi.id = 1ll;
   pj.id = 2ll;
+  pi.time_bin = 1;
+  pj.time_bin = 1;
 
 #if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
   /* Give the primitive variables sensible values, since the Riemann solver does
@@ -157,8 +159,20 @@ void test() {
   i_not_ok = memcmp(&pi, &pi2, sizeof(struct part));
   j_not_ok = memcmp(&pj, &pj2, sizeof(struct part));
 
-  if (i_not_ok) error("Particles 'pi' do not match after density");
-  if (j_not_ok) error("Particles 'pj' do not match after density");
+  if (i_not_ok) {
+    printParticle_single(&pi, &xpi);
+    printParticle_single(&pi2, &xpi);
+    print_bytes(&pj, sizeof(struct part));
+    print_bytes(&pj2, sizeof(struct part));
+    error("Particles 'pi' do not match after force (byte = %d)", i_not_ok);
+  }
+  if (j_not_ok) {
+    printParticle_single(&pj, &xpj);
+    printParticle_single(&pj2, &xpj);
+    print_bytes(&pj, sizeof(struct part));
+    print_bytes(&pj2, sizeof(struct part));
+    error("Particles 'pj' do not match after force (byte = %d)", j_not_ok);
+  }
 
   /* --- Test the force loop --- */
 
diff --git a/tests/tolerance_125_normal.dat b/tests/tolerance_125_normal.dat
index 0f11d03507b23c76b5703e118eede1359fe2afba..ff3d42e22b5b91378114294c4c81405492eafad2 100644
--- a/tests/tolerance_125_normal.dat
+++ b/tests/tolerance_125_normal.dat
@@ -1,4 +1,4 @@
 #   ID    pos_x    pos_y    pos_z      v_x      v_y      v_z        h      rho    div_v        S        u        P        c      a_x      a_y      a_z     h_dt    v_sig    dS/dt    du/dt
     0	  1e-4	   1e-4	    1e-4       1e-4	1e-4	 1e-4	    1e-4   1e-4	  1e-4	       1e-4	1e-4	 1e-4	  1e-4	 1e-4	  1e-4	   1e-4	   1e-4	   1e-4	    1e-4     1e-4
     0	  1e-4	   1e-4	    1e-4       1e-4	1e-4	 1e-4	    1e-4   1e-4	  1e-4	       1e-4	1e-4	 1e-4	  1e-4	 1e-4	  1e-4	   1e-4	   1e-4	   1e-4	    1e-4     1e-4
-    0	  1e-6	   1e-6	    1e-6       1e-6	1e-6	 1e-6	    1e-6   1e-6	  1e-6	       1e-6	1e-6	 1e-6	  1e-6	 1e-5	  1e-5	   1e-5	   1e-5	   1e-5	    1e-5     1e-5
+    0	  1e-6	   1e-6	    1e-6       1e-6	1e-6	 1e-6	    1e-6   1e-6	  1e-6	       1e-6	1e-6	 1e-6	  1e-6	 2e-5	  2e-5	   2e-5	   1e-5	   1e-5	    1e-5     1e-5
diff --git a/tests/tolerance_27_normal.dat b/tests/tolerance_27_normal.dat
index 0fe55e84a42e7541068744e1e554afff1731ed3f..713e6c20c39ae9be0a4069a17c1ce45728fb5a34 100644
--- a/tests/tolerance_27_normal.dat
+++ b/tests/tolerance_27_normal.dat
@@ -1,4 +1,4 @@
 #   ID      pos_x      pos_y      pos_z        v_x        v_y        v_z           rho        rho_dh        wcount     wcount_dh         div_v       curl_vx       curl_vy       curl_vz
-    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   2e-6	      4e-5	    4e-4       1e-2		 1e-5	     6e-6	   6e-6		 6e-6
-    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      1.2e-4	    1e-4       2e-4		 2e-4	     1e-4	   1e-4	 	 1e-4
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   2e-6	      6.2e-5	    4e-4       1.2e-2		 1e-5	     6e-6	   6e-6		 8e-6
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      2e-4	    1e-4       2e-4		 2e-4	     1e-4	   1e-4	 	 1e-4
     0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      1e-6	    1e-6       1e-6		 1e-6	     1e-6	   1e-6		 1e-6
diff --git a/tests/tolerance_27_perturbed.dat b/tests/tolerance_27_perturbed.dat
index e1fd7518e55811386967938dfff0d62f04325cb0..4b7534f4ba43e7117452af819937f2d2b0451352 100644
--- a/tests/tolerance_27_perturbed.dat
+++ b/tests/tolerance_27_perturbed.dat
@@ -1,4 +1,4 @@
 #   ID      pos_x      pos_y      pos_z        v_x        v_y        v_z           rho        rho_dh        wcount     wcount_dh         div_v       curl_vx       curl_vy       curl_vz
     0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   2e-6       1e-4	    2e-4       1e-2		 1e-5	     3e-6	   3e-6		 7e-6
-    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      1.3e-3	    1e-5       2e-3		 6e-5	     2e-3	   2e-3	 	 2e-3
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      1.3e-3	    1e-5       2e-3		 6e-5	     3e-3	   2e-3	 	 2e-3
     0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      2e-3	    1e-6       1e0		 1e-6	     2e-6	   2e-6		 2e-6
diff --git a/tests/tolerance_27_perturbed_h.dat b/tests/tolerance_27_perturbed_h.dat
index 5d6710c3946c0515f94c58eb3e0ecbfe14135b71..a1703f5b296d16f045fd28462fc9c61fc9358585 100644
--- a/tests/tolerance_27_perturbed_h.dat
+++ b/tests/tolerance_27_perturbed_h.dat
@@ -1,4 +1,4 @@
 #   ID      pos_x      pos_y      pos_z        v_x        v_y        v_z           rho        rho_dh        wcount     wcount_dh         div_v       curl_vx       curl_vy       curl_vz
-    0	      1e-6       1e-6	      1e-6 	       1e-6 	    1e-6	     1e-6	         3e-6       1e-4	        5e-4       1.4e-2		         1.1e-5	       3e-6	         3e-6		       8e-6
-    0	      1e-6       1e-6	      1e-6 	       1e-6 	    1e-6	     1e-6	         1.5e-6	      1.4e-2	      1e-5     2e-3		           2.5e-4	     3e-3	         3e-3	 	       3e-3
-    0	      1e-6       1e-6	      1e-6 	       1e-6 	    1e-6	     1e-6	         1e-6	      1e-6	        1e-6       1e0		           1e-6	       4e-6	         4e-6		       4e-6
+    0	      1e-6       1e-6	      1e-6       1e-6 	    1e-6     1e-6         3e-6        1e-4	     5e-4       1.4e-2	         1.1e-5	       3e-6	         3e-6		       8e-6
+    0	      1e-6       1e-6	      1e-6       1e-6 	    1e-6     1e-6         1.5e-6      1.4e-2	     1e-5       2e-3	         2.5e-4	       3e-3	         3e-3	 	       3e-3
+    0	      1e-6       1e-6	      1e-6       1e-6 	    1e-6     1e-6         1e-6	      1e-6	     1e-6       1e0	         1e-6	       4e-6	         4e-6		       4e-6
diff --git a/tests/tolerance_27_perturbed_h2.dat b/tests/tolerance_27_perturbed_h2.dat
index 882554741734aeb270427b62580d6077907056ad..0b3921f0294f03c199e2045364144756dc5b066e 100644
--- a/tests/tolerance_27_perturbed_h2.dat
+++ b/tests/tolerance_27_perturbed_h2.dat
@@ -1,4 +1,4 @@
-#   ID      pos_x      pos_y      pos_z        v_x        v_y        v_z           rho        rho_dh        wcount     wcount_dh         div_v       curl_vx       curl_vy       curl_vz
-    0	      1e-6       1e-6	      1e-6 	       1e-6 	    1e-6	     1e-6	         3e-6       1e-4	        5e-4       1.5e-2		         1.4e-5	       3e-6	         3e-6		       1e-5
-    0	      1e-6       1e-6	      1e-6 	       1e-6 	    1e-6	     1e-6	         1.5e-6	    2.5e-2	      1e-5       5.86e-3		       1.17e-3	     3e-3	         5.65e-3	 	       3e-3
-    0	      1e-6       1e-6	      1e-6 	       1e-6 	    1e-6	     1e-6	         1e-6	      1e-6	        1e-6       1e0		           1e-6	         4e-6	         4e-6		       4e-6
+#   ID        pos_x      pos_y      pos_z        v_x        v_y         v_z        rho        rho_dh    wcount     wcount_dh    div_v       curl_vx       curl_vy       curl_vz
+    0	      1e-6       1e-6	    1e-6 	 1e-6 	    1e-6	1e-6	   3e-6       1e-4      5e-4       1.5e-2	1.4e-5	     3e-6	   3e-6		 1e-5
+    0	      1e-6       1e-6	    1e-6 	 1e-6 	    1e-6	1e-6	 1.5e-6	    2.5e-2      1e-5       5.86e-3	1.17e-3	     3e-3	   8e-3	         3e-3
+    0	      1e-6       1e-6	    1e-6	 1e-6 	    1e-6	1e-6	   1e-6	      1e-6      1e-6       1e0		1e-6	     4e-6	   4e-6		 4e-6
diff --git a/tests/tolerance_pair_force_active.dat b/tests/tolerance_pair_force_active.dat
index c5b5620338b848f1b8f4658049e53a6424e93a60..f4394edf35e7287968673dfb949c726462b5d8ad 100644
--- a/tests/tolerance_pair_force_active.dat
+++ b/tests/tolerance_pair_force_active.dat
@@ -1,4 +1,4 @@
 #   ID  wcount   h_dt
     0	   1      2.4e-3
     0	   1      2.4e-3
-    0	   1      1e-5
+    0	   1      3e-5
diff --git a/tests/tolerance_periodic_BC_normal.dat b/tests/tolerance_periodic_BC_normal.dat
index 823e4af488b343f57e3c90e89ee2d4f13d3ca94b..fdbcd53a1f0233a87d657e5bc3751e685631a4c7 100644
--- a/tests/tolerance_periodic_BC_normal.dat
+++ b/tests/tolerance_periodic_BC_normal.dat
@@ -1,4 +1,4 @@
 #   ID      pos_x      pos_y      pos_z        v_x        v_y        v_z           rho        rho_dh        wcount     wcount_dh         div_v       curl_vx       curl_vy       curl_vz
-    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   4e-6	      4e-5	    1e-3       1e-2		 2e-4	     2e-4	   2e-4		 2e-4
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   4e-6	      7e-5	    1e-3       1.3e-2		 2e-4	     2e-4	   2e-4		 2e-4
     0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   2e-6	      2e-4	    1e-4       2e-4		 6e-4	     2e-3	   2e-3	 	 2e-3
     0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      1e-4	    1e-6       1e-4		 5e-4	     2e-4	   2e-4	 	 2e-4
diff --git a/theory/Multipoles/potential_derivatives.tex b/theory/Multipoles/potential_derivatives.tex
index 9dc9244ca56eaa56047f561aa221dd6a761e7a5a..c71cc849d5c5e0f7fbddb6b43e745838addd08cb 100644
--- a/theory/Multipoles/potential_derivatives.tex
+++ b/theory/Multipoles/potential_derivatives.tex
@@ -18,8 +18,10 @@ by constructing derivatives of the truncated potentials:
   \chi^{(4)}(r, r_s) &= \frac{16}{r_s^4} \left(48\alpha(x)^5 - 120\alpha(x)^4 + 100\alpha(x)^3 -30 \alpha(x)^2 + 2\alpha(x)\right) \nonumber \\ 
   \chi^{(5)}(r, r_s) &= \frac{32}{r_s^5} \left(240\alpha(x)^6 - 720\alpha(x)^5 + 780\alpha(x)^4 - 360\alpha(x)^3 + 62\alpha(x)^2 - 2\alpha(x) \right) \nonumber
 \end{align}
-We can now construct common quantities that appear in derivatives of
-multiple orders:
+In the Newtonian limit ($r_s\rightarrow\infty$) the first expression
+reduces to $\chi(r,r_s) = 1$ whilst all higher-order derivatives
+vanish. We can now construct common quantities that appear in
+derivatives of multiple orders:
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \begin{align}