Commit 39ed5454 authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

Merge branch 'gravity_multi_dt' into 'master'

Gravity multi dt



See merge request !333
parents f0126fe9 1b4cc45e
...@@ -27,6 +27,7 @@ Valid options are: ...@@ -27,6 +27,7 @@ Valid options are:
-f {int} Overwrite the CPU frequency (Hz) to be used for time measurements. -f {int} Overwrite the CPU frequency (Hz) to be used for time measurements.
-g Run with an external gravitational potential. -g Run with an external gravitational potential.
-G Run with self-gravity. -G Run with self-gravity.
-M Reconstruct the multipoles every time-step.
-n {int} Execute a fixed number of time steps. When unset use the time_end parameter to stop. -n {int} Execute a fixed number of time steps. When unset use the time_end parameter to stop.
-s Run with hydrodynamics. -s Run with hydrodynamics.
-S Run with stars. -S Run with stars.
......
...@@ -215,6 +215,21 @@ elif test "$gravity_force_checks" != "no"; then ...@@ -215,6 +215,21 @@ elif test "$gravity_force_checks" != "no"; then
AC_DEFINE_UNQUOTED([SWIFT_GRAVITY_FORCE_CHECKS], [$enableval] ,[Enable gravity brute-force checks]) AC_DEFINE_UNQUOTED([SWIFT_GRAVITY_FORCE_CHECKS], [$enableval] ,[Enable gravity brute-force checks])
fi fi
# Check if we want to zero the gravity forces for all particles below some ID.
AC_ARG_ENABLE([no-gravity-below-id],
[AS_HELP_STRING([--enable-no-gravity-below-id],
[Zeros the gravitational acceleration of all particles with an ID smaller than @<:@N@:>@]
)],
[no_gravity_below_id="$enableval"],
[no_gravity_below_id="no"]
)
if test "$no_gravity_below_id" == "yes"; then
AC_MSG_ERROR(Need to specify the ID below which particles get zero forces when using --enable-no-gravity-below-id!)
elif test "$no_gravity_below_id" != "no"; then
AC_DEFINE_UNQUOTED([SWIFT_NO_GRAVITY_BELOW_ID], [$enableval] ,[Particles with smaller ID than this will have zero gravity forces])
fi
# Define HAVE_POSIX_MEMALIGN if it works. # Define HAVE_POSIX_MEMALIGN if it works.
AX_FUNC_POSIX_MEMALIGN AX_FUNC_POSIX_MEMALIGN
...@@ -854,12 +869,14 @@ AC_MSG_RESULT([ ...@@ -854,12 +869,14 @@ AC_MSG_RESULT([
Adiabatic index : $with_gamma Adiabatic index : $with_gamma
Riemann solver : $with_riemann Riemann solver : $with_riemann
Cooling function : $with_cooling Cooling function : $with_cooling
External potential : $with_potential
Multipole order : $with_multipole_order External potential : $with_potential
Multipole order : $with_multipole_order
Task debugging : $enable_task_debugging No gravity below ID : $no_gravity_below_id
Debugging checks : $enable_debugging_checks
Gravity checks : $gravity_force_checks Task debugging : $enable_task_debugging
Debugging checks : $enable_debugging_checks
Gravity checks : $gravity_force_checks
]) ])
# Make sure the latest git revision string gets included # Make sure the latest git revision string gets included
......
...@@ -82,6 +82,8 @@ void print_help_message() { ...@@ -82,6 +82,8 @@ void print_help_message() {
"Run with an external gravitational potential."); "Run with an external gravitational potential.");
printf(" %2s %8s %s\n", "-F", "", "Run with feedback."); printf(" %2s %8s %s\n", "-F", "", "Run with feedback.");
printf(" %2s %8s %s\n", "-G", "", "Run with self-gravity."); printf(" %2s %8s %s\n", "-G", "", "Run with self-gravity.");
printf(" %2s %8s %s\n", "-M", "",
"Reconstruct the multipoles every time-step.");
printf(" %2s %8s %s\n", "-n", "{int}", printf(" %2s %8s %s\n", "-n", "{int}",
"Execute a fixed number of time steps. When unset use the time_end " "Execute a fixed number of time steps. When unset use the time_end "
"parameter to stop."); "parameter to stop.");
...@@ -164,6 +166,7 @@ int main(int argc, char *argv[]) { ...@@ -164,6 +166,7 @@ int main(int argc, char *argv[]) {
int with_stars = 0; int with_stars = 0;
int with_fp_exceptions = 0; int with_fp_exceptions = 0;
int with_drift_all = 0; int with_drift_all = 0;
int with_mpole_reconstruction = 0;
int verbose = 0; int verbose = 0;
int nr_threads = 1; int nr_threads = 1;
int with_verbose_timers = 0; int with_verbose_timers = 0;
...@@ -172,7 +175,8 @@ int main(int argc, char *argv[]) { ...@@ -172,7 +175,8 @@ int main(int argc, char *argv[]) {
/* Parse the parameters */ /* Parse the parameters */
int c; int c;
while ((c = getopt(argc, argv, "acCdDef:FgGhn:sSt:Tv:y:")) != -1) switch (c) { while ((c = getopt(argc, argv, "acCdDef:FgGhMn:sSt:Tv:y:")) != -1)
switch (c) {
case 'a': case 'a':
with_aff = 1; with_aff = 1;
break; break;
...@@ -210,6 +214,9 @@ int main(int argc, char *argv[]) { ...@@ -210,6 +214,9 @@ int main(int argc, char *argv[]) {
case 'h': case 'h':
if (myrank == 0) print_help_message(); if (myrank == 0) print_help_message();
return 0; return 0;
case 'M':
with_mpole_reconstruction = 1;
break;
case 'n': case 'n':
if (sscanf(optarg, "%d", &nsteps) != 1) { if (sscanf(optarg, "%d", &nsteps) != 1) {
if (myrank == 0) printf("Error parsing fixed number of steps.\n"); if (myrank == 0) printf("Error parsing fixed number of steps.\n");
...@@ -521,6 +528,8 @@ int main(int argc, char *argv[]) { ...@@ -521,6 +528,8 @@ int main(int argc, char *argv[]) {
/* Construct the engine policy */ /* Construct the engine policy */
int engine_policies = ENGINE_POLICY | engine_policy_steal; int engine_policies = ENGINE_POLICY | engine_policy_steal;
if (with_drift_all) engine_policies |= engine_policy_drift_all; if (with_drift_all) engine_policies |= engine_policy_drift_all;
if (with_mpole_reconstruction)
engine_policies |= engine_policy_reconstruct_mpoles;
if (with_hydro) engine_policies |= engine_policy_hydro; if (with_hydro) engine_policies |= engine_policy_hydro;
if (with_self_gravity) engine_policies |= engine_policy_self_gravity; if (with_self_gravity) engine_policies |= engine_policy_self_gravity;
if (with_external_gravity) engine_policies |= engine_policy_external_gravity; if (with_external_gravity) engine_policies |= engine_policy_external_gravity;
......
...@@ -1103,33 +1103,92 @@ void cell_reset_task_counters(struct cell *c) { ...@@ -1103,33 +1103,92 @@ void cell_reset_task_counters(struct cell *c) {
} }
/** /**
* @brief Checks whether the cells are direct neighbours ot not. Both cells have * @brief Recursively construct all the multipoles in a cell hierarchy.
* to be of the same size
* *
* @param ci First #cell. * @param c The #cell.
* @param cj Second #cell.
*
* @todo Deal with periodicity.
*/ */
int cell_are_neighbours(const struct cell *restrict ci, void cell_make_multipoles(struct cell *c, integertime_t ti_current) {
const struct cell *restrict cj) {
#ifdef SWIFT_DEBUG_CHECKS /* Reset everything */
if (ci->width[0] != cj->width[0]) error("Cells of different size !"); gravity_reset(c->multipole);
#endif
if (c->split) {
/* Compute CoM of all progenies */
double CoM[3] = {0., 0., 0.};
double mass = 0.;
for (int k = 0; k < 8; ++k) {
if (c->progeny[k] != NULL) {
const struct gravity_tensors *m = c->progeny[k]->multipole;
CoM[0] += m->CoM[0] * m->m_pole.M_000;
CoM[1] += m->CoM[1] * m->m_pole.M_000;
CoM[2] += m->CoM[2] * m->m_pole.M_000;
mass += m->m_pole.M_000;
}
}
c->multipole->CoM[0] = CoM[0] / mass;
c->multipole->CoM[1] = CoM[1] / mass;
c->multipole->CoM[2] = CoM[2] / mass;
/* Now shift progeny multipoles and add them up */
struct multipole temp;
double r_max = 0.;
for (int k = 0; k < 8; ++k) {
if (c->progeny[k] != NULL) {
const struct cell *cp = c->progeny[k];
const struct multipole *m = &cp->multipole->m_pole;
/* Contribution to multipole */
gravity_M2M(&temp, m, c->multipole->CoM, cp->multipole->CoM);
gravity_multipole_add(&c->multipole->m_pole, &temp);
/* Upper limit of max CoM<->gpart distance */
const double dx = c->multipole->CoM[0] - cp->multipole->CoM[0];
const double dy = c->multipole->CoM[1] - cp->multipole->CoM[1];
const double dz = c->multipole->CoM[2] - cp->multipole->CoM[2];
const double r2 = dx * dx + dy * dy + dz * dz;
r_max = max(r_max, cp->multipole->r_max + sqrt(r2));
}
}
/* Alternative upper limit of max CoM<->gpart distance */
const double dx = c->multipole->CoM[0] > c->loc[0] + c->width[0] / 2.
? c->multipole->CoM[0] - c->loc[0]
: c->loc[0] + c->width[0] - c->multipole->CoM[0];
const double dy = c->multipole->CoM[1] > c->loc[1] + c->width[1] / 2.
? c->multipole->CoM[1] - c->loc[1]
: c->loc[1] + c->width[1] - c->multipole->CoM[1];
const double dz = c->multipole->CoM[2] > c->loc[2] + c->width[2] / 2.
? c->multipole->CoM[2] - c->loc[2]
: c->loc[2] + c->width[2] - c->multipole->CoM[2];
/* Take minimum of both limits */
c->multipole->r_max = min(r_max, sqrt(dx * dx + dy * dy + dz * dz));
/* Maximum allowed distance */ } else {
const double min_dist =
1.2 * ci->width[0]; /* 1.2 accounts for rounding errors */
/* (Manhattan) Distance between the cells */ if (c->gcount > 0) {
for (int k = 0; k < 3; k++) { gravity_P2M(c->multipole, c->gparts, c->gcount);
const double center_i = ci->loc[k]; const double dx = c->multipole->CoM[0] > c->loc[0] + c->width[0] / 2.
const double center_j = cj->loc[k]; ? c->multipole->CoM[0] - c->loc[0]
if (fabs(center_i - center_j) > min_dist) return 0; : c->loc[0] + c->width[0] - c->multipole->CoM[0];
const double dy = c->multipole->CoM[1] > c->loc[1] + c->width[1] / 2.
? c->multipole->CoM[1] - c->loc[1]
: c->loc[1] + c->width[1] - c->multipole->CoM[1];
const double dz = c->multipole->CoM[2] > c->loc[2] + c->width[2] / 2.
? c->multipole->CoM[2] - c->loc[2]
: c->loc[2] + c->width[2] - c->multipole->CoM[2];
c->multipole->r_max = sqrt(dx * dx + dy * dy + dz * dz);
} else {
gravity_multipole_init(&c->multipole->m_pole);
c->multipole->CoM[0] = c->loc[0] + c->width[0] / 2.;
c->multipole->CoM[1] = c->loc[1] + c->width[1] / 2.;
c->multipole->CoM[2] = c->loc[2] + c->width[2] / 2.;
c->multipole->r_max = 0.;
}
} }
return 1; c->ti_old_multipole = ti_current;
} }
/** /**
...@@ -1145,6 +1204,8 @@ void cell_check_multipole(struct cell *c, void *data) { ...@@ -1145,6 +1204,8 @@ void cell_check_multipole(struct cell *c, void *data) {
struct gravity_tensors ma; struct gravity_tensors ma;
const double tolerance = 1e-3; /* Relative */ const double tolerance = 1e-3; /* Relative */
return;
/* First recurse */ /* First recurse */
if (c->split) if (c->split)
for (int k = 0; k < 8; k++) for (int k = 0; k < 8; k++)
......
...@@ -351,8 +351,7 @@ int cell_link_gparts(struct cell *c, struct gpart *gparts); ...@@ -351,8 +351,7 @@ int cell_link_gparts(struct cell *c, struct gpart *gparts);
int cell_link_sparts(struct cell *c, struct spart *sparts); int cell_link_sparts(struct cell *c, struct spart *sparts);
void cell_convert_hydro(struct cell *c, void *data); void cell_convert_hydro(struct cell *c, void *data);
void cell_clean_links(struct cell *c, void *data); void cell_clean_links(struct cell *c, void *data);
int cell_are_neighbours(const struct cell *restrict ci, void cell_make_multipoles(struct cell *c, integertime_t ti_current);
const struct cell *restrict cj);
void cell_check_multipole(struct cell *c, void *data); void cell_check_multipole(struct cell *c, void *data);
void cell_clean(struct cell *c); void cell_clean(struct cell *c);
void cell_check_particle_drift_point(struct cell *c, void *data); void cell_check_particle_drift_point(struct cell *c, void *data);
......
...@@ -1693,7 +1693,7 @@ void engine_make_self_gravity_tasks(struct engine *e) { ...@@ -1693,7 +1693,7 @@ void engine_make_self_gravity_tasks(struct engine *e) {
/* Are the cells to close for a MM interaction ? */ /* Are the cells to close for a MM interaction ? */
if (!gravity_multipole_accept(ci->multipole, cj->multipole, if (!gravity_multipole_accept(ci->multipole, cj->multipole,
theta_crit_inv)) theta_crit_inv, 1))
scheduler_addtask(sched, task_type_pair, task_subtype_grav, 0, 0, ci, scheduler_addtask(sched, task_type_pair, task_subtype_grav, 0, 0, ci,
cj, 1); cj, 1);
} }
...@@ -3225,6 +3225,15 @@ void engine_step(struct engine *e) { ...@@ -3225,6 +3225,15 @@ void engine_step(struct engine *e) {
/* Are we drifting everything (a la Gadget/GIZMO) ? */ /* Are we drifting everything (a la Gadget/GIZMO) ? */
if (e->policy & engine_policy_drift_all) engine_drift_all(e); if (e->policy & engine_policy_drift_all) engine_drift_all(e);
/* Are we reconstructing the multipoles or drifting them ?*/
if (e->policy & engine_policy_self_gravity) {
if (e->policy & engine_policy_reconstruct_mpoles)
engine_reconstruct_multipoles(e);
else
engine_drift_top_multipoles(e);
}
/* Print the number of active tasks ? */ /* Print the number of active tasks ? */
if (e->verbose) engine_print_task_counts(e); if (e->verbose) engine_print_task_counts(e);
...@@ -3248,9 +3257,6 @@ void engine_step(struct engine *e) { ...@@ -3248,9 +3257,6 @@ void engine_step(struct engine *e) {
gravity_exact_force_compute(e->s, e); gravity_exact_force_compute(e->s, e);
#endif #endif
/* Do we need to drift the top-level multipoles ? */
if (e->policy & engine_policy_self_gravity) engine_drift_top_multipoles(e);
/* Start all the tasks. */ /* Start all the tasks. */
TIMER_TIC; TIMER_TIC;
engine_launch(e, e->nr_threads); engine_launch(e, e->nr_threads);
...@@ -3447,6 +3453,39 @@ void engine_drift_top_multipoles(struct engine *e) { ...@@ -3447,6 +3453,39 @@ void engine_drift_top_multipoles(struct engine *e) {
clocks_getunit()); clocks_getunit());
} }
void engine_do_reconstruct_multipoles_mapper(void *map_data, int num_elements,
void *extra_data) {
struct engine *e = (struct engine *)extra_data;
struct cell *cells = (struct cell *)map_data;
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c = &cells[ind];
if (c != NULL && c->nodeID == e->nodeID) {
/* Construct the multipoles in this cell hierarchy */
cell_make_multipoles(c, e->ti_current);
}
}
}
/**
* @brief Reconstruct all the multipoles at all the levels in the tree.
*
* @param e The #engine.
*/
void engine_reconstruct_multipoles(struct engine *e) {
const ticks tic = getticks();
threadpool_map(&e->threadpool, engine_do_reconstruct_multipoles_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell), 10, e);
if (e->verbose)
message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
clocks_getunit());
}
/** /**
* @brief Create and fill the proxies. * @brief Create and fill the proxies.
* *
......
...@@ -66,9 +66,10 @@ enum engine_policy { ...@@ -66,9 +66,10 @@ enum engine_policy {
engine_policy_external_gravity = (1 << 9), engine_policy_external_gravity = (1 << 9),
engine_policy_cosmology = (1 << 10), engine_policy_cosmology = (1 << 10),
engine_policy_drift_all = (1 << 11), engine_policy_drift_all = (1 << 11),
engine_policy_cooling = (1 << 12), engine_policy_reconstruct_mpoles = (1 << 12),
engine_policy_sourceterms = (1 << 13), engine_policy_cooling = (1 << 13),
engine_policy_stars = (1 << 14) engine_policy_sourceterms = (1 << 14),
engine_policy_stars = (1 << 15)
}; };
extern const char *engine_policy_names[]; extern const char *engine_policy_names[];
...@@ -256,6 +257,7 @@ void engine_compute_next_snapshot_time(struct engine *e); ...@@ -256,6 +257,7 @@ void engine_compute_next_snapshot_time(struct engine *e);
void engine_unskip(struct engine *e); void engine_unskip(struct engine *e);
void engine_drift_all(struct engine *e); void engine_drift_all(struct engine *e);
void engine_drift_top_multipoles(struct engine *e); void engine_drift_top_multipoles(struct engine *e);
void engine_reconstruct_multipoles(struct engine *e);
void engine_dump_snapshot(struct engine *e); void engine_dump_snapshot(struct engine *e);
void engine_init(struct engine *e, struct space *s, void engine_init(struct engine *e, struct space *s,
const struct swift_params *params, int nr_nodes, int nodeID, const struct swift_params *params, int nr_nodes, int nodeID,
......
...@@ -32,6 +32,13 @@ ...@@ -32,6 +32,13 @@
#include "error.h" #include "error.h"
#include "version.h" #include "version.h"
struct exact_force_data {
const struct engine *e;
const struct space *s;
int counter_global;
double const_G;
};
/** /**
* @brief Checks whether the file containing the exact accelerations for * @brief Checks whether the file containing the exact accelerations for
* the current choice of parameters already exists. * the current choice of parameters already exists.
...@@ -83,32 +90,23 @@ int gravity_exact_force_file_exits(const struct engine *e) { ...@@ -83,32 +90,23 @@ int gravity_exact_force_file_exits(const struct engine *e) {
} }
/** /**
* @brief Run a brute-force gravity calculation for a subset of particles. * @brief Mapper function for the exact gravity calculation.
*
* All gpart with ID modulo SWIFT_GRAVITY_FORCE_CHECKS will get their forces
* computed.
*
* @param s The #space to use.
* @param e The #engine (to access the current time).
*/ */
void gravity_exact_force_compute(struct space *s, const struct engine *e) { void gravity_exact_force_compute_mapper(void *map_data, int nr_gparts,
void *extra_data) {
#ifdef SWIFT_GRAVITY_FORCE_CHECKS #ifdef SWIFT_GRAVITY_FORCE_CHECKS
const ticks tic = getticks(); /* Unpack the data */
const double const_G = e->physical_constants->const_newton_G; struct gpart *restrict gparts = (struct gpart *)map_data;
struct exact_force_data *data = (struct exact_force_data *)extra_data;
const struct space *s = data->s;
const struct engine *e = data->e;
const double const_G = data->const_G;
int counter = 0; int counter = 0;
/* Let's start by checking whether we already computed these forces */ for (int i = 0; i < nr_gparts; ++i) {
if (gravity_exact_force_file_exits(e)) {
message("Exact accelerations already computed. Skipping calculation.");
return;
}
/* No matching file present ? Do it then */
for (size_t i = 0; i < s->nr_gparts; ++i) {
struct gpart *gpi = &s->gparts[i]; struct gpart *gpi = &gparts[i];
/* Is the particle active and part of the subset to be tested ? */ /* Is the particle active and part of the subset to be tested ? */
if (gpi->id_or_neg_offset % SWIFT_GRAVITY_FORCE_CHECKS == 0 && if (gpi->id_or_neg_offset % SWIFT_GRAVITY_FORCE_CHECKS == 0 &&
...@@ -118,13 +116,13 @@ void gravity_exact_force_compute(struct space *s, const struct engine *e) { ...@@ -118,13 +116,13 @@ void gravity_exact_force_compute(struct space *s, const struct engine *e) {
double a_grav[3] = {0., 0., 0.}; double a_grav[3] = {0., 0., 0.};
/* Interact it with all other particles in the space.*/ /* Interact it with all other particles in the space.*/
for (size_t j = 0; j < s->nr_gparts; ++j) { for (int j = 0; j < (int)s->nr_gparts; ++j) {
/* No self interaction */
if (i == j) continue;
struct gpart *gpj = &s->gparts[j]; struct gpart *gpj = &s->gparts[j];
/* No self interaction */
if (gpi == gpj) continue;
/* Compute the pairwise distance. */ /* Compute the pairwise distance. */
const double dx[3] = {gpi->x[0] - gpj->x[0], // x const double dx[3] = {gpi->x[0] - gpj->x[0], // x
gpi->x[1] - gpj->x[1], // y gpi->x[1] - gpj->x[1], // y
...@@ -173,9 +171,47 @@ void gravity_exact_force_compute(struct space *s, const struct engine *e) { ...@@ -173,9 +171,47 @@ void gravity_exact_force_compute(struct space *s, const struct engine *e) {
counter++; counter++;
} }
} }
atomic_add(&data->counter_global, counter);
message("Computed exact gravity for %d gparts (took %.3f %s). ", counter, #else
clocks_from_ticks(getticks() - tic), clocks_getunit()); error("Gravity checking function called without the corresponding flag.");
#endif
}
/**
* @brief Run a brute-force gravity calculation for a subset of particles.
*
* All gpart with ID modulo SWIFT_GRAVITY_FORCE_CHECKS will get their forces
* computed.
*
* @param s The #space to use.
* @param e The #engine (to access the current time).
*/
void gravity_exact_force_compute(struct space *s, const struct engine *e) {
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
const ticks tic = getticks();
/* Let's start by checking whether we already computed these forces */
if (gravity_exact_force_file_exits(e)) {
message("Exact accelerations already computed. Skipping calculation.");
return;
}
/* No matching file present ? Do it then */
struct exact_force_data data;
data.e = e;
data.s = s;
data.counter_global = 0;
data.const_G = e->physical_constants->const_newton_G;
threadpool_map(&s->e->threadpool, gravity_exact_force_compute_mapper,
s->gparts, s->nr_gparts, sizeof(struct gpart), 1000, &data);
message("Computed exact gravity for %d gparts (took %.3f %s). ",
data.counter_global, clocks_from_ticks(getticks() - tic),
clocks_getunit());
#else #else
error("Gravity checking function called without the corresponding flag."); error("Gravity checking function called without the corresponding flag.");
......
...@@ -59,7 +59,8 @@ void gravity_props_init(struct gravity_props *p, ...@@ -59,7 +59,8 @@ void gravity_props_init(struct gravity_props *p,
void gravity_props_print(const struct gravity_props *p) { void gravity_props_print(const struct gravity_props *p) {
message("Self-gravity scheme: FMM-MM"); message("Self-gravity scheme: FMM-MM with m-poles of order %d",
SELF_GRAVITY_MULTIPOLE_ORDER);
message("Self-gravity time integration: eta=%.4f", p->eta); message("Self-gravity time integration: eta=%.4f", p->eta);
...@@ -68,7 +69,7 @@ void gravity_props_print(const struct gravity_props *p) { ...@@ -68,7 +69,7 @@ void gravity_props_print(const struct gravity_props *p) {
message("Self-gravity softening: epsilon=%.4f", p->epsilon); message("Self-gravity softening: epsilon=%.4f", p->epsilon);
if (p->a_smooth != gravity_props_default_a_smooth) if (p->a_smooth != gravity_props_default_a_smooth)
message("Self-gravity smoothing-scale: a_smooth=%f", p->a_smooth); message("Self-gravity MM smoothing-scale: a_smooth=%f", p->a_smooth);
if (p->r_cut != gravity_props_default_r_cut) if (p->r_cut != gravity_props_default_r_cut)
message("Self-gravity MM cut-off: r_cut=%f", p->r_cut); message("Self-gravity MM cut-off: r_cut=%f", p->r_cut);
...@@ -81,6 +82,7 @@ void gravity_props_print_snapshot(hid_t h_grpgrav, ...@@ -81,6 +82,7 @@ void gravity_props_print_snapshot(hid_t h_grpgrav,
io_write_attribute_f(h_grpgrav, "Time integration eta", p->eta); io_write_attribute_f(h_grpgrav, "Time integration eta", p->eta);
io_write_attribute_f(h_grpgrav, "Softening length", p->epsilon); io_write_attribute_f(h_grpgrav, "Softening length", p->epsilon);
io_write_attribute_f(h_grpgrav, "Opening angle", p->theta_crit); io_write_attribute_f(h_grpgrav, "Opening angle", p->theta_crit);
io_write_attribute_d(h_grpgrav, "MM order", SELF_GRAVITY_MULTIPOLE_ORDER);
io_write_attribute_f(h_grpgrav, "MM a_smooth", p->a_smooth); io_write_attribute_f(h_grpgrav, "MM a_smooth", p->a_smooth);
io_write_attribute_f(h_grpgrav, "MM r_cut", p->r_cut); io_write_attribute_f(h_grpgrav, "MM r_cut", p->r_cut);
} }
......
...@@ -176,9 +176,15 @@ struct gravity_tensors { ...@@ -176,9 +176,15 @@ struct gravity_tensors {
/*! Centre of mass of the matter dsitribution */ /*! Centre of mass of the matter dsitribution */
double CoM[3]; double CoM[3];
/*! Centre of mass of the matter dsitribution at the last rebuild */
double CoM_rebuild[3];
/*! Upper limit of the CoM<->gpart distance */ /*! Upper limit of the CoM<->gpart distance */
double r_max; double r_max;