diff --git a/configure.ac b/configure.ac
index d56d01ecc42fcf642c6b30437e09ef2f6557940f..fbf097976a7e67b8b35e20f1d66d231738fd80f6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -306,6 +306,18 @@ if test "$enable_naive_interactions" = "yes"; then
    AC_DEFINE([SWIFT_USE_NAIVE_INTERACTIONS],1,[Enable use of naive cell interaction functions])
 fi
 
+# Check whether we want to default to naive cell interactions (stars)
+AC_ARG_ENABLE([naive-interactions-stars],
+   [AS_HELP_STRING([--enable-naive-interactions-stars],
+     [Activate use of naive cell interaction functions for stars @<:@yes/no@:>@]
+   )],
+   [enable_naive_interactions_stars="$enableval"],
+   [enable_naive_interactions_stars="no"]
+)
+if test "$enable_naive_interactions_stars" = "yes"; then
+   AC_DEFINE([SWIFT_USE_NAIVE_INTERACTIONS_STARS],1,[Enable use of naive cell interaction functions for stars])
+fi
+
 # Check if gravity force checks are on for some particles.
 AC_ARG_ENABLE([gravity-force-checks],
    [AS_HELP_STRING([--enable-gravity-force-checks],
@@ -1943,6 +1955,7 @@ AC_MSG_RESULT([
    Interaction debugging       : $enable_debug_interactions
    Stars interaction debugging : $enable_debug_interactions_stars
    Naive interactions          : $enable_naive_interactions
+   Naive stars interactions    : $enable_naive_interactions_stars
    Gravity checks              : $gravity_force_checks
    Custom icbrtf               : $enable_custom_icbrtf
 
diff --git a/src/runner.c b/src/runner.c
index a44858659069b3ceea2e600e7e21eda798fff876..719c193e3d739bd929b008abff35eb6ad102a701 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -74,6 +74,7 @@
 #define TASK_LOOP_GRADIENT 1
 #define TASK_LOOP_FORCE 2
 #define TASK_LOOP_LIMITER 3
+#define TASK_LOOP_FEEDBACK 4
 
 /* Import the density loop functions. */
 #define FUNCTION density
@@ -110,14 +111,16 @@
 
 /* Import the stars density loop functions. */
 #define FUNCTION density
-#define UPDATE_STARS 1
+#define FUNCTION_TASK_LOOP TASK_LOOP_DENSITY
 #include "runner_doiact_stars.h"
-#undef UPDATE_STARS
+#undef FUNCTION_TASK_LOOP
 #undef FUNCTION
 
 /* Import the stars feedback loop functions. */
 #define FUNCTION feedback
+#define FUNCTION_TASK_LOOP TASK_LOOP_FEEDBACK
 #include "runner_doiact_stars.h"
+#undef FUNCTION_TASK_LOOP
 #undef FUNCTION
 
 /**
diff --git a/src/runner_doiact_stars.h b/src/runner_doiact_stars.h
index f208f14ac98a31a55df6741a2cc5f9cb0a829762..1ce0c370f31d860dd36e5af54020c8feb0da6c4f 100644
--- a/src/runner_doiact_stars.h
+++ b/src/runner_doiact_stars.h
@@ -28,15 +28,23 @@
 #define _DOSELF1_STARS(f) PASTE(runner_doself_stars, f)
 #define DOSELF1_STARS _DOSELF1_STARS(FUNCTION)
 
-#define _DO_NONSYM_PAIR1_STARS(f) PASTE(runner_do_nonsym_pair_stars, f)
-#define DO_NONSYM_PAIR1_STARS _DO_NONSYM_PAIR1_STARS(FUNCTION)
+#define _DO_SYM_PAIR1_STARS(f) PASTE(runner_do_sym_pair_stars, f)
+#define DO_SYM_PAIR1_STARS _DO_SYM_PAIR1_STARS(FUNCTION)
 
-#define _DOPAIR1_STARS(f) PASTE(runner_dopair_stars, f)
-#define DOPAIR1_STARS _DOPAIR1_STARS(FUNCTION)
+#define _DO_NONSYM_PAIR1_STARS_NAIVE(f) \
+  PASTE(runner_do_nonsym_pair_stars_naive, f)
+#define DO_NONSYM_PAIR1_STARS_NAIVE _DO_NONSYM_PAIR1_STARS_NAIVE(FUNCTION)
+
+#define _DOPAIR1_STARS_NAIVE(f) PASTE(runner_dopair_stars_naive, f)
+#define DOPAIR1_STARS_NAIVE _DOPAIR1_STARS_NAIVE(FUNCTION)
 
 #define _DOPAIR1_SUBSET_STARS(f) PASTE(runner_dopair_subset_stars, f)
 #define DOPAIR1_SUBSET_STARS _DOPAIR1_SUBSET_STARS(FUNCTION)
 
+#define _DOPAIR1_SUBSET_STARS_NAIVE(f) \
+  PASTE(runner_dopair_subset_stars_naive, f)
+#define DOPAIR1_SUBSET_STARS_NAIVE _DOPAIR1_SUBSET_STARS_NAIVE(FUNCTION)
+
 #define _DOSELF1_SUBSET_STARS(f) PASTE(runner_doself_subset_stars, f)
 #define DOSELF1_SUBSET_STARS _DOSELF1_SUBSET_STARS(FUNCTION)
 
@@ -83,8 +91,8 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
   const struct cosmology *cosmo = e->cosmology;
 
   /* Anything to do here? */
+  if (c->hydro.count == 0 || c->stars.count == 0) return;
   if (!cell_is_active_stars(c, e)) return;
-  if (c->hydro.count == 0 && c->stars.count == 0) return;
 
   /* Cosmological terms */
   const float a = cosmo->a;
@@ -100,7 +108,7 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
 
     /* Get a hold of the ith spart in ci. */
     struct spart *restrict si = &sparts[sid];
-    if (!spart_is_active(si, e) || spart_is_inhibited(si, e)) continue;
+    if (!spart_is_active(si, e)) continue;
 
     const float hi = si->h;
     const float hig2 = hi * hi * kernel_gamma2;
@@ -113,7 +121,9 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts[pjd];
-      const float hj = pj->h;
+
+      /* Early abort? */
+      if (part_is_inhibited(pj, e)) continue;
 
       /* Compute the pairwise distance. */
       const float pjx[3] = {(float)(pj->x[0] - c->loc[0]),
@@ -128,8 +138,8 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
         error("Particle pj not drifted to current time");
 #endif
 
-      if (r2 > 0.f && r2 < hig2) {
-        IACT_STARS(r2, dx, hi, hj, si, pj, a, H);
+      if (r2 < hig2) {
+        IACT_STARS(r2, dx, hi, pj->h, si, pj, a, H);
       }
     } /* loop over the parts in ci. */
   }   /* loop over the sparts in ci. */
@@ -142,11 +152,11 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
  * @param ci The first #cell
  * @param cj The second #cell
  */
-void DO_NONSYM_PAIR1_STARS(struct runner *r, struct cell *restrict ci,
-                           struct cell *restrict cj) {
+void DO_NONSYM_PAIR1_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
+                                 struct cell *restrict cj) {
 
 #ifdef SWIFT_DEBUG_CHECKS
-#ifdef UPDATE_STARS
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
   if (ci->nodeID != engine_rank) error("Should be run on a different node");
 #else
   if (cj->nodeID != engine_rank) error("Should be run on a different node");
@@ -157,6 +167,7 @@ void DO_NONSYM_PAIR1_STARS(struct runner *r, struct cell *restrict ci,
   const struct cosmology *cosmo = e->cosmology;
 
   /* Anything to do here? */
+  if (cj->hydro.count == 0 || ci->stars.count == 0) return;
   if (!cell_is_active_stars(ci, e)) return;
 
   const int scount_i = ci->stars.count;
@@ -182,7 +193,8 @@ void DO_NONSYM_PAIR1_STARS(struct runner *r, struct cell *restrict ci,
 
     /* Get a hold of the ith spart in ci. */
     struct spart *restrict si = &sparts_i[sid];
-    if (!spart_is_active(si, e) || spart_is_inhibited(si, e)) continue;
+    if (!spart_is_active(si, e)) continue;
+
     const float hi = si->h;
     const float hig2 = hi * hi * kernel_gamma2;
     const float six[3] = {(float)(si->x[0] - (cj->loc[0] + shift[0])),
@@ -194,7 +206,9 @@ void DO_NONSYM_PAIR1_STARS(struct runner *r, struct cell *restrict ci,
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts_j[pjd];
-      const float hj = pj->h;
+
+      /* Skip inhibited particles. */
+      if (part_is_inhibited(pj, e)) continue;
 
       /* Compute the pairwise distance. */
       const float pjx[3] = {(float)(pj->x[0] - cj->loc[0]),
@@ -209,27 +223,297 @@ void DO_NONSYM_PAIR1_STARS(struct runner *r, struct cell *restrict ci,
         error("Particle pj not drifted to current time");
 #endif
 
-      if (r2 < hig2) IACT_STARS(r2, dx, hi, hj, si, pj, a, H);
+      if (r2 < hig2) IACT_STARS(r2, dx, hi, pj->h, si, pj, a, H);
 
     } /* loop over the parts in cj. */
   }   /* loop over the parts in ci. */
 }
 
-void DOPAIR1_STARS(struct runner *r, struct cell *restrict ci,
-                   struct cell *restrict cj, int timer) {
+/**
+ * @brief Compute the interactions between a cell pair.
+ *
+ * @param r The #runner.
+ * @param ci The first #cell.
+ * @param cj The second #cell.
+ * @param sid The direction of the pair.
+ * @param shift The shift vector to apply to the particles in ci.
+ */
+void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
+                        const int sid, const double *shift) {
+
+  const struct engine *restrict e = r->e;
+  const struct cosmology *restrict cosmo = e->cosmology;
+
+  /* Get the cutoff shift. */
+  double rshift = 0.0;
+  for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k];
+
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  const int do_ci_stars = (ci->nodeID == e->nodeID) && (ci->stars.count != 0) &&
+                          (cj->hydro.count != 0) && cell_is_active_stars(ci, e);
+  const int do_cj_stars = (cj->nodeID == e->nodeID) && (cj->stars.count != 0) &&
+                          (ci->hydro.count != 0) && cell_is_active_stars(cj, e);
+#else
+  /* here we are updating the hydro -> switch ci, cj for local */
+  const int do_ci_stars = (cj->nodeID == e->nodeID) && (ci->stars.count != 0) &&
+                          (cj->hydro.count != 0) && cell_is_active_stars(ci, e);
+  const int do_cj_stars = (ci->nodeID == e->nodeID) && (cj->stars.count != 0) &&
+                          (ci->hydro.count != 0) && cell_is_active_stars(cj, e);
+#endif
+
+  if (do_ci_stars) {
+
+    /* Pick-out the sorted lists. */
+    const struct entry *restrict sort_j = cj->hydro.sort[sid];
+    const struct entry *restrict sort_i = ci->stars.sort[sid];
+
+#ifdef SWIFT_DEBUG_CHECKS
+    /* Some constants used to checks that the parts are in the right frame */
+    const float shift_threshold_x =
+        2. * ci->width[0] +
+        2. * max(ci->stars.dx_max_part, cj->hydro.dx_max_part);
+    const float shift_threshold_y =
+        2. * ci->width[1] +
+        2. * max(ci->stars.dx_max_part, cj->hydro.dx_max_part);
+    const float shift_threshold_z =
+        2. * ci->width[2] +
+        2. * max(ci->stars.dx_max_part, cj->hydro.dx_max_part);
+#endif /* SWIFT_DEBUG_CHECKS */
+
+    /* Get some other useful values. */
+    const double hi_max = ci->stars.h_max * kernel_gamma - rshift;
+    const int count_i = ci->stars.count;
+    const int count_j = cj->hydro.count;
+    struct spart *restrict sparts_i = ci->stars.parts;
+    struct part *restrict parts_j = cj->hydro.parts;
+    const double dj_min = sort_j[0].d;
+    const float dx_max_rshift =
+        (ci->stars.dx_max_sort + cj->hydro.dx_max_sort) - rshift;
+    const float dx_max = (ci->stars.dx_max_sort + cj->hydro.dx_max_sort);
+
+    /* Loop over the sparts 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 spart *restrict spi = &sparts_i[pid];
+      const float hi = spi->h;
+
+      /* Skip inactive particles */
+      if (!spart_is_active(spi, e)) continue;
+
+      /* Compute distance from the other cell. */
+      const double px[3] = {spi->x[0], spi->x[1], spi->x[2]};
+      float dist = px[0] * runner_shift[sid][0] + px[1] * runner_shift[sid][1] +
+                   px[2] * runner_shift[sid][2];
+
+      /* Is there anything we need to interact with ? */
+      const double di = dist + 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 = spi->x[0] - (cj->loc[0] + shift[0]);
+      const float piy = spi->x[1] - (cj->loc[1] + shift[1]);
+      const float piz = spi->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 hj = pj->h;
+        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];
+
+#ifdef SWIFT_DEBUG_CHECKS
+        /* Check that particles are in the correct frame after the shifts */
+        if (pix > shift_threshold_x || pix < -shift_threshold_x)
+          error(
+              "Invalid particle position in X for pi (pix=%e ci->width[0]=%e)",
+              pix, ci->width[0]);
+        if (piy > shift_threshold_y || piy < -shift_threshold_y)
+          error(
+              "Invalid particle position in Y for pi (piy=%e ci->width[1]=%e)",
+              piy, ci->width[1]);
+        if (piz > shift_threshold_z || piz < -shift_threshold_z)
+          error(
+              "Invalid particle position in Z for pi (piz=%e ci->width[2]=%e)",
+              piz, ci->width[2]);
+        if (pjx > shift_threshold_x || pjx < -shift_threshold_x)
+          error(
+              "Invalid particle position in X for pj (pjx=%e ci->width[0]=%e)",
+              pjx, ci->width[0]);
+        if (pjy > shift_threshold_y || pjy < -shift_threshold_y)
+          error(
+              "Invalid particle position in Y for pj (pjy=%e ci->width[1]=%e)",
+              pjy, ci->width[1]);
+        if (pjz > shift_threshold_z || pjz < -shift_threshold_z)
+          error(
+              "Invalid particle position in Z for pj (pjz=%e ci->width[2]=%e)",
+              pjz, ci->width[2]);
+
+        /* Check that particles have been drifted to the current time */
+        if (spi->ti_drift != e->ti_current)
+          error("Particle spi not drifted to current time");
+        if (pj->ti_drift != e->ti_current)
+          error("Particle pj not drifted to current time");
+#endif
+
+        /* Hit or miss? */
+        if (r2 < hig2) {
+
+          IACT_STARS(r2, dx, hi, hj, spi, pj, a, H);
+        }
+      } /* loop over the parts in cj. */
+    }   /* loop over the parts in ci. */
+  }     /* do_ci_stars */
+
+  if (do_cj_stars) {
+    /* Pick-out the sorted lists. */
+    const struct entry *restrict sort_i = ci->hydro.sort[sid];
+    const struct entry *restrict sort_j = cj->stars.sort[sid];
+
+#ifdef SWIFT_DEBUG_CHECKS
+    /* Some constants used to checks that the parts are in the right frame */
+    const float shift_threshold_x =
+        2. * ci->width[0] +
+        2. * max(ci->hydro.dx_max_part, cj->stars.dx_max_part);
+    const float shift_threshold_y =
+        2. * ci->width[1] +
+        2. * max(ci->hydro.dx_max_part, cj->stars.dx_max_part);
+    const float shift_threshold_z =
+        2. * ci->width[2] +
+        2. * max(ci->hydro.dx_max_part, cj->stars.dx_max_part);
+#endif /* SWIFT_DEBUG_CHECKS */
+
+    /* Get some other useful values. */
+    const double hj_max = cj->hydro.h_max * kernel_gamma;
+    const int count_i = ci->hydro.count;
+    const int count_j = cj->stars.count;
+    struct part *restrict parts_i = ci->hydro.parts;
+    struct spart *restrict sparts_j = cj->stars.parts;
+    const double di_max = sort_i[count_i - 1].d - rshift;
+    const float dx_max_rshift =
+        (ci->hydro.dx_max_sort + cj->stars.dx_max_sort) + rshift;
+    const float dx_max = (ci->hydro.dx_max_sort + cj->stars.dx_max_sort);
+
+    /* 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 spart *spj = &sparts_j[pjd];
+      const float hj = spj->h;
+
+      /* Skip inactive particles */
+      if (!spart_is_active(spj, e)) continue;
+
+      /* Compute distance from the other cell. */
+      const double px[3] = {spj->x[0], spj->x[1], spj->x[2]};
+      float dist = px[0] * runner_shift[sid][0] + px[1] * runner_shift[sid][1] +
+                   px[2] * runner_shift[sid][2];
+
+      /* Is there anything we need to interact with ? */
+      const double dj = dist - 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 = spj->x[0] - cj->loc[0];
+      const float pjy = spj->x[1] - cj->loc[1];
+      const float pjz = spj->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 hi = pi->h;
+        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];
+
+#ifdef SWIFT_DEBUG_CHECKS
+        /* Check that particles are in the correct frame after the shifts */
+        if (pix > shift_threshold_x || pix < -shift_threshold_x)
+          error(
+              "Invalid particle position in X for pi (pix=%e ci->width[0]=%e)",
+              pix, ci->width[0]);
+        if (piy > shift_threshold_y || piy < -shift_threshold_y)
+          error(
+              "Invalid particle position in Y for pi (piy=%e ci->width[1]=%e)",
+              piy, ci->width[1]);
+        if (piz > shift_threshold_z || piz < -shift_threshold_z)
+          error(
+              "Invalid particle position in Z for pi (piz=%e ci->width[2]=%e)",
+              piz, ci->width[2]);
+        if (pjx > shift_threshold_x || pjx < -shift_threshold_x)
+          error(
+              "Invalid particle position in X for pj (pjx=%e ci->width[0]=%e)",
+              pjx, ci->width[0]);
+        if (pjy > shift_threshold_y || pjy < -shift_threshold_y)
+          error(
+              "Invalid particle position in Y for pj (pjy=%e ci->width[1]=%e)",
+              pjy, ci->width[1]);
+        if (pjz > shift_threshold_z || pjz < -shift_threshold_z)
+          error(
+              "Invalid particle position in Z for pj (pjz=%e ci->width[2]=%e)",
+              pjz, ci->width[2]);
+
+        /* Check that particles have been drifted to the current time */
+        if (pi->ti_drift != e->ti_current)
+          error("Particle pi not drifted to current time");
+        if (spj->ti_drift != e->ti_current)
+          error("Particle spj not drifted to current time");
+#endif
+
+        /* Hit or miss? */
+        if (r2 < hjg2) {
+
+          IACT_STARS(r2, dx, hj, hi, spj, pi, a, H);
+        }
+      } /* loop over the parts in ci. */
+    }   /* loop over the parts in cj. */
+  }     /* Cell cj is active */
+}
+
+void DOPAIR1_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
+                         struct cell *restrict cj, int timer) {
 
-#ifdef UPDATE_STARS
-  const int ci_local = ci->nodeID == engine_rank;
-  const int cj_local = cj->nodeID == engine_rank;
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  const int do_ci_stars = ci->nodeID == r->e->nodeID;
+  const int do_cj_stars = cj->nodeID == r->e->nodeID;
 #else
   /* here we are updating the hydro -> switch ci, cj */
-  const int ci_local = cj->nodeID == engine_rank;
-  const int cj_local = ci->nodeID == engine_rank;
+  const int do_ci_stars = cj->nodeID == r->e->nodeID;
+  const int do_cj_stars = ci->nodeID == r->e->nodeID;
 #endif
-  if (ci_local && ci->stars.count != 0 && cj->hydro.count != 0)
-    DO_NONSYM_PAIR1_STARS(r, ci, cj);
-  if (cj_local && cj->stars.count != 0 && ci->hydro.count != 0)
-    DO_NONSYM_PAIR1_STARS(r, cj, ci);
+  if (do_ci_stars && ci->stars.count != 0 && cj->hydro.count != 0)
+    DO_NONSYM_PAIR1_STARS_NAIVE(r, ci, cj);
+  if (do_cj_stars && cj->stars.count != 0 && ci->hydro.count != 0)
+    DO_NONSYM_PAIR1_STARS_NAIVE(r, cj, ci);
 }
 
 /**
@@ -244,12 +528,151 @@ void DOPAIR1_STARS(struct runner *r, struct cell *restrict ci,
  * @param ind The list of indices of particles in @c ci to interact with.
  * @param scount The number of particles in @c ind.
  * @param cj The second #cell.
+ * @param sid The direction of the pair.
+ * @param flipped Flag to check whether the cells have been flipped or not.
  * @param shift The shift vector to apply to the particles in ci.
  */
 void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
                           struct spart *restrict sparts_i, int *restrict ind,
-                          int scount, struct cell *restrict cj,
-                          const double *shift) {
+                          int scount, struct cell *restrict cj, const int sid,
+                          const int flipped, const double *shift) {
+
+  const struct engine *e = r->e;
+  const struct cosmology *cosmo = e->cosmology;
+
+  const int count_j = cj->hydro.count;
+  struct part *restrict parts_j = cj->hydro.parts;
+
+  /* Early abort? */
+  if (count_j == 0) return;
+
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
+  /* Pick-out the sorted lists. */
+  const struct entry *restrict sort_j = cj->hydro.sort[sid];
+  const float dxj = cj->hydro.dx_max_sort;
+
+  /* Sparts are on the left? */
+  if (!flipped) {
+
+    /* Loop over the sparts_i. */
+    for (int pid = 0; pid < scount; pid++) {
+
+      /* Get a hold of the ith spart in ci. */
+      struct spart *restrict spi = &sparts_i[ind[pid]];
+      const double pix = spi->x[0] - (shift[0]);
+      const double piy = spi->x[1] - (shift[1]);
+      const double piz = spi->x[2] - (shift[2]);
+      const float hi = spi->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];
+
+#ifdef SWIFT_DEBUG_CHECKS
+        /* Check that particles have been drifted to the current time */
+        if (spi->ti_drift != e->ti_current)
+          error("Particle pi not drifted to current time");
+        if (pj->ti_drift != e->ti_current)
+          error("Particle pj not drifted to current time");
+#endif
+
+        /* Hit or miss? */
+        if (r2 < hig2) {
+          IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H);
+        }
+      } /* loop over the parts in cj. */
+    }   /* loop over the sparts in ci. */
+  }
+
+  /* Sparts are on the right. */
+  else {
+
+    /* Loop over the sparts_i. */
+    for (int pid = 0; pid < scount; pid++) {
+
+      /* Get a hold of the ith spart in ci. */
+      struct spart *restrict spi = &sparts_i[ind[pid]];
+      const double pix = spi->x[0] - (shift[0]);
+      const double piy = spi->x[1] - (shift[1]);
+      const double piz = spi->x[2] - (shift[2]);
+      const float hi = spi->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];
+
+#ifdef SWIFT_DEBUG_CHECKS
+        /* Check that particles have been drifted to the current time */
+        if (spi->ti_drift != e->ti_current)
+          error("Particle pi not drifted to current time");
+        if (pj->ti_drift != e->ti_current)
+          error("Particle pj not drifted to current time");
+#endif
+
+        /* Hit or miss? */
+        if (r2 < hig2) {
+          IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H);
+        }
+      } /* loop over the parts in cj. */
+    }   /* loop over the sparts in ci. */
+  }
+}
+
+/**
+ * @brief Compute the interactions between a cell pair, but only for the
+ *      given indices in ci.
+ *
+ * Version using a brute-force algorithm.
+ *
+ * @param r The #runner.
+ * @param ci The first #cell.
+ * @param sparts_i The #part to interact with @c cj.
+ * @param ind The list of indices of particles in @c ci to interact with.
+ * @param scount The number of particles in @c ind.
+ * @param cj The second #cell.
+ * @param shift The shift vector to apply to the particles in ci.
+ */
+void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
+                                struct spart *restrict sparts_i,
+                                int *restrict ind, int scount,
+                                struct cell *restrict cj, const double *shift) {
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (ci->nodeID != engine_rank) error("Should be run on a different node");
@@ -260,6 +683,9 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
   const int count_j = cj->hydro.count;
   struct part *restrict parts_j = cj->hydro.parts;
 
+  /* Early abort? */
+  if (count_j == 0) return;
+
   /* Cosmological terms */
   const float a = cosmo->a;
   const float H = cosmo->H;
@@ -285,6 +711,9 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts_j[pjd];
 
+      /* Skip inhibited particles */
+      if (part_is_inhibited(pj, e)) continue;
+
       /* Compute the pairwise distance. */
       float r2 = 0.0f;
       float dx[3];
@@ -334,6 +763,9 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
   const int count_i = ci->hydro.count;
   struct part *restrict parts_j = ci->hydro.parts;
 
+  /* Early abort? */
+  if (count_i == 0) return;
+
   /* Loop over the parts in ci. */
   for (int spid = 0; spid < scount; spid++) {
 
@@ -355,7 +787,9 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts_j[pjd];
-      const float hj = pj->h;
+
+      /* Early abort? */
+      if (part_is_inhibited(pj, e)) continue;
 
       /* Compute the pairwise distance. */
       const float pjx[3] = {(float)(pj->x[0] - ci->loc[0]),
@@ -371,8 +805,8 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 #endif
 
       /* Hit or miss? */
-      if (r2 > 0.f && r2 < hig2) {
-        IACT_STARS(r2, dx, hi, hj, spi, pj, a, H);
+      if (r2 < hig2) {
+        IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H);
       }
     } /* loop over the parts in cj. */
   }   /* loop over the parts in ci. */
@@ -414,6 +848,9 @@ void DOPAIR1_SUBSET_BRANCH_STARS(struct runner *r, struct cell *restrict ci,
 
   const struct engine *e = r->e;
 
+  /* Anything to do here? */
+  if (cj->hydro.count == 0) return;
+
   /* Get the relative distance between the pairs, wrapping. */
   double shift[3] = {0.0, 0.0, 0.0};
   for (int k = 0; k < 3; k++) {
@@ -423,7 +860,27 @@ void DOPAIR1_SUBSET_BRANCH_STARS(struct runner *r, struct cell *restrict ci,
       shift[k] = -e->s->dim[k];
   }
 
-  DOPAIR1_SUBSET_STARS(r, ci, sparts_i, ind, scount, cj, shift);
+#ifdef SWIFT_USE_NAIVE_INTERACTIONS_STARS
+  DOPAIR1_SUBSET_STARS_NAIVE(r, ci, sparts_i, ind, scount, cj, shift);
+#else
+  /* Get the sorting index. */
+  int sid = 0;
+  for (int k = 0; k < 3; k++)
+    sid = 3 * sid + ((cj->loc[k] - ci->loc[k] + shift[k] < 0)
+                         ? 0
+                         : (cj->loc[k] - ci->loc[k] + shift[k] > 0) ? 2 : 1);
+
+  /* Switch the cells around? */
+  const int flipped = runner_flip[sid];
+  sid = sortlistID[sid];
+
+  /* Has the cell cj been sorted? */
+  if (!(cj->hydro.sorted & (1 << sid)) ||
+      cj->hydro.dx_max_sort_old > space_maxreldx * cj->dmin)
+    error("Interacting unsorted cells.");
+
+  DOPAIR1_SUBSET_STARS(r, ci, sparts_i, ind, scount, cj, sid, flipped, shift);
+#endif
 }
 
 void DOSUB_SUBSET_STARS(struct runner *r, struct cell *ci, struct spart *sparts,
@@ -1075,18 +1532,18 @@ void DOPAIR1_BRANCH_STARS(struct runner *r, struct cell *ci, struct cell *cj) {
 
   const int ci_active = cell_is_active_stars(ci, e);
   const int cj_active = cell_is_active_stars(cj, e);
-#ifdef UPDATE_STARS
-  const int ci_local = ci->nodeID == engine_rank;
-  const int cj_local = cj->nodeID == engine_rank;
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+  const int do_ci_stars = ci->nodeID == e->nodeID;
+  const int do_cj_stars = cj->nodeID == e->nodeID;
 #else
   /* here we are updating the hydro -> switch ci, cj */
-  const int ci_local = cj->nodeID == engine_rank;
-  const int cj_local = ci->nodeID == engine_rank;
+  const int do_ci_stars = cj->nodeID == e->nodeID;
+  const int do_cj_stars = ci->nodeID == e->nodeID;
 #endif
-  const int do_ci =
-      (ci->stars.count != 0 && cj->hydro.count != 0 && ci_active && ci_local);
-  const int do_cj =
-      (cj->stars.count != 0 && ci->hydro.count != 0 && cj_active && cj_local);
+  const int do_ci = (ci->stars.count != 0 && cj->hydro.count != 0 &&
+                     ci_active && do_ci_stars);
+  const int do_cj = (cj->stars.count != 0 && ci->hydro.count != 0 &&
+                     cj_active && do_cj_stars);
 
   /* Anything to do here? */
   if (!do_ci && !do_cj) return;
@@ -1130,7 +1587,11 @@ void DOPAIR1_BRANCH_STARS(struct runner *r, struct cell *ci, struct cell *cj) {
   }
 #endif /* SWIFT_DEBUG_CHECKS */
 
-  DOPAIR1_STARS(r, ci, cj, 1);
+#ifdef SWIFT_USE_NAIVE_INTERACTIONS_STARS
+  DOPAIR1_STARS_NAIVE(r, ci, cj, 1);
+#else
+  DO_SYM_PAIR1_STARS(r, ci, cj, sid, shift);
+#endif
 }
 
 /**
@@ -1367,18 +1828,18 @@ void DOSUB_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
   /* Otherwise, compute the pair directly. */
   else {
 
-#ifdef UPDATE_STARS
-    const int ci_local = ci->nodeID == engine_rank;
-    const int cj_local = cj->nodeID == engine_rank;
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+    const int do_ci_stars = ci->nodeID == e->nodeID;
+    const int do_cj_stars = cj->nodeID == e->nodeID;
 #else
     /* here we are updating the hydro -> switch ci, cj */
-    const int ci_local = cj->nodeID == engine_rank;
-    const int cj_local = ci->nodeID == engine_rank;
+    const int do_ci_stars = cj->nodeID == e->nodeID;
+    const int do_cj_stars = ci->nodeID == e->nodeID;
 #endif
     const int do_ci = ci->stars.count != 0 && cj->hydro.count != 0 &&
-                      cell_is_active_stars(ci, e) && ci_local;
+                      cell_is_active_stars(ci, e) && do_ci_stars;
     const int do_cj = cj->stars.count != 0 && ci->hydro.count != 0 &&
-                      cell_is_active_stars(cj, e) && cj_local;
+                      cell_is_active_stars(cj, e) && do_cj_stars;
 
     if (do_ci) {