diff --git a/.gitignore b/.gitignore
index 3c643647a07a91402d4ca63e12ba7d17aaf975a4..cc936154b298d48a7661070b35dc7d2f326d56ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@ tests/swift_dopair_standard.dat
 tests/brute_force_perturbed.dat
 tests/swift_dopair_perturbed.dat
 tests/test27cells
+tests/test27cells_subset
 tests/testPeriodicBC
 tests/test125cells
 tests/brute_force_27_standard.dat
@@ -121,6 +122,7 @@ theory/Multipoles/potential.pdf
 theory/Multipoles/potential_long.pdf
 theory/Multipoles/potential_short.pdf
 theory/Multipoles/force_short.pdf
+theory/Cosmology/cosmology.pdf
 
 m4/libtool.m4
 m4/ltoptions.m4
diff --git a/INSTALL.swift b/INSTALL.swift
index e1efc945c83742cbd2cc2e9fe7afeec5cc9d1145..1782b75e34e2028110717d7873bc2c97365f8240 100644
--- a/INSTALL.swift
+++ b/INSTALL.swift
@@ -116,6 +116,8 @@ before you can build it.
 	much like the CC one. Use this when your MPI compiler has a
 	none-standard name.
 
+ - GSL: To use cosmological time integration, a version of the GSL
+        must be available. 
 
  - libtool: The build system relies on libtool as well as the other autotools.
 
diff --git a/configure.ac b/configure.ac
index b027d5b2159ce9b63d01117f9a6f07efa39c6311..c95548229667a3a90941f723da93f997cb03b66e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -407,6 +407,14 @@ AC_HEADER_STDC
 # Check for the libraries we will need.
 AC_CHECK_LIB(m,sqrt,,AC_MSG_ERROR(something is wrong with the math library!))
 
