diff --git a/src/hydro/Shadowswift/hydro_io.h b/src/hydro/Shadowswift/hydro_io.h
index d192ea9b8d4b22b29ab2ae5685fa8cecd5554775..a25f6847505f5a7ee23c4e4e76bf6ad29b18a07f 100644
--- a/src/hydro/Shadowswift/hydro_io.h
+++ b/src/hydro/Shadowswift/hydro_io.h
@@ -170,7 +170,7 @@ INLINE static void hydro_write_particles(const struct part* parts,
                                          struct io_props* list,
                                          int* num_fields) {
 
-  *num_fields = 13;
+  *num_fields = 14;
 
   /* List what we want to write */
   list[0] = io_make_output_field_convert_part(
@@ -226,6 +226,10 @@ INLINE static void hydro_write_particles(const struct part* parts,
   list[12] = io_make_output_field_convert_part(
       "TotalEnergies", FLOAT, 1, UNIT_CONV_ENERGY, -3.f * hydro_gamma_minus_one,
       parts, xparts, convert_Etot, "Total (co-moving) energy of the particles");
+
+  list[13] = io_make_output_field("NumFaceInteractions", INT, 1,
+                                  UNIT_CONV_NO_UNITS, 0.f, parts, voronoi.nface,
+                                  "Number of Voronoi face interactions");
 }
 
 /**
diff --git a/src/hydro/Shadowswift/hydro_part.h b/src/hydro/Shadowswift/hydro_part.h
index 027b0e2ff72d60c3e207a51f7ee180c86b6774dd..ac079a0753892a7fae010ebab435edebfd12446d 100644
--- a/src/hydro/Shadowswift/hydro_part.h
+++ b/src/hydro/Shadowswift/hydro_part.h
@@ -223,6 +223,9 @@ struct part {
        tessellation. */
     int flag;
 
+    /* Number of times this cell interacted with other cells. */
+    int nface;
+
   } voronoi;
 
 } SWIFT_STRUCT_ALIGN;
diff --git a/src/runner_doiact_functions_hydro.h b/src/runner_doiact_functions_hydro.h
index 2d8bf4fbb958ae407b089d9cce6d69e8031ed43d..97103ef0506c79a8fa0e0dbe20251897d1393e96 100644
--- a/src/runner_doiact_functions_hydro.h
+++ b/src/runner_doiact_functions_hydro.h
@@ -1065,8 +1065,13 @@ 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);
+#if defined(SHADOWFAX_SPH)
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_pair1_density(e, ci, cj, sid, shift);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_GRADIENT)
+#else
+  error("Using wrong pair function!");
+#endif
 #endif
 
   if (cell_is_active_hydro(ci, e)) {
@@ -1408,6 +1413,15 @@ void DOPAIR2(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)
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) || \
+    (FUNCTION_TASK_LOOP == TASK_LOOP_GRADIENT)
+  error("Using wrong pair function!");
+#else
+  cell_shadowfax_do_pair2_force(e, ci, cj, sid, shift);
+#endif
+#endif
+
   /* Maximal displacement since last rebuild */
   const double dx_max = (ci->hydro.dx_max_sort + cj->hydro.dx_max_sort);
 
@@ -1986,8 +2000,13 @@ 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);
+#if defined(SHADOWFAX_SPH)
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  cell_shadowfax_do_self1_density(e, c);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_GRADIENT)
+#else
+  error("Using wrong self function!");
+#endif
 #endif
 
   struct part *restrict parts = c->hydro.parts;
@@ -2217,6 +2236,15 @@ void DOSELF2(struct runner *r, struct cell *restrict c) {
 
   TIMER_TIC;
 
+#if defined(SHADOWFAX_SPH)
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) || \
+    (FUNCTION_TASK_LOOP == TASK_LOOP_GRADIENT)
+  error("Using wrong self function!");
+#else
+  cell_shadowfax_do_self2_force(e, c);
+#endif
+#endif
+
   struct part *restrict parts = c->hydro.parts;
   const int count = c->hydro.count;
 
diff --git a/src/shadowfax/cell_shadowfax.h b/src/shadowfax/cell_shadowfax.h
index 2f369dc1de823def81a20fa1dbd737e29cb72ebf..79762bade884929eb1eac70940249e67e36b5fda 100644
--- a/src/shadowfax/cell_shadowfax.h
+++ b/src/shadowfax/cell_shadowfax.h
@@ -4,6 +4,7 @@
 #include "active.h"
 #include "cell.h"
 #include "delaunay.h"
