From c3b6422320f5aff96d53ffc99661cd2bb1ff2c65 Mon Sep 17 00:00:00 2001
From: Matthieu Schaller <schaller@strw.leidenuniv.nl>
Date: Fri, 31 Aug 2018 17:17:11 +0200
Subject: [PATCH] First version of a symmetric M2L kernel. Benchmark with vTune
 needed now.

---
 src/gravity/Default/gravity_iact.h   |   4 +-
 src/gravity/Potential/gravity_iact.h |   4 +-
 src/gravity_derivatives.h            |  35 ++++++-
 src/multipole.h                      | 141 ++++++++++++++++++---------
 src/runner_doiact_grav.h             |  76 +++++++++++++--
 5 files changed, 203 insertions(+), 57 deletions(-)

diff --git a/src/gravity/Default/gravity_iact.h b/src/gravity/Default/gravity_iact.h
index 71e5007a49..6fce3ddd51 100644
--- a/src/gravity/Default/gravity_iact.h
+++ b/src/gravity/Default/gravity_iact.h
@@ -166,7 +166,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_grav_pm_full(
 
   /* Compute the derivatives of the potential */
   struct potential_derivatives_M2P d;
-  compute_potential_derivatives_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 0, 0.f,
+  potential_derivatives_compute_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 0, 0.f,
                                     &d);
 
   /* 0th order contributions */
@@ -271,7 +271,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_grav_pm_truncated(
 
   /* Compute the derivatives of the potential */
   struct potential_derivatives_M2P d;
-  compute_potential_derivatives_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 1,
+  potential_derivatives_compute_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 1,
                                     r_s_inv, &d);
 
   /* 0th order contributions */
diff --git a/src/gravity/Potential/gravity_iact.h b/src/gravity/Potential/gravity_iact.h
index fdc8c17da1..f2094f6ecd 100644
--- a/src/gravity/Potential/gravity_iact.h
+++ b/src/gravity/Potential/gravity_iact.h
@@ -169,7 +169,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_grav_pm_full(
 
   /* Compute the derivatives of the potential */
   struct potential_derivatives_M2P d;
-  compute_potential_derivatives_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 0, 0.f,
+  potential_derivatives_compute_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 0, 0.f,
                                     &d);
 
   /* 0th order contributions */
