From a3505366e5677015c8f08ce35a9eb16fff23c139 Mon Sep 17 00:00:00 2001
From: Matthieu Schaller <schaller@strw.leidenuniv.nl>
Date: Sat, 16 Feb 2019 21:42:15 +0100
Subject: [PATCH] Added a separate function to drift the stars independantly of
 the gparts.

---
 src/cell.c                | 119 +++++++++++++++++++++++++++++++-------
 src/cell.h                |  16 ++++-
 src/runner.c              |  18 ++++++
 src/runner_doiact_stars.h |   1 +
 4 files changed, 131 insertions(+), 23 deletions(-)

diff --git a/src/cell.c b/src/cell.c
index 22ddc6c520..990823bd9a 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -3830,15 +3830,9 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
   const int periodic = e->s->periodic;
   const double dim[3] = {e->s->dim[0], e->s->dim[1], e->s->dim[2]};
   const int with_cosmology = (e->policy & engine_policy_cosmology);
-  const float stars_h_max = e->stars_properties->h_max;
   const integertime_t ti_old_gpart = c->grav.ti_old_part;
   const integertime_t ti_current = e->ti_current;
   struct gpart *const gparts = c->grav.parts;
-  struct spart *const sparts = c->stars.parts;
-
-  float dx_max = 0.f, dx2_max = 0.f;
-  float dx_max_sort = 0.0f, dx2_max_sort = 0.f;
-  float cell_h_max = 0.f;
 
   /* Drift irrespective of cell flags? */
   force |= c->grav.do_drift;
@@ -3876,19 +3870,9 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
 
         /* Recurse */
         cell_drift_gpart(cp, e, force);
-
-        /* Update */
-        dx_max = max(dx_max, cp->stars.dx_max_part);
-        dx_max_sort = max(dx_max_sort, cp->stars.dx_max_sort);
-        cell_h_max = max(cell_h_max, cp->stars.h_max);
       }
     }
 
-    /* Store the values */
-    c->stars.h_max = cell_h_max;
-    c->stars.dx_max_part = dx_max;
-    c->stars.dx_max_sort = dx_max_sort;
-
     /* Update the time of the last drift */
     c->grav.ti_old_part = ti_current;
 
@@ -3946,6 +3930,99 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
       }
     }
 
+    /* Update the time of the last drift */
+    c->grav.ti_old_part = ti_current;
+  }
+
+  /* Clear the drift flags. */
+  c->grav.do_drift = 0;
+  c->grav.do_sub_drift = 0;
+}
+
+/**
+ * @brief Recursively drifts the #spart in a cell hierarchy.
+ *
+ * @param c The #cell.
+ * @param e The #engine (to get ti_current).
+ * @param force Drift the particles irrespective of the #cell flags.
+ */
+void cell_drift_spart(struct cell *c, const struct engine *e, int force) {
+
+  const int periodic = e->s->periodic;
+  const double dim[3] = {e->s->dim[0], e->s->dim[1], e->s->dim[2]};
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const float stars_h_max = e->stars_properties->h_max;
+  const integertime_t ti_old_spart = c->stars.ti_old_part;
+  const integertime_t ti_current = e->ti_current;
+  struct spart *const sparts = c->stars.parts;
+
+  float dx_max = 0.f, dx2_max = 0.f;
+  float dx_max_sort = 0.0f, dx2_max_sort = 0.f;
+  float cell_h_max = 0.f;
+
+  /* Drift irrespective of cell flags? */
+  force |= c->stars.do_drift;
+
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Check that we only drift local cells. */
+  if (c->nodeID != engine_rank) error("Drifting a foreign cell is nope.");
+
+  /* Check that we are actually going to move forward. */
+  if (ti_current < ti_old_spart) error("Attempt to drift to the past");
+#endif
+
+  /* Early abort? */
+  if (c->stars.count == 0) {
+
+    /* Clear the drift flags. */
+    c->stars.do_drift = 0;
+    c->stars.do_sub_drift = 0;
+
+    /* Update the time of the last drift */
+    c->stars.ti_old_part = ti_current;
+
+    return;
+  }
+
+  /* Ok, we have some particles somewhere in the hierarchy to drift */
+
+  /* Are we not in a leaf ? */
+  if (c->split && (force || c->stars.do_sub_drift)) {
+
+    /* Loop over the progeny and collect their data. */
+    for (int k = 0; k < 8; k++) {
+      if (c->progeny[k] != NULL) {
+        struct cell *cp = c->progeny[k];
+
+        /* Recurse */
+        cell_drift_gpart(cp, e, force);
+
+        /* Update */
+        dx_max = max(dx_max, cp->stars.dx_max_part);
+        dx_max_sort = max(dx_max_sort, cp->stars.dx_max_sort);
+        cell_h_max = max(cell_h_max, cp->stars.h_max);
+      }
+    }
+
+    /* Store the values */
+    c->stars.h_max = cell_h_max;
+    c->stars.dx_max_part = dx_max;
+    c->stars.dx_max_sort = dx_max_sort;
+
+    /* Update the time of the last drift */
+    c->stars.ti_old_part = ti_current;
+
+  } else if (!c->split && force && ti_current > ti_old_spart) {
+
+    /* Drift from the last time the cell was drifted to the current time */
+    double dt_drift;
+    if (with_cosmology) {
+      dt_drift =
+          cosmology_get_drift_factor(e->cosmology, ti_old_spart, ti_current);
+    } else {
+      dt_drift = (ti_current - ti_old_spart) * e->time_base;
+    }
+
     /* Loop over all the star particles in the cell */
     const size_t nr_sparts = c->stars.count;
     for (size_t k = 0; k < nr_sparts; k++) {
@@ -3957,7 +4034,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
       if (spart_is_inhibited(sp, e)) continue;
 
       /* Drift... */
-      drift_spart(sp, dt_drift, ti_old_gpart, ti_current);
+      drift_spart(sp, dt_drift, ti_old_spart, ti_current);
 
 #ifdef SWIFT_DEBUG_CHECKS
       /* Make sure the particle does not drift by more than a box length. */
@@ -4009,7 +4086,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
       if (spart_is_active(sp, e)) {
         stars_init_spart(sp);
       }
-    } /* Note: no need to compute dx_max as all spart have a gpart */
+    }
 
     /* Now, get the maximal particle motion from its square */
     dx_max = sqrtf(dx2_max);
@@ -4021,12 +4098,12 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
     c->stars.dx_max_sort = dx_max_sort;
 
     /* Update the time of the last drift */
-    c->grav.ti_old_part = ti_current;
+    c->stars.ti_old_part = ti_current;
   }
 
   /* Clear the drift flags. */