+#include "hydro_shadowfax.h"
 #include "voronoi.h"
 
 __attribute__((always_inline)) INLINE static void shadowfax_flag_particle_added(
@@ -34,13 +35,15 @@ cell_malloc_delaunay_tessellation(struct cell *c,
     /* Get a pointer to the ith particle. */
     struct part *restrict p = &parts[pd];
     p->voronoi.flag = 0;
+    p->voronoi.nface = 0;
   }
 
   c->hydro.shadowfax_enabled = 1;
 }
 
-__attribute__((always_inline)) INLINE static void cell_shadowfax_do_self1(
-    const struct engine *e, struct cell *restrict c) {
+__attribute__((always_inline)) INLINE static void
+cell_shadowfax_do_self1_density(const struct engine *e,
+                                struct cell *restrict c) {
 
   const int count = c->hydro.count;
   struct part *restrict parts = c->hydro.parts;
@@ -56,8 +59,19 @@ __attribute__((always_inline)) INLINE static void cell_shadowfax_do_self1(
       shadowfax_flag_particle_added(p, 0);
     }
   }
+}
+
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_self2_force(
+    const struct engine *e, struct cell *restrict c) {
 
-  /*  delaunay_consolidate(&c->hydro.deltess);*/
+  struct part *restrict parts = c->hydro.parts;
+
+  struct voronoi *vortess = &c->hydro.vortess;
+  for (int i = 0; i < vortess->pair_index[0]; ++i) {
+    struct voronoi_pair *pair = &vortess->pairs[0][i];
+    hydro_shadowfax_flux_exchange(&parts[pair->left], &parts[pair->right],
+                                  pair->midpoint, pair->surface_area);
+  }
 }
 
 __attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair_naive(
@@ -240,9 +254,11 @@ __attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair_subset(
   }
 }
 
