diff --git a/.gitignore b/.gitignore
index 907d6b4685189f98f4d0895f23788cf6da382317..dba88cee0989e00baef51d9e75a42b1141d15714 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,6 +57,8 @@ tests/testTimeIntegration
 tests/testSPHStep
 tests/testKernel
 tests/testInteractions
+tests/testSymmetry
+tests/testMaths
 tests/testParser
 tests/parser_output.yml
 tests/test27cells.sh
diff --git a/examples/PerturbedBox/makeIC.py b/examples/PerturbedBox/makeIC.py
index ee1d845fc2149892909a54bf588046b0b1691b03..cc7fffe14d4f361153a07101ddcec20a3c979b4a 100644
--- a/examples/PerturbedBox/makeIC.py
+++ b/examples/PerturbedBox/makeIC.py
@@ -19,6 +19,7 @@
  ##############################################################################
 
 import h5py
+import sys
 import random
 from numpy import *
 
@@ -26,13 +27,13 @@ from numpy import *
 # at a constant density and pressure in a cubic box
 
 # Parameters
-periodic= 1      # 1 For periodic box
+periodic= 1          # 1 For periodic box
 boxSize = 1.
-L = 50           # Number of particles along one axis
-rho = 1.         # Density
-P = 1.           # Pressure
-gamma = 5./3.    # Gas adiabatic index
-pert = 0.01      # Perturbation scale (in units of the interparticle separation)
+L = int(sys.argv[1]) # Number of particles along one axis
+rho = 1.             # Density
+P = 1.               # Pressure
+gamma = 5./3.        # Gas adiabatic index
+pert = 0.01          # Perturbation scale (in units of the interparticle separation)
 fileName = "perturbedBox.hdf5" 
 
 
diff --git a/examples/PerturbedBox/perturbedBox.yml b/examples/PerturbedBox/perturbedBox.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3a445e27e74fb83fb8deb56fde6003c22f7dedf1
--- /dev/null
+++ b/examples/PerturbedBox/perturbedBox.yml
@@ -0,0 +1,35 @@
+# Define the system of units to use internally. 
+InternalUnitSystem:
+  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-3  # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  basename:            perturbedBox # Common part of the name of output files
+  time_first:          0.           # Time of the first output (in internal units)
+  delta_time:          1e-1         # Time difference between consecutive outputs (in internal units)
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  delta_time:          1e-3 # 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).
+  delta_neighbours:      0.1      # The tolerance for the targetted number of neighbours.
+  max_smoothing_length:  0.1      # Maximal smoothing length allowed (in internal units).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:  ./perturbedBox.hdf5     # The file to read
diff --git a/examples/PerturbedBox/run.sh b/examples/PerturbedBox/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c15011ca526efb7250e93dc8cb002e49647b82b6
--- /dev/null
+++ b/examples/PerturbedBox/run.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# Generate the initial conditions if they are not present.
+if [ ! -e perturbedBox.hdf5 ]
+then
+    echo "Generating initial conditions for the perturbed box example..."
+    python makeIC.py 50
+fi
+
+../swift -s -t 16 perturbedBox.yml
diff --git a/src/approx_math.h b/src/approx_math.h
index cbca602b3fafcc5044b0939b2207b8f9d50a7446..ad07adeb4f3b1b54ca5f33d80eabb6a004d2a3aa 100644
--- a/src/approx_math.h
+++ b/src/approx_math.h
@@ -24,12 +24,16 @@
 /**
  * @brief Approximate version of expf(x) using a 4th order Taylor expansion
  *
- * The absolute error is of order 10^-6 for -0.2 < x < 0.2.
+ * The absolute error is smaller than 3 * 10^-6 for -0.2 < x < 0.2.
+ * The absolute error is smaller than 2 * 10^-7 for -0.1 < x < 0.1.
+
+ * The relative error is smaller than 1 * 10^-6 for -0.2 < x < 0.2.
+ * The relative error is smaller than 4 * 10^-8 for -0.1 < x < 0.1.
  *
  * @param x The number to take the exponential of.
  */
 __attribute__((always_inline)) INLINE static float approx_expf(float x) {
-  return 1.f + x * (1.f + x * (0.5f + x * (1.f / 6.0f + 1.f / 24.0f * x)));
+  return 1.f + x * (1.f + x * (0.5f + x * (1.f / 6.f + 1.f / 24.f * x)));
 }
 
 #endif /* SWIFT_APPROX_MATH_H */
