From 2f5068ee203f4a1c82a99393c8cf8932b3afbe18 Mon Sep 17 00:00:00 2001
From: Matthieu Schaller <matthieu.schaller@durham.ac.uk>
Date: Mon, 25 Jul 2016 22:15:12 +0100
Subject: [PATCH] test_125 now  checks all particles against the similar
 brute-force call

---
 src/hydro/Gadget2/hydro_part.h            |  52 +--
 src/tools.c                               | 100 +++++
 src/tools.h                               |   2 +
 tests/difffloat.py                        |   1 +
 tests/test125cells.c                      | 421 ++++++++++++++++------
 tests/test125cells.sh.in                  |  17 +-
 tests/test27cells.c                       |  18 +-
 tests/test27cells.sh.in                   |  11 +-
 tests/test27cellsPerturbed.sh.in          |   4 +-
 tests/testPair.sh.in                      |   2 +-
 tests/testPairPerturbed.sh.in             |   2 +-
 tests/tolerance_125.dat                   |   3 +
 tests/{tolerance.dat => tolerance_27.dat} |   0
 tests/tolerance_pair.dat                  |   3 +
 14 files changed, 471 insertions(+), 165 deletions(-)
 create mode 100644 tests/tolerance_125.dat
 rename tests/{tolerance.dat => tolerance_27.dat} (100%)
 create mode 100644 tests/tolerance_pair.dat

diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h
index b2e5e53094..afca176400 100644
--- a/src/hydro/Gadget2/hydro_part.h
+++ b/src/hydro/Gadget2/hydro_part.h
@@ -61,46 +61,46 @@ struct part {
   /* Derivative of the density with respect to smoothing length. */
   float rho_dh;
 
-  // union {
+  union {
 
-  struct {
+    struct {
 
-    /* Number of neighbours. */
-    float wcount;
+      /* Number of neighbours. */
+      float wcount;
 
-    /* Number of neighbours spatial derivative. */
-    float wcount_dh;
+      /* Number of neighbours spatial derivative. */
+      float wcount_dh;
 
-    /* Particle velocity curl. */
-    float rot_v[3];
+      /* Particle velocity curl. */
+      float rot_v[3];
 
-    /* Particle velocity divergence. */
-    float div_v;
+      /* Particle velocity divergence. */
+      float div_v;
 
-  } density;
+    } density;
 
-  struct {
+    struct {
 
-    /* Balsara switch */
-    float balsara;
+      /* Balsara switch */
+      float balsara;
 
-    /* Pressure over density squared (including drho/dh term) */
-    float P_over_rho2;
+      /* Pressure over density squared (including drho/dh term) */
+      float P_over_rho2;
 
-    /* Particle sound speed. */
-    float soundspeed;
+      /* Particle sound speed. */
+      float soundspeed;
 
-    /* Signal velocity. */
-    float v_sig;
+      /* Signal velocity. */
+      float v_sig;
 
-    /* Entropy time derivative */
-    float entropy_dt;
+      /* Entropy time derivative */
+      float entropy_dt;
 
-    /* Time derivative of the smoothing length */
-    float h_dt;
+      /* Time derivative of the smoothing length */
+      float h_dt;
 
-  } force;
-  //  };
+    } force;
+  };
 
   /* Particle ID. */
   long long id;
diff --git a/src/tools.c b/src/tools.c
index 710efd7e4d..50ad48af38 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -240,6 +240,70 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) {
   }
 }
 
+void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) {
+
+  float r2, hi, hj, hig2, hjg2, dx[3];
+  struct part *pi, *pj;
+
+  /* Implements a double-for loop and checks every interaction */
+  for (int i = 0; i < ci->count; ++i) {
+
+    pi = &ci->parts[i];
+    hi = pi->h;
+    hig2 = hi * hi * kernel_gamma2;
+
+    for (int j = 0; j < cj->count; ++j) {
+
+      pj = &cj->parts[j];
+      hj = pj->h;
+      hjg2 = hj * hj * kernel_gamma2;
+
+      /* Pairwise distance */
+      r2 = 0.0f;
+      for (int k = 0; k < 3; k++) {
+        dx[k] = ci->parts[i].x[k] - cj->parts[j].x[k];
+        r2 += dx[k] * dx[k];
+      }
+
+      /* Hit or miss? */
+      if (r2 < hig2 || r2 < hjg2) {
+
+        /* Interact */
+        runner_iact_nonsym_force(r2, dx, hi, hj, pi, pj);
+      }
+    }
+  }
+
+  /* Reverse double-for loop and checks every interaction */
+  for (int j = 0; j < cj->count; ++j) {
+
+    pj = &cj->parts[j];
+    hj = pj->h;
+    hjg2 = hj * hj * kernel_gamma2;
+
+    for (int i = 0; i < ci->count; ++i) {
+
+      pi = &ci->parts[i];
+      hi = pi->h;
+      hig2 = hi * hi * kernel_gamma2;
+
+      /* Pairwise distance */
+      r2 = 0.0f;
+      for (int k = 0; k < 3; k++) {
+        dx[k] = cj->parts[j].x[k] - ci->parts[i].x[k];
+        r2 += dx[k] * dx[k];
+      }
+
+      /* Hit or miss? */
+      if (r2 < hjg2 || r2 < hig2) {
+
+        /* Interact */
+        runner_iact_nonsym_force(r2, dx, hj, pi->h, pj, pi);
+      }
+    }
+  }
+}
+
 void self_all_density(struct runner *r, struct cell *ci) {
   float r2, hi, hj, hig2, hjg2, dxi[3];  //, dxj[3];
   struct part *pi, *pj;
@@ -287,6 +351,42 @@ void self_all_density(struct runner *r, struct cell *ci) {
   }
 }
 
