diff --git a/examples/ExternalPointMass/run.sh b/examples/ExternalPointMass/run.sh
index 9f90ca395a5c8cf83e67928b3fdbd4d8529ac254..4ac513f09cb8ac8dcefc256a68478e215b8bc320 100755
--- a/examples/ExternalPointMass/run.sh
+++ b/examples/ExternalPointMass/run.sh
@@ -7,4 +7,4 @@ then
     python makeIC.py 10000
 fi
 
-../swift -g -t 2 externalPointMass.yml 2>&1 | tee output.log
+../swift -g -t 1 externalPointMass.yml 2>&1 | tee output.log
diff --git a/examples/IsothermalPotential/GravityOnly/README b/examples/IsothermalPotential/GravityOnly/README
index 90fb1872aa2301cab133b8a20a8cd8de724d4553..1621aaa8ab90420dcf69b5b9caea394d619b62cf 100644
--- a/examples/IsothermalPotential/GravityOnly/README
+++ b/examples/IsothermalPotential/GravityOnly/README
@@ -1,6 +1,3 @@
-;
-; this probelm generates a set of gravity particles in an isothermal
-; potential and follows their orbits. Tests verify consdevation of
-; energy and angular momentum
-;
-;
+This example generates a set of particles in an isothermal potential
+and follows their orbits. IDL scripts verify the conservation of
+energy and angular momentum.
diff --git a/src/cell.c b/src/cell.c
index a0da9bf58ddad6fad48b7146a4b97fd7c800cc50..5d3f0673f77aca351459177ebecddda54106c6a6 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -1007,3 +1007,23 @@ int cell_unskip_tasks(struct cell *c, struct scheduler *s) {
 
   return 0;
 }
+
+/**
+ * @brief Set the super-cell pointers for all cells in a hierarchy.
+ *
+ * @param c The top-level #cell to play with.
+ * @param super Pointer to the deepest cell with tasks in this part of the tree.
+ */
+void cell_set_super(struct cell *c, struct cell *super) {
+
+  /* Are we in a cell with some kind of self/pair task ? */
+  if (super == NULL && c->nr_tasks > 0) super = c;
+
+  /* Set the super-cell */
+  c->super = super;
+
+  /* Recurse */
+  if (c->split)
+    for (int k = 0; k < 8; k++)
+      if (c->progeny[k] != NULL) cell_set_super(c->progeny[k], super);
+}
diff --git a/src/cell.h b/src/cell.h
index 4b970d587923f53dab909250de2b31da3252d6ae..7c6eed55b83277fe9c489d2ab58683d4859d3d59 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -131,14 +131,9 @@ struct cell {
   /* Parent cell. */
   struct cell *parent;
 
-  /* Super cell, i.e. the highest-level supercell that has hydro interactions.
-   */
+  /* Super cell, i.e. the highest-level supercell that has pair/self tasks */
   struct cell *super;
 
-  /* Super cell, i.e. the highest-level supercell that has gravity interactions.
-   */
-  struct cell *gsuper;
-
   /* The task computing this cell's sorts. */
   struct task *sorts;
   int sortsize;
@@ -242,5 +237,6 @@ void cell_check_multipole(struct cell *c, void *data);
 void cell_clean(struct cell *c);
 int cell_is_drift_needed(struct cell *c, int ti_current);
 int cell_unskip_tasks(struct cell *c, struct scheduler *s);
+void cell_set_super(struct cell *c, struct cell *super);
 
 #endif /* SWIFT_CELL_H */
diff --git a/src/engine.c b/src/engine.c
index a41659ada346d44d105b65a678995fab1474ce78..a8773fcbeab48bc775503c1795508f5a9bcca57f 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -111,119 +111,57 @@ void engine_addlink(struct engine *e, struct link **l, struct task *t) {
   res->next = atomic_swap(l, res);
 }
 
-/**
- * @brief Generate the gravity hierarchical tasks for a hierarchy of cells -
- * i.e. all the O(Npart) tasks.
- *
- * Tasks are only created here. The dependencies will be added later on.
- *
- * @param e The #engine.
- * @param c The #cell.
- * @param gsuper The gsuper #cell.
- */
-void engine_make_gravity_hierarchical_tasks(struct engine *e, struct cell *c,
-                                            struct cell *gsuper) {
-
-  struct scheduler *s = &e->sched;
-  const int is_with_external_gravity =
-      (e->policy & engine_policy_external_gravity) ==
-      engine_policy_external_gravity;
-  const int is_fixdt = (e->policy & engine_policy_fixdt) == engine_policy_fixdt;
-
-  /* Is this the super-cell? */
-  if (gsuper == NULL && (c->grav != NULL || (!c->split && c->gcount > 0))) {
-
-    /* This is the super cell, i.e. the first with gravity tasks attached. */
-    gsuper = c;
-
-    /* Local tasks only... */
-    if (c->nodeID == e->nodeID) {
-
-      /* Add the init task. */
-      if (c->init == NULL)
-        c->init = scheduler_addtask(s, task_type_init, task_subtype_none, 0, 0,
-                                    c, NULL, 0);
-
-      /* Add the kick task that matches the policy. */
-      if (is_fixdt) {
-        if (c->kick == NULL)
-          c->kick = scheduler_addtask(s, task_type_kick_fixdt,
-                                      task_subtype_none, 0, 0, c, NULL, 0);
-      } else {
-        if (c->kick == NULL)
-          c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0,
-                                      0, c, NULL, 0);
-      }
-
-      if (is_with_external_gravity)
-        c->grav_external = scheduler_addtask(
-            s, task_type_grav_external, task_subtype_none, 0, 0, c, NULL, 0);
-    }
-  }
-
-  /* Set the super-cell. */
-  c->gsuper = gsuper;
-
-  /* Recurse. */
-  if (c->split)
-    for (int k = 0; k < 8; k++)
-      if (c->progeny[k] != NULL)
-        engine_make_gravity_hierarchical_tasks(e, c->progeny[k], gsuper);
-}
-
 /**
  * @brief Generate the hydro hierarchical tasks for a hierarchy of cells -
  * i.e. all the O(Npart) tasks.
  *
  * Tasks are only created here. The dependencies will be added later on.
  *
+ * Note that there is no need to recurse below the super-cell.
+ *
  * @param e The #engine.
  * @param c The #cell.
- * @param super The super #cell.
  */
