diff --git a/src/cell_drift.c b/src/cell_drift.c
index 008516fdb61275cb854341251cf7baf5cce41b48..73a7ad1c5cbacf984b7ece2f1bdde648847d5eb9 100644
--- a/src/cell_drift.c
+++ b/src/cell_drift.c
@@ -241,7 +241,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
     }
 
 #ifdef SHADOWFAX_SPH
-    cell_malloc_delaunay_tesselation(c, &e->s->hs);
+    cell_malloc_delaunay_tessellation(c, &e->s->hs);
 #endif
 
     /* Now, get the maximal particle motion from its square */
diff --git a/src/cell_hydro.h b/src/cell_hydro.h
index 566e231cb2e17f74477c2af8c4de05af15e0bd6f..5f53ed8b09b17d0575edc775c70d612d8d9c5a92 100644
--- a/src/cell_hydro.h
+++ b/src/cell_hydro.h
@@ -45,6 +45,8 @@ struct cell_hydro {
   struct xpart *xparts;
 
 #ifdef SHADOWFAX_SPH
+  /*! Was Shadowfax functionality enabled for this cell? */
+  /*  int shadowfax_enabled;*/
   /*! Delaunay tessellation. */
   struct delaunay deltess;
   /*! Voronoi tessellation. */
diff --git a/src/hydro/Shadowswift/hydro.h b/src/hydro/Shadowswift/hydro.h
index 42cb26e4c37ae6482f9b823b1fea2ccd3a018941..20f4f378c3dcfbc4964d037e2aeca261ba77c481 100644
--- a/src/hydro/Shadowswift/hydro.h
+++ b/src/hydro/Shadowswift/hydro.h
@@ -213,6 +213,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_density(
     p->density.wcount_dh = p->h / (1.1f * hnew - p->h);
     return;
   }
+  p->density.wcount = 1.0f;
   volume = p->cell.volume;
 
 #ifdef SWIFT_DEBUG_CHECKS
diff --git a/src/hydro/Shadowswift/hydro_part.h b/src/hydro/Shadowswift/hydro_part.h
index 343697f3473a9a4e6487ac3318f95271639de8a8..027b0e2ff72d60c3e207a51f7ee180c86b6774dd 100644
--- a/src/hydro/Shadowswift/hydro_part.h
+++ b/src/hydro/Shadowswift/hydro_part.h
@@ -217,6 +217,14 @@ struct part {
   /* Voronoi cell. */
   struct voronoi_cell cell;
 
+  /* New Voronoi cell. */
+  struct {
+    /* Flag that keeps track of where this particle was added to the Delaunay
+       tessellation. */
+    int flag;
+
+  } voronoi;
+
 } SWIFT_STRUCT_ALIGN;
 
 #endif /* SWIFT_SHADOWSWIFT_HYDRO_PART_H */
diff --git a/src/hydro_space.c b/src/hydro_space.c
index 9c5ab9fc619fca98dc22f15124bf4a6a63dcd539..982307474cdf526b0ab68292cb2aab2d02c14939 100644
--- a/src/hydro_space.c
+++ b/src/hydro_space.c
@@ -19,6 +19,7 @@
 
 #include "hydro_space.h"
 
+#include "error.h"
 #include "space.h"
 
 /**
@@ -46,6 +47,11 @@ __attribute__((always_inline)) INLINE void hydro_space_init(
     hs->side[1] = s->dim[1];
     hs->side[2] = s->dim[2];
   }
+
+  message(
+      "Initialised hydro space with anchor [%g, %g, %g] and side [%g, %g, %g].",
+      hs->anchor[0], hs->anchor[1], hs->anchor[2], hs->side[0], hs->side[1],
+      hs->side[2]);
 }
 #else
 void hydro_space_init(struct hydro_space *hs, const struct space *s) {}
diff --git a/src/runner_doiact_functions_hydro.h b/src/runner_doiact_functions_hydro.h
index 4bdbcec05cf8fd9e5d5b06b13737d02886c94164..2d8bf4fbb958ae407b089d9cce6d69e8031ed43d 100644
--- a/src/runner_doiact_functions_hydro.h
+++ b/src/runner_doiact_functions_hydro.h
@@ -26,6 +26,10 @@
 
 #include "runner_doiact_hydro.h"
 
+#ifdef SHADOWFAX_SPH
+#include "shadowfax/cell_shadowfax.h"
+#endif
+
 /**
  * @brief Compute the interactions between a cell pair (non-symmetric case).
  *
@@ -69,6 +73,10 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci,
       shift[k] = -e->s->dim[k];
   }
 
+#if defined(SHADOWFAX_SPH) && (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_pair1_naive(e, ci, cj, -1, shift);
+#endif
+
   /* Loop over the parts in ci. */
   for (int pid = 0; pid < count_i; pid++) {
 
@@ -195,6 +203,10 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci,
       shift[k] = -e->s->dim[k];
   }
 
+#if defined(SHADOWFAX_SPH) && (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_pair2_naive(e, ci, cj, -1, shift);
+#endif
+
   /* Loop over the parts in ci. */
   for (int pid = 0; pid < count_i; pid++) {
 
@@ -585,6 +597,10 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci,
   const float a = cosmo->a;
   const float H = cosmo->H;
 
+#if defined(SHADOWFAX_SPH) && (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_pair_subset_naive(e, ci, cj, -1, shift);
+#endif
+
   /* Loop over the parts_i. */
   for (int pid = 0; pid < count; pid++) {
 
@@ -686,6 +702,11 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci,
   const struct sort_entry *sort_j = cell_get_hydro_sorts(cj, sid);
   const float dxj = cj->hydro.dx_max_sort;
 
+#if defined(SHADOWFAX_SPH) && (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_pair_subset(e, ci, parts_i, ind, count, cj, sid, flipped,
+                                shift);
+#endif
+
   /* Parts are on the left? */
   if (!flipped) {
 
@@ -1044,6 +1065,10 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
   const float a = cosmo->a;
   const float H = cosmo->H;
 
+#if defined(SHADOWFAX_SPH) && (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_pair1(e, ci, cj, sid, shift);
+#endif
+
   if (cell_is_active_hydro(ci, e)) {
 
     /* Loop over the parts in ci. */
@@ -1437,6 +1462,10 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid,
     }
   }
 
+#if defined(SHADOWFAX_SPH) && (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_pair2(e, ci, cj, sid, shift);
+#endif
+
   /* Loop over *all* the parts in ci starting from the centre until
      we are out of range of anything in cj (using the maximal hi). */
   for (int pid = count_i - 1;
@@ -1957,6 +1986,10 @@ void DOSELF1(struct runner *r, struct cell *restrict c) {
 
   TIMER_TIC;
 
+#if defined(SHADOWFAX_SPH) && (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_self1(e, c);
+#endif
+
   struct part *restrict parts = c->hydro.parts;
   const int count = c->hydro.count;
 
diff --git a/src/runner_ghost.c b/src/runner_ghost.c
index b98e47a0f31c4c5f235f6f20589597015934fb7e..ba12e952b46c9007de13bcfbdc2c91f2cac6066e 100644
--- a/src/runner_ghost.c
+++ b/src/runner_ghost.c
@@ -41,6 +41,10 @@
 #include "timestep_limiter.h"
 #include "tracers.h"
 
+#ifdef SHADOWFAX_SPH
+#include "shadowfax/cell_shadowfax.h"
+#endif
+
 /* Import the density loop functions. */
 #define FUNCTION density
 #define FUNCTION_TASK_LOOP TASK_LOOP_DENSITY
@@ -1062,6 +1066,20 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
         struct part *p = &parts[pid[i]];
         struct xpart *xp = &xparts[pid[i]];
 
+#ifdef SHADOWFAX_SPH
+        float hnew = delaunay_get_search_radius(
+            &c->hydro.deltess, pid[i] + c->hydro.deltess.vertex_start);
+        if (hnew >= p->h) {
+          p->h *= 1.5f;
+          pid[redo] = pid[i];
+          h_0[redo] = h_0[i];
+          left[redo] = left[i];
+          right[redo] = right[i];
+          redo += 1;
+        }
+        continue;
+#endif
+
 #ifdef SWIFT_DEBUG_CHECKS
         /* Is this part within the timestep? */
         if (!part_is_active(p, e)) error("Ghost applied to inactive particle");
@@ -1410,6 +1428,10 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
   /* Update h_max */
   c->hydro.h_max = h_max;
 
+#ifdef SHADOWFAX_SPH
+  cell_shadowfax_end_density(c);
+#endif
+
   /* The ghost may not always be at the top level.
    * Therefore we need to update h_max between the super- and top-levels */
   if (c->hydro.ghost) {
diff --git a/src/shadowfax/cell_shadowfax.h b/src/shadowfax/cell_shadowfax.h
index 88a55d3cf45d9a525da813a7297fd6961575d56f..aba28d9bfdde5d9c026c5bd67101b3a19c18c884 100644
--- a/src/shadowfax/cell_shadowfax.h
+++ b/src/shadowfax/cell_shadowfax.h
@@ -1,13 +1,397 @@
 #ifndef SWIFT_CELL_SHADOWFAX_H
 #define SWIFT_CELL_SHADOWFAX_H
 
+#include "active.h"
 #include "cell.h"
 #include "delaunay.h"
+#include "voronoi.h"
+
+__attribute__((always_inline)) INLINE static void shadowfax_flag_particle_added(
+    struct part *restrict p, int sid) {
+  p->voronoi.flag |= (1 << sid);
+}
+
+__attribute__((always_inline)) INLINE static int shadowfax_particle_was_added(
+    const struct part *restrict p, int sid) {
+  return (p->voronoi.flag & (1 << sid)) > 0;
+}
 
 __attribute__((always_inline)) INLINE static void
-cell_malloc_delaunay_tesselation(struct cell *c, const struct hydro_space *hs) {
+cell_malloc_delaunay_tessellation(struct cell *c,
+                                  const struct hydro_space *hs) {
+
+  /*  if(c->hydro.shadowfax_enabled){*/
+  delaunay_destroy(&c->hydro.deltess);
+  /*  }*/
+  delaunay_init(&c->hydro.deltess, c->loc, c->width, c->hydro.count,
+                10 * c->hydro.count);
+
+  const int count = c->hydro.count;
+  struct part *restrict parts = c->hydro.parts;
+
+  for (int pd = 0; pd < count; pd++) {
+    /* Get a pointer to the ith particle. */
+    struct part *restrict p = &parts[pd];
+    p->voronoi.flag = 0;
+  }
+
+  /*  c->hydro.shadowfax_enabled = 1;*/
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_self1(
+    const struct engine *e, struct cell *restrict c) {
+
+  const int count = c->hydro.count;
+  struct part *restrict parts = c->hydro.parts;
+
+  for (int pd = 0; pd < count; pd++) {
+    /* Get a pointer to the ith particle. */
+    struct part *restrict p = &parts[pd];
+    p->voronoi.flag = 0;
+  }
+
+  /* Loop over the parts in c. */
+  for (int pd = 0; pd < count; pd++) {
+
+    /* Get a pointer to the ith particle. */
+    struct part *restrict p = &parts[pd];
+
+    if (!shadowfax_particle_was_added(p, 0)) {
+      delaunay_add_local_vertex(&c->hydro.deltess, pd, p->x[0], p->x[1]);
+      shadowfax_flag_particle_added(p, 0);
+    }
+  }
+
+  /*  delaunay_consolidate(&c->hydro.deltess);*/
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair_naive(
+    const struct engine *e, struct cell *restrict ci, struct cell *restrict cj,
+    int sid, const double *shift) {
+
+  if (sid < 0) {
+    error("Doing a naive interaction!");
+  }
+
+  const int count_i = ci->hydro.count;
+  const int count_j = cj->hydro.count;
+  struct part *restrict parts_i = ci->hydro.parts;
+  struct part *restrict parts_j = cj->hydro.parts;
+
+  /* Loop over the parts in cj. */
+  for (int pid = 0; pid < count_i; pid++) {
+
+    /* Get a pointer to the ith particle. */
+    struct part *restrict pi = &parts_i[pid];
+
+    if (!shadowfax_particle_was_added(pi, 1 + sid)) {
+      delaunay_add_new_vertex(&cj->hydro.deltess, pi->x[0] - shift[0],
+                              pi->x[1] - shift[1]);
+      shadowfax_flag_particle_added(pi, 1 + sid);
+    }
+  }
+
+  /* Loop over the parts in cj. */
+  for (int pjd = 0; pjd < count_j; pjd++) {
+
+    /* Get a pointer to the jth particle. */
+    struct part *restrict pj = &parts_j[pjd];
+
+    if (!shadowfax_particle_was_added(pj, 13 + sid)) {
+      delaunay_add_new_vertex(&ci->hydro.deltess, pj->x[0] + shift[0],
+                              pj->x[1] + shift[1]);
+      shadowfax_flag_particle_added(pj, 13 + sid);
+    }
+  }
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair1_naive(
+    const struct engine *e, struct cell *restrict ci, struct cell *restrict cj,
+    int sid, const double *shift) {
+
+  if (ci == cj) error("Interacting cell with itself!");
+
+  cell_shadowfax_do_pair_naive(e, ci, cj, sid, shift);
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair2_naive(
+    const struct engine *e, struct cell *restrict ci, struct cell *restrict cj,
+    int sid, const double *shift) {
+
+  error("Shouldn't be using this function!");
+  if (ci == cj) error("Interacting cell with itself!");
+
+  cell_shadowfax_do_pair_naive(e, ci, cj, sid, shift);
+}
+
+__attribute__((always_inline)) INLINE static void
+cell_shadowfax_do_pair_subset_naive(const struct engine *e,
+                                    struct cell *restrict ci,
+                                    struct cell *restrict cj, int sid,
+                                    const double *shift) {
+
+  if (ci == cj) error("Interacting cell with itself!");
+
+  cell_shadowfax_do_pair_naive(e, ci, cj, sid, shift);
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair_subset(
+    const struct engine *e, struct cell *restrict ci,
+    struct part *restrict parts_i, int *restrict ind, int count,
+    struct cell *restrict cj, const int sid, const int flipped,
+    const double *shift) {
+
+  if (ci == cj) error("Interacting cell with itself!");
+
+  const int count_j = cj->hydro.count;
+  struct part *restrict parts_j = cj->hydro.parts;
+
+  /* Pick-out the sorted lists. */
+  const struct sort_entry *sort_j = cell_get_hydro_sorts(cj, sid);
+  const float dxj = cj->hydro.dx_max_sort;
+
+  /* Parts are on the left? */
+  if (!flipped) {
+
+    /* Loop over the parts_i. */
+    for (int pid = 0; pid < count; pid++) {
+
+      /* Get a hold of the ith part in ci. */
+      struct part *restrict pi = &parts_i[ind[pid]];
+      const double pix = pi->x[0] - (shift[0]);
+      const double piy = pi->x[1] - (shift[1]);
+      const double piz = pi->x[2] - (shift[2]);
+      const float hi = pi->h;
+      const float hig2 = hi * hi * kernel_gamma2;
+      const double di = hi * kernel_gamma + dxj + pix * runner_shift[sid][0] +
+                        piy * runner_shift[sid][1] + piz * runner_shift[sid][2];
+
+      /* Loop over the parts in cj. */
+      for (int pjd = 0; pjd < count_j && sort_j[pjd].d < di; pjd++) {
+
+        /* Get a pointer to the jth particle. */
+        struct part *restrict pj = &parts_j[sort_j[pjd].i];
+
+        /* Skip inhibited particles. */
+        if (part_is_inhibited(pj, e)) continue;
+
+        const double pjx = pj->x[0];
+        const double pjy = pj->x[1];
+        const double pjz = pj->x[2];
+
+        /* Compute the pairwise distance. */
+        float dx[3] = {(float)(pix - pjx), (float)(piy - pjy),
+                       (float)(piz - pjz)};
+        const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
+
+        /* Hit or miss? */
+        if (r2 < hig2) {
+          if (!shadowfax_particle_was_added(pj, 1 + sid)) {
+            delaunay_add_new_vertex(&ci->hydro.deltess, pj->x[0] + shift[0],
+                                    pj->x[1] + shift[1]);
+            /*            shadowfax_flag_particle_added(pj, 1+sid);*/
+          }
+        }
+      } /* loop over the parts in cj. */
+    }   /* loop over the parts in ci. */
+  }
+
+  /* Parts are on the right. */
+  else {
+
+    /* Loop over the parts_i. */
+    for (int pid = 0; pid < count; pid++) {
+
+      /* Get a hold of the ith part in ci. */
+      struct part *restrict pi = &parts_i[ind[pid]];
+      const double pix = pi->x[0] - (shift[0]);
+      const double piy = pi->x[1] - (shift[1]);
+      const double piz = pi->x[2] - (shift[2]);
+      const float hi = pi->h;
+      const float hig2 = hi * hi * kernel_gamma2;
+      const double di = -hi * kernel_gamma - dxj + pix * runner_shift[sid][0] +
+                        piy * runner_shift[sid][1] + piz * runner_shift[sid][2];
+
+      /* Loop over the parts in cj. */
+      for (int pjd = count_j - 1; pjd >= 0 && di < sort_j[pjd].d; pjd--) {
+
+        /* Get a pointer to the jth particle. */
+        struct part *restrict pj = &parts_j[sort_j[pjd].i];
+
+        /* Skip inhibited particles. */
+        if (part_is_inhibited(pj, e)) continue;
+
+        const double pjx = pj->x[0];
+        const double pjy = pj->x[1];
+        const double pjz = pj->x[2];
+
+        /* Compute the pairwise distance. */
+        float dx[3] = {(float)(pix - pjx), (float)(piy - pjy),
+                       (float)(piz - pjz)};
+        const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
+
+        /* Hit or miss? */
+        if (r2 < hig2) {
+          if (!shadowfax_particle_was_added(pj, 13 + sid)) {
+            delaunay_add_new_vertex(&ci->hydro.deltess, pj->x[0] + shift[0],
+                                    pj->x[1] + shift[1]);
+            /*            shadowfax_flag_particle_added(pj, 13+sid);*/
+          }
+        }
+      } /* loop over the parts in cj. */
+    }   /* loop over the parts in ci. */
+  }
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair1(
+    const struct engine *e, struct cell *restrict ci, struct cell *restrict cj,
+    int sid, const double *shift) {
+
+  if (ci == cj) error("Interacting cell with itself!");
+
+  /*  cell_shadowfax_do_pair_naive(e, ci, cj, sid, shift);*/
+  /*  return;*/
+
+  /* Get the cutoff shift. */
+  double rshift = 0.0;
+  for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k];
+
+  /* Pick-out the sorted lists. */
+  const struct sort_entry *restrict sort_i = cell_get_hydro_sorts(ci, sid);
+  const struct sort_entry *restrict sort_j = cell_get_hydro_sorts(cj, sid);
+
+  /* Get some other useful values. */
+  const double hi_max = ci->hydro.h_max * kernel_gamma - rshift;
+  const double hj_max = cj->hydro.h_max * kernel_gamma;
+  const int count_i = ci->hydro.count;
+  const int count_j = cj->hydro.count;
+  struct part *restrict parts_i = ci->hydro.parts;
+  struct part *restrict parts_j = cj->hydro.parts;
+  const double di_max = sort_i[count_i - 1].d - rshift;
+  const double dj_min = sort_j[0].d;
+  const float dx_max = (ci->hydro.dx_max_sort + cj->hydro.dx_max_sort);
+
+  if (cell_is_active_hydro(ci, e)) {
+
+    /* Loop over the parts in ci. */
+    for (int pid = count_i - 1;
+         pid >= 0 && sort_i[pid].d + hi_max + dx_max > dj_min; pid--) {
+
+      /* Get a hold of the ith part in ci. */
+      struct part *restrict pi = &parts_i[sort_i[pid].i];
+      const float hi = pi->h;
+
+      /* Skip inactive particles */
+      if (!part_is_active(pi, e)) continue;
+
+      /* Is there anything we need to interact with ? */
+      const double di = sort_i[pid].d + hi * kernel_gamma + dx_max - rshift;
+      if (di < dj_min) continue;
+
+      /* Get some additional information about pi */
+      const float hig2 = hi * hi * kernel_gamma2;
+      const float pix = pi->x[0] - (cj->loc[0] + shift[0]);
+      const float piy = pi->x[1] - (cj->loc[1] + shift[1]);
+      const float piz = pi->x[2] - (cj->loc[2] + shift[2]);
+
+      /* Loop over the parts in cj. */
+      for (int pjd = 0; pjd < count_j && sort_j[pjd].d < di; pjd++) {
+
+        /* Recover pj */
+        struct part *pj = &parts_j[sort_j[pjd].i];
+
+        /* Skip inhibited particles. */
+        if (part_is_inhibited(pj, e)) continue;
+
+        const float pjx = pj->x[0] - cj->loc[0];
+        const float pjy = pj->x[1] - cj->loc[1];
+        const float pjz = pj->x[2] - cj->loc[2];
+
+        /* Compute the pairwise distance. */
+        float dx[3] = {pix - pjx, piy - pjy, piz - pjz};
+        const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
+
+        /* Hit or miss? */
+        if (r2 < hig2) {
+
+          if (!shadowfax_particle_was_added(pj, 13 + sid)) {
+            delaunay_add_new_vertex(&ci->hydro.deltess, pj->x[0] + shift[0],
+                                    pj->x[1] + shift[1]);
+            shadowfax_flag_particle_added(pj, 13 + sid);
+          }
+        }
+      } /* loop over the parts in cj. */
+    }   /* loop over the parts in ci. */
+  }     /* Cell ci is active */
+
+  if (cell_is_active_hydro(cj, e)) {
+
+    /* Loop over the parts in cj. */
+    for (int pjd = 0; pjd < count_j && sort_j[pjd].d - hj_max - dx_max < di_max;
+         pjd++) {
+
+      /* Get a hold of the jth part in cj. */
+      struct part *pj = &parts_j[sort_j[pjd].i];
+      const float hj = pj->h;
+
+      /* Skip inactive particles */
+      if (!part_is_active(pj, e)) continue;
+
+      /* Is there anything we need to interact with ? */
+      const double dj = sort_j[pjd].d - hj * kernel_gamma - dx_max + rshift;
+      if (dj - rshift > di_max) continue;
+
+      /* Get some additional information about pj */
+      const float hjg2 = hj * hj * kernel_gamma2;
+      const float pjx = pj->x[0] - cj->loc[0];
+      const float pjy = pj->x[1] - cj->loc[1];
+      const float pjz = pj->x[2] - cj->loc[2];
+
+      /* Loop over the parts in ci. */
+      for (int pid = count_i - 1; pid >= 0 && sort_i[pid].d > dj; pid--) {
+
+        /* Recover pi */
+        struct part *pi = &parts_i[sort_i[pid].i];
+
+        /* Skip inhibited particles. */
+        if (part_is_inhibited(pi, e)) continue;
+
+        const float pix = pi->x[0] - (cj->loc[0] + shift[0]);
+        const float piy = pi->x[1] - (cj->loc[1] + shift[1]);
+        const float piz = pi->x[2] - (cj->loc[2] + shift[2]);
+
+        /* Compute the pairwise distance. */
+        float dx[3] = {pjx - pix, pjy - piy, pjz - piz};
+        const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
+
+        /* Hit or miss? */
+        if (r2 < hjg2) {
+
+          if (!shadowfax_particle_was_added(pi, 1 + sid)) {
+            delaunay_add_new_vertex(&cj->hydro.deltess, pi->x[0] - shift[0],
+                                    pi->x[1] - shift[1]);
+            shadowfax_flag_particle_added(pi, 1 + sid);
+          }
+        }
+      } /* loop over the parts in ci. */
+    }   /* loop over the parts in cj. */
+  }     /* Cell cj is active */
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair2(
+    const struct engine *e, struct cell *restrict ci, struct cell *restrict cj,
+    int sid, const double *shift) {
+
+  error("Shouldn't be using this function!");
+  if (ci == cj) error("Interacting cell with itself!");
+
+  cell_shadowfax_do_pair_naive(e, ci, cj, sid, shift);
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_end_density(
+    struct cell *restrict c) {
 
-  delaunay_init(&c->hydro.deltess, hs, 100, 100);
+  voronoi_init(&c->hydro.vortess, &c->hydro.deltess);
 }
 
 #endif /* SWIFT_CELL_SHADOWFAX_H */
diff --git a/src/shadowfax/delaunay.h b/src/shadowfax/delaunay.h
index b9b5ab841f0530415b1a670548d778bec28f5d2d..9523b13572352a3e7d96ddc68fc8f8a997260eee 100644
--- a/src/shadowfax/delaunay.h
+++ b/src/shadowfax/delaunay.h
@@ -28,8 +28,10 @@
 #ifndef SWIFT_DELAUNAY_H
 #define SWIFT_DELAUNAY_H
 
+#include "error.h"
 #include "geometry.h"
 #include "hydro_space.h"
+#include "memuse.h"
 #include "triangle.h"
 
 #include <float.h>
@@ -94,6 +96,9 @@
  */
 struct delaunay {
 
+  /* Activity flag, useful for debugging. */
+  int active;
+
   /* Box geometry: used to set up the initial vertices and triangles and to
    * convert input coordinates to integer coordinates. */
 
@@ -231,6 +236,45 @@ static inline unsigned long int delaunay_double_to_int(double d) {
   return (u.ull & 0xFFFFFFFFFFFFFllu);
 }
 
+inline static void delaunay_init_vertex(struct delaunay* restrict d, int v,
+                                        double x, double y) {
+
+  /* store a copy of the vertex coordinates (we should get rid of this for
+     SWIFT) */
+  d->vertices[2 * v] = x;
+  d->vertices[2 * v + 1] = y;
+
+  /* compute the rescaled coordinates. We do this because floating point values
+     in the range [1,2[ all have the same exponent (0), which guarantees that
+     their mantissas form a linear sequence */
+  double rescaled_x = 1. + (x - d->anchor[0]) * d->inverse_side;
+  double rescaled_y = 1. + (y - d->anchor[1]) * d->inverse_side;
+
+  delaunay_assert(rescaled_x >= 1.);
+  delaunay_assert(rescaled_x < 2.);
+  delaunay_assert(rescaled_y >= 1.);
+  delaunay_assert(rescaled_y < 2.);
+
+#ifdef DELAUNAY_NONEXACT
+  /* store a copy of the rescaled coordinates to apply non-exact tests */
+  d->rescaled_vertices[2 * v] = rescaled_x;
+  d->rescaled_vertices[2 * v + 1] = rescaled_y;
+#endif
+
+  /* convert the rescaled coordinates to integer coordinates and store these */
+  d->integer_vertices[2 * v] = delaunay_double_to_int(rescaled_x);
+  d->integer_vertices[2 * v + 1] = delaunay_double_to_int(rescaled_y);
+
+  /* initialise the variables that keep track of the link between vertices and
+     triangles.
+     We use negative values so that we can later detect missing links. */
+  d->vertex_triangles[v] = -1;
+  d->vertex_triangle_index[v] = -1;
+
+  /* initialise the search radii to the largest possible value */
+  d->search_radii[v] = DBL_MAX;
+}
+
 /**
  * @brief Add a new vertex with the given coordinates.
  *
@@ -252,57 +296,28 @@ inline static int delaunay_new_vertex(struct delaunay* restrict d, double x,
   if (d->vertex_index == d->vertex_size) {
     /* dynamically grow the size of the arrays with a factor 2 */
     d->vertex_size <<= 1;
-    d->vertices =
-        (double*)realloc(d->vertices, d->vertex_size * 2 * sizeof(double));
+    d->vertices = (double*)swift_realloc("delaunay vertices", d->vertices,
+                                         d->vertex_size * 2 * sizeof(double));
 #ifdef DELAUNAY_NONEXACT
-    d->rescaled_vertices = (double*)realloc(
-        d->rescaled_vertices, d->vertex_size * 2 * sizeof(double));
+    d->rescaled_vertices = (double*)swift_realloc(
+        "delaunay rescaled vertices", d->rescaled_vertices,
+        d->vertex_size * 2 * sizeof(double));
 #endif
-    d->integer_vertices = (unsigned long int*)realloc(
-        d->integer_vertices, d->vertex_size * 2 * sizeof(unsigned long int));
+    d->integer_vertices = (unsigned long int*)swift_realloc(
+        "delaunay integer vertices", d->integer_vertices,
+        d->vertex_size * 2 * sizeof(unsigned long int));
     d->vertex_triangles =
-        (int*)realloc(d->vertex_triangles, d->vertex_size * sizeof(int));
-    d->vertex_triangle_index =
-        (int*)realloc(d->vertex_triangle_index, d->vertex_size * sizeof(int));
+        (int*)swift_realloc("delaunay vertex-triangle links",
+                            d->vertex_triangles, d->vertex_size * sizeof(int));
+    d->vertex_triangle_index = (int*)swift_realloc(
+        "delaunay vertex-triangle index links", d->vertex_triangle_index,
+        d->vertex_size * sizeof(int));
     d->search_radii =
-        (double*)realloc(d->search_radii, d->vertex_size * sizeof(double));
+        (double*)swift_realloc("delaunay search radii", d->search_radii,
+                               d->vertex_size * sizeof(double));
   }
 
-  /* store a copy of the vertex coordinates (we should get rid of this for
-     SWIFT) */
-  d->vertices[2 * d->vertex_index] = x;
-  d->vertices[2 * d->vertex_index + 1] = y;
-
-  /* compute the rescaled coordinates. We do this because floating point values
-     in the range [1,2[ all have the same exponent (0), which guarantees that
-     their mantissas form a linear sequence */
-  double rescaled_x = 1. + (x - d->anchor[0]) * d->inverse_side;
-  double rescaled_y = 1. + (y - d->anchor[1]) * d->inverse_side;
-
-  delaunay_assert(rescaled_x >= 1.);
-  delaunay_assert(rescaled_x < 2.);
-  delaunay_assert(rescaled_y >= 1.);
-  delaunay_assert(rescaled_y < 2.);
-
-#ifdef DELAUNAY_NONEXACT
-  /* store a copy of the rescaled coordinates to apply non-exact tests */
-  d->rescaled_vertices[2 * d->vertex_index] = rescaled_x;
-  d->rescaled_vertices[2 * d->vertex_index + 1] = rescaled_y;
-#endif
-
-  /* convert the rescaled coordinates to integer coordinates and store these */
-  d->integer_vertices[2 * d->vertex_index] = delaunay_double_to_int(rescaled_x);
-  d->integer_vertices[2 * d->vertex_index + 1] =
-      delaunay_double_to_int(rescaled_y);
-
-  /* initialise the variables that keep track of the link between vertices and
-     triangles.
-     We use negative values so that we can later detect missing links. */
-  d->vertex_triangles[d->vertex_index] = -1;
-  d->vertex_triangle_index[d->vertex_index] = -1;
-
-  /* initialise the search radii to the largest possible value */
-  d->search_radii[d->vertex_index] = DBL_MAX;
+  delaunay_init_vertex(d, d->vertex_index, x, y);
 
   /* return the vertex index and then increase it by 1.
      After this operation, vertex_index will correspond to the size of the
@@ -328,8 +343,9 @@ inline static int delaunay_new_triangle(struct delaunay* restrict d) {
     /* no: increase the size of the triangle array with a factor 2 and
        reallocate it in memory */
     d->triangle_size <<= 1;
-    d->triangles = (struct triangle*)realloc(
-        d->triangles, d->triangle_size * sizeof(struct triangle));
+    d->triangles = (struct triangle*)swift_realloc(
+        "delaunay triangles", d->triangles,
+        d->triangle_size * sizeof(struct triangle));
   }
 
   /* return the triangle index and then increase it by 1.
@@ -522,32 +538,49 @@ inline static void delaunay_check_tessellation(struct delaunay* restrict d) {
  * @param triangle_size Initial size of the triangle array.
  */
 inline static void delaunay_init(struct delaunay* restrict d,
-                                 const struct hydro_space* restrict hs,
-                                 int vertex_size, int triangle_size) {
+                                 const double* cell_loc,
+                                 const double* cell_width, int vertex_size,
+                                 int triangle_size) {
+
+  if (d->active != 0) {
+    error("Delaunay tessellation corruption!");
+  }
+
+  if (vertex_size == 0) {
+    /* Don't bother setting up a Delaunay tessellation for emtpy cells */
+    return;
+  }
+
+  d->active = 1;
 
   /* allocate memory for the vertex arrays */
-  d->vertices = (double*)malloc(vertex_size * 2 * sizeof(double));
+  d->vertices = (double*)swift_malloc("delaunay vertices",
+                                      vertex_size * 2 * sizeof(double));
 #ifdef DELAUNAY_NONEXACT
-  d->rescaled_vertices = (double*)malloc(vertex_size * 2 * sizeof(double));
+  d->rescaled_vertices = (double*)swift_malloc(
+      "delaunay rescaled vertices", vertex_size * 2 * sizeof(double));
 #endif
-  d->integer_vertices =
-      (unsigned long int*)malloc(vertex_size * 2 * sizeof(unsigned long int));
-  d->vertex_triangles = (int*)malloc(vertex_size * sizeof(int));
-  d->vertex_triangle_index = (int*)malloc(vertex_size * sizeof(int));
-  d->search_radii = (double*)malloc(vertex_size * sizeof(double));
-  d->vertex_index = 0;
+  d->integer_vertices = (unsigned long int*)swift_malloc(
+      "delaunay integer vertices", vertex_size * 2 * sizeof(unsigned long int));
+  d->vertex_triangles = (int*)swift_malloc("delaunay vertex-triangle links",
+                                           vertex_size * sizeof(int));
+  d->vertex_triangle_index = (int*)swift_malloc(
+      "delaunay vertex-triangle index links", vertex_size * sizeof(int));
+  d->search_radii = (double*)swift_malloc("delaunay search radii",
+                                          vertex_size * sizeof(double));
+  d->vertex_index = vertex_size;
   d->vertex_size = vertex_size;
 
   /* allocate memory for the triangle array */
-  d->triangles =
-      (struct triangle*)malloc(triangle_size * sizeof(struct triangle));
+  d->triangles = (struct triangle*)swift_malloc(
+      "delaunay triangles", triangle_size * sizeof(struct triangle));
   d->triangle_index = 0;
   d->triangle_size = triangle_size;
 
   /* allocate memory for the queue (note that the queue size of 10 was chosen
      arbitrarily, and a proper value should be chosen based on performance
      measurements) */
-  d->queue = (int*)malloc(10 * sizeof(int));
+  d->queue = (int*)swift_malloc("delaunay queue", 10 * sizeof(int));
   d->queue_index = 0;
   d->queue_size = 10;
 
@@ -557,9 +590,9 @@ inline static void delaunay_init(struct delaunay* restrict d,
      work for even the very degenerate case of a single vertex that could be
      anywhere in the box. Also note that we convert the generally rectangular
      box to a square. */
-  double box_anchor[2] = {hs->anchor[0] - hs->side[0],
-                          hs->anchor[1] - hs->side[1]};
-  double box_side = 6. * fmax(hs->side[0], hs->side[1]);
+  double box_anchor[2] = {cell_loc[0] - cell_width[0],
+                          cell_loc[1] - cell_width[1]};
+  double box_side = 6. * fmax(cell_width[0], cell_width[1]);
 
   /* store the anchor and inverse side_length for the conversion from box
      coordinates to rescaled (integer) coordinates */
@@ -615,13 +648,13 @@ inline static void delaunay_init(struct delaunay* restrict d,
 
   d->last_triangle = first_triangle;
 
-  d->vertex_start = d->vertex_index;
+  d->vertex_start = 0;
   /* initialise the last vertex index to a negative value to signal that the
      Delaunay tessellation was not consolidated yet.
      delaunay_update_search_radii() will not work until delaunay_consolidate()
      was called. Neither will it be possible to convert the Delaunay
      tessellation into a Voronoi grid before this happens. */
-  d->vertex_end = -1;
+  d->vertex_end = vertex_size;
 
   /* Perform potential log output and sanity checks */
   delaunay_log("Post init check");
@@ -634,17 +667,21 @@ inline static void delaunay_init(struct delaunay* restrict d,
  * @param d Delaunay tessellation.
  */
 inline static void delaunay_destroy(struct delaunay* restrict d) {
-  free(d->vertices);
+  d->active = 0;
+  if (d->vertices != NULL) {
+    swift_free("delaunay vertices", d->vertices);
 #ifdef DELAUNAY_NONEXACT
-  free(d->rescaled_vertices);
+    swift_free("delaunay rescaled vertices", d->rescaled_vertices);
 #endif
-  free(d->integer_vertices);
-  free(d->vertex_triangles);
-  free(d->vertex_triangle_index);
-  free(d->search_radii);
-  free(d->triangles);
-  free(d->queue);
-  geometry_destroy(&d->geometry);
+    swift_free("delaunay integer vertices", d->integer_vertices);
+    swift_free("delaunay vertex-triangle links", d->vertex_triangles);
+    swift_free("delaunay vertex-triangle index links",
+               d->vertex_triangle_index);
+    swift_free("delaunay search radii", d->search_radii);
+    swift_free("delaunay triangles", d->triangles);
+    swift_free("delaunay queue", d->queue);
+    geometry_destroy(&d->geometry);
+  }
 }
 
 /**
@@ -692,7 +729,7 @@ inline static double delaunay_get_radius(const struct delaunay* restrict d,
  * @param d Delaunay tessellation.
  */
 inline static void delaunay_consolidate(struct delaunay* restrict d) {
-  d->vertex_end = d->vertex_index;
+  d->vertex_end = d->vertex_index - 3;
 }
 
 /**
@@ -738,6 +775,23 @@ inline static int delaunay_update_search_radii(struct delaunay* restrict d,
   return count;
 }
 
+inline static float delaunay_get_search_radius(struct delaunay* restrict d,
+                                               int vi) {
+  int t0 = d->vertex_triangles[vi];
+  int vi0 = d->vertex_triangle_index[vi];
+  int vi0p1 = (vi0 + 1) % 3;
+  float r = 2.0f * delaunay_get_radius(d, t0);
+  int t1 = d->triangles[t0].neighbours[vi0p1];
+  int vi1 = d->triangles[t0].index_in_neighbour[vi0p1];
+  while (t1 != t0) {
+    r = max(r, 2.f * delaunay_get_radius(d, t1));
+    int vi1p2 = (vi1 + 2) % 3;
+    vi1 = d->triangles[t1].index_in_neighbour[vi1p2];
+    t1 = d->triangles[t1].neighbours[vi1p2];
+  }
+  return r;
+}
+
 /**
  * @brief Randomly choose a neighbour from the given two options.
  *
@@ -911,14 +965,17 @@ inline static int delaunay_test_point_inside_triangle(
     case 26:
       /* testi0 is zero */
       *t_new = d->triangles[t].neighbours[0];
+      *ngb_index = 0;
       return 2;
     case 38:
       /* testi1 is zero */
       *t_new = d->triangles[t].neighbours[1];
+      *ngb_index = 1;
       return 2;
     case 41:
       /* testi2 is zero */
       *t_new = d->triangles[t].neighbours[2];
+      *ngb_index = 2;
       return 2;
     case 42:
       /* all tests returned 1 (testsum is 32 + 8 + 2) */
@@ -928,8 +985,14 @@ inline static int delaunay_test_point_inside_triangle(
       /* we have ended up in a geometrically impossible scenario. This can
          happen if the triangle vertices are colinear, or if one or multiple
          vertices coincide. */
-      fprintf(stderr, "Impossible case (%i)!\n", testsum);
-      abort();
+      return -1;
+      /*      fprintf(stderr, "Impossible case (%i)!\n", testsum);*/
+      /*      fprintf(stderr, "Vertex positions:\n");*/
+      /*      fprintf(stderr, "a: %lu %lu\n", aix, aiy);*/
+      /*      fprintf(stderr, "b: %lu %lu\n", bix, biy);*/
+      /*      fprintf(stderr, "c: %lu %lu\n", cix, ciy);*/
+      /*      fprintf(stderr, "d: %lu %lu\n", dix, diy);*/
+      /*      error("Impossible case during Delaunay construction!");*/
   }
 }
 
@@ -945,7 +1008,8 @@ inline static void delaunay_enqueue(struct delaunay* restrict d, int t) {
   if (d->queue_index == d->queue_size) {
     /* there isn't: increase the size of the queue with a factor 2. */
     d->queue_size <<= 1;
-    d->queue = (int*)realloc(d->queue, d->queue_size * sizeof(int));
+    d->queue = (int*)swift_realloc("delaunay queue", d->queue,
+                                   d->queue_size * sizeof(int));
   }
 
   delaunay_log("Enqueuing triangle %i and vertex 2", t);
@@ -1164,17 +1228,19 @@ inline static void delaunay_check_triangles(struct delaunay* restrict d) {
  * vertex should always be the final vertex of any newly created triangle.
  *
  * @param d Delaunay tessellation.
+ * @param v Vertex index.
  * @param x Horizontal coordinate of the new vertex.
  * @param y Vertical coordinate of the new vertex.
+ * @return 0 on success, -1 if the vertex already exists.
  */
-inline static void delaunay_add_vertex(struct delaunay* restrict d, double x,
-                                       double y) {
+inline static int delaunay_add_vertex(struct delaunay* restrict d, int v,
+                                      double x, double y) {
 
-  delaunay_log("Adding vertex with position %g %g", x, y);
+  if (d->active != 1) {
+    error("Trying to add a vertex to an inactive Delaunay tessellation!");
+  }
 
-  /* create the new vertex */
-  int v = delaunay_new_vertex(d, x, y);
-  delaunay_log("Created new vertex with index %i", v);
+  delaunay_log("Adding vertex with position %g %g", x, y);
 
   /* find the triangle that contains the new vertex. Starting from an initial
      guess (the last triangle accessed by the previous insertion), we test if
@@ -1185,10 +1251,16 @@ inline static void delaunay_add_vertex(struct delaunay* restrict d, double x,
   int t0, t1, ngb_index;
   t0 = d->last_triangle;
   int flag = delaunay_test_point_inside_triangle(d, v, t0, &t1, &ngb_index);
+  if (flag == -1) {
+    return -1;
+  }
   int count = 0;
   while (flag == 0) {
     t0 = t1;
     flag = delaunay_test_point_inside_triangle(d, v, t0, &t1, &ngb_index);
+    if (flag == -1) {
+      return -1;
+    }
     ++count;
     delaunay_assert(count < d->triangle_index);
   }
@@ -1289,10 +1361,10 @@ inline static void delaunay_add_vertex(struct delaunay* restrict d, double x,
     int ngb0_2 = d->triangles[t0].neighbours[i0_2];
     int ngbi0_2 = d->triangles[t0].index_in_neighbour[i0_2];
 
-    int ngb1_1 = d->triangles[t0].neighbours[i1_1];
-    int ngbi1_1 = d->triangles[t0].index_in_neighbour[i1_1];
-    int ngb1_2 = d->triangles[t0].neighbours[i1_2];
-    int ngbi1_2 = d->triangles[t0].index_in_neighbour[i1_2];
+    int ngb1_1 = d->triangles[t1].neighbours[i1_1];
+    int ngbi1_1 = d->triangles[t1].index_in_neighbour[i1_1];
+    int ngb1_2 = d->triangles[t1].neighbours[i1_2];
+    int ngbi1_2 = d->triangles[t1].index_in_neighbour[i1_2];
 
     int t2 = delaunay_new_triangle(d);
     int t3 = delaunay_new_triangle(d);
@@ -1354,6 +1426,46 @@ inline static void delaunay_add_vertex(struct delaunay* restrict d, double x,
   delaunay_log("Post vertex %i check", v);
   /* perform a consistency test if enabled */
   delaunay_check_tessellation(d);
+  return 0;
+}
+
+inline static void delaunay_add_local_vertex(struct delaunay* restrict d, int v,
+                                             double x, double y) {
+  delaunay_init_vertex(d, v, x, y);
+  if (delaunay_add_vertex(d, v, x, y) != 0) {
+    error("Local vertices cannot be added twice!");
+  }
+}
+
+inline static void delaunay_add_new_vertex(struct delaunay* restrict d,
+                                           double x, double y) {
+  if (d->active != 1) {
+    error("Trying to add a vertex to an inactive Delaunay tessellation!");
+  }
+
+  /* create the new vertex */
+  int v = delaunay_new_vertex(d, x, y);
+  delaunay_log("Created new vertex with index %i", v);
+  int flag = delaunay_add_vertex(d, v, x, y);
+  if (flag == -1) {
+    /* vertex already exists. Delete the last vertex. */
+    --d->vertex_index;
+  }
+}
+
+inline static void delaunay_write_tessellation(
+    const struct delaunay* restrict d, FILE* file, size_t* offset) {
+
+  for (int i = 0; i < d->vertex_index; ++i) {
+    fprintf(file, "V\t%lu\t%g\t%g\n", *offset + i, d->vertices[2 * i],
+            d->vertices[2 * i + 1]);
+  }
+  for (int i = 3; i < d->triangle_index; ++i) {
+    fprintf(file, "T\t%lu\t%lu\t%lu\n", *offset + d->triangles[i].vertices[0],
+            *offset + d->triangles[i].vertices[1],
+            *offset + d->triangles[i].vertices[2]);
+  }
+  *offset += d->vertex_index;
 }
 
 /**
@@ -1376,14 +1488,8 @@ inline static void delaunay_print_tessellation(
 
   FILE* file = fopen(file_name, "w");
 
-  for (int i = 0; i < d->vertex_index; ++i) {
-    fprintf(file, "V\t%i\t%g\t%g\n", i, d->vertices[2 * i],
-            d->vertices[2 * i + 1]);
-  }
-  for (int i = 0; i < d->triangle_index; ++i) {
-    fprintf(file, "T\t%i\t%i\t%i\n", d->triangles[i].vertices[0],
-            d->triangles[i].vertices[1], d->triangles[i].vertices[2]);
-  }
+  size_t offset = 0;
+  delaunay_write_tessellation(d, file, &offset);
 
   fclose(file);
 }
diff --git a/src/shadowfax/voronoi.h b/src/shadowfax/voronoi.h
index ef8f0fecbb2f5dc743165ba95b08807dc02d4d74..017d6a78d203c66ea3da628297d55d68df3f2261 100644
--- a/src/shadowfax/voronoi.h
+++ b/src/shadowfax/voronoi.h
@@ -364,6 +364,36 @@ static inline void voronoi_check_grid(const struct voronoi *restrict v) {
   printf("Total volume: %g\n", V);
 }
 
+static inline void voronoi_write_grid(const struct voronoi *restrict v,
+                                      FILE *file, size_t *offset) {
+
+  for (int i = 0; i < v->number_of_cells; ++i) {
+    fprintf(file, "G\t%g\t%g\n", v->generators[2 * i],
+            v->generators[2 * i + 1]);
+    fprintf(file, "M\t%g\t%g\n", v->cell_centroid[2 * i],
+            v->cell_centroid[2 * i + 1]);
+    for (int j = 1; j < v->vertex_number[i]; ++j) {
+      int cjm1 = v->vertex_offset[i] + j - 1;
+      int cj = v->vertex_offset[i] + j;
+      fprintf(file, "C\t%lu\t%lu\n", *offset + v->connections[cjm1],
+              *offset + v->connections[cj]);
+      fprintf(file, "F\t%g\t%g\n", v->face_midpoints[2 * cj],
+              v->face_midpoints[2 * cj + 1]);
+    }
+    fprintf(
+        file, "C\t%lu\t%lu\n",
+        *offset + v->connections[v->vertex_offset[i] + v->vertex_number[i] - 1],
+        *offset + v->connections[v->vertex_offset[i]]);
+    fprintf(file, "F\t%g\t%g\n", v->face_midpoints[2 * v->vertex_offset[i]],
+            v->face_midpoints[2 * v->vertex_offset[i] + 1]);
+  }
+  for (int i = 0; i < v->vertex_index; ++i) {
+    fprintf(file, "V\t%g\t%g\n", v->vertices[2 * i], v->vertices[2 * i + 1]);
+  }
+
+  *offset += v->vertex_index;
+}
+
 /**
  * @brief Print the Voronoi grid to a file with the given name.
  *
@@ -385,27 +415,8 @@ static inline void voronoi_print_grid(const struct voronoi *restrict v,
 
   FILE *file = fopen(file_name, "w");
 
-  for (int i = 0; i < v->number_of_cells; ++i) {
-    fprintf(file, "G\t%g\t%g\n", v->generators[2 * i],
-            v->generators[2 * i + 1]);
-    fprintf(file, "M\t%g\t%g\n", v->cell_centroid[2 * i],
-            v->cell_centroid[2 * i + 1]);
-    for (int j = 1; j < v->vertex_number[i]; ++j) {
-      int cjm1 = v->vertex_offset[i] + j - 1;
-      int cj = v->vertex_offset[i] + j;
-      fprintf(file, "C\t%i\t%i\n", v->connections[cjm1], v->connections[cj]);
-      fprintf(file, "F\t%g\t%g\n", v->face_midpoints[2 * cj],
-              v->face_midpoints[2 * cj + 1]);
-    }
-    fprintf(file, "C\t%i\t%i\n",
-            v->connections[v->vertex_offset[i] + v->vertex_number[i] - 1],
-            v->connections[v->vertex_offset[i]]);
-    fprintf(file, "F\t%g\t%g\n", v->face_midpoints[2 * v->vertex_offset[i]],
-            v->face_midpoints[2 * v->vertex_offset[i] + 1]);
-  }
-  for (int i = 0; i < v->vertex_index; ++i) {
-    fprintf(file, "V\t%g\t%g\n", v->vertices[2 * i], v->vertices[2 * i + 1]);
-  }
+  size_t offset = 0;
+  voronoi_write_grid(v, file, &offset);
 
   fclose(file);
 }
diff --git a/src/space_rebuild.c b/src/space_rebuild.c
index 0b68ca2b0cf9cfaea16ba95908fa38cacff71a25..4fb2ebfcb754ce824d575af2a325982ffb88aad3 100644
--- a/src/space_rebuild.c
+++ b/src/space_rebuild.c
@@ -30,6 +30,10 @@
 #include "engine.h"
 #include "memswap.h"
 
+#ifdef SHADOWFAX_SPH
+#include "shadowfax/cell_shadowfax.h"
+#endif
+
 /*! Expected maximal number of strays received at a rebuild */
 extern int space_expected_max_nr_strays;
 
@@ -955,6 +959,10 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
       s->local_cells_with_particles_top[s->nr_local_cells_with_particles] = k;
       s->nr_local_cells_with_particles++;
     }
+
+#ifdef SHADOWFAX_SPH
+    cell_malloc_delaunay_tessellation(c, &s->hs);
+#endif
   }
   if (verbose) {
     message("Have %d local top-level cells with particles (total=%d)",