+void self_all_force(struct runner *r, struct cell *ci) {
+  float r2, hi, hj, hig2, hjg2, dxi[3];  //, dxj[3];
+  struct part *pi, *pj;
+
+  /* Implements a double-for loop and checks every interaction */
+  for (int i = 0; i < ci->count; ++i) {
+
+    pi = &ci->parts[i];
+    hi = pi->h;
+    hig2 = hi * hi * kernel_gamma2;
+
+    for (int j = i + 1; j < ci->count; ++j) {
+
+      pj = &ci->parts[j];
+      hj = pj->h;
+      hjg2 = hj * hj * kernel_gamma2;
+
+      if (pi == pj) continue;
+
+      /* Pairwise distance */
+      r2 = 0.0f;
+      for (int k = 0; k < 3; k++) {
+        dxi[k] = ci->parts[i].x[k] - ci->parts[j].x[k];
+        r2 += dxi[k] * dxi[k];
+      }
+
+      /* Hit or miss? */
+      if (r2 < hig2 || r2 < hjg2) {
+
+        /* Interact */
+        runner_iact_force(r2, dxi, hi, hj, pi, pj);
+      }
+    }
+  }
+}
+
 void pairs_single_grav(double *dim, long long int pid,
                        struct gpart *restrict gparts, const struct part *parts,
                        int N, int periodic) {
diff --git a/src/tools.h b/src/tools.h
index 97f036994b..ba5b2f8c7f 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -40,6 +40,8 @@ void pairs_single_density(double *dim, long long int pid,
 
 void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj);
 void self_all_density(struct runner *r, struct cell *ci);
+void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj);
+void self_all_force(struct runner *r, struct cell *ci);
 
 void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic);
 
diff --git a/tests/difffloat.py b/tests/difffloat.py
index d4b48d54cb..7b0a27f668 100644
--- a/tests/difffloat.py
+++ b/tests/difffloat.py
@@ -89,6 +89,7 @@ for i in range(n_lines_to_check):
         abs_diff = abs(data1[i,j] - data2[i,j])
 
         sum = abs(data1[i,j] + data2[i,j])
+        if sum < 1e8: continue
         if sum > 0:
             rel_diff = abs(data1[i,j] - data2[i,j]) / sum
         else:
diff --git a/tests/test125cells.c b/tests/test125cells.c
index bb59df5a8e..3d96c6d370 100644
--- a/tests/test125cells.c
+++ b/tests/test125cells.c
@@ -30,6 +30,153 @@
 /* Local headers. */
 #include "swift.h"
 
