From c94fd6d695d6c67d8197142d7a2bd96a13c84d07 Mon Sep 17 00:00:00 2001
From: Matthieu Schaller <matthieu.schaller@durham.ac.uk>
Date: Sun, 1 Oct 2017 16:02:47 +0100
Subject: [PATCH] Do not escape the cells with no gparticles in the long-range
 gravity task.

---
 examples/EAGLE_12/eagle_12.yml |   2 +-
 src/const.h                    |   2 +
 src/engine.c                   |  97 +++++++++++++++++++++++---
 src/gravity_properties.c       |   2 +-
 src/runner.c                   |  15 +++-
 src/runner_doiact_grav.h       | 121 ++++++++++++++++++++++++++-------
 6 files changed, 201 insertions(+), 38 deletions(-)

diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml
index cc5d87ca02..ba181c8374 100644
--- a/examples/EAGLE_12/eagle_12.yml
+++ b/examples/EAGLE_12/eagle_12.yml
@@ -27,7 +27,7 @@ Statistics:
 Gravity:
   eta:                   0.025    # Constant dimensionless multiplier for time integration.
   epsilon:               0.001    # Softening length (in internal units).
-  theta:                 0.7      # Opening angle (Multipole acceptance criterion)
+  theta:                 2.5      # Opening angle (Multipole acceptance criterion)
   
 # Parameters for the hydrodynamics scheme
 SPH:
diff --git a/src/const.h b/src/const.h
index c8060a2be5..60c84a240a 100644
--- a/src/const.h
+++ b/src/const.h
@@ -113,4 +113,6 @@
 #define SOURCETERMS_NONE
 //#define SOURCETERMS_SN_FEEDBACK
 
+#define ICHECK 5726454604296ll
+
 #endif /* SWIFT_CONST_H */
diff --git a/src/engine.c b/src/engine.c
index a773f6f4fd..b46bd79cf5 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -1317,6 +1317,7 @@ void engine_addtasks_recv_gravity(struct engine *e, struct cell *c, struct task
   }
 
   c->recv_grav = t_grav;
