diff --git a/.gitignore b/.gitignore
index 6b03972ab8a13017ae80e284771618d4c65f6c24..b7f8ac3a1466459891366cd774e922833b1cca74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,6 +114,7 @@ tests/testPotentialSelf
 tests/testPotentialPair
 tests/testEOS
 tests/testEOS*.txt
+tests/testEOS*.png
 
 theory/latex/swift.pdf
 theory/SPH/Kernels/kernels.pdf
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ded168984750e1c9b1ecb0d5f94bf4094c283f2d..5789b1baf64554d5c53aa6696ad5727bcfda07cb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,7 +27,7 @@ TESTS = testGreetings testMaths testReading.sh testSingle testKernel testSymmetr
         testMatrixInversion testThreadpool testDump testLogger testInteractions.sh \
         testVoronoi1D testVoronoi2D testVoronoi3D testGravityDerivatives \
 	testPeriodicBC.sh testPeriodicBCPerturbed.sh testPotentialSelf \
-	testPotentialPair
+	testPotentialPair testEOS
 
 # List of test programs to compile
 check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \
@@ -37,7 +37,7 @@ check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \
                  testAdiabaticIndex testRiemannExact testRiemannTRRS \
                  testRiemannHLLC testMatrixInversion testDump testLogger \
 		 testVoronoi1D testVoronoi2D testVoronoi3D testPeriodicBC \
-		 testGravityDerivatives testPotentialSelf testPotentialPair
+		 testGravityDerivatives testPotentialSelf testPotentialPair testEOS
 
 # Rebuild tests when SWIFT is updated.
 $(check_PROGRAMS): ../src/.libs/libswiftsim.a
@@ -105,6 +105,8 @@ testPotentialSelf_SOURCES = testPotentialSelf.c
 
 testPotentialPair_SOURCES = testPotentialPair.c
 
+testEOS_SOURCES = testEOS.c
+
 # Files necessary for distribution
 EXTRA_DIST = testReading.sh makeInput.py testActivePair.sh \
 	     test27cells.sh test27cellsPerturbed.sh testParser.sh testPeriodicBC.sh \
@@ -112,4 +114,5 @@ EXTRA_DIST = testReading.sh makeInput.py testActivePair.sh \
 	     difffloat.py tolerance_125_normal.dat tolerance_125_perturbed.dat \
              tolerance_27_normal.dat tolerance_27_perturbed.dat tolerance_27_perturbed_h.dat tolerance_27_perturbed_h2.dat \
 	     tolerance_testInteractions.dat tolerance_pair_active.dat tolerance_pair_force_active.dat \