+# Check for GSL
+have_gsl="no"
+AC_CHECK_LIB([gslcblas], [cblas_dgemm])
+AC_CHECK_LIB([gsl], [gsl_integration_qag])
+if test "x$ac_cv_lib_gslcblas_cblas_dgemm" != "x"; then
+   have_gsl="yes"
+fi
+
 # Check for pthreads.
 AX_PTHREAD([LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
     CC="$PTHREAD_CC" LDFLAGS="$LDFLAGS $PTHREAD_LIBS $LIBS"],
@@ -1054,6 +1062,7 @@ AC_MSG_RESULT([
     - parallel      : $have_parallel_hdf5
    Metis enabled    : $have_metis
    FFTW3 enabled    : $have_fftw3
+   GSL enabled      : $have_gsl
    libNUMA enabled  : $have_numa
    GRACKLE enabled  : $have_grackle
    Using tcmalloc   : $have_tcmalloc
diff --git a/examples/CosmologicalBox/cosmo.yml b/examples/CosmologicalBox/cosmo.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a82cc5610b3317076a908902efdbd5b87d94262a
--- /dev/null
+++ b/examples/CosmologicalBox/cosmo.yml
@@ -0,0 +1,49 @@
+# Define the system of units to use internally. 
+InternalUnitSystem:
+  UnitMass_in_cgs:     1.989e43      # 10^10 M_sun in grams
+  UnitLength_in_cgs:   3.085678e24   # Mpc in centimeters
+  UnitVelocity_in_cgs: 1e5           # km/s in centimeters per second
+  UnitCurrent_in_cgs:  1             # Amperes
+  UnitTemp_in_cgs:     1             # Kelvin
+
+#  UnitMass_in_cgs:     1   # Grams
+#  UnitLength_in_cgs:   1   # Centimeters
+#  UnitVelocity_in_cgs: 1   # Centimeters per second
+#  UnitCurrent_in_cgs:  1   # Amperes
+#  UnitTemp_in_cgs:     1   # Kelvin
+
+# Parameters governing the time integration
+TimeIntegration:
+  time_begin: 0.    # The starting time of the simulation (in internal units).
+  time_end:   1.    # The end time of the simulation (in internal units).
+  dt_min:     1e-6  # The minimal time-step size of the simulation (in internal units).
+  dt_max:     1e-2  # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  basename:            uniformBox # Common part of the name of output files
+  time_first:          0.         # Time of the first output (in internal units)
+  delta_time:          0.01       # Time difference between consecutive outputs (in internal units)
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  delta_time:          1e-2 # Time between statistics output
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:  ./uniformBox.hdf5     # The file to read
+
+Cosmology:
+  Omega_m:        0.307
+  Omega_lambda:   0.693
+  Omega_b:        0.0455
+  h:              0.6777
+  a_begin:        0.0078125
+  a_end:          1.0
+  
+
diff --git a/examples/CosmologicalBox/makeIC.py b/examples/CosmologicalBox/makeIC.py
new file mode 100644
index 0000000000000000000000000000000000000000..01e37c67b6e2eec2984d62f4ffd503b23b5bd9ec
--- /dev/null
+++ b/examples/CosmologicalBox/makeIC.py
@@ -0,0 +1,109 @@
+###############################################################################
+ # This file is part of SWIFT.
+ # Copyright (c) 2013 Pedro Gonnet (pedro.gonnet@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/>.
+ # 
+ ##############################################################################
+
+import h5py
+import sys
+from numpy import *
+
+# Generates a swift IC file containing a cartesian distribution of particles
+# at a constant density and pressure in a cubic box
+
+# Parameters
+periodic= 1           # 1 For periodic box
+boxSize = 1.
+L = int(sys.argv[1])  # Number of particles along one axis
+rho = 2.              # Density
+P = 1.                # Pressure
+gamma = 5./3.         # Gas adiabatic index
+eta = 1.2349          # 48 ngbs with cubic spline kernel
+fileName = "uniformBox.hdf5" 
+
+#---------------------------------------------------
+numPart = L**3
+mass = boxSize**3 * rho / numPart
+internalEnergy = P / ((gamma - 1.)*rho)
+
+#--------------------------------------------------
+
+#File
+file = h5py.File(fileName, 'w')
+
+# Header
+grp = file.create_group("/Header")
+grp.attrs["BoxSize"] = boxSize
+grp.attrs["NumPart_Total"] =  [numPart, 0, 0, 0, 0, 0]
+grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0]
+grp.attrs["NumPart_ThisFile"] = [numPart, 0, 0, 0, 0, 0]
+grp.attrs["Time"] = 0.0
+grp.attrs["NumFilesPerSnapshot"] = 1
+grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+grp.attrs["Flag_Entropy_ICs"] = 0
+grp.attrs["Dimension"] = 3
+
+#Runtime parameters
+grp = file.create_group("/RuntimePars")
+grp.attrs["PeriodicBoundariesOn"] = periodic
+
+#Units
+grp = file.create_group("/Units")
+grp.attrs["Unit length in cgs (U_L)"] = 1.
+grp.attrs["Unit mass in cgs (U_M)"] = 1.
+grp.attrs["Unit time in cgs (U_t)"] = 1.
+grp.attrs["Unit current in cgs (U_I)"] = 1.
+grp.attrs["Unit temperature in cgs (U_T)"] = 1.
+
+#Particle group
+grp = file.create_group("/PartType0")
+
+v  = zeros((numPart, 3))
+ds = grp.create_dataset('Velocities', (numPart, 3), 'f')
+ds[()] = v
+v = zeros(1)
+
+m = full((numPart, 1), mass)
+ds = grp.create_dataset('Masses', (numPart,1), 'f')
+ds[()] = m
+m = zeros(1)
+
+h = full((numPart, 1), eta * boxSize / L)
+ds = grp.create_dataset('SmoothingLength', (numPart,1), 'f')
+ds[()] = h
+h = zeros(1)
+
+u = full((numPart, 1), internalEnergy)
+ds = grp.create_dataset('InternalEnergy', (numPart,1), 'f')
+ds[()] = u
+u = zeros(1)
+
+
+ids = linspace(0, numPart, numPart, endpoint=False).reshape((numPart,1))
+ds = grp.create_dataset('ParticleIDs', (numPart, 1), 'L')
+ds[()] = ids + 1
+x      = ids % L;
+y      = ((ids - x) / L) % L;
+z      = (ids - x - L * y) / L**2;
+coords = zeros((numPart, 3))
+coords[:,0] = z[:,0] * boxSize / L + boxSize / (2*L)
+coords[:,1] = y[:,0] * boxSize / L + boxSize / (2*L)
+coords[:,2] = x[:,0] * boxSize / L + boxSize / (2*L)
+ds = grp.create_dataset('Coordinates', (numPart, 3), 'd')
+ds[()] = coords
+
+file.close()
diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml
index 054356c2fb2e883ac4dcf49ecf477d076a17e658..af55da76ff513548bee52e51993fa8b78cfdc9e3 100644
--- a/examples/EAGLE_12/eagle_12.yml
+++ b/examples/EAGLE_12/eagle_12.yml
@@ -13,13 +13,22 @@ TimeIntegration:
   dt_min:     1e-10 # The minimal time-step size of the simulation (in internal units).
   dt_max:     1e-4  # The maximal time-step size of the simulation (in internal units).
 
+# Cosmological parameters
+Cosmology:
+  h:              0.6777        # Reduced Hubble constant
+  a_begin:        0.9090909     # Initial scale-factor of the simulation
+  a_end:          1.0           # Final scale factor of the simulation
+  Omega_m:        0.307         # Matter density parameter
+  Omega_lambda:   0.693         # Dark-energy density parameter
+  Omega_b:        0.0455        # Baryon density parameter
+  
 Scheduler:
   max_top_level_cells:    15
   
 # Parameters governing the snapshots
 Snapshots:
   basename:            eagle # Common part of the name of output files
-  time_first:          0.    # Time of the first output (in internal units)
+  time_first:          1.    # Time of the first output (in internal units)
   delta_time:          1e-3  # Time difference between consecutive outputs (in internal units)
 
 # Parameters governing the conserved quantities statistics
diff --git a/examples/SedovBlast_1D/makeIC.py b/examples/SedovBlast_1D/makeIC.py
index 0c3a311703651003dbf17da099e53bf8a607b881..7177f3a7670aa054e3d7341a11a7359b3d855837 100644
--- a/examples/SedovBlast_1D/makeIC.py
+++ b/examples/SedovBlast_1D/makeIC.py
@@ -23,7 +23,7 @@ from numpy import *
 # Generates a swift IC file for the Sedov blast test in a periodic cubic box
 
 # Parameters
-numPart = 1000   
+numPart = 1001
 gamma = 5./3.      # Gas adiabatic index
 rho0 = 1.          # Background density
 P0 = 1.e-6         # Background pressure
diff --git a/examples/main.c b/examples/main.c
index 6244a7bb615d2a29002625a4ca233aec7ab11eeb..828bf871bb034ce76a1a2454ed7e7dbb43e01443 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -126,6 +126,7 @@ int main(int argc, char *argv[]) {
    * scope.  */
   struct chemistry_data chemistry;
   struct cooling_function_data cooling_func;
+  struct cosmology cosmo;
   struct external_potential potential;
   struct gpart *gparts = NULL;
   struct gravity_props gravity_properties;
@@ -600,6 +601,13 @@ int main(int argc, char *argv[]) {
       phys_const_print(&prog_const);
     }
 
+    /* Initialise the cosmology */
+    if (with_cosmology)
+      cosmology_init(params, &us, &prog_const, &cosmo);
+    else
+      cosmology_init_no_cosmo(&cosmo);
+    if (with_cosmology) cosmology_print(&cosmo);
+
     /* Initialise the hydro properties */
     if (with_hydro) hydro_props_init(&hydro_properties, params);
     if (with_hydro) eos_init(&eos, params);
@@ -767,9 +775,9 @@ int main(int argc, char *argv[]) {
     /* Initialize the engine with the space and policies. */
     if (myrank == 0) clocks_gettime(&tic);
     engine_init(&e, &s, params, N_total[0], N_total[1], engine_policies,
-                talking, &reparttype, &us, &prog_const, &hydro_properties,
-                &gravity_properties, &potential, &cooling_func, &chemistry,
-                &sourceterms);
+                talking, &reparttype, &us, &prog_const, &cosmo,
+                &hydro_properties, &gravity_properties, &potential,
+                &cooling_func, &chemistry, &sourceterms);
     engine_config(0, &e, params, nr_nodes, myrank, nr_threads, with_aff,
                   talking, restart_file);
     if (myrank == 0) {
@@ -790,7 +798,7 @@ int main(int argc, char *argv[]) {
           "from t=%.3e until t=%.3e with %d threads and %d queues "
           "(dt_min=%.3e, "
           "dt_max=%.3e)...",
-          e.timeBegin, e.timeEnd, e.nr_threads, e.sched.nr_queues, e.dt_min,
+          e.time_begin, e.time_end, e.nr_threads, e.sched.nr_queues, e.dt_min,
           e.dt_max);
       fflush(stdout);
     }
@@ -837,9 +845,10 @@ int main(int argc, char *argv[]) {
 
   /* Legend */
   if (myrank == 0)
-    printf("# %6s %14s %14s %12s %12s %12s %16s [%s] %6s\n", "Step", "Time",
-           "Time-step", "Updates", "g-Updates", "s-Updates", "Wall-clock time",
-           clocks_getunit(), "Props");
+    printf("# %6s %14s %14s %14s %9s %12s %12s %12s %16s [%s] %6s\n", "Step",
+           "Time", "Scale-factor", "Time-step", "Time-bins", "Updates",
+           "g-Updates", "s-Updates", "Wall-clock time", clocks_getunit(),
+           "Props");
 
   /* File for the timers */
   if (with_verbose_timers) timers_open_file(myrank);
@@ -865,8 +874,7 @@ int main(int argc, char *argv[]) {
     if (with_verbose_timers) timers_print(e.step);
 
     /* Every so often allow the user to stop the application and dump the
-     * restart
-     * files. */
+     * restart files. */
     if (j % restart_stop_steps == 0) {
       force_stop = restart_stop_now(restart_dir, 0);
       if (myrank == 0 && force_stop)
@@ -874,8 +882,7 @@ int main(int argc, char *argv[]) {
     }
 
     /* Also if using nsteps to exit, will not have saved any restarts on exit,
-     * make
-     * sure we do that (useful in testing only). */
+     * make sure we do that (useful in testing only). */
     if (force_stop || (e.restart_onexit && e.step - 1 == nsteps))
       engine_dump_restarts(&e, 0, 1);
 
diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml
index e304639cb579e0bdec9926775c45fb445da18b80..4784a877a21e698af28f72aab473ac9c3cad605e 100644
--- a/examples/parameter_example.yml
+++ b/examples/parameter_example.yml
@@ -10,6 +10,36 @@ InternalUnitSystem:
 PhysicalConstants:
   G:            6.67408e-8 # (Optional) Overwrite the value of Newton's constant used internally by the code.
 
+# Cosmological parameters
+Cosmology:
+  h:              0.6777        # Reduced Hubble constant
+  a_begin:        0.0078125     # Initial scale-factor of the simulation
+  a_end:          1.0           # Final scale factor of the simulation
+  Omega_m:        0.307         # Matter density parameter
+  Omega_lambda:   0.693         # Dark-energy density parameter
+  Omega_b:        0.0455        # Baryon density parameter
+  Omega_r:        0.            # (Optional) Radiation density parameter
+  w_0:            -1.0          # (Optional) Dark-energy equation-of-state parameter at z=0.
+  w_a:            0.            # (Optional) Dark-energy equation-of-state time evolution parameter.
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  h_tolerance:           1e-4     # (Optional) Relative accuracy of the Netwon-Raphson scheme for the smoothing lengths.
+  h_max:                 10.      # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified.
+  max_volume_change:     1.4      # (Optional) Maximal allowed change of kernel volume over one time-step.
+  max_ghost_iterations:  30       # (Optional) Maximal number of iterations allowed to converge towards the smoothing length.
+
+# Parameters for the self-gravity scheme
+Gravity:
+  eta:          0.025    # Constant dimensionless multiplier for time integration.
+  theta:        0.7      # Opening angle (Multipole acceptance criterion)
+  epsilon:      0.1      # Softening length (in internal units).
+  a_smooth:     1.25     # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value).
+  r_cut_max:    4.5      # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value).
+  r_cut_min:    0.1      # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value).
+
 # Parameters for the task scheduling
 Scheduler:
   nr_queues:                 0         # (Optional) The number of task queues to use. Use 0  to let the system decide.
@@ -48,27 +78,6 @@ Statistics:
   energy_file_name:    energy    # (Optional) File name for energy output
   timestep_file_name:  timesteps # (Optional) File name for timing information output. Note: No underscores "_" allowed in file name
 
-# Parameters for the hydrodynamics scheme
-SPH:
-  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
-  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
-  h_tolerance:           1e-4     # (Optional) Relative accuracy of the Netwon-Raphson scheme for the smoothing lengths.
-  h_max:                 10.      # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified.
-  max_volume_change:     1.4      # (Optional) Maximal allowed change of kernel volume over one time-step.
-  max_ghost_iterations:  30       # (Optional) Maximal number of iterations allowed to converge towards the smoothing length.
-
-EoS:
-  isothermal_internal_energy: 20.26784 # Thermal energy per unit mass for the case of isothermal equation of state (in internal units).
-
-# Parameters for the self-gravity scheme
-Gravity:
-  eta:          0.025    # Constant dimensionless multiplier for time integration.
-  theta:        0.7      # Opening angle (Multipole acceptance criterion)
-  epsilon:      0.1      # Softening length (in internal units).
-  a_smooth:     1.25     # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value).
-  r_cut_max:    4.5      # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value).
-  r_cut_min:    0.1      # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value).
-
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  SedovBlast/sedov.hdf5 # The file to read
@@ -108,6 +117,11 @@ DomainDecomposition:
   minfrac:          0.9     # (Optional) Fractional of all particles that should be updated in previous step when
                             # using CPU time trigger
 
+# Parameters related to the equation of state ------------------------------------------
+
+EoS:
+  isothermal_internal_energy: 20.26784 # Thermal energy per unit mass for the case of isothermal equation of state (in internal units).
+
 # Parameters related to external potentials --------------------------------------------
 
 # Point mass external potentials
diff --git a/examples/plot_scaling_results.py b/examples/plot_scaling_results.py
index 9e938c720f81dcf2246d2e48922ec5b4dd404f3e..e39f0d2d0c00eecf7680b2f090bd2c0aa29ed8bb 100755
--- a/examples/plot_scaling_results.py
+++ b/examples/plot_scaling_results.py
@@ -148,8 +148,8 @@ def parse_files():
     
     # Loop over all files for a given series and load the times
     for j in range(0,len(file_list)):
-      times = np.loadtxt(file_list[j],usecols=(6,))
-      updates = np.loadtxt(file_list[j],usecols=(3,))
+      times = np.loadtxt(file_list[j],usecols=(9,))
+      updates = np.loadtxt(file_list[j],usecols=(6,))
       totalTime[i].append(np.sum(times))
       
     sumTotal.append(np.sum(totalTime[i]))
diff --git a/examples/plot_scaling_results_breakdown.py b/examples/plot_scaling_results_breakdown.py
index 92a9564c326b9a4d33c047a87f7792d257c96b69..6a87e42bcd393d543187e768e31a15bc56f1ae6a 100755
--- a/examples/plot_scaling_results_breakdown.py
+++ b/examples/plot_scaling_results_breakdown.py
@@ -149,8 +149,8 @@ def parse_files():
    
     # Loop over all files for a given series and load the times
     for j in range(0,len(file_list)):
-      times = np.loadtxt(file_list[j],usecols=(6,), skiprows=11)
-      updates = np.loadtxt(file_list[j],usecols=(3,), skiprows=11)
+      times = np.loadtxt(file_list[j],usecols=(9,))
+      updates = np.loadtxt(file_list[j],usecols=(6,))
       totalTime[i].append(np.sum(times))
       
     sumTotal.append(np.sum(totalTime[i]))
diff --git a/src/Makefile.am b/src/Makefile.am
index 7b216af3ad083379f182fb6e8d887b4767837bc5..0c8b53de3cca4ad4836834d13c9710ccce0cce00 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,7 +47,7 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \
     sourceterms_struct.h statistics.h memswap.h cache.h runner_doiact_vec.h profiler.h \
     dump.h logger.h active.h timeline.h xmf.h gravity_properties.h gravity_derivatives.h \
     gravity_softened_derivatives.h vector_power.h collectgroup.h hydro_space.h sort_part.h \
-    chemistry.h chemistry_io.h chemistry_struct.h restart.h
+    chemistry.h chemistry_io.h chemistry_struct.h cosmology.h restart.h
 
 # Common source files
 AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \
@@ -59,7 +59,7 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \
     statistics.c runner_doiact_vec.c profiler.c dump.c logger.c \
     part_type.c xmf.c gravity_properties.c gravity.c \
     collectgroup.c hydro_space.c equation_of_state.c \
-    chemistry.c restart.c
+    chemistry.c cosmology.c restart.c
 
 # Include files for distribution, not installation.
 nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \
diff --git a/src/active.h b/src/active.h
index 9eb4123392f4b1b6bca2f68d59991ff90b92614d..3fe52a86b373ff0b33b88eca0dac9b7c6b58a216 100644
--- a/src/active.h
+++ b/src/active.h
@@ -42,9 +42,9 @@ __attribute__((always_inline)) INLINE static int cell_are_part_drifted(
   if (c->ti_old_part > e->ti_current)
     error(
         "Cell has been drifted too far forward in time! c->ti_old=%lld (t=%e) "
-        "and e->ti_current=%lld (t=%e)",
-        c->ti_old_part, c->ti_old_part * e->timeBase, e->ti_current,
-        e->ti_current * e->timeBase);
+        "and e->ti_current=%lld (t=%e, a=%e)",
+        c->ti_old_part, c->ti_old_part * e->time_base, e->ti_current,
+        e->ti_current * e->time_base, e->cosmology->a);
 #endif
 
   return (c->ti_old_part == e->ti_current);
@@ -66,8 +66,8 @@ __attribute__((always_inline)) INLINE static int cell_are_gpart_drifted(
     error(
         "Cell has been drifted too far forward in time! c->ti_old=%lld (t=%e) "
         "and e->ti_current=%lld (t=%e)",
-        c->ti_old_gpart, c->ti_old_gpart * e->timeBase, e->ti_current,
-        e->ti_current * e->timeBase);
+        c->ti_old_gpart, c->ti_old_gpart * e->time_base, e->ti_current,
+        e->ti_current * e->time_base);
 #endif
 
   return (c->ti_old_gpart == e->ti_current);
@@ -89,9 +89,9 @@ __attribute__((always_inline)) INLINE static int cell_is_active_hydro(
   if (c->ti_hydro_end_min < e->ti_current)
     error(
         "cell in an impossible time-zone! c->ti_end_min=%lld (t=%e) and "
-        "e->ti_current=%lld (t=%e)",
-        c->ti_hydro_end_min, c->ti_hydro_end_min * e->timeBase, e->ti_current,
-        e->ti_current * e->timeBase);
+        "e->ti_current=%lld (t=%e, a=%e)",
+        c->ti_hydro_end_min, c->ti_hydro_end_min * e->time_base, e->ti_current,
+        e->ti_current * e->time_base, e->cosmology->a);
 #endif
 
   return (c->ti_hydro_end_min == e->ti_current);
@@ -132,9 +132,9 @@ __attribute__((always_inline)) INLINE static int cell_is_active_gravity(
   if (c->ti_gravity_end_min < e->ti_current)
     error(
         "cell in an impossible time-zone! c->ti_end_min=%lld (t=%e) and "
-        "e->ti_current=%lld (t=%e)",
-        c->ti_gravity_end_min, c->ti_gravity_end_min * e->timeBase,
-        e->ti_current, e->ti_current * e->timeBase);
+        "e->ti_current=%lld (t=%e, a=%e)",
+        c->ti_gravity_end_min, c->ti_gravity_end_min * e->time_base,
+        e->ti_current, e->ti_current * e->time_base, e->cosmology->a);
 #endif
 
   return (c->ti_gravity_end_min == e->ti_current);
@@ -265,9 +265,9 @@ __attribute__((always_inline)) INLINE static int cell_is_starting_hydro(
   if (c->ti_hydro_beg_max > e->ti_current)
     error(
         "cell in an impossible time-zone! c->ti_beg_max=%lld (t=%e) and "
-        "e->ti_current=%lld (t=%e)",
-        c->ti_hydro_beg_max, c->ti_hydro_beg_max * e->timeBase, e->ti_current,
-        e->ti_current * e->timeBase);
+        "e->ti_current=%lld (t=%e, a=%e)",
+        c->ti_hydro_beg_max, c->ti_hydro_beg_max * e->time_base, e->ti_current,
+        e->ti_current * e->time_base, e->cosmology->a);
 #endif
 
   return (c->ti_hydro_beg_max == e->ti_current);
@@ -287,9 +287,9 @@ __attribute__((always_inline)) INLINE static int cell_is_starting_gravity(
   if (c->ti_gravity_beg_max > e->ti_current)
     error(
         "cell in an impossible time-zone! c->ti_beg_max=%lld (t=%e) and "
-        "e->ti_current=%lld (t=%e)",
-        c->ti_gravity_beg_max, c->ti_gravity_beg_max * e->timeBase,
-        e->ti_current, e->ti_current * e->timeBase);
+        "e->ti_current=%lld (t=%e, a=%e)",
+        c->ti_gravity_beg_max, c->ti_gravity_beg_max * e->time_base,
+        e->ti_current, e->ti_current * e->time_base, e->cosmology->a);
 #endif
 
   return (c->ti_gravity_beg_max == e->ti_current);
diff --git a/src/adiabatic_index.h b/src/adiabatic_index.h
index 94504af18b7b9ae99fc8c7abaf097e985cb53ab6..e7798f7be6e28536191475f3c940c6f84a92bdad 100644
--- a/src/adiabatic_index.h
+++ b/src/adiabatic_index.h
@@ -431,4 +431,73 @@ __attribute__((always_inline)) INLINE static float pow_one_over_gamma(float x) {
 #endif
 }
 
+/**
+ * @brief Return the argument to the power three adiabatic index minus two.
+ *
+ * Computes \f$x^{3\gamma - 2}\f$.
+ *
+ * @param x Argument
+ */
+__attribute__((always_inline)) INLINE static float pow_three_gamma_minus_two(
+    float x) {
+
+#if defined(HYDRO_GAMMA_5_3)
+
+  return x * x * x; /* x^(3) */
+
+#elif defined(HYDRO_GAMMA_7_5)
+
+  return powf(x, 2.2f); /* x^(11/5) */
+
+#elif defined(HYDRO_GAMMA_4_3)
+
+  return x * x; /* x^(2) */
+
+#elif defined(HYDRO_GAMMA_2_1)
+
+  return x * x * x * x; /* x^(4) */
+
+#else
+
+  error("The adiabatic index is not defined !");
+  return 0.f;
+
+#endif
+}
+
+/**
+ * @brief Return the argument to the power three adiabatic index minus five over
+ * two.
+ *
+ * Computes \f$x^{(3\gamma - 5)/2}\f$.
+ *
+ * @param x Argument
+ */
+__attribute__((always_inline)) INLINE static float
+pow_three_gamma_minus_five_over_two(float x) {
+
+#if defined(HYDRO_GAMMA_5_3)
+
+  return 1.f; /* x^(0) */
+
+#elif defined(HYDRO_GAMMA_7_5)
+
+  return powf(x, -0.4f); /* x^(-2/5) */
+
+#elif defined(HYDRO_GAMMA_4_3)
+
+  return 1.f / sqrtf(x); /* x^(-1/2) */
+
+#elif defined(HYDRO_GAMMA_2_1)
+
+  return sqrtf(x); /* x^(1/2) */
+
+#else
+
+  error("The adiabatic index is not defined !");
+  return 0.f;
+
+#endif
+}
+
 #endif /* SWIFT_ADIABATIC_INDEX_H */
diff --git a/src/cell.c b/src/cell.c
index d5745d532d6a5e9f1581d21b687b9572238f2e4e..78a50141779d368fae646d4727f63633bbef3683 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -2280,14 +2280,11 @@ int cell_has_tasks(struct cell *c) {
 void cell_drift_part(struct cell *c, const struct engine *e, int force) {
 
   const float hydro_h_max = e->hydro_properties->h_max;
-  const double timeBase = e->timeBase;
   const integertime_t ti_old_part = c->ti_old_part;
   const integertime_t ti_current = e->ti_current;
   struct part *const parts = c->parts;
   struct xpart *const xparts = c->xparts;
 
-  /* Drift from the last time the cell was drifted to the current time */
-  const double dt = (ti_current - ti_old_part) * timeBase;
   float dx_max = 0.f, dx2_max = 0.f;
   float dx_max_sort = 0.0f, dx2_max_sort = 0.f;
   float cell_h_max = 0.f;
@@ -2307,7 +2304,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
   if (c->split && (force || c->do_sub_drift)) {
 
     /* Loop over the progeny and collect their data. */
-    for (int k = 0; k < 8; k++)
+    for (int k = 0; k < 8; k++) {
       if (c->progeny[k] != NULL) {
         struct cell *cp = c->progeny[k];
 
@@ -2319,6 +2316,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
         dx_max_sort = max(dx_max_sort, cp->dx_max_sort);
         cell_h_max = max(cell_h_max, cp->h_max);
       }
+    }
 
     /* Store the values */
     c->h_max = cell_h_max;
@@ -2330,6 +2328,24 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
 
   } else if (!c->split && force && ti_current > ti_old_part) {
 
+    /* Drift from the last time the cell was drifted to the current time */
+    double dt_drift, dt_kick_grav, dt_kick_hydro, dt_therm;
+    if (e->policy & engine_policy_cosmology) {
+      dt_drift =
+          cosmology_get_drift_factor(e->cosmology, ti_old_part, ti_current);
+      dt_kick_grav =
+          cosmology_get_grav_kick_factor(e->cosmology, ti_old_part, ti_current);
+      dt_kick_hydro = cosmology_get_hydro_kick_factor(e->cosmology, ti_old_part,
+                                                      ti_current);
+      dt_therm = cosmology_get_therm_kick_factor(e->cosmology, ti_old_part,
+                                                 ti_current);
+    } else {
+      dt_drift = (ti_current - ti_old_part) * e->time_base;
+      dt_kick_grav = (ti_current - ti_old_part) * e->time_base;
+      dt_kick_hydro = (ti_current - ti_old_part) * e->time_base;
+      dt_therm = (ti_current - ti_old_part) * e->time_base;
+    }
+
     /* Loop over all the gas particles in the cell */
     const size_t nr_parts = c->count;
     for (size_t k = 0; k < nr_parts; k++) {
@@ -2339,7 +2355,8 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
       struct xpart *const xp = &xparts[k];
 
       /* Drift... */
-      drift_part(p, xp, dt, timeBase, ti_old_part, ti_current);
+      drift_part(p, xp, dt_drift, dt_kick_hydro, dt_kick_grav, dt_therm,
+                 ti_old_part, ti_current);
 
       /* Limit h to within the allowed range */
       p->h = min(p->h, hydro_h_max);
@@ -2391,14 +2408,11 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
  */
 void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
 
-  const double timeBase = e->timeBase;
   const integertime_t ti_old_gpart = c->ti_old_gpart;
   const integertime_t ti_current = e->ti_current;
   struct gpart *const gparts = c->gparts;
   struct spart *const sparts = c->sparts;
 
-  /* Drift from the last time the cell was drifted to the current time */
-  const double dt = (ti_current - ti_old_gpart) * timeBase;
   float dx_max = 0.f, dx2_max = 0.f;
 
   /* Drift irrespective of cell flags? */
@@ -2416,7 +2430,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
   if (c->split && (force || c->do_grav_sub_drift)) {
 
     /* Loop over the progeny and collect their data. */
-    for (int k = 0; k < 8; k++)
+    for (int k = 0; k < 8; k++) {
       if (c->progeny[k] != NULL) {
         struct cell *cp = c->progeny[k];
 
@@ -2426,6 +2440,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
         /* Update */
         dx_max = max(dx_max, cp->dx_max_gpart);
       }
+    }
 
     /* Store the values */
     c->dx_max_gpart = dx_max;
@@ -2435,6 +2450,14 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
 
   } else if (!c->split && force && ti_current > ti_old_gpart) {
 
+    /* Drift from the last time the cell was drifted to the current time */
+    double dt_drift;
+    if (e->policy & engine_policy_cosmology)
+      dt_drift =
+          cosmology_get_drift_factor(e->cosmology, ti_old_gpart, ti_current);
+    else
+      dt_drift = (ti_current - ti_old_gpart) * e->time_base;
+
     /* Loop over all the g-particles in the cell */
     const size_t nr_gparts = c->gcount;
     for (size_t k = 0; k < nr_gparts; k++) {
@@ -2443,7 +2466,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
       struct gpart *const gp = &gparts[k];
 
       /* Drift... */
-      drift_gpart(gp, dt, timeBase, ti_old_gpart, ti_current);
+      drift_gpart(gp, dt_drift, ti_old_gpart, ti_current);
 
       /* Compute (square of) motion since last cell construction */
       const float dx2 = gp->x_diff[0] * gp->x_diff[0] +
@@ -2465,7 +2488,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
       struct spart *const sp = &sparts[k];
 
       /* Drift... */
-      drift_spart(sp, dt, timeBase, ti_old_gpart, ti_current);
+      drift_spart(sp, dt_drift, ti_old_gpart, ti_current);
 
       /* Note: no need to compute dx_max as all spart have a gpart */
     }
@@ -2493,19 +2516,25 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
  */
 void cell_drift_all_multipoles(struct cell *c, const struct engine *e) {
 
-  const double timeBase = e->timeBase;
   const integertime_t ti_old_multipole = c->ti_old_multipole;
   const integertime_t ti_current = e->ti_current;
 
-  /* Drift from the last time the cell was drifted to the current time */
-  const double dt = (ti_current - ti_old_multipole) * timeBase;
-
+#ifdef SWIFT_DEBUG_CHECKS
   /* Check that we are actually going to move forward. */
   if (ti_current < ti_old_multipole) error("Attempt to drift to the past");
+#endif
+
+  /* Drift from the last time the cell was drifted to the current time */
+  double dt_drift;
+  if (e->policy & engine_policy_cosmology)
+    dt_drift =
+        cosmology_get_drift_factor(e->cosmology, ti_old_multipole, ti_current);
+  else
+    dt_drift = (ti_current - ti_old_multipole) * e->time_base;
 
   /* Drift the multipole */
   if (ti_current > ti_old_multipole)
-    gravity_drift(c->multipole, dt, c->dx_max_gpart);
+    gravity_drift(c->multipole, dt_drift, c->dx_max_gpart);
 
   /* Are we not in a leaf ? */
   if (c->split) {
@@ -2530,18 +2559,24 @@ void cell_drift_all_multipoles(struct cell *c, const struct engine *e) {
  */
 void cell_drift_multipole(struct cell *c, const struct engine *e) {
 
-  const double timeBase = e->timeBase;
   const integertime_t ti_old_multipole = c->ti_old_multipole;
   const integertime_t ti_current = e->ti_current;
 
-  /* Drift from the last time the cell was drifted to the current time */
-  const double dt = (ti_current - ti_old_multipole) * timeBase;
-
+#ifdef SWIFT_DEBUG_CHECKS
   /* Check that we are actually going to move forward. */
   if (ti_current < ti_old_multipole) error("Attempt to drift to the past");
+#endif
+
+  /* Drift from the last time the cell was drifted to the current time */
+  double dt_drift;
+  if (e->policy & engine_policy_cosmology)
+    dt_drift =
+        cosmology_get_drift_factor(e->cosmology, ti_old_multipole, ti_current);
+  else
+    dt_drift = (ti_current - ti_old_multipole) * e->time_base;
 
   if (ti_current > ti_old_multipole)
-    gravity_drift(c->multipole, dt, c->dx_max_gpart);
+    gravity_drift(c->multipole, dt_drift, c->dx_max_gpart);
 
   /* Update the time of the last drift */
   c->ti_old_multipole = ti_current;
diff --git a/src/chemistry.c b/src/chemistry.c
index 35a30d8301d92120498da3aa358c1cc3d617eee4..091a0b363d16507894f3dcbba2ca79860f3cbaa9 100644
--- a/src/chemistry.c
+++ b/src/chemistry.c
@@ -51,3 +51,28 @@ void chemistry_init(const struct swift_params* parameter_file,
 void chemistry_print(const struct chemistry_data* data) {
   chemistry_print_backend(data);
 }
+
+/**
+ * @brief Write a chemistry struct to the given FILE as a stream of bytes.
+ *
+ * @param chemistry the struct
+ * @param stream the file stream
+ */
+void chemistry_struct_dump(const struct chemistry_data* chemistry,
+                           FILE* stream) {
+  restart_write_blocks((void*)chemistry, sizeof(struct chemistry_data), 1,
+                       stream, "chemistry", "chemistry function");
+}
+
+/**
+ * @brief Restore a hydro_props struct from the given FILE as a stream of
+ * bytes.
+ *
+ * @param chemistry the struct
+ * @param stream the file stream
+ */
+void chemistry_struct_restore(const struct chemistry_data* chemistry,
+                              FILE* stream) {
+  restart_read_blocks((void*)chemistry, sizeof(struct chemistry_data), 1,
+                      stream, NULL, "chemistry function");
+}
diff --git a/src/chemistry.h b/src/chemistry.h
index 25de507d60d8aa4bbb9cc4f0f6499dc52aeb93d4..a5cbd77efbaab99e98ca5f031512e7e5bef0a613 100644
--- a/src/chemistry.h
+++ b/src/chemistry.h
@@ -50,4 +50,10 @@ void chemistry_init(const struct swift_params* parameter_file,
 
 void chemistry_print(const struct chemistry_data* data);
 
+/* Dump/restore. */
+void chemistry_struct_dump(const struct chemistry_data* chemistry,
+                           FILE* stream);
+void chemistry_struct_restore(const struct chemistry_data* chemistry,
+                              FILE* stream);
+
 #endif /* SWIFT_CHEMISTRY_H */
diff --git a/src/chemistry/EAGLE/chemistry.h b/src/chemistry/EAGLE/chemistry.h
index 0ee4d2a2bfc54b1fe4b9b64f321cc23862841952..ae333252426f5fb79cc1fd1cee818754483214f8 100644
--- a/src/chemistry/EAGLE/chemistry.h
+++ b/src/chemistry/EAGLE/chemistry.h
@@ -72,9 +72,11 @@ __attribute__((always_inline)) INLINE static void chemistry_init_part(
  *
  * @param p The particle to act upon.
  * @param cd #chemistry_data containing chemistry informations.
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void chemistry_end_density(
-    struct part* restrict p, const struct chemistry_data* cd) {}
+    struct part* restrict p, const struct chemistry_data* cd,
+    const struct cosmology* cosmo) {}
 
 /**
  * @brief Sets the chemistry properties of the (x-)particles to a valid start
diff --git a/src/chemistry/EAGLE/chemistry_iact.h b/src/chemistry/EAGLE/chemistry_iact.h
index a00938e3557e68b0007e1464be2f05baefaf554a..bdbb8ac9bf7d260e29468b8bee0a84416b668d6a 100644
--- a/src/chemistry/EAGLE/chemistry_iact.h
+++ b/src/chemistry/EAGLE/chemistry_iact.h
@@ -24,36 +24,38 @@
  * @brief Smooth metal interaction functions following the EAGLE model.
  */
 
-#include "chemistry_struct.h"
-
 /**
- * @brief Do chemistry computation after the runner_iact_density (symmetric
+ * @brief do chemistry computation after the runner_iact_density (symmetric
  * version)
  *
- * @param r2 Distance squared between particles
- * @param dx Distance between particles
- * @param hi Smoothing length of i
- * @param hj Smoothing length of j
- * @param pi #part i
- * @param pj #part j
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_chemistry(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
-}
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {}
 
 /**
- * @brief Do chemistry computation after the runner_iact_density (non-symmetric
+ * @brief do chemistry computation after the runner_iact_density (non symmetric
  * version)
  *
- * @param r2 Distance squared between particles
- * @param dx Distance between particles
- * @param hi Smoothing length of i
- * @param hj Smoothing length of j
- * @param pi #part i
- * @param pj #part j
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry(
-    float r2, float *dx, float hi, float hj, struct part *pi,
-    const struct part *pj) {}
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {}
 
 #endif /* SWIFT_EAGLE_CHEMISTRY_IACT_H */
diff --git a/src/chemistry/EAGLE/chemistry_io.h b/src/chemistry/EAGLE/chemistry_io.h
index 70c62a1bbdcd646b7ec79f41943f8c6a7da2dea8..aab8ec240207a47289e35a711af8b245bf2b40fa 100644
--- a/src/chemistry/EAGLE/chemistry_io.h
+++ b/src/chemistry/EAGLE/chemistry_io.h
@@ -95,6 +95,8 @@ int chemistry_write_particles(const struct part* parts, struct io_props* list) {
   return 12;
 }
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grpsph The HDF5 group in which to write
@@ -108,5 +110,6 @@ void chemistry_write_flavour(hid_t h_grp) {
     io_write_attribute_s(h_grp, buffer, chemistry_get_element_name(elem));
   }
 }
+#endif
 
 #endif /* SWIFT_CHEMISTRY_IO_EAGLE_H */
diff --git a/src/chemistry/gear/chemistry.h b/src/chemistry/gear/chemistry.h
index 5dc7a48939cdb298233abbe358473f59fc7e72f4..e9d3d00febe2438c52728f94d0136fb72ff8dc3b 100644
--- a/src/chemistry/gear/chemistry.h
+++ b/src/chemistry/gear/chemistry.h
@@ -103,9 +103,11 @@ __attribute__((always_inline)) INLINE static void chemistry_init_part(
  *
  * @param p The particle to act upon.
  * @param cd #chemistry_data containing chemistry informations.
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void chemistry_end_density(
-    struct part* restrict p, const struct chemistry_data* cd) {
+    struct part* restrict p, const struct chemistry_data* cd,
+    const struct cosmology* cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
diff --git a/src/chemistry/gear/chemistry_iact.h b/src/chemistry/gear/chemistry_iact.h
index 269d33e35fc7a2ba4f93c018c0c942fe99fb944c..f1d724b680574cf1d78848ef242a0e0e5b0cc8e3 100644
--- a/src/chemistry/gear/chemistry_iact.h
+++ b/src/chemistry/gear/chemistry_iact.h
@@ -29,21 +29,22 @@
  * al. 2009
  */
 
-#include "chemistry_struct.h"
-
 /**
  * @brief do chemistry computation after the runner_iact_density (symmetric
  * version)
  *
- * @param r2 Distance squared between particles
- * @param dx Distance between particles
- * @param hi Smoothing length of i
- * @param hj Smoothing length of j
- * @param pi #part i
- * @param pj #part j
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_chemistry(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   struct chemistry_part_data *chi = &pi->chemistry_data;
   struct chemistry_part_data *chj = &pj->chemistry_data;
@@ -79,16 +80,18 @@ __attribute__((always_inline)) INLINE static void runner_iact_chemistry(
  * @brief do chemistry computation after the runner_iact_density (non symmetric
  * version)
  *
- * @param r2 Distance squared between particles
- * @param dx Distance between particles
- * @param hi Smoothing length of i
- * @param hj Smoothing length of j
- * @param pi #part i
- * @param pj #part j
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry(
-    float r2, float *dx, float hi, float hj, struct part *pi,
-    const struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   struct chemistry_part_data *chi = &pi->chemistry_data;
   const struct chemistry_part_data *chj = &pj->chemistry_data;
diff --git a/src/chemistry/gear/chemistry_io.h b/src/chemistry/gear/chemistry_io.h
index 07933245e258306cd5c342c1280ecac36f677b5a..9b0852fa2d23c8dd3e4d36406b55f4353d23b807 100644
--- a/src/chemistry/gear/chemistry_io.h
+++ b/src/chemistry/gear/chemistry_io.h
@@ -62,6 +62,8 @@ int chemistry_write_particles(const struct part* parts, struct io_props* list) {
   return 2;
 }
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grp The HDF5 group in which to write
@@ -76,5 +78,6 @@ void chemistry_write_flavour(hid_t h_grp) {
     io_write_attribute_s(h_grp, buffer, chemistry_get_element_name(i));
   }
 }
+#endif
 
 #endif /* SWIFT_CHEMISTRY_IO_GEAR_H */
diff --git a/src/chemistry/none/chemistry.h b/src/chemistry/none/chemistry.h
index f6f826d580502f3c65bf56480ef0c04ddff1ee37..7fb83339bed6fc2db007e58a5b8372f003186db5 100644
--- a/src/chemistry/none/chemistry.h
+++ b/src/chemistry/none/chemistry.h
@@ -30,6 +30,7 @@
 
 /* Local includes. */
 #include "chemistry_struct.h"
+#include "cosmology.h"
 #include "error.h"
 #include "hydro.h"
 #include "parser.h"
@@ -77,9 +78,11 @@ static INLINE void chemistry_print_backend(const struct chemistry_data* data) {
  *
  * @param p The particle to act upon
  * @param cd The global chemistry information.
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void chemistry_end_density(
-    struct part* restrict p, const struct chemistry_data* cd) {}
+    struct part* restrict p, const struct chemistry_data* cd,
+    const struct cosmology* cosmo) {}
 
 /**
  * @brief Sets the chemistry properties of the (x-)particles to a valid start
diff --git a/src/chemistry/none/chemistry_iact.h b/src/chemistry/none/chemistry_iact.h
index d963e4310e529f1a0f3202bc1f3ee68f605e811e..52499c5e5cc3d5749904251cc967193d875579b9 100644
--- a/src/chemistry/none/chemistry_iact.h
+++ b/src/chemistry/none/chemistry_iact.h
@@ -25,38 +25,38 @@
  * @brief Density computation
  */
 
-#include "cache.h"
-#include "chemistry_struct.h"
-#include "minmax.h"
-
 /**
  * @brief do chemistry computation after the runner_iact_density (symmetric
  * version)
  *
- * @param r2 Distance squared between particles
- * @param dx Distance between particles
- * @param hi Smoothing length of i
- * @param hj Smoothing length of j
- * @param pi #part i
- * @param pj #part j
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_chemistry(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
-}
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {}
 
 /**
  * @brief do chemistry computation after the runner_iact_density (non symmetric
  * version)
  *
- * @param r2 Distance squared between particles
- * @param dx Distance between particles
- * @param hi Smoothing length of i
- * @param hj Smoothing length of j
- * @param pi #part i
- * @param pj #part j
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry(
-    float r2, float *dx, float hi, float hj, struct part *pi,
-    const struct part *pj) {}
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {}
 
 #endif /* SWIFT_NONE_CHEMISTRY_IACT_H */
diff --git a/src/chemistry/none/chemistry_io.h b/src/chemistry/none/chemistry_io.h
index 3f1d3329e9745c21dbc61c7ae9024f69722084e5..142d2f75ce1487393e8689edbb9a6fdb1b1e85cd 100644
--- a/src/chemistry/none/chemistry_io.h
+++ b/src/chemistry/none/chemistry_io.h
@@ -53,13 +53,16 @@ int chemistry_write_particles(const struct part* parts, struct io_props* list) {
   return 0;
 }
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
- * @param h_grpsph The HDF5 group in which to write
+ * @param h_grp The HDF5 group in which to write
  */
-void chemistry_write_flavour(hid_t h_grpsph) {
+void chemistry_write_flavour(hid_t h_grp) {
 
-  io_write_attribute_s(h_grpsph, "Chemistry Model", "None");
+  io_write_attribute_s(h_grp, "Chemistry Model", "None");
 }
+#endif
 
 #endif /* SWIFT_CHEMISTRY_IO_NONE_H */
diff --git a/src/common_io.c b/src/common_io.c
index 22e5fd9289cdca52435c001be7a26105b9e5ca80..67326817397118568e060f5dff49421bb32fba4d 100644
--- a/src/common_io.c
+++ b/src/common_io.c
@@ -375,9 +375,8 @@ void io_write_unit_system(hid_t h_file, const struct unit_system* us,
  * @param h_file The (opened) HDF5 file in which to write
  */
 void io_write_code_description(hid_t h_file) {
-  hid_t h_grpcode = 0;
 
-  h_grpcode = H5Gcreate1(h_file, "/Code", 0);
+  const hid_t h_grpcode = H5Gcreate1(h_file, "/Code", 0);
   if (h_grpcode < 0) error("Error while creating code group");
 
   io_write_attribute_s(h_grpcode, "Code", "SWIFT");
@@ -395,6 +394,9 @@ void io_write_code_description(hid_t h_file) {
 #ifdef HAVE_FFTW
   io_write_attribute_s(h_grpcode, "FFTW library version", fftw3_version());
 #endif
+#ifdef HAVE_LIBGSL
+  io_write_attribute_s(h_grpcode, "GSL library version", libgsl_version());
+#endif
 #ifdef WITH_MPI
   io_write_attribute_s(h_grpcode, "MPI library", mpi_version());
 #ifdef HAVE_METIS
@@ -406,6 +408,25 @@ void io_write_code_description(hid_t h_file) {
   H5Gclose(h_grpcode);
 }
 
+/**
+ * @brief Write the #engine policy to the file.
+ * @param h_file File to write to.
+ * @param e The #engine to read the policy from.
+ */
+void io_write_engine_policy(hid_t h_file, const struct engine* e) {
+
+  const hid_t h_grp = H5Gcreate1(h_file, "/Policy", 0);
+  if (h_grp < 0) error("Error while creating policy group");
+
+  for (int i = 1; i <= engine_maxpolicy; ++i)
+    if (e->policy & (1 << i))
+      io_write_attribute_i(h_grp, engine_policy_names[i + 1], 1);
+    else
+      io_write_attribute_i(h_grp, engine_policy_names[i + 1], 0);
+
+  H5Gclose(h_grp);
+}
+
 #endif /* HAVE_HDF5 */
 
 /**
diff --git a/src/common_io.h b/src/common_io.h
index c317238160e45a9d141619d313e47c715adf8537..49358d8a374553d803de144f1135df6eee80cf15 100644
--- a/src/common_io.h
+++ b/src/common_io.h
@@ -73,6 +73,7 @@ void io_write_attribute_l(hid_t grp, const char* name, long data);
 void io_write_attribute_s(hid_t grp, const char* name, const char* str);
 
 void io_write_code_description(hid_t h_file);
+void io_write_engine_policy(hid_t h_file, const struct engine* e);
 
 void io_read_unit_system(hid_t h_file, struct unit_system* us, int mpi_rank);
 void io_write_unit_system(hid_t h_grp, const struct unit_system* us,
diff --git a/src/cooling.c b/src/cooling.c
index 89a04b30f8ce3f106d90a6db1364a3caadba6deb..57d1928a5d59ac2ff46c6cd20a45d69dec25ec60 100644
--- a/src/cooling.c
+++ b/src/cooling.c
@@ -55,7 +55,7 @@ void cooling_print(const struct cooling_function_data* cooling) {
 }
 
 /**
- * @brief Write a hydro_props struct to the given FILE as a stream of bytes.
+ * @brief Write a cooling struct to the given FILE as a stream of bytes.
  *
  * @param cooling the struct
  * @param stream the file stream
diff --git a/src/cooling/EAGLE/cooling.h b/src/cooling/EAGLE/cooling.h
index aca68ec39b677333a0e8a2b65604f2c12c96678f..62d1cc9b72681fe96c901185a10efe5523b206e3 100644
--- a/src/cooling/EAGLE/cooling.h
+++ b/src/cooling/EAGLE/cooling.h
@@ -37,6 +37,8 @@
 #include "physical_constants.h"
 #include "units.h"
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grpsph The HDF5 group in which to write
@@ -46,12 +48,14 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 
   io_write_attribute_s(h_grpsph, "Cooling Model", "EAGLE");
 }
+#endif
 
 /**
  * @brief Apply the cooling function to a particle.
  *
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
+ * @param cosmo The current cosmological model.
  * @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.
@@ -60,6 +64,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 __attribute__((always_inline)) INLINE static void cooling_cool_part(
     const struct phys_const* restrict phys_const,
     const struct unit_system* restrict us,
+    const struct cosmology* restrict cosmo,
     const struct cooling_function_data* restrict cooling,
     struct part* restrict p, struct xpart* restrict xp, float dt) {}
 
@@ -69,11 +74,13 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
  * @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 cosmo The current cosmological model.
  * @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 cosmology* restrict cosmo,
     const struct unit_system* restrict us, const struct part* restrict p) {
 
   return FLT_MAX;
diff --git a/src/cooling/const_du/cooling.h b/src/cooling/const_du/cooling.h
index 6881e7d0093583b8ba60b3d9723a2214ef677f8a..25aa974e47b277d0dfcc21077e5041a49e8168c8 100644
--- a/src/cooling/const_du/cooling.h
+++ b/src/cooling/const_du/cooling.h
@@ -44,6 +44,8 @@
 #include "physical_constants.h"
 #include "units.h"
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grpsph The HDF5 group in which to write
@@ -53,6 +55,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 
   io_write_attribute_s(h_grpsph, "Cooling Model", "Constant du/dt");
 }
+#endif
 
 /**
  * @brief Apply the cooling function to a particle.
@@ -62,6 +65,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
  *
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
+ * @param cosmo The current cosmological model.
  * @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.
@@ -70,6 +74,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 __attribute__((always_inline)) INLINE static void cooling_cool_part(
     const struct phys_const* restrict phys_const,
     const struct unit_system* restrict us,
+    const struct cosmology* restrict cosmo,
     const struct cooling_function_data* restrict cooling,
     struct part* restrict p, struct xpart* restrict xp, float dt) {
 
@@ -77,7 +82,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
   const float u_floor = cooling->min_energy;
 
   /* Get current internal energy */
-  const float u_old = hydro_get_internal_energy(p);
+  const float u_old = hydro_get_physical_internal_energy(p, cosmo);
 
   /* Current du_dt */
   const float hydro_du_dt = hydro_get_internal_energy_dt(p);
@@ -108,16 +113,18 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
  *
  * @param cooling The #cooling_function_data used in the run.
  * @param phys_const The physical constants in internal units.
+ * @param cosmo The current cosmological model.
  * @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 cosmology* restrict cosmo,
     const struct unit_system* restrict us, const struct part* restrict p) {
 
   const float cooling_rate = cooling->cooling_rate;
-  const float internal_energy = hydro_get_internal_energy(p);
+  const float internal_energy = hydro_get_physical_internal_energy(p, cosmo);
   return cooling->cooling_tstep_mult * internal_energy / fabsf(cooling_rate);
 }
 
diff --git a/src/cooling/const_lambda/cooling.h b/src/cooling/const_lambda/cooling.h
index f4fe4ac4df16af53c88a901edc97e5d70f4ae806..a402b749300e64ef79253764c402d41f5a214d82 100644
--- a/src/cooling/const_lambda/cooling.h
+++ b/src/cooling/const_lambda/cooling.h
@@ -37,6 +37,8 @@
 #include "physical_constants.h"
 #include "units.h"
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grpsph The HDF5 group in which to write
@@ -46,21 +48,24 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 
   io_write_attribute_s(h_grpsph, "Cooling Model", "Constant Lambda");
 }
+#endif
 
 /**
  * @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 cosmo The current cosmological model.
  * @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 unit_system* us,
+    const struct cosmology* restrict cosmo,
     const struct cooling_function_data* cooling, const struct part* p) {
 
   /* Get particle density */
-  const float rho = hydro_get_density(p);
+  const float rho = hydro_get_physical_density(p, cosmo);
 
   /* Get cooling function properties */
   const float X_H = cooling->hydrogen_mass_abundance;
@@ -77,6 +82,7 @@ __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 cosmo The current cosmological model.
  * @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.
@@ -84,6 +90,7 @@ __attribute__((always_inline)) INLINE static float cooling_rate(
 __attribute__((always_inline)) INLINE static void cooling_cool_part(
     const struct phys_const* restrict phys_const,
     const struct unit_system* restrict us,
+    const struct cosmology* restrict cosmo,
     const struct cooling_function_data* restrict cooling,
     struct part* restrict p, struct xpart* restrict xp, float dt) {
 
@@ -91,13 +98,13 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
   const float u_floor = cooling->min_energy;
 
   /* Current energy */
-  const float u_old = hydro_get_internal_energy(p);
+  const float u_old = hydro_get_physical_internal_energy(p, cosmo);
 
   /* Current du_dt */
   const float hydro_du_dt = hydro_get_internal_energy_dt(p);
 
   /* Calculate cooling du_dt */
-  float cooling_du_dt = cooling_rate(phys_const, us, cooling, p);
+  float cooling_du_dt = cooling_rate(phys_const, us, cosmo, cooling, p);
 
   /* Integrate cooling equation to enforce energy floor */
   /* Factor of 1.5 included since timestep could potentially double */
@@ -117,17 +124,19 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
  *
  * @param cooling The #cooling_function_data used in the run.
  * @param phys_const The physical constants in internal units.
+ * @param cosmo The current cosmological model.
  * @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 cosmology* restrict cosmo,
     const struct unit_system* restrict us, const struct part* restrict p) {
 
   /* Get current internal energy */
-  const float u = hydro_get_internal_energy(p);
-  const float du_dt = cooling_rate(phys_const, us, cooling, p);
+  const float u = hydro_get_physical_internal_energy(p, cosmo);
+  const float du_dt = cooling_rate(phys_const, us, cosmo, cooling, p);
 
   /* If we are close to (or below) the energy floor, we ignore the condition */
   if (u < 1.01f * cooling->min_energy)
diff --git a/src/cooling/grackle/cooling.h b/src/cooling/grackle/cooling.h
index 29e00435e16751f01bdb58fe26af151b422bd5a1..d1da52300121ca56feea4114d74322120bd501ce 100644
--- a/src/cooling/grackle/cooling.h
+++ b/src/cooling/grackle/cooling.h
@@ -42,6 +42,8 @@
 #define GRACKLE_NPART 1
 #define GRACKLE_RANK 3
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grpsph The HDF5 group in which to write
@@ -51,6 +53,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 
   io_write_attribute_s(h_grpsph, "Cooling Model", "Grackle");
 }
+#endif
 
 /**
  * @brief Sets the cooling properties of the (x-)particles to a valid start
@@ -120,6 +123,7 @@ __attribute__((always_inline)) INLINE static void cooling_print_backend(
 __attribute__((always_inline)) INLINE static double cooling_rate(
     const struct phys_const* restrict phys_const,
     const struct unit_system* restrict us,
+    const struct cosmology* restrict cosmo,
     const struct cooling_function_data* restrict cooling,
     struct part* restrict p, float dt) {
 
@@ -147,8 +151,8 @@ __attribute__((always_inline)) INLINE static double cooling_rate(
   data.grid_end = grid_end;
 
   /* general particle data */
-  gr_float density = hydro_get_density(p);
-  const double energy_before = hydro_get_internal_energy(p);
+  gr_float density = hydro_get_physical_density(p, cosmo);
+  const double energy_before = hydro_get_physical_internal_energy(p, cosmo);
   gr_float energy = energy_before;
   gr_float vx = 0;
   gr_float vy = 0;
@@ -221,6 +225,7 @@ __attribute__((always_inline)) INLINE static double cooling_rate(
  *
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
+ * @param cosmo The current cosmological model.
  * @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.
@@ -228,6 +233,7 @@ __attribute__((always_inline)) INLINE static double cooling_rate(
 __attribute__((always_inline)) INLINE static void cooling_cool_part(
     const struct phys_const* restrict phys_const,
     const struct unit_system* restrict us,
+    const struct cosmology* restrict cosmo,
     const struct cooling_function_data* restrict cooling,
     struct part* restrict p, struct xpart* restrict xp, float dt) {
 
@@ -237,7 +243,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
   const float hydro_du_dt = hydro_get_internal_energy_dt(p);
 
   /* compute cooling rate */
-  const float du_dt = cooling_rate(phys_const, us, cooling, p, dt);
+  const float du_dt = cooling_rate(phys_const, us, cosmo, cooling, p, dt);
 
   /* record energy lost */
   xp->cooling_data.radiated_energy += -du_dt * dt * hydro_get_mass(p);
@@ -253,12 +259,14 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
  *
  * @param cooling The #cooling_function_data used in the run.
  * @param phys_const The physical constants in internal units.
+ * @param cosmo The current cosmological model.
  * @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 cosmology* restrict cosmo,
     const struct unit_system* restrict us, const struct part* restrict p) {
 
   return FLT_MAX;
diff --git a/src/cooling/none/cooling.h b/src/cooling/none/cooling.h
index 861159ec1022fcf6f7617fc6ca0c9b470aa6e7fa..a1cc6491115a38d6971a57603fef413c35b52027 100644
--- a/src/cooling/none/cooling.h
+++ b/src/cooling/none/cooling.h
@@ -37,6 +37,8 @@
 #include "physical_constants.h"
 #include "units.h"
 
+#ifdef HAVE_HDF5
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grpsph The HDF5 group in which to write
@@ -46,6 +48,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 
   io_write_attribute_s(h_grpsph, "Cooling Model", "None");
 }
+#endif
 
 /**
  * @brief Apply the cooling function to a particle.
@@ -54,6 +57,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
  *
  * @param phys_const The physical constants in internal units.
  * @param us The internal system of units.
+ * @param cosmo The current cosmological model.
  * @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.
@@ -62,6 +66,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour(
 __attribute__((always_inline)) INLINE static void cooling_cool_part(
     const struct phys_const* restrict phys_const,
     const struct unit_system* restrict us,
+    const struct cosmology* restrict cosmo,
     const struct cooling_function_data* restrict cooling,
     struct part* restrict p, struct xpart* restrict xp, float dt) {}
 
@@ -72,12 +77,14 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
  *
  * @param cooling The #cooling_function_data used in the run.
  * @param phys_const The physical constants in internal units.
+ * @param cosmo The current cosmological model.
  * @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 cosmology* restrict cosmo,
     const struct unit_system* restrict us, const struct part* restrict p) {
 
   return FLT_MAX;
diff --git a/src/cosmology.c b/src/cosmology.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b301388e08ca0f4aa2a7d5d8f351ab88682c8ba
--- /dev/null
+++ b/src/cosmology.c
@@ -0,0 +1,679 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2017 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/>.
+ *
+ ******************************************************************************/
+
+/**
+ *  @file cosmology.c
+ *  @brief Functions relating cosmological parameters
+ */
+
+/* This object's header. */
+#include "cosmology.h"
+
+/* Some standard headers */
+#include <math.h>
+
+/* Local headers */
+#include "adiabatic_index.h"
+#include "common_io.h"
+#include "inline.h"
+#include "restart.h"
+
+#ifdef HAVE_LIBGSL
+#include <gsl/gsl_integration.h>
+#endif
+
+/*! Number of values stored in the cosmological interpolation tables */
+const int cosmology_table_length = 10000;
+
+#ifdef HAVE_LIBGSL
+/*! Size of the GSL workspace */
+const size_t GSL_workspace_size = 100000;
+#endif
+
+/**
+ * @brief Returns the interpolated value from a table.
+ *
+ * Uses linear interpolation.
+ *
+ * @brief table The table of value to interpolate from (should be of length
+ * cosmology_table_length).
+ * @brief x The value to interpolate at.
+ * @brief x_min The mininum of the range of x.
+ * @brief x_max The maximum of the range of x.
+ */
+static INLINE double interp_table(double *table, double x, double x_min,
+                                  double x_max) {
+
+  const double xx = ((x - x_min) / (x_max - x_min)) * cosmology_table_length;
+  const int i = (int)xx;
+  const int ii = (i >= cosmology_table_length) ? cosmology_table_length - 1 : i;
+
+  if (ii <= 1)
+    return table[0] * xx;
+  else
+    return table[ii - 1] + (table[ii] - table[ii - 1]) * (xx - ii);
+}
+
+/**
+ * @brief Computes the dark-energy equation of state at a given scale-factor a.
+ *
+ * We follow the convention of Linder & Jenkins, MNRAS, 346, 573, 2003
+ *
+ * @param a The current scale-factor
+ * @param w_0 The equation of state parameter at z=0
+ * @param w_a The equation of state evolution parameter
+ */
+static INLINE double cosmology_dark_energy_EoS(double a, double w_0,
+                                               double w_a) {
+
+  return w_0 + w_a * (1. - a);
+}
+
+/**
+ * @brief Computes the integral of the dark-energy equation of state
+ * up to a scale-factor a.
+ *
+ * We follow the convention of Linder & Jenkins, MNRAS, 346, 573, 2003
+ * and compute \f$ \tilde{w}(a) = \int_0^a\frac{1 + w(z)}{1+z}dz \f$.
+ *
+ * @param a The current scale-factor.
+ * @param w0 The equation of state parameter at z=0
+ * @param wa The equation of state evolution parameter
+ */
+static INLINE double w_tilde(double a, double w0, double wa) {
+  return (a - 1.) * wa - (1. + w0 + wa) * log(a);
+}
+
+/**
+ * @brief Compute \f$ E(z) \f$.
+ */
+static INLINE double E(double Or, double Om, double Ok, double Ol, double w0,
+                       double wa, double a) {
+  const double a_inv = 1. / a;
+  return sqrt(Or * a_inv * a_inv * a_inv * a_inv + Om * a_inv * a_inv * a_inv +
+              Ok * a_inv * a_inv + Ol * exp(3. * w_tilde(a, w0, wa)));
+}
+
+/**
+ * @brief Returns the time (in internal units) since Big Bang at a given
+ * scale-factor.
+ *
+ * @param c The current #cosmology.
+ * @param a Scale-factor of interest.
+ */
+double cosmology_get_time_since_big_bang(const struct cosmology *c, double a) {
+
+  /* Time between a_begin and a */
+  const double delta_t =
+      interp_table(c->time_interp_table, log(a), c->log_a_begin, c->log_a_end);
+
+  return c->time_interp_table_offset + delta_t;
+}
+
+/**
+ * @brief Update the cosmological parameters to the current simulation time.
+ *
+ * @param c The #cosmology struct.
+ * @param ti_current The current (integer) time.
+ */
+void cosmology_update(struct cosmology *c, integertime_t ti_current) {
+
+  /* Get scale factor and powers of it */
+  const double a = c->a_begin * exp(ti_current * c->time_base);
+  const double a_inv = 1. / a;
+  c->a = a;
+  c->a_inv = a_inv;
+  c->a2_inv = a_inv * a_inv;
+  c->a3_inv = a_inv * a_inv * a_inv;
+  c->a_factor_internal_energy =
+      pow(a, -3. * hydro_gamma_minus_one);          /* a^{3*(1-gamma)} */
+  c->a_factor_pressure = pow(a, -3. * hydro_gamma); /* a^{-3*gamma} */
+  c->a_factor_sound_speed =
+      pow(a, -1.5 * hydro_gamma_minus_one); /* a^{3*(1-gamma)/2} */
+  c->a_factor_grav_accel = a_inv * a_inv;   /* 1 / a^2 */
+  c->a_factor_hydro_accel =
+      pow(a, -3. * hydro_gamma + 2.); /* 1 / a^(3*gamma - 2) */
+  c->a_factor_mu =
+      pow(a, 0.5 * (3. * hydro_gamma - 5.)); /* a^{(3*gamma - 5) / 2} */
+
+  /* Redshift */
+  c->z = a_inv - 1.;
+
+  /* Dark-energy equation of state */
+  c->w = cosmology_dark_energy_EoS(a, c->w_0, c->w_a);
+
+  /* E(z) */
+  const double Omega_r = c->Omega_r;
+  const double Omega_m = c->Omega_m;
+  const double Omega_k = c->Omega_k;
+  const double Omega_l = c->Omega_lambda;
+  const double w0 = c->w_0;
+  const double wa = c->w_a;
+  const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w0, wa, a);
+
+  /* H(z) */
+  c->H = c->H0 * E_z;
+
+  /* Expansion rate */
+  c->a_dot = c->H * c->a;
+
+  /* Time-step conversion factor */
+  c->time_step_factor = c->H;
+
+  /* Time */
+  c->time = cosmology_get_time_since_big_bang(c, a);
+  c->lookback_time = c->universe_age_at_present_day - c->time;
+}
+
+/**
+ * @brief Computes \f$ dt / a^2 \f$ for the current cosmology.
+ *
+ * @param a The scale-factor of interest.
+ * @param param The current #cosmology.
+ */
+double drift_integrand(double a, void *param) {
+
+  const struct cosmology *c = (const struct cosmology *)param;
+  const double Omega_r = c->Omega_r;
+  const double Omega_m = c->Omega_m;
+  const double Omega_k = c->Omega_k;
+  const double Omega_l = c->Omega_lambda;
+  const double w_0 = c->w_0;
+  const double w_a = c->w_a;
+  const double H0 = c->H0;
+
+  const double a_inv = 1. / a;
+  const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a);
+  const double H = H0 * E_z;
+
+  return (1. / H) * a_inv * a_inv * a_inv;
+}
+
+/**
+ * @brief Computes \f$ dt / a \f$ for the current cosmology.
+ *
+ * @param a The scale-factor of interest.
+ * @param param The current #cosmology.
+ */
+double gravity_kick_integrand(double a, void *param) {
+
+  const struct cosmology *c = (const struct cosmology *)param;
+  const double Omega_r = c->Omega_r;
+  const double Omega_m = c->Omega_m;
+  const double Omega_k = c->Omega_k;
+  const double Omega_l = c->Omega_lambda;
+  const double w_0 = c->w_0;
+  const double w_a = c->w_a;
+  const double H0 = c->H0;
+
+  const double a_inv = 1. / a;
+  const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a);
+  const double H = H0 * E_z;
+
+  return (1. / H) * a_inv * a_inv;
+}
+
+/**
+ * @brief Computes \f$ dt / a^{3(\gamma - 1) + 1} \f$ for the current cosmology.
+ *
+ * @param a The scale-factor of interest.
+ * @param param The current #cosmology.
+ */
+double hydro_kick_integrand(double a, void *param) {
+
+  const struct cosmology *c = (const struct cosmology *)param;
+  const double Omega_r = c->Omega_r;
+  const double Omega_m = c->Omega_m;
+  const double Omega_k = c->Omega_k;
+  const double Omega_l = c->Omega_lambda;
+  const double w_0 = c->w_0;
+  const double w_a = c->w_a;
+  const double H0 = c->H0;
+
+  const double a_inv = 1. / a;
+  const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a);
+  const double H = H0 * E_z;
+
+  /* Note: we can't use the pre-defined pow_gamma_xxx() function as
+     as we need double precision accuracy for the GSL routine. */
+  return (1. / H) * pow(a_inv, 3. * hydro_gamma_minus_one) * a_inv;
+}
+
+/**
+ * @brief Computes \f$ dt \f$ for the current cosmology.
+ *
+ * @param a The scale-factor of interest.
+ * @param param The current #cosmology.
+ */
+double time_integrand(double a, void *param) {
+
+  const struct cosmology *c = (const struct cosmology *)param;
+  const double Omega_r = c->Omega_r;
+  const double Omega_m = c->Omega_m;
+  const double Omega_k = c->Omega_k;
+  const double Omega_l = c->Omega_lambda;
+  const double w_0 = c->w_0;
+  const double w_a = c->w_a;
+  const double H0 = c->H0;
+
+  const double a_inv = 1. / a;
+  const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a);
+  const double H = H0 * E_z;
+
+  return (1. / H) * a_inv;
+}
+
+/**
+ * @brief Initialise the interpolation tables for the integrals.
+ */
+void cosmology_init_tables(struct cosmology *c) {
+
+  const ticks tic = getticks();
+
+#ifdef HAVE_LIBGSL
+
+  /* Retrieve some constants */
+  const double a_begin = c->a_begin;
+
+  /* Allocate memory for the interpolation tables */
+  c->drift_fac_interp_table =
+      (double *)malloc(cosmology_table_length * sizeof(double));
+  c->grav_kick_fac_interp_table =
+      (double *)malloc(cosmology_table_length * sizeof(double));
+  c->hydro_kick_fac_interp_table =
+      (double *)malloc(cosmology_table_length * sizeof(double));
+  c->time_interp_table =
+      (double *)malloc(cosmology_table_length * sizeof(double));
+
+  /* Prepare a table of scale factors for the integral bounds */
+  const double delta_a =
+      (c->log_a_end - c->log_a_begin) / cosmology_table_length;
+  double *a_table = (double *)malloc(cosmology_table_length * sizeof(double));
+  for (int i = 0; i < cosmology_table_length; i++)
+    a_table[i] = exp(c->log_a_begin + delta_a * (i + 1));
+
+  /* Initalise the GSL workspace */
+  gsl_integration_workspace *space =
+      gsl_integration_workspace_alloc(GSL_workspace_size);
+
+  double result, abserr;
+
+  /* Integrate the drift factor \int_{a_begin}^{a_table[i]} dt/a^2 */
+  gsl_function F = {&drift_integrand, c};
+  for (int i = 0; i < cosmology_table_length; i++) {
+    gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size,
+                        GSL_INTEG_GAUSS61, space, &result, &abserr);
+
+    /* Store result */
+    c->drift_fac_interp_table[i] = result;
+  }
+
+  /* Integrate the kick factor \int_{a_begin}^{a_table[i]} dt/a */
+  F.function = &gravity_kick_integrand;
+  for (int i = 0; i < cosmology_table_length; i++) {
+    gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size,
+                        GSL_INTEG_GAUSS61, space, &result, &abserr);
+
+    /* Store result */
+    c->grav_kick_fac_interp_table[i] = result;
+  }
+
+  /* Integrate the kick factor \int_{a_begin}^{a_table[i]} dt/a^(3(g-1)+1) */
+  F.function = &hydro_kick_integrand;
+  for (int i = 0; i < cosmology_table_length; i++) {
+    gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size,
+                        GSL_INTEG_GAUSS61, space, &result, &abserr);
+
+    /* Store result */
+    c->hydro_kick_fac_interp_table[i] = result;
+  }
+
+  /* Integrate the time \int_{a_begin}^{a_table[i]} dt */
+  F.function = &time_integrand;
+  for (int i = 0; i < cosmology_table_length; i++) {
+    gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size,
+                        GSL_INTEG_GAUSS61, space, &result, &abserr);
+
+    /* Store result */
+    c->time_interp_table[i] = result;
+  }
+
+  /* Integrate the time \int_{0}^{a_begin} dt */
+  gsl_integration_qag(&F, 0., a_begin, 0, 1.0e-10, GSL_workspace_size,
+                      GSL_INTEG_GAUSS61, space, &result, &abserr);
+  c->time_interp_table_offset = result;
+
+  /* Integrate the time \int_{0}^{1} dt */
+  gsl_integration_qag(&F, 0., 1, 0, 1.0e-13, GSL_workspace_size,
+                      GSL_INTEG_GAUSS61, space, &result, &abserr);
+  c->universe_age_at_present_day = result;
+
+  /* Free the workspace and temp array */
+  gsl_integration_workspace_free(space);
+  free(a_table);
+
+#else
+
+  error("Code not compiled with GSL. Can't compute cosmology integrals.");
+
+#endif
+
+  message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+          clocks_getunit());
+}
+
+/**
+ * @brief Initialises the #cosmology from the values read in the parameter file.
+ *
+ * @param params The parsed values.
+ * @param us The current internal system of units.
+ * @param phys_const The physical constants in the current system of units.
+ * @param c The #cosmology to initialise.
+ */
+void cosmology_init(const struct swift_params *params,
+                    const struct unit_system *us,
+                    const struct phys_const *phys_const, struct cosmology *c) {
+
+  /* Read in the cosmological parameters */
+  c->Omega_m = parser_get_param_double(params, "Cosmology:Omega_m");
+  c->Omega_r = parser_get_opt_param_double(params, "Cosmology:Omega_r", 0.);
+  c->Omega_lambda = parser_get_param_double(params, "Cosmology:Omega_lambda");
+  c->Omega_b = parser_get_param_double(params, "Cosmology:Omega_b");
+  c->w_0 = parser_get_opt_param_double(params, "Cosmology:w_0", -1.);
+  c->w_a = parser_get_opt_param_double(params, "Cosmology:w_a", 0.);
+  c->h = parser_get_param_double(params, "Cosmology:h");
+
+  /* Read the start and end of the simulation */
+  c->a_begin = parser_get_param_double(params, "Cosmology:a_begin");
+  c->a_end = parser_get_param_double(params, "Cosmology:a_end");
+  c->log_a_begin = log(c->a_begin);
+  c->log_a_end = log(c->a_end);
+  c->time_base = (c->log_a_end - c->log_a_begin) / max_nr_timesteps;
+  c->time_base_inv = 1. / c->time_base;
+
+  /* Construct derived quantities */
+
+  /* Curvature density (for closure) */
+  c->Omega_k = 1. - (c->Omega_m + c->Omega_r + c->Omega_lambda);
+
+  /* Dark-energy equation of state */
+  c->w = cosmology_dark_energy_EoS(c->a_begin, c->w_0, c->w_a);
+
+  /* Hubble constant in internal units */
+  const double km = 1.e5 / units_cgs_conversion_factor(us, UNIT_CONV_LENGTH);
+  const double H0_cgs =
+      100. * c->h * (km / (1.e6 * phys_const->const_parsec)); /* s^-1 */
+  c->H0 = H0_cgs * units_cgs_conversion_factor(us, UNIT_CONV_TIME);
+  c->Hubble_time = 1. / c->H0;
+
+  /* Initialise the interpolation tables */
+  c->drift_fac_interp_table = NULL;
+  c->grav_kick_fac_interp_table = NULL;
+  c->hydro_kick_fac_interp_table = NULL;
+  c->time_interp_table = NULL;
+  c->time_interp_table_offset = 0.;
+  cosmology_init_tables(c);
+
+  /* Set remaining variables to alid values */
+  cosmology_update(c, 0);
+
+  /* Update the times */
+  c->time_begin = cosmology_get_time_since_big_bang(c, c->a_begin);
+  c->time_end = cosmology_get_time_since_big_bang(c, c->a_end);
+}
+
+/**
+ * @brief Initialise the #cosmology for non-cosmological time-integration
+ *
+ * Essentially sets all constants to 1 or 0.
+ *
+ * @param c The #cosmology to initialise.
+ */
+void cosmology_init_no_cosmo(struct cosmology *c) {
+
+  c->Omega_m = 0.;
+  c->Omega_r = 0.;
+  c->Omega_k = 0.;
+  c->Omega_lambda = 0.;
+  c->Omega_b = 0.;
+  c->w_0 = 0.;
+  c->w_a = 0.;
+  c->h = 0.;
+  c->w = 0.;
+
+  c->a_begin = 1.;
+  c->a_end = 1.;
+  c->log_a_begin = 0.;
+  c->log_a_end = 0.;
+
+  c->H = 0.;
+  c->a = 1.;
+  c->a_inv = 1.;
+  c->a2_inv = 1.;
+  c->a3_inv = 1.;
+  c->a_factor_internal_energy = 1.;
+  c->a_factor_pressure = 1.;
+  c->a_factor_sound_speed = 1.;
+  c->a_factor_mu = 1.;
+  c->a_factor_hydro_accel = 1.;
+  c->a_factor_grav_accel = 1.;
+
+  c->time_step_factor = 1.;
+
+  c->a_dot = 0.;
+  c->time = 0.;
+  c->universe_age_at_present_day = 0.;
+
+  /* Initialise the interpolation tables */
+  c->drift_fac_interp_table = NULL;
+  c->grav_kick_fac_interp_table = NULL;
+  c->hydro_kick_fac_interp_table = NULL;
+  c->time_interp_table = NULL;
+  c->time_interp_table_offset = 0.;
+
+  c->time_begin = 0.;
+  c->time_end = 0.;
+}
+
+/**
+ * @brief Computes the cosmology factor that enters the drift operator.
+ *
+ * Computes \f$ \int_{a_start}^{a_end} dt/a^2 \f$ using the interpolation table.
+ *
+ * @param c The current #cosmology.
+ * @param ti_start the (integer) time of the start of the drift.
+ * @param ti_end the (integer) time of the end of the drift.
+ */
+double cosmology_get_drift_factor(const struct cosmology *c,
+                                  integertime_t ti_start,
+                                  integertime_t ti_end) {
+
+  const double a_start = c->log_a_begin + ti_start * c->time_base;
+  const double a_end = c->log_a_begin + ti_end * c->time_base;
+
+  const double int_start = interp_table(c->drift_fac_interp_table, a_start,
+                                        c->log_a_begin, c->log_a_end);
+  const double int_end = interp_table(c->drift_fac_interp_table, a_end,
+                                      c->log_a_begin, c->log_a_end);
+
+  return int_end - int_start;
+}
+
+/**
+ * @brief Computes the cosmology factor that enters the gravity kick operator.
+ *
+ * Computes \f$ \int_{a_start}^{a_end} dt/a \f$ using the interpolation table.
+ *
+ * @param c The current #cosmology.
+ * @param ti_start the (integer) time of the start of the drift.
+ * @param ti_end the (integer) time of the end of the drift.
+ */
+double cosmology_get_grav_kick_factor(const struct cosmology *c,
+                                      integertime_t ti_start,
+                                      integertime_t ti_end) {
+
+  const double a_start = c->log_a_begin + ti_start * c->time_base;
+  const double a_end = c->log_a_begin + ti_end * c->time_base;
+
+  const double int_start = interp_table(c->grav_kick_fac_interp_table, a_start,
+                                        c->log_a_begin, c->log_a_end);
+  const double int_end = interp_table(c->grav_kick_fac_interp_table, a_end,
+                                      c->log_a_begin, c->log_a_end);
+
+  return int_end - int_start;
+}
+
+/**
+ * @brief Computes the cosmology factor that enters the hydro kick operator.
+ *
+ * Computes \f$ \int_{a_start}^{a_end} dt/a \f$ using the interpolation table.
+ *
+ * @param c The current #cosmology.
+ * @param ti_start the (integer) time of the start of the drift.
+ * @param ti_end the (integer) time of the end of the drift.
+ */
+double cosmology_get_hydro_kick_factor(const struct cosmology *c,
+                                       integertime_t ti_start,
+                                       integertime_t ti_end) {
+
+  const double a_start = c->log_a_begin + ti_start * c->time_base;
+  const double a_end = c->log_a_begin + ti_end * c->time_base;
+
+  const double int_start = interp_table(c->drift_fac_interp_table, a_start,
+                                        c->log_a_begin, c->log_a_end);
+  const double int_end = interp_table(c->drift_fac_interp_table, a_end,
+                                      c->log_a_begin, c->log_a_end);
+
+  return int_end - int_start;
+}
+
+/**
+ * @brief Computes the cosmology factor that enters the thermal variable kick
+ * operator.
+ *
+ * Computes \f$ \int_{a_start}^{a_end} dt/a^2 \f$ using the interpolation table.
+ *
+ * @param c The current #cosmology.
+ * @param ti_start the (integer) time of the start of the drift.
+ * @param ti_end the (integer) time of the end of the drift.
+ */
+double cosmology_get_therm_kick_factor(const struct cosmology *c,
+                                       integertime_t ti_start,
+                                       integertime_t ti_end) {
+
+  const double a_start = c->log_a_begin + ti_start * c->time_base;
+  const double a_end = c->log_a_begin + ti_end * c->time_base;
+
+  const double int_start = interp_table(c->hydro_kick_fac_interp_table, a_start,
+                                        c->log_a_begin, c->log_a_end);
+  const double int_end = interp_table(c->hydro_kick_fac_interp_table, a_end,
+                                      c->log_a_begin, c->log_a_end);
+
+  return int_end - int_start;
+}
+
+/**
+ * @brief Compute the cosmic time (in internal units) between two scale-factors.
+ *
+ * @brief c The current #cosmology.
+ * @brief a1 The first scale-factor.
+ * @brief a2 The second scale-factor.
+ */
+double cosmology_get_delta_time(const struct cosmology *c, double a1,
+                                double a2) {
+
+  /* Time between a_begin and a1 */
+  const double t1 =
+      interp_table(c->time_interp_table, log(a1), c->log_a_begin, c->log_a_end);
+
+  /* Time between a_begin and a1 */
+  const double t2 =
+      interp_table(c->time_interp_table, log(a2), c->log_a_begin, c->log_a_end);
+
+  return t2 - t1;
+}
+
+/**
+ * @brief Prints the #cosmology model to stdout.
+ */
+void cosmology_print(const struct cosmology *c) {
+
+  message(
+      "Density parameters: [O_m, O_l, O_b, O_k, O_r] = [%f, %f, %f, %f, %f]",
+      c->Omega_m, c->Omega_lambda, c->Omega_b, c->Omega_k, c->Omega_r);
+  message("Dark energy equation of state: w_0=%f w_a=%f", c->w_0, c->w_a);
+  message("Hubble constant: h = %f, H_0 = %e U_t^(-1)", c->h, c->H0);
+  message("Hubble time: 1/H0 = %e U_t", c->Hubble_time);
+  message("Universe age at present day: %e U_t",
+          c->universe_age_at_present_day);
+}
+
+void cosmology_clean(struct cosmology *c) {
+
+  free(c->drift_fac_interp_table);
+  free(c->grav_kick_fac_interp_table);
+  free(c->hydro_kick_fac_interp_table);
+  free(c->time_interp_table);
+}
+
+#ifdef HAVE_HDF5
+void cosmology_write_model(hid_t h_grp, const struct cosmology *c) {
+
+  io_write_attribute_d(h_grp, "a_beg", c->a_begin);
+  io_write_attribute_d(h_grp, "a_end", c->a_end);
+  io_write_attribute_d(h_grp, "time_beg [internal units]", c->time_begin);
+  io_write_attribute_d(h_grp, "time_end [internal units]", c->time_end);
+  io_write_attribute_d(h_grp, "h", c->h);
+  io_write_attribute_d(h_grp, "H0 [internal units]", c->H0);
+  io_write_attribute_d(h_grp, "Hubble time [internal units]", c->Hubble_time);
+  io_write_attribute_d(h_grp, "Omega_m", c->Omega_m);
+  io_write_attribute_d(h_grp, "Omega_r", c->Omega_r);
+  io_write_attribute_d(h_grp, "Omega_b", c->Omega_b);
+  io_write_attribute_d(h_grp, "Omega_k", c->Omega_k);
+  io_write_attribute_d(h_grp, "Omega_lambda", c->Omega_lambda);
+  io_write_attribute_d(h_grp, "w_0", c->w_0);
+  io_write_attribute_d(h_grp, "w_a", c->w_a);
+}
+#endif
+
+/**
+ * @brief Write a cosmology struct to the given FILE as a stream of bytes.
+ *
+ * @param cosmology the struct
+ * @param stream the file stream
+ */
+void cosmology_struct_dump(const struct cosmology *cosmology, FILE *stream) {
+  restart_write_blocks((void *)cosmology, sizeof(struct cosmology), 1, stream,
+                       "cosmology", "cosmology function");
+}
+
+/**
+ * @brief Restore a cosmology struct from the given FILE as a stream of
+ * bytes.
+ *
+ * @param cosmology the struct
+ * @param stream the file stream
+ */
+void cosmology_struct_restore(struct cosmology *cosmology, FILE *stream) {
+  restart_read_blocks((void *)cosmology, sizeof(struct cosmology), 1, stream,
+                      NULL, "cosmology function");
+
+  /* Re-initialise the tables */
+  cosmology_init_tables(cosmology);
+}
diff --git a/src/cosmology.h b/src/cosmology.h
new file mode 100644
index 0000000000000000000000000000000000000000..b1b33930bad7a49c0f2abe3a2201d71c9be57305
--- /dev/null
+++ b/src/cosmology.h
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2017 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_COSMOLOGY_H
+#define SWIFT_COSMOLOGY_H
+
+/* Config parameters. */
+#include "../config.h"
+
+#include "parser.h"
+#include "physical_constants.h"
+#include "timeline.h"
+#include "units.h"
+
+/**
+ * @brief Cosmological parameters
+ */
+struct cosmology {
+
+  /*! Current expansion factor of the Universe */
+  double a;
+
+  /*! Inverse of the current expansion factor of the Universe */
+  double a_inv;
+
+  /*! Inverse square of the current expansion factor of the Universe */
+  double a2_inv;
+
+  /*! Inverse cube of the current expansion factor of the Universe */
+  double a3_inv;
+
+  /*! Power of the scale-factor used for internal energy conversion to physical
+   */
+  double a_factor_internal_energy;
+
+  /*! Power of the scale-factor used for pressure conversion to physical */
+  double a_factor_pressure;
+
+  /*! Power of the scale-factor used for sound-speed conversion to physical */
+  double a_factor_sound_speed;
+
+  /*! Power of the scale-factor used for relative velocities in viscosity term
+   */
+  double a_factor_mu;
+
+  /*! Power of the scale-factor used for gravity accelerations */
+  double a_factor_grav_accel;
+
+  /*! Power of the scale-factor used for hydro accelerations */
+  double a_factor_hydro_accel;
+
+  /*! Current redshift */
+  double z;
+
+  /*! Hubble constant at the current redshift (in internal units) */
+  double H;
+
+  /*! Conversion factor from internal time-step size to cosmological step */
+  double time_step_factor;
+
+  /*! Expansion rate at the current redshift (in internal units) */
+  double a_dot;
+
+  /*! Time (in internal units) since the Big Bang */
+  double time;
+
+  /*! Lookback time (in internal units) */
+  double lookback_time;
+
+  /*! Dark-energy equation of state at the current time */
+  double w;
+
+  /*------------------------------------------------------------------ */
+
+  /*! Starting expansion factor */
+  double a_begin;
+
+  /*! Final expansion factor */
+  double a_end;
+
+  /*! Time (in internal units) since the Big Bang at the start */
+  double time_begin;
+
+  /*! Time (in internal units) since the Big Bang at the end */
+  double time_end;
+
+  /*! Conversion factor from integer time-line to \f$ d\log{a} \f$ */
+  double time_base;
+
+  /*! Inverse of conversion factor from integer time-line to \f$ d\log{a} \f$ */
+  double time_base_inv;
+
+  /*! Reduced Hubble constant (H0 / (100km/s/Mpc)) */
+  double h;
+
+  /*! Hubble constant at z = 0 (in internal units) */
+  double H0;
+
+  /*! Hubble time 1/H0 */
+  double Hubble_time;
+
+  /*! Matter density parameter */
+  double Omega_m;
+
+  /*! Baryon density parameter */
+  double Omega_b;
+
+  /*! Radiation constant density parameter */
+  double Omega_lambda;
+
+  /*! Cosmological constant density parameter */
+  double Omega_r;
+
+  /*! Curvature density parameter */
+  double Omega_k;
+
+  /*! Dark-energy equation of state at z=0 */
+  double w_0;
+
+  /*! Dark-energy evolution parameter */
+  double w_a;
+
+  /*! Log of starting expansion factor */
+  double log_a_begin;
+
+  /*! Log of final expansion factor */
+  double log_a_end;
+
+  /*! Drift factor interpolation table */
+  double *drift_fac_interp_table;
+
+  /*! Kick factor (gravity) interpolation table */
+  double *grav_kick_fac_interp_table;
+
+  /*! Kick factor (hydro) interpolation table */
+  double *hydro_kick_fac_interp_table;
+
+  /*! Time interpolation table */
+  double *time_interp_table;
+
+  /*! Time between Big Bang and first entry in the table */
+  double time_interp_table_offset;
+
+  /*! Time at the present-day (a=1) */
+  double universe_age_at_present_day;
+};
+
+void cosmology_update(struct cosmology *c, integertime_t ti_current);
+
+double cosmology_get_drift_factor(const struct cosmology *cosmo,
+                                  integertime_t ti_start, integertime_t ti_end);
+double cosmology_get_grav_kick_factor(const struct cosmology *cosmo,
+                                      integertime_t ti_start,
+                                      integertime_t ti_end);
+double cosmology_get_hydro_kick_factor(const struct cosmology *cosmo,
+                                       integertime_t ti_start,
+                                       integertime_t ti_end);
+double cosmology_get_therm_kick_factor(const struct cosmology *cosmo,
+                                       integertime_t ti_start,
+                                       integertime_t ti_end);
+
+double cosmology_get_delta_time(const struct cosmology *c, double a1,
+                                double a2);
+
+void cosmology_init(const struct swift_params *params,
+                    const struct unit_system *us,
+                    const struct phys_const *phys_const, struct cosmology *c);
+
+void cosmology_init_no_cosmo(struct cosmology *c);
+
+void cosmology_print(const struct cosmology *c);
+void cosmology_clean(struct cosmology *c);
+
+#ifdef HAVE_HDF5
+void cosmology_write_model(hid_t h_grp, const struct cosmology *c);
+#endif
+
+/* Dump/restore. */
+void cosmology_struct_dump(const struct cosmology *cosmology, FILE *stream);
+void cosmology_struct_restore(struct cosmology *cosmology, FILE *stream);
+
+#endif /* SWIFT_COSMOLOGY_H */
diff --git a/src/drift.h b/src/drift.h
index e86d290cb796153d3c3fc43c21b25d2c7e435657..b7d5e3abe648e327f1560641676685b2d038ce3b 100644
--- a/src/drift.h
+++ b/src/drift.h
@@ -30,16 +30,15 @@
 #include "part.h"
 
 /**
- * @brief Perform the 'drift' operation on a #gpart
+ * @brief Perform the 'drift' operation on a #gpart.
  *
  * @param gp The #gpart to drift.
- * @param dt The drift time-step
- * @param timeBase The minimal allowed time-step size.
- * @param ti_old Integer start of time-step
- * @param ti_current Integer end of time-step
+ * @param dt_drift The drift time-step.
+ * @param ti_old Integer start of time-step (for debugging checks).
+ * @param ti_current Integer end of time-step (for debugging checks).
  */
 __attribute__((always_inline)) INLINE static void drift_gpart(
-    struct gpart *restrict gp, double dt, double timeBase, integertime_t ti_old,
+    struct gpart *restrict gp, double dt_drift, integertime_t ti_old,
     integertime_t ti_current) {
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -54,14 +53,14 @@ __attribute__((always_inline)) INLINE static void drift_gpart(
 #endif
 
   /* Drift... */
-  gp->x[0] += gp->v_full[0] * dt;
-  gp->x[1] += gp->v_full[1] * dt;
-  gp->x[2] += gp->v_full[2] * dt;
+  gp->x[0] += gp->v_full[0] * dt_drift;
+  gp->x[1] += gp->v_full[1] * dt_drift;
+  gp->x[2] += gp->v_full[2] * dt_drift;
 
   /* Compute offset since last cell construction */
-  gp->x_diff[0] -= gp->v_full[0] * dt;
-  gp->x_diff[1] -= gp->v_full[1] * dt;
-  gp->x_diff[2] -= gp->v_full[2] * dt;
+  gp->x_diff[0] -= gp->v_full[0] * dt_drift;
+  gp->x_diff[1] -= gp->v_full[1] * dt_drift;
+  gp->x_diff[2] -= gp->v_full[2] * dt_drift;
 }
 
 /**
@@ -69,14 +68,17 @@ __attribute__((always_inline)) INLINE static void drift_gpart(
  *
  * @param p The #part to drift.
  * @param xp The #xpart of the particle.
- * @param dt The drift time-step
- * @param timeBase The minimal allowed time-step size.
- * @param ti_old Integer start of time-step
- * @param ti_current Integer end of time-step
+ * @param dt_drift The drift time-step
+ * @param dt_kick_grav The kick time-step for gravity accelerations.
+ * @param dt_kick_hydro The kick time-step for hydro accelerations.
+ * @param dt_therm The drift time-step for thermodynamic quantities.
+ * @param ti_old Integer start of time-step (for debugging checks).
+ * @param ti_current Integer end of time-step (for debugging checks).
  */
 __attribute__((always_inline)) INLINE static void drift_part(
-    struct part *restrict p, struct xpart *restrict xp, double dt,
-    double timeBase, integertime_t ti_old, integertime_t ti_current) {
+    struct part *restrict p, struct xpart *restrict xp, double dt_drift,
+    double dt_kick_hydro, double dt_kick_grav, double dt_therm,
+    integertime_t ti_old, integertime_t ti_current) {
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (p->ti_drift != ti_old)
@@ -89,21 +91,25 @@ __attribute__((always_inline)) INLINE static void drift_part(
 #endif
 
   /* Drift... */
-  p->x[0] += xp->v_full[0] * dt;
-  p->x[1] += xp->v_full[1] * dt;
-  p->x[2] += xp->v_full[2] * dt;
+  p->x[0] += xp->v_full[0] * dt_drift;
+  p->x[1] += xp->v_full[1] * dt_drift;
+  p->x[2] += xp->v_full[2] * dt_drift;
 
   /* Predict velocities (for hydro terms) */
-  p->v[0] += p->a_hydro[0] * dt;
-  p->v[1] += p->a_hydro[1] * dt;
-  p->v[2] += p->a_hydro[2] * dt;
+  p->v[0] += p->a_hydro[0] * dt_kick_hydro;
+  p->v[1] += p->a_hydro[1] * dt_kick_hydro;
+  p->v[2] += p->a_hydro[2] * dt_kick_hydro;
+
+  p->v[0] += xp->a_grav[0] * dt_kick_grav;
+  p->v[1] += xp->a_grav[1] * dt_kick_grav;
+  p->v[2] += xp->a_grav[2] * dt_kick_grav;
 
   /* Predict the values of the extra fields */
-  hydro_predict_extra(p, xp, dt);
+  hydro_predict_extra(p, xp, dt_drift, dt_therm);
 
   /* Compute offsets since last cell construction */
   for (int k = 0; k < 3; k++) {
-    const float dx = xp->v_full[k] * dt;
+    const float dx = xp->v_full[k] * dt_drift;
     xp->x_diff[k] -= dx;
     xp->x_diff_sort[k] -= dx;
   }
@@ -113,13 +119,12 @@ __attribute__((always_inline)) INLINE static void drift_part(
  * @brief Perform the 'drift' operation on a #spart
  *
  * @param sp The #spart to drift.
- * @param dt The drift time-step
- * @param timeBase The minimal allowed time-step size.
- * @param ti_old Integer start of time-step
- * @param ti_current Integer end of time-step
+ * @param dt_drift The drift time-step.
+ * @param ti_old Integer start of time-step (for debugging checks).
+ * @param ti_current Integer end of time-step (for debugging checks).
  */
 __attribute__((always_inline)) INLINE static void drift_spart(
-    struct spart *restrict sp, double dt, double timeBase, integertime_t ti_old,
+    struct spart *restrict sp, double dt_drift, integertime_t ti_old,
     integertime_t ti_current) {
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -134,9 +139,9 @@ __attribute__((always_inline)) INLINE static void drift_spart(
 #endif
 
   /* Drift... */
-  sp->x[0] += sp->v[0] * dt;
-  sp->x[1] += sp->v[1] * dt;
-  sp->x[2] += sp->v[2] * dt;
+  sp->x[0] += sp->v[0] * dt_drift;
+  sp->x[1] += sp->v[1] * dt_drift;
+  sp->x[2] += sp->v[2] * dt_drift;
 }
 
 #endif /* SWIFT_DRIFT_H */
diff --git a/src/engine.c b/src/engine.c
index 3d33fda917b27222a46802285d7f07665c4b352c..c52c4b21cd9bb4d3222edb3e804507ee747bae0f 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -51,8 +51,10 @@
 #include "active.h"
 #include "atomic.h"
 #include "cell.h"
+#include "chemistry.h"
 #include "clocks.h"
 #include "cooling.h"
+#include "cosmology.h"
 #include "cycle.h"
 #include "debug.h"
 #include "error.h"
@@ -85,15 +87,15 @@ const char *engine_policy_names[] = {"none",
                                      "steal",
                                      "keep",
                                      "block",
-                                     "cpu_tight",
+                                     "cpu tight",
                                      "mpi",
-                                     "numa_affinity",
+                                     "numa affinity",
                                      "hydro",
-                                     "self_gravity",
-                                     "external_gravity",
-                                     "cosmology_integration",
-                                     "drift_all",
-                                     "reconstruct_mpoles",
+                                     "self gravity",
+                                     "external gravity",
+                                     "cosmological integration",
+                                     "drift everything",
+                                     "reconstruct multi-poles",
                                      "cooling",
                                      "sourceterms",
                                      "stars"};
@@ -4374,14 +4376,17 @@ void engine_step(struct engine *e) {
   if (e->nodeID == 0) {
 
     /* Print some information to the screen */
-    printf("  %6d %14e %14e %12zu %12zu %12zu %21.3f %6d\n", e->step, e->time,
-           e->timeStep, e->updates, e->g_updates, e->s_updates,
+    printf("  %6d %14e %14e %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n",
+           e->step, e->time, e->cosmology->a, e->time_step, e->min_active_bin,
+           e->max_active_bin, e->updates, e->g_updates, e->s_updates,
            e->wallclock_time, e->step_props);
     fflush(stdout);
 
-    fprintf(e->file_timesteps, "  %6d %14e %14e %12zu %12zu %12zu %21.3f %6d\n",
-            e->step, e->time, e->timeStep, e->updates, e->g_updates,
-            e->s_updates, e->wallclock_time, e->step_props);
+    fprintf(e->file_timesteps,
+            "  %6d %14e %14e %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n",
+            e->step, e->time, e->cosmology->a, e->time_step, e->min_active_bin,
+            e->max_active_bin, e->updates, e->g_updates, e->s_updates,
+            e->wallclock_time, e->step_props);
     fflush(e->file_timesteps);
   }
 
@@ -4389,12 +4394,21 @@ void engine_step(struct engine *e) {
   e->ti_old = e->ti_current;
   e->ti_current = e->ti_end_min;
   e->max_active_bin = get_max_active_bin(e->ti_end_min);
+  e->min_active_bin = get_min_active_bin(e->ti_current, e->ti_old);
   e->step += 1;
-  e->time = e->ti_current * e->timeBase + e->timeBegin;
-  e->timeOld = e->ti_old * e->timeBase + e->timeBegin;
-  e->timeStep = (e->ti_current - e->ti_old) * e->timeBase;
   e->step_props = engine_step_prop_none;
 
+  if (e->policy & engine_policy_cosmology) {
+    e->time_old = e->time;
+    cosmology_update(e->cosmology, e->ti_current);
+    e->time = e->cosmology->time;
+    e->time_step = e->time - e->time_old;
+  } else {
+    e->time = e->ti_current * e->time_base + e->time_begin;
+    e->time_old = e->ti_old * e->time_base + e->time_begin;
+    e->time_step = (e->ti_current - e->ti_old) * e->time_base;
+  }
+
   /* Prepare the tasks to be launched, rebuild or repartition if needed. */
   engine_prepare(e);
 
@@ -5171,6 +5185,7 @@ void engine_unpin() {
  * @param reparttype What type of repartition algorithm are we using ?
  * @param internal_units The system of units used internally.
  * @param physical_constants The #phys_const used for this run.
+ * @param cosmo The #cosmology used for this run.
  * @param hydro The #hydro_props used for this run.
  * @param gravity The #gravity_props used for this run.
  * @param potential The properties of the external potential.
@@ -5182,7 +5197,7 @@ void engine_init(
     struct engine *e, struct space *s, const struct swift_params *params,
     long long Ngas, long long Ndm, int policy, int verbose,
     struct repartition *reparttype, const struct unit_system *internal_units,
-    const struct phys_const *physical_constants,
+    const struct phys_const *physical_constants, struct cosmology *cosmo,
     const struct hydro_props *hydro, const struct gravity_props *gravity,
     const struct external_potential *potential,
     const struct cooling_function_data *cooling_func,
@@ -5200,16 +5215,15 @@ void engine_init(
   e->proxy_ind = NULL;
   e->nr_proxies = 0;
   e->reparttype = reparttype;
-  e->timeBegin = parser_get_param_double(params, "TimeIntegration:time_begin");
-  e->timeEnd = parser_get_param_double(params, "TimeIntegration:time_end");
-  e->timeOld = e->timeBegin;
-  e->time = e->timeBegin;
   e->ti_old = 0;
   e->ti_current = 0;
+  e->time_step = 0.;
+  e->time_base = 0.;
+  e->time_base_inv = 0.;
+  e->time_begin = 0.;
+  e->time_end = 0.;
   e->max_active_bin = num_time_bins;
-  e->timeStep = 0.;
-  e->timeBase = 0.;
-  e->timeBase_inv = 0.;
+  e->min_active_bin = 1;
   e->internal_units = internal_units;
   e->timeFirstSnapshot =
       parser_get_param_double(params, "Snapshots:time_first");
@@ -5231,6 +5245,7 @@ void engine_init(
   e->count_step = 0;
   e->wallclock_time = 0.f;
   e->physical_constants = physical_constants;
+  e->cosmology = cosmo;
   e->hydro_properties = hydro;
   e->gravity_properties = gravity;
   e->external_potential = potential;
@@ -5246,10 +5261,29 @@ void engine_init(
   /* Make the space link back to the engine. */
   s->e = e;
 
-  /* Setup the timestep */
-  e->timeBase = (e->timeEnd - e->timeBegin) / max_nr_timesteps;
-  e->timeBase_inv = 1.0 / e->timeBase;
-  e->ti_current = 0;
+  /* Setup the timestep if non-cosmological */
+  if (!(e->policy & engine_policy_cosmology)) {
+    e->time_begin =
+        parser_get_param_double(params, "TimeIntegration:time_begin");
+    e->time_end = parser_get_param_double(params, "TimeIntegration:time_end");
+    e->time_old = e->time_begin;
+    e->time = e->time_begin;
+
+    e->time_base = (e->time_end - e->time_begin) / max_nr_timesteps;
+    e->time_base_inv = 1.0 / e->time_base;
+    e->ti_current = 0;
+  } else {
+
+    e->time_begin = e->cosmology->time_begin;
+    e->time_end = e->cosmology->time_end;
+    e->time_old = e->time_begin;
+    e->time = e->time_begin;
+
+    /* Copy the relevent information from the cosmology model */
+    e->time_base = e->cosmology->time_base;
+    e->time_base_inv = e->cosmology->time_base_inv;
+    e->ti_current = 0;
+  }
 }
 
 /**
@@ -5485,12 +5519,13 @@ void engine_config(int restart, struct engine *e,
           "Version: %s \n# "
           "Number of threads: %d\n# Number of MPI ranks: %d\n# Hydrodynamic "
           "scheme: %s\n# Hydrodynamic kernel: %s\n# No. of neighbours: %.2f "
-          "+/- %.4f\n# Eta: %f\n",
+          "+/- %.4f\n# Eta: %f\n# Config: %s\n# CFLAGS: %s\n",
           hostname(), git_branch(), git_revision(), compiler_name(),
           compiler_version(), e->nr_threads, e->nr_nodes, SPH_IMPLEMENTATION,
           kernel_name, e->hydro_properties->target_neighbours,
           e->hydro_properties->delta_neighbours,
-          e->hydro_properties->eta_neighbours);
+          e->hydro_properties->eta_neighbours, configuration_options(),
+          compilation_cflags());
 
       fprintf(e->file_timesteps,
               "# Step Properties: Rebuild=%d, Redistribute=%d, Repartition=%d, "
@@ -5500,9 +5535,10 @@ void engine_config(int restart, struct engine *e,
               engine_step_prop_snapshot, engine_step_prop_restarts);
 
       fprintf(e->file_timesteps,
-              "# %6s %14s %14s %12s %12s %12s %16s [%s] %6s\n", "Step", "Time",
-              "Time-step", "Updates", "g-Updates", "s-Updates",
-              "Wall-clock time", clocks_getunit(), "Props");
+              "# %6s %14s %14s %14s %9s %12s %12s %12s %16s [%s] %6s\n", "Step",
+              "Time", "Scale-factor", "Time-step", "Time-bins", "Updates",
+              "g-Updates", "s-Updates", "Wall-clock time", clocks_getunit(),
+              "Props");
       fflush(e->file_timesteps);
     }
   }
@@ -5519,11 +5555,11 @@ void engine_config(int restart, struct engine *e,
     if (e->nodeID == 0) gravity_props_print(e->gravity_properties);
 
   /* Check we have sensible time bounds */
-  if (e->timeBegin >= e->timeEnd)
+  if (e->time_begin >= e->time_end)
     error(
         "Final simulation time (t_end = %e) must be larger than the start time "
         "(t_beg = %e)",
-        e->timeEnd, e->timeBegin);
+        e->time_end, e->time_begin);
 
   /* Check we have sensible time-step values */
   if (e->dt_min > e->dt_max)
@@ -5532,47 +5568,40 @@ void engine_config(int restart, struct engine *e,
         "size (%e)",
         e->dt_min, e->dt_max);
 
-  /* Deal with timestep */
-  if (!restart) {
-    e->timeBase = (e->timeEnd - e->timeBegin) / max_nr_timesteps;
-    e->timeBase_inv = 1.0 / e->timeBase;
-    e->ti_current = 0;
-  }
-
   /* Info about time-steps */
   if (e->nodeID == 0) {
-    message("Absolute minimal timestep size: %e", e->timeBase);
+    message("Absolute minimal timestep size: %e", e->time_base);
 
-    float dt_min = e->timeEnd - e->timeBegin;
+    float dt_min = e->time_end - e->time_begin;
     while (dt_min > e->dt_min) dt_min /= 2.f;
 
     message("Minimal timestep size (on time-line): %e", dt_min);
 
-    float dt_max = e->timeEnd - e->timeBegin;
+    float dt_max = e->time_end - e->time_begin;
     while (dt_max > e->dt_max) dt_max /= 2.f;
 
     message("Maximal timestep size (on time-line): %e", dt_max);
   }
 
-  if (e->dt_min < e->timeBase && e->nodeID == 0)
+  if (e->dt_min < e->time_base && e->nodeID == 0)
     error(
         "Minimal time-step size smaller than the absolute possible minimum "
         "dt=%e",
-        e->timeBase);
+        e->time_base);
 
-  if (e->dt_max > (e->timeEnd - e->timeBegin) && e->nodeID == 0)
+  if (e->dt_max > (e->time_end - e->time_begin) && e->nodeID == 0)
     error("Maximal time-step size larger than the simulation run time t=%e",
-          e->timeEnd - e->timeBegin);
+          e->time_end - e->time_begin);
 
   /* Deal with outputs */
   if (e->deltaTimeSnapshot < 0.)
     error("Time between snapshots (%e) must be positive.",
           e->deltaTimeSnapshot);
 
-  if (e->timeFirstSnapshot < e->timeBegin)
+  if (e->timeFirstSnapshot < e->time_begin)
     error(
         "Time of first snapshot (%e) must be after the simulation start t=%e.",
-        e->timeFirstSnapshot, e->timeBegin);
+        e->timeFirstSnapshot, e->time_begin);
 
   /* Find the time of the first output */
   engine_compute_next_snapshot_time(e);
@@ -5737,7 +5766,7 @@ void engine_print_policy(struct engine *e) {
     printf("[0000] %s engine_policy: engine policies are [ ",
            clocks_get_timesincestart());
     for (int k = 0; k <= engine_maxpolicy; k++)
-      if (e->policy & (1 << k)) printf(" %s ", engine_policy_names[k + 1]);
+      if (e->policy & (1 << k)) printf(" '%s' ", engine_policy_names[k + 1]);
     printf(" ]\n");
     fflush(stdout);
   }
@@ -5745,7 +5774,7 @@ void engine_print_policy(struct engine *e) {
   printf("%s engine_policy: engine policies are [ ",
          clocks_get_timesincestart());
   for (int k = 0; k <= engine_maxpolicy; k++)
-    if (e->policy & (1 << k)) printf(" %s ", engine_policy_names[k + 1]);
+    if (e->policy & (1 << k)) printf(" '%s' ", engine_policy_names[k + 1]);
   printf(" ]\n");
   fflush(stdout);
 #endif
@@ -5758,13 +5787,30 @@ void engine_print_policy(struct engine *e) {
  */
 void engine_compute_next_snapshot_time(struct engine *e) {
 
-  for (double time = e->timeFirstSnapshot;
-       time < e->timeEnd + e->deltaTimeSnapshot; time += e->deltaTimeSnapshot) {
+  /* Find upper-bound on last output */
+  double time_end;
+  if (e->policy & engine_policy_cosmology)
+    time_end = e->cosmology->a_end * e->deltaTimeSnapshot;
+  else
+    time_end = e->time_end + e->deltaTimeSnapshot;
+
+  /* Find next snasphot above current time */
+  double time = e->timeFirstSnapshot;
+  while (time < time_end) {
 
     /* Output time on the integer timeline */
-    e->ti_nextSnapshot = (time - e->timeBegin) / e->timeBase;
+    if (e->policy & engine_policy_cosmology)
+      e->ti_nextSnapshot = log(time / e->cosmology->a_begin) / e->time_base;
+    else
+      e->ti_nextSnapshot = (time - e->time_begin) / e->time_base;
 
+    /* Found it? */
     if (e->ti_nextSnapshot > e->ti_current) break;
+
+    if (e->policy & engine_policy_cosmology)
+      time *= e->deltaTimeSnapshot;
+    else
+      time += e->deltaTimeSnapshot;
   }
 
   /* Deal with last snapshot */
@@ -5774,10 +5820,15 @@ void engine_compute_next_snapshot_time(struct engine *e) {
   } else {
 
     /* Be nice, talk... */
-    const float next_snapshot_time =
-        e->ti_nextSnapshot * e->timeBase + e->timeBegin;
-    if (e->verbose)
+    if (e->policy & engine_policy_cosmology) {
+      const float next_snapshot_time =
+          exp(e->ti_nextSnapshot * e->time_base) * e->cosmology->a_begin;
+      message("Next output time set to a=%e.", next_snapshot_time);
+    } else {
+      const float next_snapshot_time =
+          e->ti_nextSnapshot * e->time_base + e->time_begin;
       message("Next output time set to t=%e.", next_snapshot_time);
+    }
   }
 }
 
@@ -5820,6 +5871,7 @@ void engine_struct_dump(struct engine *e, FILE *stream) {
   space_struct_dump(e->s, stream);
   units_struct_dump(e->internal_units, stream);
   units_struct_dump(e->snapshotUnits, stream);
+  cosmology_struct_dump(e->cosmology, stream);
 
 #ifdef WITH_MPI
   /* Save the partition for restoration. */
@@ -5832,6 +5884,7 @@ void engine_struct_dump(struct engine *e, FILE *stream) {
   gravity_props_struct_dump(e->gravity_properties, stream);
   potential_struct_dump(e->external_potential, stream);
   cooling_struct_dump(e->cooling_func, stream);
+  chemistry_struct_dump(e->chemistry, stream);
   sourceterms_struct_dump(e->sourceterms, stream);
   parser_struct_dump(e->parameter_file, stream);
 }
@@ -5871,6 +5924,11 @@ void engine_struct_restore(struct engine *e, FILE *stream) {
   units_struct_restore(us, stream);
   e->snapshotUnits = us;
 
+  struct cosmology *cosmo =
+      (struct cosmology *)malloc(sizeof(struct cosmology));
+  cosmology_struct_restore(cosmo, stream);
+  e->cosmology = cosmo;
+
 #ifdef WITH_MPI
   struct repartition *reparttype =
       (struct repartition *)malloc(sizeof(struct repartition));
@@ -5904,6 +5962,11 @@ void engine_struct_restore(struct engine *e, FILE *stream) {
   cooling_struct_restore(cooling_func, stream);
   e->cooling_func = cooling_func;
 
+  struct chemistry_data *chemistry =
+      (struct chemistry_data *)malloc(sizeof(struct chemistry_data));
+  chemistry_struct_restore(chemistry, stream);
+  e->chemistry = chemistry;
+
   struct sourceterms *sourceterms =
       (struct sourceterms *)malloc(sizeof(struct sourceterms));
   sourceterms_struct_restore(sourceterms, stream);
diff --git a/src/engine.h b/src/engine.h
index 67ca66c12fc56b55fd25091b24635c837c567f92..0fa8ca93b84760d0d92d9494f6e8e6224e3d1d9a 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -126,13 +126,13 @@ struct engine {
   double dt_min, dt_max;
 
   /* Time of the simulation beginning */
-  double timeBegin;
+  double time_begin;
 
   /* Time of the simulation end */
-  double timeEnd;
+  double time_end;
 
   /* The previous system time. */
-  double timeOld;
+  double time_old;
   integertime_t ti_old;
 
   /* The current system time. */
@@ -142,12 +142,15 @@ struct engine {
   /* The highest active bin at this time */
   timebin_t max_active_bin;
 
+  /* The lowest active bin at this time */
+  timebin_t min_active_bin;
+
   /* Time step */
-  double timeStep;
+  double time_step;
 
   /* Time base */
-  double timeBase;
-  double timeBase_inv;
+  double time_base;
+  double time_base_inv;
 
   /* Minimal hydro ti_end for the next time-step */
   integertime_t ti_hydro_end_min;
@@ -268,6 +271,9 @@ struct engine {
   /* Physical constants definition */
   const struct phys_const *physical_constants;
 
+  /* The cosmological model */
+  struct cosmology *cosmology;
+
   /* Properties of the hydro scheme */
   const struct hydro_props *hydro_properties;
 
@@ -328,7 +334,7 @@ void engine_init(
     struct engine *e, struct space *s, const struct swift_params *params,
     long long Ngas, long long Ndm, int policy, int verbose,
     struct repartition *reparttype, const struct unit_system *internal_units,
-    const struct phys_const *physical_constants,
+    const struct phys_const *physical_constants, struct cosmology *cosmo,
     const struct hydro_props *hydro, const struct gravity_props *gravity,
     const struct external_potential *potential,
     const struct cooling_function_data *cooling_func,
diff --git a/src/gravity/Default/gravity.h b/src/gravity/Default/gravity.h
index 94192321440cd6fcb49722a5c69f1f121f24cd1e..bc06b17188f99785404a1162d46384ee26c884ea 100644
--- a/src/gravity/Default/gravity.h
+++ b/src/gravity/Default/gravity.h
@@ -21,6 +21,7 @@
 #define SWIFT_DEFAULT_GRAVITY_H
 
 #include <float.h>
+#include "cosmology.h"
 #include "gravity_properties.h"
 #include "minmax.h"
 
@@ -63,22 +64,37 @@ __attribute__((always_inline)) INLINE static float gravity_get_potential(
  * We use Gadget-2's type 0 time-step criterion.
  *
  * @param gp Pointer to the g-particle data.
+ * @param a_hydro The accelerations coming from the hydro scheme (can be 0).
  * @param grav_props Constants used in the gravity scheme.
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static float
 gravity_compute_timestep_self(const struct gpart* const gp,
-                              const struct gravity_props* restrict grav_props) {
+                              const float a_hydro[3],
+                              const struct gravity_props* restrict grav_props,
+                              const struct cosmology* cosmo) {
 
-  const float ac2 = gp->a_grav[0] * gp->a_grav[0] +
-                    gp->a_grav[1] * gp->a_grav[1] +
-                    gp->a_grav[2] * gp->a_grav[2];
+  /* Get physical acceleration (gravity contribution) */
+  float a_phys_x = gp->a_grav[0] * cosmo->a_factor_grav_accel;
+  float a_phys_y = gp->a_grav[1] * cosmo->a_factor_grav_accel;
+  float a_phys_z = gp->a_grav[2] * cosmo->a_factor_grav_accel;
+
+  /* Get physical acceleration (hydro contribution) */
+  a_phys_x += a_hydro[0] * cosmo->a_factor_hydro_accel;
+  a_phys_y += a_hydro[1] * cosmo->a_factor_hydro_accel;
+  a_phys_z += a_hydro[2] * cosmo->a_factor_hydro_accel;
+
+  const float ac2 =
+      a_phys_x * a_phys_x + a_phys_y * a_phys_y + a_phys_z * a_phys_z;
 
   const float ac_inv = (ac2 > 0.f) ? 1.f / sqrtf(ac2) : FLT_MAX;
 
+  // MATTHIEU cosmological evolution of the softening?
   const float epsilon = gravity_get_softening(gp);
 
   /* Note that 0.66666667 = 2. (from Gadget) / 3. (Plummer softening) */
-  const float dt = sqrtf(0.66666667f * grav_props->eta * epsilon * ac_inv);
+  const float dt =
+      sqrtf(0.66666667f * cosmo->a * grav_props->eta * epsilon * ac_inv);
 
   return dt;
 }
diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h
index 890380b23ac1496854dc5359f9249993c166d2c3..1228aa69abfe812e5b2e73f066bb13be3292aa20 100644
--- a/src/hydro/Default/hydro.h
+++ b/src/hydro/Default/hydro.h
@@ -21,71 +21,134 @@
 
 #include "adiabatic_index.h"
 #include "approx_math.h"
+#include "cosmology.h"
+#include "dimension.h"
 #include "equation_of_state.h"
 #include "hydro_space.h"
+#include "kernel_hydro.h"
 #include "minmax.h"
 
 #include <float.h>
 
 /**
- * @brief Returns the internal energy of a particle
+ * @brief Returns the comoving 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) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_internal_energy(const struct part *restrict p) {
 
   return p->u;
 }
 
 /**
- * @brief Returns the pressure of a particle
+ * @brief Returns the physical internal energy of a particle
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_internal_energy(const struct part *restrict p,
+                                   const struct cosmology *cosmo) {
+
+  return cosmo->a_factor_internal_energy * p->u;
+}
+
+/**
+ * @brief Returns the comoving 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(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure(
     const struct part *restrict p) {
 
   return gas_pressure_from_internal_energy(p->rho, p->u);
 }
 
 /**
- * @brief Returns the entropy of a particle
+ * @brief Returns the physical pressure of a particle
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return cosmo->a_factor_pressure *
+         gas_pressure_from_internal_energy(p->rho, p->u);
+}
+
+/**
+ * @brief Returns the comoving 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(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy(
     const struct part *restrict p) {
 
   return gas_entropy_from_internal_energy(p->rho, p->u);
 }
 
 /**
- * @brief Returns the sound speed of a particle
+ * @brief Returns the physical entropy of a particle
  *
  * @param p The particle of interest
- * @param dt Time since the last kick
+ * @param cosmo The cosmological model.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
-    const struct part *restrict p) {
+__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  /* Note: no cosmological conversion required here with our choice of
+   * coordinates. */
+  return gas_entropy_from_internal_energy(p->rho, p->u);
+}
+
+/**
+ * @brief Returns the comoving sound speed of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_soundspeed(const struct part *restrict p) {
 
   return p->force.soundspeed;
 }
 
 /**
- * @brief Returns the density of a particle
+ * @brief Returns the physical sound speed of a particle
  *
  * @param p The particle of interest
+ * @param cosmo The cosmological model.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_density(
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_soundspeed(const struct part *restrict p,
+                              const struct cosmology *cosmo) {
+
+  return cosmo->a_factor_sound_speed * p->force.soundspeed;
+}
+
+/**
+ * @brief Returns the comoving density of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_density(
     const struct part *restrict p) {
 
   return p->rho;
 }
 
+/**
+ * @brief Returns the physical density of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_density(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return p->rho * cosmo->a3_inv;
+}
+
 /**
  * @brief Returns the mass of a particle
  *
@@ -102,16 +165,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
  *
  * @param p The particle of interest
  * @param xp The extended data of the particle.
- * @param dt The time since the last kick.
+ * @param dt_kick_hydro The time (for hydro accelerations) since the last kick.
+ * @param dt_kick_grav The time (for gravity accelerations) since the last kick.
  * @param v (return) The velocities at the current time.
  */
 __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities(
-    const struct part *restrict p, const struct xpart *xp, float dt,
-    float v[3]) {
-
-  v[0] = xp->v_full[0] + p->a_hydro[0] * dt;
-  v[1] = xp->v_full[1] + p->a_hydro[1] * dt;
-  v[2] = xp->v_full[2] + p->a_hydro[2] * dt;
+    const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro,
+    float dt_kick_grav, float v[3]) {
+
+  v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro +
+         xp->a_grav[0] * dt_kick_grav;
+  v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro +
+         xp->a_grav[1] * dt_kick_grav;
+  v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro +
+         xp->a_grav[2] * dt_kick_grav;
 }
 
 /**
@@ -146,17 +213,19 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt(
  *
  * @param p Pointer to the particle data
  * @param xp Pointer to the extended particle data
- *
+ * @param hydro_properties The constants used in the scheme
+ * @param cosmo The cosmological model.
  */
 __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 struct hydro_props *restrict hydro_properties,
+    const struct cosmology *restrict cosmo) {
 
-  const float CFL_condition = hydro_properties->CFL_condition;
+  const float CFL = hydro_properties->CFL_condition;
 
   /* CFL condition */
-  const float dt_cfl =
-      2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig;
+  const float dt_cfl = 2.f * kernel_gamma * CFL * cosmo->a * p->h /
+                       (cosmo->a_factor_sound_speed * p->force.v_sig);
 
   /* Limit change in u */
   const float dt_u_change =
@@ -187,6 +256,7 @@ __attribute__((always_inline)) INLINE static void hydro_timestep_extra(
  */
 __attribute__((always_inline)) INLINE static void hydro_init_part(
     struct part *restrict p, const struct hydro_space *hs) {
+
   p->density.wcount = 0.f;
   p->density.wcount_dh = 0.f;
   p->rho = 0.f;
@@ -204,9 +274,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
  * and add the self-contribution term.
  *
  * @param p The particle to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_density(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -226,14 +297,15 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
   p->density.wcount_dh *= h_inv * kernel_gamma * kernel_norm;
 
   const float irho = 1.f / p->rho;
+  const float a_inv2 = cosmo->a2_inv;
 
   /* 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 * a_inv2 * irho;
+  p->density.rot_v[1] *= h_inv_dim_plus_one * a_inv2 * irho;
+  p->density.rot_v[2] *= h_inv_dim_plus_one * a_inv2 * irho;
 
   /* 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 * a_inv2 * irho;
 }
 
 /**
@@ -241,9 +313,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
  *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -268,10 +342,13 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
  *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
- * @param time The current time
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_prepare_force(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
+
+  const float fac_mu = cosmo->a_factor_mu;
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -296,7 +373,8 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force(
   p->force.P_over_rho2 = u * hydro_gamma_minus_one / (p->rho * xp->omega);
 
   /* Balsara switch */
-  p->force.balsara = normDiv_v / (normDiv_v + normRot_v + 0.0001f * fc * h_inv);
+  p->force.balsara =
+      normDiv_v / (normDiv_v + normRot_v + 0.0001f * fac_mu * fc * h_inv);
 
   /* Viscosity parameter decay time */
   /* const float tau = h / (2.f * const_viscosity_length * p->force.soundspeed);
@@ -349,6 +427,8 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
   p->v[0] = xp->v_full[0];
   p->v[1] = xp->v_full[1];
   p->v[2] = xp->v_full[2];
+
+  p->u = xp->u_full;
 }
 
 /**
@@ -356,19 +436,18 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
  *
  * @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
- * @param t1 The time at the end of the drift
- * @param timeBase The minimal time-step size
+ * @param dt_drift The drift time-step for positions.
+ * @param dt_therm The drift time-step for thermal quantities.
  */
 __attribute__((always_inline)) INLINE static void hydro_predict_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt) {
+    struct part *restrict p, struct xpart *restrict xp, float dt_drift,
+    float dt_therm) {
   float u, w;
 
   const float h_inv = 1.f / p->h;
 
   /* Predict smoothing length */
-  const float w1 = p->force.h_dt * h_inv * dt;
+  const float w1 = p->force.h_dt * h_inv * dt_drift;
   if (fabsf(w1) < 0.2f)
     p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */
   else
@@ -382,7 +461,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
     p->rho *= expf(w2);
 
   /* Predict internal energy */
-  w = p->force.u_dt / p->u * dt;
+  w = p->force.u_dt / p->u * dt_therm;
   if (fabsf(w) < 0.2f)
     u = p->u *= approx_expf(w);
   else
@@ -398,9 +477,10 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
  * Multiplies the forces and accelerationsby the appropiate constants
  *
  * @param p The particle to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_force(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
   p->force.h_dt *= p->h * hydro_dimension_inv;
 }
 
@@ -409,11 +489,10 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  *
  * @param p The particle to act upon
  * @param xp The particle extended data to act upon
- * @param dt The time-step for this kick
- * @param half_dt The half time-step for this kick
+ * @param dt_therm The time-step for this kick (for thermodynamic quantities)
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt) {}
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {}
 
 /**
  *  @brief Converts hydro quantity of a particle at the start of a run
@@ -441,6 +520,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   xp->v_full[0] = p->v[0];
   xp->v_full[1] = p->v[1];
   xp->v_full[2] = p->v[2];
+  xp->a_grav[0] = 0.f;
+  xp->a_grav[1] = 0.f;
+  xp->a_grav[2] = 0.f;
   xp->u_full = p->u;
 
   hydro_reset_acceleration(p);
diff --git a/src/hydro/Default/hydro_iact.h b/src/hydro/Default/hydro_iact.h
index 89b90be22b831066c8b9211bfe50208b4c4af67e..658b4aba83085610a49bb9d2579d4f20c70d6c5b 100644
--- a/src/hydro/Default/hydro_iact.h
+++ b/src/hydro/Default/hydro_iact.h
@@ -26,22 +26,32 @@
  * @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
+ * and use the same
  * numerical coefficients as the Gadget-2 code. When used with the Spline-3
- *kernel, the results
+ * kernel, the results
  * should be equivalent to the ones obtained with Gadget-2 up to the rounding
- *errors and interactions
+ * errors and interactions
  * missed by the Gadget-2 tree-code neighbours search.
  *
  * The code uses internal energy instead of entropy as a thermodynamical
- *variable.
+ * variable.
  */
 
 /**
- * @brief Density loop
+ * @brief Density interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_density(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float r = sqrtf(r2), ri = 1.0f / r;
   float xi, xj;
@@ -97,10 +107,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
 }
 
 /**
- * @brief Density loop (non-symmetric version)
+ * @brief Density interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float r, ri;
   float xi;
@@ -145,10 +165,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
 }
 
 /**
- * @brief Force loop
+ * @brief Force interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_force(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float r = sqrtf(r2), ri = 1.0f / r;
   float xi, xj;
@@ -160,6 +190,10 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   float f;
   int k;
 
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
+
   /* Get some values in local variables. */
   mi = pi->mass;
   mj = pj->mass;
@@ -184,12 +218,12 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
 
   /* Compute dv dot r. */
   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];
+         (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
   dvdr *= ri;
 
   /* Compute the relative velocity. (This is 0 if the particles move away from
    * each other and negative otherwise) */
-  omega_ij = min(dvdr, 0.f);
+  omega_ij = min(fac_mu * dvdr, 0.f);
 
   /* Compute signal velocity */
   v_sig = pi->force.soundspeed + pj->force.soundspeed - 2.0f * omega_ij;
@@ -240,10 +274,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
 }
 
 /**
- * @brief Force loop (non-symmetric version)
+ * @brief Force interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float r = sqrtf(r2), ri = 1.0f / r;
   float xi, xj;
@@ -255,6 +299,10 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   float f;
   int k;
 
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
+
   /* Get some values in local variables. */
   // mi = pi->mass;
   mj = pj->mass;
@@ -279,12 +327,12 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
 
   /* Compute dv dot r. */
   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];
+         (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
   dvdr *= ri;
 
   /* Compute the relative velocity. (This is 0 if the particles move away from
    * each other and negative otherwise) */
-  omega_ij = min(dvdr, 0.f);
+  omega_ij = min(fac_mu * dvdr, 0.f);
 
   /* Compute signal velocity */
   v_sig = pi->force.soundspeed + pj->force.soundspeed - 2.0f * omega_ij;
diff --git a/src/hydro/Default/hydro_part.h b/src/hydro/Default/hydro_part.h
index 6290ee5ba37a567b3819a06b8b824d83071ee4c2..2a18e03cb533ca860f227a31152ef2058e0dd37d 100644
--- a/src/hydro/Default/hydro_part.h
+++ b/src/hydro/Default/hydro_part.h
@@ -34,6 +34,9 @@ struct xpart {
   /* Velocity at the last full step. */
   float v_full[3];
 
+  /* Gravitational acceleration at the last full step. */
+  float a_grav[3];
+
   /* Additional data used to record cooling information */
   struct cooling_xpart_data cooling_data;
 
diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h
index f3c33bc7a00bc649d5e6a2d5b75bc04022359f72..185a98b6d207bb851512a686be51414341fe7740 100644
--- a/src/hydro/Gadget2/hydro.h
+++ b/src/hydro/Gadget2/hydro.h
@@ -33,6 +33,7 @@
 
 #include "adiabatic_index.h"
 #include "approx_math.h"
+#include "cosmology.h"
 #include "dimension.h"
 #include "equation_of_state.h"
 #include "hydro_properties.h"
@@ -41,60 +42,123 @@
 #include "minmax.h"
 
 /**
- * @brief Returns the internal energy of a particle
+ * @brief Returns the comoving internal energy of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
-    const struct part *restrict p) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_internal_energy(const struct part *restrict p) {
 
   return gas_internal_energy_from_entropy(p->rho, p->entropy);
 }
 
 /**
- * @brief Returns the pressure of a particle
+ * @brief Returns the physical internal energy of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_internal_energy(const struct part *restrict p,
+                                   const struct cosmology *cosmo) {
+
+  return gas_internal_energy_from_entropy(p->rho * cosmo->a3_inv, p->entropy);
+}
+
+/**
+ * @brief Returns the comoving pressure of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_pressure(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure(
     const struct part *restrict p) {
 
   return gas_pressure_from_entropy(p->rho, p->entropy);
 }
 
 /**
- * @brief Returns the entropy of a particle
+ * @brief Returns the physical pressure of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_entropy(
+__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return gas_pressure_from_entropy(p->rho * cosmo->a3_inv, p->entropy);
+}
+
+/**
+ * @brief Returns the comoving entropy of a particle
+ *
+ * @param p The particle of interest.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy(
     const struct part *restrict p) {
 
   return p->entropy;
 }
 
 /**
- * @brief Returns the sound speed of a particle
+ * @brief Returns the physical entropy of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  /* Note: no cosmological conversion required here with our choice of
+   * coordinates. */
+  return p->entropy;
+}
+
+/**
+ * @brief Returns the comoving sound speed of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
-    const struct part *restrict p) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_soundspeed(const struct part *restrict p) {
 
   return p->force.soundspeed;
 }
 
 /**
- * @brief Returns the density of a particle
+ * @brief Returns the physical sound speed of a particle
  *
  * @param p The particle of interest
+ * @param cosmo The cosmological model.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_density(
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_soundspeed(const struct part *restrict p,
+                              const struct cosmology *cosmo) {
+
+  return cosmo->a_factor_sound_speed * p->force.soundspeed;
+}
+
+/**
+ * @brief Returns the comoving density of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_density(
     const struct part *restrict p) {
 
   return p->rho;
 }
 
+/**
+ * @brief Returns the physical density of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_density(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return p->rho * cosmo->a3_inv;
+}
+
 /**
  * @brief Returns the mass of a particle
  *
@@ -111,16 +175,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
  *
  * @param p The particle of interest
  * @param xp The extended data of the particle.
- * @param dt The time since the last kick.
+ * @param dt_kick_hydro The time (for hydro accelerations) since the last kick.
+ * @param dt_kick_grav The time (for gravity accelerations) since the last kick.
  * @param v (return) The velocities at the current time.
  */
 __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities(
-    const struct part *restrict p, const struct xpart *xp, float dt,
-    float v[3]) {
-
-  v[0] = xp->v_full[0] + p->a_hydro[0] * dt;
-  v[1] = xp->v_full[1] + p->a_hydro[1] * dt;
-  v[2] = xp->v_full[2] + p->a_hydro[2] * dt;
+    const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro,
+    float dt_kick_grav, float v[3]) {
+
+  v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro +
+         xp->a_grav[0] * dt_kick_grav;
+  v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro +
+         xp->a_grav[1] * dt_kick_grav;
+  v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro +
+         xp->a_grav[2] * dt_kick_grav;
 }
 
 /**
@@ -155,17 +223,19 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt(
  *
  * @param p Pointer to the particle data
  * @param xp Pointer to the extended particle data
- *
+ * @param hydro_properties The constants used in the scheme
+ * @param cosmo The cosmological model.
  */
 __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 struct hydro_props *restrict hydro_properties,
+    const struct cosmology *restrict cosmo) {
 
-  const float CFL_condition = hydro_properties->CFL_condition;
+  const float CFL = hydro_properties->CFL_condition;
 
   /* CFL condition */
-  const float dt_cfl =
-      2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig;
+  const float dt_cfl = 2.f * kernel_gamma * CFL * cosmo->a * p->h /
+                       (cosmo->a_factor_sound_speed * p->force.v_sig);
 
   return dt_cfl;
 }
@@ -214,9 +284,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
  * and add the self-contribution term.
  *
  * @param p The particle to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_density(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -237,14 +308,15 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
   p->density.wcount_dh *= h_inv_dim_plus_one;
 
   const float rho_inv = 1.f / p->rho;
+  const float a_inv2 = cosmo->a2_inv;
 
-  /* 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 (physical) velocity curl components */
+  p->density.rot_v[0] *= h_inv_dim_plus_one * a_inv2 * rho_inv;
+  p->density.rot_v[1] *= h_inv_dim_plus_one * a_inv2 * rho_inv;
+  p->density.rot_v[2] *= h_inv_dim_plus_one * a_inv2 * rho_inv;
 
-  /* Finish calculation of the velocity divergence */
-  p->density.div_v *= h_inv_dim_plus_one * rho_inv;
+  /* Finish calculation of the (physical) velocity divergence */
+  p->density.div_v *= h_inv_dim_plus_one * a_inv2 * rho_inv;
 }
 
 /**
@@ -252,9 +324,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
  *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -279,13 +353,13 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
  *
  * @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
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_prepare_force(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  const float fac_mu = cosmo->a_factor_mu;
 
   /* Inverse of the physical density */
   const float rho_inv = 1.f / p->rho;
@@ -309,7 +383,7 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force(
 
   /* Compute the Balsara switch */
   const float balsara =
-      abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed / fac_mu / p->h);
+      abs_div_v / (abs_div_v + curl_v + 0.0001f * fac_mu * soundspeed / p->h);
 
   /* Compute the "grad h" term */
   const float omega_inv =
@@ -375,18 +449,17 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
  *
  * @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
- * @param t1 The time at the end of the drift
- * @param timeBase The minimal time-step size
+ * @param dt_drift The drift time-step for positions.
+ * @param dt_therm The drift time-step for thermal quantities.
  */
 __attribute__((always_inline)) INLINE static void hydro_predict_extra(
-    struct part *restrict p, const struct xpart *restrict xp, float dt) {
+    struct part *restrict p, const struct xpart *restrict xp, float dt_drift,
+    float dt_therm) {
 
   const float h_inv = 1.f / p->h;
 
   /* Predict smoothing length */
-  const float w1 = p->force.h_dt * h_inv * dt;
+  const float w1 = p->force.h_dt * h_inv * dt_drift;
   if (fabsf(w1) < 0.2f)
     p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */
   else
@@ -400,7 +473,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
     p->rho *= expf(w2);
 
   /* Predict the entropy */
-  p->entropy += p->entropy_dt * dt;
+  p->entropy += p->entropy_dt * dt_therm;
 
   /* Re-compute the pressure */
   const float pressure = gas_pressure_from_entropy(p->rho, p->entropy);
@@ -423,14 +496,15 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
  * Multiplies the forces and accelerationsby the appropiate constants
  *
  * @param p The particle to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_force(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
 
   p->force.h_dt *= p->h * hydro_dimension_inv;
 
-  p->entropy_dt =
-      0.5f * gas_entropy_from_internal_energy(p->rho, p->entropy_dt);
+  p->entropy_dt = 0.5f * cosmo->a2_inv *
+                  gas_entropy_from_internal_energy(p->rho, p->entropy_dt);
 }
 
 /**
@@ -438,19 +512,19 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  *
  * @param p The particle to act upon
  * @param xp The particle extended data to act upon
- * @param dt The time-step for this kick
+ * @param dt_therm The time-step for this kick (for thermodynamic quantities)
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt) {
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {
 
   /* Do not decrease the entropy by more than a factor of 2 */
-  if (dt > 0. && p->entropy_dt * dt < -0.5f * xp->entropy_full) {
+  if (dt_therm > 0. && p->entropy_dt * dt_therm < -0.5f * xp->entropy_full) {
     /* message("Warning! Limiting entropy_dt. Possible cooling error.\n
      * entropy_full = %g \n entropy_dt * dt =%g \n", */
     /* 	     xp->entropy_full,p->entropy_dt * dt); */
-    p->entropy_dt = -0.5f * xp->entropy_full / dt;
+    p->entropy_dt = -0.5f * xp->entropy_full / dt_therm;
   }
-  xp->entropy_full += p->entropy_dt * dt;
+  xp->entropy_full += p->entropy_dt * dt_therm;
 
   /* Compute the pressure */
   const float pressure = gas_pressure_from_entropy(p->rho, xp->entropy_full);
@@ -510,6 +584,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   xp->v_full[0] = p->v[0];
   xp->v_full[1] = p->v[1];
   xp->v_full[2] = p->v[2];
+  xp->a_grav[0] = 0.f;
+  xp->a_grav[1] = 0.f;
+  xp->a_grav[2] = 0.f;
   xp->entropy_full = p->entropy;
 
   hydro_reset_acceleration(p);
diff --git a/src/hydro/Gadget2/hydro_debug.h b/src/hydro/Gadget2/hydro_debug.h
index 6500d1126bd5b5a65d3e511c13afb8364574e0ba..d0642a03a4c4eecb2da80fdae473948e460c5e31 100644
--- a/src/hydro/Gadget2/hydro_debug.h
+++ b/src/hydro/Gadget2/hydro_debug.h
@@ -31,7 +31,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->h, p->density.wcount, p->density.wcount_dh, p->mass, p->density.rho_dh,
-      p->rho, hydro_get_pressure(p), p->force.P_over_rho2, p->entropy,
+      p->rho, hydro_get_comoving_pressure(p), 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->time_bin);
diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h
index d30fd7b80318465cb654d769accd0e185336a878..90484c9cee1b384b0540f56e3c845cc4120cdfe0 100644
--- a/src/hydro/Gadget2/hydro_iact.h
+++ b/src/hydro/Gadget2/hydro_iact.h
@@ -36,10 +36,20 @@
 #include "minmax.h"
 
 /**
- * @brief Density loop
+ * @brief Density interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_density(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float wi, wi_dx;
   float wj, wj_dx;
@@ -117,10 +127,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
 }
 
 /**
- * @brief Density loop (non-symmetric version)
+ * @brief Density interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float wi, wi_dx;
   float dv[3], curlvr[3];
@@ -399,14 +419,26 @@ runner_iact_nonsym_2_vec_density(float *R2, float *Dx, float *Dy, float *Dz,
 #endif
 
 /**
- * @brief Force loop
+ * @brief Force interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_force(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float wi, wj, wi_dx, wj_dx;
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
 
   const float r = sqrtf(r2);
   const float r_inv = 1.0f / r;
@@ -446,7 +478,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   /* 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];
+                     (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
 
   /* Balsara term */
   const float balsara_i = pi->force.balsara;
@@ -486,8 +518,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   pj->force.h_dt -= mi * dvdr * r_inv / rhoi * wj_dr;
 
   /* Update the signal velocity. */
-  pi->force.v_sig = (pi->force.v_sig > v_sig) ? pi->force.v_sig : v_sig;
-  pj->force.v_sig = (pj->force.v_sig > v_sig) ? pj->force.v_sig : v_sig;
+  pi->force.v_sig = max(pi->force.v_sig, v_sig);
+  pj->force.v_sig = max(pj->force.v_sig, v_sig);
 
   /* Change in entropy */
   pi->entropy_dt += mj * visc_term * dvdr;
@@ -506,14 +538,26 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
 }
 
 /**
- * @brief Force loop (non-symmetric version)
+ * @brief Force interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float wi, wj, wi_dx, wj_dx;
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
 
   const float r = sqrtf(r2);
   const float r_inv = 1.0f / r;
@@ -553,7 +597,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   /* 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];
+                     (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
 
   /* Balsara term */
   const float balsara_i = pi->force.balsara;
@@ -588,7 +632,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   pi->force.h_dt -= mj * dvdr * r_inv / rhoj * wi_dr;
 
   /* Update the signal velocity. */
-  pi->force.v_sig = (pi->force.v_sig > v_sig) ? pi->force.v_sig : v_sig;
+  pi->force.v_sig = max(pi->force.v_sig, v_sig);
 
   /* Change in entropy */
   pi->entropy_dt += mj * visc_term * dvdr;
diff --git a/src/hydro/Gadget2/hydro_io.h b/src/hydro/Gadget2/hydro_io.h
index 917e260fbd16526c7f2f6983b674df597555a41f..1d1f5ed453f249191b6853a3a699de847ed501f2 100644
--- a/src/hydro/Gadget2/hydro_io.h
+++ b/src/hydro/Gadget2/hydro_io.h
@@ -57,12 +57,12 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
 
 void convert_u(const struct engine* e, const struct part* p, float* ret) {
 
-  ret[0] = hydro_get_internal_energy(p);
+  ret[0] = hydro_get_comoving_internal_energy(p);
 }
 
 void convert_P(const struct engine* e, const struct part* p, float* ret) {
 
-  ret[0] = hydro_get_pressure(p);
+  ret[0] = hydro_get_comoving_pressure(p);
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h
index 55745b52f4459905b02adf4824c489510ee93f97..90f73571701b37b3377601655330d8d25f862a05 100644
--- a/src/hydro/Gadget2/hydro_part.h
+++ b/src/hydro/Gadget2/hydro_part.h
@@ -46,6 +46,9 @@ struct xpart {
   /* Velocity at the last full step. */
   float v_full[3];
 
+  /* Gravitational acceleration at the last full step. */
+  float a_grav[3];
+
   /* Entropy at the last full step. */
   float entropy_full;
 
diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h
index b8c2c5e405e116acf5632b42b3b5fb60ae3e0d4e..0faa4bf39ae533ee9942898bdc08118ee4078868 100644
--- a/src/hydro/Gizmo/hydro.h
+++ b/src/hydro/Gizmo/hydro.h
@@ -22,6 +22,7 @@
 
 #include "adiabatic_index.h"
 #include "approx_math.h"
+#include "cosmology.h"
 #include "equation_of_state.h"
 #include "hydro_gradients.h"
 #include "hydro_properties.h"
@@ -41,10 +42,12 @@
  * @param p Pointer to the particle data.
  * @param xp Pointer to the extended particle data.
  * @param hydro_properties Pointer to the hydro parameters.
+ * @param cosmo The cosmological model.
  */
 __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 struct hydro_props* restrict hydro_properties,
+    const struct cosmology* restrict cosmo) {
 
   const float CFL_condition = hydro_properties->CFL_condition;
 
@@ -63,8 +66,11 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep(
       sqrtf(vrel[0] * vrel[0] + vrel[1] * vrel[1] + vrel[2] * vrel[2]) +
       sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho);
   vmax = max(vmax, p->timestepvars.vmax);
-  const float psize = powf(p->geometry.volume / hydro_dimension_unit_sphere,
-                           hydro_dimension_inv);
+
+  // MATTHIEU: Bert is this correct? Do we need more cosmology terms here?
+  const float psize =
+      cosmo->a * powf(p->geometry.volume / hydro_dimension_unit_sphere,
+                      hydro_dimension_inv);
   float dt = FLT_MAX;
   if (vmax > 0.) {
     dt = psize / vmax;
@@ -223,9 +229,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
  * passive particles.
  *
  * @param p The particle to act upon.
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_density(
-    struct part* restrict p) {
+    struct part* restrict p, const struct cosmology* cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -318,6 +325,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
   }
 #endif
 
+  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
   float momentum[3];
   momentum[0] = p->conserved.momentum[0];
   momentum[1] = p->conserved.momentum[1];
@@ -377,9 +385,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
  *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
-    struct part* restrict p, struct xpart* restrict xp) {
+    struct part* restrict p, struct xpart* restrict xp,
+    const struct cosmology* cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -420,13 +430,17 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
  *
  * @param p The particle to act upon.
  * @param xp The extended particle data to act upon.
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_prepare_force(
-    struct part* restrict p, struct xpart* restrict xp) {
+    struct part* restrict p, struct xpart* restrict xp,
+    const struct cosmology* cosmo) {
 
   /* Initialize time step criterion variables */
   p->timestepvars.vmax = 0.;
 
+  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
+
   /* Set the actual velocity of the particle */
   hydro_velocities_prepare_force(p, xp);
 }
@@ -510,13 +524,11 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities(
  *
  * @param p Particle to act upon.
  * @param xp The extended particle data to act upon.
- * @param dt The drift time-step.
- * @param t0 Integer start time of the drift interval.
- * @param t1 Integer end time of the drift interval.
- * @param timeBase Conversion factor between integer and physical time.
+ * @param dt_drift The drift time-step for positions.
+ * @param dt_therm The drift time-step for thermal quantities.
  */
 __attribute__((always_inline)) INLINE static void hydro_predict_extra(
-    struct part* p, struct xpart* xp, float dt) {
+    struct part* p, struct xpart* xp, float dt_drift, float dt_therm) {
 
 #ifdef GIZMO_LLOYD_ITERATION
   return;
@@ -525,7 +537,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
   const float h_inv = 1.0f / p->h;
 
   /* Predict smoothing length */
-  const float w1 = p->force.h_dt * h_inv * dt;
+  const float w1 = p->force.h_dt * h_inv * dt_drift;
   float h_corr;
   if (fabsf(w1) < 0.2f)
     h_corr = approx_expf(w1); /* 4th order expansion of exp(w) */
@@ -540,19 +552,20 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
 
   /* drift the primitive variables based on the old fluxes */
   if (p->geometry.volume > 0.) {
-    p->primitives.rho += p->conserved.flux.mass * dt / p->geometry.volume;
+    p->primitives.rho += p->conserved.flux.mass * dt_drift / p->geometry.volume;
   }
 
   if (p->conserved.mass > 0.) {
     p->primitives.v[0] +=
-        p->conserved.flux.momentum[0] * dt / p->conserved.mass;
+        p->conserved.flux.momentum[0] * dt_drift / p->conserved.mass;
     p->primitives.v[1] +=
-        p->conserved.flux.momentum[1] * dt / p->conserved.mass;
+        p->conserved.flux.momentum[1] * dt_drift / p->conserved.mass;
     p->primitives.v[2] +=
-        p->conserved.flux.momentum[2] * dt / p->conserved.mass;
+        p->conserved.flux.momentum[2] * dt_drift / p->conserved.mass;
 
+// MATTHIEU: Bert is this correct?
 #if !defined(EOS_ISOTHERMAL_GAS)
-    const float u = p->conserved.energy + p->conserved.flux.energy * dt;
+    const float u = p->conserved.energy + p->conserved.flux.energy * dt_therm;
     p->primitives.P =
         hydro_gamma_minus_one * u * p->primitives.rho / p->conserved.mass;
 #endif
@@ -576,12 +589,14 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
  * should only happen at the start of the simulation.
  *
  * @param p Particle to act upon.
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_force(
-    struct part* p) {
+    struct part* p, const struct cosmology* cosmo) {
 
   /* set the variables that are used to drift the primitive variables */
 
+  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
   hydro_velocities_end_force(p);
 }
 
@@ -679,12 +694,12 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra(
 }
 
 /**
- * @brief Returns the internal energy of a particle
+ * @brief Returns the comoving internal energy of a particle
  *
  * @param p The particle of interest.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
-    const struct part* restrict p) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_internal_energy(const struct part* restrict p) {
 
   if (p->primitives.rho > 0.)
     return gas_internal_energy_from_pressure(p->primitives.rho,
@@ -694,11 +709,25 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
 }
 
 /**
- * @brief Returns the entropy of a particle
+ * @brief Returns the physical internal energy of a particle
  *
  * @param p The particle of interest.
+ * @param cosmo The cosmological model.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_entropy(
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_internal_energy(const struct part* restrict p,
+                                   const struct cosmology* cosmo) {
+
+  return cosmo->a_factor_internal_energy *
+         hydro_get_comoving_internal_energy(p);
+}
+
+/**
+ * @brief Returns the comoving entropy of a particle
+ *
+ * @param p The particle of interest.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy(
     const struct part* restrict p) {
 
   if (p->primitives.rho > 0.) {
@@ -708,13 +737,27 @@ __attribute__((always_inline)) INLINE static float hydro_get_entropy(
   }
 }
 
+/**
+ * @brief Returns the physical internal energy of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy(
+    const struct part* restrict p, const struct cosmology* cosmo) {
+
+  /* Note: no cosmological conversion required here with our choice of
+   * coordinates. */
+  return hydro_get_comoving_entropy(p);
+}
+
 /**
  * @brief Returns the sound speed of a particle
  *
  * @param p The particle of interest.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
-    const struct part* restrict p) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_soundspeed(const struct part* restrict p) {
 
   if (p->primitives.rho > 0.)
     return gas_soundspeed_from_pressure(p->primitives.rho, p->primitives.P);
@@ -723,16 +766,41 @@ __attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
 }
 
 /**
- * @brief Returns the pressure of a particle
+ * @brief Returns the physical sound speed of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_soundspeed(const struct part* restrict p,
+                              const struct cosmology* cosmo) {
+
+  return cosmo->a_factor_sound_speed * hydro_get_comoving_soundspeed(p);
+}
+
+/**
+ * @brief Returns the comoving pressure of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_pressure(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure(
     const struct part* restrict p) {
 
   return p->primitives.P;
 }
 
+/**
+ * @brief Returns the comoving pressure of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure(
+    const struct part* restrict p, const struct cosmology* cosmo) {
+
+  return cosmo->a_factor_pressure * p->primitives.P;
+}
+
 /**
  * @brief Returns the mass of a particle
  *
@@ -749,38 +817,56 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
  *
  * @param p The particle of interest
  * @param xp The extended data of the particle.
- * @param dt The time since the last kick.
+ * @param dt_kick_hydro The time (for hydro accelerations) since the last kick.
+ * @param dt_kick_grav The time (for gravity accelerations) since the last kick.
  * @param v (return) The velocities at the current time.
  */
 __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities(
-    const struct part* restrict p, const struct xpart* xp, float dt,
-    float v[3]) {
+    const struct part* restrict p, const struct xpart* xp, float dt_kick_hydro,
+    float dt_kick_grav, float v[3]) {
 
   if (p->conserved.mass > 0.) {
     v[0] = p->primitives.v[0] +
-           p->conserved.flux.momentum[0] * dt / p->conserved.mass;
+           p->conserved.flux.momentum[0] * dt_kick_hydro / p->conserved.mass;
     v[1] = p->primitives.v[1] +
-           p->conserved.flux.momentum[1] * dt / p->conserved.mass;
+           p->conserved.flux.momentum[1] * dt_kick_hydro / p->conserved.mass;
     v[2] = p->primitives.v[2] +
-           p->conserved.flux.momentum[2] * dt / p->conserved.mass;
+           p->conserved.flux.momentum[2] * dt_kick_hydro / p->conserved.mass;
   } else {
     v[0] = p->primitives.v[0];
     v[1] = p->primitives.v[1];
     v[2] = p->primitives.v[2];
   }
+
+  // MATTHIEU: Bert is this correct?
+  v[0] += xp->a_grav[0] * dt_kick_grav;
+  v[1] += xp->a_grav[1] * dt_kick_grav;
+  v[2] += xp->a_grav[2] * dt_kick_grav;
 }
 
 /**
- * @brief Returns the density of a particle
+ * @brief Returns the comoving density of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_density(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_density(
     const struct part* restrict p) {
 
   return p->primitives.rho;
 }
 
+/**
+ * @brief Returns the physical density of a particle
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_density(
+    const struct part* restrict p, const struct cosmology* cosmo) {
+
+  return cosmo->a3_inv * p->primitives.rho;
+}
+
 /**
  * @brief Modifies the thermal state of a particle to the imposed internal
  * energy
diff --git a/src/hydro/Gizmo/hydro_gradients.h b/src/hydro/Gizmo/hydro_gradients.h
index 46cafcc31ef80cef468a915fdfdaf9b1625807ab..cd53c1dfce670abe58e2aa108f28b1146b3f1013 100644
--- a/src/hydro/Gizmo/hydro_gradients.h
+++ b/src/hydro/Gizmo/hydro_gradients.h
@@ -45,7 +45,7 @@
  * @param p Particle.
  */
 __attribute__((always_inline)) INLINE static void hydro_gradients_init(
-    struct part* p) {}
+    struct part *p) {}
 
 /**
  * @brief Gradient calculations done during the neighbour loop
@@ -58,8 +58,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_init(
  * @param pj Particle j.
  */
 __attribute__((always_inline)) INLINE static void hydro_gradients_collect(
-    float r2, float* dx, float hi, float hj, struct part* pi, struct part* pj) {
-}
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj) {}
 
 /**
  * @brief Gradient calculations done during the neighbour loop: non-symmetric
@@ -73,8 +73,9 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect(
  * @param pj Particle j.
  */
 __attribute__((always_inline)) INLINE static void
-hydro_gradients_nonsym_collect(float r2, float* dx, float hi, float hj,
-                               struct part* pi, struct part* pj) {}
+hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj,
+                               struct part *restrict pi,
+                               struct part *restrict pj) {}
 
 /**
  * @brief Finalize the gradient variables after all data have been collected
@@ -82,7 +83,7 @@ hydro_gradients_nonsym_collect(float r2, float* dx, float hi, float hj,
  * @param p Particle.
  */
 __attribute__((always_inline)) INLINE static void hydro_gradients_finalize(
-    struct part* p) {}
+    struct part *p) {}
 
 #endif
 
@@ -91,8 +92,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize(
  * gradients_none does nothing, since all gradients are zero -- are they?).
  */
 __attribute__((always_inline)) INLINE static void hydro_gradients_predict(
-    struct part* pi, struct part* pj, float hi, float hj, float* dx, float r,
-    float* xij_i, float* Wi, float* Wj) {
+    struct part* restrict pi, struct part* restrict pj, float hi, float hj,
+    const float* dx, float r, float* xij_i, float* Wi, float* Wj) {
 
   float dWi[5], dWj[5];
   float xij_j[3];
diff --git a/src/hydro/Gizmo/hydro_gradients_gizmo.h b/src/hydro/Gizmo/hydro_gradients_gizmo.h
index 034f03c619a2815912a163f5ba7487cf0761dbbe..0140279745c8a2520479175ecf6e5e24d3fba1d6 100644
--- a/src/hydro/Gizmo/hydro_gradients_gizmo.h
+++ b/src/hydro/Gizmo/hydro_gradients_gizmo.h
@@ -62,7 +62,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_init(
  * @param pj Particle j.
  */
 __attribute__((always_inline)) INLINE static void hydro_gradients_collect(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj) {
 
   float r = sqrtf(r2);
   float xi, xj;
@@ -299,8 +300,9 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect(
  * @param pj Particle j.
  */
 __attribute__((always_inline)) INLINE static void
-hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj,
-                               struct part *pi, struct part *pj) {
+hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj,
+                               struct part *restrict pi,
+                               struct part *restrict pj) {
 
   float r = sqrtf(r2);
   float xi;
diff --git a/src/hydro/Gizmo/hydro_gradients_sph.h b/src/hydro/Gizmo/hydro_gradients_sph.h
index 56a5a88cc184d0260036c8557aacf7a3f198213f..b3e3eae5b7ca11b305085058960904a4a3877845 100644
--- a/src/hydro/Gizmo/hydro_gradients_sph.h
+++ b/src/hydro/Gizmo/hydro_gradients_sph.h
@@ -61,7 +61,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_init(
  * @param pj Particle j.
  */
 __attribute__((always_inline)) INLINE static void hydro_gradients_collect(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj) {
 
   float wi, wi_dx, xi, hi_inv;
   float wj, wj_dx, xj, hj_inv;
@@ -163,8 +164,9 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect(
  * @param pj Particle j.
  */
 __attribute__((always_inline)) INLINE static void
-hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj,
-                               struct part *pi, struct part *pj) {
+hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj,
+                               struct part *restrict pi,
+                               struct part *restrict pj) {
 
   float wi, wi_dx, xi, hi_inv;
   float r = sqrtf(r2);
diff --git a/src/hydro/Gizmo/hydro_iact.h b/src/hydro/Gizmo/hydro_iact.h
index a42c3d6a77c5d25e32c5f34cc581d8cbec1ffba9..08c2480f4722d8704c250e5089786e93a5116da4 100644
--- a/src/hydro/Gizmo/hydro_iact.h
+++ b/src/hydro/Gizmo/hydro_iact.h
@@ -37,15 +37,19 @@
  * order accurate gradient calculations and for the calculation of the interface
  * surface areas.
  *
- * @param r2 Squared distance between particle i and particle j.
- * @param dx Distance vector between the particles (dx = pi->x - pj->x).
- * @param hi Smoothing length of particle i.
- * @param hj Smoothing length of particle j.
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
  * @param pi Particle i.
  * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_density(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float r = sqrtf(r2);
   float xi, xj;
@@ -99,15 +103,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
  * order accurate gradient calculations and for the calculation of the interface
  * surface areas.
  *
- * @param r2 Squared distance between particle i and particle j.
- * @param dx Distance vector between the particles (dx = pi->x - pj->x).
- * @param hi Smoothing length of particle i.
- * @param hj Smoothing length of particle j.
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
  * @param pi Particle i.
  * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float r;
   float xi;
@@ -141,15 +149,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
  * This method wraps around hydro_gradients_collect, which can be an empty
  * method, in which case no gradients are used.
  *
- * @param r2 Squared distance between particle i and particle j.
- * @param dx Distance vector between the particles (dx = pi->x - pj->x).
- * @param hi Smoothing length of particle i.
- * @param hj Smoothing length of particle j.
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
  * @param pi Particle i.
  * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_gradient(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   hydro_gradients_collect(r2, dx, hi, hj, pi, pj);
 }
@@ -161,15 +173,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_gradient(
  * This method wraps around hydro_gradients_nonsym_collect, which can be an
  * empty method, in which case no gradients are used.
  *
- * @param r2 Squared distance between particle i and particle j.
- * @param dx Distance vector between the particles (dx = pi->x - pj->x).
- * @param hi Smoothing length of particle i.
- * @param hj Smoothing length of particle j.
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
  * @param pi Particle i.
  * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   hydro_gradients_nonsym_collect(r2, dx, hi, hj, pi, pj);
 }
@@ -192,16 +208,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient(
  * This method also calculates the maximal velocity used to calculate the time
  * step.
  *
- * @param r2 Squared distance between particle i and particle j.
- * @param dx Distance vector between the particles (dx = pi->x - pj->x).
- * @param hi Smoothing length of particle i.
- * @param hj Smoothing length of particle j.
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
  * @param pi Particle i.
  * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj,
-    int mode) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, int mode, float a, float H) {
 
   float r = sqrtf(r2);
   float xi, xj;
@@ -457,17 +476,21 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common(
  *
  * This method calls runner_iact_fluxes_common with mode 1.
  *
- * @param r2 Squared distance between particle i and particle j.
- * @param dx Distance vector between the particles (dx = pi->x - pj->x).
- * @param hi Smoothing length of particle i.
- * @param hj Smoothing length of particle j.
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
  * @param pi Particle i.
  * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_force(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
-  runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1);
+  runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1, a, H);
 }
 
 /**
@@ -476,17 +499,21 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
  *
  * This method calls runner_iact_fluxes_common with mode 0.
  *
- * @param r2 Squared distance between particle i and particle j.
- * @param dx Distance vector between the particles (dx = pi->x - pj->x).
- * @param hi Smoothing length of particle i.
- * @param hj Smoothing length of particle j.
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
  * @param pi Particle i.
  * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
-  runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0);
+  runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H);
 }
 
 #endif /* SWIFT_GIZMO_HYDRO_IACT_H */
diff --git a/src/hydro/Gizmo/hydro_io.h b/src/hydro/Gizmo/hydro_io.h
index aa26316d54c003c2fbd1fda7d05eadfb222c5fc2..b8e2e30646c3aafb73d387010ab7ea0b0a663a77 100644
--- a/src/hydro/Gizmo/hydro_io.h
+++ b/src/hydro/Gizmo/hydro_io.h
@@ -74,7 +74,7 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
  */
 void convert_u(const struct engine* e, const struct part* p, float* ret) {
 
-  ret[0] = hydro_get_internal_energy(p);
+  ret[0] = hydro_get_comoving_internal_energy(p);
 }
 
 /**
@@ -85,7 +85,7 @@ void convert_u(const struct engine* e, const struct part* p, float* ret) {
  * @param ret (return) Entropic function of the particle
  */
 void convert_A(const struct engine* e, const struct part* p, float* ret) {
-  ret[0] = hydro_get_entropy(p);
+  ret[0] = hydro_get_comoving_entropy(p);
 }
 
 /**
diff --git a/src/hydro/Gizmo/hydro_part.h b/src/hydro/Gizmo/hydro_part.h
index fdd73dd196465d7257555dcb2529935eec3fe3df..d5bc3f84238fecbf3b2f120f031996f55bbd65fe 100644
--- a/src/hydro/Gizmo/hydro_part.h
+++ b/src/hydro/Gizmo/hydro_part.h
@@ -34,6 +34,9 @@ struct xpart {
   /* Velocity at the last full step. */
   float v_full[3];
 
+  /* Gravitational acceleration at the last full step. */
+  float a_grav[3];
+
   /* Additional data used to record cooling information */
   struct cooling_xpart_data cooling_data;
 
diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h
index 935b5d96843c5ed13b167ad1152c96b5ced647bd..97cd5ef577dcfd7b07c5183a92349313096a6412 100644
--- a/src/hydro/Minimal/hydro.h
+++ b/src/hydro/Minimal/hydro.h
@@ -35,6 +35,7 @@
 
 #include "adiabatic_index.h"
 #include "approx_math.h"
+#include "cosmology.h"
 #include "dimension.h"
 #include "equation_of_state.h"
 #include "hydro_properties.h"
@@ -43,7 +44,7 @@
 #include "minmax.h"
 
 /**
- * @brief Returns the internal energy of a particle
+ * @brief Returns the comoving internal energy of a particle
  *
  * For implementations where the main thermodynamic variable
  * is not internal energy, this function computes the internal
@@ -51,25 +52,61 @@
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
-    const struct part *restrict p) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_internal_energy(const struct part *restrict p) {
 
   return p->u;
 }
 
 /**
- * @brief Returns the pressure of a particle
+ * @brief Returns the physical internal energy of a particle
+ *
+ * For implementations where the main thermodynamic variable
+ * is not internal energy, this function computes the internal
+ * energy from the thermodynamic variable and converts it to
+ * physical coordinates.
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_internal_energy(const struct part *restrict p,
+                                   const struct cosmology *cosmo) {
+
+  return p->u * cosmo->a_factor_internal_energy;
+}
+
+/**
+ * @brief Returns the comoving pressure of a particle
+ *
+ * Computes the pressure based on the particle's properties.
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_pressure(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure(
     const struct part *restrict p) {
 
   return gas_pressure_from_internal_energy(p->rho, p->u);
 }
 
 /**
- * @brief Returns the entropy of a particle
+ * @brief Returns the physical pressure of a particle
+ *
+ * Computes the pressure based on the particle's properties and
+ * convert it to physical coordinates.
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return cosmo->a_factor_pressure *
+         gas_pressure_from_internal_energy(p->rho, p->u);
+}
+
+/**
+ * @brief Returns the comoving entropy of a particle
  *
  * For implementations where the main thermodynamic variable
  * is not entropy, this function computes the entropy from
@@ -77,34 +114,78 @@ __attribute__((always_inline)) INLINE static float hydro_get_pressure(
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_entropy(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy(
     const struct part *restrict p) {
 
   return gas_entropy_from_internal_energy(p->rho, p->u);
 }
 
 /**
- * @brief Returns the sound speed of a particle
+ * @brief Returns the physical entropy of a particle
+ *
+ * For implementations where the main thermodynamic variable
+ * is not entropy, this function computes the entropy from
+ * the thermodynamic variable and converts it to
+ * physical coordinates.
  *
  * @param p The particle of interest
+ * @param cosmo The cosmological model.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
-    const struct part *restrict p) {
+__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  /* Note: no cosmological conversion required here with our choice of
+   * coordinates. */
+  return gas_entropy_from_internal_energy(p->rho, p->u);
+}
+
+/**
+ * @brief Returns the comoving sound speed of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_soundspeed(const struct part *restrict p) {
 
   return p->force.soundspeed;
 }
 
 /**
- * @brief Returns the density of a particle
+ * @brief Returns the physical sound speed of a particle
  *
  * @param p The particle of interest
+ * @param cosmo The cosmological model.
  */
-__attribute__((always_inline)) INLINE static float hydro_get_density(
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_soundspeed(const struct part *restrict p,
+                              const struct cosmology *cosmo) {
+
+  return cosmo->a_factor_sound_speed * p->force.soundspeed;
+}
+
+/**
+ * @brief Returns the comoving density of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_density(
     const struct part *restrict p) {
 
   return p->rho;
 }
 
+/**
+ * @brief Returns the comoving density of a particle.
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_density(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return cosmo->a3_inv * p->rho;
+}
+
 /**
  * @brief Returns the mass of a particle
  *
@@ -121,16 +202,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
  *
  * @param p The particle of interest
  * @param xp The extended data of the particle.
- * @param dt The time since the last kick.
+ * @param dt_kick_hydro The time (for hydro accelerations) since the last kick.
+ * @param dt_kick_grav The time (for gravity accelerations) since the last kick.
  * @param v (return) The velocities at the current time.
  */
 __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities(
-    const struct part *restrict p, const struct xpart *xp, float dt,
-    float v[3]) {
-
-  v[0] = xp->v_full[0] + p->a_hydro[0] * dt;
-  v[1] = xp->v_full[1] + p->a_hydro[1] * dt;
-  v[2] = xp->v_full[2] + p->a_hydro[2] * dt;
+    const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro,
+    float dt_kick_grav, float v[3]) {
+
+  v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro +
+         xp->a_grav[0] * dt_kick_grav;
+  v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro +
+         xp->a_grav[1] * dt_kick_grav;
+  v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro +
+         xp->a_grav[2] * dt_kick_grav;
 }
 
 /**
@@ -168,17 +253,18 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt(
  * @param p Pointer to the particle data
  * @param xp Pointer to the extended particle data
  * @param hydro_properties The SPH parameters
- *
+ * @param cosmo The cosmological model.
  */
 __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 struct hydro_props *restrict hydro_properties,
+    const struct cosmology *restrict cosmo) {
 
   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;
+  const float dt_cfl = 2.f * kernel_gamma * CFL_condition * cosmo->a * p->h /
+                       (cosmo->a_factor_sound_speed * p->force.v_sig);
 
   return dt_cfl;
 }
@@ -218,13 +304,15 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
  * Multiplies the density and number of neighbours by the appropiate constants
  * and add the self-contribution term.
  * Additional quantities such as velocity gradients will also get the final
- *terms
- * added to them here.
+ * terms added to them here.
+ *
+ * Also adds/multiplies the cosmological terms if need be.
  *
  * @param p The particle to act upon
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_density(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -248,11 +336,17 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
 /**
  * @brief Sets all particle fields to sensible values when the #part has 0 ngbs.
  *
+ * In the desperate case where a particle has no neighbours (likely because
+ * of the h_max ceiling), set the particle fields to something sensible to avoid
+ * NaNs in the next calculations.
+ *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
+ * @param cosmo The cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -278,9 +372,11 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
  *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_prepare_force(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
   /* Compute the pressure */
   const float pressure = gas_pressure_from_internal_energy(p->rho, p->u);
@@ -346,17 +442,22 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
  * Additional hydrodynamic quantites are drifted forward in time here. These
  * include thermal quantities (thermal energy or total energy or entropy, ...).
  *
+ * Note the different time-step sizes used for the different quantities as they
+ * include cosmological factors.
+ *
  * @param p The particle.
  * @param xp The extended data of the particle.
- * @param dt The drift time-step.
+ * @param dt_drift The drift time-step for positions.
+ * @param dt_therm The drift time-step for thermal quantities.
  */
 __attribute__((always_inline)) INLINE static void hydro_predict_extra(
-    struct part *restrict p, const struct xpart *restrict xp, float dt) {
+    struct part *restrict p, const struct xpart *restrict xp, float dt_drift,
+    float dt_therm) {
 
   const float h_inv = 1.f / p->h;
 
   /* Predict smoothing length */
-  const float w1 = p->force.h_dt * h_inv * dt;
+  const float w1 = p->force.h_dt * h_inv * dt_drift;
   if (fabsf(w1) < 0.2f)
     p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */
   else
@@ -370,7 +471,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
     p->rho *= expf(w2);
 
   /* Predict the internal energy */
-  p->u += p->u_dt * dt;
+  p->u += p->u_dt * dt_therm;
 
   /* Compute the new pressure */
   const float pressure = gas_pressure_from_internal_energy(p->rho, p->u);
@@ -386,13 +487,16 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
  * @brief Finishes the force calculation.
  *
  * Multiplies the force and accelerations by the appropiate constants
- * and add the self-contribution term. In most cases, there is nothing
+ * and add the self-contribution term. In most cases, there is little
  * to do here.
  *
+ * Cosmological terms are also added/multiplied here.
+ *
  * @param p The particle to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_force(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
 
   p->force.h_dt *= p->h * hydro_dimension_inv;
 }
@@ -403,18 +507,18 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  * Additional hydrodynamic quantites are kicked forward in time here. These
  * include thermal quantities (thermal energy or total energy or entropy, ...).
  *
- * @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 p The particle to act upon.
+ * @param xp The particle extended data to act upon.
+ * @param dt_therm The time-step for this kick (for thermodynamic quantities).
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt) {
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {
 
   /* Do not decrease the energy by more than a factor of 2*/
-  if (dt > 0. && p->u_dt * dt < -0.5f * xp->u_full) {
-    p->u_dt = -0.5f * xp->u_full / dt;
+  if (dt_therm > 0. && p->u_dt * dt_therm < -0.5f * xp->u_full) {
+    p->u_dt = -0.5f * xp->u_full / dt_therm;
   }
-  xp->u_full += p->u_dt * dt;
+  xp->u_full += p->u_dt * dt_therm;
 
   /* Compute the pressure */
   const float pressure = gas_pressure_from_internal_energy(p->rho, xp->u_full);
@@ -467,6 +571,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   xp->v_full[0] = p->v[0];
   xp->v_full[1] = p->v[1];
   xp->v_full[2] = p->v[2];
+  xp->a_grav[0] = 0.f;
+  xp->a_grav[1] = 0.f;
+  xp->a_grav[2] = 0.f;
   xp->u_full = p->u;
 
   hydro_reset_acceleration(p);
diff --git a/src/hydro/Minimal/hydro_debug.h b/src/hydro/Minimal/hydro_debug.h
index 876ce148824489d4c43358c2c519aa3b90dcf002..541029ee06dd2799443fc89b688d7baca3fae0f8 100644
--- a/src/hydro/Minimal/hydro_debug.h
+++ b/src/hydro/Minimal/hydro_debug.h
@@ -43,8 +43,9 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle(
       "time_bin=%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->u, p->u_dt, p->force.v_sig, p->force.pressure, p->h, p->force.h_dt,
-      (int)p->density.wcount, p->mass, p->density.rho_dh, p->rho, p->time_bin);
+      p->u, p->u_dt, p->force.v_sig, hydro_get_comoving_pressure(p), p->h,
+      p->force.h_dt, (int)p->density.wcount, p->mass, p->density.rho_dh, p->rho,
+      p->time_bin);
 }
 
 #endif /* SWIFT_MINIMAL_HYDRO_DEBUG_H */
diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h
index 0d4db1123d23e59146a2b026700c7b44a9e99f0c..bfd8f1dff5febbd14b8a1e3a1cb8c01d49bc85ba 100644
--- a/src/hydro/Minimal/hydro_iact.h
+++ b/src/hydro/Minimal/hydro_iact.h
@@ -36,10 +36,20 @@
 #include "minmax.h"
 
 /**
- * @brief Density loop
+ * @brief Density interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_density(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float wi, wj, wi_dx, wj_dx;
 
@@ -71,10 +81,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
 }
 
 /**
- * @brief Density loop (non-symmetric version)
+ * @brief Density interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float wi, wi_dx;
 
@@ -95,12 +115,24 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
 }
 
 /**
- * @brief Force loop
+ * @brief Force interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_force(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
 
   const float r = sqrtf(r2);
   const float r_inv = 1.0f / r;
@@ -136,7 +168,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   /* 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];
+                     (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
 
   /* Are the particles moving towards each others ? */
   const float omega_ij = min(dvdr, 0.f);
@@ -195,12 +227,24 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
 }
 
 /**
- * @brief Force loop (non-symmetric version)
+ * @brief Force interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
 
   const float r = sqrtf(r2);
   const float r_inv = 1.0f / r;
@@ -236,7 +280,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   /* 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];
+                     (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
 
   /* Are the particles moving towards each others ? */
   const float omega_ij = min(dvdr, 0.f);
diff --git a/src/hydro/Minimal/hydro_io.h b/src/hydro/Minimal/hydro_io.h
index d30d1e6ce6ecc00f5c370239e966ab1391055c3b..5922834e12f6dd74e951b46c2c93f975d7e8b82e 100644
--- a/src/hydro/Minimal/hydro_io.h
+++ b/src/hydro/Minimal/hydro_io.h
@@ -71,12 +71,12 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
 
 void convert_S(const struct engine* e, const struct part* p, float* ret) {
 
-  ret[0] = hydro_get_entropy(p);
+  ret[0] = hydro_get_comoving_entropy(p);
 }
 
 void convert_P(const struct engine* e, const struct part* p, float* ret) {
 
-  ret[0] = hydro_get_pressure(p);
+  ret[0] = hydro_get_comoving_pressure(p);
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
diff --git a/src/hydro/Minimal/hydro_part.h b/src/hydro/Minimal/hydro_part.h
index 7556f415b9a3fb03923c98352322a9922f078f9a..c33f1b9a214cf9839f1acb965b686d4a4962865c 100644
--- a/src/hydro/Minimal/hydro_part.h
+++ b/src/hydro/Minimal/hydro_part.h
@@ -53,6 +53,9 @@ struct xpart {
   /*! Velocity at the last full step. */
   float v_full[3];
 
+  /*! Gravitational acceleration at the last full step. */
+  float a_grav[3];
+
   /*! Internal energy at the last full step. */
   float u_full;
 
diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h
index 2c10e4fde8865c5afa228fbb92a79dfa5aa55a87..37de855b375a5ac11f8a33f3993f7d2101c58522 100644
--- a/src/hydro/PressureEntropy/hydro.h
+++ b/src/hydro/PressureEntropy/hydro.h
@@ -33,6 +33,7 @@
 
 #include "adiabatic_index.h"
 #include "approx_math.h"
+#include "cosmology.h"
 #include "dimension.h"
 #include "equation_of_state.h"
 #include "hydro_properties.h"
@@ -41,60 +42,123 @@
 #include "minmax.h"
 
 /**
- * @brief Returns the internal energy of a particle
+ * @brief Returns the comoving internal energy of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
-    const struct part *restrict p) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_internal_energy(const struct part *restrict p) {
 
   return gas_internal_energy_from_entropy(p->rho_bar, p->entropy);
 }
 
 /**
- * @brief Returns the pressure of a particle
+ * @brief Returns the physical internal energy of a particle
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_internal_energy(const struct part *restrict p,
+                                   const struct cosmology *cosmo) {
+
+  return gas_internal_energy_from_entropy(p->rho_bar * cosmo->a3_inv,
+                                          p->entropy);
+}
+
+/**
+ * @brief Returns the comoving pressure of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_pressure(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure(
     const struct part *restrict p) {
 
   return gas_pressure_from_entropy(p->rho_bar, p->entropy);
 }
 
 /**
- * @brief Returns the entropy of a particle
+ * @brief Returns the physical pressure of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_entropy(
+__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return gas_pressure_from_entropy(p->rho_bar * cosmo->a3_inv, p->entropy);
+}
+
+/**
+ * @brief Returns the comoving entropy of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy(
     const struct part *restrict p) {
 
   return p->entropy;
 }
 
 /**
- * @brief Returns the sound speed of a particle
+ * @brief Returns the physical entropy of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  /* Note: no cosmological conversion required here with our choice of
+   * coordinates. */
+  return p->entropy;
+}
+
+/**
+ * @brief Returns the comoving sound speed of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
-    const struct part *restrict p) {
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_soundspeed(const struct part *restrict p) {
 
   return p->force.soundspeed;
 }
 
 /**
- * @brief Returns the physical density of a particle
+ * @brief Returns the physical sound speed of a particle
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_soundspeed(const struct part *restrict p,
+                              const struct cosmology *cosmo) {
+
+  return cosmo->a_factor_sound_speed * p->force.soundspeed;
+}
+
+/**
+ * @brief Returns the comoving density of a particle
  *
  * @param p The particle of interest
  */
-__attribute__((always_inline)) INLINE static float hydro_get_density(
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_density(
     const struct part *restrict p) {
 
   return p->rho;
 }
 
+/**
+ * @brief Returns the physical density of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_density(
+    const struct part *restrict p, const struct cosmology *cosmo) {
+
+  return p->rho * cosmo->a3_inv;
+}
+
 /**
  * @brief Returns the mass of a particle
  *
@@ -111,16 +175,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass(
  *
  * @param p The particle of interest
  * @param xp The extended data of the particle.
- * @param dt The time since the last kick.
+ * @param dt_kick_hydro The time (for hydro accelerations) since the last kick.
+ * @param dt_kick_grav The time (for gravity accelerations) since the last kick.
  * @param v (return) The velocities at the current time.
  */
 __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities(
-    const struct part *restrict p, const struct xpart *xp, float dt,
-    float v[3]) {
-
-  v[0] = xp->v_full[0] + p->a_hydro[0] * dt;
-  v[1] = xp->v_full[1] + p->a_hydro[1] * dt;
-  v[2] = xp->v_full[2] + p->a_hydro[2] * dt;
+    const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro,
+    float dt_kick_grav, float v[3]) {
+
+  v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro +
+         xp->a_grav[0] * dt_kick_grav;
+  v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro +
+         xp->a_grav[1] * dt_kick_grav;
+  v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro +
+         xp->a_grav[2] * dt_kick_grav;
 }
 
 /**
@@ -153,19 +221,21 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt(
 /**
  * @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
- *
+ * @param p Pointer to the particle data.
+ * @param xp Pointer to the extended particle data.
+ * @param hydro_properties The constants used in the scheme.
+ * @param cosmo The current cosmological model.
  */
 __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 struct hydro_props *restrict hydro_properties,
+    const struct cosmology *restrict cosmo) {
 
-  const float CFL_condition = hydro_properties->CFL_condition;
+  const float CFL = hydro_properties->CFL_condition;
 
   /* CFL condition */
-  const float dt_cfl =
-      2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig;
+  const float dt_cfl = 2.f * kernel_gamma * CFL * cosmo->a * p->h /
+                       (cosmo->a_factor_sound_speed * p->force.v_sig);
 
   return dt_cfl;
 }
@@ -212,9 +282,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
  * and add the self-contribution term.
  *
  * @param p The particle to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_density(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -240,15 +311,16 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
   p->density.wcount_dh *= h_inv_dim_plus_one;
 
   const float rho_inv = 1.f / p->rho;
+  const float a_inv2 = cosmo->a2_inv;
   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;
+  p->density.rot_v[0] *= h_inv_dim_plus_one * a_inv2 * rho_inv;
+  p->density.rot_v[1] *= h_inv_dim_plus_one * a_inv2 * rho_inv;
+  p->density.rot_v[2] *= h_inv_dim_plus_one * a_inv2 * rho_inv;
 
   /* Finish calculation of the velocity divergence */
   p->density.div_v *= h_inv_dim_plus_one * rho_inv;
@@ -259,9 +331,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
  *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
   /* Some smoothing length multiples. */
   const float h = p->h;
@@ -288,11 +362,13 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
  *
  * @param p The particle to act upon
  * @param xp The extended particle data to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_prepare_force(
-    struct part *restrict p, struct xpart *restrict xp) {
+    struct part *restrict p, struct xpart *restrict xp,
+    const struct cosmology *cosmo) {
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  const float fac_mu = cosmo->a_factor_mu;
 
   /* Compute the norm of the curl */
   const float curl_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] +
@@ -310,7 +386,7 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force(
 
   /* Compute the Balsara switch */
   const float balsara =
-      abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed / fac_mu / p->h);
+      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;
@@ -380,15 +456,17 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
  *
  * @param p The particle
  * @param xp The extended data of the particle
- * @param dt The drift time-step.
+ * @param dt_drift The drift time-step for positions.
+ * @param dt_therm The drift time-step for thermal quantities.
  */
 __attribute__((always_inline)) INLINE static void hydro_predict_extra(
-    struct part *restrict p, const struct xpart *restrict xp, float dt) {
+    struct part *restrict p, const struct xpart *restrict xp, float dt_drift,
+    float dt_therm) {
 
   const float h_inv = 1.f / p->h;
 
   /* Predict smoothing length */
-  const float w1 = p->force.h_dt * h_inv * dt;
+  const float w1 = p->force.h_dt * h_inv * dt_drift;
   if (fabsf(w1) < 0.2f)
     p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */
   else
@@ -405,7 +483,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
   }
 
   /* Predict the entropy */
-  p->entropy += p->entropy_dt * dt;
+  p->entropy += p->entropy_dt * dt_therm;
 
   /* Compute the pressure */
   const float pressure = gas_pressure_from_entropy(p->rho_bar, p->entropy);
@@ -429,14 +507,15 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
  * Multiplies the forces and accelerationsby the appropiate constants
  *
  * @param p The particle to act upon
+ * @param cosmo The current cosmological model.
  */
 __attribute__((always_inline)) INLINE static void hydro_end_force(
-    struct part *restrict p) {
+    struct part *restrict p, const struct cosmology *cosmo) {
 
   p->force.h_dt *= p->h * hydro_dimension_inv;
 
-  p->entropy_dt =
-      0.5f * gas_entropy_from_internal_energy(p->rho_bar, p->entropy_dt);
+  p->entropy_dt = 0.5f * cosmo->a2_inv *
+                  gas_entropy_from_internal_energy(p->rho_bar, p->entropy_dt);
 }
 
 /**
@@ -444,17 +523,16 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
  *
  * @param p The particle to act upon
  * @param xp The particle extended data to act upon
- * @param dt The time-step for this kick
- * @param half_dt The half time-step for this kick
+ * @param dt_therm The time-step for this kick (for thermodynamic quantities)
  */
 __attribute__((always_inline)) INLINE static void hydro_kick_extra(
-    struct part *restrict p, struct xpart *restrict xp, float dt) {
+    struct part *restrict p, struct xpart *restrict xp, float dt_therm) {
 
   /* Do not decrease the entropy (temperature) by more than a factor of 2*/
-  if (dt > 0. && p->entropy_dt * dt < -0.5f * xp->entropy_full) {
-    p->entropy_dt = -0.5f * xp->entropy_full / dt;
+  if (dt_therm > 0. && p->entropy_dt * dt_therm < -0.5f * xp->entropy_full) {
+    p->entropy_dt = -0.5f * xp->entropy_full / dt_therm;
   }
-  xp->entropy_full += p->entropy_dt * dt;
+  xp->entropy_full += p->entropy_dt * dt_therm;
 
   /* Compute the pressure */
   const float pressure =
@@ -519,6 +597,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part(
   xp->v_full[0] = p->v[0];
   xp->v_full[1] = p->v[1];
   xp->v_full[2] = p->v[2];
+  xp->a_grav[0] = 0.f;
+  xp->a_grav[1] = 0.f;
+  xp->a_grav[2] = 0.f;
 
   hydro_reset_acceleration(p);
   hydro_init_part(p, NULL);
diff --git a/src/hydro/PressureEntropy/hydro_debug.h b/src/hydro/PressureEntropy/hydro_debug.h
index 3a0a315a4fa0eb4710042e8020002691ed9c425a..14d69bb650ff1bbd49394c0ca2f6256ad0cb188d 100644
--- a/src/hydro/PressureEntropy/hydro_debug.h
+++ b/src/hydro/PressureEntropy/hydro_debug.h
@@ -40,10 +40,10 @@ __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->h, p->density.wcount, p->density.wcount_dh, p->mass, p->density.rho_dh,
-      p->rho, p->rho_bar, hydro_get_pressure(p), 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->time_bin);
+      p->rho, p->rho_bar, hydro_get_comoving_pressure(p),
+      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->time_bin);
 }
 
 #endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_DEBUG_H */
diff --git a/src/hydro/PressureEntropy/hydro_iact.h b/src/hydro/PressureEntropy/hydro_iact.h
index 171f7911a31b53fce74713e6d7e244bc79c59828..c9e3c4ec7728df8a8e7d59b8c21f22bd613463d8 100644
--- a/src/hydro/PressureEntropy/hydro_iact.h
+++ b/src/hydro/PressureEntropy/hydro_iact.h
@@ -21,7 +21,7 @@
 
 /**
  * @file PressureEntropy/hydro_iact.h
- * @brief Pressure-Entropy implementation of SPH (Neighbour loop equations)
+ * @brief Pressure-Entropy implementation of SPH (Particle interactions)
  *
  * The thermal variable is the entropy (S) and the entropy is smoothed over
  * contact discontinuities to prevent spurious surface tension.
@@ -31,10 +31,20 @@
  */
 
 /**
- * @brief Density loop
+ * @brief Density interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_density(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float wi, wi_dx;
   float wj, wj_dx;
@@ -111,10 +121,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density(
 }
 
 /**
- * @brief Density loop (non-symmetric version)
+ * @brief Density interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float wi, wi_dx;
   float dv[3], curlvr[3];
@@ -164,14 +184,26 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
 }
 
 /**
- * @brief Force loop
+ * @brief Force interaction between two particles.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void runner_iact_force(
-    float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) {
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
 
   float wi, wj, wi_dx, wj_dx;
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
 
   const float r = sqrtf(r2);
   const float r_inv = 1.0f / r;
@@ -215,7 +247,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
   /* 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];
+                     (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
 
   /* Balsara term */
   const float balsara_i = pi->force.balsara;
@@ -265,14 +297,26 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
 }
 
 /**
- * @brief Force loop (non-symmetric version)
+ * @brief Force interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi First particle.
+ * @param pj Second particle (not updated).
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
  */
 __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 r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
 
   float wi, wj, wi_dx, wj_dx;
 
-  const float fac_mu = 1.f; /* Will change with cosmological integration */
+  /* Cosmological factors entering the EoMs */
+  const float fac_mu = pow_three_gamma_minus_five_over_two(a);
+  const float a2_Hubble = a * a * H;
 
   const float r = sqrtf(r2);
   const float r_inv = 1.0f / r;
@@ -316,7 +360,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   /* 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];
+                     (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2;
 
   /* Balsara term */
   const float balsara_i = pi->force.balsara;
diff --git a/src/hydro/PressureEntropy/hydro_io.h b/src/hydro/PressureEntropy/hydro_io.h
index 3c06f60408c62b50964377917600c869652f3576..454d999b6dcd604e25da4c513d902854c43c781b 100644
--- a/src/hydro/PressureEntropy/hydro_io.h
+++ b/src/hydro/PressureEntropy/hydro_io.h
@@ -69,12 +69,12 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
 
 void convert_u(const struct engine* e, const struct part* p, float* ret) {
 
-  ret[0] = hydro_get_internal_energy(p);
+  ret[0] = hydro_get_comoving_internal_energy(p);
 }
 
 void convert_P(const struct engine* e, const struct part* p, float* ret) {
 
-  ret[0] = hydro_get_pressure(p);
+  ret[0] = hydro_get_comoving_pressure(p);
 }
 
 void convert_part_pos(const struct engine* e, const struct part* p,
diff --git a/src/hydro/PressureEntropy/hydro_part.h b/src/hydro/PressureEntropy/hydro_part.h
index c9482cd1ace7c53863885155cbca1afc6dddeb5f..fb8424d66196b7013866acef6bec6ec9889a3353 100644
--- a/src/hydro/PressureEntropy/hydro_part.h
+++ b/src/hydro/PressureEntropy/hydro_part.h
@@ -45,6 +45,9 @@ struct xpart {
   /*! Velocity at the last full step. */
   float v_full[3];
 
+  /*! Gravitational acceleration at the last full step. */
+  float a_grav[3];
+
   /*! Entropy at the last full step. */
   float entropy_full;
 
diff --git a/src/kick.h b/src/kick.h
index 7ccea7d26974297cfebc605808c4443633140ec1..9b1f4f18112a1cb2affcff70e7773ba4c48681b5 100644
--- a/src/kick.h
+++ b/src/kick.h
@@ -32,16 +32,14 @@
  * @brief Perform the 'kick' operation on a #gpart
  *
  * @param gp The #gpart to kick.
- * @param ti_start The starting (integer) time of the kick
- * @param ti_end The ending (integer) time of the kick
- * @param timeBase The minimal allowed time-step size.
+ * @param dt_kick_grav The kick time-step for gravity accelerations.
+ * @param ti_start The starting (integer) time of the kick (for debugging
+ * checks).
+ * @param ti_end The ending (integer) time of the kick (for debugging checks).
  */
 __attribute__((always_inline)) INLINE static void kick_gpart(
-    struct gpart *restrict gp, integertime_t ti_start, integertime_t ti_end,
-    double timeBase) {
-
-  /* Time interval for this half-kick */
-  const float dt = (ti_end - ti_start) * timeBase;
+    struct gpart *restrict gp, double dt_kick_grav, integertime_t ti_start,
+    integertime_t ti_end) {
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (gp->ti_kick != ti_start)
@@ -54,12 +52,12 @@ __attribute__((always_inline)) INLINE static void kick_gpart(
 #endif
 
   /* Kick particles in momentum space */
-  gp->v_full[0] += gp->a_grav[0] * dt;
-  gp->v_full[1] += gp->a_grav[1] * dt;
-  gp->v_full[2] += gp->a_grav[2] * dt;
+  gp->v_full[0] += gp->a_grav[0] * dt_kick_grav;
+  gp->v_full[1] += gp->a_grav[1] * dt_kick_grav;
+  gp->v_full[2] += gp->a_grav[2] * dt_kick_grav;
 
   /* Kick extra variables */
-  gravity_kick_extra(gp, dt);
+  gravity_kick_extra(gp, dt_kick_grav);
 }
 
 /**
@@ -67,16 +65,17 @@ __attribute__((always_inline)) INLINE static void kick_gpart(
  *
  * @param p The #part to kick.
  * @param xp The #xpart of the particle.
- * @param ti_start The starting (integer) time of the kick
- * @param ti_end The ending (integer) time of the kick
- * @param timeBase The minimal allowed time-step size.
+ * @param dt_kick_hydro The kick time-step for hydro accelerations.
+ * @param dt_kick_grav The kick time-step for gravity accelerations.
+ * @param dt_kick_therm The kick time-step for changes in thermal state.
+ * @param ti_start The starting (integer) time of the kick (for debugging
+ * checks).
+ * @param ti_end The ending (integer) time of the kick (for debugging checks).
  */
 __attribute__((always_inline)) INLINE static void kick_part(
-    struct part *restrict p, struct xpart *restrict xp, integertime_t ti_start,
-    integertime_t ti_end, double timeBase) {
-
-  /* Time interval for this half-kick */
-  const float dt = (ti_end - ti_start) * timeBase;
+    struct part *restrict p, struct xpart *restrict xp, double dt_kick_hydro,
+    double dt_kick_grav, double dt_kick_therm, integertime_t ti_start,
+    integertime_t ti_end) {
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (p->ti_kick != ti_start)
@@ -88,18 +87,19 @@ __attribute__((always_inline)) INLINE static void kick_part(
   p->ti_kick = ti_end;
 #endif
 
-  /* Get the acceleration */
-  float a_tot[3] = {p->a_hydro[0], p->a_hydro[1], p->a_hydro[2]};
+  /* Kick particles in momentum space (hydro acc.) */
+  xp->v_full[0] += p->a_hydro[0] * dt_kick_hydro;
+  xp->v_full[1] += p->a_hydro[1] * dt_kick_hydro;
+  xp->v_full[2] += p->a_hydro[2] * dt_kick_hydro;
+
+  /* Kick particles in momentum space (grav acc.) */
   if (p->gpart != NULL) {
-    a_tot[0] += p->gpart->a_grav[0];
-    a_tot[1] += p->gpart->a_grav[1];
-    a_tot[2] += p->gpart->a_grav[2];
+    xp->v_full[0] += p->gpart->a_grav[0] * dt_kick_grav;
+    xp->v_full[1] += p->gpart->a_grav[1] * dt_kick_grav;
+    xp->v_full[2] += p->gpart->a_grav[2] * dt_kick_grav;
   }
 
-  /* Kick particles in momentum space */
-  xp->v_full[0] += a_tot[0] * dt;
-  xp->v_full[1] += a_tot[1] * dt;
-  xp->v_full[2] += a_tot[2] * dt;
+  /* Give the gpart friend the same velocity */
   if (p->gpart != NULL) {
     p->gpart->v_full[0] = xp->v_full[0];
     p->gpart->v_full[1] = xp->v_full[1];
@@ -107,24 +107,22 @@ __attribute__((always_inline)) INLINE static void kick_part(
   }
 
   /* Extra kick work */
-  hydro_kick_extra(p, xp, dt);
-  if (p->gpart != NULL) gravity_kick_extra(p->gpart, dt);
+  hydro_kick_extra(p, xp, dt_kick_therm);
+  if (p->gpart != NULL) gravity_kick_extra(p->gpart, dt_kick_grav);
 }
 
 /**
  * @brief Perform the 'kick' operation on a #spart
  *
  * @param sp The #spart to kick.
- * @param ti_start The starting (integer) time of the kick
- * @param ti_end The ending (integer) time of the kick
- * @param timeBase The minimal allowed time-step size.
+ * @param dt_kick_grav The kick time-step for gravity accelerations.
+ * @param ti_start The starting (integer) time of the kick (for debugging
+ * checks).
+ * @param ti_end The ending (integer) time of the kick (for debugging checks).
  */
 __attribute__((always_inline)) INLINE static void kick_spart(
-    struct spart *restrict sp, integertime_t ti_start, integertime_t ti_end,
-    double timeBase) {
-
-  /* Time interval for this half-kick */
-  const float dt = (ti_end - ti_start) * timeBase;
+    struct spart *restrict sp, double dt_kick_grav, integertime_t ti_start,
+    integertime_t ti_end) {
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (sp->ti_kick != ti_start)
@@ -136,20 +134,18 @@ __attribute__((always_inline)) INLINE static void kick_spart(
   sp->ti_kick = ti_end;
 #endif
 
-  /* Acceleration from gravity */
-  const float a[3] = {sp->gpart->a_grav[0], sp->gpart->a_grav[1],
-                      sp->gpart->a_grav[2]};
-
   /* Kick particles in momentum space */
-  sp->v[0] += a[0] * dt;
-  sp->v[1] += a[1] * dt;
-  sp->v[2] += a[2] * dt;
+  sp->v[0] += sp->gpart->a_grav[0] * dt_kick_grav;
+  sp->v[1] += sp->gpart->a_grav[1] * dt_kick_grav;
+  sp->v[2] += sp->gpart->a_grav[2] * dt_kick_grav;
+
+  /* Give the gpart friend the same velocity */
   sp->gpart->v_full[0] = sp->v[0];
   sp->gpart->v_full[1] = sp->v[1];
   sp->gpart->v_full[2] = sp->v[2];
 
   /* Kick extra variables */
-  star_kick_extra(sp, dt);
+  star_kick_extra(sp, dt_kick_grav);
 }
 
 #endif /* SWIFT_KICK_H */
diff --git a/src/parallel_io.c b/src/parallel_io.c
index 315c187e65f1a30b0401cb9368944f8f9968223a..d3f5f8dc36dd63ad1b7cf4d65311751cd15f887b 100644
--- a/src/parallel_io.c
+++ b/src/parallel_io.c
@@ -870,6 +870,8 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
   io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1);
   int dimension = (int)hydro_dimension;
   io_write_attribute(h_grp, "Dimension", INT, &dimension, 1);
+  io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1);
+  io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1);
 
   /* GADGET-2 legacy values */
   /* Number of particles of each type */
@@ -899,6 +901,9 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
   /* Print the code version */
   io_write_code_description(h_file);
 
+  /* Print the run's policy */
+  io_write_engine_policy(h_file, e);
+
   /* Print the SPH parameters */
   if (e->policy & engine_policy_hydro) {
     h_grp = H5Gcreate(h_file, "/HydroScheme", H5P_DEFAULT, H5P_DEFAULT,
@@ -926,6 +931,15 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6],
     H5Gclose(h_grp);
   }
 
+  /* Print the gravity parameters */
+  if (e->policy & engine_policy_cosmology) {
+    h_grp =
+        H5Gcreate(h_file, "/Cosmology", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+    if (h_grp < 0) error("Error while creating cosmology group");
+    cosmology_write_model(h_grp, e->cosmology);
+    H5Gclose(h_grp);
+  }
+
   /* Print the runtime parameters */
   h_grp =
       H5Gcreate(h_file, "/Parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
diff --git a/src/profiler.c b/src/profiler.c
index 62ba881a15a32de63dba3cce95feab79d595aa84..1dd1a41cc336942d17790e96c8f883d65e54a51f 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -147,7 +147,7 @@ void profiler_write_timing_info(const struct engine *e, ticks time,
                                 FILE *file) {
 
   fprintf(file, "  %6d %14e %14e %10zu %10zu %10zu %21.3f\n", e->step, e->time,
-          e->timeStep, e->updates, e->g_updates, e->s_updates,
+          e->time_step, e->updates, e->g_updates, e->s_updates,
           clocks_from_ticks(time));
   fflush(file);
 }
diff --git a/src/proxy.c b/src/proxy.c
index 10df8d191db992bdd26b39cd18e950f41c4690b3..ff7d12d92f1c90e1339113fcbde20847fb902283 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -55,10 +55,10 @@ void proxy_cells_exch1(struct proxy *p) {
     p->size_pcells_out += p->cells_out[k]->pcell_size;
 
   /* Send the number of pcells. */
-  if (MPI_Isend(&p->size_pcells_out, 1, MPI_INT, p->nodeID,
-                p->mynodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD,
-                &p->req_cells_count_out) != MPI_SUCCESS)
-    error("Failed to isend nr of pcells.");
+  int err = MPI_Isend(&p->size_pcells_out, 1, MPI_INT, p->nodeID,
+                      p->mynodeID * proxy_tag_shift + proxy_tag_count,
+                      MPI_COMM_WORLD, &p->req_cells_count_out);
+  if (err != MPI_SUCCESS) mpi_error(err, "Failed to isend nr of pcells.");
   // message( "isent pcell count (%i) from node %i to node %i." ,
   // p->size_pcells_out , p->mynodeID , p->nodeID ); fflush(stdout);
 
@@ -74,19 +74,20 @@ void proxy_cells_exch1(struct proxy *p) {
   }
 
   /* Send the pcell buffer. */
-  if (MPI_Isend(p->pcells_out, sizeof(struct pcell) * p->size_pcells_out,
-                MPI_BYTE, p->nodeID,
-                p->mynodeID * proxy_tag_shift + proxy_tag_cells, MPI_COMM_WORLD,
-                &p->req_cells_out) != MPI_SUCCESS)
-    error("Failed to pcell_out buffer.");
+  err = MPI_Isend(p->pcells_out, sizeof(struct pcell) * p->size_pcells_out,
+                  MPI_BYTE, p->nodeID,
+                  p->mynodeID * proxy_tag_shift + proxy_tag_cells,
+                  MPI_COMM_WORLD, &p->req_cells_out);
+
+  if (err != MPI_SUCCESS) mpi_error(err, "Failed to pcell_out buffer.");
   // message( "isent pcells (%i) from node %i to node %i." , p->size_pcells_out
   // , p->mynodeID , p->nodeID ); fflush(stdout);
 
   /* Receive the number of pcells. */
-  if (MPI_Irecv(&p->size_pcells_in, 1, MPI_INT, p->nodeID,
-                p->nodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD,
-                &p->req_cells_count_in) != MPI_SUCCESS)
-    error("Failed to irecv nr of pcells.");
+  err = MPI_Irecv(&p->size_pcells_in, 1, MPI_INT, p->nodeID,
+                  p->nodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD,
+                  &p->req_cells_count_in);
+  if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv nr of pcells.");
 // message( "irecv pcells count on node %i from node %i." , p->mynodeID ,
 // p->nodeID ); fflush(stdout);
 
@@ -106,11 +107,12 @@ void proxy_cells_exch2(struct proxy *p) {
     error("Failed to allocate pcell_in buffer.");
 
   /* Receive the particle buffers. */
-  if (MPI_Irecv(p->pcells_in, sizeof(struct pcell) * p->size_pcells_in,
-                MPI_BYTE, p->nodeID,
-                p->nodeID * proxy_tag_shift + proxy_tag_cells, MPI_COMM_WORLD,
-                &p->req_cells_in) != MPI_SUCCESS)
-    error("Failed to irecv part data.");
+  int err = MPI_Irecv(p->pcells_in, sizeof(struct pcell) * p->size_pcells_in,
+                      MPI_BYTE, p->nodeID,
+                      p->nodeID * proxy_tag_shift + proxy_tag_cells,
+                      MPI_COMM_WORLD, &p->req_cells_in);
+
+  if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv part data.");
 // message( "irecv pcells (%i) on node %i from node %i." , p->size_pcells_in ,
 // p->mynodeID , p->nodeID ); fflush(stdout);
 
diff --git a/src/runner.c b/src/runner.c
index 0738267cf340da1039071f96f7e3d296c4169ef5..1b8f9a2fc84b08c590396f1251a6bf3c5cc3189e 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -186,14 +186,17 @@ 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 struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
   const struct cooling_function_data *cooling_func = e->cooling_func;
   const struct phys_const *constants = e->physical_constants;
   const struct unit_system *us = e->internal_units;
-  const double timeBase = e->timeBase;
+  const double time_base = e->time_base;
+  const integertime_t ti_current = e->ti_current;
+  struct part *restrict parts = c->parts;
+  struct xpart *restrict xparts = c->xparts;
+  const int count = c->count;
 
   TIMER_TIC;
 
@@ -215,9 +218,19 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) {
 
       if (part_is_active(p, e)) {
 
+        double dt_cool;
+        if (with_cosmology) {
+          const integertime_t ti_step = get_integer_timestep(p->time_bin);
+          const integertime_t ti_begin =
+              get_integer_time_begin(ti_current + 1, p->time_bin);
+          dt_cool =
+              cosmology_get_delta_time(cosmo, ti_begin, ti_begin + ti_step);
+        } else {
+          dt_cool = get_timestep(p->time_bin, time_base);
+        }
+
         /* Let's cool ! */
-        const double dt = get_timestep(p->time_bin, timeBase);
-        cooling_cool_part(constants, us, cooling_func, p, xp, dt);
+        cooling_cool_part(constants, us, cosmo, cooling_func, p, xp, dt_cool);
       }
     }
   }
@@ -641,6 +654,9 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
   struct xpart *restrict xparts = c->xparts;
   const struct engine *e = r->e;
   const struct space *s = e->s;
+  const struct hydro_space *hs = &s->hs;
+  const struct cosmology *cosmo = e->cosmology;
+  const struct chemistry_data *chemistry = e->chemistry;
   const float hydro_h_max = e->hydro_properties->h_max;
   const float eps = e->hydro_properties->h_tolerance;
   const float hydro_eta_dim =
@@ -701,8 +717,8 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
         } else {
 
           /* Finish the density calculation */
-          hydro_end_density(p);
-          chemistry_end_density(p, e->chemistry);
+          hydro_end_density(p, cosmo);
+          chemistry_end_density(p, chemistry, cosmo);
 
           /* Compute one step of the Newton-Raphson scheme */
           const float n_sum = p->density.wcount * h_old_dim;
@@ -739,11 +755,12 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
             redo += 1;
 
             /* Re-initialise everything */
-            hydro_init_part(p, &s->hs);
-            chemistry_init_part(p, e->chemistry);
+            hydro_init_part(p, hs);
+            chemistry_init_part(p, chemistry);
 
             /* Off we go ! */
             continue;
+
           } else {
 
             /* Ok, this particle is a lost cause... */
@@ -751,7 +768,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
 
             /* Do some damage control if no neighbours at all were found */
             if (p->density.wcount == kernel_root * kernel_norm)
-              hydro_part_has_no_neighbours(p, xp);
+              hydro_part_has_no_neighbours(p, xp, cosmo);
           }
         }
 
@@ -760,7 +777,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
         /* As of here, particle force variables will be set. */
 
         /* Compute variables required for the force loop */
-        hydro_prepare_force(p, xp);
+        hydro_prepare_force(p, xp, cosmo);
 
         /* The particle force values are now set.  Do _NOT_
            try to read any particle density variables! */
@@ -963,6 +980,8 @@ void runner_do_drift_gpart(struct runner *r, struct cell *c, int timer) {
 void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
   struct part *restrict parts = c->parts;
   struct xpart *restrict xparts = c->xparts;
   struct gpart *restrict gparts = c->gparts;
@@ -971,7 +990,7 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
   const int gcount = c->gcount;
   const int scount = c->scount;
   const integertime_t ti_current = e->ti_current;
-  const double timeBase = e->timeBase;
+  const double time_base = e->time_base;
 
   TIMER_TIC;
 
@@ -1009,22 +1028,31 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
               ti_end, ti_begin, ti_step, p->time_bin, ti_current);
 #endif
 
+        /* Time interval for this half-kick */
+        double dt_kick_grav, dt_kick_hydro, dt_kick_therm;
+        if (with_cosmology) {
+          dt_kick_hydro = cosmology_get_hydro_kick_factor(
+              cosmo, ti_begin, ti_begin + ti_step / 2);
+          dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_begin,
+                                                        ti_begin + ti_step / 2);
+          dt_kick_therm = cosmology_get_therm_kick_factor(
+              cosmo, ti_begin, ti_begin + ti_step / 2);
+        } else {
+          dt_kick_hydro = (ti_step / 2) * time_base;
+          dt_kick_grav = (ti_step / 2) * time_base;
+          dt_kick_therm = (ti_step / 2) * time_base;
+        }
+
         /* do the kick */
-        kick_part(p, xp, ti_begin, ti_begin + ti_step / 2, timeBase);
+        kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, ti_begin,
+                  ti_begin + ti_step / 2);
 
         /* Update the accelerations to be used in the drift for hydro */
         if (p->gpart != NULL) {
 
-          const float a_tot[3] = {p->a_hydro[0] + p->gpart->a_grav[0],
-                                  p->a_hydro[1] + p->gpart->a_grav[1],
-                                  p->a_hydro[2] + p->gpart->a_grav[2]};
-
-          p->a_hydro[0] = a_tot[0];
-          p->a_hydro[1] = a_tot[1];
-          p->a_hydro[2] = a_tot[2];
-          p->gpart->a_grav[0] = a_tot[0];
-          p->gpart->a_grav[1] = a_tot[1];
-          p->gpart->a_grav[2] = a_tot[2];
+          xp->a_grav[0] = p->gpart->a_grav[0];
+          xp->a_grav[1] = p->gpart->a_grav[1];
+          xp->a_grav[2] = p->gpart->a_grav[2];
         }
       }
     }
@@ -1053,8 +1081,17 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
               ti_end, ti_begin, ti_step, gp->time_bin, ti_current);
 #endif
 
+        /* Time interval for this half-kick */
+        double dt_kick_grav;
+        if (with_cosmology) {
+          dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_begin,
+                                                        ti_begin + ti_step / 2);
+        } else {
+          dt_kick_grav = (ti_step / 2) * time_base;
+        }
+
         /* do the kick */
-        kick_gpart(gp, ti_begin, ti_begin + ti_step / 2, timeBase);
+        kick_gpart(gp, dt_kick_grav, ti_begin, ti_begin + ti_step / 2);
       }
     }
 
@@ -1082,8 +1119,17 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
               ti_end, ti_begin, ti_step, sp->time_bin, ti_current);
 #endif
 
+        /* Time interval for this half-kick */
+        double dt_kick_grav;
+        if (with_cosmology) {
+          dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_begin,
+                                                        ti_begin + ti_step / 2);
+        } else {
+          dt_kick_grav = (ti_step / 2) * time_base;
+        }
+
         /* do the kick */
-        kick_spart(sp, ti_begin, ti_begin + ti_step / 2, timeBase);
+        kick_spart(sp, dt_kick_grav, ti_begin, ti_begin + ti_step / 2);
       }
     }
   }
@@ -1103,8 +1149,8 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) {
 void runner_do_kick2(struct runner *r, struct cell *c, int timer) {
 
   const struct engine *e = r->e;
-  const integertime_t ti_current = e->ti_current;
-  const double timeBase = e->timeBase;
+  const struct cosmology *cosmo = e->cosmology;
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
   const int count = c->count;
   const int gcount = c->gcount;
   const int scount = c->scount;
@@ -1112,6 +1158,8 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) {
   struct xpart *restrict xparts = c->xparts;
   struct gpart *restrict gparts = c->gparts;
   struct spart *restrict sparts = c->sparts;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
 
   TIMER_TIC;
 
@@ -1145,9 +1193,24 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) {
               "time_bin=%d ti_current=%lld",
               ti_begin, ti_step, p->time_bin, ti_current);
 #endif
+        /* Time interval for this half-kick */
+        double dt_kick_grav, dt_kick_hydro, dt_kick_therm;
+        if (with_cosmology) {
+          dt_kick_hydro = cosmology_get_hydro_kick_factor(
+              cosmo, ti_begin + ti_step / 2, ti_begin + ti_step);
+          dt_kick_grav = cosmology_get_grav_kick_factor(
+              cosmo, ti_begin + ti_step / 2, ti_begin + ti_step);
+          dt_kick_therm = cosmology_get_therm_kick_factor(
+              cosmo, ti_begin + ti_step / 2, ti_begin + ti_step);
+        } else {
+          dt_kick_hydro = (ti_step / 2) * time_base;
+          dt_kick_grav = (ti_step / 2) * time_base;
+          dt_kick_therm = (ti_step / 2) * time_base;
+        }
 
         /* Finish the time-step with a second half-kick */
-        kick_part(p, xp, ti_begin + ti_step / 2, ti_begin + ti_step, timeBase);
+        kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm,
+                  ti_begin + ti_step / 2, ti_begin + ti_step);
 
 #ifdef SWIFT_DEBUG_CHECKS
         /* Check that kick and the drift are synchronized */
@@ -1177,8 +1240,18 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) {
           error("Particle in wrong time-bin");
 #endif
 
+        /* Time interval for this half-kick */
+        double dt_kick_grav;
+        if (with_cosmology) {
+          dt_kick_grav = cosmology_get_grav_kick_factor(
+              cosmo, ti_begin + ti_step / 2, ti_begin + ti_step);
+        } else {
+          dt_kick_grav = (ti_step / 2) * time_base;
+        }
+
         /* Finish the time-step with a second half-kick */
-        kick_gpart(gp, ti_begin + ti_step / 2, ti_begin + ti_step, timeBase);
+        kick_gpart(gp, dt_kick_grav, ti_begin + ti_step / 2,
+                   ti_begin + ti_step);
 
 #ifdef SWIFT_DEBUG_CHECKS
         /* Check that kick and the drift are synchronized */
@@ -1209,8 +1282,18 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) {
           error("Particle in wrong time-bin");
 #endif
 
+        /* Time interval for this half-kick */
+        double dt_kick_grav;
+        if (with_cosmology) {
+          dt_kick_grav = cosmology_get_grav_kick_factor(
+              cosmo, ti_begin + ti_step / 2, ti_begin + ti_step);
+        } else {
+          dt_kick_grav = (ti_step / 2) * time_base;
+        }
+
         /* Finish the time-step with a second half-kick */
-        kick_spart(sp, ti_begin + ti_step / 2, ti_begin + ti_step, timeBase);
+        kick_spart(sp, dt_kick_grav, ti_begin + ti_step / 2,
+                   ti_begin + ti_step);
 
 #ifdef SWIFT_DEBUG_CHECKS
         /* Check that kick and the drift are synchronized */
@@ -1245,7 +1328,6 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) {
   struct xpart *restrict xparts = c->xparts;
   struct gpart *restrict gparts = c->gparts;
   struct spart *restrict sparts = c->sparts;
-  const double timeBase = e->timeBase;
 
   TIMER_TIC;
 
@@ -1292,10 +1374,6 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) {
         p->time_bin = get_time_bin(ti_new_step);
         if (p->gpart != NULL) p->gpart->time_bin = p->time_bin;
 
-        /* Tell the particle what the new physical time step is */
-        float dt = get_timestep(p->time_bin, timeBase);
-        hydro_timestep_extra(p, dt);
-
         /* Number of updated particles */
         updated++;
         if (p->gpart != NULL) g_updated++;
@@ -1503,6 +1581,7 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) {
 void runner_do_end_force(struct runner *r, struct cell *c, int timer) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
   const int count = c->count;
   const int gcount = c->gcount;
   const int scount = c->scount;
@@ -1531,7 +1610,7 @@ void runner_do_end_force(struct runner *r, struct cell *c, int timer) {
       if (part_is_active(p, e)) {
 
         /* Finish the force loop */
-        hydro_end_force(p);
+        hydro_end_force(p, cosmo);
       }
     }
 
diff --git a/src/runner_doiact.h b/src/runner_doiact.h
index 038c27a950d8748512b484d8941e2f029edaaab0..2ea4cbf24576e50607379d8659106a57a1f80356 100644
--- a/src/runner_doiact.h
+++ b/src/runner_doiact.h
@@ -138,6 +138,7 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci,
                    struct cell *restrict cj) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
 
   TIMER_TIC;
 
@@ -149,6 +150,10 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci,
   struct part *restrict parts_i = ci->parts;
   struct part *restrict parts_j = cj->parts;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   /* Get the relative distance between the pairs, wrapping. */
   double shift[3] = {0.0, 0.0, 0.0};
   for (int k = 0; k < 3; k++) {
@@ -197,9 +202,9 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci,
       /* Hit or miss? */
       if (r2 < hig2 && pi_active) {
 
-        IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+        IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+        runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
       }
       if (r2 < hjg2 && pj_active) {
@@ -208,9 +213,9 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci,
         dx[1] = -dx[1];
         dx[2] = -dx[2];
 
-        IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+        IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+        runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
       }
 
@@ -233,6 +238,7 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci,
                    struct cell *restrict cj) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
 
   TIMER_TIC;
 
@@ -244,6 +250,10 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci,
   struct part *restrict parts_i = ci->parts;
   struct part *restrict parts_j = cj->parts;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   /* Get the relative distance between the pairs, wrapping. */
   double shift[3] = {0.0, 0.0, 0.0};
   for (int k = 0; k < 3; k++) {
@@ -294,15 +304,15 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci,
 
         if (pi_active && pj_active) {
 
-          IACT(r2, dx, hi, hj, pi, pj);
+          IACT(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_chemistry(r2, dx, hi, hj, pi, pj);
+          runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
         } else if (pi_active) {
 
-          IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+          IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
         } else if (pj_active) {
 
@@ -310,9 +320,9 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci,
           dx[1] = -dx[1];
           dx[2] = -dx[2];
 
-          IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+          IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
         }
       }
@@ -333,12 +343,17 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci,
 void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
 
   TIMER_TIC;
 
   /* Anything to do here? */
   if (!cell_is_active_hydro(c, e)) return;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   const int count = c->count;
   struct part *restrict parts = c->parts;
 
@@ -384,15 +399,15 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) {
       /* Hit or miss? */
       if (doi && doj) {
 
-        IACT(r2, dx, hi, hj, pi, pj);
+        IACT(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_chemistry(r2, dx, hi, hj, pi, pj);
+        runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
       } else if (doi) {
 
-        IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+        IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+        runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
       } else if (doj) {
 
@@ -400,9 +415,9 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) {
         dx[1] = -dx[1];
         dx[2] = -dx[2];
 
-        IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+        IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+        runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
       }
     } /* loop over the parts in cj. */
@@ -422,12 +437,17 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) {
 void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
 
   TIMER_TIC;
 
   /* Anything to do here? */
   if (!cell_is_active_hydro(c, e)) return;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   const int count = c->count;
   struct part *restrict parts = c->parts;
 
@@ -473,15 +493,15 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) {
       /* Hit or miss? */
       if (doi && doj) {
 
-        IACT(r2, dx, hi, hj, pi, pj);
+        IACT(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_chemistry(r2, dx, hi, hj, pi, pj);
+        runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
       } else if (doi) {
 
-        IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+        IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+        runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
       } else if (doj) {
 
@@ -489,9 +509,9 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) {
         dx[1] = -dx[1];
         dx[2] = -dx[2];
 
-        IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+        IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+        runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
       }
     } /* loop over the parts in cj. */
@@ -519,11 +539,18 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci,
                          int count, struct cell *restrict cj,
                          const double *shift) {
 
+  const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
+
   TIMER_TIC;
 
   const int count_j = cj->count;
   struct part *restrict parts_j = cj->parts;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   /* Loop over the parts_i. */
   for (int pid = 0; pid < count; pid++) {
 
@@ -535,7 +562,6 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci,
     const float hig2 = hi * hi * kernel_gamma2;
 
 #ifdef SWIFT_DEBUG_CHECKS
-    const struct engine *e = r->e;
     if (!part_is_active(pi, e))
       error("Trying to correct smoothing length of inactive particle !");
 #endif
@@ -565,9 +591,9 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci,
       /* Hit or miss? */
       if (r2 < hig2) {
 
-        IACT_NONSYM(r2, dx, hi, pj->h, pi, pj);
+        IACT_NONSYM(r2, dx, hi, pj->h, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj);
+        runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj, a, H);
 #endif
       }
     } /* loop over the parts in cj. */
@@ -595,11 +621,18 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci,
                    struct cell *restrict cj, const int sid, const int flipped,
                    const double *shift) {
 
+  const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
+
   TIMER_TIC;
 
   const int count_j = cj->count;
   struct part *restrict parts_j = cj->parts;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   /* Pick-out the sorted lists. */
   const struct entry *restrict sort_j = cj->sort[sid];
   const float dxj = cj->dx_max_sort;
@@ -636,7 +669,6 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci,
         const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
 
 #ifdef SWIFT_DEBUG_CHECKS
-        const struct engine *e = r->e;
         /* Check that particles have been drifted to the current time */
         if (pi->ti_drift != e->ti_current)
           error("Particle pi not drifted to current time");
@@ -647,9 +679,9 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci,
         /* Hit or miss? */
         if (r2 < hig2) {
 
-          IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+          IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
         }
       } /* loop over the parts in cj. */
@@ -688,7 +720,6 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci,
         const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
 
 #ifdef SWIFT_DEBUG_CHECKS
-        const struct engine *e = r->e;
         /* Check that particles have been drifted to the current time */
         if (pi->ti_drift != e->ti_current)
           error("Particle pi not drifted to current time");
@@ -699,9 +730,9 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci,
         /* Hit or miss? */
         if (r2 < hig2) {
 
-          IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+          IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
         }
       } /* loop over the parts in cj. */
@@ -782,12 +813,15 @@ void DOPAIR_SUBSET_BRANCH(struct runner *r, struct cell *restrict ci,
 void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci,
                    struct part *restrict parts, int *restrict ind, int count) {
 
-#ifdef SWIFT_DEBUG_CHECKS
   const struct engine *e = r->e;
-#endif
+  const struct cosmology *cosmo = e->cosmology;
 
   TIMER_TIC;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   const int count_i = ci->count;
   struct part *restrict parts_j = ci->parts;
 
@@ -811,6 +845,7 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci,
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts_j[pjd];
+      const float hj = pj->h;
 
       /* Compute the pairwise distance. */
       const float pjx[3] = {(float)(pj->x[0] - ci->loc[0]),
@@ -830,9 +865,9 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci,
       /* Hit or miss? */
       if (r2 > 0.f && r2 < hig2) {
 
-        IACT_NONSYM(r2, dx, hi, pj->h, pi, pj);
+        IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-        runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj);
+        runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
       }
     } /* loop over the parts in cj. */
@@ -875,6 +910,7 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
              const double *shift) {
 
   const struct engine *restrict e = r->e;
+  const struct cosmology *restrict cosmo = e->cosmology;
 
   TIMER_TIC;
 
@@ -907,6 +943,10 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
   const double dj_min = sort_j[0].d;
   const float dx_max = (ci->dx_max_sort + cj->dx_max_sort);
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   if (cell_is_active_hydro(ci, e)) {
 
     /* Loop over the parts in ci. */
@@ -981,9 +1021,9 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
         /* Hit or miss? */
         if (r2 < hig2) {
 
-          IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+          IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
         }
       } /* loop over the parts in cj. */
@@ -1064,9 +1104,9 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
         /* Hit or miss? */
         if (r2 < hjg2) {
 
-          IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+          IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
         }
       } /* loop over the parts in ci. */
@@ -1170,7 +1210,8 @@ void DOPAIR1_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) {
 void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
              const double *shift) {
 
-  struct engine *restrict e = r->e;
+  const struct engine *restrict e = r->e;
+  const struct cosmology *restrict cosmo = e->cosmology;
 
   TIMER_TIC;
 
@@ -1200,6 +1241,10 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
   struct part *restrict parts_i = ci->parts;
   struct part *restrict parts_j = cj->parts;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   /* Maximal displacement since last rebuild */
   const double dx_max = (ci->dx_max_sort + cj->dx_max_sort);
 
@@ -1330,9 +1375,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
         /* Hit or miss?
            (note that we will do the other condition in the reverse loop) */
         if (r2 < hig2) {
-          IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+          IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
         }
       } /* loop over the active parts in cj. */
@@ -1395,14 +1440,14 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
 
           /* Does pj need to be updated too? */
           if (part_is_active(pj, e)) {
-            IACT(r2, dx, hi, hj, pi, pj);
+            IACT(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_chemistry(r2, dx, hi, hj, pi, pj);
+            runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
           } else {
-            IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+            IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+            runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
           }
         }
@@ -1490,9 +1535,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
         /* Hit or miss?
            (note that we must avoid the r2 < hig2 cases we already processed) */
         if (r2 < hjg2 && r2 >= hig2) {
-          IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+          IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+          runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
         }
       } /* loop over the active parts in ci. */
@@ -1558,14 +1603,14 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
 
           /* Does pi need to be updated too? */
           if (part_is_active(pi, e)) {
-            IACT(r2, dx, hj, hi, pj, pi);
+            IACT(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_chemistry(r2, dx, hj, hi, pj, pi);
+            runner_iact_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
           } else {
-            IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+            IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+            runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
           }
         }
@@ -1673,6 +1718,7 @@ void DOPAIR2_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) {
 void DOSELF1(struct runner *r, struct cell *restrict c) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
 
   TIMER_TIC;
 
@@ -1691,6 +1737,10 @@ void DOSELF1(struct runner *r, struct cell *restrict c) {
       countdt += 1;
     }
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   /* Loop over the particles in the cell. */
   for (int pid = 0; pid < count; pid++) {
 
@@ -1732,9 +1782,9 @@ void DOSELF1(struct runner *r, struct cell *restrict c) {
         /* Hit or miss? */
         if (r2 < hj * hj * kernel_gamma2) {
 
-          IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+          IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
         }
       } /* loop over all other particles. */
@@ -1776,22 +1826,22 @@ void DOSELF1(struct runner *r, struct cell *restrict c) {
 
           /* Which parts need to be updated? */
           if (r2 < hig2 && doj) {
-            IACT(r2, dx, hi, hj, pi, pj);
+            IACT(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_chemistry(r2, dx, hi, hj, pi, pj);
+            runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
           } else if (!doj) {
-            IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+            IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+            runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
           } else {
             dx[0] = -dx[0];
             dx[1] = -dx[1];
             dx[2] = -dx[2];
-            IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+            IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+            runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
           }
         }
@@ -1845,6 +1895,7 @@ void DOSELF1_BRANCH(struct runner *r, struct cell *c) {
 void DOSELF2(struct runner *r, struct cell *restrict c) {
 
   const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
 
   TIMER_TIC;
 
@@ -1863,6 +1914,10 @@ void DOSELF2(struct runner *r, struct cell *restrict c) {
       countdt += 1;
     }
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   /* Loop over the particles in the cell. */
   for (int pid = 0; pid < count; pid++) {
 
@@ -1904,9 +1959,9 @@ void DOSELF2(struct runner *r, struct cell *restrict c) {
         /* Hit or miss? */
         if (r2 < hig2 || r2 < hj * hj * kernel_gamma2) {
 
-          IACT_NONSYM(r2, dx, hj, hi, pj, pi);
+          IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi);
+          runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H);
 #endif
         }
       } /* loop over all other particles. */
@@ -1946,14 +2001,14 @@ void DOSELF2(struct runner *r, struct cell *restrict c) {
 
           /* Does pj need to be updated too? */
           if (part_is_active(pj, e)) {
-            IACT(r2, dx, hi, hj, pi, pj);
+            IACT(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_chemistry(r2, dx, hi, hj, pi, pj);
+            runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
           } else {
-            IACT_NONSYM(r2, dx, hi, hj, pi, pj);
+            IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H);
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
-            runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj);
+            runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H);
 #endif
           }
         }
diff --git a/src/serial_io.c b/src/serial_io.c
index 047c3d3f88ba56eca8720fa06bba9bf5c3db07b7..3e62bd7fda99ed7703a4fe67340d5a03e5dc45b8 100644
--- a/src/serial_io.c
+++ b/src/serial_io.c
@@ -778,6 +778,8 @@ void write_output_serial(struct engine* e, const char* baseName,
     io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1);
     int dimension = (int)hydro_dimension;
     io_write_attribute(h_grp, "Dimension", INT, &dimension, 1);
+    io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1);
+    io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1);
 
     /* GADGET-2 legacy values */
     /* Number of particles of each type */
@@ -807,6 +809,9 @@ void write_output_serial(struct engine* e, const char* baseName,
     /* Print the code version */
     io_write_code_description(h_file);
 
+    /* Print the run's policy */
+    io_write_engine_policy(h_file, e);
+
     /* Print the SPH parameters */
     if (e->policy & engine_policy_hydro) {
       h_grp = H5Gcreate(h_file, "/HydroScheme", H5P_DEFAULT, H5P_DEFAULT,
@@ -834,6 +839,15 @@ void write_output_serial(struct engine* e, const char* baseName,
       H5Gclose(h_grp);
     }
 
+    /* Print the cosmological model */
+    if (e->policy & engine_policy_cosmology) {
+      h_grp = H5Gcreate(h_file, "/Cosmology", H5P_DEFAULT, H5P_DEFAULT,
+                        H5P_DEFAULT);
+      if (h_grp < 0) error("Error while creating cosmology group");
+      cosmology_write_model(h_grp, e->cosmology);
+      H5Gclose(h_grp);
+    }
+
     /* Print the runtime parameters */
     h_grp =
         H5Gcreate(h_file, "/Parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
diff --git a/src/single_io.c b/src/single_io.c
index 4ba85c2b1b6970469b17ac2d475e297b848604c6..caa39e4a7cf583b210d3e9322abcd53c332cfe70 100644
--- a/src/single_io.c
+++ b/src/single_io.c
@@ -630,6 +630,8 @@ void write_output_single(struct engine* e, const char* baseName,
   io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1);
   int dimension = (int)hydro_dimension;
   io_write_attribute(h_grp, "Dimension", INT, &dimension, 1);
+  io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1);
+  io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1);
 
   /* GADGET-2 legacy values */
   /* Number of particles of each type */
@@ -659,6 +661,9 @@ void write_output_single(struct engine* e, const char* baseName,
   /* Print the code version */
   io_write_code_description(h_file);
 
+  /* Print the run's policy */
+  io_write_engine_policy(h_file, e);
+
   /* Print the SPH parameters */
   if (e->policy & engine_policy_hydro) {
     h_grp = H5Gcreate(h_file, "/HydroScheme", H5P_DEFAULT, H5P_DEFAULT,
@@ -686,6 +691,15 @@ void write_output_single(struct engine* e, const char* baseName,
     H5Gclose(h_grp);
   }
 
+  /* Print the cosmological model  */
+  if (e->policy & engine_policy_cosmology) {
+    h_grp =
+        H5Gcreate(h_file, "/Cosmology", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+    if (h_grp < 0) error("Error while creating cosmology group");
+    cosmology_write_model(h_grp, e->cosmology);
+    H5Gclose(h_grp);
+  }
+
   /* Print the runtime parameters */
   h_grp =
       H5Gcreate(h_file, "/Parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
diff --git a/src/statistics.c b/src/statistics.c
index ed5e0f743411d501c11c7ada35d82d77c2398a3d..ed3197fbd0538394bb1c40d834c16e174a410068 100644
--- a/src/statistics.c
+++ b/src/statistics.c
@@ -105,17 +105,24 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) {
   /* Unpack the data */
   const struct index_data *data = (struct index_data *)extra_data;
   const struct space *s = data->s;
+  const struct engine *e = s->e;
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+  const double time = e->time;
   const struct part *restrict parts = (struct part *)map_data;
   const struct xpart *restrict xparts =
       s->xparts + (ptrdiff_t)(parts - s->parts);
-  const integertime_t ti_current = s->e->ti_current;
-  const double timeBase = s->e->timeBase;
-  const double time = s->e->time;
   struct statistics *const global_stats = data->stats;
 
-  /* Required for external potential energy */
-  const struct external_potential *potential = s->e->external_potential;
-  const struct phys_const *phys_const = s->e->physical_constants;
+  /* Some information about the physical model */
+  const struct external_potential *potential = e->external_potential;
+  const struct phys_const *phys_const = e->physical_constants;
+  const struct cosmology *cosmo = e->cosmology;
+
+  /* Some constants from cosmology */
+  const float a_inv = cosmo->a_inv;
+  const float a_inv2 = a_inv * a_inv;
 
   /* Local accumulator */
   struct statistics stats;
@@ -130,17 +137,35 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) {
     const struct gpart *gp = (p->gpart != NULL) ? gp = p->gpart : NULL;
 
     /* Get useful time variables */
-    const integertime_t ti_begin =
+    const integertime_t ti_beg =
         get_integer_time_begin(ti_current, p->time_bin);
     const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin);
-    const float dt = (ti_current - ((ti_begin + ti_end) / 2)) * timeBase;
+
+    /* Get time-step since the last kick */
+    float dt_kick_grav, dt_kick_hydro, dt_therm;
+    if (with_cosmology) {
+      dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+      dt_kick_grav -=
+          cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+      dt_kick_hydro =
+          cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current);
+      dt_kick_hydro -=
+          cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+      dt_therm = cosmology_get_therm_kick_factor(cosmo, ti_beg, ti_current);
+      dt_therm -=
+          cosmology_get_therm_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    } else {
+      dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+      dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+      dt_therm = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    }
 
     float v[3];
-    hydro_get_drifted_velocities(p, xp, dt, v);
+    hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, v);
     const double x[3] = {p->x[0], p->x[1], p->x[2]};
     const float m = hydro_get_mass(p);
-    const float entropy = hydro_get_entropy(p);
-    const float u_inter = hydro_get_internal_energy(p);
+    const float entropy = hydro_get_physical_entropy(p, cosmo);
+    const float u_inter = hydro_get_physical_internal_energy(p, cosmo);
 
     /* Collect mass */
     stats.mass += m;
@@ -161,11 +186,12 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) {
     stats.ang_mom[2] += m * (x[0] * v[1] - x[1] * v[0]);
 
     /* Collect energies. */
-    stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+    stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) *
+                   a_inv2; /* 1/2 m a^2 \dot{r}^2 */
     stats.E_int += m * u_inter;
     stats.E_rad += cooling_get_radiated_energy(xp);
     if (gp != NULL) {
-      stats.E_pot_self += m * gravity_get_potential(gp);
+      stats.E_pot_self += m * gravity_get_potential(gp) * a_inv;
       stats.E_pot_ext += m * external_gravity_get_potential_energy(
                                  time, potential, phys_const, gp);
     }
@@ -192,15 +218,22 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts,
   /* Unpack the data */
   const struct index_data *data = (struct index_data *)extra_data;
   const struct space *s = data->s;
+  const struct engine *e = s->e;
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+  const double time = e->time;
   const struct gpart *restrict gparts = (struct gpart *)map_data;
-  const integertime_t ti_current = s->e->ti_current;
-  const double timeBase = s->e->timeBase;
-  const double time = s->e->time;
   struct statistics *const global_stats = data->stats;
 
-  /* Required for external potential energy */
-  const struct external_potential *potential = s->e->external_potential;
-  const struct phys_const *phys_const = s->e->physical_constants;
+  /* Some information about the physical model */
+  const struct external_potential *potential = e->external_potential;
+  const struct phys_const *phys_const = e->physical_constants;
+  const struct cosmology *cosmo = e->cosmology;
+
+  /* Some constants from cosmology */
+  const float a_inv = cosmo->a_inv;
+  const float a_inv2 = a_inv * a_inv;
 
   /* Local accumulator */
   struct statistics stats;
@@ -216,15 +249,24 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts,
     if (gp->id_or_neg_offset < 0) continue;
 
     /* Get useful variables */
-    const integertime_t ti_begin =
+    const integertime_t ti_beg =
         get_integer_time_begin(ti_current, gp->time_bin);
     const integertime_t ti_end = get_integer_time_end(ti_current, gp->time_bin);
-    const float dt = (ti_current - ((ti_begin + ti_end) / 2)) * timeBase;
+
+    /* Get time-step since the last kick */
+    float dt_kick_grav;
+    if (with_cosmology) {
+      dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+      dt_kick_grav -=
+          cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    } else {
+      dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    }
 
     /* Extrapolate velocities */
-    const float v[3] = {gp->v_full[0] + gp->a_grav[0] * dt,
-                        gp->v_full[1] + gp->a_grav[1] * dt,
-                        gp->v_full[2] + gp->a_grav[2] * dt};
+    const float v[3] = {gp->v_full[0] + gp->a_grav[0] * dt_kick_grav,
+                        gp->v_full[1] + gp->a_grav[1] * dt_kick_grav,
+                        gp->v_full[2] + gp->a_grav[2] * dt_kick_grav};
 
     const float m = gravity_get_mass(gp);
     const double x[3] = {gp->x[0], gp->x[1], gp->x[2]};
@@ -248,8 +290,9 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts,
     stats.ang_mom[2] += m * (x[0] * v[1] - x[1] * v[0]);
 
     /* Collect energies. */
-    stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
-    stats.E_pot_self += m * gravity_get_potential(gp);
+    stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) *
+                   a_inv2; /* 1/2 m a^2 \dot{r}^2 */
+    stats.E_pot_self += m * gravity_get_potential(gp) * a_inv;
     stats.E_pot_ext += m * external_gravity_get_potential_energy(
                                time, potential, phys_const, gp);
   }
diff --git a/src/swift.h b/src/swift.h
index bd3c7fd5741b8c93f2931e1ec0f148d659249752..7691720942f32d29d3269ccdd7adbe8db32280bf 100644
--- a/src/swift.h
+++ b/src/swift.h
@@ -31,6 +31,7 @@
 #include "clocks.h"
 #include "const.h"
 #include "cooling.h"
+#include "cosmology.h"
 #include "cycle.h"
 #include "debug.h"
 #include "dump.h"
diff --git a/src/timeline.h b/src/timeline.h
index 0f38ff3e9421c122b61caf74290c170b62b2dd92..66b2c9456fb9e2e9f8b36272a9bbf3b7764523fc 100644
--- a/src/timeline.h
+++ b/src/timeline.h
@@ -40,6 +40,12 @@ typedef char timebin_t;
 /*! Fictious time-bin to hold inhibited particles */
 #define time_bin_inhibited (num_time_bins + 2)
 
+/*! Fictitious time-bin for particles not awaken */
+#define time_bin_not_awake (0)
+
+/*! Fictitious time-bin for particles woken up */
+#define time_bin_awake (-1)
+
 /**
  * @brief Returns the integer time interval corresponding to a time bin
  *
@@ -122,4 +128,17 @@ static INLINE timebin_t get_max_active_bin(integertime_t time) {
   return bin;
 }
 
+/**
+ * @brief Returns the lowest active time bin at a given point on the time line.
+ *
+ * @param ti_current The current point on the time line.
+ * @param ti_old The last synchronisation point on the time line.
+ */
+static INLINE timebin_t get_min_active_bin(integertime_t ti_current,
+                                           integertime_t ti_old) {
+
+  const timebin_t min_bin = get_max_active_bin(ti_current - ti_old);
+  return (ti_old > 0) ? min_bin : (min_bin - 1);
+}
+
 #endif /* SWIFT_TIMELINE_H */
diff --git a/src/timestep.h b/src/timestep.h
index 309a0b1407d3ee634711e07fa9b9f0a04a25ba1c..4e715e1f15dd525d89b44ae3e716278cebe28a8d 100644
--- a/src/timestep.h
+++ b/src/timestep.h
@@ -33,14 +33,14 @@
  * @param new_dt The time-step to convert.
  * @param old_bin The old time bin.
  * @param ti_current The current time on the integer time-line.
- * @param timeBase_inv The inverse of the system's minimal time-step.
+ * @param time_base_inv The inverse of the system's minimal time-step.
  */
 __attribute__((always_inline)) INLINE static integertime_t
 make_integer_timestep(float new_dt, timebin_t old_bin, integertime_t ti_current,
-                      double timeBase_inv) {
+                      double time_base_inv) {
 
   /* Convert to integer time */
-  integertime_t new_dti = (integertime_t)(new_dt * timeBase_inv);
+  integertime_t new_dti = (integertime_t)(new_dt * time_base_inv);
 
   /* Current time-step */
   integertime_t current_dti = get_integer_timestep(old_bin);
@@ -51,7 +51,7 @@ make_integer_timestep(float new_dt, timebin_t old_bin, integertime_t ti_current,
 
   /* Put this timestep on the time line */
   integertime_t dti_timeline = max_nr_timesteps;
-  while (new_dti < dti_timeline) dti_timeline /= 2LL;
+  while (new_dti < dti_timeline) dti_timeline /= ((integertime_t)2);
   new_dti = dti_timeline;
 
   /* Make sure we are allowed to increase the timestep size */
@@ -70,16 +70,22 @@ make_integer_timestep(float new_dt, timebin_t old_bin, integertime_t ti_current,
 __attribute__((always_inline)) INLINE static integertime_t get_gpart_timestep(
     const struct gpart *restrict gp, const struct engine *restrict e) {
 
-  float new_dt = FLT_MAX;
+  float new_dt_self = FLT_MAX, new_dt_ext = FLT_MAX;
 
   if (e->policy & engine_policy_external_gravity)
-    new_dt =
-        min(new_dt, external_gravity_timestep(e->time, e->external_potential,
-                                              e->physical_constants, gp));
+    new_dt_ext = external_gravity_timestep(e->time, e->external_potential,
+                                           e->physical_constants, gp);
 
+  const float a_hydro[3] = {0.f, 0.f, 0.f};
   if (e->policy & engine_policy_self_gravity)
-    new_dt =
-        min(new_dt, gravity_compute_timestep_self(gp, e->gravity_properties));
+    new_dt_ext = gravity_compute_timestep_self(
+        gp, a_hydro, e->gravity_properties, e->cosmology);
+
+  /* Take the minimum of all */
+  float new_dt = min(new_dt_self, new_dt_ext);
+
+  /* Apply cosmology correction */
+  new_dt *= e->cosmology->time_step_factor;
 
   /* Limit timestep within the allowed range */
   new_dt = min(new_dt, e->dt_max);
@@ -89,7 +95,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_gpart_timestep(
 
   /* Convert to integer time */
   const integertime_t new_dti = make_integer_timestep(
-      new_dt, gp->time_bin, e->ti_current, e->timeBase_inv);
+      new_dt, gp->time_bin, e->ti_current, e->time_base_inv);
 
   return new_dti;
 }
@@ -106,26 +112,29 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep(
     const struct engine *restrict e) {
 
   /* Compute the next timestep (hydro condition) */
-  const float new_dt_hydro = hydro_compute_timestep(p, xp, e->hydro_properties);
+  const float new_dt_hydro =
+      hydro_compute_timestep(p, xp, e->hydro_properties, e->cosmology);
 
   /* 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->internal_units, p);
+                                      e->cosmology, e->internal_units, p);
 
   /* Compute the next timestep (gravity condition) */
-  float new_dt_grav = FLT_MAX;
+  float new_dt_grav = FLT_MAX, new_dt_self_grav = FLT_MAX,
+        new_dt_ext_grav = FLT_MAX;
   if (p->gpart != NULL) {
 
     if (e->policy & engine_policy_external_gravity)
-      new_dt_grav = min(new_dt_grav, external_gravity_timestep(
-                                         e->time, e->external_potential,
-                                         e->physical_constants, p->gpart));
+      new_dt_ext_grav = external_gravity_timestep(
+          e->time, e->external_potential, e->physical_constants, p->gpart);
 
     if (e->policy & engine_policy_self_gravity)
-      new_dt_grav = min(new_dt_grav, gravity_compute_timestep_self(
-                                         p->gpart, e->gravity_properties));
+      new_dt_self_grav = gravity_compute_timestep_self(
+          p->gpart, p->a_hydro, e->gravity_properties, e->cosmology);
+
+    new_dt_grav = min(new_dt_self_grav, new_dt_ext_grav);
   }
 
   /* Final time-step is minimum of hydro and gravity */
@@ -139,6 +148,9 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep(
 
   new_dt = min(new_dt, dt_h_change);
 
+  /* Apply cosmology correction (H==1 if non-cosmological) */
+  new_dt *= e->cosmology->time_step_factor;
+
   /* Limit timestep within the allowed range */
   new_dt = min(new_dt, e->dt_max);
   if (new_dt < e->dt_min)
@@ -147,7 +159,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep(
 
   /* Convert to integer time */
   const integertime_t new_dti = make_integer_timestep(
-      new_dt, p->time_bin, e->ti_current, e->timeBase_inv);
+      new_dt, p->time_bin, e->ti_current, e->time_base_inv);
 
   return new_dti;
 }
@@ -161,16 +173,26 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep(
 __attribute__((always_inline)) INLINE static integertime_t get_spart_timestep(
     const struct spart *restrict sp, const struct engine *restrict e) {
 
-  float new_dt = star_compute_timestep(sp);
+  /* Stellar time-step */
+  float new_dt_star = star_compute_timestep(sp);
+
+  /* Gravity time-step */
+  float new_dt_self = FLT_MAX, new_dt_ext = FLT_MAX;
 
   if (e->policy & engine_policy_external_gravity)
-    new_dt = min(new_dt,
-                 external_gravity_timestep(e->time, e->external_potential,
-                                           e->physical_constants, sp->gpart));
+    new_dt_ext = external_gravity_timestep(e->time, e->external_potential,
+                                           e->physical_constants, sp->gpart);
 
+  const float a_hydro[3] = {0.f, 0.f, 0.f};
   if (e->policy & engine_policy_self_gravity)
-    new_dt = min(new_dt, gravity_compute_timestep_self(sp->gpart,
-                                                       e->gravity_properties));
+    new_dt_self = gravity_compute_timestep_self(
+        sp->gpart, a_hydro, e->gravity_properties, e->cosmology);
+
+  /* Take the minimum of all */
+  float new_dt = min3(new_dt_star, new_dt_self, new_dt_ext);
+
+  /* Apply cosmology correction (H==1 if non-cosmological) */
+  new_dt *= e->cosmology->time_step_factor;
 
   /* Limit timestep within the allowed range */
   new_dt = min(new_dt, e->dt_max);
@@ -180,7 +202,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_spart_timestep(
 
   /* Convert to integer time */
   const integertime_t new_dti = make_integer_timestep(
-      new_dt, sp->time_bin, e->ti_current, e->timeBase_inv);
+      new_dt, sp->time_bin, e->ti_current, e->time_base_inv);
 
   return new_dti;
 }
diff --git a/src/tools.c b/src/tools.c
index 89d89e62ea092ba6c6ec661e423d3e0ee44eb7fe..4653c2ef799f9256bd459d9dcc1cf5698a7db6f4 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -27,6 +27,8 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/time.h>
 
 /* This object's header. */
 #include "tools.h"
@@ -34,6 +36,7 @@
 /* Local includes. */
 #include "active.h"
 #include "cell.h"
+#include "cosmology.h"
 #include "error.h"
 #include "gravity.h"
 #include "hydro.h"
@@ -73,6 +76,7 @@ void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic) {
   // double maxratio = 1.0;
   double r2, dx[3], rho = 0.0;
   double rho_max = 0.0, rho_min = 100;
+  float a = 1.f, H = 0.f;
 
   /* Loop over all particle pairs. */
   for (j = 0; j < N; j++) {
@@ -93,7 +97,7 @@ void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic) {
       r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
       if (r2 < parts[j].h * parts[j].h || r2 < parts[k].h * parts[k].h) {
         runner_iact_density(r2, NULL, parts[j].h, parts[k].h, &parts[j],
-                            &parts[k]);
+                            &parts[k], a, H);
         /* if ( parts[j].h / parts[k].h > maxratio )
             {
             maxratio = parts[j].h / parts[k].h;
@@ -132,12 +136,10 @@ void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic) {
 void pairs_single_density(double *dim, long long int pid,
                           struct part *restrict parts, int N, int periodic) {
   int i, k;
-  // int mj, mk;
-  // double maxratio = 1.0;
   double r2, dx[3];
   float fdx[3];
   struct part p;
-  // double ih = 12.0/6.25;
+  float a = 1.f, H = 0.f;
 
   /* Find "our" part. */
   for (k = 0; k < N && parts[k].id != pid; k++)
@@ -163,7 +165,7 @@ void pairs_single_density(double *dim, long long int pid,
     }
     r2 = fdx[0] * fdx[0] + fdx[1] * fdx[1] + fdx[2] * fdx[2];
     if (r2 < p.h * p.h) {
-      runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k]);
+      runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H);
       /* printf( "pairs_simple: interacting particles %lli [%i,%i,%i] and %lli
          [%i,%i,%i], r=%e.\n" ,
           pid , (int)(p.x[0]*ih) , (int)(p.x[1]*ih) , (int)(p.x[2]*ih) ,
@@ -185,6 +187,7 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) {
   struct part *pi, *pj;
   const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]};
   const struct engine *e = r->e;
+  float a = 1.f, H = 0.f;
 
   /* Implements a double-for loop and checks every interaction */
   for (int i = 0; i < ci->count; ++i) {
@@ -212,7 +215,7 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) {
       if (r2 < hig2) {
 
         /* Interact */
-        runner_iact_nonsym_density(r2, dx, hi, pj->h, pi, pj);
+        runner_iact_nonsym_density(r2, dx, hi, pj->h, pi, pj, a, H);
       }
     }
   }
@@ -243,7 +246,7 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) {
       if (r2 < hjg2) {
 
         /* Interact */
-        runner_iact_nonsym_density(r2, dx, hj, pi->h, pj, pi);
+        runner_iact_nonsym_density(r2, dx, hj, pi->h, pj, pi, a, H);
       }
     }
   }
@@ -255,6 +258,7 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) {
   struct part *pi, *pj;
   const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]};
   const struct engine *e = r->e;
+  float a = 1.f, H = 0.f;
 
   /* Implements a double-for loop and checks every interaction */
   for (int i = 0; i < ci->count; ++i) {
@@ -284,7 +288,7 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) {
       if (r2 < hig2 || r2 < hjg2) {
 
         /* Interact */
-        runner_iact_nonsym_force(r2, dx, hi, hj, pi, pj);
+        runner_iact_nonsym_force(r2, dx, hi, hj, pi, pj, a, H);
       }
     }
   }
@@ -317,7 +321,7 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) {
       if (r2 < hjg2 || r2 < hig2) {
 
         /* Interact */
-        runner_iact_nonsym_force(r2, dx, hj, pi->h, pj, pi);
+        runner_iact_nonsym_force(r2, dx, hj, pi->h, pj, pi, a, H);
       }
     }
   }
@@ -327,6 +331,7 @@ void self_all_density(struct runner *r, struct cell *ci) {
   float r2, hi, hj, hig2, hjg2, dxi[3];  //, dxj[3];
   struct part *pi, *pj;
   const struct engine *e = r->e;
+  float a = 1.f, H = 0.f;
 
   /* Implements a double-for loop and checks every interaction */
   for (int i = 0; i < ci->count; ++i) {
@@ -354,7 +359,7 @@ void self_all_density(struct runner *r, struct cell *ci) {
       if (r2 < hig2 && part_is_active(pi, e)) {
 
         /* Interact */
-        runner_iact_nonsym_density(r2, dxi, hi, hj, pi, pj);
+        runner_iact_nonsym_density(r2, dxi, hi, hj, pi, pj, a, H);
       }
 
       /* Hit or miss? */
@@ -365,7 +370,7 @@ void self_all_density(struct runner *r, struct cell *ci) {
         dxi[2] = -dxi[2];
 
         /* Interact */
-        runner_iact_nonsym_density(r2, dxi, hj, hi, pj, pi);
+        runner_iact_nonsym_density(r2, dxi, hj, hi, pj, pi, a, H);
       }
     }
   }
@@ -374,6 +379,7 @@ void self_all_density(struct runner *r, struct cell *ci) {
 void self_all_force(struct runner *r, struct cell *ci) {
   float r2, hi, hj, hig2, hjg2, dxi[3];  //, dxj[3];
   struct part *pi, *pj;
+  float a = 1.f, H = 0.f;
 
   /* Implements a double-for loop and checks every interaction */
   for (int i = 0; i < ci->count; ++i) {
@@ -401,7 +407,7 @@ void self_all_force(struct runner *r, struct cell *ci) {
       if (r2 < hig2 || r2 < hjg2) {
 
         /* Interact */
-        runner_iact_force(r2, dxi, hi, hj, pi, pj);
+        runner_iact_force(r2, dxi, hi, hj, pi, pj, a, H);
       }
     }
   }
@@ -411,10 +417,12 @@ void self_all_force(struct runner *r, struct cell *ci) {
  * @brief Compute the force on a single particle brute-force.
  */
 void engine_single_density(double *dim, long long int pid,
-                           struct part *restrict parts, int N, int periodic) {
+                           struct part *restrict parts, int N, int periodic,
+                           const struct cosmology *cosmo) {
   double r2, dx[3];
   float fdx[3];
   struct part p;
+  float a = 1.f, H = 0.f;
 
   /* Find "our" part. */
   int k;
@@ -441,14 +449,14 @@ void engine_single_density(double *dim, long long int pid,
     }
     r2 = fdx[0] * fdx[0] + fdx[1] * fdx[1] + fdx[2] * fdx[2];
     if (r2 < p.h * p.h * kernel_gamma2) {
-      runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k]);
+      runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H);
     }
   }
 
   /* Dump the result. */
-  hydro_end_density(&p);
+  hydro_end_density(&p, cosmo);
   message("part %lli (h=%e) has wcount=%e, rho=%e.", p.id, p.h,
-          p.density.wcount, hydro_get_density(&p));
+          p.density.wcount, hydro_get_comoving_density(&p));
   fflush(stdout);
 }
 
@@ -458,6 +466,7 @@ void engine_single_force(double *dim, long long int pid,
   double r2, dx[3];
   float fdx[3];
   struct part p;
+  float a = 1.f, H = 0.f;
 
   /* Find "our" part. */
   for (k = 0; k < N && parts[k].id != pid; k++)
@@ -486,7 +495,7 @@ void engine_single_force(double *dim, long long int pid,
     if (r2 < p.h * p.h * kernel_gamma2 ||
         r2 < parts[k].h * parts[k].h * kernel_gamma2) {
       hydro_reset_acceleration(&p);
-      runner_iact_nonsym_force(r2, fdx, p.h, parts[k].h, &p, &parts[k]);
+      runner_iact_nonsym_force(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H);
     }
   }
 
@@ -694,3 +703,14 @@ int compare_particles(struct part a, struct part b, double threshold) {
 
 #endif
 }
+
+/**
+ * @brief return the resident memory use of the process and its children.
+ *
+ * @result memory use in Kb.
+ */
+long get_maxrss() {
+  struct rusage usage;
+  getrusage(RUSAGE_SELF, &usage);
+  return usage.ru_maxrss;
+}
diff --git a/src/tools.h b/src/tools.h
index 4d9e8d3ef86f9ad2661118acf008797893ea5bd7..bb141101a3bf6fad38a83a15ea7f6bb5de86e9f8 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -52,4 +52,6 @@ int compare_values(double a, double b, double threshold, double *absDiff,
                    double *absSum, double *relDiff);
 int compare_particles(struct part a, struct part b, double threshold);
 
+long get_maxrss();
+
 #endif /* SWIFT_TOOL_H */
diff --git a/src/version.c b/src/version.c
index f4177e5c83c776ea063ad32fd00895199c94b182..54749721de96bde010f56965152c536b08672230 100644
--- a/src/version.c
+++ b/src/version.c
@@ -37,6 +37,10 @@
 #include <fftw3.h>
 #endif
 
+#ifdef HAVE_LIBGSL
+#include <gsl/gsl_version.h>
+#endif
+
 /* Some standard headers. */
 #include <stdio.h>
 #include <stdlib.h>
@@ -332,6 +336,22 @@ const char *fftw3_version(void) {
   return version;
 }
 
+/**
+ * @brief return the GSL version used when SWIFT was built.
+ *
+ * @result description of the GSL version.
+ */
+const char *libgsl_version(void) {
+
+  static char version[256] = {0};
+#if defined(HAVE_LIBGSL)
+  sprintf(version, "%s", gsl_version);
+#else
+  sprintf(version, "Unknown version");
+#endif
+  return version;
+}
+
 /**
  * @brief return the thread barrier used in SWIFT.
  *
@@ -376,6 +396,9 @@ void greetings(void) {
 #ifdef HAVE_FFTW
   printf(" FFTW library version: %s\n", fftw3_version());
 #endif
+#ifdef HAVE_LIBGSL
+  printf(" GSL  library version: %s\n", libgsl_version());
+#endif
 #ifdef WITH_MPI
   printf(" MPI library: %s\n", mpi_version());
 #ifdef HAVE_METIS
diff --git a/src/version.h b/src/version.h
index 1af76b647b2d401bb4a7998b281864fb3e63a0c8..3163f242c50e56c64cc709b13dfe926f93672a00 100644
--- a/src/version.h
+++ b/src/version.h
@@ -34,6 +34,7 @@ const char* mpi_version(void);
 const char* metis_version(void);
 const char* hdf5_version(void);
 const char* fftw3_version(void);
+const char* libgsl_version(void);
 const char* thread_barrier_version(void);
 void greetings(void);
 
diff --git a/tests/test125cells.c b/tests/test125cells.c
index 7c6a161093c0cb823efb04f62e0ba570a5dd1651..6098b8969874a3bb942de770b84220c047af6e1c 100644
--- a/tests/test125cells.c
+++ b/tests/test125cells.c
@@ -1,4 +1,3 @@
-
 /*******************************************************************************
  * This file is part of SWIFT.
  * Copyright (C) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk).
@@ -403,16 +402,16 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
             main_cell->parts[pid].x[1], main_cell->parts[pid].x[2],
             main_cell->parts[pid].v[0], main_cell->parts[pid].v[1],
             main_cell->parts[pid].v[2], main_cell->parts[pid].h,
-            hydro_get_density(&main_cell->parts[pid]),
+            hydro_get_comoving_density(&main_cell->parts[pid]),
 #if defined(MINIMAL_SPH) || defined(SHADOWFAX_SPH)
             0.f,
 #else
             main_cell->parts[pid].density.div_v,
 #endif
-            hydro_get_entropy(&main_cell->parts[pid]),
-            hydro_get_internal_energy(&main_cell->parts[pid]),
-            hydro_get_pressure(&main_cell->parts[pid]),
-            hydro_get_soundspeed(&main_cell->parts[pid]),
+            hydro_get_comoving_entropy(&main_cell->parts[pid]),
+            hydro_get_comoving_internal_energy(&main_cell->parts[pid]),
+            hydro_get_comoving_pressure(&main_cell->parts[pid]),
+            hydro_get_comoving_soundspeed(&main_cell->parts[pid]),
             main_cell->parts[pid].a_hydro[0], main_cell->parts[pid].a_hydro[1],
             main_cell->parts[pid].a_hydro[2], main_cell->parts[pid].force.h_dt,
 #if defined(GADGET2_SPH)
@@ -597,6 +596,10 @@ int main(int argc, char *argv[]) {
   engine.max_active_bin = num_time_bins;
   engine.nodeID = NODE_ID;
 
+  struct cosmology cosmo;
+  cosmology_init_no_cosmo(&cosmo);
+  engine.cosmology = &cosmo;
+
   struct runner runner;
   runner.e = &engine;
 
diff --git a/tests/test27cells.c b/tests/test27cells.c
index 0b8d96a29649d2af14deaefd105901936d337842..6b275094de8f2f1a54e94f35ae10e347adb19b4f 100644
--- a/tests/test27cells.c
+++ b/tests/test27cells.c
@@ -225,9 +225,9 @@ void zero_particle_fields(struct cell *c) {
 /**
  * @brief Ends the loop by adding the appropriate coefficients
  */
-void end_calculation(struct cell *c) {
+void end_calculation(struct cell *c, const struct cosmology *cosmo) {
   for (int pid = 0; pid < c->count; pid++) {
-    hydro_end_density(&c->parts[pid]);
+    hydro_end_density(&c->parts[pid], cosmo);
 
     /* Recover the common "Neighbour number" definition */
     c->parts[pid].density.wcount *= pow_dimension(c->parts[pid].h);
@@ -260,7 +260,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
             main_cell->parts[pid].x[1], main_cell->parts[pid].x[2],
             main_cell->parts[pid].v[0], main_cell->parts[pid].v[1],
             main_cell->parts[pid].v[2],
-            hydro_get_density(&main_cell->parts[pid]),
+            hydro_get_comoving_density(&main_cell->parts[pid]),
 #if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
             0.f,
 #else
@@ -297,7 +297,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
               "%13e %13e %13e\n",
               cj->parts[pjd].id, cj->parts[pjd].x[0], cj->parts[pjd].x[1],
               cj->parts[pjd].x[2], cj->parts[pjd].v[0], cj->parts[pjd].v[1],
-              cj->parts[pjd].v[2], hydro_get_density(&cj->parts[pjd]),
+              cj->parts[pjd].v[2], hydro_get_comoving_density(&cj->parts[pjd]),
 #if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
               0.f,
 #else
@@ -450,6 +450,10 @@ int main(int argc, char *argv[]) {
   engine.hydro_properties = &hp;
   engine.nodeID = NODE_ID;
 
+  struct cosmology cosmo;
+  cosmology_init_no_cosmo(&cosmo);
+  engine.cosmology = &cosmo;
+
   struct runner runner;
   runner.e = &engine;
 
@@ -539,7 +543,7 @@ int main(int argc, char *argv[]) {
     time += toc - tic;
 
     /* Let's get physical ! */
-    end_calculation(main_cell);
+    end_calculation(main_cell, &cosmo);
 
     /* Dump if necessary */
     if (i % 50 == 0) {
@@ -587,7 +591,7 @@ int main(int argc, char *argv[]) {
   const ticks toc = getticks();
 
   /* Let's get physical ! */
-  end_calculation(main_cell);
+  end_calculation(main_cell, &cosmo);
 
   /* Dump */
   sprintf(outputFileName, "brute_force_27_%s.dat", outputFileNameExtension);
diff --git a/tests/testActivePair.c b/tests/testActivePair.c
index 447f812df63db97d2b4320f898289bd521eaab3f..62d46c5c0a21d49bf1cb8317ad192c9eabf59c4d 100644
--- a/tests/testActivePair.c
+++ b/tests/testActivePair.c
@@ -179,9 +179,9 @@ void zero_particle_fields(struct cell *c) {
 /**
  * @brief Ends the loop by adding the appropriate coefficients
  */
-void end_calculation(struct cell *c) {
+void end_calculation(struct cell *c, const struct cosmology *cosmo) {
   for (int pid = 0; pid < c->count; pid++) {
-    hydro_end_density(&c->parts[pid]);
+    hydro_end_density(&c->parts[pid], cosmo);
 
     /* Recover the common "Neighbour number" definition */
     c->parts[pid].density.wcount *= pow_dimension(c->parts[pid].h);
@@ -246,8 +246,8 @@ void test_pair_interactions(struct runner *runner, struct cell **ci,
   vec_interaction(runner, *ci, *cj);
 
   /* Let's get physical ! */
-  end_calculation(*ci);
-  end_calculation(*cj);
+  end_calculation(*ci, runner->e->cosmology);
+  end_calculation(*cj, runner->e->cosmology);
 
   /* Dump if necessary */
   dump_particle_fields(swiftOutputFileName, *ci, *cj);
@@ -262,8 +262,8 @@ void test_pair_interactions(struct runner *runner, struct cell **ci,
   serial_interaction(runner, *ci, *cj);
 
   /* Let's get physical ! */
-  end_calculation(*ci);
-  end_calculation(*cj);
+  end_calculation(*ci, runner->e->cosmology);
+  end_calculation(*cj, runner->e->cosmology);
 
   dump_particle_fields(bruteForceOutputFileName, *ci, *cj);
 }
@@ -425,6 +425,7 @@ int main(int argc, char *argv[]) {
   double perturbation = 0.1, h_pert = 1.1;
   struct space space;
   struct engine engine;
+  struct cosmology cosmo;
   struct runner *runner;
   char c;
   static long long partId = 0;
@@ -507,6 +508,9 @@ int main(int argc, char *argv[]) {
   engine.max_active_bin = num_time_bins;
   engine.nodeID = NODE_ID;
 
+  cosmology_init_no_cosmo(&cosmo);
+  engine.cosmology = &cosmo;
+
   if (posix_memalign((void **)&runner, SWIFT_STRUCT_ALIGNMENT,
                      sizeof(struct runner)) != 0) {
     error("couldn't allocate runner");
diff --git a/tests/testAdiabaticIndex.c b/tests/testAdiabaticIndex.c
index e0c8c4f54bd2d6e5ddadb25bc44b96f1ca19aad2..64a60fd2aa1f85a9a28fa312922f5fd68daa62d7 100644
--- a/tests/testAdiabaticIndex.c
+++ b/tests/testAdiabaticIndex.c
@@ -17,22 +17,25 @@
  *
  ******************************************************************************/
 
-#include "adiabatic_index.h"
-#include "error.h"
+#include "../config.h"
+
+#include <fenv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swift.h"
 
 /**
- * @brief Check that a and b are consistent (up to some absolute error)
+ * @brief Check that a and b are consistent (up to some relative error)
  *
  * @param a First value
  * @param b Second value
  * @param s String used to identify this check in messages
  */
 void check_value(float a, float b, const char* s) {
-  if (fabsf(a - b) > 1.e-5f) {
-    error("Values are inconsistent: %g %g (%s)!", a, b, s);
-  } else {
-    message("Values are consistent: %g %g (%s).", a, b, s);
-  }
+  if (fabsf(a - b) / fabsf(a + b) > 1.e-6f)
+    error("Values are inconsistent: %12.15e %12.15e (%s)!", a, b, s);
 }
 
 /**
@@ -72,33 +75,41 @@ void check_constants() {
  * @brief Check that the adiabatic index power functions return the correct
  * values
  */
-void check_functions() {
+void check_functions(float x) {
+
   float val_a, val_b;
-  const float x = 0.4;
 
-  val_a = pow(x, -hydro_gamma);
+  val_a = powf(x, -hydro_gamma);
   val_b = pow_minus_gamma(x);
   check_value(val_a, val_b, "x^(-gamma)");
 
-  val_a = pow(x, 2.0f / (hydro_gamma - 1.0f));
+  val_a = powf(x, 2.0f / (hydro_gamma - 1.0f));
   val_b = pow_two_over_gamma_minus_one(x);
   check_value(val_a, val_b, "x^(2/(gamma-1))");
 
-  val_a = pow(x, 2.0f * hydro_gamma / (hydro_gamma - 1.0f));
+  val_a = powf(x, 2.0f * hydro_gamma / (hydro_gamma - 1.0f));
   val_b = pow_two_gamma_over_gamma_minus_one(x);
   check_value(val_a, val_b, "x^((2 gamma)/(gamma-1))");
 
-  val_a = pow(x, 0.5f * (hydro_gamma - 1.0f) / hydro_gamma);
+  val_a = powf(x, 0.5f * (hydro_gamma - 1.0f) / hydro_gamma);
   val_b = pow_gamma_minus_one_over_two_gamma(x);
   check_value(val_a, val_b, "x^((gamma-1)/(2 gamma))");
 
-  val_a = pow(x, -0.5f * (hydro_gamma + 1.0f) / hydro_gamma);
+  val_a = powf(x, -0.5f * (hydro_gamma + 1.0f) / hydro_gamma);
   val_b = pow_minus_gamma_plus_one_over_two_gamma(x);
   check_value(val_a, val_b, "x^(-(gamma+1)/(2 gamma))");
 
-  val_a = pow(x, 1.0f / hydro_gamma);
+  val_a = powf(x, 1.0f / hydro_gamma);
   val_b = pow_one_over_gamma(x);
   check_value(val_a, val_b, "x^(1/gamma)");
+
+  val_a = powf(x, 3.f * hydro_gamma - 2.f);
+  val_b = pow_three_gamma_minus_two(x);
+  check_value(val_a, val_b, "x^(3gamma - 2)");
+
+  val_a = powf(x, (3.f * hydro_gamma - 5.f) / 2.f);
+  val_b = pow_three_gamma_minus_five_over_two(x);
+  check_value(val_a, val_b, "x^((3gamma - 5)/2)");
 }
 
 /**
@@ -106,11 +117,34 @@ void check_functions() {
  */
 int main() {
 
+  /* Initialize CPU frequency, this also starts time. */
+  unsigned long long cpufreq = 0;
+  clocks_set_cpufreq(cpufreq);
+
+/* Choke on FPEs */
+#ifdef HAVE_FE_ENABLE_EXCEPT
+  feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
+#endif
+
+  message("Testing for gamma=%f", hydro_gamma);
+
+  /* Get some randomness going */
+  const int seed = time(NULL);
+  message("Seed = %d", seed);
+  srand(seed);
+
   /* check the values of the adiabatic index constants */
   check_constants();
 
-  /* check the adiabatic index power functions */
-  check_functions();
+  for (int i = 0; i < 100; ++i) {
+
+    const float x = random_uniform(0., 100.);
+
+    message("Random test %d/100 (x=%e)", i, x);
+
+    /* check the adiabatic index power functions */
+    check_functions(x);
+  }
 
   return 0;
 }
diff --git a/tests/testInteractions.c b/tests/testInteractions.c
index 76ee5078819882c38e3e57ac33bc4ee3ae6fc67e..31b7eb431da6fc12e767bc9053a21dc9ef010598 100644
--- a/tests/testInteractions.c
+++ b/tests/testInteractions.c
@@ -130,15 +130,15 @@ void dump_indv_particle_fields(char *fileName, struct part *p) {
           "%8.5f "
           "%8.5f %8.5f %13e %13e %13e %13e %13e %8.5f %8.5f\n",
           p->id, p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->h,
-          hydro_get_density(p),
+          hydro_get_comoving_density(p),
 #if defined(MINIMAL_SPH) || defined(SHADOWFAX_SPH)
           0.f,
 #else
           p->density.div_v,
 #endif
-          hydro_get_entropy(p), hydro_get_internal_energy(p),
-          hydro_get_pressure(p), hydro_get_soundspeed(p), p->a_hydro[0],
-          p->a_hydro[1], p->a_hydro[2], p->force.h_dt,
+          hydro_get_comoving_entropy(p), hydro_get_comoving_internal_energy(p),
+          hydro_get_comoving_pressure(p), hydro_get_comoving_soundspeed(p),
+          p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->force.h_dt,
 #if defined(GADGET2_SPH)
           p->force.v_sig, p->entropy_dt, 0.f
 #elif defined(DEFAULT_SPH)
@@ -213,6 +213,9 @@ void test_interactions(struct part test_part, struct part *parts, size_t count,
   ticks serial_time = 0;
   ticks vec_time = 0;
 
+  const float a = 1.f;
+  const float H = 0.f;
+
   char serial_filename[200] = "";
   char vec_filename[200] = "";
 
@@ -274,7 +277,7 @@ void test_interactions(struct part test_part, struct part *parts, size_t count,
 #endif
     for (size_t i = 0; i < count; i++) {
       IACT(r2[i], &(dx[3 * i]), pi_serial.h, pj_serial[i].h, &pi_serial,
-           &pj_serial[i]);
+           &pj_serial[i], a, H);
     }
     serial_time += getticks() - tic;
   }
@@ -419,6 +422,9 @@ void test_force_interactions(struct part test_part, struct part *parts,
   char serial_filename[200] = "";
   char vec_filename[200] = "";
 
+  const float a = 1.f;
+  const float H = 0.f;
+
   strcpy(serial_filename, filePrefix);
   strcpy(vec_filename, filePrefix);
   sprintf(serial_filename + strlen(serial_filename), "_serial.dat");
@@ -497,7 +503,7 @@ void test_force_interactions(struct part test_part, struct part *parts,
 #endif
     for (size_t i = 0; i < count; i++) {
       runner_iact_nonsym_force(r2[i], &(dx[3 * i]), pi_serial.h, pj_serial[i].h,
-                               &pi_serial, &pj_serial[i]);
+                               &pi_serial, &pj_serial[i], a, H);
     }
     serial_time += getticks() - tic;
   }
diff --git a/tests/testPeriodicBC.c b/tests/testPeriodicBC.c
index f2929061a2449a76f5e5cee0412bd7c90865fbf8..ffbb37a99781e6a4aed6e34fe016f239d949c870 100644
--- a/tests/testPeriodicBC.c
+++ b/tests/testPeriodicBC.c
@@ -204,9 +204,9 @@ void zero_particle_fields(struct cell *c) {
 /**
  * @brief Ends the loop by adding the appropriate coefficients
  */
-void end_calculation(struct cell *c) {
+void end_calculation(struct cell *c, const struct cosmology *cosmo) {
   for (int pid = 0; pid < c->count; pid++) {
-    hydro_end_density(&c->parts[pid]);
+    hydro_end_density(&c->parts[pid], cosmo);
   }
 }
 
@@ -236,7 +236,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, int i, int j,
             main_cell->parts[pid].x[1], main_cell->parts[pid].x[2],
             main_cell->parts[pid].v[0], main_cell->parts[pid].v[1],
             main_cell->parts[pid].v[2],
-            hydro_get_density(&main_cell->parts[pid]),
+            hydro_get_comoving_density(&main_cell->parts[pid]),
 #if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
             0.f,
 #else
@@ -332,7 +332,7 @@ void test_boundary_conditions(struct cell **cells, struct runner runner,
 #endif
 
   /* Let's get physical ! */
-  end_calculation(main_cell);
+  end_calculation(main_cell, runner.e->cosmology);
 
   /* Dump particles from the main cell. */
   dump_particle_fields(swiftOutputFileName, main_cell, loc_i, loc_j, loc_k);
@@ -370,7 +370,7 @@ void test_boundary_conditions(struct cell **cells, struct runner runner,
 #endif
 
   /* Let's get physical ! */
-  end_calculation(main_cell);
+  end_calculation(main_cell, runner.e->cosmology);
 
   /* Dump */
   dump_particle_fields(bruteForceOutputFileName, main_cell, loc_i, loc_j,
@@ -496,6 +496,10 @@ int main(int argc, char *argv[]) {
   struct runner runner;
   runner.e = &engine;
 
+  struct cosmology cosmo;
+  cosmology_init_no_cosmo(&cosmo);
+  engine.cosmology = &cosmo;
+
   /* Construct some cells */
   struct cell *cells[dim * dim * dim];
   static long long partId = 0;
diff --git a/tests/testSymmetry.c b/tests/testSymmetry.c
index 2e950c5c79f84d601b8d034927b174ac0454de68..7a62f735b57b3a8fe5b91308b4dfe8ce00706e0e 100644
--- a/tests/testSymmetry.c
+++ b/tests/testSymmetry.c
@@ -41,6 +41,10 @@ void test() {
 /*  voronoi_set_box(box_anchor, box_side);*/
 #endif
 
+  /* Start with some values for the cosmological paramters */
+  const float a = (float)random_uniform(0.8, 1.);
+  const float H = 1.f;
+
   /* Create two random particles (don't do this at home !) */
   struct part pi, pj;
   for (size_t i = 0; i < sizeof(struct part) / sizeof(float); ++i) {
@@ -137,20 +141,17 @@ void test() {
   /* --- Test the density loop --- */
 
   /* Call the symmetric version */
-  runner_iact_density(r2, dx, pi.h, pj.h, &pi, &pj);
-  /* Now the chemistry. WARNING chemistry is not initialized */
-  runner_iact_chemistry(r2, dx, pi.h, pj.h, &pi, &pj);
+  runner_iact_density(r2, dx, pi.h, pj.h, &pi, &pj, a, H);
+  runner_iact_chemistry(r2, dx, pi.h, pj.h, &pi, &pj, a, H);
 
   /* Call the non-symmetric version */
-  runner_iact_nonsym_density(r2, dx, pi2.h, pj2.h, &pi2, &pj2);
-  /* Now the chemistry. WARNING chemistry is not initialized */
-  runner_iact_nonsym_chemistry(r2, dx, pi2.h, pj2.h, &pi2, &pj2);
+  runner_iact_nonsym_density(r2, dx, pi2.h, pj2.h, &pi2, &pj2, a, H);
+  runner_iact_nonsym_chemistry(r2, dx, pi2.h, pj2.h, &pi2, &pj2, a, H);
   dx[0] = -dx[0];
   dx[1] = -dx[1];
   dx[2] = -dx[2];
-  runner_iact_nonsym_density(r2, dx, pj2.h, pi2.h, &pj2, &pi2);
-  /* Now the chemistry. WARNING chemistry is not initialized */
-  runner_iact_nonsym_chemistry(r2, dx, pj2.h, pi2.h, &pj2, &pi2);
+  runner_iact_nonsym_density(r2, dx, pj2.h, pi2.h, &pj2, &pi2, a, H);
+  runner_iact_nonsym_chemistry(r2, dx, pj2.h, pi2.h, &pj2, &pi2, a, H);
 
   /* Check that the particles are the same */
   i_not_ok = memcmp(&pi, &pi2, sizeof(struct part));
@@ -162,14 +163,14 @@ void test() {
   /* --- Test the force loop --- */
 
   /* Call the symmetric version */
-  runner_iact_force(r2, dx, pi.h, pj.h, &pi, &pj);
+  runner_iact_force(r2, dx, pi.h, pj.h, &pi, &pj, a, H);
 
   /* Call the non-symmetric version */
-  runner_iact_nonsym_force(r2, dx, pi2.h, pj2.h, &pi2, &pj2);
+  runner_iact_nonsym_force(r2, dx, pi2.h, pj2.h, &pi2, &pj2, a, H);
   dx[0] = -dx[0];
   dx[1] = -dx[1];
   dx[2] = -dx[2];
-  runner_iact_nonsym_force(r2, dx, pj2.h, pi2.h, &pj2, &pi2);
+  runner_iact_nonsym_force(r2, dx, pj2.h, pi2.h, &pj2, &pi2, a, H);
 
 /* Check that the particles are the same */
 #if defined(GIZMO_SPH)
diff --git a/tests/testTimeIntegration.c b/tests/testTimeIntegration.c
index 42a3d224f43d580e512119edc55051bd22719a3b..972e6f2323c0401c70de2990bcb088f95b3dfd83 100644
--- a/tests/testTimeIntegration.c
+++ b/tests/testTimeIntegration.c
@@ -95,8 +95,8 @@ int main() {
   run.e = &eng;
 
   eng.time = 0.;
-  eng.timeBegin = 0.;
-  eng.timeEnd = N_orbits * T;
+  eng.time_begin = 0.;
+  eng.time_end = N_orbits * T;
   eng.dt_min = dt; /* This forces the time-step to be dt        */
   eng.dt_max = dt; /* irrespective of the state of the particle */
 
@@ -104,7 +104,7 @@ int main() {
   for (i = 0; i < N; i++) {
 
     /* Move forward in time */
-    eng.timeOld = eng.time;
+    eng.time_old = eng.time;
     eng.time += dt;
 
     /* Compute gravitational acceleration */
diff --git a/theory/Cosmology/bibliography.bib b/theory/Cosmology/bibliography.bib
new file mode 100644
index 0000000000000000000000000000000000000000..6979bf7dd23bdb8543ac8752c12432837480d4ed
--- /dev/null
+++ b/theory/Cosmology/bibliography.bib
@@ -0,0 +1,140 @@
+@ARTICLE{Springel2005,
+   author = {{Springel}, V.},
+    title = "{The cosmological simulation code GADGET-2}",
+  journal = {\mnras},
+   eprint = {astro-ph/0505010},
+ keywords = {methods: numerical, galaxies: interactions, dark matter},
+     year = 2005,
+    month = dec,
+   volume = 364,
+    pages = {1105-1134},
+      doi = {10.1111/j.1365-2966.2005.09655.x},
+   adsurl = {http://adsabs.harvard.edu/abs/2005MNRAS.364.1105S},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+@ARTICLE{Wright2006,
+   author = {{Wright}, E.~L.},
+    title = "{A Cosmology Calculator for the World Wide Web}",
+  journal = {\pasp},
+   eprint = {astro-ph/0609593},
+ keywords = {Cosmology: Miscellaneous, Methods: Miscellaneous},
+     year = 2006,
+    month = dec,
+   volume = 118,
+    pages = {1711-1715},
+      doi = {10.1086/510102},
+   adsurl = {http://adsabs.harvard.edu/abs/2006PASP..118.1711W},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+
+@ARTICLE{Quinn1997,
+   author = {{Quinn}, T. and {Katz}, N. and {Stadel}, J. and {Lake}, G.},
+    title = "{Time stepping N-body simulations}",
+  journal = {ArXiv Astrophysics e-prints},
+   eprint = {astro-ph/9710043},
+ keywords = {Astrophysics},
+     year = 1997,
+    month = oct,
+   adsurl = {http://adsabs.harvard.edu/abs/1997astro.ph.10043Q},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+@ARTICLE{Linder2003,
+   author = {{Linder}, E.~V. and {Jenkins}, A.},
+    title = "{Cosmic structure growth and dark energy}",
+  journal = {\mnras},
+   eprint = {astro-ph/0305286},
+ keywords = {gravitation, methods: numerical, cosmological parameters},
+     year = 2003,
+    month = dec,
+   volume = 346,
+    pages = {573-583},
+      doi = {10.1046/j.1365-2966.2003.07112.x},
+   adsurl = {http://adsabs.harvard.edu/abs/2003MNRAS.346..573L},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+@book{GSL,
+ author = {Gough, Brian},
+ title = {GNU Scientific Library Reference Manual - Third Edition},
+ year = {2009},
+ isbn = {0954612078, 9780954612078},
+ edition = {3rd},
+ publisher = {Network Theory Ltd.},
+}
+
+@ARTICLE{Springel2002,
+   author = {{Springel}, V. and {Hernquist}, L.},
+    title = "{Cosmological smoothed particle hydrodynamics simulations: the entropy equation}",
+  journal = {\mnras},
+   eprint = {astro-ph/0111016},
+ keywords = {methods: numerical, galaxies: evolution, galaxies: starburst, methods: numerical, galaxies: evolution, galaxies: starburst},
+     year = 2002,
+    month = jul,
+   volume = 333,
+    pages = {649-664},
+      doi = {10.1046/j.1365-8711.2002.05445.x},
+   adsurl = {http://adsabs.harvard.edu/abs/2002MNRAS.333..649S},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+
+@BOOK{Peebles1980,
+   author = {{Peebles}, P.~J.~E.},
+    title = "{The large-scale structure of the universe}",
+ keywords = {Cosmology, Galactic Clusters, Galactic Evolution, Universe, Astronomical Models, Correlation, Mass Distribution, Particle Motion, Relativistic Theory, Statistical Distributions},
+booktitle = {Research supported by the National Science Foundation.~Princeton, N.J., Princeton University Press, 1980.~435 p.},
+     year = 1980,
+   adsurl = {http://adsabs.harvard.edu/abs/1980lssu.book.....P},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+
+
+@ARTICLE{Hopkins2013,
+   author = {{Hopkins}, P.~F.},
+    title = "{A general class of Lagrangian smoothed particle hydrodynamics methods and implications for fluid mixing problems}",
+  journal = {\mnras},
+archivePrefix = "arXiv",
+   eprint = {1206.5006},
+ primaryClass = "astro-ph.IM",
+ keywords = {hydrodynamics, instabilities, turbulence, methods: numerical, cosmology: theory},
+     year = 2013,
+    month = feb,
+   volume = 428,
+    pages = {2840-2856},
+      doi = {10.1093/mnras/sts210},
+   adsurl = {http://adsabs.harvard.edu/abs/2013MNRAS.428.2840H},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+@ARTICLE{Price2012,
+   author = {{Price}, D.~J.},
+    title = "{Smoothed particle hydrodynamics and magnetohydrodynamics}",
+  journal = {Journal of Computational Physics},
+archivePrefix = "arXiv",
+   eprint = {1012.1885},
+ primaryClass = "astro-ph.IM",
+     year = 2012,
+    month = feb,
+   volume = 231,
+    pages = {759-794},
+      doi = {10.1016/j.jcp.2010.12.011},
+   adsurl = {http://adsabs.harvard.edu/abs/2012JCoPh.231..759P},
+  adsnote = {Provided by the SAO/NASA Astrophysics Data System}
+}
+
+@article{Monaghan1997,
+title = "SPH and Riemann Solvers",
+journal = "Journal of Computational Physics",
+volume = "136",
+number = "2",
+pages = "298 - 307",
+year = "1997",
+issn = "0021-9991",
+doi = "https://doi.org/10.1006/jcph.1997.5732",
+url = "http://www.sciencedirect.com/science/article/pii/S0021999197957326",
+author = "J.J. Monaghan"
+}
\ No newline at end of file
diff --git a/theory/Cosmology/coordinates.tex b/theory/Cosmology/coordinates.tex
new file mode 100644
index 0000000000000000000000000000000000000000..56354623ea5a4127306c13f122e6f45223c7309d
--- /dev/null
+++ b/theory/Cosmology/coordinates.tex
@@ -0,0 +1,126 @@
+\subsection{Choice of co-moving coordinates}
+\label{ssec:ccordinates}
+
+Note that, unlike the \gadget convention, we do not express quantities with
+``little h'' ($h$) included; for instance units of length are expressed in
+units of $\rm{Mpc}$ and not ${\rm{Mpc}}/h$. Similarly, the time integration
+operators (see below) also include an $h$-factor via the explicit appearance of
+the Hubble constant.\\
+In physical coordinates, the Lagrangian for a particle $i$ in the
+\cite{Springel2002} flavour of SPH with gravity reads
+\begin{equation}
+  \Lag =
+  \frac{1}{2} m_i \dot{\mathbf{r}}_i^2 -
+  \frac{1}{\gamma-1}m_iA_i\rho_i^{\gamma-1} -
+  m_i \phi
+\end{equation}
+Introducing the comoving positions $\mathbf{r}'$ such that $\mathbf{r}
+= a(t) \mathbf{r}'$ and comoving densities $\rho' \equiv a^3(t)\rho$,
+\begin{equation}
+  \Lag =
+  \frac{1}{2} m_i \left(a\dot{\mathbf{r}}_i' + \dot{a}\mathbf{r}_i'
+  \right)^2 - 
+  \frac{1}{\gamma-1}m_iA_i'\left(\frac{\rho_i'}{a^3}\right)^{\gamma-1}
+  - m_i \phi,
+\end{equation}
+where $A'=A$ is chosen such that the equation of state for
+the gas and thermodynamic relations between quantities have the same
+form (i.e. are scale-factor free) in the primed coordinates as
+well. This implies
+\begin{equation}
+  P' = a^{3\gamma}P,\quad u'=a^{3(\gamma-1)}u, \quad c'=a^{3(\gamma-1)/2}c,
+\end{equation}
+for the pressure, internal energy and sound-speed
+respectively. Following \cite{Peebles1980} (ch.7), we introduce the
+gauge transformation $\Lag \rightarrow \Lag + \frac{d}{dt}\Psi$ with
+$\Psi \equiv \frac{1}{2}a\dot{a}\mathbf{r}_i^2$ and obtain
+\begin{align}
+  \Lag &= \frac{1}{2}m_ia^2 \dot{\mathbf{r}}_i^2 -
+  \frac{1}{\gamma-1}m_iA_i'\left(\frac{\rho_i'}{a^3}\right)^{\gamma-1}
+  -\frac{\phi'}{a},\\
+  \phi' &= a\phi + \frac{1}{2}a^2\ddot{a}\mathbf{r}_i'^2.\nonumber
+\end{align}
+Finally, we introduce the velocities $\mathbf{v}' \equiv
+a^2\dot{\mathbf{r}'}$ that are used internally by the code. Note that these
+velocities \emph{do not} have a physical interpretation. We caution that they
+are not the peculiar velocities, nor the Hubble flow, nor the total
+velocities\footnote{One additional inconvenience of our choice of
+  generalised coordinates is that our velocities $\mathbf{v}'$ and
+  sound-speed $c'$ do not have the same dependencies on the
+  scale-factor. The signal velocity entering the time-step calculation
+  will hence read $v_{\rm sig} = a\dot{\mathbf{r}'} + c = \frac{1}{a} \left(
+    |\mathbf{v}'| + a^{(5 - 3\gamma)/2}c'\right)$.}.
+This choice implies that $\dot{v}' = a \ddot{r}$. Using the SPH
+definition of density, $\rho_i =
+\sum_jm_jW(\mathbf{r}_{j}'-\mathbf{r}_{i}',h_i') =
+\sum_jm_jW_{ij}'(h_i')$, we can follow \cite{Price2012} and apply the
+Euler-Lagrange equations to write
+\begin{alignat}{3}
+  \dot{\mathbf{r}}_i'&= \frac{1}{a^2} \mathbf{v}_i'&  \label{eq:cosmo_eom_r} \\
+  \dot{\mathbf{v}}_i' &= -\sum_j m_j &&\left[\frac{1}{a^{3(\gamma-1)}}f_i'A_i'\rho_i'^{\gamma-2}\mathbf{\nabla}_i'W_{ij}'(h_i)\right. \nonumber\\
+  &   && + \left. \frac{1}{a^{3(\gamma-1)}}f_j'A_j'\rho_j'^{\gamma-2}\mathbf{\nabla}_i'W_{ij}'(h_j)\right. \nonumber\\
+  &   && + \left. \frac{1}{a}\mathbf{\nabla}_i'\phi'\right] \label{eq:cosmo_eom_v}
+\end{alignat}
+with
+\begin{equation}
+    f_i' = \left[1 + \frac{h_i'}{3\rho_i'}\frac{\partial
+      \rho_i'}{\partial h_i'}\right]^{-1}, \qquad \mathbf{\nabla}_i'
+  \equiv \frac{\partial}{\partial \mathbf{r}_{i}'}. \nonumber
+\end{equation}
+These correspond to the equations of motion for density-entropy SPH
+\citep[e.g. eq. 14 of][]{Hopkins2013} with cosmological and
+gravitational terms. SPH flavours that evolve the internal energy $u$ instead of the
+entropy require the additional equation of motion describing the evolution of
+$u'$:
+\begin{equation}
+  \dot{u}_i' = \frac{P_i'}{\rho_i'^2}\left[3H\rho_i' + \frac{1}{a^2}f_i'\sum_jm_j\left(\mathbf{v}_i' -
+    \mathbf{v}_j'\right)\cdot\mathbf{\nabla}_i'W_{ij}'(h_i)\right],
+  \label{eq:cosmo_eom_u}
+\end{equation}
+where the first term in the brackets accounts for the change in energy
+due to the expansion of the Universe. The scale-factors appearing in
+the equations are later absorbed in the time-integration operators
+(Sec.~\ref{ssec:operators}) such that the RHS of the equations of
+motions is identical for the primed quantities to the ones obtained in
+the non-cosmological case for the physical quantities.
+
+Additional terms in the SPH equations of motion (e.g. viscosity
+switches) often rely on the velocity divergence and curl. Their SPH
+estimators $\langle\cdot\rangle$ in physical coordinates can be
+related to their estimators based on our primed-coordinates using:
+\begin{align}
+  \left\langle \mathbf{\nabla}\cdot\dot{\mathbf{r}}_i \right\rangle &=
+  \frac{1}{a^2} \left\langle
+  \mathbf{\nabla}'\cdot\mathbf{v}_i'\right\rangle =
+  \frac{1}{a^2\rho_i'}\sum_j m_j\left(\mathbf{v}_j' -
+  \mathbf{v}_i'\right) \cdot \mathbf{\nabla}_i'W_{ij}'(h_i), \nonumber \\
+  \left\langle \mathbf{\nabla}\times\dot{\mathbf{r}}_i \right\rangle &=
+  \frac{1}{a^2} \left\langle
+  \mathbf{\nabla}'\times\mathbf{v}_i'\right\rangle =
+  \frac{1}{a^2\rho_i'}\sum_j m_j\left(\mathbf{v}_j' -
+  \mathbf{v}_i'\right) \times \mathbf{\nabla}_i'W_{ij}'(h_i). \nonumber
+\end{align}
+We finally give the expressions for the \cite{Monaghan1997} viscosity
+term, that enters most SPH flavours, in our system of coordinates. The
+viscosity ``tensor'' $\Pi_{ij} \equiv \frac{1}{2}\alpha_{\rm visc} v_{\rm
+    sig}'\mu_{ij}/\left(\rho_i + \rho_j\right)$ can be computed
+  in the primmed coordinates from the following quantities
+\begin{align}
+  \omega_{ij}' &= \left(\mathbf{v}_i' - \mathbf{v}_j'\right) \cdot
+  \left(\mathbf{r}_i' - \mathbf{r}_j'\right), \\
+  \mu_{ij}' &=
+  a^{(3\gamma-5)/2} \left(\omega_{ij}' + a^2H\left|\mathbf{r}_i' -
+  \mathbf{r}_j'\right|^2 \right) / |\mathbf{r}_i' - \mathbf{r}_j' |,
+  \\
+  v_{\rm sig}' &= c_i' + c_j' - 3 \mu_{ij}'.
+\end{align}
+which leads to $\Pi_{ij}'=a^{3\gamma}\Pi_{ij}$. Note that he last quantity is
+also used to compute the time-step size. The evolution of entropy is
+then
+\begin{equation}
+  \dot{A}_i = \dot{A}_i' = \frac{1}{a^2}\frac{1}{2}\frac{\gamma-1}{\rho_i'^{\gamma-1}} \sum_j
+  m_j \Pi_{ij}' \left(\mathbf{v}_i' -
+  \mathbf{v}_j'\right)\cdot\mathbf{\nabla}_i'W_{ij}'(h_i),
+\end{equation}
+indicating that the entropy evolves with the same scale-factor
+dependence as the comoving positions (eq.~\ref{eq:cosmo_eom_r}).
diff --git a/theory/Cosmology/cosmology_standalone.tex b/theory/Cosmology/cosmology_standalone.tex
new file mode 100644
index 0000000000000000000000000000000000000000..7f4e7afd3f0d7725b7ee36a245428e19376d1d0c
--- /dev/null
+++ b/theory/Cosmology/cosmology_standalone.tex
@@ -0,0 +1,48 @@
+\documentclass[fleqn, usenatbib, useAMS, a4paper]{mnras}
+\usepackage{graphicx}
+\usepackage{amsmath,paralist,xcolor,xspace,amssymb}
+\usepackage{times}
+\usepackage{comment}
+\usepackage[super]{nth}
+
+\newcommand{\todo}[1]{{\textcolor{red}{#1}}}
+\newcommand{\gadget}{{\sc Gadget}\xspace}
+\newcommand{\swift}{{\sc Swift}\xspace}
+\newcommand{\nbody}{$N$-body\xspace}
+\newcommand{\Lag}{\mathcal{L}}
+
+%opening
+\title{Cosmology equations in SWIFT}
+\author{Matthieu Schaller}
+\begin{document}
+
+\date{\today}
+
+\pagerange{\pageref{firstpage}--\pageref{lastpage}} \pubyear{2018}
+
+\maketitle
+
+\label{firstpage}
+
+\begin{abstract}
+Making cosmology great again.
+\end{abstract}
+
+\begin{keywords}
+\end{keywords}
+
+\section{Cosmology equations in \swift}
+\label{sec:cosmo}
+
+\input{flrw}
+
+\input{coordinates}
+
+\input{operators}
+
+\bibliographystyle{mnras}
+\bibliography{./bibliography.bib}
+
+\label{lastpage}
+
+\end{document}
diff --git a/theory/Cosmology/flrw.tex b/theory/Cosmology/flrw.tex
new file mode 100644
index 0000000000000000000000000000000000000000..c50f44c19cfd4da2ad6ff187759edf721001c326
--- /dev/null
+++ b/theory/Cosmology/flrw.tex
@@ -0,0 +1,58 @@
+\subsection{Background evolution}
+\label{ssec:flrw}
+
+In \swift we assume a standard FLRW metric for the evolution of the background
+density of the Universe and use the Friedmann equations to describe the
+evolution of the scale-factor $a(t)$.  We scale $a$ such that its present-day
+value is $a_0 \equiv a(t=t_{\rm now}) = 1$. We also define redshift $z \equiv
+1/a - 1$ and the Hubble parameter
+\begin{equation}
+H(t) \equiv \frac{\dot{a}(t)}{a(t)}
+\end{equation}
+with its present-day value denoted as $H_0 = H(t=t_{\rm now})$. Following
+normal conventions we write $H_0 = 100
+h~\rm{km}\cdot\rm{s}^{-1}\cdot\rm{Mpc}^{-1}$ and use $h$ as the input parameter
+for the Hubble constant.
+
+To allow for general expansion histories we use the full Friedmann equations
+and write
+\begin{align}
+H(a) &\equiv H_0 E(a) \\ E(a) &\equiv\sqrt{\Omega_m a^{-3} + \Omega_r
+  a^{-4} + \Omega_k a^{-2} + \Omega_\Lambda \exp\left(3\tilde{w}(a)\right)},
+\\
+\tilde{w}(a) &= (a-1)w_a - (1+w_0 + w_a)\log\left(a\right),
+\label{eq:friedmann}
+\end{align}
+where we followed \cite{Linder2003} to parametrize the evolution of
+the dark-energy equation-of-state\footnote{Note that $\tilde{w}(z)\equiv
+  \int_0^z \frac{1+w(z')}{1+z'}dz'$, which leads to the analytic
+  expression we use.} as:
+\begin{equation}
+w(a) \equiv w_0 + w_a~(1-a).
+\end{equation}
+The cosmological model is hence fully defined by specifying the dimensionless
+constants $\Omega_m$, $\Omega_r$, $\Omega_k$, $\Omega_\Lambda$, $h$, $w_0$ and
+$w_a$ as well as the starting redshift (or scale-factor of the simulation)
+$a_{\rm start}$ and final time $a_{\rm end}$. \\ At any scale-factor $a_{\rm
+age}$, the time $t_{\rm age}$ since the Big Bang (age of the Universe) can be
+computed as \citep[e.g.][]{Wright2006}:
+\begin{equation}
+  t_{\rm age} = \int_{0}^{a_{\rm age}} dt = \int_{0}^{a_{\rm age}}
+  \frac{da}{a H(a)} = \frac{1}{H_0} \int_{0}^{a_{\rm age}}
+  \frac{da}{a E(a)}.
+\end{equation}
+For a general set of cosmological parameters, this integral can only be
+evaluated numerically, which is too slow to be evaluated accurately during a
+run. At the start of the simulation we tabulate this integral for $10^4$ values
+of $a_{\rm age}$ equally spaced between $\log(a_{\rm start})$ and $\log(a_{\rm
+end})$. The values are obtained via adaptive quadrature using the 61-points
+Gauss-Konrod rule implemented in the {\sc gsl} library \citep{GSL} with a
+relative error limit of $\epsilon=10^{-10}$. The value for a specific $a$ (over
+the course of a simulation run) is then obtained by linear interpolation of the
+table.
+
+\subsubsection{Typical Values of the Cosmological Parameters}
+
+Typical values for the constants are: $\Omega_m = 0.3, \Omega_\Lambda=0.7, 0 <
+\Omega_r<10^{-3}, |\Omega_k | < 10^{-2}, h=0.7, a_{\rm start} = 10^{-2}, a_{\rm
+end} = 1, w_0 = -1\pm 0.1, w_a=0\pm0.2$ and $\gamma = 5/3$.
diff --git a/theory/Cosmology/operators.tex b/theory/Cosmology/operators.tex
new file mode 100644
index 0000000000000000000000000000000000000000..89aa32bae554dceba8f1525cb209728a17154f5b
--- /dev/null
+++ b/theory/Cosmology/operators.tex
@@ -0,0 +1,55 @@
+\subsection{Time-integration operators}
+\label{ssec:operators}
+For the choice of cosmological coordinates made in \swift, the normal
+``kick'' and ``drift'' operators get modified to account for the
+expansion of the Universe. The derivation of these operators from the
+system's Lagrangian is given in appendix A of \cite{Quinn1997} for the
+collision-less case. We do not repeat that derivation here but, for
+completeness, give the expressions we use as well as the ones used for
+the hydro-dynamics. 
+
+The ``drift'' operator gets modified such that $\Delta t$ for a
+time-step running from a scale-factor $a_{n}$ to $a_{n+1}$ becomes
+
+\begin{equation}
+  \Delta t_{\rm drift} \equiv \int_{a_n}^{a_{n+1}} \frac{dt}{a^2} = \frac{1}{H_0} \int_{a_n}^{a_{n+1}} \frac{da}{a^3E(a)},
+\end{equation}
+with $E(a)$ given by eq.~\ref{eq:friedmann}. Similarly, the time-step
+entering ``kick'' operator for collision-less acceleration reads
+\begin{equation}
+  \Delta t_{\rm kick,g} \equiv \int_{a_n}^{a_{n+1}} \frac{dt}{a} = \frac{1}{H_0} \int_{a_n}^{a_{n+1}} \frac{da}{a^2E(a)}.
+\end{equation}
+However, for the case of gas dynamics, given our choice of
+coordinates, the ``kick'' operator has a second variant that reads
+\begin{equation}
+  \Delta t_{\rm kick,h} \equiv \int_{a_n}^{a_{n+1}} \frac{dt}{a^{3(\gamma-1)}} = \frac{1}{H_0} \int_{a_n}^{a_{n+1}} \frac{da}{a^{3\gamma - 2}E(a)},
+\end{equation}
+where $\gamma$ is the adiabatic index of the gas.  Accelerations
+arising from hydrodynamic forces (\nth{1} and \nth{2} term in
+eq.~\ref{eq:cosmo_eom_v}) are integrated forward in time using $\Delta
+t_{\rm kick,h}$, whilst the accelerations given by the gravity forces
+(\nth{3} term in eq.~\ref{eq:cosmo_eom_v}) use $\Delta t_{\rm
+  kick,g}$. The entropy or internal energy is integrated forward in
+time using $\Delta t_{\rm kick,A} = \Delta t_{\rm
+  drift}$\footnote{Note that {\sc gadget-2} uses a slightly different
+  operator here. They first multiply $\dot{A}_i'$ by $1/H$ and do not
+  not consider the $1/a^2$ term as part of the time-integration
+  operator. They then use $\int H dt$ as the operator, which
+  integrates out trivially. This slight inconsistency with the rest of
+  the time-integration operators is unlikely to lead to any practical
+  difference.}, whilst the change in energy due to the expansion of
+the Universe (first term in eq.~\ref{eq:cosmo_eom_u}) can be computed
+using
+\begin{equation}
+  \int_{a_n}^{a_{n+1}} H dt = \int_{a_n}^{a_{n+1}} \frac{da}{a} =
+  \log{a_{n+1}} - \log{a_n}.
+\end{equation}
+Following the same method as for the age of the Universe
+(sec. \ref{ssec:flrw}), the three non-trivial integrals are evaluated
+numerically at the start of the simulation for a series $10^4$ values
+of $a$ placed at regular intervals between $\log a_{\rm begin}$ and
+$\log a_{\rm end}$. The values for a specific pair of scale-factors
+$a_n$ and $a_{n+1}$ are then obtained by interpolating that table
+linearly.
+
+
diff --git a/theory/Cosmology/run.sh b/theory/Cosmology/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b386ecadda7046ac886d32bd3ceb278e90f4d81c
--- /dev/null
+++ b/theory/Cosmology/run.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+echo "Generating PDF..."
+pdflatex -jobname=cosmology cosmology_standalone.tex
+bibtex cosmology.aux
+pdflatex -jobname=cosmology cosmology_standalone.tex
+pdflatex -jobname=cosmology cosmology_standalone.tex