-__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) {
+__attribute__((always_inline)) INLINE static void
+cell_shadowfax_do_pair1_density(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!");
 
@@ -377,6 +393,21 @@ __attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair1(
   }     /* Cell cj is active */
 }
 
+__attribute__((always_inline)) INLINE static void cell_shadowfax_do_pair2_force(
+    const struct engine *e, struct cell *restrict ci, struct cell *restrict cj,
+    int sid, const double *shift) {
+
+  struct part *restrict parts_i = ci->hydro.parts;
+  struct part *restrict parts_j = cj->hydro.parts;
+
+  struct voronoi *vortess = &ci->hydro.vortess;
+  for (int i = 0; i < vortess->pair_index[1 + sid]; ++i) {
+    struct voronoi_pair *pair = &vortess->pairs[1 + sid][i];
+    hydro_shadowfax_flux_exchange(&parts_i[pair->left], &parts_j[pair->right],
+                                  pair->midpoint, pair->surface_area);
+  }
+}
+
 __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) {
diff --git a/src/shadowfax/hydro_shadowfax.h b/src/shadowfax/hydro_shadowfax.h
new file mode 100644
index 0000000000000000000000000000000000000000..235cb122220354e2869e32e1b14e16c59fc9fdd1
--- /dev/null
+++ b/src/shadowfax/hydro_shadowfax.h
@@ -0,0 +1,11 @@
+#ifndef SWIFT_HYDRO_SHADOWFAX_H
+#define SWIFT_HYDRO_SHADOWFAX_H
+
+__attribute__((always_inline)) INLINE static void hydro_shadowfax_flux_exchange(
+    struct part *restrict pi, struct part *restrict pj, double *midpoint, double surface_area) {
+    
+    ++pi->voronoi.nface;
+    ++pj->voronoi.nface;
+}
+
+#endif /* SWIFT_HYDRO_SHADOWFAX_H */
diff --git a/src/shadowfax/voronoi.h b/src/shadowfax/voronoi.h
index e9077c0812776d79fa9c52eb71ff66bbeb345b47..70d4ab5191524a916398322e8e9607cdd9bf0449 100644
--- a/src/shadowfax/voronoi.h
+++ b/src/shadowfax/voronoi.h
@@ -1,6 +1,6 @@
 /*******************************************************************************
  * This file is part of cVoronoi.
- * Copyright (c) 2020 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ * Copyright (c) 2020, 2021 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
  *
  * 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
@@ -68,6 +68,7 @@ struct voronoi_pair {
 #ifdef VORONOI_STORE_CONNECTIONS
   /*! First vertex of the interface. */
   double a[2];
+
   /*! Second vertex of the interface. */
   double b[2];
 #endif
@@ -87,6 +88,7 @@ struct voronoi_cell_new {
   double centroid[2];
 
 #ifdef VORONOI_STORE_GENERATORS
+  /*! Position of the cell generator. */
   double generator[2];
 #endif
 
@@ -109,11 +111,20 @@ struct voronoi {
   /*! @brief Voronoi cells. */
   struct voronoi_cell_new *cells;
 
-  /*! @brief Number of cells (and number of generators). */
+  /*! @brief Number of cells. */
   int number_of_cells;
 
+  /*! @brief Voronoi cell pairs. We store these per (SWIFT) cell, i.e. pairs[0]
+   *  contains all pairs that are completely contained within this cell, while
+   *  pairs[1] corresponds to pairs crossing the boundary between this cell and
+   *  the cell with coordinates that are lower in all coordinate directions (the
+   *  cell to the left, front, bottom, sid=0), and so on. */
   struct voronoi_pair *pairs[27];
+
+  /*! @brief Current number of pairs per cell index. */
   int pair_index[27];
+
+  /*! @brief Allocated number of pairs per cell index. */
   int pair_size[27];
 };
 
@@ -219,6 +230,7 @@ static inline double voronoi_compute_centroid_volume_triangle(
  *
  * @param v Voronoi grid.
  * @param d Delaunay tessellation (read-only).
+ * @param parts Local cell generators (read-only).
  */
 static inline void voronoi_init(struct voronoi *restrict v,
                                 const struct delaunay *restrict d,
@@ -456,25 +468,49 @@ static inline void voronoi_check_grid(const struct voronoi *restrict v) {
   printf("Total volume: %g\n", V);
 }
 
+/**
+ * @brief Write the Voronoi grid information to the given file.
+ *
+ * The output depends on the configuration. The maximal output contains 3
+ * different types of output lines:
+ *  - "G\tgx\tgx: x and y position of a single grid generator (optional).
+ *  - "C\tcx\tcy\tV\tnface": centroid position, volume and (optionally) number
+ *    of faces for a single Voronoi cell.
+ *  - "F\tax\tay\tbx\tby\tleft\tngb\tright\tA\tmx\tmy": edge positions
+ *    (optional), left and right generator index (and ngb cell index), surface
+ *    area and midpoint position for a single two-pair interface.
+ *
+ * @param v Voronoi grid.
+ * @param file File to write to.
+ */
 static inline void voronoi_write_grid(const struct voronoi *restrict v,
                                       FILE *file) {
 
-#ifdef VORONOI_STORE_GENERATORS
+  /* first write the cells (and generators, if those are stored) */
   for (int i = 0; i < v->number_of_cells; ++i) {
     struct voronoi_cell_new *this_cell = &v->cells[i];
+#ifdef VORONOI_STORE_GENERATORS
     fprintf(file, "G\t%g\t%g\n", this_cell->generator[0],
             this_cell->generator[1]);
-  }
 #endif
+    fprintf(file, "C\t%g\t%g\t%g", this_cell->centroid[0],
+            this_cell->centroid[1], this_cell->volume);
+#ifdef VORONOI_STORE_CELL_STATS
+    fprintf(file, "\t%i", this_cell->nface);
+#endif
+    fprintf(file, "\n");
+  }
+  /* now write the pairs */
   for (int ngb = 0; ngb < 27; ++ngb) {
     for (int i = 0; i < v->pair_index[ngb]; ++i) {
       struct voronoi_pair *pair = &v->pairs[ngb][i];
+      fprintf(file, "F\t");
 #ifdef VORONOI_STORE_CONNECTIONS
-      fprintf(file, "F\t%g\t%g\t%g\t%g\t%i\t%i\t%i\n", pair->a[0], pair->a[1],
-              pair->b[0], pair->b[1], pair->left, ngb, pair->right);
-#else
-      fprintf(file, "F\t%i\t%i\t%i\n", pair->left, ngb, pair->right);
+      fprintf(file, "%g\t%g\t%g\t%g\t", pair->a[0], pair->a[1], pair->b[0],
+              pair->b[1]);
 #endif
+      fprintf(file, "%i\t%i\t%i\t%g\t%g\t%g\n", pair->left, ngb, pair->right,
+              pair->surface_area, pair->midpoint[0], pair->midpoint[1]);
     }
   }
 }
@@ -482,16 +518,6 @@ static inline void voronoi_write_grid(const struct voronoi *restrict v,
 /**
  * @brief Print the Voronoi grid to a file with the given name.
  *
- * The grid is output as follows:
- *  1. First, each generator is output, together with all its connections.
- *     The generator is output as "G\tx\ty\n", where x and y are the coordinates
- *     of the generator. The centroid of the corresponding cell is output as
- *     "M\tx\ty\n".
- *     The connections are output as "C\tindex\tindex\n", where the two indices
- *     are the indices of two vertices of the grid, in the order output by 2.
- *     The midpoint of each edge is output as "F\tx\ty\n".
- *  2. Next, all vertices of the grid are output, in the format "V\tx\ty\n".
- *
  * @param v Voronoi grid (read-only).
  * @param file_name Name of the output file.
  */