-	     fft_params.yml tolerance_periodic_BC_normal.dat tolerance_periodic_BC_perturbed.dat
+	     fft_params.yml tolerance_periodic_BC_normal.dat tolerance_periodic_BC_perturbed.dat \
+	     testEOS.sh testEOS_plot.sh
diff --git a/tests/testEOS.c b/tests/testEOS.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f8ca496507268f2abf6875435b0042e7337adc9
--- /dev/null
+++ b/tests/testEOS.c
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk),
+ *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ *               2018 Jacob Kegerreis (jacob.kegerreis@durham.ac.uk)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <fenv.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Conditional headers. */
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+/* Local headers. */
+#include "equation_of_state.h"
+#include "swift.h"
+
+/* Engine policy flags. */
+#ifndef ENGINE_POLICY
+#define ENGINE_POLICY engine_policy_none
+#endif
+
+/**
+ * @brief Write a list of densities, energies, and resulting pressures to file
+ *  from an equation of state.
+ *
+ *                      WORK IN PROGRESS
+ *
+ * So far only does the Hubbard & MacFarlane (1980) equations of state.
+ *
+ * Usage:
+ *      $  ./testEOS  (mat_id)  (do_output)
+ *
+ * Sys args (optional):
+ *      mat_id | int | Material ID, see equation_of_state.h for the options.
+ *          Default: 201 (= id_HM80_ice).
+ *
+ *      do_output | int | Set 1 to write the output file of rho, u, P values,
+ *          set 0 for no output. Default: 0.
+ *
+ * Output text file contains:
+ *  header
+ *  num_rho num_u   mat_id                      # Header values
+ *  rho_0   rho_1   rho_2   ...   rho_num_rho   # Array of densities, rho
+ *  u_0     u_1     u_2     ...   u_num_u       # Array of energies, u
+ *  P_0_0   P_0_1   ...     P_0_num_u           # Array of pressures, P(rho, u)
+ *  P_1_0   ...     ...     P_1_num_u
+ *  ...     ...     ...     ...
+ *  P_num_rho_0     ...     P_num_rho_num_u
+ *
+ * Note that the values tested extend beyond the range that most EOS are
+ * designed for (e.g. outside table limits), to help test the EOS in case of
+ * unexpected particle behaviour.
+ *
+ */
+
+#ifdef EOS_PLANETARY
+int main(int argc, char *argv[]) {
+  float rho, log_rho, log_u, P;
+  struct unit_system us;
+  const struct phys_const *phys_const = 0;  // Unused placeholder
+  const struct swift_params *params = 0;    // Unused placeholder
+  const float J_kg_to_erg_g = 1e4;  // Convert J/kg to erg/g
+  char filename[64];
+  // Output table params
+  const int num_rho = 100, num_u = 100;
+  float log_rho_min = logf(1e-4), log_rho_max = logf(30.f),
+        log_u_min = logf(1e4), log_u_max = logf(1e10),
+        log_rho_step = (log_rho_max - log_rho_min) / (num_rho - 1.f),
+        log_u_step = (log_u_max - log_u_min) / (num_u - 1.f);
+  float A1_rho[num_rho], A1_u[num_u];
+  // Sys args
+  int mat_id, do_output;
+  // Default sys args
+  const int mat_id_def = id_HM80_ice;
+  const int do_output_def = 0;
+
+  // Check the number of system arguments and use defaults if not provided
+  switch (argc) {
+    case 1:
+      // Default both
+      mat_id = mat_id_def;
+      do_output = do_output_def;
+      break;
+
+    case 2:
+      // Read mat_id, default do_output
+      mat_id = atoi(argv[1]);
+      do_output = do_output_def;
+      break;
+
+    case 3:
+      // Read both
+      mat_id = atoi(argv[1]);
+      do_output = atoi(argv[2]);
+      break;
+
+    default:
+      error("Invalid number of system arguments!\n");
+      mat_id = mat_id_def;  // Ignored, just here to keep the compiler happy
+      do_output = do_output_def;
+  };
+
+  /* Greeting message */
+  printf("This is %s\n", package_description());
+
+  // Check material ID
+  // Material base type
+  switch ((int)(mat_id / type_factor)) {
+    // Tillotson
+    case type_Til:
+      switch (mat_id) {
+        case id_Til_iron:
+          printf("  Tillotson iron \n");
+          break;
+
+        case id_Til_granite:
+          printf("  Tillotson granite \n");
+          break;
+
+        case id_Til_water:
+          printf("  Tillotson water \n");
+          break;
+
+        default:
+          error("Unknown material ID! mat_id = %d \n", mat_id);
+      };
+      break;
+
+    // Hubbard & MacFarlane (1980)
+    case type_HM80:
+      switch (mat_id) {
+        case id_HM80_HHe:
+          printf("  Hubbard & MacFarlane (1980) hydrogen-helium atmosphere \n");
+          break;
+
+        case id_HM80_ice:
+          printf("  Hubbard & MacFarlane (1980) ice mix \n");
+          break;
+
+        case id_HM80_rock:
+          printf("  Hubbard & MacFarlane (1980) rock mix \n");
+          break;
+
+        default:
+          error("Unknown material ID! mat_id = %d \n", mat_id);
+      };
+      break;
+
+    // ANEOS
+    case type_ANEOS:
+      switch (mat_id) {
+        case id_ANEOS_iron:
+          printf("  ANEOS iron \n");
+          break;
+
+        case id_MANEOS_forsterite:
+          printf("  MANEOS forsterite \n");
+          break;
+
+        default:
+          error("Unknown material ID! mat_id = %d \n", mat_id);
+      };
+      break;
+
+    // SESAME
+    case type_SESAME:
+      switch (mat_id) {
+        case id_SESAME_iron:
+          printf("  SESAME iron \n");
+          break;
+
+        default:
+          error("Unknown material ID! mat_id = %d \n", mat_id);
+      };
+      break;
+
+    default:
+      error("Unknown material type! mat_id = %d \n", mat_id);
+  }
+
+  // Convert to internal units (Earth masses and radii)
+  units_init(&us, 5.9724e27, 6.3710e8, 1.f, 1.f, 1.f);
+  log_rho_min -= logf(units_cgs_conversion_factor(&us, UNIT_CONV_DENSITY));
+  log_rho_max -= logf(units_cgs_conversion_factor(&us, UNIT_CONV_DENSITY));
+  log_u_min +=
+      logf(J_kg_to_erg_g /
+           units_cgs_conversion_factor(&us, UNIT_CONV_ENERGY_PER_UNIT_MASS));
+  log_u_max +=
+      logf(J_kg_to_erg_g /
+           units_cgs_conversion_factor(&us, UNIT_CONV_ENERGY_PER_UNIT_MASS));
+
+  // Initialise the EOS materials
+  eos_init(&eos, phys_const, &us, params);
+
+  // Output file
+  sprintf(filename, "testEOS_rho_u_P_%d.txt", mat_id);
+  FILE *f = fopen(filename, "w");
+  if (f == NULL) {
+    printf("Could not open output file!\n");
+    exit(EXIT_FAILURE);
+  }
+
+  if (do_output == 1) {
+    fprintf(f, "Density  Sp.Int.Energy  mat_id \n");
+    fprintf(f, "%d      %d            %d \n", num_rho, num_u, mat_id);
+  }
+
+  // Densities
+  log_rho = log_rho_min;
+  for (int i = 0; i < num_rho; i++) {
+    A1_rho[i] = exp(log_rho);
+    log_rho += log_rho_step;
+
+    if (do_output == 1)
+      fprintf(f, "%.6e ",
+              A1_rho[i] * units_cgs_conversion_factor(&us, UNIT_CONV_DENSITY));
+  }
+  if (do_output == 1) fprintf(f, "\n");
+
+  // Sp. int. energies
+  log_u = log_u_min;
+  for (int i = 0; i < num_u; i++) {
+    A1_u[i] = exp(log_u);
+    log_u += log_u_step;
+
+    if (do_output == 1)
+      fprintf(f, "%.6e ", A1_u[i] *
+              units_cgs_conversion_factor(&us, UNIT_CONV_ENERGY_PER_UNIT_MASS));
+  }
+  if (do_output == 1) fprintf(f, "\n");
+
+  // Pressures
+  for (int i = 0; i < num_rho; i++) {
+    rho = A1_rho[i];
+
+    for (int j = 0; j < num_u; j++) {
+      P = gas_pressure_from_internal_energy(rho, A1_u[j], mat_id);
+
+      if (do_output == 1)
+        fprintf(f, "%.6e ",
+                P * units_cgs_conversion_factor(&us, UNIT_CONV_PRESSURE));
+    }
+
+    if (do_output == 1) fprintf(f, "\n");
+  }
+  fclose(f);
+
+  return 0;
+}
+#else
+int main() {
+  return 0;
+}
+#endif
diff --git a/tests/testEOS.py b/tests/testEOS.py
new file mode 100644
index 0000000000000000000000000000000000000000..363bab200b58c65fa24cc033af4b8d3c04b7b503
--- /dev/null
+++ b/tests/testEOS.py
@@ -0,0 +1,176 @@
+###############################################################################
+ # This file is part of SWIFT.
+ # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ #               2018 Jacob Kegerreis (jacob.kegerreis@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/>.
+ #
+ ##############################################################################
+"""
+Plot the output of testEOS to show how the equation of state pressure varies
+with density and specific internal energy.
+
+Usage:
+    python  testEOS.py  (mat_id)
+
+    Sys args (optional):
+        mat_id | int | Material ID, see equation_of_state.h for the options.
+            Default: 201 (= HM80_ice).
+
+Text file contains:
+    header
+    num_rho  num_u  mat_id                      # Header info
+    rho_0   rho_1   rho_2   ...   rho_num_rho   # Array of densities, rho
+    u_0     u_1     u_2     ...   u_num_u       # Array of energies, u
+    P_0_0   P_0_1   ...     P_0_num_u           # Array of pressures, P(rho, u)
+    P_1_0   ...     ...     P_1_num_u
+    ...     ...     ...     ...
+    P_num_rho_0     ...     P_num_rho_num_u
+
+Note that the values tested extend beyond the range that most EOS are
+designed for (e.g. outside table limits), to help test the EOS in case of
+unexpected particle behaviour.
+"""
+
+# ========
+# Modules and constants
+# ========
+from __future__ import division
+import numpy as np
+import matplotlib
+matplotlib.use("Agg")
+import matplotlib.pyplot as plt
+import sys
+
+# Material types (copied from src/equation_of_state/planetary/equation_of_state.h)
+type_factor = 100
+Di_type = {
+    'Til'       : 1,
+    'HM80'      : 2,
+    'ANEOS'     : 3,
+    'SESAME'    : 4,
+}
+Di_material = {
+    # Tillotson
+    'Til_iron'      : Di_type['Til']*type_factor,
+    'Til_granite'   : Di_type['Til']*type_factor + 1,
+    'Til_water'     : Di_type['Til']*type_factor + 2,
+    # Hubbard & MacFarlane (1980) Uranus/Neptune
+    'HM80_HHe'      : Di_type['HM80']*type_factor,      # Hydrogen-helium atmosphere
+    'HM80_ice'      : Di_type['HM80']*type_factor + 1,  # H20-CH4-NH3 ice mix
+    'HM80_rock'     : Di_type['HM80']*type_factor + 2,  # SiO2-MgO-FeS-FeO rock mix
+    # ANEOS
+    'ANEOS_iron'        : Di_type['ANEOS']*type_factor,
+    'MANEOS_forsterite' : Di_type['ANEOS']*type_factor + 1,
+    # SESAME
+    'SESAME_iron'   : Di_type['SESAME']*type_factor,
+}
+# Invert so the mat_id are the keys
+Di_mat_id = {mat_id : mat for mat, mat_id in Di_material.iteritems()}
+
+# Unit conversion
+Ba_to_Mbar = 1e-12
+erg_g_to_J_kg = 1e-4
+
+if __name__ == '__main__':
+    # Sys args
+    try:
+        mat_id = int(sys.argv[1])
+    except IndexError:
+        mat_id = Di_material['HM80_ice']
+
+    # Check the material
+    try:
+        mat = Di_mat_id[mat_id]
+        print mat
+        sys.stdout.flush()
+    except KeyError:
+        print "Error: unknown material ID! mat_id = %d" % mat_id
+        print "Materials:"
+        for mat_id, mat in sorted(Di_mat_id.iteritems()):
+            print "  %s%s%d" % (mat, (20 - len("%s" % mat))*" ", mat_id)
+
+    filename = "testEOS_rho_u_P_%d.txt" % mat_id
+
+    # Load the header info and density and energy arrays
+    with open(filename) as f:
+        f.readline()
+        num_rho, num_u, mat_id = np.array(f.readline().split(), dtype=int)
+        A1_rho = np.array(f.readline().split(), dtype=float)
+        A1_u = np.array(f.readline().split(), dtype=float)
+
+    # Load pressure array
+    A2_P = np.loadtxt(filename, skiprows=4)
+
+    # Convert pressures from cgs Barye to Mbar
+    A2_P *= Ba_to_Mbar
+    # Convert energies from cgs to SI
+    A1_u *= erg_g_to_J_kg
+
+    # Check that the numbers are right
+    assert A1_rho.shape == (num_rho,)
+    assert A1_u.shape == (num_u,)
+    assert A2_P.shape == (num_rho, num_u)
+
+    # Plot
+    plt.figure(figsize=(7, 7))
+    ax = plt.gca()
+
+    # P(rho) at fixed u
+    num_u_fix = 9
+    A1_idx = np.floor(np.linspace(0, num_u - 1, num_u_fix)).astype(int)
+    A1_colour = matplotlib.cm.rainbow(np.linspace(0, 1, num_u_fix))
+
+    for i, idx in enumerate(A1_idx):
+        plt.plot(A1_rho, A2_P[:, idx], c=A1_colour[i],
+                 label=r"%.2e" % A1_u[idx])
+
+    plt.legend(title="Sp. Int. Energy (J kg$^{-1}$)")
+    plt.xscale('log')
+    plt.yscale('log')
+    plt.xlabel(r"Density (g cm$^{-3}$)")
+    plt.ylabel(r"Pressure (Mbar)")
+    plt.title(mat)
+    plt.tight_layout()
+
+    plt.savefig("testEOS_%d.png" % mat_id)
+    plt.close()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/testEOS.sh b/tests/testEOS.sh
new file mode 100755
index 0000000000000000000000000000000000000000..411ac746be186bfe5758e03c2a852e081daefd10
--- /dev/null
+++ b/tests/testEOS.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+echo ""
+
+rm -f testEOS_rho_u_P_*.txt
+
+echo "Running testEOS for each planetary material"
+
+A1_mat_id=(
+    100
+    101
+    102
+    200
+    201
+    202
+)
+
+for mat_id in "${A1_mat_id[@]}"
+do
+    ./testEOS "$mat_id" 1
+done
+
+exit $?
diff --git a/tests/testEOS_plot.sh b/tests/testEOS_plot.sh
new file mode 100755
index 0000000000000000000000000000000000000000..39108c5e19d8f4474de508e205951a1fd0aebcc9
--- /dev/null
+++ b/tests/testEOS_plot.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+echo ""
+
+echo "Plotting testEOS output for each planetary material"
+
+A1_mat_id=(
+    100
+    101
+    102
+    200
+    201
+    202
+)
+
+for mat_id in "${A1_mat_id[@]}"
+do
+    python ./testEOS.py "$mat_id"
+done
+
+exit $?