-  c->grav.do_drift = 0;
-  c->grav.do_sub_drift = 0;
+  c->stars.do_drift = 0;
+  c->stars.do_sub_drift = 0;
 }
 
 /**
diff --git a/src/cell.h b/src/cell.h
index 63937ba021..a299af5a43 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -490,6 +490,9 @@ struct cell {
     /*! Max smoothing length in this cell. */
     double h_max;
 
+    /*! Last (integer) time the cell's spart were drifted forward in time. */
+    integertime_t ti_old_part;
+
     /*! Spin lock for various uses (#spart case). */
     swift_lock_type lock;
 
@@ -541,6 +544,12 @@ struct cell {
     /*! Is the #spart data of this cell being used in a sub-cell? */
     int hold;
 
+    /*! Does this cell need to be drifted (stars)? */
+    char do_drift;
+
+    /*! Do any of this cell's sub-cells need to be drifted (stars)? */
+    char do_sub_drift;
+
 #ifdef SWIFT_DEBUG_CHECKS
     /*! Last (integer) time the cell's sort arrays were updated. */
     integertime_t ti_sort;
@@ -720,6 +729,7 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s);
 void cell_set_super(struct cell *c, struct cell *super);
 void cell_drift_part(struct cell *c, const struct engine *e, int force);
 void cell_drift_gpart(struct cell *c, const struct engine *e, int force);
+void cell_drift_spart(struct cell *c, const struct engine *e, int force);
 void cell_drift_multipole(struct cell *c, const struct engine *e);
 void cell_drift_all_multipoles(struct cell *c, const struct engine *e);
 void cell_check_timesteps(struct cell *c);
@@ -912,7 +922,8 @@ __attribute__((always_inline)) INLINE static int cell_can_split_pair_hydro_task(
   /* Note that since tasks are create after a rebuild no need to take */
   /* into account any part motion (i.e. dx_max == 0 here) */
   return c->split &&
-         (space_stretch * kernel_gamma * c->hydro.h_max < 0.5f * c->dmin);
+         (space_stretch * kernel_gamma * c->hydro.h_max < 0.5f * c->dmin) &&
+         (space_stretch * kernel_gamma * c->stars.h_max < 0.5f * c->dmin);
 }
 
 /**
@@ -930,7 +941,8 @@ __attribute__((always_inline)) INLINE static int cell_can_split_self_hydro_task(
   /* Note: No need for more checks here as all the sub-pairs and sub-self */
   /* tasks will be created. So no need to check for h_max */
   return c->split &&
-         (space_stretch * kernel_gamma * c->hydro.h_max < 0.5f * c->dmin);
+         (space_stretch * kernel_gamma * c->hydro.h_max < 0.5f * c->dmin) &&
+         (space_stretch * kernel_gamma * c->stars.h_max < 0.5f * c->dmin);
 }
 
 /**
diff --git a/src/runner.c b/src/runner.c
index 6585458064..c9ac839568 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -1774,6 +1774,21 @@ void runner_do_drift_gpart(struct runner *r, struct cell *c, int timer) {
   if (timer) TIMER_TOC(timer_drift_gpart);
 }
 
+/**
+ * @brief Drift all spart in a cell.
+ *
+ * @param r The runner thread.
+ * @param c The cell.
+ * @param timer Are we timing this ?
+ */
+void runner_do_drift_spart(struct runner *r, struct cell *c, int timer) {
+
+  TIMER_TIC;
+
+  cell_drift_spart(c, r->e, 0);
+
+  if (timer) TIMER_TOC(timer_drift_spart);
+}
 /**
  * @brief Perform the first half-kick on all the active particles in a cell.
  *
@@ -3162,6 +3177,9 @@ void *runner_main(void *data) {
         case task_type_drift_part:
           runner_do_drift_part(r, ci, 1);
           break;
+        case task_type_drift_spart:
+          runner_do_drift_spart(r, ci, 1);
+          break;
         case task_type_drift_gpart:
           runner_do_drift_gpart(r, ci, 1);
           break;
diff --git a/src/runner_doiact_stars.h b/src/runner_doiact_stars.h
index a8cd8a94b1..f1210acad8 100644
--- a/src/runner_doiact_stars.h
+++ b/src/runner_doiact_stars.h
@@ -1434,6 +1434,7 @@ void DOSUB_SELF1_STARS(struct runner *r, struct cell *ci, int gettimer) {
   if (ci->nodeID != engine_rank)
     error("This function should not be called on foreign cells");
 #endif
+
   /* Should we even bother? */
   if (ci->hydro.count == 0 || ci->stars.count == 0 ||
       !cell_is_active_stars(ci, r->e))
-- 
GitLab