+enum velocity_field {
+  velocity_zero,
+  velocity_const,
+  velocity_divergent,
+  velocity_rotating
+};
+
+enum pressure_field { pressure_const, pressure_gradient, pressure_divergent };
+
+void set_velocity(struct part *part, enum velocity_field vel, float size) {
+
+  switch (vel) {
+    case velocity_zero:
+      part->v[0] = 0.f;
+      part->v[1] = 0.f;
+      part->v[2] = 0.f;
+      break;
+    case velocity_const:
+      part->v[0] = 1.f;
+      part->v[1] = 0.f;
+      part->v[2] = 0.f;
+      break;
+    case velocity_divergent:
+      part->v[0] = part->x[0] - 2.5 * size;
+      part->v[1] = part->x[1] - 2.5 * size;
+      part->v[2] = part->x[2] - 2.5 * size;
+      break;
+    case velocity_rotating:
+      part->v[0] = part->x[1];
+      part->v[1] = -part->x[0];
+      part->v[2] = 0.f;
+      break;
+  }
+}
+
+float get_pressure(double x[3], enum pressure_field press, float size) {
+
+  float r2 = 0.;
+  float dx[3] = {0.f};
+
+  switch (press) {
+    case pressure_const:
+      return 1.5f;
+      break;
+    case pressure_gradient:
+      return 1.5f * x[0]; /* gradient along x */
+      break;
+    case pressure_divergent:
+      dx[0] = x[0] - 2.5 * size;
+      dx[1] = x[1] - 2.5 * size;
+      dx[2] = x[2] - 2.5 * size;
+      r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
+      return sqrt(r2) + 1.5f;
+      break;
+  }
+  return 0.f;
+}
+
+void set_energy_state(struct part *part, enum pressure_field press, float size,
+                      float density) {
+
+  const float pressure = get_pressure(part->x, press, size);
+
+#if defined(GADGET2_SPH)
+  part->entropy = pressure / pow_gamma(density);
+#else
+  error("Need to define pressure here !");
+#endif
+}
+
+struct solution_part {
+
+  long long id;
+  double x[3];
+  float v[3];
+  float a_hydro[3];
+  float h;
+  float rho;
+  float div_v;
+  float S;
+  float u;
+  float P;
+  float c;
+  float h_dt;
+  float v_sig;
+  float S_dt;
+  float u_dt;
+};
+
+void get_solution(const struct cell *main_cell, struct solution_part *solution,
+                  float density, enum velocity_field vel,
+                  enum pressure_field press, float size) {
+
+  for (size_t i = 0; i < main_cell->count; ++i) {
+
+    solution[i].id = main_cell->parts[i].id;
+
+    solution[i].x[0] = main_cell->parts[i].x[0];
+    solution[i].x[1] = main_cell->parts[i].x[1];
+    solution[i].x[2] = main_cell->parts[i].x[2];
+
+    solution[i].v[0] = main_cell->parts[i].v[0];
+    solution[i].v[1] = main_cell->parts[i].v[1];
+    solution[i].v[2] = main_cell->parts[i].v[2];
+
+    solution[i].h = main_cell->parts[i].h;
+
+    solution[i].rho = density;
+
+    solution[i].P = get_pressure(solution[i].x, press, size);
+    solution[i].u = solution[i].P / (solution[i].rho * hydro_gamma_minus_one);
+    solution[i].S = solution[i].P / pow_gamma(solution[i].rho);
+    solution[i].c = sqrt(hydro_gamma * solution[i].P / solution[i].rho);
+
+    if (vel == velocity_divergent)
+      solution[i].div_v = 3.f;
+    else
+      solution[i].div_v = 0.f;
+
+    solution[i].h_dt = solution[i].h * solution[i].div_v / 3.;
+
+    float gradP[3] = {0.f};
+    if (press == pressure_gradient) {
+      gradP[0] = 1.5f;
+      gradP[1] = 0.f;
+      gradP[2] = 0.f;
+    } else if (press == pressure_divergent) {
+      float dx[3];
+      dx[0] = solution[i].x[0] - 2.5 * size;
+      dx[1] = solution[i].x[1] - 2.5 * size;
+      dx[2] = solution[i].x[2] - 2.5 * size;
+      float r = sqrt(dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]);
+      if (r > 0.) {
+        gradP[0] = dx[0] / r;
+        gradP[1] = dx[1] / r;
+        gradP[2] = dx[2] / r;
+      }
+    }
+
+    solution[i].a_hydro[0] = -gradP[0] / solution[i].rho;
+    solution[i].a_hydro[1] = -gradP[1] / solution[i].rho;
+    solution[i].a_hydro[2] = -gradP[2] / solution[i].rho;
+
+    solution[i].v_sig = 2.f * solution[i].c;
+  }
+}
+
 /**
  * @brief Constructs a cell and all of its particle in a valid state prior to
  * a SPH time-step.
@@ -41,11 +188,10 @@
  * separation.
  * @param density The density of the fluid.
  * @param partId The running counter of IDs.
- * @param pert The perturbation to apply to the particles in the cell in units
- * of the inter-particle separation.
  */
 struct cell *make_cell(size_t n, const double offset[3], double size, double h,
-                       double density, long long *partId, double pert) {
+                       double density, long long *partId,
+                       enum velocity_field vel, enum pressure_field press) {
 
   const size_t count = n * n * n;
   const double volume = size * size * size;
@@ -67,28 +213,24 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h,
   for (size_t x = 0; x < n; ++x) {
     for (size_t y = 0; y < n; ++y) {
       for (size_t z = 0; z < n; ++z) {
-        part->x[0] =
-            offset[0] +
-            size * (x + 0.5 + random_uniform(-0.5, 0.5) * pert) / (float)n;
-        part->x[1] =
-            offset[1] +
-            size * (y + 0.5 + random_uniform(-0.5, 0.5) * pert) / (float)n;
-        part->x[2] =
-            offset[2] +
-            size * (z + 0.5 + random_uniform(-0.5, 0.5) * pert) / (float)n;
-        part->v[0] = 0.f;
-        part->v[1] = 0.f;
-        part->v[2] = 0.f;
+        part->x[0] = offset[0] + size * (x + 0.5) / (float)n;
+        part->x[1] = offset[1] + size * (y + 0.5) / (float)n;
+        part->x[2] = offset[2] + size * (z + 0.5) / (float)n;
         part->h = size * h / (float)n;
-        part->entropy = 1.f;
-        part->id = ++(*partId);
         part->mass = density * volume / count;
+
+        set_velocity(part, vel, size);
+        set_energy_state(part, press, size, density);
+
+        part->id = ++(*partId);
         part->ti_begin = 0;
         part->ti_end = 1;
+
         xpart->v_full[0] = part->v[0];
         xpart->v_full[1] = part->v[1];
         xpart->v_full[2] = part->v[2];
         ++part;
+        ++xpart;
       }
     }
   }
@@ -129,78 +271,59 @@ void clean_up(struct cell *ci) {
  * @brief Dump all the particles to a file
  */
 void dump_particle_fields(char *fileName, struct cell *main_cell,
-                          struct cell **cells) {
+                          struct solution_part *solution, int with_solution) {
   FILE *file = fopen(fileName, "w");
 
   /* Write header */
   fprintf(file,
-          "# %4s %10s %10s %10s %10s %10s %10s %13s %13s %13s %13s %13s "
-          "%13s %13s %13s\n",
-          "ID", "pos_x", "pos_y", "pos_z", "v_x", "v_y", "v_z", "rho", "rho_dh",
-          "wcount", "wcount_dh", "div_v", "curl_vx", "curl_vy", "curl_vz");
+          "# %4s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s "
+          "%8s %8s %8s %8s %8s\n",
+          "ID", "pos_x", "pos_y", "pos_z", "v_x", "v_y", "v_z", "h", "rho",
+          "div_v", "S", "u", "P", "c", "a_x", "a_y", "a_z", "h_dt", "v_sig",
+          "dS/dt", "du/dt");
 
   fprintf(file, "# Main cell --------------------------------------------\n");
 
   /* Write main cell */
   for (size_t pid = 0; pid < main_cell->count; pid++) {
     fprintf(file,
-            "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e "
-            "%13e %13e %13e\n",
+            "%6llu %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f "
+            "%8.5f "
+            "%8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f\n",
             main_cell->parts[pid].id, main_cell->parts[pid].x[0],
             main_cell->parts[pid].x[1], main_cell->parts[pid].x[2],
             main_cell->parts[pid].v[0], main_cell->parts[pid].v[1],
-            main_cell->parts[pid].v[2], main_cell->parts[pid].rho,
-            main_cell->parts[pid].rho_dh, main_cell->parts[pid].density.wcount,
-            main_cell->parts[pid].density.wcount_dh,
-#if defined(GADGET2_SPH)
-            main_cell->parts[pid].div_v, main_cell->parts[pid].density.rot_v[0],
-            main_cell->parts[pid].density.rot_v[1],
-            main_cell->parts[pid].density.rot_v[2]
-#elif defined(DEFAULT_SPH)
-            main_cell->parts[pid].density.div_v,
-            main_cell->parts[pid].density.rot_v[0],
-            main_cell->parts[pid].density.rot_v[1],
-            main_cell->parts[pid].density.rot_v[2]
-#else
-            0., 0., 0., 0.
-#endif
-            );
+            main_cell->parts[pid].v[2], main_cell->parts[pid].h,
+            main_cell->parts[pid].rho, main_cell->parts[pid].density.div_v,
+            hydro_get_entropy(&main_cell->parts[pid], 0.f),
+            hydro_get_internal_energy(&main_cell->parts[pid], 0.f),
+            hydro_get_pressure(&main_cell->parts[pid], 0.f),
+            hydro_get_soundspeed(&main_cell->parts[pid], 0.f),
+            main_cell->parts[pid].a_hydro[0], main_cell->parts[pid].a_hydro[1],
+            main_cell->parts[pid].a_hydro[2], main_cell->parts[pid].force.h_dt,
+            main_cell->parts[pid].force.v_sig,
+            main_cell->parts[pid].force.entropy_dt, 0.f);
   }
 
-  /* Write all other cells */
-  for (int i = 0; i < 5; ++i) {
-    for (int j = 0; j < 5; ++j) {
-      for (int k = 0; k < 5; ++k) {
-        struct cell *cj = cells[i * 25 + j * 5 + k];
-        if (cj == main_cell) continue;
-
-        fprintf(file,
-                "# Offset: [%2d %2d %2d] -----------------------------------\n",
-                i - 2, j - 2, k - 2);
-
-        for (size_t pjd = 0; pjd < cj->count; pjd++) {
-          fprintf(
-              file,
-              "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e "
-              "%13e %13e %13e\n",
-              cj->parts[pjd].id, cj->parts[pjd].x[0], cj->parts[pjd].x[1],
-              cj->parts[pjd].x[2], cj->parts[pjd].v[0], cj->parts[pjd].v[1],
-              cj->parts[pjd].v[2], cj->parts[pjd].rho, cj->parts[pjd].rho_dh,
-              cj->parts[pjd].density.wcount, cj->parts[pjd].density.wcount_dh,
-#if defined(GADGET2_SPH)
-              cj->parts[pjd].div_v, cj->parts[pjd].density.rot_v[0],
-              cj->parts[pjd].density.rot_v[1], cj->parts[pjd].density.rot_v[2]
-#elif defined(DEFAULT_SPH)
-              cj->parts[pjd].density.div_v, cj->parts[pjd].density.rot_v[0],
-              cj->parts[pjd].density.rot_v[1], cj->parts[pjd].density.rot_v[2]
-#else
-              0., 0., 0., 0.
-#endif
-              );
-        }
-      }
+  if (with_solution) {
+
+    fprintf(file, "# Solution ---------------------------------------------\n");
+
+    for (size_t pid = 0; pid < main_cell->count; pid++) {
+      fprintf(file,
+              "%6llu %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f "
+              "%8.5f %8.5f "
+              "%8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f\n",
+              solution[pid].id, solution[pid].x[0], solution[pid].x[1],
+              solution[pid].x[2], solution[pid].v[0], solution[pid].v[1],
+              solution[pid].v[2], solution[pid].h, solution[pid].rho,
+              solution[pid].div_v, solution[pid].S, solution[pid].u,
+              solution[pid].P, solution[pid].c, solution[pid].a_hydro[0],
+              solution[pid].a_hydro[1], solution[pid].a_hydro[2],
+              solution[pid].h_dt, solution[pid].v_sig, solution[pid].S_dt, 0.f);
     }
   }
+
   fclose(file);
 }
 
@@ -214,10 +337,11 @@ void runner_doself2_force(struct runner *r, struct cell *ci);
 int main(int argc, char *argv[]) {
 
   size_t runs = 0, particles = 0;
-  double h = 1.2348, size = 1., rho = 1.;
-  double perturbation = 0.;
+  double h = 1.23485, size = 1., rho = 2.5;
   char outputFileNameExtension[200] = "";
   char outputFileName[200] = "";
+  enum velocity_field vel = velocity_zero;
+  enum pressure_field press = pressure_const;
 
   /* Initialize CPU frequency, this also starts time. */
   unsigned long long cpufreq = 0;
@@ -230,7 +354,7 @@ int main(int argc, char *argv[]) {
   srand(0);
 
   char c;
-  while ((c = getopt(argc, argv, "m:s:h:p:r:t:d:f:v:")) != -1) {
+  while ((c = getopt(argc, argv, "m:s:h:n:r:t:d:f:v:p:")) != -1) {
     switch (c) {
       case 'h':
         sscanf(optarg, "%lf", &h);
@@ -238,21 +362,24 @@ int main(int argc, char *argv[]) {
       case 's':
         sscanf(optarg, "%lf", &size);
         break;
-      case 'p':
+      case 'n':
         sscanf(optarg, "%zu", &particles);
         break;
       case 'r':
         sscanf(optarg, "%zu", &runs);
         break;
-      case 'd':
-        sscanf(optarg, "%lf", &perturbation);
-        break;
       case 'm':
         sscanf(optarg, "%lf", &rho);
         break;
       case 'f':
         strcpy(outputFileNameExtension, optarg);
         break;
+      case 'v':
+        sscanf(optarg, "%d", (int *)&vel);
+        break;
+      case 'p':
+        sscanf(optarg, "%d", (int *)&press);
+        break;
       case '?':
         error("Unknown option.");
         break;
@@ -261,28 +388,38 @@ int main(int argc, char *argv[]) {
 
   if (h < 0 || particles == 0 || runs == 0) {
     printf(
-        "\nUsage: %s -p PARTICLES_PER_AXIS -r NUMBER_OF_RUNS [OPTIONS...]\n"
-        "\nGenerates a cell pair, filled with particles on a Cartesian grid."
-        "\nThese are then interacted using runner_dopair1_density."
+        "\nUsage: %s -n PARTICLES_PER_AXIS -r NUMBER_OF_RUNS [OPTIONS...]\n"
+        "\nGenerates 125 cells, filled with particles on a Cartesian grid."
+        "\nThese are then interacted using runner_dopair1_density() and "
+        "runner_doself1_density() followed by runner_dopair2_force() and "
+        "runner_doself2_force()"
         "\n\nOptions:"
         "\n-h DISTANCE=1.2348 - Smoothing length in units of <x>"
         "\n-m rho             - Physical density in the cell"
         "\n-s size            - Physical size of the cell"
-        "\n-d pert            - Perturbation to apply to the particles [0,1["
+        "\n-v type (0,1,2,3)  - Velocity field: (zero, constant, divergent, "
         "rotating)"
+        "\n-p type (0,1,2)    - Pressure field: (constant, gradient divergent)"
         "\n-f fileName        - Part of the file name used to save the dumps\n",
         argv[0]);
     exit(1);
   }
 
   /* Help users... */
+  message("Adiabatic index: ga = %f", hydro_gamma);
   message("Smoothing length: h = %f", h * size);
   message("Kernel:               %s", kernel_name);
-  message("Neighbour target: N = %f",
-          h * h * h * 4.0 * M_PI * kernel_gamma3 / 3.0);
+  message("Neighbour target: N = %f", h * h * h * kernel_norm);
   message("Density target: rho = %f", rho);
-  // message("div_v target:   div = %f", vel == 2 ? 3.f : 0.f);
-  // message("curl_v target: curl = [0., 0., %f]", vel == 3 ? -2.f : 0.f);
+  message("div_v target:   div = %f", vel == 2 ? 3.f : 0.f);
+  message("curl_v target: curl = [0., 0., %f]", vel == 3 ? -2.f : 0.f);
+  if (press == pressure_const)
+    message("P field constant");
+  else if (press == pressure_gradient)
+    message("P field gradient");
+  else
+    message("P field divergent");
+
   printf("\n");
 
   /* Build the infrastructure */
@@ -291,10 +428,9 @@ int main(int argc, char *argv[]) {
   space.h_max = h;
 
   struct hydro_props hp;
-  hp.target_neighbours = h * h * h * 4.0 * M_PI * kernel_gamma3 / 3.0;
-  hp.delta_neighbours = 1;
-  hp.max_smoothing_iterations =
-      1; /* We construct correct h values, 1 is enough */
+  hp.target_neighbours = h * h * h * kernel_norm;
+  hp.delta_neighbours = 1.;
+  hp.max_smoothing_iterations = 1;
 
   struct engine engine;
   engine.hydro_properties = &hp;
@@ -320,7 +456,7 @@ int main(int argc, char *argv[]) {
 
         /* Construct it */
         cells[i * 25 + j * 5 + k] =
-            make_cell(particles, offset, size, h, rho, &partId, perturbation);
+            make_cell(particles, offset, size, h, rho, &partId, vel, press);
 
         /* Store the inner cells */
         if (i > 0 && i < 4 && j > 0 && j < 4 && k > 0 && k < 4) {
@@ -334,6 +470,12 @@ int main(int argc, char *argv[]) {
   /* Store the main cell for future use */
   main_cell = cells[62];
 
+  /* Construct the real solution */
+  struct solution_part *solution =
+      malloc(main_cell->count * sizeof(struct solution_part));
+  get_solution(main_cell, solution, rho, vel, press, size);
+
+  /* Start the test */
   ticks time = 0;
   for (size_t i = 0; i < runs; ++i) {
 
@@ -387,8 +529,6 @@ int main(int argc, char *argv[]) {
     /* Ghost to finish everything on the central cells */
     for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j]);
 
-    message("N_ngb = %f", main_cell->parts[0].density.wcount);
-
 /* Do the force calculation */
 #if defined(DEFAULT_SPH) || !defined(WITH_VECTORIZATION)
 
@@ -415,50 +555,97 @@ int main(int argc, char *argv[]) {
     time += toc - tic;
 
     /* Dump if necessary */
-    if (i % 50 == 0) {
+    if (i == 0) {
       sprintf(outputFileName, "swift_dopair_125_%s.dat",
               outputFileNameExtension);
-      dump_particle_fields(outputFileName, main_cell, cells);
+      dump_particle_fields(outputFileName, main_cell, solution, 0);
     }
   }
 
   /* Output timing */
   message("SWIFT calculation took       : %15lli ticks.", time / runs);
 
-  /* Now perform a brute-force version for accuracy tests */
+  /* NOW BRUTE-FORCE CALCULATION */
+
+  const ticks tic = getticks();
+
+  /* Initialise the particles */
+  for (int j = 0; j < 125; ++j) runner_do_init(&runner, cells[j], 0);
+
+/* Do the density calculation */
+#if defined(DEFAULT_SPH) || !defined(WITH_VECTORIZATION)
+
+  /* Run all the pairs (only once !)*/
+  for (int i = 0; i < 5; i++) {
+    for (int j = 0; j < 5; j++) {
+      for (int k = 0; k < 5; k++) {
+
+        struct cell *ci = cells[i * 25 + j * 5 + k];
+
+        for (int ii = -1; ii < 2; ii++) {
+          int iii = i + ii;
+          if (iii < 0 || iii >= 5) continue;
+          iii = (iii + 5) % 5;
+          for (int jj = -1; jj < 2; jj++) {
+            int jjj = j + jj;
+            if (jjj < 0 || jjj >= 5) continue;
+            jjj = (jjj + 5) % 5;
+            for (int kk = -1; kk < 2; kk++) {
+              int kkk = k + kk;
+              if (kkk < 0 || kkk >= 5) continue;
+              kkk = (kkk + 5) % 5;
+
+              struct cell *cj = cells[iii * 25 + jjj * 5 + kkk];
+
+              if (cj > ci) pairs_all_density(&runner, ci, cj);
+            }
+          }
+        }
+      }
+    }
+  }
 
-  /*   /\* Zero the fields *\/ */
-  /*   for (int i = 0; i < 125; ++i) zero_particle_fields(cells[i]); */
+  /* And now the self-interaction for the central cells*/
+  for (int j = 0; j < 27; ++j) self_all_density(&runner, inner_cells[j]);
 
-  /*   const ticks tic = getticks(); */
+#endif
 
-  /* #if defined(DEFAULT_SPH) || !defined(WITH_VECTORIZATION) */
+  /* Ghost to finish everything on the central cells */
+  for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j]);
 
-  /*   /\* Run all the brute-force pairs *\/ */
-  /*   for (int j = 0; j < 125; ++j) */
-  /*     if (cells[j] != main_cell) pairs_all_density(&runner, main_cell,
-   * cells[j]); */
+/* Do the force calculation */
+#if defined(DEFAULT_SPH) || !defined(WITH_VECTORIZATION)
 
-  /*   /\* And now the self-interaction *\/ */
-  /*   self_all_density(&runner, main_cell); */
+  /* Do the pairs (for the central 27 cells) */
+  for (int i = 1; i < 4; i++) {
+    for (int j = 1; j < 4; j++) {
+      for (int k = 1; k < 4; k++) {
 
-  /* #endif */
+        struct cell *cj = cells[i * 25 + j * 5 + k];
+
+        if (main_cell != cj) pairs_all_force(&runner, main_cell, cj);
+      }
+    }
+  }
+
+  /* And now the self-interaction for the main cell */
+  self_all_force(&runner, main_cell);
+#endif
 
-  /*   const ticks toc = getticks(); */
+  /* Finally, give a gentle kick */
+  runner_do_kick(&runner, main_cell, 0);
 
-  /*   /\* Let's get physical ! *\/ */
-  /*   end_calculation(main_cell); */
+  const ticks toc = getticks();
 
-  /*   /\* Dump *\/ */
-  /*   sprintf(outputFileName, "brute_force_125_%s.dat",
-   * outputFileNameExtension); */
-  /*   dump_particle_fields(outputFileName, main_cell, cells); */
+  /* Output timing */
+  message("Brute force calculation took : %15lli ticks.", toc - tic);
 
-  /*   /\* Output timing *\/ */
-  /*   message("Brute force calculation took : %15lli ticks.", toc - tic); */
+  sprintf(outputFileName, "brute_force_125_%s.dat", outputFileNameExtension);
+  dump_particle_fields(outputFileName, main_cell, solution, 0);
 
   /* Clean things to make the sanitizer happy ... */
   for (int i = 0; i < 125; ++i) clean_up(cells[i]);
+  free(solution);
 
   return 0;
 }
diff --git a/tests/test125cells.sh.in b/tests/test125cells.sh.in
index 838bbef973..ae8eb4ec39 100755
--- a/tests/test125cells.sh.in
+++ b/tests/test125cells.sh.in
@@ -1,8 +1,13 @@
 #!/bin/bash
-rm brute_force_125_standard.dat swift_dopair_125_standard.dat
-
-./test125cells -p 4 -r 1 -d 0 -f standard
-
-#python @srcdir@/difffloat.py brute_force_125_standard.dat swift_dopair_125_standard.dat @srcdir@/tolerance.dat 4
-
+for v in {0..3}
+do
+    for p in {0..2}
+    do
+	rm brute_force_125_standard.dat swift_dopair_125_standard.dat
+	./test125cells -n 6 -r 1 -v $v -p $p -f standard
+	python @srcdir@/difffloat.py brute_force_125_standard.dat swift_dopair_125_standard.dat @srcdir@/tolerance_125.dat 6
+	echo ""
+    done
+done
+	
 exit $?
diff --git a/tests/test27cells.c b/tests/test27cells.c
index 5d9cd0e2c8..c6c0c0f10d 100644
--- a/tests/test27cells.c
+++ b/tests/test27cells.c
@@ -249,7 +249,7 @@ void runner_doself1_density(struct runner *r, struct cell *ci);
 /* And go... */
 int main(int argc, char *argv[]) {
   size_t runs = 0, particles = 0;
-  double h = 1.2348, size = 1., rho = 1.;
+  double h = 1.23485, size = 1., rho = 1.;
   double perturbation = 0.;
   char outputFileNameExtension[200] = "";
   char outputFileName[200] = "";
@@ -266,7 +266,7 @@ int main(int argc, char *argv[]) {
   srand(0);
 
   char c;
-  while ((c = getopt(argc, argv, "m:s:h:p:r:t:d:f:v:")) != -1) {
+  while ((c = getopt(argc, argv, "m:s:h:n:r:t:d:f:v:")) != -1) {
     switch (c) {
       case 'h':
         sscanf(optarg, "%lf", &h);
@@ -274,7 +274,7 @@ int main(int argc, char *argv[]) {
       case 's':
         sscanf(optarg, "%lf", &size);
         break;
-      case 'p':
+      case 'n':
         sscanf(optarg, "%zu", &particles);
         break;
       case 'r':
@@ -300,9 +300,10 @@ int main(int argc, char *argv[]) {
 
   if (h < 0 || particles == 0 || runs == 0) {
     printf(
-        "\nUsage: %s -p PARTICLES_PER_AXIS -r NUMBER_OF_RUNS [OPTIONS...]\n"
-        "\nGenerates a cell pair, filled with particles on a Cartesian grid."
-        "\nThese are then interacted using runner_dopair1_density."
+        "\nUsage: %s -n PARTICLES_PER_AXIS -r NUMBER_OF_RUNS [OPTIONS...]\n"
+        "\nGenerates 27 cells, filled with particles on a Cartesian grid."
+        "\nThese are then interacted using runner_dopair1_density() and "
+        "runner_doself1_density()."
         "\n\nOptions:"
         "\n-h DISTANCE=1.2348 - Smoothing length in units of <x>"
         "\n-m rho             - Physical density in the cell"
@@ -316,13 +317,14 @@ int main(int argc, char *argv[]) {
   }
 
   /* Help users... */
+  message("Adiabatic index: ga = %f", hydro_gamma);
   message("Smoothing length: h = %f", h * size);
   message("Kernel:               %s", kernel_name);
-  message("Neighbour target: N = %f",
-          h * h * h * 4.0 * M_PI * kernel_gamma3 / 3.0);
+  message("Neighbour target: N = %f", h * h * h * kernel_norm);
   message("Density target: rho = %f", rho);
   message("div_v target:   div = %f", vel == 2 ? 3.f : 0.f);
   message("curl_v target: curl = [0., 0., %f]", vel == 3 ? -2.f : 0.f);
+
   printf("\n");
 
   /* Build the infrastructure */
diff --git a/tests/test27cells.sh.in b/tests/test27cells.sh.in
index b556576647..546b9cd27f 100755
--- a/tests/test27cells.sh.in
+++ b/tests/test27cells.sh.in
@@ -1,8 +1,11 @@
 #!/bin/bash
-rm brute_force_27_standard.dat swift_dopair_27_standard.dat
 
-./test27cells -p 6 -r 1 -d 0 -f standard
-
-python @srcdir@/difffloat.py brute_force_27_standard.dat swift_dopair_27_standard.dat @srcdir@/tolerance.dat 6
+for v in {0..3}
+do
+    rm brute_force_27_standard.dat swift_dopair_27_standard.dat
+    ./test27cells -n 6 -r 1 -d 0 -f standard -v $v
+    python @srcdir@/difffloat.py brute_force_27_standard.dat swift_dopair_27_standard.dat @srcdir@/tolerance_27.dat 6
+    echo ""
+done
 
 exit $?
diff --git a/tests/test27cellsPerturbed.sh.in b/tests/test27cellsPerturbed.sh.in
index 3d7574f9e9..c003b046a4 100755
--- a/tests/test27cellsPerturbed.sh.in
+++ b/tests/test27cellsPerturbed.sh.in
@@ -1,8 +1,8 @@
 #!/bin/bash
 rm brute_force_27_perturbed.dat swift_dopair_27_perturbed.dat
 
-./test27cells -p 6 -r 1 -d 0.1 -f perturbed
+./test27cells -n 6 -r 1 -d 0.1 -f perturbed
 
-python @srcdir@/difffloat.py brute_force_27_perturbed.dat swift_dopair_27_perturbed.dat @srcdir@/tolerance.dat 6
+python @srcdir@/difffloat.py brute_force_27_perturbed.dat swift_dopair_27_perturbed.dat @srcdir@/tolerance_27.dat 6
 
 exit $?
diff --git a/tests/testPair.sh.in b/tests/testPair.sh.in
index e719aeec4a..086db14fdd 100755
--- a/tests/testPair.sh.in
+++ b/tests/testPair.sh.in
@@ -3,6 +3,6 @@ rm brute_force_standard.dat swift_dopair_standard.dat
 
 ./testPair -p 6 -r 1 -d 0 -f standard
 
-python @srcdir@/difffloat.py brute_force_standard.dat swift_dopair_standard.dat @srcdir@/tolerance.dat
+python @srcdir@/difffloat.py brute_force_standard.dat swift_dopair_standard.dat @srcdir@/tolerance_pair.dat
 
 exit $?
diff --git a/tests/testPairPerturbed.sh.in b/tests/testPairPerturbed.sh.in
index d94a040d42..f17d7559e0 100755
--- a/tests/testPairPerturbed.sh.in
+++ b/tests/testPairPerturbed.sh.in
@@ -3,6 +3,6 @@ rm brute_force_perturbed.dat swift_dopair_perturbed.dat
 
 ./testPair -p 6 -r 1 -d 0.1 -f perturbed
 
-python @srcdir@/difffloat.py brute_force_perturbed.dat swift_dopair_perturbed.dat @srcdir@/tolerance.dat
+python @srcdir@/difffloat.py brute_force_perturbed.dat swift_dopair_perturbed.dat @srcdir@/tolerance_pair.dat
 
 exit $?
diff --git a/tests/tolerance_125.dat b/tests/tolerance_125.dat
new file mode 100644
index 0000000000..4870b20d96
--- /dev/null
+++ b/tests/tolerance_125.dat
@@ -0,0 +1,3 @@
+#   ID    pos_x    pos_y    pos_z      v_x      v_y      v_z        h      rho    div_v        S        u        P        c      a_x      a_y      a_z     h_dt    v_sig    dS/dt    du/dt
+    0	  1e-5	   1e-5	    1e-5       1e-5	1e-5	 1e-5	    1e-5   1e-5	  1e-5	       1e-5	1e-5	 1e-5	  1e-5	 1e-5	  1e-5	   1e-5	   1e-5	   1e-5	    1e-5     1e-5
+    0	  1e-5	   1e-5	    1e-5       1e-5	1e-5	 1e-5	    1e-5   1e-5	  1e-5	       1e-5	1e-5	 1e-5	  1e-5	 1e-5	  1e-5	   1e-5	   1e-5	   1e-5	    1e-5     1e-5
diff --git a/tests/tolerance.dat b/tests/tolerance_27.dat
similarity index 100%
rename from tests/tolerance.dat
rename to tests/tolerance_27.dat
diff --git a/tests/tolerance_pair.dat b/tests/tolerance_pair.dat
new file mode 100644
index 0000000000..f5031c5f47
--- /dev/null
+++ b/tests/tolerance_pair.dat
@@ -0,0 +1,3 @@
+#   ID      pos_x      pos_y      pos_z        v_x        v_y        v_z           rho        rho_dh        wcount     wcount_dh         div_v       curl_vx       curl_vy       curl_vz
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-5	      1e-5	    2e-5       3e-2		 1e-5	     1e-5	   1e-5		 1e-5
+    0	    1e-6       1e-6	  1e-6 	       1e-6 	  1e-6	     1e-6	   1e-5	      1.2e-5	    1e-5       1e-2		 1e-4	     1e-4	   1e-4		 1e-4
-- 
GitLab