Commit 1215102d authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

Merge branch 'gravity_bf' into 'master'

Gravity brute force checks, extra options

See merge request !1014
parents 273e64f3 79fe1127
......@@ -41,3 +41,33 @@ this mode, configure the code with ``--enable-glass-making``.
Note that this will *not* generate the initial random distribution of
particles. An initial condition file with particles still has to be provided.
Gravity force checks
~~~~~~~~~~~~~~~~~~~~
To test the accuracy of the gravitational forces approximated by the code,
SWIFT can be configured with the option to additionally compute the "exact"
forces for each active particle during each timestep. Here the exact forces are
simply the Newtonian sum, i.e.,
:math:`\vec{F}_{i,j} = \sum^{n}_{i \neq j} \frac{G m_i m_j}{\vec{r}_{i,j}^2}.`
To run SWIFT in this mode, configure the code with
``--enable-gravity-force-checks=N``, which means that the exact forces will be
computed for every :math:`N^{th}` particle based on their ID (i.e., to compute
the exact forces for all particles set ``N=1``).
Two `.dat` files will be output during each timestep, one containing the forces
(really it is the accelerations that are stored) as computed by ``_swift_``, and
another containing the ``_exact_`` forces. The total force (``a_swift``), along
with the contributed force from each component of the tree (P2P, M2P and M2L)
and the FFT mesh if periodic (PM) is stored (i.e., ``a_swift[0]`` = ``a_p2p[0]`` +
``a_m2p[0]`` + ``a_m2l[0]`` + ``a_PM[0]``, for the :math:`x` component). In addition,
the number of particles contributing to each force component is also stored
(these numbers will add up to :math:`n-1`).
This mode will slow down the code *considerably*, and it is not recommended to
be run on problems with more than :math:`10^{5}` particles when
``--enable-gravity-force-checks=1``. For larger runs, sampling a sub-set of
particles via the argument ``N`` of the configuration option is recommended.
This mode must be run on a single node/rank, and is primarily designed for pure
gravity tests (i.e., DMO).
......@@ -1263,3 +1263,23 @@ Showing all the parameters for a basic cosmologica test-case, one would have:
snapshots. Snapshots at a given time would always have the same set of
digits irrespective of the number of snapshots produced before.
Gravity Force Checks
--------------------
By default, when the code is configured with ``--enable-gravity-force-checks``,
the "exact" forces of all active gparts are computed during each timestep.
To give a bit more control over this, you can select to only perform the exact
force computation during the timesteps that all gparts are active, and/or only
at the timesteps when a snapshot is being dumped, i.e.,
.. code:: YAML
ForceChecks:
only_when_all_active: 1 # Only compute exact forces during timesteps when all gparts are active.
only_at_snapshots: 1 # Only compute exact forces during timesteps when a snapshot is being dumped.
If ``only_when_all_active:1`` and ``only_at_snapshots:1`` are enabled together,
and all the gparts are not active during the timestep of the snapshot dump, the
exact forces computation is performed on the first timestep at which all the
gparts are active after that snapshot output timestep.
......@@ -77,7 +77,11 @@ Gravity:
dithering: 1 # (Optional) Activate the dithering of the gravity mesh at every rebuild (this is the default value).
dithering_ratio: 1.0 # (Optional) Magnitude of each component of the dithering vector in units of the top-level cell sizes (this is the default value).
# Parameters for the Friends-Of-Friends algorithm
# Parameters when running with SWIFT_GRAVITY_FORCE_CHECKS
ForceChecks:
only_when_all_active: 1 # (Optional) Only compute exact forces during timesteps when all gparts are active (default: 0).
only_at_snapshots: 1 # (Optional) Only compute exact forces during timesteps when a snapshot is being dumped (default: 0).
FOF:
basename: fof_output # Filename for the FOF outputs (Unused when FoF is only run to seed BHs).
scale_factor_first: 0.91 # Scale-factor of first FoF black hole seeding calls (needed for cosmological runs).
......
......@@ -2397,6 +2397,10 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs,
e->forcerebuild = 1;
e->wallclock_time = (float)clocks_diff(&time1, &time2);
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
e->force_checks_snapshot_flag = 0;
#endif
if (e->verbose) message("took %.3f %s.", e->wallclock_time, clocks_getunit());
}
......@@ -2570,9 +2574,38 @@ void engine_step(struct engine *e) {
#endif
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
/* Run the brute-force gravity calculation for some gparts */
if (e->policy & engine_policy_self_gravity)
gravity_exact_force_compute(e->s, e);
/* Do we need to check if all gparts are active? */
if (e->force_checks_only_all_active) {
size_t nr_gparts = e->s->nr_gparts;
e->all_gparts_active = 1;
/* Look for inactive gparts */
for (size_t i = 0; i < nr_gparts; ++i) {
struct gpart *gp = &e->s->gparts[i];
/* If one gpart is inactive we can stop. */
if (!gpart_is_active(gp, e)) {
e->all_gparts_active = 0;
break;
}
}
}
/* Check if we want to run force checks this timestep. */
if (e->policy & engine_policy_self_gravity) {
/* Are all gparts active (and the option is selected)? */
if ((e->all_gparts_active && e->force_checks_only_all_active) ||
!e->force_checks_only_all_active) {
/* Is this a snapshot timestep (and the option is selected)? */
if ((e->force_checks_snapshot_flag &&
e->force_checks_only_at_snapshots) ||
!e->force_checks_only_at_snapshots) {
/* Do checks */
gravity_exact_force_compute(e->s, e);
}
}
}
#endif
/* Get current CPU times.*/
......@@ -2609,9 +2642,24 @@ void engine_step(struct engine *e) {
}
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
/* Check the accuracy of the gravity calculation */
if (e->policy & engine_policy_self_gravity)
gravity_exact_force_check(e->s, e, 1e-1);
/* Check if we want to run force checks this timestep. */
if (e->policy & engine_policy_self_gravity) {
/* Are all gparts active (and the option is selected)? */
if ((e->all_gparts_active && e->force_checks_only_all_active) ||
!e->force_checks_only_all_active) {
/* Is this a snapshot timestep (and the option is selected)? */
if ((e->force_checks_snapshot_flag &&
e->force_checks_only_at_snapshots) ||
!e->force_checks_only_at_snapshots) {
/* Do checks */
gravity_exact_force_check(e->s, e, 1e-1);
/* Reset flag waiting for next output time */
e->force_checks_snapshot_flag = 0;
}
}
}
#endif
#ifdef SWIFT_DEBUG_CHECKS
......@@ -2740,6 +2788,11 @@ void engine_check_for_dumps(struct engine *e) {
case output_snapshot:
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
/* Indicate we are allowed to do a brute force calculation now */
e->force_checks_snapshot_flag = 1;
#endif
/* Do we want a corresponding VELOCIraptor output? */
if (with_stf && e->snapshot_invoke_stf && !e->stf_this_timestep) {
......@@ -3841,6 +3894,13 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params,
}
#endif
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
e->force_checks_only_all_active =
parser_get_opt_param_int(params, "ForceChecks:only_when_all_active", 0);
e->force_checks_only_at_snapshots =
parser_get_opt_param_int(params, "ForceChecks:only_at_snapshots", 0);
#endif
/* Make the space link back to the engine. */
s->e = e;
......
......@@ -486,6 +486,20 @@ struct engine {
/* Has there been an stf this timestep? */
char stf_this_timestep;
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
/* Run brute force checks only on steps when all gparts active? */
int force_checks_only_all_active;
/* Run brute force checks only during snapshot timesteps? */
int force_checks_only_at_snapshots;
/* Are all gparts active this timestep? */
int all_gparts_active;
/* Flag to tell brute force checks a snapshot was recently written. */
int force_checks_snapshot_flag;
#endif
};
/* Function prototypes, engine.c. */
......
......@@ -71,7 +71,7 @@ float ewald_fac;
*
* @param boxSize The side-length (L) of the volume.
*/
void gravity_exact_force_ewald_init(double boxSize) {
void gravity_exact_force_ewald_init(const double boxSize) {
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
......@@ -431,7 +431,7 @@ int gravity_exact_force_file_exits(const struct engine *e) {
char line[100];
char dummy1[10], dummy2[10];
double epsilon, newton_G;
double newton_G;
int N, periodic;
/* Reads file header */
if (fgets(line, 100, file) != line) error("Problem reading title");
......@@ -439,17 +439,12 @@ int gravity_exact_force_file_exits(const struct engine *e) {
sscanf(line, "%s %s %le", dummy1, dummy2, &newton_G);
if (fgets(line, 100, file) != line) error("Problem reading N");
sscanf(line, "%s %s %d", dummy1, dummy2, &N);
if (fgets(line, 100, file) != line) error("Problem reading epsilon");
sscanf(line, "%s %s %le", dummy1, dummy2, &epsilon);
if (fgets(line, 100, file) != line) error("Problem reading BC");
sscanf(line, "%s %s %d", dummy1, dummy2, &periodic);
fclose(file);
/* Check whether it matches the current parameters */
if (N == SWIFT_GRAVITY_FORCE_CHECKS && periodic == e->s->periodic &&
(fabs(epsilon - gravity_get_softening(0, e->gravity_properties)) /
epsilon <
1e-5) &&
(fabs(newton_G - e->physical_constants->const_newton_G) / newton_G <
1e-5)) {
return 1;
......@@ -475,6 +470,7 @@ void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
const struct space *s = data->s;
const struct part *parts = s->parts;
const struct spart *sparts = s->sparts;
const struct bpart *bparts = s->bparts;
const struct engine *e = data->e;
const int periodic = s->periodic;
const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
......@@ -485,13 +481,14 @@ void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
struct gpart *gpi = &gparts[i];
/* Get the particle ID */
long long id = 0;
if (gpi->type == swift_type_gas)
id = parts[-gpi->id_or_neg_offset].id;
else if (gpi->type == swift_type_stars)
id = sparts[-gpi->id_or_neg_offset].id;
else if (gpi->type == swift_type_black_hole)
error("Unexisting type");
id = bparts[-gpi->id_or_neg_offset].id;
else
id = gpi->id_or_neg_offset;
......@@ -506,6 +503,8 @@ void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
/* Be ready for the calculation */
double a_grav[3] = {0., 0., 0.};
double a_grav_short[3] = {0., 0., 0.};
double a_grav_long[3] = {0., 0., 0.};
double pot = 0.;
/* Interact it with all other particles in the space.*/
......@@ -558,9 +557,32 @@ void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
a_grav[2] += f * dz;
pot += phi;
/* Apply Ewald correction for periodic BC */
/* Apply Ewald correction for periodic BC
*
* We also want to check what the tree and mesh do so we want to mimic
* that:
* - a_grav_short is the total acceleration multiplied by the
* short-range correction.
* - a_grav_long is the total acceleration (including Ewald correction)
* minus the short-range acceleration.
*/
if (periodic && r > 1e-5 * hi) {
/* Compute trunctation for long and short range forces */
const double r_s_inv = e->mesh->r_s_inv;
const double u_lr = r * r_s_inv;
double corr_f_lr;
kernel_long_grav_force_eval_double(u_lr, &corr_f_lr);
a_grav_short[0] += f * dx * corr_f_lr;
a_grav_short[1] += f * dy * corr_f_lr;
a_grav_short[2] += f * dz * corr_f_lr;
a_grav_long[0] += f * dx * (1. - corr_f_lr);
a_grav_long[1] += f * dy * (1. - corr_f_lr);
a_grav_long[2] += f * dz * (1. - corr_f_lr);
/* Ewald correction. */
double corr_f[3], corr_pot;
gravity_exact_force_ewald_evaluate(dx, dy, dz, corr_f, &corr_pot);
......@@ -568,13 +590,19 @@ void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
a_grav[1] += mj * corr_f[1];
a_grav[2] += mj * corr_f[2];
pot += mj * corr_pot;
a_grav_long[0] += mj * corr_f[0];
a_grav_long[1] += mj * corr_f[1];
a_grav_long[2] += mj * corr_f[2];
}
}
/* Store the exact answer */
gpi->a_grav_exact[0] = a_grav[0] * const_G;
gpi->a_grav_exact[1] = a_grav[1] * const_G;
gpi->a_grav_exact[2] = a_grav[2] * const_G;
for (int k = 0; k < 3; k++) {
gpi->a_grav_exact[k] = a_grav[k] * const_G;
gpi->a_grav_exact_short[k] = a_grav_short[k] * const_G;
gpi->a_grav_exact_long[k] = a_grav_long[k] * const_G;
}
gpi->potential_exact = pot * const_G;
counter++;
......@@ -647,6 +675,7 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
const struct part *parts = s->parts;
const struct spart *sparts = s->sparts;
const struct bpart *bparts = s->bparts;
/* File name */
char file_name_swift[100];
......@@ -654,34 +683,36 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
SELF_GRAVITY_MULTIPOLE_ORDER);
/* Creare files and write header */
const double epsilon = gravity_get_softening(0, e->gravity_properties);
FILE *file_swift = fopen(file_name_swift, "w");
fprintf(file_swift, "# Gravity accuracy test - SWIFT FORCES\n");
fprintf(file_swift, "# G= %16.8e\n", e->physical_constants->const_newton_G);
fprintf(file_swift, "# N= %d\n", SWIFT_GRAVITY_FORCE_CHECKS);
fprintf(file_swift, "# epsilon= %16.8e\n", epsilon);
fprintf(file_swift, "# periodic= %d\n", s->periodic);
fprintf(file_swift, "# theta= %16.8e\n", e->gravity_properties->theta_crit);
fprintf(file_swift, "# Git Branch: %s\n", git_branch());
fprintf(file_swift, "# Git Revision: %s\n", git_revision());
fprintf(file_swift,
"# %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s\n",
"# %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s "
"%16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s\n",
"id", "pos[0]", "pos[1]", "pos[2]", "a_swift[0]", "a_swift[1]",
"a_swift[2]", "potential", "a_PM[0]", "a_PM[1]", "a_PM[2]",
"potentialPM");
"potentialPM", "a_p2p[0]", "a_p2p[1]", "a_p2p[2]", "a_m2p[0]",
"a_m2p[1]", "a_m2p[2]", "a_m2l[0]", "a_m2l[1]", "a_m2l[2]", "n_p2p",
"n_m2p", "n_m2l", "n_PM");
/* Output particle SWIFT accelerations */
for (size_t i = 0; i < s->nr_gparts; ++i) {
struct gpart *gpi = &s->gparts[i];
/* Get the particle ID */
long long id = 0;
if (gpi->type == swift_type_gas)
id = parts[-gpi->id_or_neg_offset].id;
else if (gpi->type == swift_type_stars)
id = sparts[-gpi->id_or_neg_offset].id;
else if (gpi->type == swift_type_black_hole)
error("Unexisting type");
id = bparts[-gpi->id_or_neg_offset].id;
else
id = gpi->id_or_neg_offset;
......@@ -690,11 +721,17 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
fprintf(file_swift,
"%18lld %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e "
"%16.8e %16.8e %16.8e\n",
"%16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e "
"%16.8e %16.8e %16.8e %18lld %18lld %18lld %18lld\n",
id, gpi->x[0], gpi->x[1], gpi->x[2], gpi->a_grav[0],
gpi->a_grav[1], gpi->a_grav[2],
gravity_get_comoving_potential(gpi), gpi->a_grav_PM[0],
gpi->a_grav_PM[1], gpi->a_grav_PM[2], gpi->potential_PM);
gpi->a_grav_PM[1], gpi->a_grav_PM[2], gpi->potential_PM,
gpi->a_grav_p2p[0], gpi->a_grav_p2p[1], gpi->a_grav_p2p[2],
gpi->a_grav_m2p[0], gpi->a_grav_m2p[1], gpi->a_grav_m2p[2],
gpi->a_grav_m2l[0], gpi->a_grav_m2l[1], gpi->a_grav_m2l[2],
gpi->num_interacted_p2p, gpi->num_interacted_m2p,
gpi->num_interacted_m2l, gpi->num_interacted_pm);
}
}
......@@ -716,13 +753,16 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
fprintf(file_exact, "# Gravity accuracy test - EXACT FORCES\n");
fprintf(file_exact, "# G= %16.8e\n", e->physical_constants->const_newton_G);
fprintf(file_exact, "# N= %d\n", SWIFT_GRAVITY_FORCE_CHECKS);
fprintf(file_exact, "# epsilon=%16.8e\n", epsilon);
fprintf(file_exact, "# periodic= %d\n", s->periodic);
fprintf(file_exact, "# Git Branch: %s\n", git_branch());
fprintf(file_exact, "# Git Revision: %s\n", git_revision());
fprintf(file_exact, "# %16s %16s %16s %16s %16s %16s %16s %16s\n", "id",
"pos[0]", "pos[1]", "pos[2]", "a_exact[0]", "a_exact[1]",
"a_exact[2]", "potential");
fprintf(file_exact,
"# %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s %16s "
"%16s %16s %16s\n",
"id", "pos[0]", "pos[1]", "pos[2]", "a_exact[0]", "a_exact[1]",
"a_exact[2]", "potential", "a_exact_short[0]", "a_exact_short[1]",
"a_exact_short[2]", "a_exact_long[0]", "a_exact_long[1]",
"a_exact_long[2]");
/* Output particle exact accelerations */
for (size_t i = 0; i < s->nr_gparts; ++i) {
......@@ -741,12 +781,15 @@ void gravity_exact_force_check(struct space *s, const struct engine *e,
/* Is the particle was active and part of the subset to be tested ? */
if (id % SWIFT_GRAVITY_FORCE_CHECKS == 0 && gpart_is_starting(gpi, e)) {
fprintf(file_exact,
"%18lld %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e\n", id,
gpi->x[0], gpi->x[1], gpi->x[2], gpi->a_grav_exact[0],
"%18lld %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e %16.8e "
"%16.8e %16.8e %16.8e %16.8e %16.8e %16.8e\n",
id, gpi->x[0], gpi->x[1], gpi->x[2], gpi->a_grav_exact[0],
gpi->a_grav_exact[1], gpi->a_grav_exact[2],
gpi->potential_exact);
gpi->potential_exact, gpi->a_grav_exact_short[0],
gpi->a_grav_exact_short[1], gpi->a_grav_exact_short[2],
gpi->a_grav_exact_long[0], gpi->a_grav_exact_long[1],
gpi->a_grav_exact_long[2]);
}
}
......
......@@ -152,9 +152,20 @@ __attribute__((always_inline)) INLINE static void gravity_init_gpart(
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
gp->potential_PM = 0.f;
gp->a_grav_PM[0] = 0.f;
gp->a_grav_PM[1] = 0.f;
gp->a_grav_PM[2] = 0.f;
/* Track accelerations of each component. */
for (int i = 0; i < 3; i++) {
gp->a_grav_PM[i] = 0.f;
gp->a_grav_p2p[i] = 0.f;
gp->a_grav_m2p[i] = 0.f;
gp->a_grav_m2l[i] = 0.f;
}
/* Interaction counters. */
gp->num_interacted_m2p = 0;
gp->num_interacted_m2l = 0;
gp->num_interacted_p2p = 0;
gp->num_interacted_pm = 0;
#endif
#ifdef SWIFT_DEBUG_CHECKS
......@@ -188,9 +199,12 @@ __attribute__((always_inline)) INLINE static void gravity_end_force(
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
gp->potential_PM *= const_G;
gp->a_grav_PM[0] *= const_G;
gp->a_grav_PM[1] *= const_G;
gp->a_grav_PM[2] *= const_G;
for (int i = 0; i < 3; i++) {
gp->a_grav_PM[i] *= const_G;
gp->a_grav_p2p[i] *= const_G;
gp->a_grav_m2p[i] *= const_G;
gp->a_grav_m2l[i] *= const_G;
}
#endif
#ifdef SWIFT_DEBUG_CHECKS
......
......@@ -58,9 +58,6 @@ struct gpart {
#ifdef SWIFT_DEBUG_CHECKS
/* Numer of gparts this gpart interacted with */
long long num_interacted;
/* Time of the last drift */
integertime_t ti_drift;
......@@ -70,6 +67,8 @@ struct gpart {
/* Has this particle been initialised? */
int initialised;
/* Total number of gparts this gpart interacted with */
long long num_interacted;
#endif
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
......@@ -80,11 +79,24 @@ struct gpart {
/*! Potential taken from the mesh only */
float potential_PM;
/* Brute-force particle acceleration. */
/* Acceleration taken from each component of the tree */
float a_grav_p2p[3];
float a_grav_m2p[3];
float a_grav_m2l[3];
/* Brute-force particle accelerations */
double a_grav_exact[3];
double a_grav_exact_long[3];
double a_grav_exact_short[3];
/* Brute-force particle potential. */
double potential_exact;
/* Type specific interaction counters */
long long num_interacted_m2p;
long long num_interacted_m2l;
long long num_interacted_p2p;
long long num_interacted_pm;
#endif
} SWIFT_STRUCT_ALIGN;
......
......@@ -162,9 +162,20 @@ __attribute__((always_inline)) INLINE static void gravity_init_gpart(
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
gp->potential_PM = 0.f;
gp->a_grav_PM[0] = 0.f;
gp->a_grav_PM[1] = 0.f;
gp->a_grav_PM[2] = 0.f;
/* Track accelerations of each component. */
for (int i = 0; i < 3; i++) {
gp->a_grav_PM[i] = 0.f;
gp->a_grav_p2p[i] = 0.f;
gp->a_grav_m2p[i] = 0.f;
gp->a_grav_m2l[i] = 0.f;
}
/* Interaction counters. */
gp->num_interacted_m2p = 0;
gp->num_interacted_m2l = 0;
gp->num_interacted_p2p = 0;
gp->num_interacted_pm = 0;
#endif
#ifdef SWIFT_DEBUG_CHECKS
......@@ -202,9 +213,12 @@ __attribute__((always_inline)) INLINE static void gravity_end_force(
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
gp->potential_PM *= const_G;
gp->a_grav_PM[0] *= const_G;
gp->a_grav_PM[1] *= const_G;
gp->a_grav_PM[2] *= const_G;
for (int i = 0; i < 3; i++) {
gp->a_grav_PM[i] *= const_G;
gp->a_grav_p2p[i] *= const_G;
gp->a_grav_m2p[i] *= const_G;
gp->a_grav_m2l[i] *= const_G;
}
#endif
#ifdef SWIFT_DEBUG_CHECKS
......
......@@ -59,9 +59,6 @@ struct gpart {
#ifdef SWIFT_DEBUG_CHECKS
/* Numer of gparts this gpart interacted with */
long long num_interacted;
/* Time of the last drift */
integertime_t ti_drift;
......@@ -71,6 +68,8 @@ struct gpart {
/* Has this particle been initialised? */
int initialised;
/* Total number of gparts this gpart interacted with */
long long num_interacted;
#endif
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
......@@ -81,11 +80,24 @@ struct gpart {
/*! Potential taken from the mesh only */
float potential_PM;
/* Brute-force particle acceleration. */
/* Acceleration taken from each component of the tree */
float a_grav_p2p[3];
float a_grav_m2p[3];
float a_grav_m2l[3];
/* Brute-force particle accelerations */
double a_grav_exact[3];
double a_grav_exact_long[3];
double a_grav_exact_short[3];
/* Brute-force particle potential. */
double potential_exact;
/* Type specific interaction counters */
long long num_interacted_m2l;
long long num_interacted_m2p;
long long num_interacted_p2p;
long long num_interacted_pm;
#endif
} SWIFT_STRUCT_ALIGN;
......
......@@ -208,6 +208,42 @@ __attribute__((always_inline)) INLINE static void kernel_long_grav_force_eval(
#endif
}
/**
* @brief Computes the long-range correction term for the force calculation
* coming from FFT in double precision.
*
* @param u The ratio of the distance to the FFT cell scale \f$u = r/r_s\f$.
* @param W (return) The value of the kernel function.
*/
__attribute__((always_inline)) INLINE static void
kernel_long_grav_force_eval_double(const double u, double *const W) {
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
#ifdef GADGET2_LONG_RANGE_CORRECTION