+  c->recv_multipole = t_multi;
   
   for (struct link *l = c->grav; l != NULL; l = l->next) {
     scheduler_addunlock(s, t_grav, l->t);
@@ -1948,13 +1949,32 @@ void engine_make_self_gravity_tasks_mapper(void *map_data, int num_elements,
     struct gravity_tensors *const multi_i = ci->multipole;
     const double CoM_i[3] = {multi_i->CoM[0], multi_i->CoM[1], multi_i->CoM[2]};
 
-    /* Loop over every other cell */
-    for (int ii = 0; ii < cdim[0]; ii++) {
-      for (int jj = 0; jj < cdim[1]; jj++) {
-        for (int kk = 0; kk < cdim[2]; kk++) {
+    /* /\* Loop over every other cell *\/ */
+    /* for (int ii = 0; ii < cdim[0]; ii++) { */
+    /*   for (int jj = 0; jj < cdim[1]; jj++) { */
+    /*     for (int kk = 0; kk < cdim[2]; kk++) { */
 
-          /* Get the cell */
-          const int cjd = cell_getid(cdim, ii, jj, kk);
+    /*       /\* Get the cell *\/ */
+    /*       const int cjd = cell_getid(cdim, ii, jj, kk); */
+    /*       struct cell *cj = &cells[cjd]; */
+
+
+    /* Now loop over all the neighbours of this cell */
+    for (int ii = -1; ii < 2; ii++) {
+      int iii = i + ii;
+      if (!s->periodic && (iii < 0 || iii >= cdim[0])) continue;
+      iii = (iii + cdim[0]) % cdim[0];
+      for (int jj = -1; jj < 2; jj++) {
+        int jjj = j + jj;
+        if (!s->periodic && (jjj < 0 || jjj >= cdim[1])) continue;
+        jjj = (jjj + cdim[1]) % cdim[1];
+        for (int kk = -1; kk < 2; kk++) {
+          int kkk = k + kk;
+          if (!s->periodic && (kkk < 0 || kkk >= cdim[2])) continue;
+          kkk = (kkk + cdim[2]) % cdim[2];
+
+          /* Get the neighbouring cell */
+          const int cjd = cell_getid(cdim, iii, jjj, kkk);
           struct cell *cj = &cells[cjd];
 
 	  /* Avoid duplicates of local pairs*/
@@ -1980,9 +2000,13 @@ void engine_make_self_gravity_tasks_mapper(void *map_data, int num_elements,
           const double r2 = dx * dx + dy * dy + dz * dz;
 
           /* Are the cells too close for a MM interaction ? */
-          if (!gravity_M2L_accept(multi_i->r_max_rebuild,
+          if (1 || !gravity_M2L_accept(multi_i->r_max_rebuild,
                                   multi_j->r_max_rebuild, theta_crit2, r2)) {
 
+	    if(i==11 && j==11 && k==10)
+	      message("Found direct neighbour: (i,j,k)=(%d,%d,%d) (iii,jjj,kkk)=(%d,%d,%d) nodeID=%d", 	i,j,k, iii,jjj,kkk, cj->nodeID);
+
+
             /* Ok, we need to add a direct pair calculation */
             scheduler_addtask(sched, task_type_pair, task_subtype_grav, 0, 0,
                               ci, cj);
@@ -2985,6 +3009,59 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
         }
 #endif
       }
+
+
+      /* Only interested in gravity tasks as of here. */
+      if (t->subtype == task_subtype_grav) {
+
+#ifdef WITH_MPI
+        /* Activate the send/recv tasks. */
+        if (ci->nodeID != engine_rank) {
+
+          /* If the local cell is active, receive data from the foreign cell. */
+          if (cj_active) {
+            scheduler_activate(s, ci->recv_grav);
+            scheduler_activate(s, ci->recv_multipole);
+	  }
+
+          /* Is the foreign cell active and will need stuff from us? */
+          if (ci_active) {
+
+            struct link *l =
+                scheduler_activate_send(s, cj->send_grav, ci->nodeID);
+
+            /* Drift the cell which will be sent at the level at which it is
+               sent, i.e. drift the cell specified in the send task (l->t)
+               itself. */
+            cell_activate_drift_gpart(l->t->ci, s);
+
+	    scheduler_activate_send(s, cj->send_multipole, ci->nodeID);
+	  }
+	} else if (cj->nodeID != engine_rank) {
+
+          /* If the local cell is active, receive data from the foreign cell. */
+          if (ci_active) {
+            scheduler_activate(s, cj->recv_grav);
+            scheduler_activate(s, cj->recv_multipole);
+	  }
+
+          /* Is the foreign cell active and will need stuff from us? */
+          if (cj_active) {
+
+            struct link *l =
+	      scheduler_activate_send(s, ci->send_grav, cj->nodeID);
+
+
+            /* Drift the cell which will be sent at the level at which it is
+               sent, i.e. drift the cell specified in the send task (l->t)
+               itself. */
+            cell_activate_drift_gpart(l->t->ci, s);
+
+	    scheduler_activate_send(s, ci->send_multipole, cj->nodeID);
+	  }
+	}
+#endif
+      }
     }
 
     /* Kick/init ? */
@@ -3066,9 +3143,9 @@ void engine_print_task_counts(struct engine *e) {
   int counts[task_type_count + 1];
   for (int k = 0; k <= task_type_count; k++) counts[k] = 0;
   for (int k = 0; k < nr_tasks; k++) {
-    /* if (tasks[k].skip) */
-    /*   counts[task_type_count] += 1; */
-    /* else */
+    if (tasks[k].skip)
+      counts[task_type_count] += 1;
+    else
       counts[(int)tasks[k].type] += 1;
   }
   message("Total = %d  (per cell = %d)", nr_tasks,
diff --git a/src/gravity_properties.c b/src/gravity_properties.c
index 27a5de0a41..cb3860b5f6 100644
--- a/src/gravity_properties.c
+++ b/src/gravity_properties.c
@@ -52,7 +52,7 @@ void gravity_props_init(struct gravity_props *p,
 
   /* Opening angle */
   p->theta_crit = parser_get_param_double(params, "Gravity:theta");
-  if (p->theta_crit >= 1.) error("Theta too large. FMM won't converge.");
+  //if (p->theta_crit >= 1.) error("Theta too large. FMM won't converge.");
   p->theta_crit2 = p->theta_crit * p->theta_crit;
   p->theta_crit_inv = 1. / p->theta_crit;
 
diff --git a/src/runner.c b/src/runner.c
index 8e99a7f6cb..5afc5eca3d 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -1419,6 +1419,14 @@ void runner_do_end_force(struct runner *r, struct cell *c, int timer) {
 
   TIMER_TIC;
 
+
+#if (ICHECK != 0)
+  for(int i=0; i < c->gcount; ++i)
+    if(c->gparts[i].id_or_neg_offset == ICHECK)
+      message("Found gpart");
+#endif
+
+
   /* Anything to do here? */
   if (!cell_is_active(c, e)) return;
 
@@ -1476,14 +1484,15 @@ void runner_do_end_force(struct runner *r, struct cell *c, int timer) {
 
           /* Check that this gpart has interacted with all the other
            * particles (via direct or multipoles) in the box */
-          if (gp->num_interacted != (long long)e->total_nr_gparts)
+          if (gp->num_interacted != e->total_nr_gparts && gp->id_or_neg_offset == ICHECK)
             error(
                 "g-particle (id=%lld, type=%s) did not interact "
                 "gravitationally "
                 "with all other gparts gp->num_interacted=%lld, "
-                "total_gparts=%zd",
+                "total_gparts=%zd (local num_gparts=%zd)",
                 gp->id_or_neg_offset, part_type_names[gp->type],
-                gp->num_interacted, e->total_nr_gparts);
+                gp->num_interacted, e->total_nr_gparts,
+	  	e->s->nr_gparts);
         }
 #endif
       }
diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h
index 8ff90412cc..89d7231d8a 100644
--- a/src/runner_doiact_grav.h
+++ b/src/runner_doiact_grav.h
@@ -43,6 +43,13 @@ void runner_do_grav_down(struct runner *r, struct cell *c, int timer) {
   struct gpart *gparts = c->gparts;
   const int gcount = c->gcount;
 
+#if (ICHECK != 0)
+  for(int i=0; i < c->gcount; ++i)
+    if(c->gparts[i].id_or_neg_offset == ICHECK)
+      message("Found gpart depth=%d split=%d m->num_interacted=%lld", 
+	      c->depth, c->split, c->multipole->pot.num_interacted);
+#endif
+
   TIMER_TIC;
 
 #ifdef SWIFT_DEBUG_CHECKS
@@ -1136,20 +1143,40 @@ void runner_do_grav_long_range(struct runner *r, struct cell *ci, int timer) {
   const struct gravity_props *props = e->gravity_properties;
   const int periodic = s->periodic;
   const double cell_width = s->width[0];
+  const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]};
   const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
   const double theta_crit2 = props->theta_crit2;
   const double max_distance = props->a_smooth * props->r_cut_max * cell_width;
   const double max_distance2 = max_distance * max_distance;
 
+#if (ICHECK != 0)
+  int check = 0;
+  int direct_ngbs = 0;
+  int direct_ngbs_gpart = 0;
+  int other_ngbs_gpart = 0;
+  for(int i=0; i < ci->gcount; ++i)
+    if(ci->gparts[i].id_or_neg_offset == ICHECK) {
+      message("Found gpart");
+      check = 1;
+    }
+#endif
+
+#ifdef SWIFT_DEBUG_CHECKS
+  long long counter = 0;
+#endif
+
   TIMER_TIC;
 
   /* Recover the list of top-level cells */
-  struct cell *cells = e->s->cells_top;
-  const int nr_cells = e->s->nr_cells;
+  struct cell *cells = s->cells_top;
+  const int nr_cells = s->nr_cells;
 
   /* Anything to do here? */
   if (!cell_is_active(ci, e)) return;
 
+  if (ci->nodeID != engine_rank)
+    error("Non-local cell in long-range gravity task!");
+  
   /* Check multipole has been drifted */
   if (ci->ti_old_multipole != e->ti_current)
     error("Interacting un-drifted multipole");
@@ -1157,38 +1184,74 @@ void runner_do_grav_long_range(struct runner *r, struct cell *ci, int timer) {
   /* Recover the local multipole */
   struct gravity_tensors *const multi_i = ci->multipole;
   const double CoM_i[3] = {multi_i->CoM[0], multi_i->CoM[1], multi_i->CoM[2]};
-  const double CoM_rebuild_i[3] = {multi_i->CoM_rebuild[0],
-                                   multi_i->CoM_rebuild[1],
-                                   multi_i->CoM_rebuild[2]};
+  /* const double CoM_rebuild_i[3] = {multi_i->CoM_rebuild[0], */
+  /*                                  multi_i->CoM_rebuild[1], */
+  /*                                  multi_i->CoM_rebuild[2]}; */
+
+  /* Get the cell index. MATTHIEU */
+  const int cid = (ci - cells);// / sizeof(struct cell);
+  const int i = cid / (cdim[1] * cdim[2]);
+  const int j = (cid / cdim[2]) % cdim[1];
+  const int k = cid % cdim[2];
 
   /* Loop over all the top-level cells and go for a M-M interaction if
    * well-separated */
-  for (int i = 0; i < nr_cells; ++i) {
+  for (int n = 0; n < nr_cells; ++n) {
 
     /* Handle on the top-level cell and it's gravity business*/
-    struct cell *cj = &cells[i];
+    struct cell *cj = &cells[n];
     const struct gravity_tensors *const multi_j = cj->multipole;
 
-    /* Avoid stupid cases */
-    if (ci == cj || cj->gcount == 0) continue;
+    /* Avoid self contributions */
+    if (ci == cj) continue;
 
-    /* Get the distance between the CoMs at the last rebuild*/
-    double dx_r = CoM_rebuild_i[0] - multi_j->CoM_rebuild[0];
-    double dy_r = CoM_rebuild_i[1] - multi_j->CoM_rebuild[1];
-    double dz_r = CoM_rebuild_i[2] - multi_j->CoM_rebuild[2];
+#ifdef SWIFT_DEBUG_CHECKS
+    counter += multi_j->m_pole.num_gpart;
+#endif
 
-    /* Apply BC */
-    if (periodic) {
-      dx_r = nearest(dx_r, dim[0]);
-      dy_r = nearest(dy_r, dim[1]);
-      dz_r = nearest(dz_r, dim[2]);
-    }
-    const double r2_rebuild = dx_r * dx_r + dy_r * dy_r + dz_r * dz_r;
+    // MATTHIEU
+    const int cjd = (cj - cells);// / sizeof(struct cell);
+    const int ii = cjd / (cdim[1] * cdim[2]);
+    const int jj = (cjd / cdim[2]) % cdim[1];
+    const int kk = cjd % cdim[2];
+    /* if(check) message("cid=%d cjd=%d cj->nodeID=%d cj->gcount=%d",  */
+    /* 		      cid, cjd, cj->nodeID, cj->gcount); */
+
+    /* /\* Get the distance between the CoMs at the last rebuild*\/ */
+    /* double dx_r = CoM_rebuild_i[0] - multi_j->CoM_rebuild[0]; */
+    /* double dy_r = CoM_rebuild_i[1] - multi_j->CoM_rebuild[1]; */
+    /* double dz_r = CoM_rebuild_i[2] - multi_j->CoM_rebuild[2]; */
+
+    /* /\* Apply BC *\/ */
+    /* if (periodic) { */
+    /*   dx_r = nearest(dx_r, dim[0]); */
+    /*   dy_r = nearest(dy_r, dim[1]); */
+    /*   dz_r = nearest(dz_r, dim[2]); */
+    /* } */
+    /* const double r2_rebuild = dx_r * dx_r + dy_r * dy_r + dz_r * dz_r; */
+
+    /* Are we in charge of this cell pair? MATTHIEU*/
+    /* if (gravity_M2L_accept(multi_i->r_max_rebuild, multi_j->r_max_rebuild, */
+    /*                        theta_crit2, r2_rebuild)) { */
+    if((abs(i-ii) <= 1 || abs(i-ii - cdim[0]) <= 1) && 
+       (abs(j-jj) <= 1 || abs(j-jj - cdim[1]) <= 1) && 
+       (abs(k-kk) <= 1)|| abs(k-kk - cdim[2]) <= 1) {
+
+#if (ICHECK != 0)
+      if(check) {
+	++direct_ngbs;
+	direct_ngbs_gpart += cj->multipole->m_pole.num_gpart;
+	message("Found direct neighbour %d: (i,j,k)=(%d,%d,%d) (ii,jj,kk)=(%d,%d,%d) nodeID=%d",
+		direct_ngbs, i,j,k, ii,jj,kk, cj->nodeID);
+      }
+#endif
+      
 
-    /* Are we in charge of this cell pair? */
-    if (gravity_M2L_accept(multi_i->r_max_rebuild, multi_j->r_max_rebuild,
-                           theta_crit2, r2_rebuild)) {
+    }else{
 
+      if(check)
+	other_ngbs_gpart += cj->multipole->m_pole.num_gpart;
+      
       /* Let's compute the current distance between the cell pair*/
       double dx = CoM_i[0] - multi_j->CoM[0];
       double dy = CoM_i[1] - multi_j->CoM[1];
@@ -1225,6 +1288,18 @@ void runner_do_grav_long_range(struct runner *r, struct cell *ci, int timer) {
     } /* We are in charge of this pair */
   }   /* Loop over top-level cells */
 
+
+  if(check)
+    message("Interacted with %d indirectly and ignored %d direct interactions (counter=%lld) nr_cells=%d",
+	    other_ngbs_gpart, direct_ngbs_gpart, counter, nr_cells);
+	    
+
+#ifdef SWIFT_DEBUG_CHECKS
+  counter += ci->multipole->m_pole.num_gpart;
+  if(counter != e->total_nr_gparts)
+    error("Not found the right number of particles in top-level interactions");
+#endif
+
   if (timer) TIMER_TOC(timer_dograv_long_range);
 }
 
-- 
GitLab