-void engine_make_hydro_hierarchical_tasks(struct engine *e, struct cell *c,
-                                          struct cell *super) {
+void engine_make_hierarchical_tasks(struct engine *e, struct cell *c) {
 
   struct scheduler *s = &e->sched;
-  const int is_fixdt = (e->policy & engine_policy_fixdt) == engine_policy_fixdt;
-  const int is_with_cooling =
-      (e->policy & engine_policy_cooling) == engine_policy_cooling;
-  const int is_with_sourceterms =
-      (e->policy & engine_policy_sourceterms) == engine_policy_sourceterms;
+  const int is_fixdt = (e->policy & engine_policy_fixdt);
+  const int is_hydro = (e->policy & engine_policy_hydro);
+  const int is_with_cooling = (e->policy & engine_policy_cooling);
+  const int is_with_sourceterms = (e->policy & engine_policy_sourceterms);
 
-  /* Is this the super-cell? */
-  if (super == NULL && (c->density != NULL || (c->count > 0 && !c->split))) {
-
-    /* This is the super cell, i.e. the first with density tasks attached. */
-    super = c;
+  /* Are we in a super-cell ? */
+  if (c->super == c) {
 
     /* Local tasks only... */
     if (c->nodeID == e->nodeID) {
 
       /* Add the init task. */
-      if (c->init == NULL)
-        c->init = scheduler_addtask(s, task_type_init, task_subtype_none, 0, 0,
-                                    c, NULL, 0);
+      c->init = scheduler_addtask(s, task_type_init, task_subtype_none, 0, 0, c,
+                                  NULL, 0);
 
       /* Add the kick task that matches the policy. */
       if (is_fixdt) {
-        if (c->kick == NULL)
-          c->kick = scheduler_addtask(s, task_type_kick_fixdt,
-                                      task_subtype_none, 0, 0, c, NULL, 0);
+        c->kick = scheduler_addtask(s, task_type_kick_fixdt, task_subtype_none,
+                                    0, 0, c, NULL, 0);
       } else {
-        if (c->kick == NULL)
-          c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0,
-                                      0, c, NULL, 0);
+        c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0, 0,
+                                    c, NULL, 0);
       }
 
       /* Generate the ghost task. */
-      c->ghost = scheduler_addtask(s, task_type_ghost, task_subtype_none, 0, 0,
-                                   c, NULL, 0);
+      if (is_hydro)
+        c->ghost = scheduler_addtask(s, task_type_ghost, task_subtype_none, 0,
+                                     0, c, NULL, 0);
+
 #ifdef EXTRA_HYDRO_LOOP
       /* Generate the extra ghost task. */
-      c->extra_ghost = scheduler_addtask(s, task_type_extra_ghost,
-                                         task_subtype_none, 0, 0, c, NULL, 0);
+      if (is_hydro)
+        c->extra_ghost = scheduler_addtask(s, task_type_extra_ghost,
+                                           task_subtype_none, 0, 0, c, NULL, 0);
 #endif
+
+      /* Cooling task */
       if (is_with_cooling)
         c->cooling = scheduler_addtask(s, task_type_cooling, task_subtype_none,
                                        0, 0, c, NULL, 0);
@@ -232,16 +170,19 @@ void engine_make_hydro_hierarchical_tasks(struct engine *e, struct cell *c,
         c->sourceterms = scheduler_addtask(s, task_type_sourceterms,
                                            task_subtype_none, 0, 0, c, NULL, 0);
     }
-  }
 
-  /* Set the super-cell. */
-  c->super = super;
+  } else { /* We are above the super-cell so need to go deeper */
 
-  /* Recurse. */
-  if (c->split)
-    for (int k = 0; k < 8; k++)
-      if (c->progeny[k] != NULL)
-        engine_make_hydro_hierarchical_tasks(e, c->progeny[k], super);
+#ifdef SWIFT_DEBUG_CHECKS
+    if (c->super != NULL) error("Incorrectly set super pointer");
+#endif
+
+    /* Recurse. */
+    if (c->split)
+      for (int k = 0; k < 8; k++)
+        if (c->progeny[k] != NULL)
+          engine_make_hierarchical_tasks(e, c->progeny[k]);
+  }
 }
 
 /**
@@ -1289,6 +1230,30 @@ void engine_make_gravity_tasks(struct engine *e) {
   }
 }
 
+void engine_make_external_gravity_tasks(struct engine *e) {
+
+  struct space *s = e->s;
+  struct scheduler *sched = &e->sched;
+  const int nodeID = e->nodeID;
+  struct cell *cells = s->cells_top;
+  const int nr_cells = s->nr_cells;
+
+  for (int cid = 0; cid < nr_cells; ++cid) {
+
+    struct cell *ci = &cells[cid];
+
+    /* Skip cells without gravity particles */
+    if (ci->gcount == 0) continue;
+
+    /* Is that neighbour local ? */
+    if (ci->nodeID != nodeID) continue;
+
+    /* If the cells is local build a self-interaction */
+    scheduler_addtask(sched, task_type_self, task_subtype_external_grav, 0, 0,
+                      ci, NULL, 0);
+  }
+}
+
 /**
  * @brief Constructs the top-level pair tasks for the first hydro loop over
  * neighbours
@@ -1431,11 +1396,27 @@ static inline void engine_make_gravity_dependencies(struct scheduler *sched,
                                                     struct cell *c) {
 
   /* init --> gravity --> kick */
-  scheduler_addunlock(sched, c->gsuper->init, gravity);
-  scheduler_addunlock(sched, gravity, c->gsuper->kick);
+  scheduler_addunlock(sched, c->super->init, gravity);
+  scheduler_addunlock(sched, gravity, c->super->kick);
 
   /* grav_up --> gravity ( --> kick) */
-  scheduler_addunlock(sched, c->gsuper->grav_up, gravity);
+  scheduler_addunlock(sched, c->super->grav_up, gravity);
+}
+
+/**
+ * @brief Creates the dependency network for the external gravity tasks of a
+ * given cell.
+ *
+ * @param sched The #scheduler.
+ * @param gravity The gravity task to link.
+ * @param c The cell.
+ */
+static inline void engine_make_external_gravity_dependencies(
+    struct scheduler *sched, struct task *gravity, struct cell *c) {
+
+  /* init --> external gravity --> kick */
+  scheduler_addunlock(sched, c->super->init, gravity);
+  scheduler_addunlock(sched, gravity, c->super->kick);
 }
 
 /**
@@ -1474,19 +1455,27 @@ void engine_link_gravity_tasks(struct engine *e) {
 
       /* Gather the multipoles --> mm interaction --> kick */
       scheduler_addunlock(sched, gather, t);
-      scheduler_addunlock(sched, t, t->ci->gsuper->kick);
+      scheduler_addunlock(sched, t, t->ci->super->kick);
 
       /* init --> mm interaction */
-      scheduler_addunlock(sched, t->ci->gsuper->init, t);
+      scheduler_addunlock(sched, t->ci->super->init, t);
     }
 
-    /* Self-interaction? */
+    /* Self-interaction for self-gravity? */
     if (t->type == task_type_self && t->subtype == task_subtype_grav) {
 
       engine_make_gravity_dependencies(sched, t, t->ci);
 
     }
 
+    /* Self-interaction for external gravity ? */
+    else if (t->type == task_type_self &&
+             t->subtype == task_subtype_external_grav) {
+
+      engine_make_external_gravity_dependencies(sched, t, t->ci);
+
+    }
+
     /* Otherwise, pair interaction? */
     else if (t->type == task_type_pair && t->subtype == task_subtype_grav) {
 
@@ -1495,7 +1484,7 @@ void engine_link_gravity_tasks(struct engine *e) {
         engine_make_gravity_dependencies(sched, t, t->ci);
       }
 
-      if (t->cj->nodeID == nodeID && t->ci->gsuper != t->cj->gsuper) {
+      if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) {
 
         engine_make_gravity_dependencies(sched, t, t->cj);
       }
@@ -1510,6 +1499,15 @@ void engine_link_gravity_tasks(struct engine *e) {
       }
     }
 
+    /* Sub-self-interaction for external gravity ? */
+    else if (t->type == task_type_sub_self &&
+             t->subtype == task_subtype_external_grav) {
+
+      if (t->ci->nodeID == nodeID) {
+        engine_make_external_gravity_dependencies(sched, t, t->ci);
+      }
+    }
+
     /* Otherwise, sub-pair interaction? */
     else if (t->type == task_type_sub_pair && t->subtype == task_subtype_grav) {
 
@@ -1517,7 +1515,7 @@ void engine_link_gravity_tasks(struct engine *e) {
 
         engine_make_gravity_dependencies(sched, t, t->ci);
       }
-      if (t->cj->nodeID == nodeID && t->ci->gsuper != t->cj->gsuper) {
+      if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) {
 
         engine_make_gravity_dependencies(sched, t, t->cj);
       }
@@ -1781,12 +1779,6 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) {
       }
 #endif
     }
