diff --git a/AUTHORS b/AUTHORS
index c822300c22885a05b42d58a51cc86af9da410429..6f283405b69a7d3a5397916f0a3afa7f4fb54a4a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -10,3 +10,4 @@ Tom Theuns 		tom.theuns@durham.ac.uk
 Richard G. Bower	r.g.bower@durham.ac.uk
 Stefan Arridge		stefan.arridge@durham.ac.uk
 Massimiliano Culpo	massimiliano.culpo@googlemail.com
+Yves Revaz   		yves.revaz@epfl.ch
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 0658dd27e043b11c7480eaf8b01c0c40809e215c..2a5aeba7d1db0b1e1e56a9a6eed3059aba6a09ff 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -763,7 +763,8 @@ INPUT                  =  @top_srcdir@ @top_srcdir@/src @top_srcdir@/tests @top_
 INPUT		       += @top_srcdir@/src/hydro/Minimal
 INPUT		       += @top_srcdir@/src/gravity/Default
 INPUT		       += @top_srcdir@/src/riemann
-INPUT		       += @top_srcdir@/src/cooling/const_lambda
+INPUT		       += @top_srcdir@/src/potential/point_mass
+INPUT		       += @top_srcdir@/src/cooling/const_du
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/examples/Disk-Patch/GravityOnly/README b/examples/DiscPatch/GravityOnly/README
similarity index 100%
rename from examples/Disk-Patch/GravityOnly/README
rename to examples/DiscPatch/GravityOnly/README
diff --git a/examples/Disk-Patch/GravityOnly/disk-patch.yml b/examples/DiscPatch/GravityOnly/disc-patch.yml
similarity index 91%
rename from examples/Disk-Patch/GravityOnly/disk-patch.yml
rename to examples/DiscPatch/GravityOnly/disc-patch.yml
index 78b42e78356f83e80eee8e7f5f91ad7dcf90c37f..c76e4f612250d180f2ba2fccd0c6209878173433 100644
--- a/examples/Disk-Patch/GravityOnly/disk-patch.yml
+++ b/examples/DiscPatch/GravityOnly/disc-patch.yml
@@ -19,7 +19,7 @@ Statistics:
   
 # Parameters governing the snapshots
 Snapshots:
-  basename:            Disk-Patch # Common part of the name of output files
+  basename:            Disc-Patch # Common part of the name of output files
   time_first:          0.         # Time of the first output (in internal units)
   delta_time:          8.         # Time difference between consecutive outputs (in internal units)
 
@@ -33,11 +33,11 @@ SPH:
 
 # Parameters related to the initial conditions
 InitialConditions:
-  file_name:  Disk-Patch.hdf5       # The file to read
+  file_name:  Disc-Patch.hdf5       # The file to read
 
 # External potential parameters
-Disk-PatchPotential:
+DiscPatchPotential:
   surface_density: 10.
   scale_height:    100.
-  z_disk:          300.
+  z_disc:          300.
   timestep_mult:   0.03
diff --git a/examples/Disk-Patch/GravityOnly/makeIC.py b/examples/DiscPatch/GravityOnly/makeIC.py
similarity index 98%
rename from examples/Disk-Patch/GravityOnly/makeIC.py
rename to examples/DiscPatch/GravityOnly/makeIC.py
index 702a50ff53b73d004ff36be8049823515675cccf..42cd26e235deb17a899a65050ef5caa9c832c59c 100644
--- a/examples/Disk-Patch/GravityOnly/makeIC.py
+++ b/examples/DiscPatch/GravityOnly/makeIC.py
@@ -26,7 +26,7 @@ import random
 
 # Generates N particles in a box of [0:BoxSize,0:BoxSize,-2scale_height:2scale_height]
 # see Creasey, Theuns & Bower, 2013, for the equations:
-# disk parameters are: surface density sigma
+# disc parameters are: surface density sigma
 #                      scale height b
 # density: rho(z) = (sigma/2b) sech^2(z/b)
 # isothermal velocity dispersion = <v_z^2? = b pi G sigma
@@ -79,7 +79,7 @@ N       = int(sys.argv[1])  # Number of particles
 rho = 2.              # Density
 P = 1.                # Pressure
 gamma = 5./3.         # Gas adiabatic index
-fileName = "Disk-Patch.hdf5" 
+fileName = "Disc-Patch.hdf5" 
 
 
 #---------------------------------------------------
diff --git a/examples/DiscPatch/GravityOnly/run.sh b/examples/DiscPatch/GravityOnly/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9af1011ee653253f0d1b2cd26db0ac13cf11adc0
--- /dev/null
+++ b/examples/DiscPatch/GravityOnly/run.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# Generate the initial conditions if they are not present.
+if [ ! -e Disc-Patch.hdf5 ]
+then
+    echo "Generating initial conditions for the disc-patch example..."
+    python makeIC.py 1000
+fi
+
+../../swift -g -t 2 disc-patch.yml
diff --git a/examples/Disk-Patch/GravityOnly/test.pro b/examples/DiscPatch/GravityOnly/test.pro
similarity index 99%
rename from examples/Disk-Patch/GravityOnly/test.pro
rename to examples/DiscPatch/GravityOnly/test.pro
index 4bd0d001975d80b6729cf2ef7b95f81da5bc4fe8..04e0afdf7e6d2b4f0122a3d7d1bd1084539c405e 100644
--- a/examples/Disk-Patch/GravityOnly/test.pro
+++ b/examples/DiscPatch/GravityOnly/test.pro
@@ -8,7 +8,7 @@ iplot = 1 ; if iplot = 1, make plot of E/Lz conservation, else, simply compare f
 @physunits
 
 indir    = './'
-basefile = 'Disk-Patch_'
+basefile = 'Disc-Patch_'
 
 ; set properties of potential
 uL   = phys.pc                  ; unit of length
diff --git a/examples/Disk-Patch/HydroStatic/README b/examples/DiscPatch/HydroStatic/README
similarity index 58%
rename from examples/Disk-Patch/HydroStatic/README
rename to examples/DiscPatch/HydroStatic/README
index 56578731eb16a27febb3627524956b4e38b6428f..42853e6b51983f2868528202adec3fc829c2ddbc 100644
--- a/examples/Disk-Patch/HydroStatic/README
+++ b/examples/DiscPatch/HydroStatic/README
@@ -1,4 +1,4 @@
-Generates and evolves a disk-patch, where gas is in hydrostatic
+Generates and evolves a disc-patch, where gas is in hydrostatic
 equilibrium with an imposed external gravitational force, using the
 equations from Creasey, Theuns & Bower, 2013, MNRAS, Volume 429,
 Issue 3, p.1922-1948.
@@ -10,11 +10,11 @@ To generate ICs ready for a scientific run:
 2) Generate pre-ICs by running the 'makeIC.py' script.
 
 3) Run SWIFT with an isothermal EoS, no cooling nor feedback, and the
-disk-patch potential switched on and using the parameters from
-'disk-patch-icc.yml'
+disc-patch potential switched on and using the parameters from
+'disc-patch-icc.yml'
 
 4) The ICs are then ready to be run for a science problem. Rename the last 
-output to 'Disk-Patch-dynamic.hdf5'. These are now the ICs for the actual test.
+output to 'Disc-Patch-dynamic.hdf5'. These are now the ICs for the actual test.
 
-When running SWIFT with the parameters from 'disk-patch.yml' and an
-ideal gas EoS on these ICs the disk should stay in equilibrium.
+When running SWIFT with the parameters from 'disc-patch.yml' and an
+ideal gas EoS on these ICs the disc should stay in equilibrium.
diff --git a/examples/Disk-Patch/HydroStatic/disk-patch-icc.yml b/examples/DiscPatch/HydroStatic/disc-patch-icc.yml
similarity index 91%
rename from examples/Disk-Patch/HydroStatic/disk-patch-icc.yml
rename to examples/DiscPatch/HydroStatic/disc-patch-icc.yml
index ebf04675852a7663119ed1ecfd33a05da6b7bb15..6a27016b8a3f484b7c1c9b74594073d5f28efe90 100644
--- a/examples/Disk-Patch/HydroStatic/disk-patch-icc.yml
+++ b/examples/DiscPatch/HydroStatic/disc-patch-icc.yml
@@ -19,7 +19,7 @@ Statistics:
   
 # Parameters governing the snapshots
 Snapshots:
-  basename:            Disk-Patch   # Common part of the name of output files
+  basename:            Disc-Patch   # Common part of the name of output files
   time_first:          0.           # Time of the first output (in internal units)
   delta_time:          12.          # Time difference between consecutive outputs (in internal units)
 
@@ -33,12 +33,12 @@ SPH:
 
 # Parameters related to the initial conditions
 InitialConditions:
-  file_name:  Disk-Patch.hdf5       # The file to read
+  file_name:  Disc-Patch.hdf5       # The file to read
 
 # External potential parameters
-Disk-PatchPotential:
+DiscPatchPotential:
   surface_density: 10.
   scale_height:    100.
-  z_disk:          200.
+  z_disc:          200.
   timestep_mult:   0.03
   growth_time:     5.
diff --git a/examples/Disk-Patch/HydroStatic/disk-patch.yml b/examples/DiscPatch/HydroStatic/disc-patch.yml
similarity index 91%
rename from examples/Disk-Patch/HydroStatic/disk-patch.yml
rename to examples/DiscPatch/HydroStatic/disc-patch.yml
index 55df81a08d16c6a4f39aa5e9e9205101dedaa3a9..8bd67c5b08de82bb6a3d47ccf3419f85e3e5c6b1 100644
--- a/examples/Disk-Patch/HydroStatic/disk-patch.yml
+++ b/examples/DiscPatch/HydroStatic/disc-patch.yml
@@ -19,7 +19,7 @@ Statistics:
   
 # Parameters governing the snapshots
 Snapshots:
-  basename:           Disk-Patch-dynamic # Common part of the name of output files
+  basename:           Disc-Patch-dynamic # Common part of the name of output files
   time_first:         968.               # Time of the first output (in internal units)
   delta_time:         24.                 # Time difference between consecutive outputs (in internal units)
 
@@ -33,11 +33,11 @@ SPH:
 
 # Parameters related to the initial conditions
 InitialConditions:
-  file_name:  Disk-Patch-dynamic.hdf5       # The file to read
+  file_name:  Disc-Patch-dynamic.hdf5       # The file to read
 
 # External potential parameters
-Disk-PatchPotential:
+DiscPatchPotential:
   surface_density: 10.
   scale_height:    100.
-  z_disk:          200.
+  z_disc:          200.
   timestep_mult:   0.03
diff --git a/examples/Disk-Patch/HydroStatic/dynamic.pro b/examples/DiscPatch/HydroStatic/dynamic.pro
similarity index 100%
rename from examples/Disk-Patch/HydroStatic/dynamic.pro
rename to examples/DiscPatch/HydroStatic/dynamic.pro
diff --git a/examples/Disk-Patch/HydroStatic/getGlass.sh b/examples/DiscPatch/HydroStatic/getGlass.sh
similarity index 100%
rename from examples/Disk-Patch/HydroStatic/getGlass.sh
rename to examples/DiscPatch/HydroStatic/getGlass.sh
diff --git a/examples/Disk-Patch/HydroStatic/makeIC.py b/examples/DiscPatch/HydroStatic/makeIC.py
similarity index 98%
rename from examples/Disk-Patch/HydroStatic/makeIC.py
rename to examples/DiscPatch/HydroStatic/makeIC.py
index 40b1d1f1ff9e08dae0c4b0b1539ca773c93009b4..48cc578658a9520477d40bf504e3eb7c3c8e5164 100644
--- a/examples/Disk-Patch/HydroStatic/makeIC.py
+++ b/examples/DiscPatch/HydroStatic/makeIC.py
@@ -25,9 +25,9 @@ import math
 import random
 import matplotlib.pyplot as plt
 
-# Generates a disk-patch in hydrostatic equilibrium
+# Generates a disc-patch in hydrostatic equilibrium
 # see Creasey, Theuns & Bower, 2013, for the equations:
-# disk parameters are: surface density sigma
+# disc parameters are: surface density sigma
 #                      scale height b
 # density: rho(z) = (sigma/2b) sech^2(z/b)
 # isothermal velocity dispersion = <v_z^2? = b pi G sigma
@@ -79,7 +79,7 @@ Radius  = 100.         # maximum radius of particles [kpc]
 G       = const_G 
 
 # File
-fileName = "Disk-Patch.hdf5" 
+fileName = "Disc-Patch.hdf5" 
 
 #---------------------------------------------------
 mass           = 1
@@ -145,7 +145,7 @@ mass           = 0.*h + pmass
 entropy_flag   = 0
 vel            = 0 + 0 * pos
 
-# move centre of disk to middle of box
+# move centre of disc to middle of box
 pos[:,:]     += boxSize/2
 
 
diff --git a/examples/Disk-Patch/HydroStatic/test.pro b/examples/DiscPatch/HydroStatic/test.pro
similarity index 99%
rename from examples/Disk-Patch/HydroStatic/test.pro
rename to examples/DiscPatch/HydroStatic/test.pro
index 31e027e3a308b04f1c59222e1a339786857061ac..950aebc65d7d34cd7aaeb2368734e5492902a912 100644
--- a/examples/Disk-Patch/HydroStatic/test.pro
+++ b/examples/DiscPatch/HydroStatic/test.pro
@@ -8,7 +8,7 @@ iplot = 1 ; if iplot = 1, make plot of E/Lz conservation, else, simply compare f
 @physunits
 
 indir    = './'
-basefile = 'Disk-Patch_'
+basefile = 'Disc-Patch_'
 
 ; set properties of potential
 uL   = phys.pc                  ; unit of length
diff --git a/examples/Disk-Patch/GravityOnly/run.sh b/examples/Disk-Patch/GravityOnly/run.sh
deleted file mode 100755
index a123ad24d7ca34105c22f5f31e75c688c681288f..0000000000000000000000000000000000000000
--- a/examples/Disk-Patch/GravityOnly/run.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-# Generate the initial conditions if they are not present.
-if [ ! -e Isothermal.hdf5 ]
-then
-    echo "Generating initial conditions for the disk-patch example..."
-    python makeIC.py 1000
-fi
-
-../../swift -g -t 2 disk-patch.yml
diff --git a/examples/EAGLE_25/README b/examples/EAGLE_25/README
index 077fd9cf06ce64be98fa0d8a736125c474fb7a76..88fc1ea3eede1e254907dd5ba1dbf2eaa81fb694 100644
--- a/examples/EAGLE_25/README
+++ b/examples/EAGLE_25/README
@@ -13,4 +13,4 @@ The particle load of the main EAGLE simulation can be reproduced by
 running these ICs on 64 cores.
 
 MD5 checksum of the ICs: 
-ada2c728db2bd2d77a20c4eef52dfaf1  EAGLE_ICs_25.hdf5
+02cd1c353b86230af047b5d4ab22afcf  EAGLE_ICs_25.hdf5
diff --git a/examples/ExternalPointMass/externalPointMass.yml b/examples/ExternalPointMass/externalPointMass.yml
index d06c165651ce8f33692d1512ddd8fdae80ffb556..ce300b32157361e7860d201c186823471a179c0a 100644
--- a/examples/ExternalPointMass/externalPointMass.yml
+++ b/examples/ExternalPointMass/externalPointMass.yml
@@ -38,7 +38,7 @@ InitialConditions:
   shift_z:    50.
 
 # External potential parameters
-PointMass:
+PointMassPotential:
   position_x:      50.     # location of external point mass in internal units
   position_y:      50.
   position_z:      50.	
diff --git a/examples/MultiTypes/multiTypes.yml b/examples/MultiTypes/multiTypes.yml
index 28d02fefa8168e35af696975a7c73a1bf767155e..51a6d2b478681e2e1c61e199f758e35c507ec195 100644
--- a/examples/MultiTypes/multiTypes.yml
+++ b/examples/MultiTypes/multiTypes.yml
@@ -35,8 +35,9 @@ InitialConditions:
   file_name:  ./multiTypes.hdf5     # The file to read
 
 # External potential parameters
-PointMass:
+PointMassPotential:
   position_x:      50.     # location of external point mass in internal units
   position_y:      50.
   position_z:      50.	
   mass:            1e10     # mass of external point mass in internal units
+  timestep_mult:   1e-2
diff --git a/examples/SedovBlast_1D/sedov.yml b/examples/SedovBlast_1D/sedov.yml
index 6f519835d26ff5aa851ffb8999e650815c522cd3..1ecfeb32452d05f299b98124c4fdfc79126f7504 100644
--- a/examples/SedovBlast_1D/sedov.yml
+++ b/examples/SedovBlast_1D/sedov.yml
@@ -21,7 +21,7 @@ Snapshots:
 
 # Parameters governing the conserved quantities statistics
 Statistics:
-  delta_time:          1e-3 # Time between statistics output
+  delta_time:          1e-5 # Time between statistics output
 
 # Parameters for the hydrodynamics scheme
 SPH:
