From 44f618ee742f08d80b51e26cd5b425ae07fef644 Mon Sep 17 00:00:00 2001
From: Matthieu Schaller <schaller@strw.leidenuniv.nl>
Date: Mon, 12 Nov 2018 17:33:18 +0100
Subject: [PATCH] Sort the extra particles at the end of their top-level cells.

---
 src/cell.c  | 29 +++++++++++++++++++
 src/cell.h  |  3 ++
 src/space.c | 82 +++++++++++++++++++++++++++++++++++++++++++----------
 src/space.h |  4 +++
 4 files changed, 103 insertions(+), 15 deletions(-)

diff --git a/src/cell.c b/src/cell.c
index 1c4d1f9e32..57795efcd3 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -3794,6 +3794,35 @@ void cell_convert_spart_to_gpart(const struct engine *e, struct cell *c,
 #endif
 }
 
+void cell_reorder_extra_parts(struct cell *c) {
+
+  struct part *parts = c->hydro.parts;
+  struct xpart *xparts = c->hydro.xparts;
+  const int count_real = c->hydro.count;
+  const int count_total = count_real + space_extra_parts;
+
+  int first_not_extra = count_real;
+
+  /* Find extra particles */
+  for (int i = 0; i < count_real; ++i) {
+    if (parts[i].time_bin == time_bin_not_created) {
+
+      /* Find the first non-extra particle after the end of the
+         real particles */
+      while (parts[first_not_extra].time_bin == time_bin_not_created) {
+        ++first_not_extra;
+      }
+
+      if (first_not_extra >= count_total)
+        error("Looking for extra particles beyond this cell's range!");
+
+      memswap(&parts[i], &parts[first_not_extra], sizeof(struct part));
+      memswap(&xparts[i], &xparts[first_not_extra], sizeof(struct xpart));
+      if (parts[i].gpart) error("Need to handle gpart pointer!");
+    }
+  }
+}
+
 /**
  * @brief Can we use the MM interactions fo a given pair of cells?
  *
diff --git a/src/cell.h b/src/cell.h
index 5d542e5f2d..009e6522db 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -663,6 +663,9 @@ void cell_convert_part_to_gpart(const struct engine *e, struct cell *c,
                                 struct part *p, struct xpart *xp);
 void cell_convert_spart_to_gpart(const struct engine *e, struct cell *c,
                                  struct spart *sp);
+void cell_reorder_extra_parts(struct cell *c);
+void cell_reorder_extra_gparts(struct cell *c);
+void cell_reorder_extra_sparts(struct cell *c);
 int cell_can_use_pair_mm(const struct cell *ci, const struct cell *cj,
                          const struct engine *e, const struct space *s);
 int cell_can_use_pair_mm_rebuild(const struct cell *ci, const struct cell *cj,
diff --git a/src/space.c b/src/space.c
index a27280d411..6f78ed8674 100644
--- a/src/space.c
+++ b/src/space.c
@@ -767,12 +767,12 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
   size_t size_gparts = s->size_gparts;
   size_t size_sparts = s->size_sparts;
 
-  /* Number of inhibited particles found on the node */
+  /* Counter for the number of inhibited particles found on the node */
   size_t count_inhibited_parts = 0;
   size_t count_inhibited_gparts = 0;
   size_t count_inhibited_sparts = 0;
 
-  /* Number of extra particles found on the node */
+  /* Counter for the number of extra particles found on the node */
   size_t count_extra_parts = 0;
   size_t count_extra_gparts = 0;
   size_t count_extra_sparts = 0;
@@ -1157,22 +1157,26 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
   }
 #endif /* SWIFT_DEBUG_CHECKS */
 
-  /* Extract the cell counts from the sorted indices. */
+  /* Extract the cell counts from the sorted indices. Deduct the extra
+   * particles. */
   size_t last_index = 0;
   h_index[nr_parts] = s->nr_cells;  // sentinel.
   for (size_t k = 0; k < nr_parts; k++) {
     if (h_index[k] < h_index[k + 1]) {
-      cells_top[h_index[k]].hydro.count = k - last_index + 1;
+      cells_top[h_index[k]].hydro.count =
+          k - last_index + 1 - space_extra_parts;
       last_index = k + 1;
     }
   }
 
-  /* Extract the cell counts from the sorted indices. */
+  /* Extract the cell counts from the sorted indices. Deduct the extra
+   * particles. */
   size_t last_sindex = 0;
   s_index[nr_sparts] = s->nr_cells;  // sentinel.
   for (size_t k = 0; k < nr_sparts; k++) {
     if (s_index[k] < s_index[k + 1]) {
-      cells_top[s_index[k]].stars.count = k - last_sindex + 1;
+      cells_top[s_index[k]].stars.count =
+          k - last_sindex + 1 - space_extra_sparts;
       last_sindex = k + 1;
     }
   }
@@ -1252,12 +1256,14 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
   }
 #endif /* SWIFT_DEBUG_CHECKS */
 
-  /* Extract the cell counts from the sorted indices. */
+  /* Extract the cell counts from the sorted indices. Deduct the extra
+   * particles. */
   size_t last_gindex = 0;
   g_index[nr_gparts] = s->nr_cells;
   for (size_t k = 0; k < nr_gparts; k++) {
     if (g_index[k] < g_index[k + 1]) {
-      cells_top[g_index[k]].grav.count = k - last_gindex + 1;
+      cells_top[g_index[k]].grav.count =
+          k - last_gindex + 1 - space_extra_gparts;
       last_gindex = k + 1;
     }
   }
@@ -1302,10 +1308,10 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
       c->hydro.xparts = xfinger;
       c->grav.parts = gfinger;
       c->stars.parts = sfinger;