-
-    /* External gravity tasks should depend on init and unlock the kick */
-    else if (t->type == task_type_grav_external) {
-      scheduler_addunlock(sched, t->ci->init, t);
-      scheduler_addunlock(sched, t, t->ci->kick);
-    }
     /* Cooling tasks should depend on kick and unlock sourceterms */
     else if (t->type == task_type_cooling) {
       scheduler_addunlock(sched, t->ci->kick, t);
@@ -1862,6 +1854,13 @@ void engine_maketasks(struct engine *e) {
   /* Add the gravity mm tasks. */
   if (e->policy & engine_policy_self_gravity) engine_make_gravity_tasks(e);
 
+  /* Add the external gravity tasks. */
+  if (e->policy & engine_policy_external_gravity)
+    engine_make_external_gravity_tasks(e);
+
+  if (e->sched.nr_tasks == 0 && (s->nr_gparts > 0 || s->nr_parts > 0))
+    error("We have particles but no hydro or gravity tasks were created.");
+
   /* Split the tasks. */
   scheduler_splittasks(sched);
 
@@ -1885,25 +1884,24 @@ void engine_maketasks(struct engine *e) {
   /* Count the number of tasks associated with each cell and
      store the density tasks in each cell, and make each sort
      depend on the sorts of its progeny. */
-  if (e->policy & engine_policy_hydro) engine_count_and_link_tasks(e);
+  engine_count_and_link_tasks(e);
 
-  /* Append hierarchical tasks to each cells */
-  if (e->policy & engine_policy_hydro)
-    for (int k = 0; k < nr_cells; k++)
-      engine_make_hydro_hierarchical_tasks(e, &cells[k], NULL);
+  /* Now that the self/pair tasks are at the right level, set the super
+   * pointers. */
+  for (int k = 0; k < nr_cells; k++) cell_set_super(&cells[k], NULL);
 
-  if ((e->policy & engine_policy_self_gravity) ||
-      (e->policy & engine_policy_external_gravity))
-    for (int k = 0; k < nr_cells; k++)
-      engine_make_gravity_hierarchical_tasks(e, &cells[k], NULL);
+  /* Append hierarchical tasks to each cells */
+  for (int k = 0; k < nr_cells; k++)
+    engine_make_hierarchical_tasks(e, &cells[k]);
 
   /* Run through the tasks and make force tasks for each density task.
      Each force task depends on the cell ghosts and unlocks the kick task
      of its super-cell. */
   if (e->policy & engine_policy_hydro) engine_make_extra_hydroloop_tasks(e);
 
-  /* Add the dependencies for the self-gravity stuff */
-  if (e->policy & engine_policy_self_gravity) engine_link_gravity_tasks(e);
+  /* Add the dependencies for the gravity stuff */
+  if (e->policy & (engine_policy_self_gravity | engine_policy_external_gravity))
+    engine_link_gravity_tasks(e);
 
 #ifdef WITH_MPI
 
@@ -2625,7 +2623,10 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs) {
   /* Add the tasks corresponding to external gravity to the masks */
   if (e->policy & engine_policy_external_gravity) {
 
-    mask |= 1 << task_type_grav_external;
+    mask |= 1 << task_type_self;
+    mask |= 1 << task_type_sub_self;
+
+    submask |= 1 << task_subtype_external_grav;
   }
 
   /* Add MPI tasks if need be */
@@ -2794,7 +2795,11 @@ void engine_step(struct engine *e) {
 
   /* Add the tasks corresponding to external gravity to the masks */
   if (e->policy & engine_policy_external_gravity) {
-    mask |= 1 << task_type_grav_external;
+
+    mask |= 1 << task_type_self;
+    mask |= 1 << task_type_sub_self;
+
+    submask |= 1 << task_subtype_external_grav;
   }
 
   /* Add the tasks corresponding to cooling to the masks */
diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h
index a383a2fdce9e64a5673d0136184368220dc08458..bd970795bdf070a7bd7915cc4f493218dbf319d1 100644
--- a/src/hydro/Gizmo/hydro.h
+++ b/src/hydro/Gizmo/hydro.h
@@ -524,6 +524,7 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy(
   /* conserved.energy is NOT the specific energy (u), but the total thermal
      energy (u*m) */
   p->conserved.energy = u * p->conserved.mass;
+  p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u;
 }
 
 /**
@@ -540,4 +541,5 @@ __attribute__((always_inline)) INLINE static void hydro_set_entropy(
 
   p->conserved.energy = gas_internal_energy_from_entropy(p->primitives.rho, S) *
                         p->conserved.mass;
+  p->primitives.P = gas_pressure_from_entropy(p->primitives.rho, S);
 }
diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h
index 2c037a05fcba1d9f7a491e97895b57ae0e35eac2..0c69728a9ce6317a8d7ddab945e7aab6e94ee247 100644
--- a/src/hydro/PressureEntropy/hydro.h
+++ b/src/hydro/PressureEntropy/hydro.h
@@ -338,11 +338,10 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force(
 
   /* Compute "grad h" term (note we use rho here and not rho_bar !)*/
   const float rho_inv = 1.f / p->rho;
-  const float entropy_minus_one_over_gamma = 1.f / p->entropy_one_over_gamma;
   const float rho_dh =
       1.f / (1.f + hydro_dimension_inv * p->h * p->density.rho_dh * rho_inv);
-  const float pressure_dh = p->density.pressure_dh * rho_inv * p->h *
-                            hydro_dimension_inv * entropy_minus_one_over_gamma;
+  const float pressure_dh =
+      p->density.pressure_dh * rho_inv * p->h * hydro_dimension_inv;
 
   const float grad_h_term = rho_dh * pressure_dh;
 
@@ -442,7 +441,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_force(
 
   p->force.h_dt *= p->h * hydro_dimension_inv;
 
-  p->entropy_dt *=
+  p->entropy_dt =
       0.5f * gas_entropy_from_internal_energy(p->rho_bar, p->entropy_dt);
 }
 
diff --git a/src/hydro/PressureEntropy/hydro_iact.h b/src/hydro/PressureEntropy/hydro_iact.h
index 18e22233f6f53e488119a58a988ba4c9faf3db36..ce1c38ca69954252dc804af9181b9060a14afcb9 100644
--- a/src/hydro/PressureEntropy/hydro_iact.h
+++ b/src/hydro/PressureEntropy/hydro_iact.h
@@ -255,8 +255,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_force(
 
   /* Now, convolve with the kernel */
   const float visc_term = 0.5f * visc * (wi_dr + wj_dr);
-  const float sph_term = (S_gamma_j / S_gamma_i - f_i) * P_over_rho2_i * wi_dr +
-                         (S_gamma_i / S_gamma_j - f_j) * P_over_rho2_j * wj_dr;
+  const float sph_term =
+      (S_gamma_j / S_gamma_i - f_i / S_gamma_i) * P_over_rho2_i * wi_dr +
+      (S_gamma_i / S_gamma_j - f_j / S_gamma_j) * P_over_rho2_j * wj_dr;
 
   /* Eventually got the acceleration */
   const float acc = (visc_term + sph_term) * r_inv;
@@ -365,8 +366,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
 
   /* Now, convolve with the kernel */
   const float visc_term = 0.5f * visc * (wi_dr + wj_dr);
-  const float sph_term = (S_gamma_j / S_gamma_i - f_i) * P_over_rho2_i * wi_dr +
-                         (S_gamma_i / S_gamma_j - f_j) * P_over_rho2_j * wj_dr;
+  const float sph_term =
+      (S_gamma_j / S_gamma_i - f_i / S_gamma_i) * P_over_rho2_i * wi_dr +
+      (S_gamma_i / S_gamma_j - f_j / S_gamma_j) * P_over_rho2_j * wj_dr;
 
   /* Eventually got the acceleration */
   const float acc = (visc_term + sph_term) * r_inv;
diff --git a/src/minmax.h b/src/minmax.h
index 9d92cd71d849dba615fdb05bc342014e0593d989..a53093663c79cf4280d136747663552e49c7f1b2 100644
--- a/src/minmax.h
+++ b/src/minmax.h
@@ -43,4 +43,18 @@
     _a > _b ? _a : _b;            \
   })
 
+/**
+ * @brief Limits the value of x to be between a and b
+ *
+ * Only wraps once. If x > 2b, the returned value will be larger than b.
+ * Similarly for x < -b.
+ */
+#define box_wrap(x, a, b)                               \
+  ({                                                    \
+    const __typeof__(x) _x = (x);                       \
+    const __typeof__(a) _a = (a);                       \
+    const __typeof__(b) _b = (b);                       \
+    _x < _a ? (_x + _b) : ((_x > _b) ? (_x - _b) : _x); \
+  })
+
 #endif /* SWIFT_MINMAX_H */
diff --git a/src/riemann.h b/src/riemann.h
index d0ae57a640e13c2098708735d6c34de70ebea5b0..69e1a038fc37cb07e1094c8e6736f79b6afa4f35 100644
--- a/src/riemann.h
+++ b/src/riemann.h
@@ -27,18 +27,17 @@
 #include "stdio.h"
 #include "stdlib.h"
 
-/* Check that we use an ideal equation of state, since other equations of state
-   are not compatible with these Riemann solvers. */
-#ifndef EOS_IDEAL_GAS
-#error Currently there are no Riemann solvers that can handle the requested \
-       equation of state. Select an ideal gas equation of state if you want to \
-       use this hydro scheme!
-#endif
-
 #if defined(RIEMANN_SOLVER_EXACT)
 
 #define RIEMANN_SOLVER_IMPLEMENTATION "Exact Riemann solver (Toro 2009)"
+#if defined(EOS_IDEAL_GAS)
 #include "riemann/riemann_exact.h"
+#elif defined(EOS_ISOTHERMAL_GAS)
+#include "riemann/riemann_exact_isothermal.h"
+#else
+#error \
+    "The Exact Riemann solver is incompatible with the selected equation of state!"
+#endif
 
 #elif defined(RIEMANN_SOLVER_TRRS)
 
diff --git a/src/riemann/riemann_exact_isothermal.h b/src/riemann/riemann_exact_isothermal.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e8a6a4dcce456b55f85148bed7342ad4e651c1b
--- /dev/null
+++ b/src/riemann/riemann_exact_isothermal.h
@@ -0,0 +1,450 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@ugent.be)
+ *
+ * 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_RIEMANN_EXACT_ISOTHERMAL_H
+#define SWIFT_RIEMANN_EXACT_ISOTHERMAL_H
+
+#include <float.h>
+#include "adiabatic_index.h"
+#include "minmax.h"
+#include "riemann_vacuum.h"
+
+#define const_isothermal_soundspeed \
+  sqrtf(hydro_gamma_minus_one* const_isothermal_internal_energy)
+
+/**
+ * @brief Relative difference between the middle state velocity and the left or
+ * right state velocity used in the middle state density iteration.
+ *
+ * @param rho Current estimate of the middle state density.
+ * @param W Left or right state vector.
+ * @return Density dependent part of the middle state velocity.
+ */
+__attribute__((always_inline)) INLINE static float riemann_fb(float rho,
+                                                              float* W) {
+  if (rho < W[0]) {
+    return const_isothermal_soundspeed * logf(rho / W[0]);
+  } else {
+    return const_isothermal_soundspeed *
+           (sqrtf(rho / W[0]) - sqrtf(W[0] / rho));
+  }
+}
+
+/**
+ * @brief Derivative w.r.t. rho of the function riemann_fb.
+ *
+ * @param rho Current estimate of the middle state density.
+ * @param W Left or right state vector.
+ * @return Derivative of riemann_fb.
+ */
+__attribute__((always_inline)) INLINE static float riemann_fprimeb(float rho,
+                                                                   float* W) {
+  if (rho < W[0]) {
+    return const_isothermal_soundspeed * W[0] / rho;
+  } else {
+    return 0.5 * const_isothermal_soundspeed *
+           (sqrtf(rho / W[0]) + sqrtf(W[0] / rho)) / rho;
+  }
+}
+
+/**
+ * @brief Difference between the left and right middle state velocity estimates.
+ *
+ * Since the middle state velocity takes on a constant value, we want to get
+ * this difference as close to zero as possible.
+ *
+ * @param rho Current estimate of the middle state density.
+ * @param WL Left state vector.
+ * @param WR Right state vector.
+ * @param vL Left state velocity along the interface normal.
+ * @param vR Right state velocity along the interface normal.
+ * @return Difference between the left and right middle state velocity
+ * estimates.
+ */
+__attribute__((always_inline)) INLINE static float riemann_f(
+    float rho, float* WL, float* WR, float vL, float vR) {
+  return riemann_fb(rho, WR) + riemann_fb(rho, WL) + vR - vL;
+}
+
+/**
+ * @brief Derivative of riemann_f w.r.t. rho.
+ *
+ * @param rho Current estimate of the middle state density.
+ * @param WL Left state vector.
+ * @param WR Right state vector.
+ * @return Derivative of riemann_f.
+ */
+__attribute__((always_inline)) INLINE static float riemann_fprime(float rho,
+                                                                  float* WL,
+                                                                  float* WR) {
+  return riemann_fprimeb(rho, WL) + riemann_fprimeb(rho, WR);
+}
+
+/**
+ * @brief Get a good first guess for the middle state density.
+ *
+ * @param WL The left state vector
+ * @param WR The right state vector
+ * @param vL The left velocity along the interface normal
+ * @param vR The right velocity along the interface normal
+ */
+__attribute__((always_inline)) INLINE static float riemann_guess_rho(float* WL,
+                                                                     float* WR,
+                                                                     float vL,
+                                                                     float vR) {
+
+  /* Currently three possibilities and not really an algorithm to decide which
+     one to choose: */
+  /* just the average */
+  return 0.5f * (WL[0] + WR[0]);
+
+  /* two rarefaction approximation */
+  return sqrtf(WL[0] * WR[0] * expf((vL - vR) / const_isothermal_soundspeed));
+
+  /* linearized primitive variable approximation */
+  return 0.25f * (WL[0] + WR[0]) * (vL - vR) / const_isothermal_soundspeed +
+         0.5f * (WL[0] + WR[0]);
+}
+
+/**
+ * @brief Find the zeropoint of riemann_f(rho) using Brent's method.
+ *
+ * @param lower_limit Lower limit for the method (riemann_f(lower_limit) < 0)
+ * @param upper_limit Upper limit for the method (riemann_f(upper_limit) > 0)
+ * @param lowf Value of riemann_f(lower_limit).
+ * @param upf  Value of riemann_f(upper_limit).
+ * @param error_tol Tolerance used to decide if the solution is converged
+ * @param WL Left state vector
+ * @param WR Right state vector
+ * @param vL The left velocity along the interface normal
+ * @param vR The right velocity along the interface normal
+ */
+__attribute__((always_inline)) INLINE static float riemann_solve_brent(
+    float lower_limit, float upper_limit, float lowf, float upf,
+    float error_tol, float* WL, float* WR, float vL, float vR) {
+
+  float a, b, c, d, s;
+  float fa, fb, fc, fs;
+  float tmp, tmp2;
+  int mflag;
+  int i;
+
+  a = lower_limit;
+  b = upper_limit;
+  c = 0.0f;
+  d = FLT_MAX;
+
+  fa = lowf;
+  fb = upf;
+
+  fc = 0.0f;
+  s = 0.0f;
+  fs = 0.0f;
+
+  /* if f(a) f(b) >= 0 then error-exit */
+  if (fa * fb >= 0.0f) {
+    error(
+        "Brent's method called with equal sign function values!\n"
+        "f(%g) = %g, f(%g) = %g\n",
+        a, fa, b, fb);
+    /* return NaN */
+    return 0.0f / 0.0f;
+  }
+
+  /* if |f(a)| < |f(b)| then swap (a,b) */
+  if (fabs(fa) < fabs(fb)) {
+    tmp = a;
+    a = b;
+    b = tmp;
+    tmp = fa;
+    fa = fb;
+    fb = tmp;
+  }
+
+  c = a;
+  fc = fa;
+  mflag = 1;
+  i = 0;
+
+  while (!(fb == 0.0f) && (fabs(a - b) > error_tol * 0.5f * (a + b))) {
+    if ((fa != fc) && (fb != fc)) /* Inverse quadratic interpolation */
+      s = a * fb * fc / (fa - fb) / (fa - fc) +
+          b * fa * fc / (fb - fa) / (fb - fc) +
+          c * fa * fb / (fc - fa) / (fc - fb);
+    else
+      /* Secant Rule */
+      s = b - fb * (b - a) / (fb - fa);
+
+    tmp2 = 0.25f * (3.0f * a + b);
+    if (!(((s > tmp2) && (s < b)) || ((s < tmp2) && (s > b))) ||
+        (mflag && (fabs(s - b) >= (0.5f * fabs(b - c)))) ||
+        (!mflag && (fabs(s - b) >= (0.5f * fabs(c - d)))) ||
+        (mflag && (fabs(b - c) < error_tol)) ||
+        (!mflag && (fabs(c - d) < error_tol))) {
+      s = 0.5f * (a + b);
+      mflag = 1;
+    } else {
+      mflag = 0;
+    }
+    fs = riemann_f(s, WL, WR, vL, vR);
+    d = c;
+    c = b;
+    fc = fb;
+    if (fa * fs < 0.) {
+      b = s;
+      fb = fs;
+    } else {
+      a = s;
+      fa = fs;
+    }
+
+    /* if |f(a)| < |f(b)| then swap (a,b) */
+    if (fabs(fa) < fabs(fb)) {
+      tmp = a;
+      a = b;
+      b = tmp;
+      tmp = fa;
+      fa = fb;
+      fb = tmp;
+    }
+    i++;
+  }
+  return b;
+}
+
+/**
+ * @brief Solve the Riemann problem between the given left and right state and
+ * along the given interface normal
+ *
+ * @param WL The left state vector
+ * @param WR The right state vector
+ * @param Whalf Empty state vector in which the result will be stored
+ * @param n_unit Normal vector of the interface
+ */
+__attribute__((always_inline)) INLINE static void riemann_solver_solve(
+    float* WL, float* WR, float* Whalf, float* n_unit) {
+
+  /* velocity of the left and right state in a frame aligned with n_unit */
+  float vL, vR, vhalf;
+  /* variables used for finding rhostar */
+  float rho, rhoguess, frho, frhoguess;
+  /* variables used for sampling the solution */
+  float u, S, SH, ST;
+
+  int errorFlag = 0;
+
+  /* sanity checks */
+  if (WL[0] != WL[0]) {
+    printf("NaN WL!\n");
+    errorFlag = 1;
+  }
+  if (WR[0] != WR[0]) {
+    printf("NaN WR!\n");
+    errorFlag = 1;
+  }
+  if (WL[0] < 0.0f) {
+    printf("Negative WL!\n");
+    errorFlag = 1;
+  }
+  if (WR[0] < 0.0f) {
+    printf("Negative WR!\n");
+    errorFlag = 1;
+  }
+  if (errorFlag) {
+    printf("WL: %g %g %g %g %g\n", WL[0], WL[1], WL[2], WL[3], WL[4]);
+    printf("WR: %g %g %g %g %g\n", WR[0], WR[1], WR[2], WR[3], WR[4]);
+    error("Riemman solver input error!\n");
+  }
+
+  /* calculate velocities in interface frame */
+  vL = WL[1] * n_unit[0] + WL[2] * n_unit[1] + WL[3] * n_unit[2];
+  vR = WR[1] * n_unit[0] + WR[2] * n_unit[1] + WR[3] * n_unit[2];
+
+  /* VACUUM... */
+
+  rho = 0.;
+  /* obtain a first guess for p */
+  rhoguess = riemann_guess_rho(WL, WR, vL, vR);
+  frho = riemann_f(rho, WL, WR, vL, vR);
+  frhoguess = riemann_f(rhoguess, WL, WR, vL, vR);
+  /* ok, rhostar is close to 0, better use Brent's method... */
+  /* we use Newton-Raphson until we find a suitable interval */
+  if (frho * frhoguess >= 0.0f) {
+    /* Newton-Raphson until convergence or until suitable interval is found
+       to use Brent's method */
+    unsigned int counter = 0;
+    while (fabs(rho - rhoguess) > 1.e-6f * 0.5f * (rho + rhoguess) &&
+           frhoguess < 0.0f) {
+      rho = rhoguess;
+      rhoguess = rhoguess - frhoguess / riemann_fprime(rhoguess, WL, WR);
+      frhoguess = riemann_f(rhoguess, WL, WR, vL, vR);
+      counter++;
+      if (counter > 1000) {
+        error("Stuck in Newton-Raphson!\n");
+      }
+    }
+  }
+  /* As soon as there is a suitable interval: use Brent's method */
+  if (1.e6 * fabs(rho - rhoguess) > 0.5f * (rho + rhoguess) &&
+      frhoguess > 0.0f) {
+    rho = 0.0f;
+    frho = riemann_f(rho, WL, WR, vL, vR);
+    /* use Brent's method to find the zeropoint */
+    rho = riemann_solve_brent(rho, rhoguess, frho, frhoguess, 1.e-6, WL, WR, vL,
+                              vR);
+  } else {
+    rho = rhoguess;
+  }
+
+  /* calculate the middle state velocity */
+  u = 0.5f * (vL - riemann_fb(rho, WL) + vR + riemann_fb(rho, WR));
+
+  /* sample the solution */
+  if (u > 0.0f) {
+    /* left state */
+    Whalf[1] = WL[1];
+    Whalf[2] = WL[2];
+    Whalf[3] = WL[3];
+    if (WL[0] < rho) {
+      /* left shock wave */
+      S = vL - const_isothermal_soundspeed * sqrtf(rho / WL[0]);
+      if (S >= 0.) {
+        /* to the left of the shock */
+        Whalf[0] = WL[0];
+        vhalf = 0.0f;
+      } else {
+        /* to the right of the shock */
+        Whalf[0] = rho;
+        vhalf = u - vL;
+      }
+    } else {
+      /* left rarefaction wave */
+      SH = vL - const_isothermal_soundspeed;
+      ST = u - const_isothermal_soundspeed;
+      if (SH > 0.) {
+        /* to the left of the rarefaction */
+        Whalf[0] = WL[0];
+        vhalf = 0.0f;
+      } else if (ST > 0.0f) {
+        /* inside the rarefaction */
+        Whalf[0] = WL[0] * expf(vL / const_isothermal_soundspeed - 1.0f);
+        vhalf = const_isothermal_soundspeed - vL;
+      } else {
+        /* to the right of the rarefaction */
+        Whalf[0] = rho;
+        vhalf = u - vL;
+      }
+    }
+  } else {
+    /* right state */
+    Whalf[1] = WR[1];
+    Whalf[2] = WR[2];
+    Whalf[3] = WR[3];
+    if (WR[0] < rho) {
+      /* right shock wave */
+      S = vR + const_isothermal_soundspeed * sqrtf(rho / WR[0]);
+      if (S > 0.0f) {
+        /* to the left of the shock wave: middle state */
+        Whalf[0] = rho;
+        vhalf = u - vR;
+      } else {
+        /* to the right of the shock wave: right state */
+        Whalf[0] = WR[0];
+        vhalf = 0.0f;
+      }
+    } else {
+      /* right rarefaction wave */
+      SH = vR + const_isothermal_soundspeed;
+      ST = u + const_isothermal_soundspeed;
+      if (ST > 0.0f) {
+        /* to the left of rarefaction: middle state */
+        Whalf[0] = rho;
+        vhalf = u - vR;
+      } else if (SH > 0.0f) {
+        /* inside rarefaction */
+        Whalf[0] = WR[0] * expf(-vR / const_isothermal_soundspeed - 1.0f);
+        vhalf = -const_isothermal_soundspeed - vR;
+      } else {
+        /* to the right of rarefaction: right state */
+        Whalf[0] = WR[0];
+        vhalf = 0.0f;
+      }
+    }
+  }
+
+  /* add the velocity solution along the interface normal to the velocities */
+  Whalf[1] += vhalf * n_unit[0];
+  Whalf[2] += vhalf * n_unit[1];
+  Whalf[3] += vhalf * n_unit[2];
+
+  /* the pressure is completely irrelevant in this case */
+  Whalf[4] =
+      Whalf[0] * const_isothermal_soundspeed * const_isothermal_soundspeed;
+}
+
+__attribute__((always_inline)) INLINE static void riemann_solve_for_flux(
+    float* Wi, float* Wj, float* n_unit, float* vij, float* totflux) {
+
+  float Whalf[5];
+  float flux[5][3];
+  float vtot[3];
+  float rhoe;
+
+  riemann_solver_solve(Wi, Wj, Whalf, n_unit);
+
+  flux[0][0] = Whalf[0] * Whalf[1];
+  flux[0][1] = Whalf[0] * Whalf[2];
+  flux[0][2] = Whalf[0] * Whalf[3];
+
+  vtot[0] = Whalf[1] + vij[0];
+  vtot[1] = Whalf[2] + vij[1];
+  vtot[2] = Whalf[3] + vij[2];
+  flux[1][0] = Whalf[0] * vtot[0] * Whalf[1] + Whalf[4];
+  flux[1][1] = Whalf[0] * vtot[0] * Whalf[2];
+  flux[1][2] = Whalf[0] * vtot[0] * Whalf[3];
+  flux[2][0] = Whalf[0] * vtot[1] * Whalf[1];
+  flux[2][1] = Whalf[0] * vtot[1] * Whalf[2] + Whalf[4];
+  flux[2][2] = Whalf[0] * vtot[1] * Whalf[3];
+  flux[3][0] = Whalf[0] * vtot[2] * Whalf[1];
+  flux[3][1] = Whalf[0] * vtot[2] * Whalf[2];
+  flux[3][2] = Whalf[0] * vtot[2] * Whalf[3] + Whalf[4];
+
+  /* eqn. (15) */
+  /* F_P = \rho e ( \vec{v} - \vec{v_{ij}} ) + P \vec{v} */
+  /* \rho e = P / (\gamma-1) + 1/2 \rho \vec{v}^2 */
+  rhoe = Whalf[4] / hydro_gamma_minus_one +
+         0.5f * Whalf[0] *
+             (vtot[0] * vtot[0] + vtot[1] * vtot[1] + vtot[2] * vtot[2]);
+  flux[4][0] = rhoe * Whalf[1] + Whalf[4] * vtot[0];
+  flux[4][1] = rhoe * Whalf[2] + Whalf[4] * vtot[1];
+  flux[4][2] = rhoe * Whalf[3] + Whalf[4] * vtot[2];
+
+  totflux[0] =
+      flux[0][0] * n_unit[0] + flux[0][1] * n_unit[1] + flux[0][2] * n_unit[2];
+  totflux[1] =
+      flux[1][0] * n_unit[0] + flux[1][1] * n_unit[1] + flux[1][2] * n_unit[2];
+  totflux[2] =
+      flux[2][0] * n_unit[0] + flux[2][1] * n_unit[1] + flux[2][2] * n_unit[2];
+  totflux[3] =
+      flux[3][0] * n_unit[0] + flux[3][1] * n_unit[1] + flux[3][2] * n_unit[2];
+  totflux[4] =
+      flux[4][0] * n_unit[0] + flux[4][1] * n_unit[1] + flux[4][2] * n_unit[2];
+}
+
+#endif /* SWIFT_RIEMANN_EXACT_ISOTHERMAL_H */
diff --git a/src/riemann/riemann_hllc.h b/src/riemann/riemann_hllc.h
index 1a4c3f5f8338f6504a8c5f1d9eab8451eb20246c..962fb8380ad9919d7b7ad96325a12f0bfc53d255 100644
--- a/src/riemann/riemann_hllc.h
+++ b/src/riemann/riemann_hllc.h
@@ -24,6 +24,11 @@
 #include "minmax.h"
 #include "riemann_vacuum.h"
 
+#ifndef EOS_IDEAL_GAS
+#error \
+    "The HLLC Riemann solver currently only supports and ideal gas equation of state. Either select this equation of state, or try using another Riemann solver!"
+#endif
+
 __attribute__((always_inline)) INLINE static void riemann_solve_for_flux(
     float *WL, float *WR, float *n, float *vij, float *totflux) {
 
diff --git a/src/riemann/riemann_trrs.h b/src/riemann/riemann_trrs.h
index b13a76b4c57af548497780e974e5c9ee3a721fac..be56b93583b693d7d492e0c8b1357cdbe57e88b5 100644
--- a/src/riemann/riemann_trrs.h
+++ b/src/riemann/riemann_trrs.h
@@ -23,6 +23,11 @@
 #include "adiabatic_index.h"
 #include "riemann_vacuum.h"
 
+#ifndef EOS_IDEAL_GAS
+#error \
+    "The TRRS Riemann solver currently only supports an ideal gas equation of state. Either select this equation of state, or try using another Riemann solver!"
+#endif
+
 /**
  * @brief Solve the Riemann problem using the Two Rarefaction Riemann Solver
  *
diff --git a/src/runner.c b/src/runner.c
index 7294d0e1c862af4f31c0ef32b5f936df56e9df70..cf70e482bc5e31d35500ec00a49e4d888d6270f5 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -184,12 +184,12 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) {
   for (int i = 0; i < gcount; i++) {
 
     /* Get a direct pointer on the part. */
-    struct gpart *restrict g = &gparts[i];
+    struct gpart *restrict gp = &gparts[i];
 
     /* Is this part within the time step? */
-    if (g->ti_end <= ti_current) {
+    if (gp->ti_end <= ti_current) {
 
-      external_gravity_acceleration(time, potential, constants, g);
+      external_gravity_acceleration(time, potential, constants, gp);
     }
   }
 
@@ -1333,9 +1333,12 @@ void *runner_main(void *data) {
             runner_doself2_force(r, ci);
           else if (t->subtype == task_subtype_grav)
             runner_doself_grav(r, ci, 1);
+          else if (t->subtype == task_subtype_external_grav)
+            runner_do_grav_external(r, ci, 1);
           else
             error("Unknown task subtype.");
           break;
+
         case task_type_pair:
           if (t->subtype == task_subtype_density)
             runner_dopair1_density(r, ci, cj);
@@ -1350,9 +1353,7 @@ void *runner_main(void *data) {
           else
             error("Unknown task subtype.");
           break;
-        case task_type_sort:
-          runner_do_sort(r, ci, t->flags, 1);
-          break;
+
         case task_type_sub_self:
           if (t->subtype == task_subtype_density)
             runner_dosub_self1_density(r, ci, 1);
@@ -1364,9 +1365,12 @@ void *runner_main(void *data) {
             runner_dosub_self2_force(r, ci, 1);
           else if (t->subtype == task_subtype_grav)
             runner_dosub_grav(r, ci, cj, 1);
+          else if (t->subtype == task_subtype_external_grav)
+            runner_do_grav_external(r, ci, 1);
           else
             error("Unknown task subtype.");
           break;
+
         case task_type_sub_pair:
           if (t->subtype == task_subtype_density)
             runner_dosub_pair1_density(r, ci, cj, t->flags, 1);
@@ -1381,6 +1385,10 @@ void *runner_main(void *data) {
           else
             error("Unknown task subtype.");
           break;
+
+        case task_type_sort:
+          runner_do_sort(r, ci, t->flags, 1);
+          break;
         case task_type_init:
           runner_do_init(r, ci, 1);
           break;
@@ -1424,9 +1432,6 @@ void *runner_main(void *data) {
         case task_type_grav_fft:
           runner_do_grav_fft(r);
           break;
-        case task_type_grav_external:
-          runner_do_grav_external(r, t->ci, 1);
-          break;
         case task_type_cooling:
           runner_do_cooling(r, t->ci, 1);
           break;
diff --git a/src/scheduler.c b/src/scheduler.c
index b4e2575807aff4cb8b3878dcb25a773269038b74..e3fe92e51ad810ad932cdd307dd25c7fe6f60f4c 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -1185,20 +1185,10 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) {
         break;
       case task_type_pair:
       case task_type_sub_pair:
-        if (t->subtype == task_subtype_grav) {
-
-          qid = t->ci->gsuper->owner;
-          if (qid < 0 ||
-              s->queues[qid].count > s->queues[t->cj->gsuper->owner].count)
-            qid = t->cj->gsuper->owner;
-
-        } else {
-
-          qid = t->ci->super->owner;
-          if (qid < 0 ||
-              s->queues[qid].count > s->queues[t->cj->super->owner].count)
-            qid = t->cj->super->owner;
-        }
+        qid = t->ci->super->owner;
+        if (qid < 0 ||
+            s->queues[qid].count > s->queues[t->cj->super->owner].count)
+          qid = t->cj->super->owner;
         break;
       case task_type_recv:
 #ifdef WITH_MPI
diff --git a/src/space.c b/src/space.c
index ddd4c076e9ef9c18c8bf25eeb9360dc7333b88f8..186e11c066f3c8d788c3eaa189da3ed2461aed87 100644
--- a/src/space.c
+++ b/src/space.c
@@ -112,6 +112,15 @@ struct parallel_sort {
   volatile unsigned int first, last, waiting;
 };
 
+/**
+ * @brief Information required to compute the particle cell indices.
+ */
+struct index_data {
+  struct space *s;
+  struct cell *cells;
+  int *ind;
+};
+
 /**
  * @brief Get the shift-id of the given pair of cells, swapping them
  *      if need be.
@@ -326,7 +335,6 @@ void space_regrid(struct space *s, double cell_max, int verbose) {
           c->count = 0;
           c->gcount = 0;
           c->super = c;
-          c->gsuper = c;
           c->ti_old = ti_current;
           lock_init(&c->lock);
         }
@@ -402,7 +410,6 @@ void space_regrid(struct space *s, double cell_max, int verbose) {
       s->cells_top[k].cooling = NULL;
       s->cells_top[k].sourceterms = NULL;
       s->cells_top[k].super = &s->cells_top[k];
-      s->cells_top[k].gsuper = &s->cells_top[k];
 #if WITH_MPI
       s->cells_top[k].recv_xv = NULL;
       s->cells_top[k].recv_rho = NULL;
@@ -446,49 +453,21 @@ void space_rebuild(struct space *s, double cell_max, int verbose) {
   struct cell *restrict cells_top = s->cells_top;
   const int ti_current = (s->e != NULL) ? s->e->ti_current : 0;
 
-  const double ih[3] = {s->iwidth[0], s->iwidth[1], s->iwidth[2]};
-  const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
-  const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]};
-
   /* Run through the particles and get their cell index. */
-  // tic = getticks();
   const size_t ind_size = s->size_parts;
   int *ind;
   if ((ind = (int *)malloc(sizeof(int) * ind_size)) == NULL)
     error("Failed to allocate temporary particle indices.");
-  for (size_t k = 0; k < nr_parts; k++) {
-    struct part *restrict p = &s->parts[k];
-    for (int j = 0; j < 3; j++)
-      if (p->x[j] < 0.0)
-        p->x[j] += dim[j];
-      else if (p->x[j] >= dim[j])
-        p->x[j] -= dim[j];
-    ind[k] =
-        cell_getid(cdim, p->x[0] * ih[0], p->x[1] * ih[1], p->x[2] * ih[2]);
-    cells_top[ind[k]].count++;
-  }
-  // message( "getting particle indices took %.3f %s." ,
-  // clocks_from_ticks(getticks() - tic), clocks_getunit()):
+  if (ind_size > 0) space_parts_get_cell_index(s, ind, cells_top, verbose);
+  for (size_t i = 0; i < s->nr_parts; ++i) cells_top[ind[i]].count++;
 
   /* Run through the gravity particles and get their cell index. */
-  // tic = getticks();
   const size_t gind_size = s->size_gparts;
   int *gind;
   if ((gind = (int *)malloc(sizeof(int) * gind_size)) == NULL)
     error("Failed to allocate temporary g-particle indices.");
-  for (size_t k = 0; k < nr_gparts; k++) {
-    struct gpart *restrict gp = &s->gparts[k];
-    for (int j = 0; j < 3; j++)
-      if (gp->x[j] < 0.0)
-        gp->x[j] += dim[j];
-      else if (gp->x[j] >= dim[j])
-        gp->x[j] -= dim[j];
-    gind[k] =
-        cell_getid(cdim, gp->x[0] * ih[0], gp->x[1] * ih[1], gp->x[2] * ih[2]);
-    cells_top[gind[k]].gcount++;
-  }
-// message( "getting g-particle indices took %.3f %s." ,
-// clocks_from_ticks(getticks() - tic), clocks_getunit());
+  if (gind_size > 0) space_gparts_get_cell_index(s, gind, cells_top, verbose);
+  for (size_t i = 0; i < s->nr_gparts; ++i) cells_top[gind[i]].gcount++;
 
 #ifdef WITH_MPI
 
@@ -592,6 +571,9 @@ void space_rebuild(struct space *s, double cell_max, int verbose) {
     ind = ind_new;
   }
 
+  const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]};
+  const double ih[3] = {s->iwidth[0], s->iwidth[1], s->iwidth[2]};
+
   /* Assign each particle to its cell. */
   for (size_t k = nr_parts; k < s->nr_parts; k++) {
     const struct part *const p = &s->parts[k];
@@ -619,9 +601,10 @@ void space_rebuild(struct space *s, double cell_max, int verbose) {
   for (size_t k = 1; k < nr_parts; k++) {
     if (ind[k - 1] > ind[k]) {
       error("Sort failed!");
-    } else if (ind[k] != cell_getid(cdim, s->parts[k].x[0] * ih[0],
-                                    s->parts[k].x[1] * ih[1],
-                                    s->parts[k].x[2] * ih[2])) {
+    } else if (ind[k] != cell_getid(s->cdim, 
+                                    s->parts[k].x[0] * s->iwidth[0],
+                                    s->parts[k].x[1] * s->iwidth[1],
+                                    s->parts[k].x[2] * s->iwidth[2])) {
       error("Incorrect indices!");
     }
   }
@@ -766,6 +749,164 @@ void space_sanitize(struct space *s) {
   }
 }
 
+/**
+ * @brief #threadpool mapper function to compute the particle cell indices.
+ *
+ * @param map_data Pointer towards the particles.
+ * @param nr_parts The number of particles to treat.
+ * @param extra_data Pointers to the space and index list
+ */
+void space_parts_get_cell_index_mapper(void *map_data, int nr_parts,
+                                       void *extra_data) {
+
+  /* Unpack the data */
+  struct part *restrict parts = (struct part *)map_data;
+  struct index_data *data = (struct index_data *)extra_data;
+  struct space *s = data->s;
+  int *const ind = data->ind + (ptrdiff_t)(parts - s->parts);
+
+  /* Get some constants */
+  const double dim_x = s->dim[0];
+  const double dim_y = s->dim[1];
+  const double dim_z = s->dim[2];
+  const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]};
+  const double ih_x = s->iwidth[0];
+  const double ih_y = s->iwidth[1];
+  const double ih_z = s->iwidth[2];
+
+  for (int k = 0; k < nr_parts; k++) {
+
+    /* Get the particle */
+    struct part *restrict p = &parts[k];
+
+    const double old_pos_x = p->x[0];
+    const double old_pos_y = p->x[1];
+    const double old_pos_z = p->x[2];
+
+    /* Put it back into the simulation volume */
+    const double pos_x = box_wrap(old_pos_x, 0.0, dim_x);
+    const double pos_y = box_wrap(old_pos_y, 0.0, dim_y);
+    const double pos_z = box_wrap(old_pos_z, 0.0, dim_z);
+
+    /* Get its cell index */
+    const int index =
+        cell_getid(cdim, pos_x * ih_x, pos_y * ih_y, pos_z * ih_z);
+    ind[k] = index;
+
+    /* Update the position */
+    p->x[0] = pos_x;
+    p->x[1] = pos_y;
+    p->x[2] = pos_z;
+  }
+}
+
+/**
+ * @brief #threadpool mapper function to compute the g-particle cell indices.
+ *
+ * @param map_data Pointer towards the g-particles.
+ * @param nr_gparts The number of g-particles to treat.
+ * @param extra_data Pointers to the space and index list
+ */
+void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts,
+                                        void *extra_data) {
+
+  /* Unpack the data */
+  struct gpart *restrict gparts = (struct gpart *)map_data;
+  struct index_data *data = (struct index_data *)extra_data;
+  struct space *s = data->s;
+  int *const ind = data->ind + (ptrdiff_t)(gparts - s->gparts);
+
+  /* Get some constants */
+  const double dim_x = s->dim[0];
+  const double dim_y = s->dim[1];
+  const double dim_z = s->dim[2];
+  const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]};
+  const double ih_x = s->iwidth[0];
+  const double ih_y = s->iwidth[1];
+  const double ih_z = s->iwidth[2];
+
+  for (int k = 0; k < nr_gparts; k++) {
+
+    /* Get the particle */
+    struct gpart *restrict gp = &gparts[k];
+
+    const double old_pos_x = gp->x[0];
+    const double old_pos_y = gp->x[1];
+    const double old_pos_z = gp->x[2];
+
+    /* Put it back into the simulation volume */
+    const double pos_x = box_wrap(old_pos_x, 0.0, dim_x);
+    const double pos_y = box_wrap(old_pos_y, 0.0, dim_y);
+    const double pos_z = box_wrap(old_pos_z, 0.0, dim_z);
+
+    /* Get its cell index */
+    const int index =
+        cell_getid(cdim, pos_x * ih_x, pos_y * ih_y, pos_z * ih_z);
+    ind[k] = index;
+
+    /* Update the position */
+    gp->x[0] = pos_x;
+    gp->x[1] = pos_y;
+    gp->x[2] = pos_z;
+  }
+}
+
+/**
+ * @brief Computes the cell index of all the particles and update the cell
+ * count.
+ *
+ * @param s The #space.
+ * @param ind The array of indices to fill.
+ * @param cells The array of #cell to update.
+ * @param verbose Are we talkative ?
+ */
+void space_parts_get_cell_index(struct space *s, int *ind, struct cell *cells,
+                                int verbose) {
+
+  const ticks tic = getticks();
+
+  /* Pack the extra information */
+  struct index_data data;
+  data.s = s;
+  data.cells = cells;
+  data.ind = ind;
+
+  threadpool_map(&s->e->threadpool, space_parts_get_cell_index_mapper, s->parts,
+                 s->nr_parts, sizeof(struct part), 1000, &data);
+
+  if (verbose)
+    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+            clocks_getunit());
+}
+
+/**
+ * @brief Computes the cell index of all the g-particles and update the cell
+ * gcount.
+ *
+ * @param s The #space.
+ * @param gind The array of indices to fill.
+ * @param cells The array of #cell to update.
+ * @param verbose Are we talkative ?
+ */
+void space_gparts_get_cell_index(struct space *s, int *gind, struct cell *cells,
+                                 int verbose) {
+
+  const ticks tic = getticks();
+
+  /* Pack the extra information */
+  struct index_data data;
+  data.s = s;
+  data.cells = cells;
+  data.ind = gind;
+
+  threadpool_map(&s->e->threadpool, space_gparts_get_cell_index_mapper,
+                 s->gparts, s->nr_gparts, sizeof(struct gpart), 1000, &data);
+
+  if (verbose)
+    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
+            clocks_getunit());
+}
+
 /**
  * @brief Sort the particles and condensed particles according to the given
  * indices.
@@ -1351,7 +1492,6 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) {
         temp->nodeID = c->nodeID;
         temp->parent = c;
         temp->super = NULL;
-        temp->gsuper = NULL;
         c->progeny[k] = temp;
       }
 
diff --git a/src/space.h b/src/space.h
index 85f32bd7580945de6d9713316b557c92667987c0..011dfb71a6c3ac2b51093ce83bc6b65ceecc2821 100644
--- a/src/space.h
+++ b/src/space.h
@@ -170,6 +170,10 @@ void space_recycle(struct space *s, struct cell *c);
 void space_split(struct space *s, struct cell *cells, int nr_cells,
                  int verbose);
 void space_split_mapper(void *map_data, int num_elements, void *extra_data);
+void space_parts_get_cell_index(struct space *s, int *ind, struct cell *cells,
+                                int verbose);
+void space_gparts_get_cell_index(struct space *s, int *gind, struct cell *cells,
+                                 int verbose);
 void space_do_parts_sort();
 void space_do_gparts_sort();
 void space_init_parts(struct space *s);
diff --git a/src/task.c b/src/task.c
index 00068f45769b4ca606cc729bd5e89c13ae729eef..54b9363b7ac3d5c372b591c00b0b03cc274f66b5 100644
--- a/src/task.c
+++ b/src/task.c
@@ -48,13 +48,13 @@
 
 /* Task type names. */
 const char *taskID_names[task_type_count] = {
-    "none",       "sort",    "self",          "pair",          "sub_self",
-    "sub_pair",   "init",    "ghost",         "extra_ghost",   "kick",
-    "kick_fixdt", "send",    "recv",          "grav_gather_m", "grav_fft",
-    "grav_mm",    "grav_up", "grav_external", "cooling",       "sourceterms"};
+    "none",       "sort",    "self",    "pair",          "sub_self",
+    "sub_pair",   "init",    "ghost",   "extra_ghost",   "kick",
+    "kick_fixdt", "send",    "recv",    "grav_gather_m", "grav_fft",
+    "grav_mm",    "grav_up", "cooling", "sourceterms"};
 
 const char *subtaskID_names[task_subtype_count] = {
-    "none", "density", "gradient", "force", "grav", "tend"};
+    "none", "density", "gradient", "force", "grav", "external_grav", "tend"};
 
 /**
  * @brief Computes the overlap between the parts array of two given cells.
@@ -135,6 +135,7 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
           break;
 
         case task_subtype_grav:
+        case task_subtype_external_grav:
           return task_action_gpart;
           break;
 
@@ -150,7 +151,14 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
     case task_type_kick_fixdt:
     case task_type_send:
     case task_type_recv:
-      return task_action_all;
+      if (t->ci->count > 0 && t->ci->gcount > 0)
+        return task_action_all;
+      else if (t->ci->count > 0)
+        return task_action_part;
+      else if (t->ci->gcount > 0)
+        return task_action_gpart;
+      else
+        error("Task without particles");
       break;
 
     case task_type_grav_gather_m:
@@ -160,10 +168,6 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
       return task_action_multipole;
       break;
 
-    case task_type_grav_external:
-      return task_action_gpart;
-      break;
-
     default:
       error("Unknown task_action for task");
       return task_action_none;
@@ -393,3 +397,15 @@ void task_print_submask(unsigned int submask) {
     printf(" %s=%s", subtaskID_names[k], (submask & (1 << k)) ? "yes" : "no");
   printf(" ]\n");
 }
+
+/**
+ * @brief Print basic information about a task.
+ *
+ * @param t The #task.
+ */
+void task_print(const struct task *t) {
+
+  message("Type:'%s' sub_type:'%s' wait=%d nr_unlocks=%d skip=%d",
+          taskID_names[t->type], subtaskID_names[t->subtype], t->wait,
+          t->nr_unlock_tasks, t->skip);
+}
diff --git a/src/task.h b/src/task.h
index bc4df3dc2a4cfee3c382e9f2059cba84f29299f7..f840c0b4b8e807dce28f6f13479dbdf4995ab66d 100644
--- a/src/task.h
+++ b/src/task.h
@@ -53,7 +53,6 @@ enum task_types {
   task_type_grav_fft,
   task_type_grav_mm,
   task_type_grav_up,
-  task_type_grav_external,
   task_type_cooling,
   task_type_sourceterms,
   task_type_count
@@ -68,6 +67,7 @@ enum task_subtypes {
   task_subtype_gradient,
   task_subtype_force,
   task_subtype_grav,
+  task_subtype_external_grav,
   task_subtype_tend,
   task_subtype_count
 } __attribute__((packed));
@@ -160,5 +160,6 @@ int task_lock(struct task *t);
 void task_print_mask(unsigned int mask);
 void task_print_submask(unsigned int submask);
 void task_do_rewait(struct task *t);
+void task_print(const struct task *t);
 
 #endif /* SWIFT_TASK_H */
diff --git a/theory/SPH/Flavours/sph_flavours.tex b/theory/SPH/Flavours/sph_flavours.tex
index 1ca7fb7018ed14cbf4972a181b66f841b75b6f43..5fe1277373552d60607671299437a371e068169c 100644
--- a/theory/SPH/Flavours/sph_flavours.tex
+++ b/theory/SPH/Flavours/sph_flavours.tex
@@ -305,17 +305,72 @@ P_{\partial h_i}$ and $\rho_{\partial h_i}$
 (eq. \ref{eq:sph:minimal:rho_dh}):
 
 \begin{equation}
-  f_i \equiv \left(\frac{\bar P_{\partial h_i} h_i}{3\rho_i
-    \tilde{A}_i}\right)\left(1 + \frac{h_i}{3\rho_i}\rho_{\partial 
-    h_i}\right)^{-1}.
+  f_i \equiv \left(\frac{h_i}{3\rho_i}\bar P_{\partial
+    h_i}\right)\left(1 + \frac{h_i}{3\rho_i}\rho_{\partial
+    h_i}\right)^{-1}. 
 \end{equation}
 
 \subsubsection{Hydrodynamical accelerations (\nth{2} neighbour loop)}
 
+The accelerations are given by the following term:
+
+\begin{align}
+  \frac{d\vec{v}_i}{dt} = -\sum_j m_j &\left[\frac{\bar P_i}{\bar\rho_i^2} \left(\frac{\tilde A_j}{\tilde A_i} - \frac{f_i}{\tilde A_i}\right)\nabla_x W(\vec{x}_{ij}, h_i) \right.  \nonumber \\
+  &+\frac{P_j}{\rho_j^2} \left(\frac{\tilde A_i}{\tilde A_j} - \frac{f_j}{\tilde A_j}\right)\nabla_x W(\vec{x}_{ij},h_j) \\
+  &+ \left. \bigg.\nu_{ij} \Wij \right], \label{eq:sph:pe:dv_dt}
+\end{align}
+where the viscosity term $\nu_{ij}$ has been computed as in
+the \GadgetSPH case (Eq. \ref{eq:sph:gadget2:balsara}
+and \ref{eq:sph:gadget2:nu_ij}). For completeness, the equation of
+motion for the entropy is
+
+\begin{equation}
+\frac{dA_i}{dt} = \frac{1}{2} A_{\rm eos}\left(\rho_i, \sum_j
+m_j \nu_{ij}\vec{v}_{ij}\cdot \Wij\right).
+\end{equation}
+
+\subsubsection{Time integration}
+
+The time-step condition is identical to the \MinimalSPH case
+(Eq. \ref{eq:sph:minimal:dt}). The same applies to the integration
+forward in time (Eq. \ref{eq:sph:minimal:kick_v} to
+\ref{eq:sph:minimal:kick_c}) with the exception of the change in
+internal energy (Eq. \ref{eq:sph:minimal:kick_u}) which gets replaced
+by an integration for the the entropy:
+
+\begin{align}
+  \vec{v}_i &\rightarrow \vec{v}_i + \frac{d\vec{v}_i}{dt} \Delta t  \label{eq:sph:pe:kick_v}\\
+  A_i &\rightarrow A_i + \frac{dA_i}{dt} \Delta t \label{eq:sph:pe:kick_A}\\
+  P_i &\rightarrow P_{\rm eos}\left(\rho_i, A_i\right) \label{eq:sph:pe:kick_P}, \\
+  c_i &\rightarrow c_{\rm eos}\left(\rho_i,
+  A_i\right) \label{eq:sph:pe:kick_c}, \\
+  \tilde A_i &= A_i^{1/\gamma}
+\end{align}
+where, once again, we made use of the equation of state relating
+thermodynamical quantities.
 
 
 \subsubsection{Particle properties prediction}
 
+The prediction step is also identical to the \MinimalSPH case with the
+entropic function replacing the thermal energy.
+
+\begin{align}
+  \vec{x}_i &\rightarrow \vec{x}_i + \vec{v}_i \Delta t  \label{eq:sph:pe:drift_x} \\
+  h_i &\rightarrow h_i \exp\left(\frac{1}{h_i} \frac{dh_i}{dt}
+  \Delta t\right), \label{eq:sph:pe:drift_h}\\
+  \rho_i &\rightarrow \rho_i \exp\left(-\frac{3}{h_i} \frac{dh_i}{dt}
+  \Delta t\right), \label{eq:sph:pe:drift_rho} \\
+  \tilde A_i &\rightarrow \left(A_i + \frac{dA_i}{dt}
+  \Delta t\right)^{1/\gamma} \label{eq:sph:pe:drift_A_tilde}, \\
+  P_i &\rightarrow P_{\rm eos}\left(\rho_i, A_i + \frac{dA_i}{dt} \Delta t\right), \label{eq:sph:pe:drift_P}\\
+  c_i &\rightarrow c_{\rm eos}\left(\rho_i, A_i + \frac{dA_i}{dt}
+  \Delta t\right) \label{eq:sph:pe:drift_c}, 
+\end{align}
+where, as above, the last two updated quantities are obtained using
+the pre-defined equation of state. Note that the entropic function $A_i$
+itself is \emph{not} updated.
+
 \subsection{Pressure-Energy SPH}
 \label{sec:sph:pu}