diff --git a/src/cell.h b/src/cell.h
index 9f35f4386cb161517b1b0c57468f1c0317c0c6a7..b9e060050827e6e0bbd62c87024bbf066d3807f8 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -152,7 +152,7 @@ struct cell {
   double mom[3], ang_mom[3];
 
   /* Mass, potential, internal  and kinetic energy of particles in this cell. */
-  double mass, e_pot, e_int, e_kin;
+  double mass, e_pot, e_int, e_kin, entropy;
 
   /* Number of particles updated in this cell. */
   int updated, g_updated;
diff --git a/src/engine.c b/src/engine.c
index 8e471466fad5bac7c17603a42a59fba50d8c024e..6609f7f0d53453c6649a8089d2b656f555e00f75 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -2098,7 +2098,7 @@ void engine_collect_drift(struct cell *c) {
   if (c->drift != NULL) return;
 
   /* Counters for the different quantities. */
-  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, mass = 0.0;
+  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, entropy = 0.0, mass = 0.0;
   double mom[3] = {0.0, 0.0, 0.0}, ang_mom[3] = {0.0, 0.0, 0.0};
 
   /* Only do something is the cell is non-empty */
@@ -2120,6 +2120,7 @@ void engine_collect_drift(struct cell *c) {
         e_kin += cp->e_kin;
         e_int += cp->e_int;
         e_pot += cp->e_pot;
+        entropy += cp->entropy;
         mom[0] += cp->mom[0];
         mom[1] += cp->mom[1];
         mom[2] += cp->mom[2];
@@ -2135,6 +2136,7 @@ void engine_collect_drift(struct cell *c) {
   c->e_kin = e_kin;
   c->e_int = e_int;
   c->e_pot = e_pot;
+  c->entropy = entropy;
   c->mom[0] = mom[0];
   c->mom[1] = mom[1];
   c->mom[2] = mom[2];
@@ -2151,7 +2153,7 @@ void engine_print_stats(struct engine *e) {
 
   const struct space *s = e->s;
 
-  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, mass = 0.0;
+  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, entropy = 0.0, mass = 0.0;
   double mom[3] = {0.0, 0.0, 0.0}, ang_mom[3] = {0.0, 0.0, 0.0};
 
   /* Collect the cell data. */
@@ -2167,6 +2169,7 @@ void engine_print_stats(struct engine *e) {
       e_kin += c->e_kin;
       e_int += c->e_int;
       e_pot += c->e_pot;
+      entropy += c->entropy;
       mom[0] += c->mom[0];
       mom[1] += c->mom[1];
       mom[2] += c->mom[2];
@@ -2178,8 +2181,8 @@ void engine_print_stats(struct engine *e) {
 /* Aggregate the data from the different nodes. */
 #ifdef WITH_MPI
   {
-    double in[10] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0.};
-    double out[10];
+    double in[11] = {0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.};
+    double out[11];
     out[0] = e_kin;
     out[1] = e_int;
     out[2] = e_pot;
@@ -2190,7 +2193,8 @@ void engine_print_stats(struct engine *e) {
     out[7] = ang_mom[1];
     out[8] = ang_mom[2];
     out[9] = mass;
-    if (MPI_Allreduce(out, in, 10, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) !=
+    out[10] = entropy;
+    if (MPI_Reduce(out, in, 11, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD) !=
         MPI_SUCCESS)
       error("Failed to aggregate stats.");
     e_kin = out[0];
@@ -2203,6 +2207,7 @@ void engine_print_stats(struct engine *e) {
     ang_mom[1] = out[7];
     ang_mom[2] = out[8];
     mass = out[9];
+    entropy = out[10];
   }
 #endif
 
@@ -2210,10 +2215,11 @@ void engine_print_stats(struct engine *e) {
 
   /* Print info */
   if (e->nodeID == 0) {
-    fprintf(e->file_stats,
-            " %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e\n",
-            e->time, mass, e_tot, e_kin, e_int, e_pot, mom[0], mom[1], mom[2],
-            ang_mom[0], ang_mom[1], ang_mom[2]);
+    fprintf(
+        e->file_stats,
+        " %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e\n",
+        e->time, mass, e_tot, e_kin, e_int, e_pot, entropy, mom[0], mom[1],
+        mom[2], ang_mom[0], ang_mom[1], ang_mom[2]);
     fflush(e->file_stats);
   }
 }
@@ -2973,10 +2979,11 @@ void engine_init(struct engine *e, struct space *s,
                                 engine_default_energy_file_name);
     sprintf(energyfileName + strlen(energyfileName), ".txt");
     e->file_stats = fopen(energyfileName, "w");
-    fprintf(e->file_stats,
-            "# %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s\n",
-            "Time", "Mass", "E_tot", "E_kin", "E_int", "E_pot", "p_x", "p_y",
-            "p_z", "ang_x", "ang_y", "ang_z");
+    fprintf(
+        e->file_stats,
+        "#%14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s\n",
+        "Time", "Mass", "E_tot", "E_kin", "E_int", "E_pot", "Entropy", "p_x",
+        "p_y", "p_z", "ang_x", "ang_y", "ang_z");
     fflush(e->file_stats);
 
     char timestepsfileName[200] = "";
diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h
index 7af9a22c7d12dad36f40e5eea1f69715ffd35c35..323f066db6a047db7ae3401a3525afa941bfc047 100644
--- a/src/hydro/Gadget2/hydro_iact.h
+++ b/src/hydro/Gadget2/hydro_iact.h
@@ -470,7 +470,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
 
   /* Change in entropy */
   pi->entropy_dt += 0.5f * mj * visc_term * dvdr;
-  pj->entropy_dt -= 0.5f * mi * visc_term * dvdr;
+  pj->entropy_dt += 0.5f * mi * visc_term * dvdr;
 }
 
 /**
diff --git a/src/runner.c b/src/runner.c
index e48d2ccaba69315f4295a0dbacd36e9c7d26a0c4..63243ab66d24a2efc045e19e866e24b7a0f4868c 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -593,7 +593,7 @@ void runner_do_drift(struct runner *r, struct cell *c, int timer) {
   struct gpart *restrict gparts = c->gparts;
   float dx_max = 0.f, dx2_max = 0.f, h_max = 0.f;
 
-  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, mass = 0.0;
+  double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, entropy = 0.0, mass = 0.0;
   double mom[3] = {0.0, 0.0, 0.0};
   double ang_mom[3] = {0.0, 0.0, 0.0};
 
@@ -670,6 +670,9 @@ void runner_do_drift(struct runner *r, struct cell *c, int timer) {
       e_kin += 0.5 * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
       e_pot += 0.;
       e_int += m * hydro_get_internal_energy(p, half_dt);
+
+      /* Collect entropy */
+      entropy += m * hydro_get_entropy(p, half_dt);
     }
 
     /* Now, get the maximal particle motion from its square */
@@ -694,6 +697,7 @@ void runner_do_drift(struct runner *r, struct cell *c, int timer) {
         e_kin += cp->e_kin;
         e_int += cp->e_int;
         e_pot += cp->e_pot;
+        entropy += cp->entropy;
         mom[0] += cp->mom[0];
         mom[1] += cp->mom[1];
         mom[2] += cp->mom[2];
@@ -710,6 +714,7 @@ void runner_do_drift(struct runner *r, struct cell *c, int timer) {
   c->e_kin = e_kin;
   c->e_int = e_int;
   c->e_pot = e_pot;
+  c->entropy = entropy;
   c->mom[0] = mom[0];
   c->mom[1] = mom[1];
   c->mom[2] = mom[2];
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 90220e972065a19878aa330af3d03c6988e4e2cf..4d6cb65ca6971d30fd6e39f52ce582c59cecb8b8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -21,20 +21,26 @@ AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) -DTIMER
 AM_LDFLAGS = ../src/.libs/libswiftsim.a $(HDF5_LDFLAGS) $(HDF5_LIBS)
 
 # List of programs and scripts to run in the test suite
-TESTS = testGreetings testReading.sh testSingle testPair.sh testPairPerturbed.sh \
-	test27cells.sh test27cellsPerturbed.sh testParser.sh testKernel testSPHStep \
-	test125cells.sh
+TESTS = testGreetings testMaths testReading.sh testSingle testKernel testSymmetry \
+        testPair.sh testPairPerturbed.sh test27cells.sh test27cellsPerturbed.sh  \
+        testParser.sh testSPHStep test125cells.sh
 
 # List of test programs to compile
 check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \
 		 testSPHStep testPair test27cells test125cells testParser \
-                 testKernel testInteractions
+                 testKernel testInteractions testMaths testSymmetry
 
 # Sources for the individual programs
 testGreetings_SOURCES = testGreetings.c
 
+testMaths_SOURCES = testMaths.c
+
 testReading_SOURCES = testReading.c
 
+testKernel_SOURCES = testKernel.c
+
+testSymmetry_SOURCES = testSymmetry.c
+
 testTimeIntegration_SOURCES = testTimeIntegration.c
 
 testSPHStep_SOURCES = testSPHStep.c
@@ -49,8 +55,6 @@ test125cells_SOURCES = test125cells.c
 
 testParser_SOURCES = testParser.c
 
-testKernel_SOURCES = testKernel.c
-
 testInteractions_SOURCES = testInteractions.c
 
 # Files necessary for distribution
diff --git a/tests/testMaths.c b/tests/testMaths.c
new file mode 100644
index 0000000000000000000000000000000000000000..96c75313db18edc653aa3a48cb6ac34913297806
--- /dev/null
+++ b/tests/testMaths.c
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (C) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#include "approx_math.h"
+#include "vector.h"
+
+#include <math.h>
+#include <stdio.h>
+
+int main() {
+
+  const int numPoints = 60000;
+
+  for (int i = 0; i < numPoints; ++i) {
+
+    const float x = 0.6f * (i / (float)numPoints) - 0.3f;
+    const float exp_correct = expf(x);
+    const float exp_approx = approx_expf(x);
+
+    const float abs = fabs(exp_correct - exp_approx);
+    const float rel =
+        0.5f * fabs(exp_correct - exp_approx) / fabs(exp_correct + exp_approx);
+
+    printf("%2d: x= %f exp(x)= %e approx_exp(x)=%e abs=%e rel=%e\n", i, x,
+           exp_correct, exp_approx, abs, rel);
+
+    if (abs > 3e-6 && fabsf(x) <= 0.2) {
+      printf("Absolute difference too large !\n");
+      return 1;
+    }
+    if (abs > 1.2e-7 && fabsf(x) <= 0.1) {
+      printf("Absolute difference too large !\n");
+      return 1;
+    }
+
+    if (rel > 1e-6 && fabsf(x) <= 0.2) {
+      printf("Relative difference too large !\n");
+      return 1;
+    }
+    if (rel > 4e-8 && fabsf(x) <= 0.1) {
+      printf("Relative difference too large !\n");
+      return 1;
+    }
+  }
+
+  printf("\nAll values are consistent\n");
+
+  return 0;
+}
diff --git a/tests/testSymmetry.c b/tests/testSymmetry.c
new file mode 100644
index 0000000000000000000000000000000000000000..eb3fab6becca08e9ef87e7c60cc8c04bd2a0290c
--- /dev/null
+++ b/tests/testSymmetry.c
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (C) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#include "../config.h"
+
+#include <fenv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swift.h"
+
+int main(int argc, char *argv[]) {
+
+  /* Choke if need be */
+  feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
+
+  /* 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) {
+    *(((float *)&pi) + i) = (float)random_uniform(0., 2.);
+    *(((float *)&pj) + i) = (float)random_uniform(0., 2.);
+  }
+
+  /* Make the particle smoothing length and position reasonable */
+  for (size_t i = 0; i < 3; ++i) pi.x[0] = random_uniform(-1., 1.);
+  for (size_t i = 0; i < 3; ++i) pj.x[0] = random_uniform(-1., 1.);
+  pi.h = 2.f;
+  pj.h = 2.f;
+  pi.id = 1;
+  pj.id = 2;
+
+  /* Make an xpart companion */
+  struct xpart xpi, xpj;
+  bzero(&xpi, sizeof(struct xpart));
+  bzero(&xpj, sizeof(struct xpart));
+
+  /* Make some copies */
+  struct part pi2, pj2;
+  memcpy(&pi2, &pi, sizeof(struct part));
+  memcpy(&pj2, &pj, sizeof(struct part));
+
+  int i_ok = memcmp(&pi, &pi2, sizeof(struct part));
+  int j_ok = memcmp(&pj, &pj2, sizeof(struct part));
+
+  if (i_ok != 0) error("Particles 'pi' do not match after copy");
+  if (j_ok != 0) error("Particles 'pj' do not match after copy");
+
+  /* Compute distance vector */
+  float dx[3];
+  dx[0] = pi.x[0] - pj.x[0];
+  dx[1] = pi.x[1] - pj.x[1];
+  dx[2] = pi.x[2] - pj.x[2];
+  float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
+
+  /* --- Test the density loop --- */
+
+  /* Call the symmetric version */
+  runner_iact_density(r2, dx, pi.h, pj.h, &pi, &pj);
+
+  /* Call the non-symmetric version */
+  runner_iact_nonsym_density(r2, dx, pi2.h, pj2.h, &pi2, &pj2);
+  dx[0] = -dx[0];
+  dx[1] = -dx[1];
+  dx[2] = -dx[2];
+  runner_iact_nonsym_density(r2, dx, pj2.h, pi2.h, &pj2, &pi2);
+
+  /* Check that the particles are the same */
+  i_ok = memcmp(&pi, &pi2, sizeof(struct part));
+  j_ok = memcmp(&pj, &pj2, sizeof(struct part));
+
+  if (i_ok) error("Particles 'pi' do not match after density");
+  if (j_ok) error("Particles 'pj' do not match after density");
+
+  /* --- Test the force loop --- */
+
+  /* Call the symmetric version */
+  runner_iact_force(r2, dx, pi.h, pj.h, &pi, &pj);
+
+  /* Call the non-symmetric version */
+  runner_iact_nonsym_force(r2, dx, pi2.h, pj2.h, &pi2, &pj2);
+  dx[0] = -dx[0];
+  dx[1] = -dx[1];
+  dx[2] = -dx[2];
+  runner_iact_nonsym_force(r2, dx, pj2.h, pi2.h, &pj2, &pi2);
+
+  /* Check that the particles are the same */
+  i_ok = memcmp(&pi, &pi2, sizeof(struct part));
+  j_ok = memcmp(&pj, &pj2, sizeof(struct part));
+
+  if (i_ok) error("Particles 'pi' do not match after force");
+  if (j_ok) error("Particles 'pj' do not match after force");
+
+  return 0;
+}