-      finger = &finger[c->hydro.count];
-      xfinger = &xfinger[c->hydro.count];
-      gfinger = &gfinger[c->grav.count];
-      sfinger = &sfinger[c->stars.count];
+      finger = &finger[c->hydro.count + space_extra_parts];
+      xfinger = &xfinger[c->hydro.count + space_extra_parts];
+      gfinger = &gfinger[c->grav.count + space_extra_gparts];
+      sfinger = &sfinger[c->stars.count + space_extra_sparts];
 
       /* Add this cell to the list of local cells */
       s->local_cells_top[s->nr_local_cells] = k;
@@ -1328,8 +1334,12 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
             clocks_from_ticks(getticks() - tic2), clocks_getunit());
   }
 
-  /* At this point, we have the upper-level cells, old or new. Now make
-     sure that the parts in each cell are ok. */
+  /* Re-order the extra particles such that they are at the end of their cell's
+     memory pool. */
+  space_reorder_extras(s, verbose);
+
+  /* At this point, we have the upper-level cells. Now recursively split each
+     cell to get the full AMR grid. */
   space_split(s, verbose);
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -1369,6 +1379,39 @@ void space_split(struct space *s, int verbose) {
             clocks_getunit());
 }
 
+void space_reorder_extra_parts_mapper(void *map_data, int num_cells,
+                                      void *extra_data) {
+
+  struct cell *cells_top = (struct cell *)map_data;
+  for (int ind = 0; ind < num_cells; ind++) {
+    struct cell *c = &cells_top[ind];
+    cell_reorder_extra_parts(c);
+  }
+}
+
+/**
+ * @brief Re-orders the particles in each cell such that the extra particles
+ * for on-the-fly creation are located at the end of their respective cells.
+ *
+ * This assumes that all the particles (real and extra) have already been sorted
+ * in their correct top-level cell.
+ *
+ * @param s The #space to act upon.
+ * @param verbose Are we talkative?
+ */
+void space_reorder_extras(struct space *s, int verbose) {
+
+#ifdef WITH_MPI
+  if (space_extra_parts || space_extra_gparts || space_extra_sparts)
+    error("Need an MPI-proof version of this.");
+#endif
+
+  /* Re-order the gas particles */
+  if (space_extra_parts)
+    threadpool_map(&s->e->threadpool, space_reorder_extra_parts_mapper,
+                   s->cells_top, s->nr_cells, sizeof(struct cell), 0, NULL);
+}
+
 /**
  * @brief #threadpool mapper function to sanitize the cells
  *
@@ -2250,6 +2293,8 @@ void space_split_recursive(struct space *s, struct cell *c,
 #ifdef SWIFT_DEBUG_CHECKS
         if (parts[k].time_bin == time_bin_inhibited)
           error("Inhibited particle present in space_split()");
+        if (parts[k].time_bin == time_bin_not_created)
+          error("Extra particle present in space_split()");
 #endif
         buff[k].x[0] = parts[k].x[0];
         buff[k].x[1] = parts[k].x[1];
@@ -2264,6 +2309,8 @@ void space_split_recursive(struct space *s, struct cell *c,
 #ifdef SWIFT_DEBUG_CHECKS
         if (gparts[k].time_bin == time_bin_inhibited)
           error("Inhibited particle present in space_split()");
+        if (gparts[k].time_bin == time_bin_not_created)
+          error("Extra particle present in space_split()");
 #endif
         gbuff[k].x[0] = gparts[k].x[0];
         gbuff[k].x[1] = gparts[k].x[1];
@@ -2278,6 +2325,8 @@ void space_split_recursive(struct space *s, struct cell *c,
 #ifdef SWIFT_DEBUG_CHECKS
         if (sparts[k].time_bin == time_bin_inhibited)
           error("Inhibited particle present in space_split()");
+        if (sparts[k].time_bin == time_bin_not_created)
+          error("Extra particle present in space_split()");
 #endif
         sbuff[k].x[0] = sparts[k].x[0];
         sbuff[k].x[1] = sparts[k].x[1];
@@ -3234,8 +3283,11 @@ void space_convert_quantities_mapper(void *restrict map_data, int count,
   const ptrdiff_t index = parts - s->parts;
   struct xpart *restrict xparts = s->xparts + index;
 
+  /* Loop over all the particles ignoring the extra buffer ones for on-the-fly
+   * cretion */
   for (int k = 0; k < count; k++)
-    hydro_convert_quantities(&parts[k], &xparts[k], cosmo, hydro_props);
+    if (parts[k].time_bin <= num_time_bins)
+      hydro_convert_quantities(&parts[k], &xparts[k], cosmo, hydro_props);
 }
 
 /**
diff --git a/src/space.h b/src/space.h
index cdf83e4ada..4f1a39c287 100644
--- a/src/space.h
+++ b/src/space.h
@@ -72,6 +72,9 @@ extern int space_subsize_self_grav;
 extern int space_subsize_pair_stars;
 extern int space_subsize_self_stars;
 extern int space_subdepth_grav;
+extern int space_extra_parts;
+extern int space_extra_gparts;
+extern int space_extra_sparts;
 
 /**
  * @brief The space in which the cells and particles reside.
@@ -282,6 +285,7 @@ void space_recycle_list(struct space *s, struct cell *cell_list_begin,
                         struct gravity_tensors *multipole_list_begin,
                         struct gravity_tensors *multipole_list_end);
 void space_split(struct space *s, int verbose);
+void space_reorder_extras(struct space *s, int verbose);
 void space_split_mapper(void *map_data, int num_elements, void *extra_data);
 void space_list_useful_top_level_cells(struct space *s);
 void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts,
-- 
GitLab