@@ -281,7 +281,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_grav_pm_truncated(
 
   /* Compute the derivatives of the potential */
   struct potential_derivatives_M2P d;
-  compute_potential_derivatives_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 1,
+  potential_derivatives_compute_M2P(r_x, r_y, r_z, r2, r_inv, h, h_inv, 1,
                                     r_s_inv, &d);
 
   /* 0th order contributions */
diff --git a/src/gravity_derivatives.h b/src/gravity_derivatives.h
index 756fb7af66..2516d29d17 100644
--- a/src/gravity_derivatives.h
+++ b/src/gravity_derivatives.h
@@ -125,6 +125,37 @@ struct potential_derivatives_M2P {
 #endif
 };
 
+__attribute__((always_inline)) INLINE static void
+potential_derivatives_flip_signs(struct potential_derivatives_M2L *pot) {
+
+#if SELF_GRAVITY_MULTIPOLE_ORDER > 0
+  /* 1st order terms */
+  pot->D_100 = -pot->D_100;
+  pot->D_010 = -pot->D_010;
+  pot->D_001 = -pot->D_001;
+#endif
+
+#if SELF_GRAVITY_MULTIPOLE_ORDER > 2
+  /* 3rd order terms */
+  pot->D_300 = -pot->D_300;
+  pot->D_030 = -pot->D_030;
+  pot->D_003 = -pot->D_003;
+  pot->D_210 = -pot->D_210;
+  pot->D_201 = -pot->D_201;
+  pot->D_021 = -pot->D_021;
+  pot->D_120 = -pot->D_120;
+  pot->D_012 = -pot->D_012;
+  pot->D_102 = -pot->D_102;
+  pot->D_111 = -pot->D_111;
+#endif
+
+#if SELF_GRAVITY_MULTIPOLE_ORDER > 4
+  //MATTHIEU
+  error("oo");
+#endif
+  
+}
+
 /**
  * @brief Compute all the relevent derivatives of the softened and truncated
  * gravitational potential for the M2L kernel.
@@ -141,7 +172,7 @@ struct potential_derivatives_M2P {
  * @param pot (return) The structure containing all the derivatives.
  */
 __attribute__((always_inline)) INLINE static void
-compute_potential_derivatives_M2L(const float r_x, const float r_y,
+potential_derivatives_compute_M2L(const float r_x, const float r_y,
                                   const float r_z, const float r2,
                                   const float r_inv, const float eps,
                                   const float eps_inv, const int periodic,
@@ -397,7 +428,7 @@ compute_potential_derivatives_M2L(const float r_x, const float r_y,
  * @param pot (return) The structure containing all the derivatives.
  */
 __attribute__((always_inline)) INLINE static void
-compute_potential_derivatives_M2P(const float r_x, const float r_y,
+potential_derivatives_compute_M2P(const float r_x, const float r_y,
                                   const float r_z, const float r2,
                                   const float r_inv, const float eps,
                                   const float eps_inv, const int periodic,
diff --git a/src/multipole.h b/src/multipole.h
index c3d5d84252..994131dbe8 100644
--- a/src/multipole.h
+++ b/src/multipole.h
@@ -1551,51 +1551,11 @@ INLINE static void gravity_M2M(struct multipole *m_a,
 #endif
 }
 
-/**
- * @brief Compute the field tensors due to a multipole.
- *
- * Corresponds to equation (28b).
- *
- * @param l_b The field tensor to compute.
- * @param m_a The multipole creating the field.
- * @param pos_b The position of the field tensor.
- * @param pos_a The position of the multipole.
- * @param props The #gravity_props of this calculation.
- * @param periodic Is the calculation periodic ?
- * @param dim The size of the simulation box.
- * @param rs_inv The inverse of the gravity mesh-smoothing scale.
- */
-INLINE static void gravity_M2L(struct grav_tensor *l_b,
-                               const struct multipole *m_a,
-                               const double pos_b[3], const double pos_a[3],
-                               const struct gravity_props *props, int periodic,
-                               const double dim[3], float rs_inv) {
-
-  /* Recover some constants */
-  const float eps = props->epsilon_cur;
-  const float eps_inv = props->epsilon_cur_inv;
-
-  /* Compute distance vector */
-  float dx = (float)(pos_b[0] - pos_a[0]);
-  float dy = (float)(pos_b[1] - pos_a[1]);
-  float dz = (float)(pos_b[2] - pos_a[2]);
-
-  /* Apply BC */
-  if (periodic) {
-    dx = nearest(dx, dim[0]);
-    dy = nearest(dy, dim[1]);
-    dz = nearest(dz, dim[2]);
-  }
-
-  /* Compute distance */
-  const float r2 = dx * dx + dy * dy + dz * dz;
-  const float r_inv = 1. / sqrtf(r2);
-
-  /* Compute all derivatives */
-  struct potential_derivatives_M2L pot;
-  compute_potential_derivatives_M2L(dx, dy, dz, r2, r_inv, eps, eps_inv,
-                                    periodic, rs_inv, &pot);
+INLINE static void gravity_M2L_apply(struct grav_tensor *l_b,
+				     const struct multipole *m_a,
+				     struct potential_derivatives_M2L pot){
 
+  
 #ifdef SWIFT_DEBUG_CHECKS
   /* Count interactions */
   l_b->num_interacted += m_a->num_gpart;
@@ -1926,6 +1886,99 @@ INLINE static void gravity_M2L(struct grav_tensor *l_b,
 #endif
 }
 
+/**
+ * @brief Compute the field tensors due to a multipole.
+ *
+ * Corresponds to equation (28b).
+ *
+ * @param l_b The field tensor to compute.
+ * @param m_a The multipole creating the field.
+ * @param pos_b The position of the field tensor.
+ * @param pos_a The position of the multipole.
+ * @param props The #gravity_props of this calculation.
+ * @param periodic Is the calculation periodic ?
+ * @param dim The size of the simulation box.
+ * @param rs_inv The inverse of the gravity mesh-smoothing scale.
+ */
+INLINE static void gravity_M2L_nonsym(struct grav_tensor *l_b,
+				      const struct multipole *m_a,
+				      const double pos_b[3], const double pos_a[3],
+				      const struct gravity_props *props, int periodic,
+				      const double dim[3], float rs_inv) {
+
+  /* Recover some constants */
+  const float eps = props->epsilon_cur;
+  const float eps_inv = props->epsilon_cur_inv;
+
+  /* Compute distance vector */
+  float dx = (float)(pos_b[0] - pos_a[0]);
+  float dy = (float)(pos_b[1] - pos_a[1]);
+  float dz = (float)(pos_b[2] - pos_a[2]);
+
+  /* Apply BC */
+  if (periodic) {
+    dx = nearest(dx, dim[0]);
+    dy = nearest(dy, dim[1]);
+    dz = nearest(dz, dim[2]);
+  }
+
+  /* Compute distance */
+  const float r2 = dx * dx + dy * dy + dz * dz;
+  const float r_inv = 1. / sqrtf(r2);
+
+  /* Compute all derivatives */
+  struct potential_derivatives_M2L pot;
+  potential_derivatives_compute_M2L(dx, dy, dz, r2, r_inv, eps, eps_inv,
+                                    periodic, rs_inv, &pot);
+
+  /* Do the M2L tensor multiplication */
+  gravity_M2L_apply(l_b, m_a, pot);
+}
+
+
+INLINE static void gravity_M2L_symmetric(struct grav_tensor *l_a,
+					 struct grav_tensor *l_b,
+					 const struct multipole *m_a,
+					 const struct multipole *m_b,
+					 const double pos_b[3], const double pos_a[3],
+					 const struct gravity_props *props, int periodic,
+					 const double dim[3], float rs_inv) {
+
+  /* Recover some constants */
+  const float eps = props->epsilon_cur;
+  const float eps_inv = props->epsilon_cur_inv;
+
+  /* Compute distance vector */
+  float dx = (float)(pos_b[0] - pos_a[0]);
+  float dy = (float)(pos_b[1] - pos_a[1]);
+  float dz = (float)(pos_b[2] - pos_a[2]);
+
+  /* Apply BC */
+  if (periodic) {
+    dx = nearest(dx, dim[0]);
+    dy = nearest(dy, dim[1]);
+    dz = nearest(dz, dim[2]);
+  }
+
+  /* Compute distance */
+  const float r2 = dx * dx + dy * dy + dz * dz;
+  const float r_inv = 1. / sqrtf(r2);
+
+  /* Compute all derivatives */
+  struct potential_derivatives_M2L pot;
+  potential_derivatives_compute_M2L(dx, dy, dz, r2, r_inv, eps, eps_inv,
+                                    periodic, rs_inv, &pot);
+
+  /* Do the first M2L tensor multiplication */
+  gravity_M2L_apply(l_b, m_a, pot);
+
+  /* Flip the signs */
+  potential_derivatives_flip_signs(&pot);
+  
+  /* Do the first M2L tensor multiplication */
+  gravity_M2L_apply(l_a, m_b, pot);
+}
+
 /**
  * @brief Creates a copy of #grav_tensor shifted to a new location.
  *
diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h
index a4bc0509ce..bc45000965 100644
--- a/src/runner_doiact_grav.h
+++ b/src/runner_doiact_grav.h
@@ -642,8 +642,8 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci,
   TIMER_TIC;
 
   /* Record activity status */
-  const int ci_active = cell_is_active_gravity(ci, e);
-  const int cj_active = cell_is_active_gravity(cj, e);
+  const int ci_active = cell_is_active_gravity(ci, e) && (ci->nodeID == e->nodeID);
+  const int cj_active = cell_is_active_gravity(cj, e) && (cj->nodeID == e->nodeID);
 
   /* Anything to do here? */
   if (!ci_active && !cj_active) return;
@@ -1122,9 +1122,71 @@ static INLINE void runner_doself_grav_pp(struct runner *r, struct cell *c) {
   TIMER_TOC(timer_doself_grav_pp);
 }
 
+/**
+ * @brief Computes the interaction of the field tensor and multipole
+ * of two cells symmetrically.
+ *
+ * @param r The #runner.
+ * @param ci The first #cell.
+ * @param cj The second #cell.
+ */
 static INLINE void runner_dopair_grav_mm_symmetric(struct runner *r,
 						   struct cell *restrict ci,
 						   struct cell *restrict cj) {
+
+  /* Some constants */
+  const struct engine *e = r->e;
+  const struct gravity_props *props = e->gravity_properties;
+  const int periodic = e->mesh->periodic;
+  const double dim[3] = {e->mesh->dim[0], e->mesh->dim[1], e->mesh->dim[2]};
+  const float r_s_inv = e->mesh->r_s_inv;
+
+  TIMER_TIC;
+
+  /* Anything to do here? */
+  if ((!cell_is_active_gravity_mm(ci, e) || ci->nodeID != engine_rank) ||
+      (!cell_is_active_gravity_mm(cj, e) || cj->nodeID != engine_rank))
+    error("Invalid state in symmetric M-M calculation!");
+
+  /* Short-cut to the multipole */
+  const struct multipole *multi_i = &ci->multipole->m_pole;
+  const struct multipole *multi_j = &cj->multipole->m_pole;
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (ci == cj) error("Interacting a cell with itself using M2L");
+
+  if (multi_i->num_gpart == 0)
+    error("Multipole i does not seem to have been set.");
+
+  if (multi_j->num_gpart == 0)
+    error("Multipole j does not seem to have been set.");
+  
+  if (ci->multipole->pot.ti_init != e->ti_current)
+    error("ci->grav tensor not initialised.");
+
+  if (ci->multipole->pot.ti_init != e->ti_current)
+    error("cj->grav tensor not initialised.");
+
+  if (ci->ti_old_multipole != e->ti_current)
+    error(
+        "Undrifted multipole ci->ti_old_multipole=%lld ci->nodeID=%d "
+        "cj->nodeID=%d e->ti_current=%lld",
+        ci->ti_old_multipole, ci->nodeID, cj->nodeID, e->ti_current);
+
+  if (cj->ti_old_multipole != e->ti_current)
+    error(
+        "Undrifted multipole cj->ti_old_multipole=%lld cj->nodeID=%d "
+        "ci->nodeID=%d e->ti_current=%lld",
+        cj->ti_old_multipole, cj->nodeID, ci->nodeID, e->ti_current);
+#endif
+
+  
+  /* Let's interact at this level */
+  gravity_M2L_symmetric(&ci->multipole->pot, &cj->multipole->pot, multi_i, multi_j, ci->multipole->CoM,
+			cj->multipole->CoM, props, periodic, dim, r_s_inv);
+  
+
+  TIMER_TOC(timer_dopair_grav_mm);  
 }
 
 /**
@@ -1171,8 +1233,8 @@ static INLINE void runner_dopair_grav_mm_nonsym(struct runner *r,
 #endif
 
   /* Let's interact at this level */
-  gravity_M2L(&ci->multipole->pot, multi_j, ci->multipole->CoM,
-              cj->multipole->CoM, props, periodic, dim, r_s_inv);
+  gravity_M2L_nonsym(&ci->multipole->pot, multi_j, ci->multipole->CoM,
+		     cj->multipole->CoM, props, periodic, dim, r_s_inv);
 
   TIMER_TOC(timer_dopair_grav_mm);
 }
@@ -1185,8 +1247,8 @@ static INLINE void runner_dopair_grav_mm_nonsym(struct runner *r,
  * @param cj The second #cell.
  */
 static INLINE void runner_dopair_grav_mm(struct runner *r,
-                                                   struct cell *ci,
-                                                   struct cell *cj) {
+					 struct cell *ci,
+					 struct cell *cj) {
 
   const struct engine *e = r->e;
 
@@ -1593,7 +1655,7 @@ static INLINE void runner_do_grav_long_range(struct runner *r, struct cell *ci,
                            theta_crit2, r2_rebuild)) {
 
       /* Call the PM interaction fucntion on the active sub-cells of ci */
-      runner_dopair_grav_mm(r, ci, cj);
+      runner_dopair_grav_mm_nonsym(r, ci, cj);
       // runner_dopair_recursive_grav_pm(r, ci, cj);
 
       /* Record that this multipole received a contribution */
-- 
GitLab