diff --git a/examples/UniformBox_3D/uniformBox.yml b/examples/UniformBox_3D/uniformBox.yml
index 7c9c74e1342bffb939131a265188cae269cc773f..8aaa802b64de46244f7066bce00f342cad8c5ef0 100644
--- a/examples/UniformBox_3D/uniformBox.yml
+++ b/examples/UniformBox_3D/uniformBox.yml
@@ -33,11 +33,3 @@ SPH:
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  ./uniformBox.hdf5     # The file to read
-
-
-  # External potential parameters
-PointMass:
-  position_x:      50.     # location of external point mass in internal units
-  position_y:      50.
-  position_z:      50.	
-  mass:            1e10     # mass of external point mass in internal units
diff --git a/examples/main.c b/examples/main.c
index 8591c0c70010075e62be73d29ac3644bc8b1f315..15d0fdb78fede79c24efc49f19082e25d58694ae 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -541,7 +541,7 @@ int main(int argc, char *argv[]) {
 
       /* Make sure output file is empty, only on one rank. */
       char dumpfile[30];
-      snprintf(dumpfile, 30, "thread_info_MPI-step%d.dat", j);
+      snprintf(dumpfile, 30, "thread_info_MPI-step%d.dat", j + 1);
       FILE *file_thread;
       if (myrank == 0) {
         file_thread = fopen(dumpfile, "w");
@@ -593,7 +593,7 @@ int main(int argc, char *argv[]) {
 
 #else
       char dumpfile[30];
-      snprintf(dumpfile, 30, "thread_info-step%d.dat", j);
+      snprintf(dumpfile, 30, "thread_info-step%d.dat", j + 1);
       FILE *file_thread;
       file_thread = fopen(dumpfile, "w");
       /* Add some information to help with the plots */
diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml
index 10bd09a18f7e8099e4db559e76957d19d8f90164..fb193a81baf410360172793763875891f654211a 100644
--- a/examples/parameter_example.yml
+++ b/examples/parameter_example.yml
@@ -12,6 +12,7 @@ Scheduler:
   cell_max_size:    8000000  # (Optional) Maximal number of interactions per task if we force the split (this is the default value).
   cell_sub_size:    64000000 # (Optional) Maximal number of interactions per sub-task  (this is the default value).
   cell_split_size:  400      # (Optional) Maximal number of particles per cell (this is the default value).
+  cell_max_count:   10000    # (Optional) Maximal number of particles per cell allowed before triggering a sanitizing (this is the default value).
 
 # Parameters governing the time integration
 TimeIntegration:
@@ -66,7 +67,7 @@ DomainDecomposition:
 # Parameters related to external potentials --------------------------------------------
   
 # Point mass external potentials
-PointMass:
+PointMassPotential:
   position_x:      50.      # location of external point mass (internal units)
   position_y:      50.
   position_z:      50.
@@ -82,12 +83,12 @@ IsothermalPotential:
   timestep_mult:   0.03     # Dimensionless pre-factor for the time-step condition
 
 # Disk-patch potential parameters
-Disk-PatchPotential:
-  surface_density: 10.      # Surface density of the disk (internal units)
-  scale_height:    100.     # Scale height of the disk (internal units)
-  z_disk:          200.     # Disk height (internal units)
+DiscPatchPotential:
+  surface_density: 10.      # Surface density of the disc (internal units)
+  scale_height:    100.     # Scale height of the disc (internal units)
+  z_disc:          200.     # Position of the disc along the z-axis (internal units)
   timestep_mult:   0.03     # Dimensionless pre-factor for the time-step condition
-  growth_time:     5.       # (Optional) Time for the disk to grow to its final size (multiple of the dynamical time)
+  growth_time:     5.       # (Optional) Time for the disc to grow to its final size (multiple of the dynamical time)
 
 # Parameters related to cooling function  ----------------------------------------------
 
diff --git a/examples/plot_scaling_results.py b/examples/plot_scaling_results.py
index 5a76e9870bd3ec55807c7b79c475c62b14119e5c..938d204bea8a9da81a93cf2d6d7334ac99d10e3a 100755
--- a/examples/plot_scaling_results.py
+++ b/examples/plot_scaling_results.py
@@ -131,8 +131,10 @@ def parse_files():
     file_list = [ file_list[j] for j in sorted_indices]
 
     parse_header(file_list[0])
+
+    branch[i] = branch[i].replace("_", "\\_") 
     
-    version.append(branch[i] + " " + revision[i] + "\n" + hydro_scheme[i] + 
+    version.append("$\\textrm{%s}$"%str(branch[i]) + " " + revision[i] + "\n" + hydro_scheme[i] + 
                    "\n" + hydro_kernel[i] + r", $N_{ngb}=%d$"%float(hydro_neighbours[i]) + 
                    r", $\eta=%.3f$"%float(hydro_eta[i]))
     times.append([])
@@ -215,14 +217,21 @@ def plot_results(times,totalTime,speedUp,parallelEff):
     pts = [1, 10**np.floor(np.log10(threadList[i][-1])+1)]
     totalTimePlot.loglog(pts,totalTime[i][0]/pts, 'k--', lw=1., color='0.2')
     totalTimePlot.loglog(threadList[i],totalTime[i],linestyle[i],label=version[i])
-  
+
+  y_min = 10**np.floor(np.log10(np.min(totalTime[:][-1])*0.6))
+  y_max = 1.2*10**np.floor(np.log10(np.max(totalTime[:][0]) * 1.5)+1)
   totalTimePlot.set_xscale('log')
   totalTimePlot.set_xlabel("${\\rm Threads}$", labelpad=0.)
   totalTimePlot.set_ylabel("${\\rm Time~to~solution}~[{\\rm ms}]$", labelpad=0.)
   totalTimePlot.set_xlim([0.9, 10**(np.floor(np.log10(threadList[i][-1]))+0.5)])
-  totalTimePlot.set_ylim([10**np.floor(np.log10(np.min(totalTime)*0.6)), 1.2*10**np.floor(np.log10(np.max(totalTime) * 1.5)+1)])
+  totalTimePlot.set_ylim(y_min, y_max)
+
+  ax2 = totalTimePlot.twinx()
+  ax2.set_yscale('log')
+  ax2.set_ylabel("${\\rm Time~to~solution}~[{\\rm hr}]$", labelpad=0.)
+  ax2.set_ylim(y_min / 3.6e6, y_max / 3.6e6)
   
-  totalTimePlot.legend(bbox_to_anchor=(1.14, 0.97), loc=2, borderaxespad=0.,prop={'size':12}, frameon=False)
+  totalTimePlot.legend(bbox_to_anchor=(1.21, 0.97), loc=2, borderaxespad=0.,prop={'size':12}, frameon=False)
   emptyPlot.axis('off')
   
   for i, txt in enumerate(threadList[0]):
diff --git a/examples/plot_tasks.py b/examples/plot_tasks.py
index fb8b2ce57a47b4d397284bba9960b098c1e3ce62..7b4683422725f206a3f582e00d82712c7e3c3f59 100755
--- a/examples/plot_tasks.py
+++ b/examples/plot_tasks.py
@@ -56,8 +56,9 @@ pl.rcParams.update(PLOT_PARAMS)
 
 #  Tasks and subtypes. Indexed as in tasks.h.
 TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init", "ghost",
-             "kick", "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft",
-             "grav_mm", "grav_up", "grav_external", "count"]
+             "extra_ghost", "kick", "kick_fixdt", "send", "recv",
+             "grav_gather_m", "grav_fft", "grav_mm", "grav_up",
+             "grav_external", "cooling", "count"]
 
 TASKCOLOURS = {"none": "black",
                "sort": "lightblue",
@@ -67,6 +68,7 @@ TASKCOLOURS = {"none": "black",
                "sub_pair": "navy",
                "init": "indigo",
                "ghost": "cyan",
+               "extra_ghost": "cyan",
                "kick": "green",
                "kick_fixdt": "green",
                "send": "yellow",
@@ -76,6 +78,7 @@ TASKCOLOURS = {"none": "black",
                "grav_mm": "mediumturquoise",
                "grav_up": "mediumvioletred",
                "grav_external": "darkred",
+               "cooling": "darkblue",
                "count": "powerblue"}
 
 SUBTYPES = ["none", "density", "gradient", "force", "grav", "tend", "count"]
@@ -118,7 +121,7 @@ toc_step = int(full_step[5])
 CPU_CLOCK = float(full_step[-1])
 data = data[1:,:]
 
-print "CPU frequency:", CPU_CLOCK / 1.e9
+print "CPU frequency:", CPU_CLOCK
 
 # Avoid start and end times of zero.
 data = data[data[:,4] != 0]
@@ -130,6 +133,7 @@ if delta_t == 0:
     dt = max(data[:,5]) - min(data[:,4])
     if dt > delta_t:
         delta_t = dt
+    print "Data range: ", delta_t / CPU_CLOCK * 1000, "ms"
 
 # Once more doing the real gather and plots this time.
 start_t = tic_step 
diff --git a/examples/plot_tasks_MPI.py b/examples/plot_tasks_MPI.py
index 398324cdc773d1dc4b7f26c58866c9df6469cc0b..02bc4a03510afce396429316fb4489926bc41b12 100755
--- a/examples/plot_tasks_MPI.py
+++ b/examples/plot_tasks_MPI.py
@@ -2,7 +2,7 @@
 """
 Usage:
     plot_tasks_MPI.py input.dat png-output-prefix [time-range-ms]
-   
+
 where input.dat is a thread info file for a step of an MPI run.  Use the '-y
 interval' flag of the swift MPI commands to create these. The output plots
 will be called 'png-output-prefix<mpi-rank>.png', i.e. one each for all the
@@ -40,6 +40,8 @@ matplotlib.use("Agg")
 import pylab as pl
 import numpy as np
 import sys
+#import warnings
+#warnings.simplefilter("error")
 
 #  Basic plot configuration.
 PLOT_PARAMS = {"axes.labelsize": 10,
@@ -61,9 +63,10 @@ PLOT_PARAMS = {"axes.labelsize": 10,
 pl.rcParams.update(PLOT_PARAMS)
 
 #  Tasks and subtypes. Indexed as in tasks.h.
-TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init", "ghost",
-             "kick", "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft",
-             "grav_mm", "grav_up", "grav_external", "count"]
+TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init",
+             "ghost", "extra_ghost", "kick", "kick_fixdt", "send", "recv",
+             "grav_gather_m", "grav_fft", "grav_mm", "grav_up",
+             "grav_external", "cooling", "count"]
 
 TASKCOLOURS = {"none": "black",
                "sort": "lightblue",
@@ -73,6 +76,7 @@ TASKCOLOURS = {"none": "black",
                "sub_pair": "navy",
                "init": "indigo",
                "ghost": "cyan",
+               "extra_ghost": "cyan",
                "kick": "green",
                "kick_fixdt": "green",
                "send": "yellow",
@@ -82,6 +86,7 @@ TASKCOLOURS = {"none": "black",
                "grav_mm": "mediumturquoise",
                "grav_up": "mediumvioletred",
                "grav_external": "darkred",
+               "cooling": "darkblue",
                "count": "powerblue"}
 
 SUBTYPES = ["none", "density", "gradient", "force", "grav", "tend", "count"]
@@ -111,7 +116,7 @@ outbase = sys.argv[2]
 delta_t = 0
 if len( sys.argv ) == 4:
     delta_t = int(sys.argv[3])
-    
+
 #  Read input.
 data = pl.loadtxt( infile )
 
@@ -121,7 +126,7 @@ tic_step = int(full_step[5])
 toc_step = int(full_step[6])
 CPU_CLOCK = float(full_step[-1])
 
-print "CPU frequency:", CPU_CLOCK / 1.e9
+print "CPU frequency:", CPU_CLOCK
 
 
 nranks = int(max(data[:,0])) + 1
@@ -143,6 +148,8 @@ if delta_t == 0:
         dt = max(data[:,6]) - min(data[:,5])
         if dt > delta_t:
             delta_t = dt
+    print "Data range: ", delta_t / CPU_CLOCK * 1000, "ms"
+
 
 # Once more doing the real gather and plots this time.
 for rank in range(nranks):
@@ -152,93 +159,107 @@ for rank in range(nranks):
     tic_step = int(full_step[5])
     toc_step = int(full_step[6])
     data = data[1:,:]
+    typesseen = []
 
-    start_t = tic_step
-    data[:,5] -= start_t
-    data[:,6] -= start_t
-    end_t = (toc_step - start_t) / CPU_CLOCK * 1000
-
-    tasks = {}
-    tasks[-1] = []
-    for i in range(nthread):
-        tasks[i] = []
-
-    num_lines = pl.shape(data)[0]
-    for line in range(num_lines):
-        thread = int(data[line,1])
-        tasks[thread].append({})
-        tasks[thread][-1]["type"] = TASKTYPES[int(data[line,2])]
-        tasks[thread][-1]["subtype"] = SUBTYPES[int(data[line,3])]
-        tic = int(data[line,5]) / CPU_CLOCK * 1000
-        toc = int(data[line,6]) / CPU_CLOCK * 1000
-        tasks[thread][-1]["tic"] = tic
-        tasks[thread][-1]["toc"] = toc
-        tasks[thread][-1]["t"] = (toc + tic)/ 2
-
-    combtasks = {}
-    combtasks[-1] = []
-    for i in range(nthread):
-        combtasks[i] = []
-
-    for thread in range(nthread):
-        tasks[thread] = sorted(tasks[thread], key=lambda l: l["t"])
-        lasttype = ""
-        types = []
-        for task in tasks[thread]:
-            if task["type"] not in types:
-                types.append(task["type"])
-            if lasttype == "" or not lasttype == task["type"]:
-                combtasks[thread].append({})
-                combtasks[thread][-1]["type"] = task["type"]
-                combtasks[thread][-1]["subtype"] = task["subtype"]
-                combtasks[thread][-1]["tic"] = task["tic"]
-                combtasks[thread][-1]["toc"] = task["toc"]
-                if task["type"] == "self" or task["type"] == "pair" or task["type"] == "sub":
-                    combtasks[thread][-1]["colour"] = SUBCOLOURS[task["subtype"]]
+    #  Dummy image for ranks that have no tasks.
+    if data.size == 0:
+        print "rank ", rank, " has no tasks"
+        fig = pl.figure()
+        ax = fig.add_subplot(1,1,1)
+        ax.set_xlim(-delta_t * 0.03 * 1000 / CPU_CLOCK, delta_t * 1.03 * 1000 / CPU_CLOCK)
+        ax.set_ylim(0, nthread)
+        start_t = tic_step
+        end_t = (toc_step - start_t) / CPU_CLOCK * 1000
+    else:
+
+        start_t = tic_step
+        data[:,5] -= start_t
+        data[:,6] -= start_t
+        end_t = (toc_step - start_t) / CPU_CLOCK * 1000
+
+        tasks = {}
+        tasks[-1] = []
+        for i in range(nthread):
+            tasks[i] = []
+
+        num_lines = pl.shape(data)[0]
+        for line in range(num_lines):
+            thread = int(data[line,1])
+            tasks[thread].append({})
+            tasks[thread][-1]["type"] = TASKTYPES[int(data[line,2])]
+            tasks[thread][-1]["subtype"] = SUBTYPES[int(data[line,3])]
+            tic = int(data[line,5]) / CPU_CLOCK * 1000
+            toc = int(data[line,6]) / CPU_CLOCK * 1000
+            tasks[thread][-1]["tic"] = tic
+            tasks[thread][-1]["toc"] = toc
+            tasks[thread][-1]["t"] = (toc + tic)/ 2
+
+        combtasks = {}
+        combtasks[-1] = []
+        for i in range(nthread):
+            combtasks[i] = []
+
+        for thread in range(nthread):
+            tasks[thread] = sorted(tasks[thread], key=lambda l: l["t"])
+            lasttype = ""
+            types = []
+            for task in tasks[thread]:
+                if task["type"] not in types:
+                    types.append(task["type"])
+                if lasttype == "" or not lasttype == task["type"]:
+                    combtasks[thread].append({})
+                    combtasks[thread][-1]["type"] = task["type"]
+                    combtasks[thread][-1]["subtype"] = task["subtype"]
+                    combtasks[thread][-1]["tic"] = task["tic"]
+                    combtasks[thread][-1]["toc"] = task["toc"]
+                    if task["type"] == "self" or task["type"] == "pair" or task["type"] == "sub":
+                        combtasks[thread][-1]["colour"] = SUBCOLOURS[task["subtype"]]
+                    else:
+                        combtasks[thread][-1]["colour"] = TASKCOLOURS[task["type"]]
+                    lasttype = task["type"]
                 else:
-                    combtasks[thread][-1]["colour"] = TASKCOLOURS[task["type"]]
-                lasttype = task["type"]
-            else:
-                combtasks[thread][-1]["toc"] = task["toc"]
+                    combtasks[thread][-1]["toc"] = task["toc"]
+
+        fig = pl.figure()
+        ax = fig.add_subplot(1,1,1)
+        ax.set_xlim(-delta_t * 0.03 * 1000 / CPU_CLOCK, delta_t * 1.03 * 1000 / CPU_CLOCK)
+        ax.set_ylim(0, nthread)
+        tictoc = np.zeros(2)
+        for i in range(nthread):
+
+            #  Collect ranges and colours into arrays.
+            tictocs = np.zeros(len(combtasks[i])*2)
+            colours = np.empty(len(combtasks[i])*2, dtype='object')
+            coloursseen = []
+            j = 0
+            for task in combtasks[i]:
+                tictocs[j] = task["tic"]
+                tictocs[j+1] = task["toc"]
+                colours[j] = task["colour"]
+                colours[j+1] = task["colour"]
+                j = j + 2
+                if task["colour"] not in coloursseen:
+                    coloursseen.append(task["colour"])
+
+                #  Legend support, collections don't add to this.
+                if task["subtype"] != "none":
+                    qtask = task["type"] + "/" + task["subtype"]
+                else:
+                    qtask = task["type"]
 
-    typesseen = []
-    fig = pl.figure()
-    ax = fig.add_subplot(1,1,1)
-    ax.set_xlim(-delta_t * 0.03 * 1000 / CPU_CLOCK, delta_t * 1.03 * 1000 / CPU_CLOCK)
-    ax.set_ylim(0, nthread)
-    tictoc = np.zeros(2)
-    for i in range(nthread):
-
-        #  Collect ranges and colours into arrays.
-        tictocs = np.zeros(len(combtasks[i])*2)
-        colours = np.empty(len(combtasks[i])*2, dtype='object')
-        coloursseen = []
-        j = 0
-        for task in combtasks[i]:
-            tictocs[j] = task["tic"]
-            tictocs[j+1] = task["toc"]
-            colours[j] = task["colour"]
-            colours[j+1] = task["colour"]
-            j = j + 2
-            if task["colour"] not in coloursseen:
-                coloursseen.append(task["colour"])
-
-            #  Legend support, collections don't add to this.
-            if task["subtype"] != "none":
-                qtask = task["type"] + "/" + task["subtype"]
-            else:
-                qtask = task["type"]
-            if qtask not in typesseen:
-                pl.plot([], [], color=task["colour"], label=qtask)
-                typesseen.append(qtask)
-
-        #  Now plot each colour, faster to use a mask to select colour ranges.
-        for colour in coloursseen:
-            collection = collections.BrokenBarHCollection.span_where(tictocs, ymin=i+0.05, ymax=i+0.95,
-                                                                     where=colours == colour,
-                                                                     facecolor=colour,
-                                                                     linewidths=0)
-            ax.add_collection(collection)
+                if qtask not in typesseen:
+                    pl.plot([], [], color=task["colour"], label=qtask)
+                    typesseen.append(qtask)
+
+            #  Now plot each colour, faster to use a mask to select colour ranges.
+            for colour in coloursseen:
+                collection = collections.BrokenBarHCollection.span_where(tictocs,
+                                                                         ymin=i+0.05,
+                                                                         ymax=i+0.95,
+                                                                         where=colours == colour,
+                                                                         facecolor=colour,
+                                                                         linewidths=0)
+                ax.add_collection(collection)
 
 
     #  Legend and room for it.
@@ -247,7 +268,8 @@ for rank in range(nranks):
         nrow = nrow + 1
     ax.fill_between([0, 0], nthread+0.5, nthread + nrow + 0.5, facecolor="white")
     ax.set_ylim(0, nthread + nrow + 1)
-    ax.legend(loc=1, shadow=True, mode="expand", ncol=5)
+    if data.size > 0:
+        ax.legend(loc=1, shadow=True, mode="expand", ncol=5)
 
     # Start and end of time-step
     ax.plot([0, 0], [0, nthread + nrow + 1], 'k--', linewidth=1)
diff --git a/src/Makefile.am b/src/Makefile.am
index 97db6eca672974a62561388cda3a80ba659475b6..fb606d7bd36cc9593958cb385caef3318960967e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,19 +42,20 @@ endif
 include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \
     engine.h swift.h serial_io.h timers.h debug.h scheduler.h proxy.h parallel_io.h \
     common_io.h single_io.h multipole.h map.h tools.h partition.h clocks.h parser.h \
-    physical_constants.h physical_constants_cgs.h potentials.h version.h \
-    hydro_properties.h threadpool.h cooling.h sourceterms.h
+    physical_constants.h physical_constants_cgs.h potential.h version.h \
+    hydro_properties.h riemann.h threadpool.h cooling.h cooling_struct.h sourceterms.h
+
 
 # Common source files
 AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \
     serial_io.c timers.c debug.c scheduler.c proxy.c parallel_io.c \
     units.c common_io.c single_io.c multipole.c version.c map.c \
     kernel_hydro.c tools.c part.c partition.c clocks.c parser.c \
-    physical_constants.c potentials.c hydro_properties.c \
-    runner_doiact_fft.c threadpool.c cooling.c sourceterms.c 
+    physical_constants.c potential.c hydro_properties.c \
+    runner_doiact_fft.c threadpool.c cooling.c sourceterms.c
 
 # Include files for distribution, not installation.
-nobase_noinst_HEADERS = approx_math.h atomic.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \
+nobase_noinst_HEADERS = align.h approx_math.h atomic.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \
 		 kernel_long_gravity.h vector.h runner_doiact.h runner_doiact_grav.h runner_doiact_fft.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 \
@@ -69,11 +70,17 @@ nobase_noinst_HEADERS = approx_math.h atomic.h cycle.h error.h inline.h kernel_h
                  hydro/Default/hydro_debug.h hydro/Default/hydro_part.h \
 		 hydro/Gadget2/hydro.h hydro/Gadget2/hydro_iact.h hydro/Gadget2/hydro_io.h \
                  hydro/Gadget2/hydro_debug.h hydro/Gadget2/hydro_part.h \
+		 hydro/PressureEntropy/hydro.h hydro/PressureEntropy/hydro_iact.h hydro/PressureEntropy/hydro_io.h \
+                 hydro/PressureEntropy/hydro_debug.h hydro/PressureEntropy/hydro_part.h \
 		 hydro/Gizmo/hydro.h hydro/Gizmo/hydro_iact.h hydro/Gizmo/hydro_io.h \
                  hydro/Gizmo/hydro_debug.h hydro/Gizmo/hydro_part.h \
-	         riemann.h riemann/riemann_hllc.h riemann/riemann_trrs.h \
+	         riemann/riemann_hllc.h riemann/riemann_trrs.h \
 		 riemann/riemann_exact.h riemann/riemann_vacuum.h \
-	         cooling/const_du/cooling.h cooling/const_lambda/cooling.h
+	         potential/none/potential.h potential/point_mass/potential.h \
+                 potential/isothermal/potential.h potential/disc_patch/potential.h \
+		 cooling/none/cooling.h cooling/none/cooling_struct.h \
+	         cooling/const_du/cooling.h cooling/const_du/cooling_struct.h \
+                 cooling/const_lambda/cooling.h cooling/const_lambda/cooling_struct.h 
 
 
 # Sources and flags for regular library
diff --git a/src/adiabatic_index.h b/src/adiabatic_index.h
index a0c9ce09e3e004af07e8b208ef9f1af5f46c9e81..59937db3c8d09fc7e6e969de0aee60f01a2e5a2c 100644
--- a/src/adiabatic_index.h
+++ b/src/adiabatic_index.h
@@ -410,7 +410,7 @@ __attribute__((always_inline)) INLINE static float pow_one_over_gamma(float x) {
 
 #if defined(HYDRO_GAMMA_5_3)
 
-  return powf(x, 0.6f); /* x^(3/5) */
+  return powf(x, hydro_one_over_gamma); /* x^(3/5) */
 
 #elif defined(HYDRO_GAMMA_7_5)
 
@@ -418,7 +418,7 @@ __attribute__((always_inline)) INLINE static float pow_one_over_gamma(float x) {
 
 #elif defined(HYDRO_GAMMA_4_3)
 
-  return powf(x, 0.75f); /* x^(3/4) */
+  return powf(x, hydro_one_over_gamma); /* x^(3/4) */
 
 #elif defined(HYDRO_GAMMA_2_1)
 
diff --git a/src/align.h b/src/align.h
new file mode 100644
index 0000000000000000000000000000000000000000..84e2909c0866c18f0f8378df9d0efc8d0f6545b5
--- /dev/null
+++ b/src/align.h
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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_ALIGN_H
+#define SWIFT_ALIGN_H
+
+/**
+ * @brief Defines alignment of structures
+ */
+#define SWIFT_STRUCT_ALIGN __attribute__((aligned(32)))
+
+#endif /* SWIFT_ALIGN_H */
diff --git a/src/cell.c b/src/cell.c
index 7ce6fb81a8fa6875884d3f5c840c36e5177cdf6b..8728f32cb04f2f1de389386b632371a27d523bb9 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -679,6 +679,59 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset) {
     part_relink_parts(gparts, gcount, parts - parts_offset);
 }
 
+/**
+ * @brief Sanitizes the smoothing length values of cells by setting large
+ * outliers to more sensible values.
+ *
+ * We compute the mean and standard deviation of the smoothing lengths in
+ * logarithmic space and limit values to mean + 4 sigma.
+ *
+ * @param c The cell.
+ */
+void cell_sanitize(struct cell *c) {
+
+  const int count = c->count;
+  struct part *parts = c->parts;
+
+  /* First collect some statistics */
+  float h_mean = 0.f, h_mean2 = 0.f;
+  float h_min = FLT_MAX, h_max = 0.f;
+  for (int i = 0; i < count; ++i) {
+
+    const float h = logf(parts[i].h);
+    h_mean += h;
+    h_mean2 += h * h;
+    h_max = max(h_max, h);
+    h_min = min(h_min, h);
+  }
+  h_mean /= count;
+  h_mean2 /= count;
+  const float h_var = h_mean2 - h_mean * h_mean;
+  const float h_std = (h_var > 0.f) ? sqrtf(h_var) : 0.1f * h_mean;
+
+  /* Choose a cut */
+  const float h_limit = expf(h_mean + 4.f * h_std);
+
+  /* Be verbose this is not innocuous */
+  message("Cell properties: h_min= %f h_max= %f geometric mean= %f.",
+          expf(h_min), expf(h_max), expf(h_mean));
+
+  if (c->h_max > h_limit) {
+
+    message("Smoothing lengths will be limited to (mean + 4sigma)= %f.",
+            h_limit);
+
+    /* Apply the cut */
+    for (int i = 0; i < count; ++i) parts->h = min(parts[i].h, h_limit);
+
+    c->h_max = h_limit;
+
+  } else {
+
+    message("Smoothing lengths will not be limited.");
+  }
+}
+
 /**
  * @brief Converts hydro quantities to a valid state after the initial density
  * calculation
diff --git a/src/cell.h b/src/cell.h
index b1abd0e2134687c123ba0a2e7b397df5572349ff..f87420c86c5765f42fe04e8dee95558edff90cf9 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -30,6 +30,7 @@
 #include <stddef.h>
 
 /* Local includes. */
+#include "align.h"
 #include "lock.h"
 #include "multipole.h"
 #include "part.h"
@@ -44,7 +45,7 @@ struct space;
  * The maximum was lowered by a further factor of 2 to be on the safe side.*/
 #define cell_max_tag (1 << 29)
 
-#define cell_align 32
+#define cell_align 128
 
 /* Global variables. */
 extern int cell_next_tag;
@@ -74,7 +75,8 @@ struct pcell {
 
   /* Relative indices of the cell's progeny. */
   int progeny[8];
-};
+
+} SWIFT_STRUCT_ALIGN;
 
 /* Structure to store the data of a single cell. */
 struct cell {
@@ -185,7 +187,7 @@ struct cell {
   double mom[3], ang_mom[3];
 
   /* Mass, potential, internal  and kinetic energy of particles in this cell. */
-  double mass, e_pot, e_int, e_kin, entropy;
+  double mass, e_pot, e_int, e_kin, e_rad, entropy;
 
   /* Number of particles updated in this cell. */
   int updated, g_updated;
@@ -211,7 +213,7 @@ struct cell {
 
 #endif
 
-} __attribute__((aligned(cell_align)));
+} SWIFT_STRUCT_ALIGN;
 
 /* Convert cell location to ID. */
 #define cell_getid(cdim, i, j, k) \
@@ -219,6 +221,7 @@ struct cell {
 
 /* Function prototypes. */
 void cell_split(struct cell *c, ptrdiff_t parts_offset);
+void cell_sanitize(struct cell *c);
 int cell_locktree(struct cell *c);
 void cell_unlocktree(struct cell *c);
 int cell_glocktree(struct cell *c);
diff --git a/src/const.h b/src/const.h
index 817c645ba2354614caa6d70bf42d54bca41a284f..bffdaa7f773a160178017f9ba8a77c796028bf55 100644
--- a/src/const.h
+++ b/src/const.h
@@ -65,6 +65,7 @@
 /* SPH variant to use */
 //#define MINIMAL_SPH
 #define GADGET2_SPH
+//#define HOPKINS_PE_SPH
 //#define DEFAULT_SPH
 //#define GIZMO_SPH
 
@@ -90,16 +91,18 @@
 #define const_gravity_eta 0.025f
 
 /* External gravity properties */
-#define EXTERNAL_POTENTIAL_POINTMASS
+#define EXTERNAL_POTENTIAL_NONE
+//#define EXTERNAL_POTENTIAL_POINTMASS
 //#define EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
-//#define EXTERNAL_POTENTIAL_DISK_PATCH
+//#define EXTERNAL_POTENTIAL_DISC_PATCH
 
 /* Source terms */
 #define SN_FEEDBACK
 
 /* Cooling properties */
+#define COOLING_NONE
 //#define COOLING_CONST_DU
-#define COOLING_CONST_LAMBDA
+//#define COOLING_CONST_LAMBDA
 //#define COOLING_GRACKLE
 
 /* Are we debugging ? */
diff --git a/src/cooling.c b/src/cooling.c
index 102adba9d521dbe53caeff3c4409292bb64a29b2..e0208dbb591445d0877ef1e703d6e8cf349ddfd6 100644
--- a/src/cooling.c
+++ b/src/cooling.c
@@ -36,7 +36,7 @@
 void cooling_init(const struct swift_params* parameter_file,
                   const struct UnitSystem* us,
                   const struct phys_const* phys_const,
-                  struct cooling_data* cooling) {
+                  struct cooling_function_data* cooling) {
 
   cooling_init_backend(parameter_file, us, phys_const, cooling);
 }
@@ -48,7 +48,7 @@ void cooling_init(const struct swift_params* parameter_file,
  *
  * @param cooling The properties of the cooling function.
  */
-void cooling_print(const struct cooling_data* cooling) {
+void cooling_print(const struct cooling_function_data* cooling) {
 
   cooling_print_backend(cooling);
 }
diff --git a/src/cooling.h b/src/cooling.h
index 034ee2329d91b17b875932bc4eb40d0d80a05111..1b326f6dc4fdf796dd1587e73e9b591f0f500ccb 100644
--- a/src/cooling.h
+++ b/src/cooling.h
@@ -31,7 +31,9 @@
 #include "const.h"
 
 /* Import the right cooling definition */
-#if defined(COOLING_CONST_DU)
+#if defined(COOLING_NONE)
+#include "./cooling/none/cooling.h"
+#elif defined(COOLING_CONST_DU)
 #include "./cooling/const_du/cooling.h"
 #elif defined(COOLING_CONST_LAMBDA)
 #include "./cooling/const_lambda/cooling.h"
@@ -45,8 +47,8 @@
 void cooling_init(const struct swift_params* parameter_file,
                   const struct UnitSystem* us,
                   const struct phys_const* phys_const,
-                  struct cooling_data* cooling);
+                  struct cooling_function_data* cooling);
 
-void cooling_print(const struct cooling_data* cooling);
+void cooling_print(const struct cooling_function_data* cooling);
 
 #endif /* SWIFT_COOLING_H */
diff --git a/src/cooling/const_du/cooling.h b/src/cooling/const_du/cooling.h
index 634723f5a5a9af56aefc5fee1d409f583b243eba..b25980ff2269ca9ea176edcc2a3c771647819133 100644
--- a/src/cooling/const_du/cooling.h
+++ b/src/cooling/const_du/cooling.h
@@ -22,11 +22,12 @@
 #define SWIFT_COOLING_CONST_DU_H
 
 /**
- * @file src/cooling/const/cooling.h
+ * @file src/cooling/const_du/cooling.h
  * @brief Routines related to the "constant cooling" cooling function.
  *
  * This is the simplest possible cooling function. A constant cooling rate with
- * a minimal energy floor is applied.
+ * a minimal energy floor is applied. Should be used as a template for more
+ * realistic functions.
  */
 
 /* Some standard headers. */
@@ -34,6 +35,7 @@
 
 /* Local includes. */
 #include "const.h"
+#include "cooling_struct.h"
 #include "error.h"
 #include "hydro.h"
 #include "parser.h"
@@ -41,33 +43,24 @@
 #include "physical_constants.h"
 #include "units.h"
 
-/**
- * @brief Properties of the cooling function.
- */
-struct cooling_data {
-
-  /*! Cooling rate in internal units. du_dt = -cooling_rate */
-  float cooling_rate;
-
-  /*! Minimally allowed internal energy of the particles */
-  float min_energy;
-
-  /*! Constant multiplication factor for time-step criterion */
-  float cooling_tstep_mult;
-};
-
 /**
  * @brief Apply the cooling function to a particle.
  *
+ * In this simple example we just apply the const cooling rate
+ * and check that we don't go below the given floor.
+ *
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
- * @param cooling The #cooling_data used in the run.
+ * @param cooling The #cooling_function_data used in the run.
  * @param p Pointer to the particle data.
+ * @param xp Pointer to the extended particle data.
  * @param dt The time-step of this particle.
  */
 __attribute__((always_inline)) INLINE static void cooling_cool_part(
-    const struct phys_const* const phys_const, const struct UnitSystem* us,
-    const struct cooling_data* cooling, struct part* p, float dt) {
+    const struct phys_const* restrict phys_const,
+    const struct UnitSystem* restrict us,
+    const struct cooling_function_data* restrict cooling,
+    struct part* restrict p, struct xpart* restrict xp, float dt) {
 
   /* Get current internal energy (dt=0) */
   const float u_old = hydro_get_internal_energy(p, 0.f);
@@ -86,27 +79,69 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
 
   /* Update the internal energy */
   hydro_set_internal_energy(p, u_new);
+
+  /* Store the radiated energy */
+  xp->cooling_data.radiated_energy += hydro_get_mass(p) * (u_old - u_new);
 }
 
 /**
  * @brief Computes the cooling time-step.
  *
- * @param cooling The #cooling_data used in the run.
+ * In this simple example, we return \f$ \alpha \frac{u}{du/dt} \f$.
+ * This is used to compute the time-step of the particle. Cooling functions
+ * that are solved implicitly can simply return FLT_MAX here.
+ *
+ * @param cooling The #cooling_function_data used in the run.
  * @param phys_const The physical constants in internal units.
+ * @param us The internal system of units.
  * @param p Pointer to the particle data.
  */
-__attribute__((always_inline)) INLINE static double cooling_timestep(
-    const struct cooling_data* cooling,
-    const struct phys_const* const phys_const, const struct part* const p) {
+__attribute__((always_inline)) INLINE static float cooling_timestep(
+    const struct cooling_function_data* restrict cooling,
+    const struct phys_const* restrict phys_const,
+    const struct UnitSystem* restrict us, const struct part* restrict p) {
 
   const float cooling_rate = cooling->cooling_rate;
-  const float internal_energy =
-      hydro_get_internal_energy(p, 0);  // dt = 0 because using current entropy
+  const float internal_energy = hydro_get_internal_energy(p, 0);
   return cooling->cooling_tstep_mult * internal_energy / cooling_rate;
 }
 
 /**
- * @brief Initialises the cooling properties.
+ * @brief Sets the cooling properties of the (x-)particles to a valid start
+ * state.
+ *
+ * In this case, we set the total radiated energy to 0. Note that the particle
+ * structure is just passed in for cases where information needs to be read
+ * from there.
+ *
+ * @param p Pointer to the particle data.
+ * @param xp Pointer to the extended particle data.
+ */
+__attribute__((always_inline)) INLINE static void cooling_init_part(
+    const struct part* restrict p, struct xpart* restrict xp) {
+
+  xp->cooling_data.radiated_energy = 0.f;
+}
+
+/**
+ * @brief Returns the total radiated energy by this particle.
+ *
+ * In this simple example we jsut return the quantity accumulated in the
+ * #cooling_xpart_data of this particle.
+ *
+ * @param xp The extended particle data
+ */
+__attribute__((always_inline)) INLINE static float cooling_get_radiated_energy(
+    const struct xpart* restrict xp) {
+
+  return xp->cooling_data.radiated_energy;
+}
+
+/**
+ * @brief Initialises the cooling function properties from the parameter file
+ *
+ * In this example, we just read in the values from the YAML file without
+ * doing any conversions or multiplying any constants in.
  *
  * @param parameter_file The parsed parameter file.
  * @param us The current internal system of units.
@@ -115,7 +150,8 @@ __attribute__((always_inline)) INLINE static double cooling_timestep(
  */
 static INLINE void cooling_init_backend(
     const struct swift_params* parameter_file, const struct UnitSystem* us,
-    const struct phys_const* phys_const, struct cooling_data* cooling) {
+    const struct phys_const* phys_const,
+    struct cooling_function_data* cooling) {
 
   cooling->cooling_rate =
       parser_get_param_double(parameter_file, "ConstCooling:cooling_rate");
@@ -130,9 +166,10 @@ static INLINE void cooling_init_backend(
  *
  * @param cooling The properties of the cooling function.
  */
-static INLINE void cooling_print_backend(const struct cooling_data* cooling) {
+static INLINE void cooling_print_backend(
+    const struct cooling_function_data* cooling) {
 
-  message("Cooling function is 'Constant cooling' with rate %f and floor %f",
+  message("Cooling function is 'Constant cooling' with rate %f and floor %f.",
           cooling->cooling_rate, cooling->min_energy);
 }
 
diff --git a/src/cooling/const_du/cooling_struct.h b/src/cooling/const_du/cooling_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc00b001cf6b576266de02dac885f87d089bd8e4
--- /dev/null
+++ b/src/cooling/const_du/cooling_struct.h
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ *                    Richard Bower (r.g.bower@durham.ac.uk)
+ *                    Stefan Arridge  (stefan.arridge@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_COOLING_STRUCT_CONST_DU_H
+#define SWIFT_COOLING_STRUCT_CONST_DU_H
+
+/**
+ * @file src/cooling/const_du/cooling_struct.h
+ * @brief Structure related to the "constant cooling" cooling function.
+ *
+ * This is the simplest possible cooling function. A constant cooling rate with
+ * a minimal energy floor is applied. Should be used as a template for more
+ * realistic functions.
+ */
+
+/**
+ * @brief Properties of the cooling function.
+ */
+struct cooling_function_data {
+
+  /*! Cooling rate in internal units. du_dt = -cooling_rate */
+  float cooling_rate;
+
+  /*! Minimally allowed internal energy of the particles */
+  float min_energy;
+
+  /*! Constant multiplication factor for time-step criterion */
+  float cooling_tstep_mult;
+};
+
+/**
+ * @brief Properties of the cooling stored in the particle data.
+ *
+ * This is used to carry properties such as the total amount of
+ * energy radiated away.
+ */
+struct cooling_xpart_data {
+
+  /*! Energy radiated away by this particle since the start of the run */
+  float radiated_energy;
+};
+
+#endif /* SWIFT_COOLING_STRUCT_CONST_DU_H */
diff --git a/src/cooling/const_lambda/cooling.h b/src/cooling/const_lambda/cooling.h
index 3fd583b55a31534996e23e4dce71bcae9394d7de..11cf2cae51f1ab2646d1391d2164c399c77a7bba 100644
--- a/src/cooling/const_lambda/cooling.h
+++ b/src/cooling/const_lambda/cooling.h
@@ -35,40 +35,17 @@
 #include "physical_constants.h"
 #include "units.h"
 
-/* Cooling Properties */
-struct cooling_data {
-
-  /*! Cooling rate in cgs units. Defined by 'rho * du/dt = -lambda * n_H^2'*/
-  float lambda;
-
-  /*! Minimum temperature (in Kelvin) for all gas particles*/
-  float min_temperature;
-
-  /*! Fraction of gas mass that is Hydrogen. Used to calculate n_H*/
-  float hydrogen_mass_abundance;
-
-  /* 'mu', used to convert min_temperature to min_internal energy*/
-  float mean_molecular_weight;
-
-  /*! Minimally allowed internal energy of the particles */
-  float min_energy;
-  float min_energy_cgs;
-
-  /*! Constant multiplication factor for time-step criterion */
-  float cooling_tstep_mult;
-};
-
 /**
  * @brief Calculates du/dt in code units for a particle.
  *
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
- * @param cooling The #cooling_data used in the run.
+ * @param cooling The #cooling_function_data used in the run.
  * @param p Pointer to the particle data..
  */
 __attribute__((always_inline)) INLINE static float cooling_rate(
     const struct phys_const* const phys_const, const struct UnitSystem* us,
-    const struct cooling_data* cooling, const struct part* p) {
+    const struct cooling_function_data* cooling, const struct part* p) {
 
   /* Get particle properties */
   /* Density */
@@ -101,13 +78,15 @@ __attribute__((always_inline)) INLINE static float cooling_rate(
  *
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
- * @param cooling The #cooling_data used in the run.
+ * @param cooling The #cooling_function_data used in the run.
  * @param p Pointer to the particle data.
  * @param dt The time-step of this particle.
  */
 __attribute__((always_inline)) INLINE static void cooling_cool_part(
-    const struct phys_const* const phys_const, const struct UnitSystem* us,
-    const struct cooling_data* cooling, struct part* p, float dt) {
+    const struct phys_const* restrict phys_const,
+    const struct UnitSystem* restrict us,
+    const struct cooling_function_data* restrict cooling,
+    struct part* restrict p, struct xpart* restrict xp, float dt) {
 
   /* Get current internal energy (dt=0) */
   const float u_old = hydro_get_internal_energy(p, 0.f);
@@ -135,20 +114,23 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
    * " */
   /*       "%g, du_dt*dt = %g, u_old + du_dt*dt = %g, u_new = %g\n", */
   /*       u_old, du_dt, dt, du_dt * dt, u_new, u_new_test); */
+
+  /* Store the radiated energy */
+  xp->cooling_data.radiated_energy += hydro_get_mass(p) * (u_old - u_new);
 }
 
 /**
  * @brief Computes the time-step due to cooling
  *
- * @param cooling The #cooling_data used in the run.
+ * @param cooling The #cooling_function_data used in the run.
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
  * @param p Pointer to the particle data.
  */
 __attribute__((always_inline)) INLINE static float cooling_timestep(
-    const struct cooling_data* cooling,
-    const struct phys_const* const phys_const, const struct UnitSystem* us,
-    const struct part* const p) {
+    const struct cooling_function_data* restrict cooling,
+    const struct phys_const* restrict phys_const,
+    const struct UnitSystem* restrict us, const struct part* restrict p) {
 
   /* Get du_dt */
   const float du_dt = cooling_rate(phys_const, us, cooling, p);
@@ -159,6 +141,30 @@ __attribute__((always_inline)) INLINE static float cooling_timestep(
   return u / du_dt;
 }
 
+/**
+ * @brief Sets the cooling properties of the (x-)particles to a valid start
+ * state.
+ *
+ * @param p Pointer to the particle data.
+ * @param xp Pointer to the extended particle data.
+ */
+__attribute__((always_inline)) INLINE static void cooling_init_part(
+    const struct part* restrict p, struct xpart* restrict xp) {
+
+  xp->cooling_data.radiated_energy = 0.f;
+}
+
+/**
+ * @brief Returns the total radiated energy by this particle.
+ *
+ * @param xp The extended particle data
+ */
+__attribute__((always_inline)) INLINE static float cooling_get_radiated_energy(
+    const struct xpart* restrict xp) {
+
+  return xp->cooling_data.radiated_energy;
+}
+
 /**
  * @brief Initialises the cooling properties.
  *
@@ -169,7 +175,8 @@ __attribute__((always_inline)) INLINE static float cooling_timestep(
  */
 static INLINE void cooling_init_backend(
     const struct swift_params* parameter_file, const struct UnitSystem* us,
-    const struct phys_const* phys_const, struct cooling_data* cooling) {
+    const struct phys_const* phys_const,
+    struct cooling_function_data* cooling) {
 
   cooling->lambda =
       parser_get_param_double(parameter_file, "LambdaCooling:lambda");
@@ -199,7 +206,8 @@ static INLINE void cooling_init_backend(
  *
  * @param cooling The properties of the cooling function.
  */
-static INLINE void cooling_print_backend(const struct cooling_data* cooling) {
+static INLINE void cooling_print_backend(
+    const struct cooling_function_data* cooling) {
 
   message(
       "Cooling function is 'Constant lambda' with "
diff --git a/src/cooling/const_lambda/cooling_struct.h b/src/cooling/const_lambda/cooling_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..27c5df16bffbe7d165237d201ca68ea4ba89dd73
--- /dev/null
+++ b/src/cooling/const_lambda/cooling_struct.h
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
+ *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ *                    Richard Bower (r.g.bower@durham.ac.uk)
+ *                    Stefan Arridge  (stefan.arridge@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_COOLING_STRUCT_CONST_LAMBDA_H
+#define SWIFT_COOLING_STRUCT_CONST_LAMBDA_H
+
+/**
+ * @brief Properties of the cooling function.
+ */
+struct cooling_function_data {
+
+  /*! Cooling rate in cgs units. Defined by 'rho * du/dt = -lambda * n_H^2'*/
+  float lambda;
+
+  /*! Minimum temperature (in Kelvin) for all gas particles*/
+  float min_temperature;
+
+  /*! Fraction of gas mass that is Hydrogen. Used to calculate n_H*/
+  float hydrogen_mass_abundance;
+
+  /* 'mu', used to convert min_temperature to min_internal energy*/
+  float mean_molecular_weight;
+
+  /*! Minimally allowed internal energy of the particles */
+  float min_energy;
+  float min_energy_cgs;
+
+  /*! Constant multiplication factor for time-step criterion */
+  float cooling_tstep_mult;
+};
+
+/**
+ * @brief Properties of the cooling stored in the particle data.
+ */
+struct cooling_xpart_data {
+
+  /*! Energy radiated away by this particle since the start of the run */
+  float radiated_energy;
+};
+
+#endif /* SWIFT_COOLING_STRUCT_CONST_LAMBDA_H */
diff --git a/src/cooling/none/cooling.h b/src/cooling/none/cooling.h
new file mode 100644
index 0000000000000000000000000000000000000000..0461100dc11e7ffbb4616766923142442b4ac943
--- /dev/null
+++ b/src/cooling/none/cooling.h
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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_COOLING_NONE_H
+#define SWIFT_COOLING_NONE_H
+
+/**
+ * @file src/cooling/none/cooling.h
+ * @brief Empty infrastructure for the cases without cooling function
+ */
+
+/* Some standard headers. */
+#include <float.h>
+#include <math.h>
+
+/* Local includes. */
+#include "error.h"
+#include "hydro.h"
+#include "parser.h"
+#include "part.h"
+#include "physical_constants.h"
+#include "units.h"
+
+/**
+ * @brief Apply the cooling function to a particle.
+ *
+ * We do nothing.
+ *
+ * @param phys_const The physical constants in internal units.
+ * @param us The internal system of units.
+ * @param cooling The #cooling_function_data used in the run.
+ * @param p Pointer to the particle data.
+ * @param dt The time-step of this particle.
+ */
+__attribute__((always_inline)) INLINE static void cooling_cool_part(
+    const struct phys_const* restrict phys_const,
+    const struct UnitSystem* restrict us,
+    const struct cooling_function_data* restrict cooling,
+    struct part* restrict p, struct xpart* restrict xp, float dt) {}
+
+/**
+ * @brief Computes the cooling time-step.
+ *
+ * We return FLT_MAX so as to impose no limit on the time-step.
+ *
+ * @param cooling The #cooling_function_data used in the run.
+ * @param phys_const The physical constants in internal units.
+ * @param us The internal system of units.
+ * @param p Pointer to the particle data.
+ */
+__attribute__((always_inline)) INLINE static float cooling_timestep(
+    const struct cooling_function_data* restrict cooling,
+    const struct phys_const* restrict phys_const,
+    const struct UnitSystem* restrict us, const struct part* restrict p) {
+
+  return FLT_MAX;
+}
+
+/**
+ * @brief Sets the cooling properties of the (x-)particles to a valid start
+ * state.
+ *
+ * Nothing to do here.
+ *
+ * @param p Pointer to the particle data.
+ * @param xp Pointer to the extended particle data.
+ */
+__attribute__((always_inline)) INLINE static void cooling_init_part(
+    const struct part* restrict p, struct xpart* restrict xp) {}
+
+/**
+ * @brief Returns the total radiated energy by this particle.
+ *
+ * No cooling, so return 0.
+ *
+ * @param xp The extended particle data
+ */
+__attribute__((always_inline)) INLINE static float cooling_get_radiated_energy(
+    const struct xpart* restrict xp) {
+
+  return 0.f;
+}
+
+/**
+ * @brief Initialises the cooling properties.
+ *
+ * Nothing to do here.
+ *
+ * @param parameter_file The parsed parameter file.
+ * @param us The current internal system of units.
+ * @param phys_const The physical constants in internal units.
+ * @param cooling The cooling properties to initialize
+ */
+static INLINE void cooling_init_backend(
+    const struct swift_params* parameter_file, const struct UnitSystem* us,
+    const struct phys_const* phys_const,
+    struct cooling_function_data* cooling) {}
+
+/**
+ * @brief Prints the properties of the cooling model to stdout.
+ *
+ * @param cooling The properties of the cooling function.
+ */
+static INLINE void cooling_print_backend(
+    const struct cooling_function_data* cooling) {
+
+  message("Cooling function is 'No cooling'.");
+}
+
+#endif /* SWIFT_COOLING_NONE_H */
diff --git a/src/cooling/none/cooling_struct.h b/src/cooling/none/cooling_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..a08530c44d7405df934136f2861f84ba619d2595
--- /dev/null
+++ b/src/cooling/none/cooling_struct.h
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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_COOLING_STRUCT_NONE_H
+#define SWIFT_COOLING_STRUCT_NONE_H
+
+/**
+ * @file src/cooling/none/cooling_struct.h
+ * @brief Empty infrastructure for the cases without cooling function
+ */
+
+/**
+ * @brief Properties of the cooling function.
+ */
+struct cooling_function_data {};
+
+/**
+ * @brief Properties of the cooling stored in the particle data
+ */
+struct cooling_xpart_data {};
+
+#endif /* SWIFT_COOLING_STRUCT_NONE_H */
diff --git a/src/cooling_struct.h b/src/cooling_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c567788423ae39507864de8b4a687eeed358cb6
--- /dev/null
+++ b/src/cooling_struct.h
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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_COOLING_STRUCT_H
+#define SWIFT_COOLING_STRUCT_H
+
+/**
+ * @file src/cooling_struct.h
+ * @brief Branches between the different cooling functions.
+ */
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Local headers. */
+#include "const.h"
+
+/* Import the right cooling definition */
+#if defined(COOLING_NONE)
+#include "./cooling/none/cooling_struct.h"
+#elif defined(COOLING_CONST_DU)
+#include "./cooling/const_du/cooling_struct.h"
+#elif defined(COOLING_CONST_LAMBDA)
+#include "./cooling/const_lambda/cooling_struct.h"
+#elif defined(COOLING_GRACKLE)
+#include "./cooling/grackle/cooling_struct.h"
+#else
+#error "Invalid choice of cooling function."
+#endif
+
+#endif /* SWIFT_COOLING_STRUCT_H */
diff --git a/src/debug.c b/src/debug.c
index d73bc86a92cf5ca28c202e7b567cf7c40ba6eccb..be42485a38ea8d560797e8f1ccc5936456febcd8 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -44,6 +44,8 @@
 #include "./hydro/Minimal/hydro_debug.h"
 #elif defined(GADGET2_SPH)
 #include "./hydro/Gadget2/hydro_debug.h"
+#elif defined(HOPKINS_PE_SPH)
+#include "./hydro/PressureEntropy/hydro_debug.h"
 #elif defined(DEFAULT_SPH)
 #include "./hydro/Default/hydro_debug.h"
 #elif defined(GIZMO_SPH)
@@ -65,7 +67,7 @@
  *
  * (Should be used for debugging only as it runs in O(N).)
  */
-void printParticle(const struct part *parts, struct xpart *xparts,
+void printParticle(const struct part *parts, const struct xpart *xparts,
                    long long int id, size_t N) {
 
   int found = 0;
@@ -125,7 +127,7 @@ void printgParticle(const struct gpart *gparts, const struct part *parts,
  */
 void printParticle_single(const struct part *p, const struct xpart *xp) {
 
-  printf("## Particle: id=%lld", p->id);
+  printf("## Particle: id=%lld ", p->id);
   hydro_debug_particle(p, xp);
   printf("\n");
 }
diff --git a/src/debug.h b/src/debug.h
index 22b63820745ca7282b7699f0be09e493238d83c2..2142a22eca91338580d8f50197a57de0cf248bee 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -24,7 +24,7 @@
 #include "part.h"
 #include "space.h"
 
-void printParticle(const struct part *parts, struct xpart *xparts,
+void printParticle(const struct part *parts, const struct xpart *xparts,
                    long long int id, size_t N);
 void printgParticle(const struct gpart *gparts, const struct part *parts,
                     long long int id, size_t N);
diff --git a/src/engine.c b/src/engine.c
index f877bf5f28335b3c937fc653951d64286333bb68..175eaec6de5fe47665f0f6276143ab840ed2f75a 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -1946,14 +1946,14 @@ void engine_maketasks(struct engine *e) {
   scheduler_ranktasks(sched);
 
   /* Weight the tasks. */
-  scheduler_reweight(sched);
+  scheduler_reweight(sched, e->verbose);
 
   /* Set the tasks age. */
   e->tasks_age = 0;
 
   if (e->verbose)
-    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
-            clocks_getunit());
+    message("took %.3f %s (including reweight).",
+            clocks_from_ticks(getticks() - tic), clocks_getunit());
 }
 
 /**
@@ -2254,6 +2254,8 @@ void engine_rebuild(struct engine *e) {
   /* Re-build the space. */
   space_rebuild(e->s, 0.0, e->verbose);
 
+  if (e->ti_current == 0) space_sanitize(e->s);
+
 /* If in parallel, exchange the cell structure. */
 #ifdef WITH_MPI
   engine_exchange_cells(e);
@@ -2278,8 +2280,11 @@ void engine_rebuild(struct engine *e) {
  * @brief Prepare the #engine by re-building the cells and tasks.
  *
  * @param e The #engine to prepare.
+ * @param nodrift Whether to drift particles before rebuilding or not. Will
+ *                not be necessary if all particles have already been
+ *                drifted (before repartitioning for instance).
  */
-void engine_prepare(struct engine *e) {
+void engine_prepare(struct engine *e, int nodrift) {
 
   TIMER_TIC;
 
@@ -2295,32 +2300,32 @@ void engine_prepare(struct engine *e) {
   rebuild = buff;
 #endif
 
-  /* Did this not go through? */
+  /* And rebuild if necessary. */
   if (rebuild) {
 
-    /* First drift all particles to the current time */
-    e->drift_all = 1;
-    threadpool_map(&e->threadpool, runner_do_drift_mapper, e->s->cells_top,
-                   e->s->nr_cells, sizeof(struct cell), 1, e);
+    /* Drift all particles to the current time if needed. */
+    if (!nodrift) {
+      e->drift_all = 1;
+      engine_drift(e);
 
-    /* Restore the default drifting policy */
-    e->drift_all = (e->policy & engine_policy_drift_all);
+      /* Restore the default drifting policy */
+      e->drift_all = (e->policy & engine_policy_drift_all);
+    }
 
-    /* And now rebuild */
     engine_rebuild(e);
   }
 
   /* Re-rank the tasks every now and then. */
   if (e->tasks_age % engine_tasksreweight == 1) {
-    scheduler_reweight(&e->sched);
+    scheduler_reweight(&e->sched, e->verbose);
   }
   e->tasks_age += 1;
 
   TIMER_TOC(timer_prepare);
 
   if (e->verbose)
-    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
-            clocks_getunit());
+    message("took %.3f %s (including marktask, rebuild and reweight).",
+            clocks_from_ticks(getticks() - tic), clocks_getunit());
 }
 
 /**
@@ -2412,6 +2417,7 @@ void engine_collect_kick(struct cell *c) {
  */
 void engine_collect_timestep(struct engine *e) {
 
+  const ticks tic = getticks();
   int updates = 0, g_updates = 0;
   int ti_end_min = max_nr_timesteps;
   const struct space *s = e->s;
@@ -2456,6 +2462,10 @@ void engine_collect_timestep(struct engine *e) {
   e->ti_end_min = ti_end_min;
   e->updates = updates;
   e->g_updates = g_updates;
+
+  if (e->verbose)
+    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+            clocks_getunit());
 }
 
 /**
@@ -2465,9 +2475,11 @@ void engine_collect_timestep(struct engine *e) {
  */
 void engine_print_stats(struct engine *e) {
 
+  const ticks tic = getticks();
   const struct space *s = e->s;
 
-  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, entropy = 0.0, mass = 0.0;
+  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, e_rad = 0.0;
+  double entropy = 0.0, mass = 0.0;
   double mom[3] = {0.0, 0.0, 0.0}, ang_mom[3] = {0.0, 0.0, 0.0};
 
   /* Collect the cell data. */
@@ -2478,6 +2490,7 @@ void engine_print_stats(struct engine *e) {
       e_kin += c->e_kin;
       e_int += c->e_int;
       e_pot += c->e_pot;
+      e_rad += c->e_rad;
       entropy += c->entropy;
       mom[0] += c->mom[0];
       mom[1] += c->mom[1];
@@ -2490,33 +2503,35 @@ void engine_print_stats(struct engine *e) {
 /* Aggregate the data from the different nodes. */
 #ifdef WITH_MPI
   {
-    double in[11] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.};
-    double out[11];
+    double in[12] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.};
+    double out[12];
     out[0] = e_kin;
     out[1] = e_int;
     out[2] = e_pot;
-    out[3] = mom[0];
-    out[4] = mom[1];
-    out[5] = mom[2];
-    out[6] = ang_mom[0];
-    out[7] = ang_mom[1];
-    out[8] = ang_mom[2];
-    out[9] = mass;
-    out[10] = entropy;
+    out[3] = e_rad;
+    out[4] = mom[0];
+    out[5] = mom[1];
+    out[6] = mom[2];
+    out[7] = ang_mom[0];
+    out[8] = ang_mom[1];
+    out[9] = ang_mom[2];
+    out[10] = mass;
+    out[11] = entropy;
     if (MPI_Reduce(out, in, 11, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD) !=
         MPI_SUCCESS)
       error("Failed to aggregate stats.");
     e_kin = out[0];
     e_int = out[1];
     e_pot = out[2];
-    mom[0] = out[3];
-    mom[1] = out[4];
-    mom[2] = out[5];
-    ang_mom[0] = out[6];
-    ang_mom[1] = out[7];
-    ang_mom[2] = out[8];
-    mass = out[9];
-    entropy = out[10];
+    e_rad = out[3];
+    mom[0] = out[4];
+    mom[1] = out[5];
+    mom[2] = out[6];
+    ang_mom[0] = out[7];
+    ang_mom[1] = out[8];
+    ang_mom[2] = out[9];
+    mass = out[10];
+    entropy = out[11];
   }
 #endif
 
@@ -2524,13 +2539,17 @@ void engine_print_stats(struct engine *e) {
 
   /* Print info */
   if (e->nodeID == 0) {
-    fprintf(
-        e->file_stats,
-        " %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e\n",
-        e->time, mass, e_tot, e_kin, e_int, e_pot, entropy, mom[0], mom[1],
-        mom[2], ang_mom[0], ang_mom[1], ang_mom[2]);
+    fprintf(e->file_stats,
+            " %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e "
+            "%14e\n",
+            e->time, mass, e_tot, e_kin, e_int, e_pot, e_rad, entropy, mom[0],
+            mom[1], mom[2], ang_mom[0], ang_mom[1], ang_mom[2]);
     fflush(e->file_stats);
   }
+
+  if (e->verbose)
+    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+            clocks_getunit());
 }
 
 /**
@@ -2544,6 +2563,8 @@ void engine_print_stats(struct engine *e) {
 void engine_launch(struct engine *e, int nr_runners, unsigned int mask,
                    unsigned int submask) {
 
+  const ticks tic = getticks();
+
   /* Prepare the scheduler. */
   atomic_inc(&e->sched.waiting);
 
@@ -2568,6 +2589,10 @@ void engine_launch(struct engine *e, int nr_runners, unsigned int mask,
   while (e->barrier_launch || e->barrier_running)
     if (pthread_cond_wait(&e->barrier_cond, &e->barrier_mutex) != 0)
       error("Error while waiting for barrier.");
+
+  if (e->verbose)
+    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+            clocks_getunit());
 }
 
 /**
@@ -2587,7 +2612,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs) {
 
   if (e->nodeID == 0) message("Running initialisation fake time-step.");
 
-  engine_prepare(e);
+  engine_prepare(e, 1);
 
   engine_marktasks(e);
 
@@ -2646,7 +2671,15 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs) {
   TIMER_TOC(timer_runners);
 
   /* Apply some conversions (e.g. internal energy -> entropy) */
-  if (!flag_entropy_ICs) space_map_cells_pre(s, 0, cell_convert_hydro, NULL);
+  if (!flag_entropy_ICs) {
+
+    /* Apply the conversion */
+    space_map_cells_pre(s, 0, cell_convert_hydro, NULL);
+
+    /* Correct what we did (e.g. in PE-SPH, need to recompute rho_bar) */
+    if (hydro_need_extra_init_loop)
+      engine_launch(e, e->nr_threads, mask, submask);
+  }
 
   clocks_gettime(&time2);
 
@@ -2688,8 +2721,7 @@ void engine_step(struct engine *e) {
 
     /* Drift everybody to the snapshot position */
     e->drift_all = 1;
-    threadpool_map(&e->threadpool, runner_do_drift_mapper, e->s->cells_top,
-                   e->s->nr_cells, sizeof(struct cell), 1, e);
+    engine_drift(e);
 
     /* Restore the default drifting policy */
     e->drift_all = (e->policy & engine_policy_drift_all);
@@ -2727,15 +2759,20 @@ void engine_step(struct engine *e) {
     e->timeLastStatistics += e->deltaTimeStatistics;
   }
 
-  /* Drift only the necessary particles */
-  threadpool_map(&e->threadpool, runner_do_drift_mapper, e->s->cells_top,
-                 e->s->nr_cells, sizeof(struct cell), 1, e);
+  /* Drift only the necessary particles, that all means all particles
+   * if we are about to repartition. */
+  int repart = (e->forcerepart != REPART_NONE);
+  e->drift_all = repart || e->drift_all;
+  engine_drift(e);
 
   /* Re-distribute the particles amongst the nodes? */
-  if (e->forcerepart != REPART_NONE) engine_repartition(e);
+  if (repart) engine_repartition(e);
 
   /* Prepare the space. */
-  engine_prepare(e);
+  engine_prepare(e, e->drift_all);
+
+  /* Restore the default drifting policy */
+  e->drift_all = (e->policy & engine_policy_drift_all);
 
   /* Build the masks corresponding to the policy */
   unsigned int mask = 0, submask = 0;
@@ -2807,6 +2844,8 @@ void engine_step(struct engine *e) {
     submask |= 1 << task_subtype_tend;
   }
 
+  if (e->verbose) engine_print_task_counts(e);
+
   /* Send off the runners. */
   TIMER_TIC;
   engine_launch(e, e->nr_threads, mask, submask);
@@ -2827,6 +2866,21 @@ int engine_is_done(struct engine *e) {
   return !(e->ti_current < max_nr_timesteps);
 }
 
+/**
+ * @brief Drift particles using the current engine drift policy.
+ *
+ * @param e The #engine.
+ */
+void engine_drift(struct engine *e) {
+
+  const ticks tic = getticks();
+  threadpool_map(&e->threadpool, runner_do_drift_mapper, e->s->cells_top,
+                 e->s->nr_cells, sizeof(struct cell), 1, e);
+  if (e->verbose)
+    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+            clocks_getunit());
+}
+
 /**
  * @brief Create and fill the proxies.
  *
@@ -3339,11 +3393,11 @@ void engine_init(struct engine *e, struct space *s,
                                 engine_default_energy_file_name);
     sprintf(energyfileName + strlen(energyfileName), ".txt");
     e->file_stats = fopen(energyfileName, "w");
-    fprintf(
-        e->file_stats,
-        "#%14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s\n",
-        "Time", "Mass", "E_tot", "E_kin", "E_int", "E_pot", "Entropy", "p_x",
-        "p_y", "p_z", "ang_x", "ang_y", "ang_z");
+    fprintf(e->file_stats,
+            "#%14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s "
+            "%14s\n",
+            "Time", "Mass", "E_tot", "E_kin", "E_int", "E_pot", "E_radcool",
+            "Entropy", "p_x", "p_y", "p_z", "ang_x", "ang_y", "ang_z");
     fflush(e->file_stats);
 
     char timestepsfileName[200] = "";
diff --git a/src/engine.h b/src/engine.h
index 1005dbb46aeefd6843e2fab278d0c17115cf869a..914025c125b9646be93b463e76606bf5813366f4 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -38,10 +38,10 @@
 
 /* Includes. */
 #include "clocks.h"
-#include "cooling.h"
+#include "cooling_struct.h"
 #include "parser.h"
 #include "partition.h"
-#include "potentials.h"
+#include "potential.h"
 #include "runner.h"
 #include "scheduler.h"
 #include "sourceterms.h"
@@ -219,6 +219,7 @@ struct engine {
 /* Function prototypes. */
 void engine_barrier(struct engine *e, int tid);
 void engine_compute_next_snapshot_time(struct engine *e);
+void engine_drift(struct engine *e);
 void engine_dump_snapshot(struct engine *e);
 void engine_init(struct engine *e, struct space *s,
                  const struct swift_params *params, int nr_nodes, int nodeID,
@@ -231,7 +232,7 @@ void engine_init(struct engine *e, struct space *s,
                  struct sourceterms *sourceterms);
 void engine_launch(struct engine *e, int nr_runners, unsigned int mask,
                    unsigned int submask);
-void engine_prepare(struct engine *e);
+void engine_prepare(struct engine *e, int nodrift);
 void engine_print(struct engine *e);
 void engine_init_particles(struct engine *e, int flag_entropy_ICs);
 void engine_step(struct engine *e);
diff --git a/src/equation_of_state.h b/src/equation_of_state.h
index af59d8a2cad1632c67b6d377b5ed9dfe9484b4aa..5b19f99ab85d8a2b4e5e6f0b4eeb542925b4ee50 100644
--- a/src/equation_of_state.h
+++ b/src/equation_of_state.h
@@ -126,6 +126,21 @@ 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);
+}
+
 /* ------------------------------------------------------------------------- */
 #elif defined(EOS_ISOTHERMAL_GAS)
 
@@ -221,6 +236,22 @@ gas_soundspeed_from_internal_energy(float density, float u) {
                hydro_gamma_minus_one);
 }
 
+/**
+ * @brief Returns the sound speed given density and pressure
+ *
+ * Since we are using an isothermal EoS, the pressure value is ignored
+ * Computes \f$c = \sqrt{u_{cst} \gamma \rho^{\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(const_isothermal_internal_energy * hydro_gamma *
+               hydro_gamma_minus_one);
+}
+
 /* ------------------------------------------------------------------------- */
 #else
 
diff --git a/src/gravity/Default/gravity.h b/src/gravity/Default/gravity.h
index 2415e20ac5eb68f1b773b990bab232707166903c..9e0ca81edff06b8a32afb185f24a88b41dc87da7 100644
--- a/src/gravity/Default/gravity.h
+++ b/src/gravity/Default/gravity.h
@@ -22,47 +22,14 @@
 
 #include <float.h>
 #include "minmax.h"
-#include "potentials.h"
-
-/**
- * @brief Computes the gravity time-step of a given particle due to an external
- *potential.
- *
- * This function only branches towards the potential chosen by the user.
- *
- * @param potential The properties of the external potential.
- * @param phys_const The physical constants in internal units.
- * @param gp Pointer to the g-particle data.
- */
-__attribute__((always_inline)) INLINE static float
-gravity_compute_timestep_external(const struct external_potential* potential,
-                                  const struct phys_const* const phys_const,
-                                  const struct gpart* const gp) {
-
-  float dt = FLT_MAX;
-
-#ifdef EXTERNAL_POTENTIAL_POINTMASS
-  dt = min(dt, external_gravity_pointmass_timestep(potential, phys_const, gp));
-#endif
-#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
-  dt = min(dt, external_gravity_isothermalpotential_timestep(potential,
-                                                             phys_const, gp));
-#endif
-#ifdef EXTERNAL_POTENTIAL_DISK_PATCH
-  dt = min(dt, external_gravity_disk_patch_timestep(potential, phys_const, gp));
-#endif
-  return dt;
-}
 
 /**
  * @brief Computes the gravity time-step of a given particle due to self-gravity
  *
- * @param phys_const The physical constants in internal units.
  * @param gp Pointer to the g-particle data.
  */
 __attribute__((always_inline)) INLINE static float
-gravity_compute_timestep_self(const struct phys_const* const phys_const,
-                              const struct gpart* const gp) {
+gravity_compute_timestep_self(const struct gpart* const gp) {
 
   const float ac2 = gp->a_grav[0] * gp->a_grav[0] +
                     gp->a_grav[1] * gp->a_grav[1] +
@@ -125,31 +92,6 @@ __attribute__((always_inline)) INLINE static void gravity_end_force(
   gp->a_grav[2] *= const_G;
 }
 
-/**
- * @brief Computes the gravitational acceleration induced by external potentials
- *
- * This function only branches towards the potential chosen by the user.
- *
- * @param time The current time in internal units.
- * @param potential The properties of the external potential.
- * @param phys_const The physical constants in internal units.
- * @param gp The particle to act upon.
- */
-__attribute__((always_inline)) INLINE static void external_gravity(
-    double time, const struct external_potential* potential,
-    const struct phys_const* const phys_const, struct gpart* gp) {
-
-#ifdef EXTERNAL_POTENTIAL_POINTMASS
-  external_gravity_pointmass(potential, phys_const, gp);
-#endif
-#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
-  external_gravity_isothermalpotential(potential, phys_const, gp);
-#endif
-#ifdef EXTERNAL_POTENTIAL_DISK_PATCH
-  external_gravity_disk_patch_potential(time, potential, phys_const, gp);
-#endif
-}
-
 /**
  * @brief Kick the additional variables
  *
diff --git a/src/gravity/Default/gravity_part.h b/src/gravity/Default/gravity_part.h
index 1850ff0a1644d3593f78f150646eae8b2f074e1e..f06e65e5b30ebcd609c0c6204de33da17b770add 100644
--- a/src/gravity/Default/gravity_part.h
+++ b/src/gravity/Default/gravity_part.h
@@ -53,6 +53,6 @@ struct gpart {
      which this gpart is linked. */
   long long id_or_neg_offset;
 
-} __attribute__((aligned(gpart_align)));
+} SWIFT_STRUCT_ALIGN;
 
 #endif /* SWIFT_DEFAULT_GRAVITY_PART_H */
diff --git a/src/hydro.h b/src/hydro.h
index 4a2b0bd029d494e2091b9081d22b7949cec5648c..9e02c2009e307f0623ffb535ff9068603c2d4147 100644
--- a/src/hydro.h
+++ b/src/hydro.h
@@ -34,6 +34,10 @@
 #include "./hydro/Gadget2/hydro.h"
 #include "./hydro/Gadget2/hydro_iact.h"
 #define SPH_IMPLEMENTATION "Gadget-2 version of SPH (Springel 2005)"
+#elif defined(HOPKINS_PE_SPH)
+#include "./hydro/PressureEntropy/hydro.h"
+#include "./hydro/PressureEntropy/hydro_iact.h"
+#define SPH_IMPLEMENTATION "Pressure-Entropy SPH (Hopkins 2013)"
 #elif defined(DEFAULT_SPH)
 #include "./hydro/Default/hydro.h"
 #include "./hydro/Default/hydro_iact.h"
diff --git a/src/hydro/Default/hydro_part.h b/src/hydro/Default/hydro_part.h
index f42c3dc886ae1ab8f472ffdf5ff508f6735d1bb1..c7464bcf338b1c5b81ffa91d92264c2bd35e9313 100644
--- a/src/hydro/Default/hydro_part.h
+++ b/src/hydro/Default/hydro_part.h
@@ -19,6 +19,8 @@
 #ifndef SWIFT_DEFAULT_HYDRO_PART_H
 #define SWIFT_DEFAULT_HYDRO_PART_H
 
+#include "cooling_struct.h"
+
 /* Extra particle data not needed during the SPH loops over neighbours. */
 struct xpart {
 
@@ -28,12 +30,15 @@ struct xpart {
   /* Velocity at the last full step. */
   float v_full[3];
 
+  /* Additional data used to record cooling information */
+  struct cooling_xpart_data cooling_data;
+
   float u_full;
 
   /* Old density. */
   float omega;
 
-} __attribute__((aligned(xpart_align)));
+} SWIFT_STRUCT_ALIGN;
 
 /* Data of a single particle. */
 struct part {
@@ -120,6 +125,6 @@ struct part {
   /* Pointer to corresponding gravity part. */
   struct gpart* gpart;
 
-} __attribute__((aligned(part_align)));
+} SWIFT_STRUCT_ALIGN;
 
 #endif /* SWIFT_DEFAULT_HYDRO_PART_H */
diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h
index 09a8f50d5b2e9abd43c3b9bd43a12fad8a347258..0bdf56fe844309998db1fad4cf9581edb6b88305 100644
--- a/src/hydro/Gadget2/hydro.h
+++ b/src/hydro/Gadget2/hydro.h
@@ -19,12 +19,25 @@
 #ifndef SWIFT_GADGET2_HYDRO_H
 #define SWIFT_GADGET2_HYDRO_H
 
+/**
+ * @file Gadget2/hydro.h
+ * @brief SPH interaction functions following the Gadget-2 version of SPH.
+ *
+ * The interactions computed here are the ones presented in the Gadget-2 paper
+ * Springel, V., MNRAS, Volume 364, Issue 4, pp. 1105-1134.
+ * We use the same numerical coefficients as the Gadget-2 code. When used with
+ * the Spline-3 kernel, the results should be equivalent to the ones obtained
+ * with Gadget-2 up to the rounding errors and interactions missed by the
+ * Gadget-2 tree-code neighbours search.
+ */
+
 #include "adiabatic_index.h"
 #include "approx_math.h"
 #include "dimension.h"
 #include "equation_of_state.h"
 #include "hydro_properties.h"
 #include "kernel_hydro.h"
+#include "minmax.h"
 
 /**
  * @brief Returns the internal energy of a particle
@@ -104,8 +117,9 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
  * @brief Modifies the thermal state of a particle to the imposed internal
  * energy
  *
- * This overrides the current state of the particle but does *not* change its
- * time-derivatives
+ * This overwrites the current state of the particle but does *not* change its
+ * time-derivatives. Entropy, pressure, sound-speed and signal velocity will be
+ * updated.
  *
  * @param p The particle
  * @param u The new internal energy
@@ -114,13 +128,31 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy(
     struct part *restrict p, float u) {
 
   p->entropy = gas_entropy_from_internal_energy(p->rho, u);
+
+  /* Compute the new pressure */
+  const float pressure = gas_pressure_from_internal_energy(p->rho, u);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  /* Update the signal velocity */
+  const float v_sig_old = p->force.v_sig;
+  const float v_sig_new = p->force.v_sig - p->force.soundspeed + soundspeed;
+  const float v_sig = max(v_sig_old, v_sig_new);
+
+  const float rho_inv = 1.f / p->rho;
+
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = pressure * rho_inv * rho_inv;
+  p->force.v_sig = v_sig;
 }
 
 /**
  * @brief Modifies the thermal state of a particle to the imposed entropy
  *
- * This overrides the current state of the particle but does *not* change its
- * time-derivatives
+ * This overwrites the current state of the particle but does *not* change its
+ * time-derivatives. Entropy, pressure, sound-speed and signal velocity will be
+ * updated.
  *
  * @param p The particle
  * @param S The new entropy
@@ -129,6 +161,23 @@ __attribute__((always_inline)) INLINE static void hydro_set_entropy(
     struct part *restrict p, float S) {
 
   p->entropy = S;
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho, p->entropy);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  /* Update the signal velocity */
+  const float v_sig_old = p->force.v_sig;
+  const float v_sig_new = p->force.v_sig - p->force.soundspeed + soundspeed;
+  const float v_sig = max(v_sig_old, v_sig_new);
+
+  const float rho_inv = 1.f / p->rho;
+
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = pressure * rho_inv * rho_inv;
+  p->force.v_sig = v_sig;
 }
 
 /**
@@ -183,7 +232,7 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
   p->density.wcount = 0.f;
   p->density.wcount_dh = 0.f;
   p->rho = 0.f;
-  p->rho_dh = 0.f;
+  p->density.rho_dh = 0.f;
   p->density.div_v = 0.f;
   p->density.rot_v[0] = 0.f;
   p->density.rot_v[1] = 0.f;
@@ -210,27 +259,24 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
 
   /* Final operation on the density (add self-contribution). */
   p->rho += p->mass * kernel_root;
-  p->rho_dh -= hydro_dimension * p->mass * kernel_root;
+  p->density.rho_dh -= hydro_dimension * p->mass * kernel_root;
   p->density.wcount += kernel_root;
 
   /* Finish the calculation by inserting the missing h-factors */
   p->rho *= h_inv_dim;
-  p->rho_dh *= h_inv_dim_plus_one;
+  p->density.rho_dh *= h_inv_dim_plus_one;
   p->density.wcount *= kernel_norm;
   p->density.wcount_dh *= h_inv * kernel_gamma * kernel_norm;
 
-  const float irho = 1.f / p->rho;
-
-  /* Compute the derivative term */
-  p->rho_dh = 1.f / (1.f + hydro_dimension_inv * p->h * p->rho_dh * irho);
+  const float rho_inv = 1.f / p->rho;
 
   /* Finish calculation of the velocity curl components */
-  p->density.rot_v[0] *= h_inv_dim_plus_one * irho;
-  p->density.rot_v[1] *= h_inv_dim_plus_one * irho;
-  p->density.rot_v[2] *= h_inv_dim_plus_one * irho;
+  p->density.rot_v[0] *= h_inv_dim_plus_one * rho_inv;
+  p->density.rot_v[1] *= h_inv_dim_plus_one * rho_inv;
+  p->density.rot_v[2] *= h_inv_dim_plus_one * rho_inv;
 
   /* Finish calculation of the velocity divergence */
-  p->density.div_v *= h_inv_dim_plus_one * irho;
+  p->density.div_v *= h_inv_dim_plus_one * rho_inv;
 }
 
 /**
@@ -261,19 +307,23 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force(
   const float half_dt = (ti_current - (p->ti_begin + p->ti_end) / 2) * timeBase;
   const float pressure = hydro_get_pressure(p, half_dt);
 
-  const float irho = 1.f / p->rho;
-
-  /* Divide the pressure by the density and density gradient */
-  const float P_over_rho2 = pressure * irho * irho * p->rho_dh;
-
   /* Compute the sound speed */
-  const float soundspeed = sqrtf(hydro_gamma * pressure * irho);
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_inv = 1.f / p->rho;
+  const float P_over_rho2 = pressure * rho_inv * rho_inv;
 
   /* Compute the Balsara switch */
   const float balsara =
       abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed / fac_mu / p->h);
 
+  /* Compute the "grad h" term */
+  const float grad_h_term =
+      1.f / (1.f + hydro_dimension_inv * p->h * p->density.rho_dh * rho_inv);
+
   /* Update variables. */
+  p->force.f = grad_h_term;
   p->force.P_over_rho2 = P_over_rho2;
   p->force.soundspeed = soundspeed;
   p->force.balsara = balsara;
@@ -337,17 +387,16 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
   const float dt_entr = (t1 - (p->ti_begin + p->ti_end) / 2) * timeBase;
   const float pressure = hydro_get_pressure(p, dt_entr);
 
-  const float irho = 1.f / p->rho;
-
-  /* Divide the pressure by the density and density gradient */
-  const float P_over_rho2 = pressure * irho * irho * p->rho_dh;
-
   /* Compute the new sound speed */
-  const float soundspeed = sqrtf(hydro_gamma * pressure * irho);
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_inv = 1.f / p->rho;
+  const float P_over_rho2 = pressure * rho_inv * rho_inv;
 
   /* Update variables */
-  p->force.P_over_rho2 = P_over_rho2;
   p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = P_over_rho2;
 }
 
 /**
@@ -388,6 +437,19 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
   /* Do not 'overcool' when timestep increases */
   if (p->entropy + p->entropy_dt * half_dt < 0.5f * p->entropy)
     p->entropy_dt = -0.5f * p->entropy / half_dt;
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho, p->entropy);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_inv = 1.f / p->rho;
+  const float P_over_rho2 = pressure * rho_inv * rho_inv;
+
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = P_over_rho2;
 }
 
 /**
@@ -402,6 +464,19 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
 
   /* We read u in the entropy field. We now get S from u */
   p->entropy = gas_entropy_from_internal_energy(p->rho, p->entropy);
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho, p->entropy);
+
+  /* Compute the sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_inv = 1.f / p->rho;
+  const float P_over_rho2 = pressure * rho_inv * rho_inv;
+
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = P_over_rho2;
 }
 
 #endif /* SWIFT_GADGET2_HYDRO_H */
diff --git a/src/hydro/Gadget2/hydro_debug.h b/src/hydro/Gadget2/hydro_debug.h
index 7c8a6eaba96929b01f1901393d7d0498d58badf4..656299b38374f68824ec20d85ece169d5f1fd599 100644
--- a/src/hydro/Gadget2/hydro_debug.h
+++ b/src/hydro/Gadget2/hydro_debug.h
@@ -30,8 +30,8 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle(
       "v_sig=%e dh/dt=%.3e t_begin=%d, t_end=%d\n",
       p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0],
       xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2],
-      p->h, p->density.wcount, p->density.wcount_dh, p->mass, p->rho_dh, p->rho,
-      hydro_get_pressure(p, 0.), p->force.P_over_rho2, p->entropy,
+      p->h, p->density.wcount, p->density.wcount_dh, p->mass, p->density.rho_dh,
+      p->rho, hydro_get_pressure(p, 0.), p->force.P_over_rho2, p->entropy,
       p->entropy_dt, p->force.soundspeed, p->density.div_v, p->density.rot_v[0],
       p->density.rot_v[1], p->density.rot_v[2], p->force.balsara,
       p->force.v_sig, p->force.h_dt, p->ti_begin, p->ti_end);
diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h
index 8a4edfe62f59a3fae551fdb65f46987509f89251..fca1bcff91a71fb2a26adc117382630a576f9090 100644
--- a/src/hydro/Gadget2/hydro_iact.h
+++ b/src/hydro/Gadget2/hydro_iact.h
@@ -20,21 +20,20 @@
 #ifndef SWIFT_GADGET2_HYDRO_IACT_H
 #define SWIFT_GADGET2_HYDRO_IACT_H
 
-#include "minmax.h"
-
 /**
+ * @file Gadget2/hydro_iact.h
  * @brief SPH interaction functions following the Gadget-2 version of SPH.
  *
  * The interactions computed here are the ones presented in the Gadget-2 paper
- *and use the same
- * numerical coefficients as the Gadget-2 code. When used with the Spline-3
- *kernel, the results
- * should be equivalent to the ones obtained with Gadget-2 up to the rounding
- *errors and interactions
- * missed by the Gadget-2 tree-code neighbours search.
- *
+ * Springel, V., MNRAS, Volume 364, Issue 4, pp. 1105-1134.
+ * We use the same numerical coefficients as the Gadget-2 code. When used with
+ * the Spline-3 kernel, the results should be equivalent to the ones obtained
+ * with Gadget-2 up to the rounding errors and interactions missed by the
+ * Gadget-2 tree-code neighbours search.
  */
 
+#include "minmax.h"
+
 /**
  * @brief Density loop
  */
@@ -60,7 +59,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
 
   /* Compute contribution to the density */
   pi->rho += mj * wi;
-  pi->rho_dh -= mj * (hydro_dimension * wi + ui * wi_dx);
+  pi->density.rho_dh -= mj * (hydro_dimension * wi + ui * wi_dx);
 
   /* Compute contribution to the number of neighbours */
   pi->density.wcount += wi;
@@ -73,7 +72,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
 
   /* Compute contribution to the density */
   pj->rho += mi * wj;
-  pj->rho_dh -= mi * (hydro_dimension * wj + uj * wj_dx);
+  pj->density.rho_dh -= mi * (hydro_dimension * wj + uj * wj_dx);
 
   /* Compute contribution to the number of neighbours */
   pj->density.wcount += wj;
@@ -210,13 +209,13 @@ __attribute__((always_inline)) INLINE static void runner_iact_vec_density(
   /* Update particles. */
   for (k = 0; k < VEC_SIZE; k++) {
     pi[k]->rho += rhoi.f[k];
-    pi[k]->rho_dh -= rhoi_dh.f[k];
+    pi[k]->density.rho_dh -= rhoi_dh.f[k];
     pi[k]->density.wcount += wcounti.f[k];
     pi[k]->density.wcount_dh -= wcounti_dh.f[k];
     pi[k]->density.div_v -= div_vi.f[k];
     for (j = 0; j < 3; j++) pi[k]->density.rot_v[j] += curl_vi[j].f[k];
     pj[k]->rho += rhoj.f[k];
-    pj[k]->rho_dh -= rhoj_dh.f[k];
+    pj[k]->density.rho_dh -= rhoj_dh.f[k];
     pj[k]->density.wcount += wcountj.f[k];
     pj[k]->density.wcount_dh -= wcountj_dh.f[k];
     pj[k]->density.div_v -= div_vj.f[k];
@@ -249,17 +248,17 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
   const float ri = 1.0f / r;
 
   /* Compute the kernel function */
-  const float h_inv = 1.0f / hi;
-  const float u = r * h_inv;
-  kernel_deval(u, &wi, &wi_dx);
+  const float hi_inv = 1.0f / hi;
+  const float ui = r * hi_inv;
+  kernel_deval(ui, &wi, &wi_dx);
 
   /* Compute contribution to the density */
   pi->rho += mj * wi;
-  pi->rho_dh -= mj * (hydro_dimension * wi + u * wi_dx);
+  pi->density.rho_dh -= mj * (hydro_dimension * wi + ui * wi_dx);
 
   /* Compute contribution to the number of neighbours */
   pi->density.wcount += wi;
-  pi->density.wcount_dh -= u * wi_dx;
+  pi->density.wcount_dh -= ui * wi_dx;
 
   const float fac = mj * wi_dx * ri;
 
@@ -367,7 +366,7 @@ runner_iact_nonsym_vec_density(float *R2, float *Dx, float *Hi, float *Hj,
   /* Update particles. */
   for (k = 0; k < VEC_SIZE; k++) {
     pi[k]->rho += rhoi.f[k];
-    pi[k]->rho_dh -= rhoi_dh.f[k];
+    pi[k]->density.rho_dh -= rhoi_dh.f[k];
     pi[k]->density.wcount += wcounti.f[k];
     pi[k]->density.wcount_dh -= wcounti_dh.f[k];
     pi[k]->density.div_v -= div_vi.f[k];
@@ -416,7 +415,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   kernel_deval(xj, &wj, &wj_dx);
   const float wj_dr = hjd_inv * wj_dx;
 
-  /* Compute gradient terms */
+  /* Compute h-gradient terms */
+  const float f_i = pi->force.f;
+  const float f_j = pj->force.f;
+
+  /* Compute pressure terms */
   const float P_over_rho2_i = pi->force.P_over_rho2;
   const float P_over_rho2_j = pj->force.P_over_rho2;
 
@@ -448,7 +451,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   /* Now, convolve with the kernel */
   const float visc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv;
   const float sph_term =
-      (P_over_rho2_i * wi_dr + P_over_rho2_j * wj_dr) * r_inv;
+      (f_i * P_over_rho2_i * wi_dr + f_j * P_over_rho2_j * wj_dr) * r_inv;
 
   /* Eventually got the acceleration */
   const float acc = visc_term + sph_term;
@@ -691,7 +694,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   kernel_deval(xj, &wj, &wj_dx);
   const float wj_dr = hjd_inv * wj_dx;
 
-  /* Compute gradient terms */
+  /* Compute h-gradient terms */
+  const float f_i = pi->force.f;
+  const float f_j = pj->force.f;
+
+  /* Compute pressure terms */
   const float P_over_rho2_i = pi->force.P_over_rho2;
   const float P_over_rho2_j = pj->force.P_over_rho2;
 
@@ -723,7 +730,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   /* Now, convolve with the kernel */
   const float visc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv;
   const float sph_term =
-      (P_over_rho2_i * wi_dr + P_over_rho2_j * wj_dr) * r_inv;
+      (f_i * P_over_rho2_i * wi_dr + f_j * P_over_rho2_j * wj_dr) * r_inv;
 
   /* Eventually got the acceleration */
   const float acc = visc_term + sph_term;
diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h
index 484792438d2717413c1ca8d4f429eac2e6d21b20..0c14da957463720dcee5349e88be91986cbb3f54 100644
--- a/src/hydro/Gadget2/hydro_part.h
+++ b/src/hydro/Gadget2/hydro_part.h
@@ -19,6 +19,20 @@
 #ifndef SWIFT_GADGET2_HYDRO_PART_H
 #define SWIFT_GADGET2_HYDRO_PART_H
 
+/**
+ * @file Gadget2/hydro_part.h
+ * @brief SPH interaction functions following the Gadget-2 version of SPH.
+ *
+ * The interactions computed here are the ones presented in the Gadget-2 paper
+ * Springel, V., MNRAS, Volume 364, Issue 4, pp. 1105-1134.
+ * We use the same numerical coefficients as the Gadget-2 code. When used with
+ * the Spline-3 kernel, the results should be equivalent to the ones obtained
+ * with Gadget-2 up to the rounding errors and interactions missed by the
+ * Gadget-2 tree-code neighbours search.
+ */
+
+#include "cooling_struct.h"
+
 /* Extra particle data not needed during the SPH loops over neighbours. */
 struct xpart {
 
@@ -28,7 +42,10 @@ struct xpart {
   /* Velocity at the last full step. */
   float v_full[3];
 
-} __attribute__((aligned(xpart_align)));
+  /* Additional data used to record cooling information */
+  struct cooling_xpart_data cooling_data;
+
+} SWIFT_STRUCT_ALIGN;
 
 /* Data of a single particle. */
 struct part {
@@ -63,9 +80,6 @@ struct part {
   /* Entropy time derivative */
   float entropy_dt;
 
-  /* Derivative of the density with respect to smoothing length. */
-  float rho_dh;
-
   union {
 
     struct {
@@ -76,6 +90,9 @@ struct part {
       /* Number of neighbours spatial derivative. */
       float wcount_dh;
 
+      /* Derivative of the density with respect to h. */
+      float rho_dh;
+
       /* Particle velocity curl. */
       float rot_v[3];
 
@@ -89,6 +106,9 @@ struct part {
       /* Balsara switch */
       float balsara;
 
+      /*! "Grad h" term */
+      float f;
+
       /* Pressure over density squared (including drho/dh term) */
       float P_over_rho2;
 
@@ -110,6 +130,6 @@ struct part {
   /* Pointer to corresponding gravity part. */
   struct gpart* gpart;
 
-} __attribute__((aligned(part_align)));
+} SWIFT_STRUCT_ALIGN;
 
 #endif /* SWIFT_GADGET2_HYDRO_PART_H */
diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h
index 37ce34e5910a033fab82dbc69839888a28c5ab12..a383a2fdce9e64a5673d0136184368220dc08458 100644
--- a/src/hydro/Gizmo/hydro.h
+++ b/src/hydro/Gizmo/hydro.h
@@ -150,18 +150,16 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
   /* compute primitive variables */
   /* eqns (3)-(5) */
   const float m = p->conserved.mass;
-  if (m > 0.f) {
-    float momentum[3];
-    momentum[0] = p->conserved.momentum[0];
-    momentum[1] = p->conserved.momentum[1];
-    momentum[2] = p->conserved.momentum[2];
-    p->primitives.rho = m / volume;
-    p->primitives.v[0] = momentum[0] / m;
-    p->primitives.v[1] = momentum[1] / m;
-    p->primitives.v[2] = momentum[2] / m;
-    const float energy = p->conserved.energy;
-    p->primitives.P = hydro_gamma_minus_one * energy / volume;
-  }
+  float momentum[3];
+  momentum[0] = p->conserved.momentum[0];
+  momentum[1] = p->conserved.momentum[1];
+  momentum[2] = p->conserved.momentum[2];
+  p->primitives.rho = m / volume;
+  p->primitives.v[0] = momentum[0] / m;
+  p->primitives.v[1] = momentum[1] / m;
+  p->primitives.v[2] = momentum[2] / m;
+  const float energy = p->conserved.energy;
+  p->primitives.P = hydro_gamma_minus_one * energy / volume;
 }
 
 /**
@@ -259,6 +257,12 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
   const float m = p->conserved.mass;
   p->primitives.rho = m / volume;
 
+  /* first get the initial velocities, as they were overwritten in end_density
+   */
+  p->primitives.v[0] = p->v[0];
+  p->primitives.v[1] = p->v[1];
+  p->primitives.v[2] = p->v[2];
+
   p->conserved.momentum[0] = m * p->primitives.v[0];
   p->conserved.momentum[1] = m * p->primitives.v[1];
   p->conserved.momentum[2] = m * p->primitives.v[2];
diff --git a/src/hydro/Gizmo/hydro_part.h b/src/hydro/Gizmo/hydro_part.h
index d425294671d4bc172f45c928c2290f8cfa8e093c..c4919ff173c64a4a83a5d1bf61ab82697cc03096 100644
--- a/src/hydro/Gizmo/hydro_part.h
+++ b/src/hydro/Gizmo/hydro_part.h
@@ -16,6 +16,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
+#ifndef SWIFT_GIZMO_HYDRO_PART_H
+#define SWIFT_GIZMO_HYDRO_PART_H
+
+#include "cooling_struct.h"
 
 /* Extra particle data not needed during the computation. */
 struct xpart {
@@ -26,7 +30,10 @@ struct xpart {
   /* Velocity at the last full step. */
   float v_full[3];
 
-} __attribute__((aligned(xpart_align)));
+  /* Additional data used to record cooling information */
+  struct cooling_xpart_data cooling_data;
+
+} SWIFT_STRUCT_ALIGN;
 
 /* Data of a single particle. */
 struct part {
@@ -196,4 +203,6 @@ struct part {
   /* Associated gravitas. */
   struct gpart *gpart;
 
-} __attribute__((aligned(part_align)));
+} SWIFT_STRUCT_ALIGN;
+
+#endif /* SWIFT_GIZMO_HYDRO_PART_H */
diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h
index 0bbc77f4a2384c79f7d3329c20b92990598d5c63..3015f26c6bad7f006e8cda16695c750ff40d74df 100644
--- a/src/hydro/Minimal/hydro.h
+++ b/src/hydro/Minimal/hydro.h
@@ -29,9 +29,8 @@
  * term is implemented.
  *
  * This corresponds to equations (43), (44), (45), (101), (103)  and (104) with
- * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of
- * Price, D., Journal of Computational Physics, 2012, Volume 231, Issue 3,
- * pp. 759-794.
+ * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of Price, D., Journal of Computational
+ * Physics, 2012, Volume 231, Issue 3, pp. 759-794.
  */
 
 #include "adiabatic_index.h"
@@ -40,6 +39,7 @@
 #include "equation_of_state.h"
 #include "hydro_properties.h"
 #include "kernel_hydro.h"
+#include "minmax.h"
 
 /**
  * @brief Returns the internal energy of a particle
@@ -66,9 +66,7 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
 __attribute__((always_inline)) INLINE static float hydro_get_pressure(
     const struct part *restrict p, float dt) {
 
-  const float u = p->u + p->u_dt * dt;
-
-  return gas_pressure_from_internal_energy(p->rho, u);
+  return p->force.pressure;
 }
 
 /**
@@ -98,9 +96,7 @@ __attribute__((always_inline)) INLINE static float hydro_get_entropy(
 __attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
     const struct part *restrict p, float dt) {
 
-  const float u = p->u + p->u_dt * dt;
-
-  return gas_soundspeed_from_internal_energy(p->rho, u);
+  return p->force.soundspeed;
 }
 
 /**
@@ -129,8 +125,9 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
  * @brief Modifies the thermal state of a particle to the imposed internal
  * energy
  *
- * This overrides the current state of the particle but does *not* change its
- * time-derivatives
+ * This overwrites the current state of the particle but does *not* change its
+ * time-derivatives. Internal energy, pressure, sound-speed and signal velocity
+ * will be updated.
  *
  * @param p The particle
  * @param u The new internal energy
@@ -139,13 +136,29 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy(
     struct part *restrict p, float u) {
 
   p->u = u;
+
+  /* Compute the new pressure */
+  const float pressure = gas_pressure_from_internal_energy(p->rho, p->u);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_internal_energy(p->rho, p->u);
+
+  /* Update the signal velocity */
+  const float v_sig_old = p->force.v_sig;
+  const float v_sig_new = p->force.v_sig - p->force.soundspeed + soundspeed;
+  const float v_sig = max(v_sig_old, v_sig_new);
+
+  p->force.soundspeed = soundspeed;
+  p->force.pressure = pressure;
+  p->force.v_sig = v_sig;
 }
 
 /**
  * @brief Modifies the thermal state of a particle to the imposed entropy
  *
- * This overrides the current state of the particle but does *not* change its
- * time-derivatives
+ * This overwrites the current state of the particle but does *not* change its
+ * time-derivatives. Internal energy, pressure, sound-speed and signal velocity
+ * will be updated.
  *
  * @param p The particle
  * @param S The new entropy
@@ -154,6 +167,21 @@ __attribute__((always_inline)) INLINE static void hydro_set_entropy(
     struct part *restrict p, float S) {
 
   p->u = gas_internal_energy_from_entropy(p->rho, S);
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_internal_energy(p->rho, p->u);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_internal_energy(p->rho, p->u);
+
+  /* Update the signal velocity */
+  const float v_sig_old = p->force.v_sig;
+  const float v_sig_new = p->force.v_sig - p->force.soundspeed + soundspeed;
+  const float v_sig = max(v_sig_old, v_sig_new);
+
+  p->force.soundspeed = soundspeed;
+  p->force.pressure = pressure;
+  p->force.v_sig = v_sig;
 }
 
 /**
@@ -215,7 +243,7 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
   p->density.wcount = 0.f;
   p->density.wcount_dh = 0.f;
   p->rho = 0.f;
-  p->rho_dh = 0.f;
+  p->density.rho_dh = 0.f;
 }
 
 /**
@@ -241,19 +269,14 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
 
   /* Final operation on the density (add self-contribution). */
   p->rho += p->mass * kernel_root;
-  p->rho_dh -= hydro_dimension * p->mass * kernel_root;
+  p->density.rho_dh -= hydro_dimension * p->mass * kernel_root;
   p->density.wcount += kernel_root;
 
   /* Finish the calculation by inserting the missing h-factors */
   p->rho *= h_inv_dim;
-  p->rho_dh *= h_inv_dim_plus_one;
+  p->density.rho_dh *= h_inv_dim_plus_one;
   p->density.wcount *= kernel_norm;
   p->density.wcount_dh *= h_inv * kernel_gamma * kernel_norm;
-
-  const float irho = 1.f / p->rho;
-
-  /* Compute the derivative term */
-  p->rho_dh = 1.f / (1.f + hydro_dimension_inv * p->h * p->rho_dh * irho);
 }
 
 /**
@@ -275,10 +298,22 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force(
     struct part *restrict p, struct xpart *restrict xp, int ti_current,
     double timeBase) {
 
+  /* Compute the pressure */
   const float half_dt = (ti_current - (p->ti_begin + p->ti_end) / 2) * timeBase;
   const float pressure = hydro_get_pressure(p, half_dt);
 
+  /* Compute the sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  /* Compute the "grad h" term */
+  const float rho_inv = 1.f / p->rho;
+  const float grad_h_term =
+      1.f / (1.f + hydro_dimension_inv * p->h * p->density.rho_dh * rho_inv);
+
+  /* Update variables. */
+  p->force.f = grad_h_term;
   p->force.pressure = pressure;
+  p->force.soundspeed = soundspeed;
 }
 
 /**
@@ -338,7 +373,13 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
 
   /* Drift the pressure */
   const float dt_entr = (t1 - (p->ti_begin + p->ti_end) / 2) * timeBase;
-  p->force.pressure = hydro_get_pressure(p, dt_entr);
+  const float pressure = hydro_get_pressure(p, dt_entr);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho, pressure);
+
+  p->force.pressure = pressure;
+  p->force.soundspeed = soundspeed;
 }
 
 /**
@@ -380,6 +421,15 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
 
   /* Do not 'overcool' when timestep increases */
   if (p->u + p->u_dt * half_dt < 0.5f * p->u) p->u_dt = -0.5f * p->u / half_dt;
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_internal_energy(p->rho, p->u);
+
+  /* Compute the sound speed */
+  const float soundspeed = gas_soundspeed_from_internal_energy(p->rho, p->u);
+
+  p->force.pressure = pressure;
+  p->force.soundspeed = soundspeed;
 }
 
 /**
@@ -393,6 +443,16 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
  * @param p The particle to act upon
  */
 __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part *restrict p) {}
+    struct part *restrict p) {
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_internal_energy(p->rho, p->u);
+
+  /* Compute the sound speed */
+  const float soundspeed = gas_soundspeed_from_internal_energy(p->rho, p->u);
+
+  p->force.pressure = pressure;
+  p->force.soundspeed = soundspeed;
+}
 
 #endif /* SWIFT_MINIMAL_HYDRO_H */
diff --git a/src/hydro/Minimal/hydro_debug.h b/src/hydro/Minimal/hydro_debug.h
index 0a6e50da6051fd961f4bf35f32caee311888a13e..16ae62413a0d76b7bf871e615fe5684219752fee 100644
--- a/src/hydro/Minimal/hydro_debug.h
+++ b/src/hydro/Minimal/hydro_debug.h
@@ -44,7 +44,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle(
       p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0],
       xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2],
       p->u, p->u_dt, p->force.v_sig, p->force.pressure, p->h, p->force.h_dt,
-      (int)p->density.wcount, p->mass, p->rho_dh, p->rho, p->ti_begin,
+      (int)p->density.wcount, p->mass, p->density.rho_dh, p->rho, p->ti_begin,
       p->ti_end);
 }
 
diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h
index 9e2028c978dc7cad03cfba17931f645bbfbfe1a0..169947b99e92d9bd1b0870d502a49e311820ff81 100644
--- a/src/hydro/Minimal/hydro_iact.h
+++ b/src/hydro/Minimal/hydro_iact.h
@@ -28,9 +28,8 @@
  * term is implemented.
  *
  * This corresponds to equations (43), (44), (45), (101), (103)  and (104) with
- * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of
- * Price, D., Journal of Computational Physics, 2012, Volume 231, Issue 3,
- * pp. 759-794.
+ * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of Price, D., Journal of Computational
+ * Physics, 2012, Volume 231, Issue 3, pp. 759-794.
  */
 
 #include "adiabatic_index.h"
@@ -56,7 +55,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
   kernel_deval(xi, &wi, &wi_dx);
 
   pi->rho += mj * wi;
-  pi->rho_dh -= mj * (hydro_dimension * wi + xi * wi_dx);
+  pi->density.rho_dh -= mj * (hydro_dimension * wi + xi * wi_dx);
   pi->density.wcount += wi;
   pi->density.wcount_dh -= xi * wi_dx;
 
@@ -66,7 +65,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
   kernel_deval(xj, &wj, &wj_dx);
 
   pj->rho += mi * wj;
-  pj->rho_dh -= mi * (hydro_dimension * wj + xj * wj_dx);
+  pj->density.rho_dh -= mi * (hydro_dimension * wj + xj * wj_dx);
   pj->density.wcount += wj;
   pj->density.wcount_dh -= xj * wj_dx;
 }
@@ -101,7 +100,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
   kernel_deval(xi, &wi, &wi_dx);
 
   pi->rho += mj * wi;
-  pi->rho_dh -= mj * (hydro_dimension * wi + xi * wi_dx);
+  pi->density.rho_dh -= mj * (hydro_dimension * wi + xi * wi_dx);
   pi->density.wcount += wi;
   pi->density.wcount_dh -= xi * wi_dx;
 }
@@ -153,8 +152,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   const float wj_dr = hjd_inv * wj_dx;
 
   /* Compute gradient terms */
-  const float P_over_rho2_i = pressurei / (rhoi * rhoi) * pi->rho_dh;
-  const float P_over_rho2_j = pressurej / (rhoj * rhoj) * pj->rho_dh;
+  const float P_over_rho2_i = pressurei / (rhoi * rhoi) * pi->force.f;
+  const float P_over_rho2_j = pressurej / (rhoj * rhoj) * pj->force.f;
 
   /* Compute dv dot r. */
   const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] +
@@ -166,8 +165,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */
 
   /* Compute sound speeds and signal velocity */
-  const float ci = sqrtf(hydro_gamma * pressurei / rhoi);
-  const float cj = sqrtf(hydro_gamma * pressurej / rhoj);
+  const float ci = pi->force.soundspeed;
+  const float cj = pj->force.soundspeed;
   const float v_sig = ci + cj - 3.f * mu_ij;
 
   /* Construct the full viscosity term */
@@ -264,8 +263,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   const float wj_dr = hjd_inv * wj_dx;
 
   /* Compute gradient terms */
-  const float P_over_rho2_i = pressurei / (rhoi * rhoi) * pi->rho_dh;
-  const float P_over_rho2_j = pressurej / (rhoj * rhoj) * pj->rho_dh;
+  const float P_over_rho2_i = pressurei / (rhoi * rhoi) * pi->force.f;
+  const float P_over_rho2_j = pressurej / (rhoj * rhoj) * pj->force.f;
 
   /* Compute dv dot r. */
   const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] +
@@ -277,8 +276,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */
 
   /* Compute sound speeds and signal velocity */
-  const float ci = sqrtf(hydro_gamma * pressurei / rhoi);
-  const float cj = sqrtf(hydro_gamma * pressurej / rhoj);
+  const float ci = pi->force.soundspeed;
+  const float cj = pj->force.soundspeed;
   const float v_sig = ci + cj - 3.f * mu_ij;
 
   /* Construct the full viscosity term */
diff --git a/src/hydro/Minimal/hydro_part.h b/src/hydro/Minimal/hydro_part.h
index ad65f8b44fc67f4aae6470246cbab91bc3710007..8542177278998d5e0b830dc164988611549ef24d 100644
--- a/src/hydro/Minimal/hydro_part.h
+++ b/src/hydro/Minimal/hydro_part.h
@@ -28,11 +28,12 @@
  * term is implemented.
  *
  * This corresponds to equations (43), (44), (45), (101), (103)  and (104) with
- * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of
- * Price, D., Journal of Computational Physics, 2012, Volume 231, Issue 3,
- * pp. 759-794.
+ * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of Price, D., Journal of Computational
+ * Physics, 2012, Volume 231, Issue 3, pp. 759-794.
  */
 
+#include "cooling_struct.h"
+
 /**
  * @brief Particle fields not needed during the SPH loops over neighbours.
  *
@@ -42,12 +43,16 @@
  */
 struct xpart {
 
-  float x_diff[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];
+
+  /*! Velocity at the last full step. */
+  float v_full[3];
 
-  float v_full[3]; /*!< Velocity at the last full step. */
+  /*! Additional data used to record cooling information */
+  struct cooling_xpart_data cooling_data;
 
-} __attribute__((aligned(xpart_align)));
+} SWIFT_STRUCT_ALIGN;
 
 /**
  * @brief Particle fields for the SPH particles
@@ -58,27 +63,35 @@ struct xpart {
  */
 struct part {
 
-  double x[3]; /*!< Particle position. */
+  /*! Particle position. */
+  double x[3];
 
-  float v[3]; /*!< Particle predicted velocity. */
+  /*! Particle predicted velocity. */
+  float v[3];
 
-  float a_hydro[3]; /*!< Particle acceleration. */
+  /*! Particle acceleration. */
+  float a_hydro[3];
 
-  float mass; /*!< Particle mass. */
+  /*! Particle mass. */
+  float mass;
 
-  float h; /*!< Particle smoothing length. */
+  /*! Particle smoothing length. */
+  float h;
 
-  int ti_begin; /*!< Time at the beginning of time-step. */
+  /*! Time at the beginning of time-step. */
+  int ti_begin;
 
-  int ti_end; /*!< Time at the end of time-step. */
+  /*! Time at the end of time-step. */
+  int ti_end;
 
-  float u; /*!< Particle internal energy. */
+  /*! Particle internal energy. */
+  float u;
 
-  float u_dt; /*!< Time derivative of the internal energy. */
+  /*! Time derivative of the internal energy. */
+  float u_dt;
 
-  float rho; /*!< Particle density. */
-
-  float rho_dh; /*!< Derivative of density with respect to h */
+  /*! Particle density. */
+  float rho;
 
   /* Store density/force specific stuff. */
   union {
@@ -92,10 +105,15 @@ struct part {
      */
     struct {
 
-      float wcount; /*!< Neighbour number count. */
+      /*! Neighbour number count. */
+      float wcount;
+
+      /*! Derivative of the neighbour number with respect to h. */
+      float wcount_dh;
+
+      /*! Derivative of density with respect to h */
+      float rho_dh;
 
-      float wcount_dh; /*!< Derivative of the neighbour number with respect to
-                          h. */
     } density;
 
     /**
@@ -107,19 +125,30 @@ struct part {
      */
     struct {
 
-      float pressure; /*!< Particle pressure. */
+      /*! "Grad h" term */
+      float f;
+
+      /*! Particle pressure. */
+      float pressure;
+
+      /*! Particle soundspeed. */
+      float soundspeed;
 
-      float v_sig; /*!< Particle signal velocity */
+      /*! Particle signal velocity */
+      float v_sig;
 
-      float h_dt; /*!< Time derivative of smoothing length  */
+      /*! Time derivative of smoothing length  */
+      float h_dt;
 
     } force;
   };
 
-  long long id; /*!< Particle unique ID. */
+  /*! Particle unique ID. */
+  long long id;
 
-  struct gpart* gpart; /*!< Pointer to corresponding gravity part. */
+  /*! Pointer to corresponding gravity part. */
+  struct gpart* gpart;
 
-} __attribute__((aligned(part_align)));
+} SWIFT_STRUCT_ALIGN;
 
 #endif /* SWIFT_MINIMAL_HYDRO_PART_H */
diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h
new file mode 100644
index 0000000000000000000000000000000000000000..ede16fe5181a546921db7acf8ffcbc130c5e91c5
--- /dev/null
+++ b/src/hydro/PressureEntropy/hydro.h
@@ -0,0 +1,515 @@
+/*******************************************************************************
+ * 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_PRESSURE_ENTROPY_HYDRO_H
+#define SWIFT_PRESSURE_ENTROPY_HYDRO_H
+
+/**
+ * @file PressureEntropy/hydro.h
+ * @brief Pressure-Entropy implementation of SPH (Non-neighbour loop
+ * equations)
+ *
+ * The thermal variable is the entropy (S) and the entropy is smoothed over
+ * contact discontinuities to prevent spurious surface tension.
+ *
+ * Follows eqautions (19), (21) and (22) of Hopkins, P., MNRAS, 2013,
+ * Volume 428, Issue 4, pp. 2840-2856 with a simple Balsara viscosity term.
+ */
+
+#include "adiabatic_index.h"
+#include "approx_math.h"
+#include "dimension.h"
+#include "equation_of_state.h"
+#include "hydro_properties.h"
+#include "kernel_hydro.h"
+#include "minmax.h"
+
+/**
+ * @brief Returns the internal energy of a particle
+ *
+ * @param p The particle of interest
+ * @param dt Time since the last kick
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
+    const struct part *restrict p, float dt) {
+
+  const float entropy = p->entropy + p->entropy_dt * dt;
+
+  return gas_internal_energy_from_entropy(p->rho_bar, entropy);
+}
+
+/**
+ * @brief Returns the pressure of a particle
+ *
+ * @param p The particle of interest
+ * @param dt Time since the last kick
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_pressure(
+    const struct part *restrict p, float dt) {
+
+  const float entropy = p->entropy + p->entropy_dt * dt;
+
+  return gas_pressure_from_entropy(p->rho_bar, entropy);
+}
+
+/**
+ * @brief Returns the entropy of a particle
+ *
+ * @param p The particle of interest
+ * @param dt Time since the last kick
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_entropy(
+    const struct part *restrict p, float dt) {
+
+  return p->entropy + p->entropy_dt * dt;
+}
+
+/**
+ * @brief Returns the sound speed of a particle
+ *
+ * @param p The particle of interest
+ * @param dt Time since the last kick
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
+    const struct part *restrict p, float dt) {
+
+  return p->force.soundspeed;
+}
+
+/**
+ * @brief Returns the physical density of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_density(
+    const struct part *restrict p) {
+
+  return p->rho;
+}
+
+/**
+ * @brief Returns the mass of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_mass(
+    const struct part *restrict p) {
+
+  return p->mass;
+}
+
+/**
+ * @brief Modifies the thermal state of a particle to the imposed internal
+ * energy
+ *
+ * This overwrites the current state of the particle but does *not* change its
+ * time-derivatives. Entropy, pressure, sound-speed and signal velocity will be
+ * updated.
+ *
+ * @param p The particle
+ * @param u The new internal energy
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_internal_energy(
+    struct part *restrict p, float u) {
+
+  p->entropy = gas_entropy_from_internal_energy(p->rho_bar, u);
+  p->entropy_one_over_gamma = pow_one_over_gamma(p->entropy);
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho_bar, p->entropy);
+
+  /* Compute the sound speed from the pressure*/
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho_bar, pressure);
+
+  /* Update the signal velocity */
+  const float v_sig_old = p->force.v_sig;
+  const float v_sig_new = p->force.v_sig - p->force.soundspeed + soundspeed;
+  const float v_sig = max(v_sig_old, v_sig_new);
+
+  const float rho_bar_inv = 1.f / p->rho_bar;
+
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = pressure * rho_bar_inv * rho_bar_inv;
+  p->force.v_sig = v_sig;
+}
+
+/**
+ * @brief Modifies the thermal state of a particle to the imposed entropy
+ *
+ * This overwrites the current state of the particle but does *not* change its
+ * time-derivatives. Entropy, pressure, sound-speed and signal velocity will be
+ * updated.
+ *
+ * @param p The particle
+ * @param S The new entropy
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_entropy(
+    struct part *restrict p, float S) {
+
+  p->entropy = S;
+  p->entropy_one_over_gamma = pow_one_over_gamma(p->entropy);
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho_bar, p->entropy);
+
+  /* Compute the sound speed from the pressure*/
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho_bar, pressure);
+
+  /* Update the signal velocity */
+  const float v_sig_old = p->force.v_sig;
+  const float v_sig_new = p->force.v_sig - p->force.soundspeed + soundspeed;
+  const float v_sig = max(v_sig_old, v_sig_new);
+
+  const float rho_bar_inv = 1.f / p->rho_bar;
+
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = pressure * rho_bar_inv * rho_bar_inv;
+  p->force.v_sig = v_sig;
+}
+
+/**
+ * @brief Computes the hydro time-step of a given particle
+ *
+ * @param p Pointer to the particle data
+ * @param xp Pointer to the extended particle data
+ *
+ */
+__attribute__((always_inline)) INLINE static float hydro_compute_timestep(
+    const struct part *restrict p, const struct xpart *restrict xp,
+    const struct hydro_props *restrict hydro_properties) {
+
+  const float CFL_condition = hydro_properties->CFL_condition;
+
+  /* CFL condition */
+  const float dt_cfl =
+      2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig;
+
+  return dt_cfl;
+}
+
+/**
+ * @brief Initialises the particles for the first time
+ *
+ * This function is called only once just after the ICs have been
+ * read in to do some conversions.
+ *
+ * @param p The particle to act upon
+ * @param xp The extended particle data to act upon
+ */
+__attribute__((always_inline)) INLINE static void hydro_first_init_part(
+    struct part *restrict p, struct xpart *restrict xp) {
+
+  p->ti_begin = 0;
+  p->ti_end = 0;
+  p->rho_bar = 0.f;
+  p->entropy_one_over_gamma = pow_one_over_gamma(p->entropy);
+  xp->v_full[0] = p->v[0];
+  xp->v_full[1] = p->v[1];
+  xp->v_full[2] = p->v[2];
+}
+
+/**
+ * @brief Prepares a particle for the density calculation.
+ *
+ * Zeroes all the relevant arrays in preparation for the sums taking place in
+ * the variaous density tasks
+ *
+ * @param p The particle to act upon
+ */
+__attribute__((always_inline)) INLINE static void hydro_init_part(
+    struct part *restrict p) {
+
+  p->rho = 0.f;
+  p->rho_bar = 0.f;
+  p->density.wcount = 0.f;
+  p->density.wcount_dh = 0.f;
+  p->density.rho_dh = 0.f;
+  p->density.pressure_dh = 0.f;
+
+  p->density.div_v = 0.f;
+  p->density.rot_v[0] = 0.f;
+  p->density.rot_v[1] = 0.f;
+  p->density.rot_v[2] = 0.f;
+}
+
+/**
+ * @brief Finishes the density calculation.
+ *
+ * Multiplies the density and number of neighbours by the appropiate constants
+ * and add the self-contribution term.
+ *
+ * @param p The particle to act upon
+ * @param ti_current The current time (on the integer timeline)
+ */
+__attribute__((always_inline)) INLINE static void hydro_end_density(
+    struct part *restrict p, int ti_current) {
+
+  /* Some smoothing length multiples. */
+  const float h = p->h;
+  const float h_inv = 1.0f / h;                       /* 1/h */
+  const float h_inv_dim = pow_dimension(h_inv);       /* 1/h^d */
+  const float h_inv_dim_plus_one = h_inv_dim * h_inv; /* 1/h^(d+1) */
+
+  /* Final operation on the density (add self-contribution). */
+  p->rho += p->mass * kernel_root;
+  p->rho_bar += p->mass * p->entropy_one_over_gamma * kernel_root;
+  p->density.rho_dh -= hydro_dimension * p->mass * kernel_root;
+  p->density.pressure_dh -=
+      hydro_dimension * p->mass * p->entropy_one_over_gamma * kernel_root;
+  p->density.wcount += kernel_root;
+
+  /* Finish the calculation by inserting the missing h-factors */
+  p->rho *= h_inv_dim;
+  p->rho_bar *= h_inv_dim;
+  p->density.rho_dh *= h_inv_dim_plus_one;
+  p->density.pressure_dh *= h_inv_dim_plus_one;
+  p->density.wcount *= kernel_norm;
+  p->density.wcount_dh *= h_inv * kernel_gamma * kernel_norm;
+
+  const float rho_inv = 1.f / p->rho;
+  const float entropy_minus_one_over_gamma = 1.f / p->entropy_one_over_gamma;
+
+  /* Final operation on the weighted density */
+  p->rho_bar *= entropy_minus_one_over_gamma;
+
+  /* Finish calculation of the velocity curl components */
+  p->density.rot_v[0] *= h_inv_dim_plus_one * rho_inv;
+  p->density.rot_v[1] *= h_inv_dim_plus_one * rho_inv;
+  p->density.rot_v[2] *= h_inv_dim_plus_one * rho_inv;
+
+  /* Finish calculation of the velocity divergence */
+  p->density.div_v *= h_inv_dim_plus_one * rho_inv;
+}
+
+/**
+ * @brief Prepare a particle for the force calculation.
+ *
+ * Computes viscosity term, conduction term and smoothing length gradient terms.
+ *
+ * @param p The particle to act upon
+ * @param xp The extended particle data to act upon
+ * @param ti_current The current time (on the timeline)
+ * @param timeBase The minimal time-step size
+ */
+__attribute__((always_inline)) INLINE static void hydro_prepare_force(
+    struct part *restrict p, struct xpart *restrict xp, int ti_current,
+    double timeBase) {
+
+  const float fac_mu = 1.f; /* Will change with cosmological integration */
+
+  /* Compute the norm of the curl */
+  const float curl_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] +
+                             p->density.rot_v[1] * p->density.rot_v[1] +
+                             p->density.rot_v[2] * p->density.rot_v[2]);
+
+  /* Compute the norm of div v */
+  const float abs_div_v = fabsf(p->density.div_v);
+
+  /* Compute the pressure */
+  const float half_dt = (ti_current - (p->ti_begin + p->ti_end) / 2) * timeBase;
+  const float entropy = hydro_get_entropy(p, half_dt);
+  const float pressure = gas_pressure_from_entropy(p->rho_bar, entropy);
+
+  /* Compute the sound speed from the pressure*/
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho_bar, pressure);
+
+  /* Compute the Balsara switch */
+  const float balsara =
+      abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed / fac_mu / p->h);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_bar_inv = 1.f / p->rho_bar;
+  const float P_over_rho2 = pressure * rho_bar_inv * rho_bar_inv;
+
+  /* Compute "grad h" term (note we use rho here and not rho_bar !)*/
+  const float rho_inv = 1.f / p->rho;
+  const float entropy_minus_one_over_gamma = 1.f / p->entropy_one_over_gamma;
+  const float rho_dh =
+      1.f / (1.f + hydro_dimension_inv * p->h * p->density.rho_dh * rho_inv);
+  const float pressure_dh = p->density.pressure_dh * rho_inv * p->h *
+                            hydro_dimension_inv * entropy_minus_one_over_gamma;
+
+  const float grad_h_term = rho_dh * pressure_dh;
+
+  /* Update variables. */
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = P_over_rho2;
+  p->force.balsara = balsara;
+  p->force.f = grad_h_term;
+}
+
+/**
+ * @brief Reset acceleration fields of a particle
+ *
+ * Resets all hydro acceleration and time derivative fields in preparation
+ * for the sums taking place in the variaous force tasks
+ *
+ * @param p The particle to act upon
+ */
+__attribute__((always_inline)) INLINE static void hydro_reset_acceleration(
+    struct part *restrict p) {
+
+  /* Reset the acceleration. */
+  p->a_hydro[0] = 0.0f;
+  p->a_hydro[1] = 0.0f;
+  p->a_hydro[2] = 0.0f;
+
+  /* Reset the time derivatives. */
+  p->entropy_dt = 0.0f;
+  p->force.h_dt = 0.0f;
+
+  /* Reset maximal signal velocity */
+  p->force.v_sig = 0.0f;
+}
+
+/**
+ * @brief Predict additional particle fields forward in time when drifting
+ *
+ * @param p The particle
+ * @param xp The extended data of the particle
+ * @param dt The drift time-step.
+ * @param t0 The time at the start of the drift (on the timeline).
+ * @param t1 The time at the end of the drift (on the timeline).
+ * @param timeBase The minimal time-step size
+ */
+__attribute__((always_inline)) INLINE static void hydro_predict_extra(
+    struct part *restrict p, const struct xpart *restrict xp, float dt, int t0,
+    int t1, double timeBase) {
+
+  const float h_inv = 1.f / p->h;
+
+  /* Predict smoothing length */
+  const float w1 = p->force.h_dt * h_inv * dt;
+  if (fabsf(w1) < 0.2f)
+    p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */
+  else
+    p->h *= expf(w1);
+
+  /* Predict density */
+  const float w2 = -hydro_dimension * w1;
+  if (fabsf(w2) < 0.2f) {
+    p->rho *= approx_expf(w2); /* 4th order expansion of exp(w) */
+    p->rho_bar *= approx_expf(w2);
+  } else {
+    p->rho *= expf(w2);
+    p->rho_bar *= expf(w2);
+  }
+
+  /* Drift the entropy */
+  const float dt_entr = (t1 - (p->ti_begin + p->ti_end) / 2) * timeBase;
+  const float entropy = hydro_get_entropy(p, dt_entr);
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho_bar, entropy);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho_bar, pressure);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_bar_inv = 1.f / p->rho_bar;
+  const float P_over_rho2 = pressure * rho_bar_inv * rho_bar_inv;
+
+  /* Update the variables */
+  p->entropy_one_over_gamma = pow_one_over_gamma(entropy);
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = P_over_rho2;
+}
+
+/**
+ * @brief Finishes the force calculation.
+ *
+ * Multiplies the forces and accelerationsby the appropiate constants
+ *
+ * @param p The particle to act upon
+ */
+__attribute__((always_inline)) INLINE static void hydro_end_force(
+    struct part *restrict p) {
+
+  p->force.h_dt *= p->h * hydro_dimension_inv;
+
+  p->entropy_dt *=
+      0.5f * hydro_gamma_minus_one * pow_minus_gamma_minus_one(p->rho_bar);
+}
+
+/**
+ * @brief Kick the additional variables
+ *
+ * @param p The particle to act upon
+ * @param xp The particle extended data to act upon
+ * @param dt The time-step for this kick
+ * @param half_dt The half time-step for this kick
+ */
+__attribute__((always_inline)) INLINE static void hydro_kick_extra(
+    struct part *restrict p, struct xpart *restrict xp, float dt,
+    float half_dt) {
+
+  /* Do not decrease the entropy (temperature) by more than a factor of 2*/
+  const float entropy_change = p->entropy_dt * dt;
+  if (entropy_change > -0.5f * p->entropy)
+    p->entropy += entropy_change;
+  else
+    p->entropy *= 0.5f;
+
+  /* Do not 'overcool' when timestep increases */
+  if (p->entropy + p->entropy_dt * half_dt < 0.5f * p->entropy)
+    p->entropy_dt = -0.5f * p->entropy / half_dt;
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho_bar, p->entropy);
+
+  /* Compute the new sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho_bar, pressure);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_bar_inv = 1.f / p->rho_bar;
+  const float P_over_rho2 = pressure * rho_bar_inv * rho_bar_inv;
+
+  p->entropy_one_over_gamma = pow_one_over_gamma(p->entropy);
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = P_over_rho2;
+}
+
+/**
+ *  @brief Converts hydro quantity of a particle at the start of a run
+ *
+ * Requires the density to be known
+ *
+ * @param p The particle to act upon
+ */
+__attribute__((always_inline)) INLINE static void hydro_convert_quantities(
+    struct part *restrict p) {
+
+  /* We read u in the entropy field. We now get S from u */
+  p->entropy = gas_entropy_from_internal_energy(p->rho_bar, p->entropy);
+  p->entropy_one_over_gamma = pow_one_over_gamma(p->entropy);
+
+  /* Compute the pressure */
+  const float pressure = gas_pressure_from_entropy(p->rho_bar, p->entropy);
+
+  /* Compute the sound speed */
+  const float soundspeed = gas_soundspeed_from_pressure(p->rho_bar, pressure);
+
+  /* Divide the pressure by the density squared to get the SPH term */
+  const float rho_bar_inv = 1.f / p->rho_bar;
+  const float P_over_rho2 = pressure * rho_bar_inv * rho_bar_inv;
+
+  p->force.soundspeed = soundspeed;
+  p->force.P_over_rho2 = P_over_rho2;
+}
+
+#endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_H */
diff --git a/src/hydro/PressureEntropy/hydro_debug.h b/src/hydro/PressureEntropy/hydro_debug.h
new file mode 100644
index 0000000000000000000000000000000000000000..486543793515795092e7cc97fe7b567b8230be3b
--- /dev/null
+++ b/src/hydro/PressureEntropy/hydro_debug.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (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_PRESSURE_ENTROPY_HYDRO_DEBUG_H
+#define SWIFT_PRESSURE_ENTROPY_HYDRO_DEBUG_H
+
+/**
+ * @file PressureEntropy/hydro_debug.h
+ * @brief Pressure-Entropy implementation of SPH (Debugging routines)
+ *
+ * The thermal variable is the entropy (S) and the entropy is smoothed over
+ * contact discontinuities to prevent spurious surface tension.
+ *
+ * Follows eqautions (19), (21) and (22) of Hopkins, P., MNRAS, 2013,
+ * Volume 428, Issue 4, pp. 2840-2856 with a simple Balsara viscosity term.
+ */
+
+__attribute__((always_inline)) INLINE static void hydro_debug_particle(
+    const struct part* p, const struct xpart* xp) {
+  printf(
+      "x=[%.3e,%.3e,%.3e], "
+      "v=[%.3e,%.3e,%.3e],v_full=[%.3e,%.3e,%.3e] \n a=[%.3e,%.3e,%.3e],\n "
+      "h=%.3e, wcount=%.3f, wcount_dh=%.3e, m=%.3e, dh_drho=%.3e, rho=%.3e, "
+      "rho_bar=%.3e, P=%.3e, dP_dh=%.3e, P_over_rho2=%.3e, S=%.3e, S^1/g=%.3e, "
+      "dS/dt=%.3e,\nc=%.3e v_sig=%e dh/dt=%.3e t_begin=%d, t_end=%d\n",
+      p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0],
+      xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2],
+      p->h, p->density.wcount, p->density.wcount_dh, p->mass, p->density.rho_dh,
+      p->rho, p->rho_bar, hydro_get_pressure(p, 0.), p->density.pressure_dh,
+      p->force.P_over_rho2, p->entropy, p->entropy_one_over_gamma,
+      p->entropy_dt, p->force.soundspeed, p->force.v_sig, p->force.h_dt,
+      p->ti_begin, p->ti_end);
+}
+
+#endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_DEBUG_H */
diff --git a/src/hydro/PressureEntropy/hydro_iact.h b/src/hydro/PressureEntropy/hydro_iact.h
new file mode 100644
index 0000000000000000000000000000000000000000..18e22233f6f53e488119a58a988ba4c9faf3db36
--- /dev/null
+++ b/src/hydro/PressureEntropy/hydro_iact.h
@@ -0,0 +1,399 @@
+/*******************************************************************************
+ * 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_PRESSURE_ENTROPY_HYDRO_IACT_H
+#define SWIFT_PRESSURE_ENTROPY_HYDRO_IACT_H
+
+/**
+ * @file PressureEntropy/hydro_iact.h
+ * @brief Pressure-Entropy implementation of SPH (Neighbour loop equations)
+ *
+ * The thermal variable is the entropy (S) and the entropy is smoothed over
+ * contact discontinuities to prevent spurious surface tension.
+ *
+ * Follows eqautions (19), (21) and (22) of Hopkins, P., MNRAS, 2013,
+ * Volume 428, Issue 4, pp. 2840-2856 with a simple Balsara viscosity term.
+ */
+
+/**
+ * @brief Density loop
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_density(
+    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+
+  float wi, wi_dx;
+  float wj, wj_dx;
+  float dv[3], curlvr[3];
+
+  /* Get the masses. */
+  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;
+
+  /* Compute the kernel function for pi */
+  const float hi_inv = 1.f / hi;
+  const float ui = r * hi_inv;
+  kernel_deval(ui, &wi, &wi_dx);
+
+  /* Compute contribution to the density */
+  pi->rho += mj * wi;
+  pi->density.rho_dh -= mj * (hydro_dimension * wi + ui * wi_dx);
+
+  /* Compute contribution to the number of neighbours */
+  pi->density.wcount += wi;
+  pi->density.wcount_dh -= ui * wi_dx;
+
+  /* Compute contribution to the weighted density */
+  pi->rho_bar += mj * pj->entropy_one_over_gamma * wi;
+  pi->density.pressure_dh -=
+      mj * pj->entropy_one_over_gamma * (hydro_dimension * wi + ui * wi_dx);
+
+  /* Compute the kernel function for pj */
+  const float hj_inv = 1.f / hj;
+  const float uj = r * hj_inv;
+  kernel_deval(uj, &wj, &wj_dx);
+
+  /* Compute contribution to the density */
+  pj->rho += mi * wj;
+  pj->density.rho_dh -= mi * (hydro_dimension * wj + uj * wj_dx);
+
+  /* Compute contribution to the number of neighbours */
+  pj->density.wcount += wj;
+  pj->density.wcount_dh -= uj * wj_dx;
+
+  /* Compute contribution to the weighted density */
+  pj->rho_bar += mi * pi->entropy_one_over_gamma * wj;
+  pj->density.pressure_dh -=
+      mi * pi->entropy_one_over_gamma * (hydro_dimension * wj + uj * wj_dx);
+
+  const float faci = mj * wi_dx * r_inv;
+  const float facj = mi * wj_dx * r_inv;
+
+  /* Compute dv dot r */
+  dv[0] = pi->v[0] - pj->v[0];
+  dv[1] = pi->v[1] - pj->v[1];
+  dv[2] = pi->v[2] - pj->v[2];
+  const float dvdr = dv[0] * dx[0] + dv[1] * dx[1] + dv[2] * dx[2];
+
+  pi->density.div_v -= faci * dvdr;
+  pj->density.div_v -= facj * dvdr;
+
+  /* Compute dv cross r */
+  curlvr[0] = dv[1] * dx[2] - dv[2] * dx[1];
+  curlvr[1] = dv[2] * dx[0] - dv[0] * dx[2];
+  curlvr[2] = dv[0] * dx[1] - dv[1] * dx[0];
+
+  pi->density.rot_v[0] += faci * curlvr[0];
+  pi->density.rot_v[1] += faci * curlvr[1];
+  pi->density.rot_v[2] += faci * curlvr[2];
+
+  pj->density.rot_v[0] += facj * curlvr[0];
+  pj->density.rot_v[1] += facj * curlvr[1];
+  pj->density.rot_v[2] += facj * curlvr[2];
+}
+
+/**
+ * @brief Density loop (Vectorized version)
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_vec_density(
+    float *R2, float *Dx, float *Hi, float *Hj, struct part **pi,
+    struct part **pj) {
+
+  error("Vectorized version of Pressure-Entropy SPH routine not existant yet.");
+}
+
+/**
+ * @brief Density loop (non-symmetric version)
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
+    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+
+  float wi, wi_dx;
+  float dv[3], curlvr[3];
+
+  /* Get the masses. */
+  const float mj = pj->mass;
+
+  /* Get r and r inverse. */
+  const float r = sqrtf(r2);
+  const float ri = 1.0f / r;
+
+  /* Compute the kernel function */
+  const float h_inv = 1.0f / hi;
+  const float ui = r * h_inv;
+  kernel_deval(ui, &wi, &wi_dx);
+
+  /* Compute contribution to the density */
+  pi->rho += mj * wi;
+  pi->density.rho_dh -= mj * (hydro_dimension * wi + ui * wi_dx);
+
+  /* Compute contribution to the number of neighbours */
+  pi->density.wcount += wi;
+  pi->density.wcount_dh -= ui * wi_dx;
+
+  /* Compute contribution to the weighted density */
+  pi->rho_bar += mj * pj->entropy_one_over_gamma * wi;
+  pi->density.pressure_dh -=
+      mj * pj->entropy_one_over_gamma * (hydro_dimension * wi + ui * wi_dx);
+
+  const float fac = mj * wi_dx * ri;
+
+  /* Compute dv dot r */
+  dv[0] = pi->v[0] - pj->v[0];
+  dv[1] = pi->v[1] - pj->v[1];
+  dv[2] = pi->v[2] - pj->v[2];
+  const float dvdr = dv[0] * dx[0] + dv[1] * dx[1] + dv[2] * dx[2];
+  pi->density.div_v -= fac * dvdr;
+
+  /* Compute dv cross r */
+  curlvr[0] = dv[1] * dx[2] - dv[2] * dx[1];
+  curlvr[1] = dv[2] * dx[0] - dv[0] * dx[2];
+  curlvr[2] = dv[0] * dx[1] - dv[1] * dx[0];
+
+  pi->density.rot_v[0] += fac * curlvr[0];
+  pi->density.rot_v[1] += fac * curlvr[1];
+  pi->density.rot_v[2] += fac * curlvr[2];
+}
+
+/**
+ * @brief Density loop (non-symmetric vectorized version)
+ */
+__attribute__((always_inline)) INLINE static void
+runner_iact_nonsym_vec_density(float *R2, float *Dx, float *Hi, float *Hj,
+                               struct part **pi, struct part **pj) {
+
+  error("Vectorized version of Pressure-Entropy SPH routine not existant yet.");
+}
+
+/**
+ * @brief Force loop
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_force(
+    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+
+  float wi, wj, wi_dx, wj_dx;
+
+  const float fac_mu = 1.f; /* Will change with cosmological integration */
+
+  const float r = sqrtf(r2);
+  const float r_inv = 1.0f / r;
+
+  /* Get some values in local variables. */
+  const float mi = pi->mass;
+  const float mj = pj->mass;
+  const float rhoi = pi->rho;
+  const float rhoj = pj->rho;
+
+  /* Get the kernel for hi. */
+  const float hi_inv = 1.0f / hi;
+  const float hid_inv = pow_dimension_plus_one(hi_inv); /* 1/h^(d+1) */
+  const float ui = r * hi_inv;
+  kernel_deval(ui, &wi, &wi_dx);
+  const float wi_dr = hid_inv * wi_dx;
+
+  /* Get the kernel for hj. */
+  const float hj_inv = 1.0f / hj;
+  const float hjd_inv = pow_dimension_plus_one(hj_inv); /* 1/h^(d+1) */
+  const float xj = r * hj_inv;
+  kernel_deval(xj, &wj, &wj_dx);
+  const float wj_dr = hjd_inv * wj_dx;
+
+  /* Compute gradient terms */
+  const float f_i = pi->force.f;
+  const float f_j = pj->force.f;
+
+  /* Compute Pressure terms */
+  const float P_over_rho2_i = pi->force.P_over_rho2;
+  const float P_over_rho2_j = pj->force.P_over_rho2;
+
+  /* Compute entropy terms */
+  const float S_gamma_i = pi->entropy_one_over_gamma;
+  const float S_gamma_j = pj->entropy_one_over_gamma;
+
+  /* Compute sound speeds */
+  const float ci = pi->force.soundspeed;
+  const float cj = pj->force.soundspeed;
+
+  /* Compute dv dot r. */
+  const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] +
+                     (pi->v[1] - pj->v[1]) * dx[1] +
+                     (pi->v[2] - pj->v[2]) * dx[2];
+
+  /* Balsara term */
+  const float balsara_i = pi->force.balsara;
+  const float balsara_j = pj->force.balsara;
+
+  /* Are the particles moving towards each others ? */
+  const float omega_ij = fminf(dvdr, 0.f);
+  const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */
+
+  /* Signal velocity */
+  const float v_sig = ci + cj - 3.f * mu_ij;
+
+  /* Now construct the full viscosity term */
+  const float rho_ij = 0.5f * (rhoi + rhoj);
+  const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij *
+                     (balsara_i + balsara_j) / rho_ij;
+
+  /* Now, convolve with the kernel */
+  const float visc_term = 0.5f * visc * (wi_dr + wj_dr);
+  const float sph_term = (S_gamma_j / S_gamma_i - f_i) * P_over_rho2_i * wi_dr +
+                         (S_gamma_i / S_gamma_j - f_j) * P_over_rho2_j * wj_dr;
+
+  /* Eventually got the acceleration */
+  const float acc = (visc_term + sph_term) * r_inv;
+
+  /* Use the force Luke ! */
+  pi->a_hydro[0] -= mj * acc * dx[0];
+  pi->a_hydro[1] -= mj * acc * dx[1];
+  pi->a_hydro[2] -= mj * acc * dx[2];
+
+  pj->a_hydro[0] += mi * acc * dx[0];
+  pj->a_hydro[1] += mi * acc * dx[1];
+  pj->a_hydro[2] += mi * acc * dx[2];
+
+  /* Get the time derivative for h. */
+  pi->force.h_dt -= mj * dvdr * r_inv / rhoj * wi_dr;
+  pj->force.h_dt -= mi * dvdr * r_inv / rhoi * wj_dr;
+
+  /* Update the signal velocity. */
+  pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig);
+  pj->force.v_sig = fmaxf(pj->force.v_sig, v_sig);
+
+  /* Change in entropy */
+  pi->entropy_dt += mj * visc_term * r_inv * dvdr;
+  pj->entropy_dt += mi * visc_term * r_inv * dvdr;
+}
+
+/**
+ * @brief Force loop (Vectorized version)
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_vec_force(
+    float *R2, float *Dx, float *Hi, float *Hj, struct part **pi,
+    struct part **pj) {
+
+  error("Vectorized version of Pressure-Entropy SPH routine not existant yet.");
+}
+
+/**
+ * @brief Force loop (non-symmetric version)
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
+    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+
+  float wi, wj, wi_dx, wj_dx;
+
+  const float fac_mu = 1.f; /* Will change with cosmological integration */
+
+  const float r = sqrtf(r2);
+  const float r_inv = 1.0f / r;
+
+  /* Get some values in local variables. */
+  // const float mi = pi->mass;
+  const float mj = pj->mass;
+  const float rhoi = pi->rho;
+  const float rhoj = pj->rho;
+
+  /* Get the kernel for hi. */
+  const float hi_inv = 1.0f / hi;
+  const float hid_inv = pow_dimension_plus_one(hi_inv); /* 1/h^(d+1) */
+  const float ui = r * hi_inv;
+  kernel_deval(ui, &wi, &wi_dx);
+  const float wi_dr = hid_inv * wi_dx;
+
+  /* Get the kernel for hj. */
+  const float hj_inv = 1.0f / hj;
+  const float hjd_inv = pow_dimension_plus_one(hj_inv); /* 1/h^(d+1) */
+  const float xj = r * hj_inv;
+  kernel_deval(xj, &wj, &wj_dx);
+  const float wj_dr = hjd_inv * wj_dx;
+
+  /* Compute gradient terms */
+  const float f_i = pi->force.f;
+  const float f_j = pj->force.f;
+
+  /* Compute Pressure terms */
+  const float P_over_rho2_i = pi->force.P_over_rho2;
+  const float P_over_rho2_j = pj->force.P_over_rho2;
+
+  /* Compute entropy terms */
+  const float S_gamma_i = pi->entropy_one_over_gamma;
+  const float S_gamma_j = pj->entropy_one_over_gamma;
+
+  /* Compute sound speeds */
+  const float ci = pi->force.soundspeed;
+  const float cj = pj->force.soundspeed;
+
+  /* Compute dv dot r. */
+  const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] +
+                     (pi->v[1] - pj->v[1]) * dx[1] +
+                     (pi->v[2] - pj->v[2]) * dx[2];
+
+  /* Balsara term */
+  const float balsara_i = pi->force.balsara;
+  const float balsara_j = pj->force.balsara;
+
+  /* Are the particles moving towards each others ? */
+  const float omega_ij = fminf(dvdr, 0.f);
+  const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */
+
+  /* Signal velocity */
+  const float v_sig = ci + cj - 3.f * mu_ij;
+
+  /* Now construct the full viscosity term */
+  const float rho_ij = 0.5f * (rhoi + rhoj);
+  const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij *
+                     (balsara_i + balsara_j) / rho_ij;
+
+  /* Now, convolve with the kernel */
+  const float visc_term = 0.5f * visc * (wi_dr + wj_dr);
+  const float sph_term = (S_gamma_j / S_gamma_i - f_i) * P_over_rho2_i * wi_dr +
+                         (S_gamma_i / S_gamma_j - f_j) * P_over_rho2_j * wj_dr;
+
+  /* Eventually got the acceleration */
+  const float acc = (visc_term + sph_term) * r_inv;
+
+  /* Use the force Luke ! */
+  pi->a_hydro[0] -= mj * acc * dx[0];
+  pi->a_hydro[1] -= mj * acc * dx[1];
+  pi->a_hydro[2] -= mj * acc * dx[2];
+
+  /* Get the time derivative for h. */
+  pi->force.h_dt -= mj * dvdr * r_inv / rhoj * wi_dr;
+
+  /* Update the signal velocity. */
+  pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig);
+
+  /* Change in entropy */
+  pi->entropy_dt += mj * visc_term * r_inv * dvdr;
+}
+
+/**
+ * @brief Force loop (Vectorized non-symmetric version)
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_nonsym_vec_force(
+    float *R2, float *Dx, float *Hi, float *Hj, struct part **pi,
+    struct part **pj) {
+
+  error("Vectorized version of Pressure-Entropy SPH routine not existant yet.");
+}
+
+#endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_IACT_H */
diff --git a/src/hydro/PressureEntropy/hydro_io.h b/src/hydro/PressureEntropy/hydro_io.h
new file mode 100644
index 0000000000000000000000000000000000000000..9914a656466f3f0d0a5eeb79b511706d7068ffc6
--- /dev/null
+++ b/src/hydro/PressureEntropy/hydro_io.h
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (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_PRESSURE_ENTROPY_HYDRO_IO_H
+#define SWIFT_PRESSURE_ENTROPY_HYDRO_IO_H
+
+/**
+ * @file PressureEntropy/hydro_io.h
+ * @brief Pressure-Entropy implementation of SPH (i/o routines)
+ *
+ * The thermal variable is the entropy (S) and the entropy is smoothed over
+ * contact discontinuities to prevent spurious surface tension.
+ *
+ * Follows eqautions (19), (21) and (22) of Hopkins, P., MNRAS, 2013,
+ * Volume 428, Issue 4, pp. 2840-2856 with a simple Balsara viscosity term.
+ */
+
+#include "adiabatic_index.h"
+#include "hydro.h"
+#include "io_properties.h"
+#include "kernel_hydro.h"
+
+/**
+ * @brief Specifies which particle fields to read from a dataset
+ *
+ * @param parts The particle array.
+ * @param list The list of i/o properties to read.
+ * @param num_fields The number of i/o fields to read.
+ */
+void hydro_read_particles(struct part* parts, struct io_props* list,
+                          int* num_fields) {
+
+  *num_fields = 8;
+
+  /* List what we want to read */
+  list[0] = io_make_input_field("Coordinates", DOUBLE, 3, COMPULSORY,
+                                UNIT_CONV_LENGTH, parts, x);
+  list[1] = io_make_input_field("Velocities", FLOAT, 3, COMPULSORY,
+                                UNIT_CONV_SPEED, parts, v);
+  list[2] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS,
+                                parts, mass);
+  list[3] = io_make_input_field("SmoothingLength", FLOAT, 1, COMPULSORY,
+                                UNIT_CONV_LENGTH, parts, h);
+  list[4] =
+      io_make_input_field("InternalEnergy", FLOAT, 1, COMPULSORY,
+                          UNIT_CONV_ENTROPY_PER_UNIT_MASS, parts, entropy);
+  list[5] = io_make_input_field("ParticleIDs", ULONGLONG, 1, COMPULSORY,
+                                UNIT_CONV_NO_UNITS, parts, id);
+  list[6] = io_make_input_field("Accelerations", FLOAT, 3, OPTIONAL,
+                                UNIT_CONV_ACCELERATION, parts, a_hydro);
+  list[7] = io_make_input_field("Density", FLOAT, 1, OPTIONAL,
+                                UNIT_CONV_DENSITY, parts, rho);
+}
+
+float convert_u(struct engine* e, struct part* p) {
+
+  return hydro_get_internal_energy(p, 0);
+}
+
+float convert_P(struct engine* e, struct part* p) {
+
+  return hydro_get_pressure(p, 0);
+}
+
+/**
+ * @brief Specifies which particle fields to write to a dataset
+ *
+ * @param parts The 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) {
+
+  *num_fields = 11;
+
+  /* List what we want to write */
+  list[0] = io_make_output_field("Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH,
+                                 parts, x);
+  list[1] =
+      io_make_output_field("Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, v);
+  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,
+                                 parts, h);
+  list[4] = io_make_output_field_convert_part("InternalEnergy", FLOAT, 1,
+                                              UNIT_CONV_ENERGY_PER_UNIT_MASS,
+                                              parts, entropy, convert_u);
+  list[5] = io_make_output_field("ParticleIDs", ULONGLONG, 1,
+                                 UNIT_CONV_NO_UNITS, parts, id);
+  list[6] = io_make_output_field("Acceleration", FLOAT, 3,
+                                 UNIT_CONV_ACCELERATION, parts, a_hydro);
+  list[7] =
+      io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho);
+  list[8] = io_make_output_field(
+      "Entropy", FLOAT, 1, UNIT_CONV_ENTROPY_PER_UNIT_MASS, parts, entropy);
+  list[9] = io_make_output_field_convert_part(
+      "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, rho, convert_P);
+  list[10] = io_make_output_field("WeightedDensity", FLOAT, 1,
+                                  UNIT_CONV_DENSITY, parts, rho_bar);
+}
+
+/**
+ * @brief Writes the current model of SPH to the file
+ * @param h_grpsph The HDF5 group in which to write
+ */
+void writeSPHflavour(hid_t h_grpsph) {
+
+  /* Viscosity and thermal conduction */
+  /* Nothing in this minimal model... */
+  writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "No treatment");
+  writeAttribute_s(
+      h_grpsph, "Viscosity Model",
+      "as in Springel (2005), i.e. Monaghan (1992) with Balsara (1995) switch");
+  writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha);
+  writeAttribute_f(h_grpsph, "Viscosity beta", 3.f);
+
+  /* Time integration properties */
+  writeAttribute_f(h_grpsph, "Maximal Delta u change over dt",
+                   const_max_u_change);
+}
+
+/**
+ * @brief Are we writing entropy in the internal energy field ?
+ *
+ * @return 1 if entropy is in 'internal energy', 0 otherwise.
+ */
+int writeEntropyFlag() { return 0; }
+
+#endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_IO_H */
diff --git a/src/hydro/PressureEntropy/hydro_part.h b/src/hydro/PressureEntropy/hydro_part.h
new file mode 100644
index 0000000000000000000000000000000000000000..cac585ff79bae737f0e5c09860a38536cbf3a38c
--- /dev/null
+++ b/src/hydro/PressureEntropy/hydro_part.h
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * 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_PRESSURE_ENTROPY_HYDRO_PART_H
+#define SWIFT_PRESSURE_ENTROPY_HYDRO_PART_H
+
+/**
+ * @file PressureEntropy/hydro_part.h
+ * @brief Pressure-Entropy implementation of SPH (Particle definition)
+ *
+ * The thermal variable is the entropy (S) and the entropy is smoothed over
+ * contact discontinuities to prevent spurious surface tension.
+ *
+ * Follows eqautions (19), (21) and (22) of Hopkins, P., MNRAS, 2013,
+ * Volume 428, Issue 4, pp. 2840-2856 with a simple Balsara viscosity term.
+ */
+
+#include "cooling_struct.h"
+
+/* Extra particle data not needed during the SPH loops over neighbours. */
+struct xpart {
+
+  /*! Offset between current position and position at last tree rebuild. */
+  float x_diff[3];
+
+  /*! Velocity at the last full step. */
+  float v_full[3];
+
+  /*! Additional data used to record cooling information */
+  struct cooling_xpart_data cooling_data;
+
+} SWIFT_STRUCT_ALIGN;
+
+/* Data of a single particle. */
+struct part {
+
+  /*! Particle position. */
+  double x[3];
+
+  /*! Particle predicted velocity. */
+  float v[3];
+
+  /*! Particle acceleration. */
+  float a_hydro[3];
+
+  /*! Particle cutoff radius. */
+  float h;
+
+  /*! Particle mass. */
+  float mass;
+
+  /*! Particle time of beginning of time-step. */
+  int ti_begin;
+
+  /*! Particle time of end of time-step. */
+  int ti_end;
+
+  /*! Particle density. */
+  float rho;
+
+  /*! Particle weighted density */
+  float rho_bar;
+
+  /*! Particle entropy. */
+  float entropy;
+
+  /*! Entropy time derivative */
+  float entropy_dt;
+
+  /*! Particle entropy to the power 1/gamma. */
+  float entropy_one_over_gamma;
+
+  union {
+
+    struct {
+
+      /*! Number of neighbours. */
+      float wcount;
+
+      /*! Number of neighbours spatial derivative. */
+      float wcount_dh;
+
+      /*! Derivative of density with respect to h */
+      float rho_dh;
+
+      /*! Derivative of pressure with respect to h */
+      float pressure_dh;
+
+      /*! Particle velocity curl. */
+      float rot_v[3];
+
+      /*! Particle velocity divergence. */
+      float div_v;
+
+    } density;
+
+    struct {
+
+      /*! Balsara switch */
+      float balsara;
+
+      /*! "Grad h" term */
+      float f;
+
+      /*! Pressure term */
+      float P_over_rho2;
+
+      /*! Particle sound speed. */
+      float soundspeed;
+
+      /*! Signal velocity. */
+      float v_sig;
+
+      /*! Time derivative of the smoothing length */
+      float h_dt;
+
+    } force;
+  };
+
+  /*! Particle ID. */
+  long long id;
+
+  /*! Pointer to corresponding gravity part. */
+  struct gpart* gpart;
+
+} SWIFT_STRUCT_ALIGN;
+
+#endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_PART_H */
diff --git a/src/hydro_io.h b/src/hydro_io.h
index f0a619b90b774574c434007b1c01a0e55e75e464..05ae94ade7b103ff1b584dc2447cbab40479d1fc 100644
--- a/src/hydro_io.h
+++ b/src/hydro_io.h
@@ -26,6 +26,8 @@
 #include "./hydro/Minimal/hydro_io.h"
 #elif defined(GADGET2_SPH)
 #include "./hydro/Gadget2/hydro_io.h"
+#elif defined(HOPKINS_PE_SPH)
+#include "./hydro/PressureEntropy/hydro_io.h"
 #elif defined(DEFAULT_SPH)
 #include "./hydro/Default/hydro_io.h"
 #elif defined(GIZMO_SPH)
diff --git a/src/parallel_io.c b/src/parallel_io.c
index 0da34d4dad114db0920c8e8f3bb617295ff3da96..66c9203e39e56d520eeace8858b0c618b45e6a22 100644
--- a/src/parallel_io.c
+++ b/src/parallel_io.c
@@ -486,6 +486,11 @@ void read_ic_parallel(char* fileName, const struct UnitSystem* internal_units,
     }
   }
 
+  /* Convert the dimensions of the box */
+  for (int j = 0; j < 3; j++)
+    dim[j] *=
+        units_conversion_factor(ic_units, internal_units, UNIT_CONV_LENGTH);
+
   /* Allocate memory to store SPH particles */
   *Ngas = N[0];
   if (posix_memalign((void*)parts, part_align, (*Ngas) * sizeof(struct part)) !=
diff --git a/src/part.h b/src/part.h
index ea895e6e0295d6a8b63309c7bd6855daa2cf7d64..6832e0c6c2e0f2c324d90629447cf6a5e809d6fb 100644
--- a/src/part.h
+++ b/src/part.h
@@ -31,22 +31,30 @@
 #endif
 
 /* Local headers. */
+#include "align.h"
 #include "const.h"
 
 /* Some constants. */
-#define part_align 64
-#define xpart_align 32
-#define gpart_align 32
+#define part_align 128
+#define xpart_align 128
+#define gpart_align 128
 
 /* Import the right hydro particle definition */
 #if defined(MINIMAL_SPH)
 #include "./hydro/Minimal/hydro_part.h"
+#define hydro_need_extra_init_loop 0
 #elif defined(GADGET2_SPH)
 #include "./hydro/Gadget2/hydro_part.h"
+#define hydro_need_extra_init_loop 0
+#elif defined(HOPKINS_PE_SPH)
+#include "./hydro/PressureEntropy/hydro_part.h"
+#define hydro_need_extra_init_loop 1
 #elif defined(DEFAULT_SPH)
 #include "./hydro/Default/hydro_part.h"
+#define hydro_need_extra_init_loop 0
 #elif defined(GIZMO_SPH)
 #include "./hydro/Gizmo/hydro_part.h"
+#define hydro_need_extra_init_loop 0
 #define EXTRA_HYDRO_LOOP
 #else
 #error "Invalid choice of SPH variant"
diff --git a/src/potential.c b/src/potential.c
new file mode 100644
index 0000000000000000000000000000000000000000..5433a05e3e7886ad88021d3916cae26adfe8b954
--- /dev/null
+++ b/src/potential.c
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
+ *                    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/>.
+ *
+ ******************************************************************************/
+
+/* Config parameters. */
+#include "../config.h"
+
+/* This object's header. */
+#include "potential.h"
+
+/**
+ * @brief Initialises the external potential properties in the internal system
+ * of units.
+ *
+ * @param parameter_file The parsed parameter file
+ * @param phys_const Physical constants in internal units
+ * @param us The current internal system of units
+ * @param potential The external potential properties to initialize
+ */
+void potential_init(const struct swift_params* parameter_file,
+                    const struct phys_const* phys_const,
+                    const struct UnitSystem* us,
+                    struct external_potential* potential) {
+
+  potential_init_backend(parameter_file, phys_const, us, potential);
+}
+
+/**
+ * @brief Prints the properties of the external potential to stdout.
+ *
+ * @param  potential The external potential properties.
+ */
+void potential_print(const struct external_potential* potential) {
+
+  potential_print_backend(potential);
+}
diff --git a/src/potential.h b/src/potential.h
new file mode 100644
index 0000000000000000000000000000000000000000..77bd41794a3a8cd244405493898d63b3f80ff3a6
--- /dev/null
+++ b/src/potential.h
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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_POTENTIAL_H
+#define SWIFT_POTENTIAL_H
+
+/**
+ * @file src/potential.h
+ * @brief Branches between the different external gravitational potentials.
+ */
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Local includes. */
+#include "const.h"
+
+/* Import the right external potential definition */
+#if defined(EXTERNAL_POTENTIAL_NONE)
+#include "./potential/none/potential.h"
+#elif defined(EXTERNAL_POTENTIAL_POINTMASS)
+#include "./potential/point_mass/potential.h"
+#elif defined(EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL)
+#include "./potential/isothermal/potential.h"
+#elif defined(EXTERNAL_POTENTIAL_DISC_PATCH)
+#include "./potential/disc_patch/potential.h"
+#else
+#error "Invalid choice of external potential"
+#endif
+
+/* Now, some generic functions, defined in the source file */
+void potential_init(const struct swift_params* parameter_file,
+                    const struct phys_const* phys_const,
+                    const struct UnitSystem* us,
+                    struct external_potential* potential);
+
+void potential_print(const struct external_potential* potential);
+
+#endif /* SWIFT_POTENTIAL_H */
diff --git a/src/potential/disc_patch/potential.h b/src/potential/disc_patch/potential.h
new file mode 100644
index 0000000000000000000000000000000000000000..21d168818e164ad3b3e18076ba824285e40956aa
--- /dev/null
+++ b/src/potential/disc_patch/potential.h
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
+ *                    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_DISC_PATCH_H
+#define SWIFT_DISC_PATCH_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <float.h>
+#include <math.h>
+
+/* Local includes. */
+#include "const.h"
+#include "error.h"
+#include "parser.h"
+#include "part.h"
+#include "physical_constants.h"
+#include "units.h"
+
+/**
+ * @brief External Potential Properties - Disc patch case
+ *
+ * See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948
+ */
+struct external_potential {
+
+  /*! Surface density of the disc */
+  double surface_density;
+
+  /*! Disc scale-height */
+  double scale_height;
+
+  /*! Position of the disc along the z-axis */
+  double z_disc;
+
+  /*! Dynamical time of the system */
+  double dynamical_time;
+
+  /*! Time over which to grow the disk in units of the dynamical time */
+  double growth_time;
+
+  /*! Time-step condition pre-factor */
+  double timestep_mult;
+};
+
+/**
+ * @brief Computes the time-step from the acceleration due to a hydrostatic
+ * disc.
+ *
+ * See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948
+ *
+ * @param time The current time.
+ * @param potential The properties of the potential.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static float external_gravity_timestep(
+    double time, const struct external_potential* restrict potential,
+    const struct phys_const* restrict phys_const,
+    const struct gpart* restrict g) {
+
+  /* initilize time step to disc dynamical time */
+  const float dt_dyn = potential->dynamical_time;
+  float dt = dt_dyn;
+
+  /* absolute value of height above disc */
+  const float dz = fabs(g->x[2] - potential->z_disc);
+
+  /* vertical cceleration */
+  const float z_accel = 2.f * M_PI * phys_const->const_newton_G *
+                        potential->surface_density *
+                        tanh(dz / potential->scale_height);
+
+  /* demand that dt * velocity <  fraction of scale height of disc */
+  float dt1 = FLT_MAX;
+  if (fabs(g->v_full[2]) > 0) {
+    dt1 = potential->scale_height / fabs(g->v_full[2]);
+    if (dt1 < dt) dt = dt1;
+  }
+
+  /* demand that dt^2 * acceleration < fraction of scale height of disc */
+  float dt2 = FLT_MAX;
+  if (fabs(z_accel) > 0) {
+    dt2 = potential->scale_height / fabs(z_accel);
+    if (dt2 < dt * dt) dt = sqrt(dt2);
+  }
+
+  /* demand that dt^3 jerk < fraction of scale height of disc */
+  float dt3 = FLT_MAX;
+  if (abs(g->v_full[2]) > 0) {
+    const float dz_accel_over_dt =
+        2.f * M_PI * phys_const->const_newton_G * potential->surface_density /
+        potential->scale_height / cosh(dz / potential->scale_height) /
+        cosh(dz / potential->scale_height) * fabs(g->v_full[2]);
+
+    dt3 = potential->scale_height / fabs(dz_accel_over_dt);
+    if (dt3 < dt * dt * dt) dt = pow(dt3, 1. / 3.);
+  }
+
+  return potential->timestep_mult * dt;
+}
+
+/**
+ * @brief Computes the gravitational acceleration along z due to a hydrostatic
+ * disc
+ *
+ * See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948
+ *
+ * @param time The current time in internal units.
+ * @param potential The properties of the potential.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static void external_gravity_acceleration(
+    double time, const struct external_potential* restrict potential,
+    const struct phys_const* restrict phys_const, struct gpart* restrict g) {
+
+  const float dz = g->x[2] - potential->z_disc;
+  const float t_dyn = potential->dynamical_time;
+
+  float reduction_factor = 1.f;
+  if (time < potential->growth_time * t_dyn)
+    reduction_factor = time / (potential->growth_time * t_dyn);
+
+  /* Accelerations. Note that they are multiplied by G later on */
+  const float z_accel = reduction_factor * 2.f * M_PI *
+                        potential->surface_density *
+                        tanh(fabs(dz) / potential->scale_height);
+
+  if (dz > 0) g->a_grav[2] -= z_accel;
+  if (dz < 0) g->a_grav[2] += z_accel;
+}
+
+/**
+ * @brief Initialises the external potential properties in the internal system
+ * of units.
+ *
+ * @param parameter_file The parsed parameter file
+ * @param phys_const Physical constants in internal units
+ * @param us The current internal system of units
+ * @param potential The external potential properties to initialize
+ */
+static INLINE void potential_init_backend(
+    const struct swift_params* parameter_file,
+    const struct phys_const* phys_const, const struct UnitSystem* us,
+    struct external_potential* potential) {
+
+  potential->surface_density = parser_get_param_double(
+      parameter_file, "DiscPatchPotential:surface_density");
+  potential->scale_height = parser_get_param_double(
+      parameter_file, "DiscPatchPotential:scale_height");
+  potential->z_disc =
+      parser_get_param_double(parameter_file, "DiscPatchPotential:z_disc");
+  potential->timestep_mult = parser_get_param_double(
+      parameter_file, "DiscPatchPotential:timestep_mult");
+  potential->growth_time = parser_get_opt_param_double(
+      parameter_file, "DiscPatchPotential:growth_time", 0.);
+  potential->dynamical_time =
+      sqrt(potential->scale_height /
+           (phys_const->const_newton_G * potential->surface_density));
+}
+
+/**
+ * @brief Prints the properties of the external potential to stdout.
+ *
+ * @param  potential The external potential properties.
+ */
+static INLINE void potential_print_backend(
+    const struct external_potential* potential) {
+
+  message(
+      "External potential is 'Disk-patch' with properties surface_density = %e "
+      "disc height= %e scale height = %e timestep multiplier = %e.",
+      potential->surface_density, potential->z_disc, potential->scale_height,
+      potential->timestep_mult);
+
+  if (potential->growth_time > 0.)
+    message("Disc will grow for %f dynamical times.", potential->growth_time);
+}
+
+#endif /* SWIFT_DISC_PATCH_H */
diff --git a/src/potential/isothermal/potential.h b/src/potential/isothermal/potential.h
new file mode 100644
index 0000000000000000000000000000000000000000..a993c09a978ca3692ec3359f7633df14760f263d
--- /dev/null
+++ b/src/potential/isothermal/potential.h
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
+ *                    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_POTENTIAL_ISOTHERMAL_H
+#define SWIFT_POTENTIAL_ISOTHERMAL_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <math.h>
+
+/* Local includes. */
+#include "error.h"
+#include "parser.h"
+#include "part.h"
+#include "physical_constants.h"
+#include "units.h"
+
+/**
+ * @brief External Potential Properties - Isothermal sphere case
+ */
+struct external_potential {
+
+  /*! Position of the centre of potential */
+  double x, y, z;
+
+  /*! Rotation velocity */
+  double vrot;
+
+  /*! Square of vrot divided by G \f$ \frac{v_{rot}^2}{G} \f$ */
+  double vrot2_over_G;
+
+  /*! Time-step condition pre-factor */
+  double timestep_mult;
+};
+
+/**
+ * @brief Computes the time-step due to the acceleration from an isothermal
+ * potential.
+ *
+ * @param time The current time.
+ * @param potential The #external_potential used in the run.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static float external_gravity_timestep(
+    double time, const struct external_potential* restrict potential,
+    const struct phys_const* restrict phys_const,
+    const struct gpart* restrict g) {
+
+  const float dx = g->x[0] - potential->x;
+  const float dy = g->x[1] - potential->y;
+  const float dz = g->x[2] - potential->z;
+
+  const float rinv2 = 1.f / (dx * dx + dy * dy + dz * dz);
+  const float drdv =
+      dx * (g->v_full[0]) + dy * (g->v_full[1]) + dz * (g->v_full[2]);
+  const double vrot = potential->vrot;
+
+  const float dota_x =
+      vrot * vrot * rinv2 * (g->v_full[0] - 2.f * drdv * dx * rinv2);
+  const float dota_y =
+      vrot * vrot * rinv2 * (g->v_full[1] - 2.f * drdv * dy * rinv2);
+  const float dota_z =
+      vrot * vrot * rinv2 * (g->v_full[2] - 2.f * drdv * dz * rinv2);
+  const float dota_2 = dota_x * dota_x + dota_y * dota_y + dota_z * dota_z;
+  const float a_2 = g->a_grav[0] * g->a_grav[0] + g->a_grav[1] * g->a_grav[1] +
+                    g->a_grav[2] * g->a_grav[2];
+
+  return potential->timestep_mult * sqrtf(a_2 / dota_2);
+}
+
+/**
+ * @brief Computes the gravitational acceleration from an isothermal potential.
+ *
+ * Note that the accelerations are multiplied by Newton's G constant
+ * later on.
+ *
+ * @param time The current time.
+ * @param potential The #external_potential used in the run.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static void external_gravity_acceleration(
+    double time, const struct external_potential* potential,
+    const struct phys_const* const phys_const, struct gpart* g) {
+
+  const float dx = g->x[0] - potential->x;
+  const float dy = g->x[1] - potential->y;
+  const float dz = g->x[2] - potential->z;
+  const float rinv2 = 1.f / (dx * dx + dy * dy + dz * dz);
+
+  const double term = -potential->vrot2_over_G * rinv2;
+
+  g->a_grav[0] += term * dx;
+  g->a_grav[1] += term * dy;
+  g->a_grav[2] += term * dz;
+}
+
+/**
+ * @brief Initialises the external potential properties in the internal system
+ * of units.
+ *
+ * @param parameter_file The parsed parameter file
+ * @param phys_const Physical constants in internal units
+ * @param us The current internal system of units
+ * @param potential The external potential properties to initialize
+ */
+static INLINE void potential_init_backend(
+    const struct swift_params* parameter_file,
+    const struct phys_const* phys_const, const struct UnitSystem* us,
+    struct external_potential* potential) {
+
+  potential->x =
+      parser_get_param_double(parameter_file, "IsothermalPotential:position_x");
+  potential->y =
+      parser_get_param_double(parameter_file, "IsothermalPotential:position_y");
+  potential->z =
+      parser_get_param_double(parameter_file, "IsothermalPotential:position_z");
+  potential->vrot =
+      parser_get_param_double(parameter_file, "IsothermalPotential:vrot");
+  potential->timestep_mult = parser_get_param_float(
+      parameter_file, "IsothermalPotential:timestep_mult");
+
+  potential->vrot2_over_G =
+      potential->vrot * potential->vrot / phys_const->const_newton_G;
+}
+
+/**
+ * @brief Prints the properties of the external potential to stdout.
+ *
+ * @param  potential The external potential properties.
+ */
+static INLINE void potential_print_backend(
+    const struct external_potential* potential) {
+
+  message(
+      "External potential is 'Isothermal' with properties are (x,y,z) = (%e, "
+      "%e, %e), vrot = %e "
+      "timestep multiplier = %e.",
+      potential->x, potential->y, potential->z, potential->vrot,
+      potential->timestep_mult);
+}
+
+#endif /* SWIFT_POTENTIAL_ISOTHERMAL_H */
diff --git a/src/potential/none/potential.h b/src/potential/none/potential.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b1c3e841521f3fb42fbdf5c8922cead2ea7cbcb
--- /dev/null
+++ b/src/potential/none/potential.h
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * 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_POTENTIAL_NONE_H
+#define SWIFT_POTENTIAL_NONE_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <float.h>
+
+/* Local includes. */
+#include "error.h"
+#include "parser.h"
+#include "part.h"
+#include "physical_constants.h"
+#include "units.h"
+
+/**
+ * @brief External Potential Properties
+ */
+struct external_potential {};
+
+/**
+ * @brief Computes the time-step due to the acceleration from nothing
+ *
+ * @param time The current time.
+ * @param potential The properties of the externa potential.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static float external_gravity_timestep(
+    double time, const struct external_potential* restrict potential,
+    const struct phys_const* restrict phys_const,
+    const struct gpart* restrict g) {
+
+  return FLT_MAX;
+}
+
+/**
+ * @brief Computes the gravitational acceleration due to nothing
+ *
+ * We do nothing.
+ *
+ * @param time The current time.
+ * @param potential The proerties of the external potential.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static void external_gravity_acceleration(
+    double time, const struct external_potential* restrict potential,
+    const struct phys_const* restrict phys_const, struct gpart* restrict g) {}
+
+/**
+ * @brief Initialises the external potential properties in the internal system
+ * of units.
+ *
+ * Nothing to do here.
+ *
+ * @param parameter_file The parsed parameter file
+ * @param phys_const Physical constants in internal units
+ * @param us The current internal system of units
+ * @param potential The external potential properties to initialize
+ */
+static INLINE void potential_init_backend(
+    const struct swift_params* parameter_file,
+    const struct phys_const* phys_const, const struct UnitSystem* us,
+    struct external_potential* potential) {}
+
+/**
+ * @brief Prints the properties of the external potential to stdout.
+ *
+ * @param  potential The external potential properties.
+ */
+static INLINE void potential_print_backend(
+    const struct external_potential* potential) {
+
+  message("External potential is 'No external potential'.");
+}
+
+#endif /* SWIFT_POTENTIAL_NONE_H */
diff --git a/src/potential/point_mass/potential.h b/src/potential/point_mass/potential.h
new file mode 100644
index 0000000000000000000000000000000000000000..f718af2e2c4ff91540e1834cb2072d321ce38705
--- /dev/null
+++ b/src/potential/point_mass/potential.h
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
+ *                    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_POTENTIAL_POINT_MASS_H
+#define SWIFT_POTENTIAL_POINT_MASS_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <math.h>
+
+/* Local includes. */
+#include "error.h"
+#include "parser.h"
+#include "part.h"
+#include "physical_constants.h"
+#include "units.h"
+
+/**
+ * @brief External Potential Properties - Point mass case
+ */
+struct external_potential {
+
+  /*! Position of the point mass */
+  double x, y, z;
+
+  /*! Mass */
+  double mass;
+
+  /*! Time-step condition pre-factor */
+  float timestep_mult;
+};
+
+/**
+ * @brief Computes the time-step due to the acceleration from a point mass
+ *
+ * We pass in the time for simulations where the potential evolves with time.
+ *
+ * @param time The current time.
+ * @param potential The properties of the externa potential.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static float external_gravity_timestep(
+    double time, const struct external_potential* restrict potential,
+    const struct phys_const* restrict phys_const,
+    const struct gpart* restrict g) {
+
+  const float G_newton = phys_const->const_newton_G;
+  const float dx = g->x[0] - potential->x;
+  const float dy = g->x[1] - potential->y;
+  const float dz = g->x[2] - potential->z;
+  const float rinv = 1.f / sqrtf(dx * dx + dy * dy + dz * dz);
+  const float rinv2 = rinv * rinv;
+  const float rinv3 = rinv2 * rinv;
+  const float drdv = (g->x[0] - potential->x) * (g->v_full[0]) +
+                     (g->x[1] - potential->y) * (g->v_full[1]) +
+                     (g->x[2] - potential->z) * (g->v_full[2]);
+  const float dota_x = G_newton * potential->mass * rinv3 *
+                       (-g->v_full[0] + 3.f * rinv2 * drdv * dx);
+  const float dota_y = G_newton * potential->mass * rinv3 *
+                       (-g->v_full[1] + 3.f * rinv2 * drdv * dy);
+  const float dota_z = G_newton * potential->mass * rinv3 *
+                       (-g->v_full[2] + 3.f * rinv2 * drdv * dz);
+  const float dota_2 = dota_x * dota_x + dota_y * dota_y + dota_z * dota_z;
+  const float a_2 = g->a_grav[0] * g->a_grav[0] + g->a_grav[1] * g->a_grav[1] +
+                    g->a_grav[2] * g->a_grav[2];
+
+  return potential->timestep_mult * sqrtf(a_2 / dota_2);
+}
+
+/**
+ * @brief Computes the gravitational acceleration of a particle due to a
+ * point mass
+ *
+ * Note that the accelerations are multiplied by Newton's G constant later
+ * on.
+ *
+ * We pass in the time for simulations where the potential evolves with time.
+ *
+ * @param time The current time.
+ * @param potential The proerties of the external potential.
+ * @param phys_const The physical constants in internal units.
+ * @param g Pointer to the g-particle data.
+ */
+__attribute__((always_inline)) INLINE static void external_gravity_acceleration(
+    double time, const struct external_potential* restrict potential,
+    const struct phys_const* restrict phys_const, struct gpart* restrict g) {
+
+  const float dx = g->x[0] - potential->x;
+  const float dy = g->x[1] - potential->y;
+  const float dz = g->x[2] - potential->z;
+  const float rinv = 1.f / sqrtf(dx * dx + dy * dy + dz * dz);
+  const float rinv3 = rinv * rinv * rinv;
+
+  g->a_grav[0] += -potential->mass * dx * rinv3;
+  g->a_grav[1] += -potential->mass * dy * rinv3;
+  g->a_grav[2] += -potential->mass * dz * rinv3;
+}
+
+/**
+ * @brief Initialises the external potential properties in the internal system
+ * of units.
+ *
+ * @param parameter_file The parsed parameter file
+ * @param phys_const Physical constants in internal units
+ * @param us The current internal system of units
+ * @param potential The external potential properties to initialize
+ */
+static INLINE void potential_init_backend(
+    const struct swift_params* parameter_file,
+    const struct phys_const* phys_const, const struct UnitSystem* us,
+    struct external_potential* potential) {
+
+  potential->x =
+      parser_get_param_double(parameter_file, "PointMassPotential:position_x");
+  potential->y =
+      parser_get_param_double(parameter_file, "PointMassPotential:position_y");
+  potential->z =
+      parser_get_param_double(parameter_file, "PointMassPotential:position_z");
+  potential->mass =
+      parser_get_param_double(parameter_file, "PointMassPotential:mass");
+  potential->timestep_mult = parser_get_param_float(
+      parameter_file, "PointMassPotential:timestep_mult");
+}
+
+/**
+ * @brief Prints the properties of the external potential to stdout.
+ *
+ * @param  potential The external potential properties.
+ */
+static INLINE void potential_print_backend(
+    const struct external_potential* potential) {
+
+  message(
+      "External potential is 'Point mass' with properties (x,y,z) = (%e, %e, "
+      "%e), M = %e timestep multiplier = %e.",
+      potential->x, potential->y, potential->z, potential->mass,
+      potential->timestep_mult);
+}
+
+#endif /* SWIFT_POTENTIAL_POINT_MASS_H */
diff --git a/src/potentials.c b/src/potentials.c
deleted file mode 100644
index dd7aed8712c01921a01462bf9de713433c81f5c1..0000000000000000000000000000000000000000
--- a/src/potentials.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*******************************************************************************
- * This file is part of SWIFT.
- * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
- *                    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/>.
- *
- ******************************************************************************/
-
-/* Config parameters. */
-#include "../config.h"
-
-/* This object's header. */
-#include "potentials.h"
-
-/**
- * @brief Initialises the external potential properties in the internal system
- * of units.
- *
- * @param parameter_file The parsed parameter file
- * @param phys_const Physical constants in internal units
- * @param us The current internal system of units
- * @param potential The external potential properties to initialize
- */
-void potential_init(const struct swift_params* parameter_file,
-                    const struct phys_const* phys_const,
-                    const struct UnitSystem* us,
-                    struct external_potential* potential) {
-
-#ifdef EXTERNAL_POTENTIAL_POINTMASS
-
-  potential->point_mass.x =
-      parser_get_param_double(parameter_file, "PointMass:position_x");
-  potential->point_mass.y =
-      parser_get_param_double(parameter_file, "PointMass:position_y");
-  potential->point_mass.z =
-      parser_get_param_double(parameter_file, "PointMass:position_z");
-  potential->point_mass.mass =
-      parser_get_param_double(parameter_file, "PointMass:mass");
-  potential->point_mass.timestep_mult =
-      parser_get_param_float(parameter_file, "PointMass:timestep_mult");
-
-#endif /* EXTERNAL_POTENTIAL_POINTMASS */
-
-#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
-
-  potential->isothermal_potential.x =
-      parser_get_param_double(parameter_file, "IsothermalPotential:position_x");
-  potential->isothermal_potential.y =
-      parser_get_param_double(parameter_file, "IsothermalPotential:position_y");
-  potential->isothermal_potential.z =
-      parser_get_param_double(parameter_file, "IsothermalPotential:position_z");
-  potential->isothermal_potential.vrot =
-      parser_get_param_double(parameter_file, "IsothermalPotential:vrot");
-  potential->isothermal_potential.timestep_mult = parser_get_param_float(
-      parameter_file, "IsothermalPotential:timestep_mult");
-
-#endif /* EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL */
-#ifdef EXTERNAL_POTENTIAL_DISK_PATCH
-  potential->disk_patch_potential.surface_density = parser_get_param_double(
-      parameter_file, "Disk-PatchPotential:surface_density");
-  potential->disk_patch_potential.scale_height = parser_get_param_double(
-      parameter_file, "Disk-PatchPotential:scale_height");
-  potential->disk_patch_potential.z_disk =
-      parser_get_param_double(parameter_file, "Disk-PatchPotential:z_disk");
-  potential->disk_patch_potential.timestep_mult = parser_get_param_double(
-      parameter_file, "Disk-PatchPotential:timestep_mult");
-  potential->disk_patch_potential.growth_time = parser_get_opt_param_double(
-      parameter_file, "Disk-PatchPotential:growth_time", 0.);
-  potential->disk_patch_potential.dynamical_time =
-      sqrt(potential->disk_patch_potential.scale_height /
-           (phys_const->const_newton_G *
-            potential->disk_patch_potential.surface_density));
-#endif /* EXTERNAL_POTENTIAL_DISK_PATCH */
-}
-
-/**
- * @brief Prints the properties of the external potential to stdout.
- *
- * @param  potential The external potential properties.
- */
-void potential_print(const struct external_potential* potential) {
-
-#ifdef EXTERNAL_POTENTIAL_POINTMASS
-
-  message(
-      "Point mass properties are (x,y,z) = (%e, %e, %e), M = %e timestep "
-      "multiplier = %e.",
-      potential->point_mass.x, potential->point_mass.y, potential->point_mass.z,
-      potential->point_mass.mass, potential->point_mass.timestep_mult);
-
-#endif /* EXTERNAL_POTENTIAL_POINTMASS */
-
-#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
-
-  message(
-      "Isothermal potential properties are (x,y,z) = (%e, %e, %e), vrot = %e "
-      "timestep multiplier = %e.",
-      potential->isothermal_potential.x, potential->isothermal_potential.y,
-      potential->isothermal_potential.z, potential->isothermal_potential.vrot,
-      potential->isothermal_potential.timestep_mult);
-
-#endif /* EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL */
-
-#ifdef EXTERNAL_POTENTIAL_DISK_PATCH
-
-  message(
-      "Disk-patch potential properties are surface_density = %e disk height= "
-      "%e scale height = %e timestep multiplier = %e.",
-      potential->disk_patch_potential.surface_density,
-      potential->disk_patch_potential.z_disk,
-      potential->disk_patch_potential.scale_height,
-      potential->disk_patch_potential.timestep_mult);
-
-  if (potential->disk_patch_potential.growth_time > 0.)
-    message("Disk will grow for %f dynamiccal times.",
-            potential->disk_patch_potential.growth_time);
-#endif /* EXTERNAL_POTENTIAL_DISK_PATCH */
-}
diff --git a/src/potentials.h b/src/potentials.h
deleted file mode 100644
index 74f0fd28566f355962c83e5d743aeae9afe09c59..0000000000000000000000000000000000000000
--- a/src/potentials.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/*******************************************************************************
- * This file is part of SWIFT.
- * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
- *                    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_POTENTIALS_H
-#define SWIFT_POTENTIALS_H
-
-/* Config parameters. */
-#include "../config.h"
-
-/* Some standard headers. */
-#include <float.h>
-#include <math.h>
-
-/* Local includes. */
-#include "const.h"
-#include "error.h"
-#include "parser.h"
-#include "part.h"
-#include "physical_constants.h"
-#include "units.h"
-
-/* External Potential Properties */
-struct external_potential {
-
-#ifdef EXTERNAL_POTENTIAL_POINTMASS
-  struct {
-    double x, y, z;
-    double mass;
-    float timestep_mult;
-  } point_mass;
-#endif
-
-#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
-  struct {
-    double x, y, z;
-    double vrot;
-    float timestep_mult;
-  } isothermal_potential;
-#endif
-
-#ifdef EXTERNAL_POTENTIAL_DISK_PATCH
-  struct {
-    double surface_density;
-    double scale_height;
-    double z_disk;
-    double dynamical_time;
-    double growth_time;
-    double timestep_mult;
-  } disk_patch_potential;
-#endif
-};
-
-/* ------------------------------------------------------------------------- */
-
-/* external potential: disk_patch */
-#ifdef EXTERNAL_POTENTIAL_DISK_PATCH
-
-/**
- * @brief Computes the time-step from the acceleration due to a hydrostatic
- * disk.
- *
- * See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948
- *
- * @param potential The properties of the potential.
- * @param phys_const The physical constants in internal units.
- * @param g Pointer to the g-particle data.
- */
-__attribute__((always_inline)) INLINE static float
-external_gravity_disk_patch_timestep(
-    const struct external_potential* restrict potential,
-    const struct phys_const* restrict phys_const,
-    const struct gpart* restrict g) {
-
-  /* initilize time step to disk dynamical time */
-  const float dt_dyn = potential->disk_patch_potential.dynamical_time;
-  float dt = dt_dyn;
-
-  /* absolute value of height above disk */
-  const float dz = fabs(g->x[2] - potential->disk_patch_potential.z_disk);
-
-  /* vertical cceleration */
-  const float z_accel = 2 * M_PI * phys_const->const_newton_G *
-                        potential->disk_patch_potential.surface_density *
-                        tanh(dz / potential->disk_patch_potential.scale_height);
-
-  /* demand that dt * velocity <  fraction of scale height of disk */
-  float dt1 = FLT_MAX;
-  if (fabs(g->v_full[2]) > 0) {
-    dt1 = potential->disk_patch_potential.scale_height / fabs(g->v_full[2]);
-    if (dt1 < dt) dt = dt1;
-  }
-
-  /* demand that dt^2 * acceleration < fraction of scale height of disk */
-  float dt2 = FLT_MAX;
-  if (fabs(z_accel) > 0) {
-    dt2 = potential->disk_patch_potential.scale_height / fabs(z_accel);
-    if (dt2 < dt * dt) dt = sqrt(dt2);
-  }
-
-  /* demand that dt^3 jerk < fraction of scale height of disk */
-  float dt3 = FLT_MAX;
-  if (abs(g->v_full[2]) > 0) {
-    const float dz_accel_over_dt =
-        2 * M_PI * phys_const->const_newton_G *
-        potential->disk_patch_potential.surface_density /
-        potential->disk_patch_potential.scale_height /
-        cosh(dz / potential->disk_patch_potential.scale_height) /
-        cosh(dz / potential->disk_patch_potential.scale_height) *
-        fabs(g->v_full[2]);
-
-    dt3 = potential->disk_patch_potential.scale_height / fabs(dz_accel_over_dt);
-    if (dt3 < dt * dt * dt) dt = pow(dt3, 1. / 3.);
-  }
-
-  return potential->disk_patch_potential.timestep_mult * dt;
-}
-
-/**
- * @brief Computes the gravitational acceleration along z due to a hydrostatic
- * disk
- *
- * See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948
- *
- * @param time The current time in internal units.
- * @param potential The properties of the potential.
- * @param phys_const The physical constants in internal units.
- * @param g Pointer to the g-particle data.
- */
-__attribute__((always_inline)) INLINE static void
-external_gravity_disk_patch_potential(
-    double time, const struct external_potential* restrict potential,
-    const struct phys_const* restrict phys_const, struct gpart* restrict g) {
-
-  const float G_newton = phys_const->const_newton_G;
-  const float dz = g->x[2] - potential->disk_patch_potential.z_disk;
-  const float t_dyn = potential->disk_patch_potential.dynamical_time;
-
-  float reduction_factor = 1.;
-  if (time < potential->disk_patch_potential.growth_time * t_dyn)
-    reduction_factor =
-        time / (potential->disk_patch_potential.growth_time * t_dyn);
-
-  const float z_accel =
-      reduction_factor * 2 * G_newton * M_PI *
-      potential->disk_patch_potential.surface_density *
-      tanh(fabs(dz) / potential->disk_patch_potential.scale_height);
-
-  /* Accelerations. Note that they are multiplied by G later on */
-  if (dz > 0) g->a_grav[2] -= z_accel / G_newton;
-  if (dz < 0) g->a_grav[2] += z_accel / G_newton;
-}
-#endif /* EXTERNAL_POTENTIAL_DISK_PATCH */
-
-/* ------------------------------------------------------------------------- */
-
-#ifdef EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL
-
-/**
- * @brief Computes the time-step due to the acceleration from an isothermal
- * potential.
- *
- * @param potential The #external_potential used in the run.
- * @param phys_const The physical constants in internal units.
- * @param g Pointer to the g-particle data.
- */
-__attribute__((always_inline)) INLINE static float
-external_gravity_isothermalpotential_timestep(
-    const struct external_potential* restrict potential,
-    const struct phys_const* restrict phys_const,
-    const struct gpart* restrict g) {
-
-  const float dx = g->x[0] - potential->isothermal_potential.x;
-  const float dy = g->x[1] - potential->isothermal_potential.y;
-  const float dz = g->x[2] - potential->isothermal_potential.z;
-
-  const float rinv2 = 1.f / (dx * dx + dy * dy + dz * dz);
-  const float drdv =
-      dx * (g->v_full[0]) + dy * (g->v_full[1]) + dz * (g->v_full[2]);
-  const double vrot = potential->isothermal_potential.vrot;
-
-  const float dota_x =
-      vrot * vrot * rinv2 * (g->v_full[0] - 2 * drdv * dx * rinv2);
-  const float dota_y =
-      vrot * vrot * rinv2 * (g->v_full[1] - 2 * drdv * dy * rinv2);
-  const float dota_z =
-      vrot * vrot * rinv2 * (g->v_full[2] - 2 * drdv * dz * rinv2);
-  const float dota_2 = dota_x * dota_x + dota_y * dota_y + dota_z * dota_z;
-  const float a_2 = g->a_grav[0] * g->a_grav[0] + g->a_grav[1] * g->a_grav[1] +
-                    g->a_grav[2] * g->a_grav[2];
-
-  return potential->isothermal_potential.timestep_mult * sqrtf(a_2 / dota_2);
-}
-
-/**
- * @brief Computes the gravitational acceleration from an isothermal potential.
- *
- * Note that the accelerations are multiplied by Newton's G constant
- * later on.
- *
- * @param potential The #external_potential used in the run.
- * @param phys_const The physical constants in internal units.
- * @param g Pointer to the g-particle data.
- */
-__attribute__((always_inline)) INLINE static void
-external_gravity_isothermalpotential(const struct external_potential* potential,
-                                     const struct phys_const* const phys_const,
-                                     struct gpart* g) {
-
-  const float G_newton = phys_const->const_newton_G;
-  const float dx = g->x[0] - potential->isothermal_potential.x;
-  const float dy = g->x[1] - potential->isothermal_potential.y;
-  const float dz = g->x[2] - potential->isothermal_potential.z;
-  const float rinv2 = 1.f / (dx * dx + dy * dy + dz * dz);
-
-  const double vrot = potential->isothermal_potential.vrot;
-  const double term = -vrot * vrot * rinv2 / G_newton;
-
-  g->a_grav[0] += term * dx;
-  g->a_grav[1] += term * dy;
-  g->a_grav[2] += term * dz;
-}
-
-#endif /* EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL */
-
-/* ------------------------------------------------------------------------- */
-
-/* Include exteral pointmass potential */
-#ifdef EXTERNAL_POTENTIAL_POINTMASS
-
-/**
- * @brief Computes the time-step due to the acceleration from a point mass
- *
- * @param potential The properties of the externa potential.
- * @param phys_const The physical constants in internal units.
- * @param g Pointer to the g-particle data.
- */
-__attribute__((always_inline)) INLINE static float
-external_gravity_pointmass_timestep(
-    const struct external_potential* restrict potential,
-    const struct phys_const* restrict phys_const,
-    const struct gpart* restrict g) {
-
-  const float G_newton = phys_const->const_newton_G;
-  const float dx = g->x[0] - potential->point_mass.x;
-  const float dy = g->x[1] - potential->point_mass.y;
-  const float dz = g->x[2] - potential->point_mass.z;
-  const float rinv = 1.f / sqrtf(dx * dx + dy * dy + dz * dz);
-  const float drdv = (g->x[0] - potential->point_mass.x) * (g->v_full[0]) +
-                     (g->x[1] - potential->point_mass.y) * (g->v_full[1]) +
-                     (g->x[2] - potential->point_mass.z) * (g->v_full[2]);
-  const float dota_x = G_newton * potential->point_mass.mass * rinv * rinv *
-                       rinv * (-g->v_full[0] + 3.f * rinv * rinv * drdv * dx);
-  const float dota_y = G_newton * potential->point_mass.mass * rinv * rinv *
-                       rinv * (-g->v_full[1] + 3.f * rinv * rinv * drdv * dy);
-  const float dota_z = G_newton * potential->point_mass.mass * rinv * rinv *
-                       rinv * (-g->v_full[2] + 3.f * rinv * rinv * drdv * dz);
-  const float dota_2 = dota_x * dota_x + dota_y * dota_y + dota_z * dota_z;
-  const float a_2 = g->a_grav[0] * g->a_grav[0] + g->a_grav[1] * g->a_grav[1] +
-                    g->a_grav[2] * g->a_grav[2];
-
-  return potential->point_mass.timestep_mult * sqrtf(a_2 / dota_2);
-}
-
-/**
- * @brief Computes the gravitational acceleration of a particle due to a
- * point mass
- *
- * Note that the accelerations are multiplied by Newton's G constant later
- * on.
- *
- * @param potential The proerties of the external potential.
- * @param phys_const The physical constants in internal units.
- * @param g Pointer to the g-particle data.
- */
-__attribute__((always_inline)) INLINE static void external_gravity_pointmass(
-    const struct external_potential* restrict potential,
-    const struct phys_const* restrict phys_const, struct gpart* restrict g) {
-
-  const float dx = g->x[0] - potential->point_mass.x;
-  const float dy = g->x[1] - potential->point_mass.y;
-  const float dz = g->x[2] - potential->point_mass.z;
-  const float rinv = 1.f / sqrtf(dx * dx + dy * dy + dz * dz);
-  const float rinv3 = rinv * rinv * rinv;
-
-  g->a_grav[0] += -potential->point_mass.mass * dx * rinv3;
-  g->a_grav[1] += -potential->point_mass.mass * dy * rinv3;
-  g->a_grav[2] += -potential->point_mass.mass * dz * rinv3;
-}
-
-#endif /* EXTERNAL_POTENTIAL_POINTMASS */
-
-/* ------------------------------------------------------------------------- */
-
-/* Now, some generic functions, defined in the source file */
-void potential_init(const struct swift_params* parameter_file,
-                    const struct phys_const* phys_const,
-                    const struct UnitSystem* us,
-                    struct external_potential* potential);
-
-void potential_print(const struct external_potential* potential);
-
-#endif /* SWIFT_POTENTIALS_H */
diff --git a/src/riemann/riemann_hllc.h b/src/riemann/riemann_hllc.h
index b8b1239d7799221c98522c06631aba5cabe69183..1a4c3f5f8338f6504a8c5f1d9eab8451eb20246c 100644
--- a/src/riemann/riemann_hllc.h
+++ b/src/riemann/riemann_hllc.h
@@ -145,11 +145,13 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux(
      we add the extra velocity flux due to the absolute motion of the fluid
      similarly, we need to add the energy fluxes due to the absolute motion */
   v2 = vij[0] * vij[0] + vij[1] * vij[1] + vij[2] * vij[2];
+  // order is important: we first use the momentum fluxes to update the energy
+  // flux and then de-boost the momentum fluxes!
+  totflux[4] += vij[0] * totflux[1] + vij[1] * totflux[2] +
+                vij[2] * totflux[3] + 0.5 * v2 * totflux[0];
   totflux[1] += vij[0] * totflux[0];
   totflux[2] += vij[1] * totflux[0];
   totflux[3] += vij[2] * totflux[0];
-  totflux[4] += vij[0] * totflux[1] + vij[1] * totflux[2] +
-                vij[2] * totflux[3] + 0.5 * v2 * totflux[0];
 }
 
 #endif /* SWIFT_RIEMANN_HLLC_H */
diff --git a/src/runner.c b/src/runner.c
index ea8f87a6b35ac2367493c2f07a7c80a89beebaa9..b77e6978f0b4acbaa2cd6fe7ff3f4a2fc81a3400 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -279,7 +279,7 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) {
     /* Is this part within the time step? */
     if (g->ti_end <= ti_current) {
 
-      external_gravity(time, potential, constants, g);
+      external_gravity_acceleration(time, potential, constants, g);
     }
   }
 
@@ -297,9 +297,10 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) {
 void runner_do_cooling(struct runner *r, struct cell *c, int timer) {
 
   struct part *restrict parts = c->parts;
+  struct xpart *restrict xparts = c->xparts;
   const int count = c->count;
   const int ti_current = r->e->ti_current;
-  const struct cooling_data *cooling = r->e->cooling_data;
+  const struct cooling_function_data *cooling_func = r->e->cooling_func;
   const struct phys_const *constants = r->e->physical_constants;
   const struct UnitSystem *us = r->e->internalUnits;
   const double timeBase = r->e->timeBase;
@@ -322,13 +323,14 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) {
 
     /* Get a direct pointer on the part. */
     struct part *restrict p = &parts[i];
+    struct xpart *restrict xp = &xparts[i];
 
     /* Kick has already updated ti_end, so need to check ti_begin */
     if (p->ti_begin == ti_current) {
 
       const double dt = (p->ti_end - p->ti_begin) * timeBase;
 
-      cooling_cool_part(constants, us, cooling, p, dt);
+      cooling_cool_part(constants, us, cooling_func, p, xp, dt);
     }
   }
 
@@ -859,7 +861,8 @@ static void runner_do_drift(struct cell *c, struct engine *e) {
   const double dt = (ti_current - ti_old) * timeBase;
 
   float dx_max = 0.f, dx2_max = 0.f, h_max = 0.f;
-  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, entropy = 0.0, mass = 0.0;
+  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, e_rad = 0.0;
+  double entropy = 0.0, mass = 0.0;
   double mom[3] = {0.0, 0.0, 0.0};
   double ang_mom[3] = {0.0, 0.0, 0.0};
 
@@ -931,6 +934,7 @@ static void runner_do_drift(struct cell *c, struct engine *e) {
       e_kin += 0.5 * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
       e_pot += 0.;
       e_int += m * hydro_get_internal_energy(p, half_dt);
+      e_rad += cooling_get_radiated_energy(xp);
 
       /* Collect entropy */
       entropy += m * hydro_get_entropy(p, half_dt);
@@ -957,6 +961,7 @@ static void runner_do_drift(struct cell *c, struct engine *e) {
         e_kin += cp->e_kin;
         e_int += cp->e_int;
         e_pot += cp->e_pot;
+        e_rad += cp->e_rad;
         entropy += cp->entropy;
         mom[0] += cp->mom[0];
         mom[1] += cp->mom[1];
@@ -974,6 +979,7 @@ static void runner_do_drift(struct cell *c, struct engine *e) {
   c->e_kin = e_kin;
   c->e_int = e_int;
   c->e_pot = e_pot;
+  c->e_rad = e_rad;
   c->entropy = entropy;
   c->mom[0] = mom[0];
   c->mom[1] = mom[1];
diff --git a/src/scheduler.c b/src/scheduler.c
index fa065879f7daeb60cfeeb67e52c64eb2036cf3cb..f98f8824c00186956e8abe5e5c2aa3aae73abf4e 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -141,6 +141,7 @@ static void scheduler_splittask(struct task *t, struct scheduler *s) {
 
       /* Get a handle on the cell involved. */
       struct cell *ci = t->ci;
+      const double hi = ci->dmin;
 
       /* Foreign task? */
       if (ci->nodeID != s->nodeID) {
@@ -149,7 +150,7 @@ static void scheduler_splittask(struct task *t, struct scheduler *s) {
       }
 
       /* Is this cell even split? */
-      if (ci->split) {
+      if (ci->split && ci->h_max * kernel_gamma * space_stretch < hi / 2) {
 
         /* Make a sub? */
         if (scheduler_dosub &&
@@ -890,10 +891,11 @@ void scheduler_reset(struct scheduler *s, int size) {
  * @brief Compute the task weights
  *
  * @param s The #scheduler.
+ * @param verbose Are we talkative ?
  */
+void scheduler_reweight(struct scheduler *s, int verbose) {
 
-void scheduler_reweight(struct scheduler *s) {
-
+  const ticks tic = getticks();
   const int nr_tasks = s->nr_tasks;
   int *tid = s->tasks_ind;
   struct task *tasks = s->tasks;
@@ -902,11 +904,8 @@ void scheduler_reweight(struct scheduler *s) {
                                0.4025, 0.1897, 0.4025, 0.1897, 0.4025,
                                0.5788, 0.4025, 0.5788};
   const float wscale = 0.001;
-  // ticks tic;
 
-  /* Run through the tasks backwards and set their waits and
-     weights. */
-  // tic = getticks();
+  /* Run through the tasks backwards and set their weights. */
   for (int k = nr_tasks - 1; k >= 0; k--) {
     struct task *t = &tasks[tid[k]];
     t->weight = 0;
@@ -963,8 +962,10 @@ void scheduler_reweight(struct scheduler *s) {
           break;
       }
   }
-  // message( "weighting tasks took %.3f %s." ,
-  // clocks_from_ticks( getticks() - tic ), clocks_getunit());
+
+  if (verbose)
+    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+            clocks_getunit());
 
   /* int min = tasks[0].weight, max = tasks[0].weight;
   for ( int k = 1 ; k < nr_tasks ; k++ )
diff --git a/src/scheduler.h b/src/scheduler.h
index 3e51197de148ee8f0bf3090551568715d3000e98..c4eb5e99447d623e5fb8e442efc1c254c00bfadd 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -116,7 +116,7 @@ void scheduler_start(struct scheduler *s, unsigned int mask,
                      unsigned int submask);
 void scheduler_reset(struct scheduler *s, int nr_tasks);
 void scheduler_ranktasks(struct scheduler *s);
-void scheduler_reweight(struct scheduler *s);
+void scheduler_reweight(struct scheduler *s, int verbose);
 struct task *scheduler_addtask(struct scheduler *s, enum task_types type,
                                enum task_subtypes subtype, int flags, int wait,
                                struct cell *ci, struct cell *cj, int tight);
diff --git a/src/serial_io.c b/src/serial_io.c
index 6e26be1a33fbc2c74ae1b8f7af2b83db285c962e..b9ad0fbaa856a889d3f84bb42013282f3640fd5e 100644
--- a/src/serial_io.c
+++ b/src/serial_io.c
@@ -528,6 +528,11 @@ void read_ic_serial(char* fileName, const struct UnitSystem* internal_units,
     H5Fclose(h_file);
   }
 
+  /* Convert the dimensions of the box */
+  for (int j = 0; j < 3; j++)
+    dim[j] *=
+        units_conversion_factor(ic_units, internal_units, UNIT_CONV_LENGTH);
+
   /* Now need to broadcast that information to all ranks. */
   MPI_Bcast(flag_entropy, 1, MPI_INT, 0, comm);
   MPI_Bcast(periodic, 1, MPI_INT, 0, comm);
diff --git a/src/single_io.c b/src/single_io.c
index 6cb7e830209b0d58919fe6f529f675b4c611a51d..ceeba4eb80a47c3feed7e898deb5e1fe7e427c0c 100644
--- a/src/single_io.c
+++ b/src/single_io.c
@@ -433,6 +433,11 @@ void read_ic_single(char* fileName, const struct UnitSystem* internal_units,
             internal_units->UnitTemperature_in_cgs);
   }
 
+  /* Convert the dimensions of the box */
+  for (int j = 0; j < 3; j++)
+    dim[j] *=
+        units_conversion_factor(ic_units, internal_units, UNIT_CONV_LENGTH);
+
   /* Allocate memory to store SPH particles */
   *Ngas = N[0];
   if (posix_memalign((void*)parts, part_align, *Ngas * sizeof(struct part)) !=
diff --git a/src/space.c b/src/space.c
index cdd5958cbc515003f4a86a41c9a7075fa3b4364f..1d2733ab2d4356c19cc0e65a0b9441edcf0acb80 100644
--- a/src/space.c
+++ b/src/space.c
@@ -42,6 +42,7 @@
 /* Local headers. */
 #include "atomic.h"
 #include "const.h"
+#include "cooling.h"
 #include "engine.h"
 #include "error.h"
 #include "gravity.h"
@@ -57,6 +58,7 @@
 int space_splitsize = space_splitsize_default;
 int space_subsize = space_subsize_default;
 int space_maxsize = space_maxsize_default;
+int space_maxcount = space_maxcount_default;
 
 /* Map shift vector to sortlist. */
 const int sortlistID[27] = {
@@ -227,7 +229,14 @@ void space_regrid(struct space *s, double cell_max, int verbose) {
   if (s->periodic && (cdim[0] < 3 || cdim[1] < 3 || cdim[2] < 3))
     error(
         "Must have at least 3 cells in each spatial dimension when periodicity "
-        "is switched on.");
+        "is switched on.\nThis error is often caused by any of the "
+        "followings:\n"
+        " - too few particles to generate a sensible grid,\n"
+        " - the initial value of 'SPH:max_smoothing_length' is too large,\n"
+        " - the (minimal) time-step is too large leading to particles with "
+        "predicted smoothing lengths too large for the box size,\n"
+        " - particle with velocities so large that they move by more than two "
+        "box sizes per time-step.\n");
 
   /* Check if we have enough cells for gravity. */
   if (s->gravity && (cdim[0] < 8 || cdim[1] < 8 || cdim[2] < 8))
@@ -690,7 +699,7 @@ void space_rebuild(struct space *s, double cell_max, int verbose) {
 
   /* At this point, we have the upper-level cells, old or new. Now make
      sure that the parts in each cell are ok. */
-  space_split(s, cells_top, verbose);
+  space_split(s, cells_top, s->nr_cells, verbose);
 
   if (verbose)
     message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
@@ -703,14 +712,16 @@ void space_rebuild(struct space *s, double cell_max, int verbose) {
  * This is done in parallel using threads in the #threadpool.
  *
  * @param s The #space.
- * @param cells The cell hierarchy
+ * @param cells The cell hierarchy.
+ * @param nr_cells The number of cells.
  * @param verbose Are we talkative ?
  */
-void space_split(struct space *s, struct cell *cells, int verbose) {
+void space_split(struct space *s, struct cell *cells, int nr_cells,
+                 int verbose) {
 
   const ticks tic = getticks();
 
-  threadpool_map(&s->e->threadpool, space_split_mapper, cells, s->nr_cells,
+  threadpool_map(&s->e->threadpool, space_split_mapper, cells, nr_cells,
                  sizeof(struct cell), 1, s);
 
   if (verbose)
@@ -718,6 +729,29 @@ void space_split(struct space *s, struct cell *cells, int verbose) {
             clocks_getunit());
 }
 
+/**
+ * @brief Runs through the top-level cells and checks whether tasks associated
+ * with them can be split. If not, try to sanitize the cells.
+ *
+ * @param s The #space to act upon.
+ */
+void space_sanitize(struct space *s) {
+
+  for (int k = 0; k < s->nr_cells; k++) {
+
+    struct cell *c = &s->cells_top[k];
+    const double min_width = c->dmin;
+
+    /* Do we have a problem ? */
+    if (c->h_max * kernel_gamma * space_stretch > min_width * 0.5 &&
+        c->count > space_maxcount) {
+
+      /* Ok, clean-up the mess */
+      cell_sanitize(c);
+    }
+  }
+}
+
 /**
  * @brief Sort the particles and condensed particles according to the given
  * indices.
@@ -1239,17 +1273,17 @@ void space_map_cells_pre(struct space *s, int full,
  *        too many particles.
  *
  * @param map_data Pointer towards the top-cells.
- * @param num_elements The number of cells to treat.
+ * @param num_cells The number of cells to treat.
  * @param extra_data Pointers to the #space.
  */
-void space_split_mapper(void *map_data, int num_elements, void *extra_data) {
+void space_split_mapper(void *map_data, int num_cells, void *extra_data) {
 
   /* Unpack the inputs. */
   struct space *s = (struct space *)extra_data;
   struct cell *restrict cells_top = (struct cell *)map_data;
   struct engine *e = s->e;
 
-  for (int ind = 0; ind < num_elements; ind++) {
+  for (int ind = 0; ind < num_cells; ind++) {
 
     struct cell *c = &cells_top[ind];
 
@@ -1268,6 +1302,12 @@ void space_split_mapper(void *map_data, int num_elements, void *extra_data) {
       atomic_cas(&s->maxdepth, maxdepth, c->depth);
     }
 
+    /* If the depth is too large, we have a problem and should stop. */
+    if (maxdepth > space_cell_maxdepth) {
+      error("Exceeded maximum depth (%d) when splitting cells, aborting",
+            space_cell_maxdepth);
+    }
+
     /* Split or let it be? */
     if (count > space_splitsize || gcount > space_splitsize) {
 
@@ -1471,6 +1511,23 @@ void space_init_parts(struct space *s) {
   }
 }
 
+/**
+ * @brief Initialises all the extra particle data
+ *
+ * Calls cooling_init_xpart() on all the particles
+ */
+void space_init_xparts(struct space *s) {
+
+  const size_t nr_parts = s->nr_parts;
+  struct part *restrict p = s->parts;
+  struct xpart *restrict xp = s->xparts;
+
+  for (size_t i = 0; i < nr_parts; ++i) {
+
+    cooling_init_part(&p[i], &xp[i]);
+  }
+}
+
 /**
  * @brief Initialises all the g-particles by setting them into a valid state
  *
@@ -1547,6 +1604,8 @@ void space_init(struct space *s, const struct swift_params *params,
                                            space_subsize_default);
   space_splitsize = parser_get_opt_param_int(
       params, "Scheduler:cell_split_size", space_splitsize_default);
+  space_maxcount = parser_get_opt_param_int(params, "Scheduler:cell_max_count",
+                                            space_maxcount_default);
   if (verbose)
     message("max_size set to %d, sub_size set to %d, split_size set to %d",
             space_maxsize, space_subsize, space_splitsize);
@@ -1630,6 +1689,7 @@ void space_init(struct space *s, const struct swift_params *params,
 
   /* Set the particles in a state where they are ready for a run */
   space_init_parts(s);
+  space_init_xparts(s);
   space_init_gparts(s);
 
   /* Init the space lock. */
diff --git a/src/space.h b/src/space.h
index 72b17405f13766ad2ccc9d53712068f28172067b..85f32bd7580945de6d9713316b557c92667987c0 100644
--- a/src/space.h
+++ b/src/space.h
@@ -41,13 +41,18 @@
 #define space_splitsize_default 400
 #define space_maxsize_default 8000000
 #define space_subsize_default 64000000
+#define space_maxcount_default 10000
 #define space_stretch 1.10f
 #define space_maxreldx 0.25f
 
+/* Maximum allowed depth of cell splits. */
+#define space_cell_maxdepth 52
+
 /* Split size. */
 extern int space_splitsize;
 extern int space_maxsize;
 extern int space_subsize;
+extern int space_maxcount;
 
 /* Map shift vector to sortlist. */
 extern const int sortlistID[27];
@@ -145,6 +150,7 @@ void space_init(struct space *s, const struct swift_params *params,
                 double dim[3], struct part *parts, struct gpart *gparts,
                 size_t Npart, size_t Ngpart, int periodic, int gravity,
                 int verbose, int dry_run);
+void space_sanitize(struct space *s);
 void space_map_cells_pre(struct space *s, int full,
                          void (*fun)(struct cell *c, void *data), void *data);
 void space_map_parts(struct space *s,
@@ -161,7 +167,8 @@ void space_gparts_sort_mapper(void *map_data, int num_elements,
                               void *extra_data);
 void space_rebuild(struct space *s, double h_max, int verbose);
 void space_recycle(struct space *s, struct cell *c);
-void space_split(struct space *s, struct cell *cells, int verbose);
+void space_split(struct space *s, struct cell *cells, int nr_cells,
+                 int verbose);
 void space_split_mapper(void *map_data, int num_elements, void *extra_data);
 void space_do_parts_sort();
 void space_do_gparts_sort();
diff --git a/src/swift.h b/src/swift.h
index 9a425dbac34e6e6ae6ecc874d5994eaab4c9836b..58745f3111fc3f29490d4591ee549907392cb87e 100644
--- a/src/swift.h
+++ b/src/swift.h
@@ -43,7 +43,7 @@
 #include "part.h"
 #include "partition.h"
 #include "physical_constants.h"
-#include "potentials.h"
+#include "potential.h"
 #include "queue.h"
 #include "runner.h"
 #include "scheduler.h"
diff --git a/src/task.c b/src/task.c
index 18197f9c5f0b239562e015c6b6b88de307444c1c..00068f45769b4ca606cc729bd5e89c13ae729eef 100644
--- a/src/task.c
+++ b/src/task.c
@@ -63,7 +63,7 @@ const char *subtaskID_names[task_subtype_count] = {
  * @param cj The second #cell.
  */
 __attribute__((always_inline)) INLINE static size_t task_cell_overlap_part(
-    const struct cell *ci, const struct cell *cj) {
+    const struct cell *restrict ci, const struct cell *restrict cj) {
 
   if (ci == NULL || cj == NULL) return 0;
 
@@ -85,7 +85,7 @@ __attribute__((always_inline)) INLINE static size_t task_cell_overlap_part(
  * @param cj The second #cell.
  */
 __attribute__((always_inline)) INLINE static size_t task_cell_overlap_gpart(
-    const struct cell *ci, const struct cell *cj) {
+    const struct cell *restrict ci, const struct cell *restrict cj) {
 
   if (ci == NULL || cj == NULL) return 0;
 
@@ -169,6 +169,10 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
       return task_action_none;
       break;
   }
+
+  /* Silence compile warnings */
+  error("Unknown task_action for task");
+  return task_action_none;
 }
 
 /**
@@ -178,7 +182,8 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
  * @param ta The first #task.
  * @param tb The second #task.
  */
-float task_overlap(const struct task *ta, const struct task *tb) {
+float task_overlap(const struct task *restrict ta,
+                   const struct task *restrict tb) {
 
   if (ta == NULL || tb == NULL) return 0.f;
 
diff --git a/src/task.h b/src/task.h
index d7d8b162f985b475e2087b90b4e2777513e670f9..bc4df3dc2a4cfee3c382e9f2059cba84f29299f7 100644
--- a/src/task.h
+++ b/src/task.h
@@ -26,6 +26,7 @@
 #include "../config.h"
 
 /* Includes. */
+#include "align.h"
 #include "cell.h"
 #include "cycle.h"
 
@@ -150,7 +151,7 @@ struct task {
   /*! Is this task implicit (i.e. does not do anything) ? */
   char implicit;
 
-} __attribute__((aligned(32)));
+} SWIFT_STRUCT_ALIGN;
 
 /* Function prototypes. */
 void task_unlock(struct task *t);
diff --git a/src/timestep.h b/src/timestep.h
index d92f88d06451892ce47db4b9468db9714bb52baa..599fb4762e11b08fc942fb02acbbf1970f477de4 100644
--- a/src/timestep.h
+++ b/src/timestep.h
@@ -68,18 +68,18 @@ __attribute__((always_inline)) INLINE static int get_integer_timestep(
 __attribute__((always_inline)) INLINE static int get_gpart_timestep(
     const struct gpart *restrict gp, const struct engine *restrict e) {
 
-  const float new_dt_external = gravity_compute_timestep_external(
-      e->external_potential, e->physical_constants, gp);
+  const float new_dt_external = external_gravity_timestep(
+      e->time, e->external_potential, e->physical_constants, gp);
+
   /* const float new_dt_self = */
   /*     gravity_compute_timestep_self(e->physical_constants, gp); */
   const float new_dt_self = FLT_MAX;  // MATTHIEU
 
-  float new_dt =
-      (new_dt_external < new_dt_self) ? new_dt_external : new_dt_self;
+  float new_dt = min(new_dt_external, new_dt_self);
 
   /* Limit timestep within the allowed range */
-  new_dt = (new_dt < e->dt_max) ? new_dt : e->dt_max;
-  new_dt = (new_dt > e->dt_min) ? new_dt : e->dt_min;
+  new_dt = min(new_dt, e->dt_max);
+  new_dt = max(new_dt, e->dt_min);
 
   /* Convert to integer time */
   const int new_dti =
@@ -102,22 +102,28 @@ __attribute__((always_inline)) INLINE static int get_part_timestep(
   /* Compute the next timestep (hydro condition) */
   const float new_dt_hydro = hydro_compute_timestep(p, xp, e->hydro_properties);
 
+  /* Compute the next timestep (cooling condition) */
+  float new_dt_cooling = FLT_MAX;
+  if (e->policy & engine_policy_cooling)
+    new_dt_cooling = cooling_timestep(e->cooling_func, e->physical_constants,
+                                      e->internalUnits, p);
+
   /* Compute the next timestep (gravity condition) */
   float new_dt_grav = FLT_MAX;
   if (p->gpart != NULL) {
 
-    const float new_dt_external = gravity_compute_timestep_external(
-        e->external_potential, e->physical_constants, p->gpart);
+    const float new_dt_external = external_gravity_timestep(
+        e->time, e->external_potential, e->physical_constants, p->gpart);
+
     /* const float new_dt_self = */
     /*     gravity_compute_timestep_self(e->physical_constants, p->gpart); */
     const float new_dt_self = FLT_MAX;  // MATTHIEU
 
-    new_dt_grav =
-        (new_dt_external < new_dt_self) ? new_dt_external : new_dt_self;
+    new_dt_grav = min(new_dt_external, new_dt_self);
   }
 
   /* Final time-step is minimum of hydro and gravity */
-  float new_dt = (new_dt_hydro < new_dt_grav) ? new_dt_hydro : new_dt_grav;
+  float new_dt = min(min(new_dt_hydro, new_dt_cooling), new_dt_grav);
 
   /* Limit change in h */
   const float dt_h_change =
@@ -125,11 +131,11 @@ __attribute__((always_inline)) INLINE static int get_part_timestep(
           ? fabsf(e->hydro_properties->log_max_h_change * p->h / p->force.h_dt)
           : FLT_MAX;
 
-  new_dt = (new_dt < dt_h_change) ? new_dt : dt_h_change;
+  new_dt = min(new_dt, dt_h_change);
 
   /* Limit timestep within the allowed range */
-  new_dt = (new_dt < e->dt_max) ? new_dt : e->dt_max;
-  new_dt = (new_dt > e->dt_min) ? new_dt : e->dt_min;
+  new_dt = min(new_dt, e->dt_max);
+  new_dt = max(new_dt, e->dt_min);
 
   /* Convert to integer time */
   const int new_dti =
diff --git a/src/units.c b/src/units.c
index f598b5ddf0b1a4b165648d5378915cd6f10f0bba..2241d441ec9af9b6d5083191e8f61010ebaccb20 100644
--- a/src/units.c
+++ b/src/units.c
@@ -319,6 +319,9 @@ void units_get_base_unit_exponants_array(float baseUnitsExp[5],
       break;
 
     case UNIT_CONV_VOLUME:
+      baseUnitsExp[UNIT_LENGTH] = 3.f;
+
+    case UNIT_CONV_INV_VOLUME:
       baseUnitsExp[UNIT_LENGTH] = -3.f;
   }
 }
diff --git a/src/units.h b/src/units.h
index 26fa15a66528dd39ea232cdf94da2ff0230300cd..78fdf1c23c3c276607d5353ee3437d8eb1e96537 100644
--- a/src/units.h
+++ b/src/units.h
@@ -90,7 +90,8 @@ enum UnitConversionFactor {
   UNIT_CONV_MAGNETIC_FIELD,
   UNIT_CONV_MAGNETIC_INDUCTANCE,
   UNIT_CONV_TEMPERATURE,
-  UNIT_CONV_VOLUME
+  UNIT_CONV_VOLUME,
+  UNIT_CONV_INV_VOLUME
 };
 
 void units_init_cgs(struct UnitSystem*);
diff --git a/tests/test125cells.c b/tests/test125cells.c
index a385a7c890fe27ed11d3c5d87d6903fa6d254516..d423efba3fda764310721586e14192afdee18a85 100644
--- a/tests/test125cells.c
+++ b/tests/test125cells.c
@@ -95,6 +95,8 @@ void set_energy_state(struct part *part, enum pressure_field press, float size,
 
 #if defined(GADGET2_SPH)
   part->entropy = pressure / pow_gamma(density);
+#elif defined(HOPKINS_PE_SPH)
+  part->entropy = pressure / pow_gamma(density);
 #elif defined(DEFAULT_SPH)
   part->u = pressure / (hydro_gamma_minus_one * density);
 #elif defined(MINIMAL_SPH)
@@ -519,6 +521,7 @@ int main(int argc, char *argv[]) {
   hp.CFL_condition = 0.1;
 
   struct engine engine;
+  bzero(&engine, sizeof(struct engine));
   engine.hydro_properties = &hp;
   engine.physical_constants = &prog_const;
   engine.s = &space;
diff --git a/tests/test27cells.c b/tests/test27cells.c
index 1a1ab88748d922b3e7fbb30a73a10809dca10863..22619af53c39218da34d771fab6ed2d10993689c 100644
--- a/tests/test27cells.c
+++ b/tests/test27cells.c
@@ -104,11 +104,18 @@ struct cell *make_cell(size_t n, double *offset, double size, double h,
         }
         part->h = size * h / (float)n;
         part->id = ++(*partId);
+
 #ifdef GIZMO_SPH
         part->conserved.mass = density * volume / count;
 #else
         part->mass = density * volume / count;
 #endif
+
+#if defined(HOPKINS_PE_SPH)
+        part->entropy = 1.f;
+        part->entropy_one_over_gamma = 1.f;
+#endif
+
         part->ti_begin = 0;
         part->ti_end = 1;
         ++part;
@@ -193,16 +200,11 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
 #if defined(GIZMO_SPH)
             0.f,
 #else
-            main_cell->parts[pid].rho_dh,
+            main_cell->parts[pid].density.rho_dh,
 #endif
             main_cell->parts[pid].density.wcount,
             main_cell->parts[pid].density.wcount_dh,
-#if defined(GADGET2_SPH)
-            main_cell->parts[pid].density.div_v,
-            main_cell->parts[pid].density.rot_v[0],
-            main_cell->parts[pid].density.rot_v[1],
-            main_cell->parts[pid].density.rot_v[2]
-#elif defined(DEFAULT_SPH)
+#if defined(GADGET2_SPH) || defined(DEFAULT_SPH) || defined(HOPKINS_PE_SPH)
             main_cell->parts[pid].density.div_v,
             main_cell->parts[pid].density.rot_v[0],
             main_cell->parts[pid].density.rot_v[1],
@@ -235,13 +237,10 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
 #if defined(GIZMO_SPH)
               0.f,
 #else
-              main_cell->parts[pjd].rho_dh,
+              main_cell->parts[pjd].density.rho_dh,
 #endif
               cj->parts[pjd].density.wcount, cj->parts[pjd].density.wcount_dh,
-#if defined(GADGET2_SPH)
-              cj->parts[pjd].density.div_v, cj->parts[pjd].density.rot_v[0],
-              cj->parts[pjd].density.rot_v[1], cj->parts[pjd].density.rot_v[2]
-#elif defined(DEFAULT_SPH)
+#if defined(GADGET2_SPH) || defined(DEFAULT_SPH) || defined(HOPKINS_PE_SPH)
               cj->parts[pjd].density.div_v, cj->parts[pjd].density.rot_v[0],
               cj->parts[pjd].density.rot_v[1], cj->parts[pjd].density.rot_v[2]
 #else
diff --git a/tests/testInteractions.c b/tests/testInteractions.c
index 52ad0c54258848883a9025bbcd9d68133eddc4b9..d14c840ec77819bbef5750b897c72139f4d7b2b4 100644
--- a/tests/testInteractions.c
+++ b/tests/testInteractions.c
@@ -110,9 +110,9 @@ void dump_indv_particle_fields(char *fileName, struct part *p) {
           "%13e %13e %13e %13e "
           "%13e %13e %13e %10f\n",
           p->id, p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2],
-          p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->rho, p->rho_dh,
-          p->density.wcount, p->density.wcount_dh, p->force.h_dt,
-          p->force.v_sig,
+          p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->rho,
+          p->density.rho_dh, p->density.wcount, p->density.wcount_dh,
+          p->force.h_dt, p->force.v_sig,
 #if defined(GADGET2_SPH)
           p->density.div_v, p->density.rot_v[0], p->density.rot_v[1],
           p->density.rot_v[2], p->entropy_dt
diff --git a/tests/testPair.c b/tests/testPair.c
index efa1e628c2d57bf7922be8affdd5436ebca2f9cf..8b272b866431db3bfe36239222cd87d669961ae7 100644
--- a/tests/testPair.c
+++ b/tests/testPair.c
@@ -139,10 +139,10 @@ void dump_particle_fields(char *fileName, struct cell *ci, struct cell *cj) {
 #if defined(GIZMO_SPH)
             0.f,
 #else
-            cj->parts[pid].rho_dh,
+            ci->parts[pid].density.rho_dh,
 #endif
             ci->parts[pid].density.wcount, ci->parts[pid].density.wcount_dh,
-#if defined(GADGET2_SPH) || defined(DEFAULT_SPH)
+#if defined(GADGET2_SPH) || defined(DEFAULT_SPH) || defined(HOPKINS_PE_SPH)
             ci->parts[pid].density.div_v, ci->parts[pid].density.rot_v[0],
             ci->parts[pid].density.rot_v[1], ci->parts[pid].density.rot_v[2]
 #else
@@ -163,10 +163,10 @@ void dump_particle_fields(char *fileName, struct cell *ci, struct cell *cj) {
 #if defined(GIZMO_SPH)
             0.f,
 #else
-            cj->parts[pjd].rho_dh,
+            cj->parts[pjd].density.rho_dh,
 #endif
             cj->parts[pjd].density.wcount, cj->parts[pjd].density.wcount_dh,
-#if defined(GADGET2_SPH) || defined(DEFAULT_SPH)
+#if defined(GADGET2_SPH) || defined(DEFAULT_SPH) || defined(HOPKINS_PE_SPH)
             cj->parts[pjd].density.div_v, cj->parts[pjd].density.rot_v[0],
             cj->parts[pjd].density.rot_v[1], cj->parts[pjd].density.rot_v[2]
 #else
diff --git a/tests/testSPHStep.c b/tests/testSPHStep.c
index fa49ed9d00c37393abd2f7e17ae628d79b4125f6..ff2ec841b27bd5ca6190517bc39f4da0c28fbc0c 100644
--- a/tests/testSPHStep.c
+++ b/tests/testSPHStep.c
@@ -102,10 +102,6 @@ int main() {
 
   int i, j, k, offset[3];
   struct part *p;
-  struct hydro_props hp;
-  hp.target_neighbours = 48.;
-  hp.delta_neighbours = 1.;
-  hp.max_smoothing_iterations = 30;
 
   int N = 10;
   float dim = 1.;
@@ -146,11 +142,24 @@ int main() {
   /* Create the infrastructure */
   struct space space;
   space.periodic = 0;
-  space.h_max = 1.;
+  space.cell_min = 1.;
+
+  struct phys_const prog_const;
+  prog_const.const_newton_G = 1.f;
+
+  struct hydro_props hp;
+  hp.target_neighbours = 48.f;
+  hp.delta_neighbours = 2.;
+  hp.max_smoothing_iterations = 1;
+  hp.CFL_condition = 0.1;
 
   struct engine e;
-  e.s = &space;
+  bzero(&e, sizeof(struct engine));
   e.hydro_properties = &hp;
+  e.physical_constants = &prog_const;
+  e.s = &space;
+  e.time = 0.1f;
+  e.ti_current = 1;
 
   struct runner r;
   r.e = &e;
diff --git a/tests/tolerance_27_normal.dat b/tests/tolerance_27_normal.dat
index 141ed3baeedd5dad7a2fda0730c2e9c828ae4b2e..71acaa89be231d02fc33e47c96a7bacf623bbf48 100644
--- a/tests/tolerance_27_normal.dat
+++ b/tests/tolerance_27_normal.dat
@@ -1,3 +1,3 @@
 #   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	   1e-6	      2e-6	    2e-5       2e-3		 2e-6	     2e-6	   2e-6		 2e-6
-    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      1e-6	    1e-5       1e-4		 2e-5	     2e-5	   2e-5	 	 2e-5
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      2e-6	    1e-5       1e-4		 2e-5	     2e-5	   2e-5	 	 2e-5
diff --git a/tests/tolerance_27_perturbed.dat b/tests/tolerance_27_perturbed.dat
index f0417d845f83d171dacb6b66024cf9a5dc41c6f1..45293cbaa223b5887f3b0ce05cd9430d0db7440b 100644
--- a/tests/tolerance_27_perturbed.dat
+++ b/tests/tolerance_27_perturbed.dat
@@ -1,3 +1,3 @@
 #   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	   1.2e-6     2e-6	    2.1e-5     2e-3		 2.1e-6	     2e-6	   2e-6		 2e-6
-    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      1e-6	    1e-5       1e-4		 2e-5	     4e-4	   4e-4	 	 4e-4
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1.2e-6     1e-5	    2.1e-5     2e-3		 2.1e-6	     2e-6	   2e-6		 2e-6
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-6	      3e-3	    1e-5       1e-4		 2e-5	     4e-4	   4e-4	 	 4e-4