Commit fa6bd92d authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

When unskipping gravity tasks, do a full tree walk to set the correct drift flags.

parent e76232f7
...@@ -504,6 +504,8 @@ int main(int argc, char *argv[]) { ...@@ -504,6 +504,8 @@ int main(int argc, char *argv[]) {
fflush(stdout); fflush(stdout);
} }
periodic = 0;
#ifdef SWIFT_DEBUG_CHECKS #ifdef SWIFT_DEBUG_CHECKS
/* Check once and for all that we don't have unwanted links */ /* Check once and for all that we don't have unwanted links */
if (!with_stars) { if (!with_stars) {
......
...@@ -1290,41 +1290,14 @@ void cell_clean(struct cell *c) { ...@@ -1290,41 +1290,14 @@ void cell_clean(struct cell *c) {
if (c->progeny[k]) cell_clean(c->progeny[k]); if (c->progeny[k]) cell_clean(c->progeny[k]);
} }
/**
* @brief Checks whether a given cell needs drifting or not.
*
* @param c the #cell.
* @param e The #engine (holding current time information).
*
* @return 1 If the cell needs drifting, 0 otherwise.
*/
int cell_is_drift_needed(struct cell *c, const struct engine *e) {
/* Do we have at least one active particle in the cell ?*/
if (cell_is_active(c, e)) return 1;
/* Loop over the pair tasks that involve this cell */
for (struct link *l = c->density; l != NULL; l = l->next) {
if (l->t->type != task_type_pair && l->t->type != task_type_sub_pair)
continue;
/* Is the other cell in the pair active ? */
if ((l->t->ci == c && cell_is_active(l->t->cj, e)) ||
(l->t->cj == c && cell_is_active(l->t->ci, e)))
return 1;
}
/* No neighbouring cell has active particles. Drift not necessary */
return 0;
}
/** /**
* @brief Clear the drift flags on the given cell. * @brief Clear the drift flags on the given cell.
*/ */
void cell_clear_drift_flags(struct cell *c, void *data) { void cell_clear_drift_flags(struct cell *c, void *data) {
c->do_drift = 0; c->do_drift = 0;
c->do_sub_drift = 0; c->do_sub_drift = 0;
c->do_grav_drift = 0;
c->do_grav_sub_drift = 0;
} }
/** /**
...@@ -1359,13 +1332,32 @@ void cell_activate_drift_part(struct cell *c, struct scheduler *s) { ...@@ -1359,13 +1332,32 @@ void cell_activate_drift_part(struct cell *c, struct scheduler *s) {
*/ */
void cell_activate_drift_gpart(struct cell *c, struct scheduler *s) { void cell_activate_drift_gpart(struct cell *c, struct scheduler *s) {
scheduler_activate(s, c->super->drift_gpart); /* If this cell is already marked for drift, quit early. */
if (c->do_grav_drift) return;
/* Mark this cell for drifting. */
c->do_grav_drift = 1;
/* Set the do_grav_sub_drifts all the way up and activate the super drift
if this has not yet been done. */
if (c == c->super) {
scheduler_activate(s, c->drift_gpart);
} else {
for (struct cell *parent = c->parent;
parent != NULL && !parent->do_grav_sub_drift;
parent = parent->parent) {
parent->do_grav_sub_drift = 1;
if (parent == c->super) {
scheduler_activate(s, parent->drift_gpart);
break;
}
}
}
} }
/** /**
* @brief Activate the sorts up a cell hierarchy. * @brief Activate the sorts up a cell hierarchy.
*/ */
void cell_activate_sorts_up(struct cell *c, struct scheduler *s) { void cell_activate_sorts_up(struct cell *c, struct scheduler *s) {
if (c == c->super) { if (c == c->super) {
scheduler_activate(s, c->sorts); scheduler_activate(s, c->sorts);
...@@ -1409,7 +1401,8 @@ void cell_activate_sorts(struct cell *c, int sid, struct scheduler *s) { ...@@ -1409,7 +1401,8 @@ void cell_activate_sorts(struct cell *c, int sid, struct scheduler *s) {
} }
/** /**
* @brief Traverse a sub-cell task and activate the sort tasks along the way. * @brief Traverse a sub-cell task and activate the drift and sort tasks along
* the way.
*/ */
void cell_activate_subcell_tasks(struct cell *ci, struct cell *cj, void cell_activate_subcell_tasks(struct cell *ci, struct cell *cj,
struct scheduler *s) { struct scheduler *s) {
...@@ -1676,6 +1669,132 @@ void cell_activate_subcell_tasks(struct cell *ci, struct cell *cj, ...@@ -1676,6 +1669,132 @@ void cell_activate_subcell_tasks(struct cell *ci, struct cell *cj,
} }
} }
/**
* @brief Traverse a sub-cell task and activate the gravity drift tasks
*/
void cell_activate_subcell_grav_tasks(struct cell *ci, struct cell *cj,
struct scheduler *s) {
/* Some constants */
const struct space *sp = s->space;
const struct engine *e = sp->e;
const int periodic = sp->periodic;
const double dim[3] = {sp->dim[0], sp->dim[1], sp->dim[2]};
const double theta_crit = e->gravity_properties->theta_crit;
/* Self interaction? */
if (cj == NULL) {
/* Do anything? */
if (!cell_is_active(ci, e)) return;
/* Recurse? */
if (ci->split) {
/* Loop over all progenies and pairs of progenies */
for (int j = 0; j < 8; j++) {
if (ci->progeny[j] != NULL) {
cell_activate_subcell_grav_tasks(ci->progeny[j], NULL, s);
for (int k = j + 1; k < 8; k++)
if (ci->progeny[k] != NULL)
cell_activate_subcell_grav_tasks(ci->progeny[j], ci->progeny[k],
s);
}
}
} else {
/* We have reached the bottom of the tree: activate gpart drift */
cell_activate_drift_gpart(ci, s);
}
}
/* Pair interaction */
else {
/* Anything to do here? */
if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) return;
/* Recover the multipole information */
struct gravity_tensors *const multi_i = ci->multipole;
struct gravity_tensors *const multi_j = cj->multipole;
const double ri_max = multi_i->r_max;
const double rj_max = multi_j->r_max;
/* Get the distance between the CoMs */
double dx = multi_i->CoM[0] - multi_j->CoM[0];
double dy = multi_i->CoM[1] - multi_j->CoM[1];
double dz = multi_i->CoM[2] - multi_j->CoM[2];
/* Apply BC */
if (periodic) {
dx = nearest(dx, dim[0]);
dy = nearest(dy, dim[1]);
dz = nearest(dz, dim[2]);
}
const double r2 = dx * dx + dy * dy + dz * dz;
/* Can we use multipoles ? */
if (gravity_multipole_accept(multi_i, multi_j, theta_crit, r2)) {
/* Ok, no need to drift anything */
return;
}
/* Otherwise, activate the gpart drifts if we are at the bottom. */
else if (!ci->split && !cj->split) {
/* Activate the drifts if the cells are local. */
if (cell_is_active(ci, e) || cell_is_active(cj, e)) {
if (ci->nodeID == engine_rank) cell_activate_drift_gpart(ci, s);
if (cj->nodeID == engine_rank) cell_activate_drift_gpart(cj, s);
}
}
/* Ok, we can still recurse */
else {
if (ri_max > rj_max) {
if (ci->split) {
/* Loop over ci's children */
for (int k = 0; k < 8; k++) {
if (ci->progeny[k] != NULL)
cell_activate_subcell_grav_tasks(ci->progeny[k], cj, s);
}
} else if (cj->split) {
/* Loop over cj's children */
for (int k = 0; k < 8; k++) {
if (cj->progeny[k] != NULL)
cell_activate_subcell_grav_tasks(ci, cj->progeny[k], s);
}
} else {
error("Fundamental error in the logic");
}
} else if (rj_max >= ri_max) {
if (cj->split) {
/* Loop over cj's children */
for (int k = 0; k < 8; k++) {
if (cj->progeny[k] != NULL)
cell_activate_subcell_grav_tasks(ci, cj->progeny[k], s);
}
} else if (ci->split) {
/* Loop over ci's children */
for (int k = 0; k < 8; k++) {
if (ci->progeny[k] != NULL)
cell_activate_subcell_grav_tasks(ci->progeny[k], cj, s);
}
} else {
error("Fundamental error in the logic");
}
}
}
}
}
/** /**
* @brief Un-skips all the tasks associated with a given cell and checks * @brief Un-skips all the tasks associated with a given cell and checks
* if the space needs to be rebuilt. * if the space needs to be rebuilt.
...@@ -1701,8 +1820,13 @@ int cell_unskip_tasks(struct cell *c, struct scheduler *s) { ...@@ -1701,8 +1820,13 @@ int cell_unskip_tasks(struct cell *c, struct scheduler *s) {
(cj != NULL && cell_is_active(cj, e) && cj->nodeID == engine_rank)) { (cj != NULL && cell_is_active(cj, e) && cj->nodeID == engine_rank)) {
scheduler_activate(s, t); scheduler_activate(s, t);
/* Set the correct sorting flags */ /* Activate hydro drift */
if (t->type == task_type_pair) { if (t->type == task_type_self) {
if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s);
}
/* Set the correct sorting flags and activate hydro drifts */
else if (t->type == task_type_pair) {
/* Store some values. */ /* Store some values. */
atomic_or(&ci->requires_sorts, 1 << t->flags); atomic_or(&ci->requires_sorts, 1 << t->flags);
atomic_or(&cj->requires_sorts, 1 << t->flags); atomic_or(&cj->requires_sorts, 1 << t->flags);
...@@ -1863,9 +1987,10 @@ int cell_unskip_tasks(struct cell *c, struct scheduler *s) { ...@@ -1863,9 +1987,10 @@ int cell_unskip_tasks(struct cell *c, struct scheduler *s) {
scheduler_activate(s, t); scheduler_activate(s, t);
/* Set the drifting flags */ /* Set the drifting flags */
if (t->type == task_type_pair) { if (t->type == task_type_self) {
cell_activate_drift_gpart(ci, s); cell_activate_subcell_grav_tasks(t->ci, NULL, s);
cell_activate_drift_gpart(cj, s); } else if (t->type == task_type_pair) {
cell_activate_subcell_grav_tasks(t->ci, t->cj, s);
} }
} }
} }
...@@ -1955,7 +2080,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { ...@@ -1955,7 +2080,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
/* Check that we are actually going to move forward. */ /* Check that we are actually going to move forward. */
if (ti_current < ti_old_part) error("Attempt to drift to the past"); if (ti_current < ti_old_part) error("Attempt to drift to the past");
#endif // SWIFT_DEBUG_CHECKS #endif
/* Are we not in a leaf ? */ /* Are we not in a leaf ? */
if (c->split && (force || c->do_sub_drift)) { if (c->split && (force || c->do_sub_drift)) {
...@@ -2040,8 +2165,9 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { ...@@ -2040,8 +2165,9 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
* *
* @param c The #cell. * @param c The #cell.
* @param e The #engine (to get ti_current). * @param e The #engine (to get ti_current).
* @param force Drift the particles irrespective of the #cell flags.
*/ */
void cell_drift_gpart(struct cell *c, const struct engine *e) { void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
const double timeBase = e->timeBase; const double timeBase = e->timeBase;
const integertime_t ti_old_gpart = c->ti_old_gpart; const integertime_t ti_old_gpart = c->ti_old_gpart;
...@@ -2053,11 +2179,19 @@ void cell_drift_gpart(struct cell *c, const struct engine *e) { ...@@ -2053,11 +2179,19 @@ void cell_drift_gpart(struct cell *c, const struct engine *e) {
const double dt = (ti_current - ti_old_gpart) * timeBase; const double dt = (ti_current - ti_old_gpart) * timeBase;
float dx_max = 0.f, dx2_max = 0.f; float dx_max = 0.f, dx2_max = 0.f;
/* Drift irrespective of cell flags? */
force |= c->do_grav_drift;
#ifdef SWIFT_DEBUG_CHECKS
/* Check that we only drift local cells. */
if (c->nodeID != engine_rank) error("Drifting a foreign cell is nope.");
/* Check that we are actually going to move forward. */ /* Check that we are actually going to move forward. */
if (ti_current < ti_old_gpart) error("Attempt to drift to the past"); if (ti_current < ti_old_gpart) error("Attempt to drift to the past");
#endif
/* Are we not in a leaf ? */ /* Are we not in a leaf ? */
if (c->split) { if (c->split && (force || c->do_grav_sub_drift)) {
/* Loop over the progeny and collect their data. */ /* Loop over the progeny and collect their data. */
for (int k = 0; k < 8; k++) for (int k = 0; k < 8; k++)
...@@ -2065,13 +2199,19 @@ void cell_drift_gpart(struct cell *c, const struct engine *e) { ...@@ -2065,13 +2199,19 @@ void cell_drift_gpart(struct cell *c, const struct engine *e) {
struct cell *cp = c->progeny[k]; struct cell *cp = c->progeny[k];
/* Recurse */ /* Recurse */
cell_drift_gpart(cp, e); cell_drift_gpart(cp, e, force);
/* Update */ /* Update */
dx_max = max(dx_max, cp->dx_max_gpart); dx_max = max(dx_max, cp->dx_max_gpart);
} }
} else if (ti_current > ti_old_gpart) { /* Store the values */
c->dx_max_gpart = dx_max;
/* Update the time of the last drift */
c->ti_old_gpart = ti_current;
} else if (!c->split && force && ti_current > ti_old_gpart) {
/* Loop over all the g-particles in the cell */ /* Loop over all the g-particles in the cell */
const size_t nr_gparts = c->gcount; const size_t nr_gparts = c->gcount;
...@@ -2111,16 +2251,16 @@ void cell_drift_gpart(struct cell *c, const struct engine *e) { ...@@ -2111,16 +2251,16 @@ void cell_drift_gpart(struct cell *c, const struct engine *e) {
/* Now, get the maximal particle motion from its square */ /* Now, get the maximal particle motion from its square */
dx_max = sqrtf(dx2_max); dx_max = sqrtf(dx2_max);
} else {
dx_max = c->dx_max_gpart;
}
/* Store the values */ /* Store the values */
c->dx_max_gpart = dx_max; c->dx_max_gpart = dx_max;
/* Update the time of the last drift */ /* Update the time of the last drift */
c->ti_old_gpart = ti_current; c->ti_old_gpart = ti_current;
}
/* Clear the drift flags. */
c->do_grav_drift = 0;
c->do_grav_sub_drift = 0;
} }
/** /**
......
...@@ -331,12 +331,18 @@ struct cell { ...@@ -331,12 +331,18 @@ struct cell {
/* Bit mask of sort directions that will be needed in the next timestep. */ /* Bit mask of sort directions that will be needed in the next timestep. */
unsigned int requires_sorts; unsigned int requires_sorts;
/*! Does this cell need to be drifted? */ /*! Does this cell need to be drifted (hydro)? */
char do_drift; char do_drift;
/*! Do any of this cell's sub-cells need to be drifted? */ /*! Do any of this cell's sub-cells need to be drifted (hydro)? */
char do_sub_drift; char do_sub_drift;
/*! Does this cell need to be drifted (gravity)? */
char do_grav_drift;
/*! Do any of this cell's sub-cells need to be drifted (gravity)? */
char do_grav_sub_drift;
/*! Bit mask of sorts that need to be computed for this cell. */ /*! Bit mask of sorts that need to be computed for this cell. */
unsigned int do_sort; unsigned int do_sort;
...@@ -390,17 +396,18 @@ void cell_check_part_drift_point(struct cell *c, void *data); ...@@ -390,17 +396,18 @@ void cell_check_part_drift_point(struct cell *c, void *data);
void cell_check_gpart_drift_point(struct cell *c, void *data); void cell_check_gpart_drift_point(struct cell *c, void *data);
void cell_check_multipole_drift_point(struct cell *c, void *data); void cell_check_multipole_drift_point(struct cell *c, void *data);
void cell_reset_task_counters(struct cell *c); void cell_reset_task_counters(struct cell *c);
int cell_is_drift_needed(struct cell *c, const struct engine *e);
int cell_unskip_tasks(struct cell *c, struct scheduler *s); int cell_unskip_tasks(struct cell *c, struct scheduler *s);
void cell_set_super(struct cell *c, struct cell *super); void cell_set_super(struct cell *c, struct cell *super);
void cell_drift_part(struct cell *c, const struct engine *e, int force); void cell_drift_part(struct cell *c, const struct engine *e, int force);
void cell_drift_gpart(struct cell *c, const struct engine *e); void cell_drift_gpart(struct cell *c, const struct engine *e, int force);
void cell_drift_multipole(struct cell *c, const struct engine *e); void cell_drift_multipole(struct cell *c, const struct engine *e);
void cell_drift_all_multipoles(struct cell *c, const struct engine *e); void cell_drift_all_multipoles(struct cell *c, const struct engine *e);
void cell_check_timesteps(struct cell *c); void cell_check_timesteps(struct cell *c);
void cell_store_pre_drift_values(struct cell *c); void cell_store_pre_drift_values(struct cell *c);
void cell_activate_subcell_tasks(struct cell *ci, struct cell *cj, void cell_activate_subcell_tasks(struct cell *ci, struct cell *cj,
struct scheduler *s); struct scheduler *s);
void cell_activate_subcell_grav_tasks(struct cell *ci, struct cell *cj,
struct scheduler *s);
void cell_activate_drift_part(struct cell *c, struct scheduler *s); void cell_activate_drift_part(struct cell *c, struct scheduler *s);
void cell_activate_drift_gpart(struct cell *c, struct scheduler *s); void cell_activate_drift_gpart(struct cell *c, struct scheduler *s);
void cell_activate_sorts(struct cell *c, int sid, struct scheduler *s); void cell_activate_sorts(struct cell *c, int sid, struct scheduler *s);
......
...@@ -2653,16 +2653,32 @@ void engine_marktasks_mapper(void *map_data, int num_elements, ...@@ -2653,16 +2653,32 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
struct task *t = &tasks[ind]; struct task *t = &tasks[ind];
/* Single-cell task? */ /* Single-cell task? */
if (t->type == task_type_self || t->type == task_type_ghost || if (t->type == task_type_self || t->type == task_type_sub_self) {
t->type == task_type_extra_ghost || t->type == task_type_cooling ||
t->type == task_type_sourceterms || t->type == task_type_sub_self) { /* Local pointer. */
struct cell *ci = t->ci;
if (ci->nodeID != engine_rank) error("Non-local self task found");
/* Set this task's skip. */ /* Set this task's skip. */
if (cell_is_active(t->ci, e)) scheduler_activate(s, t); if (cell_is_active(ci, e)) scheduler_activate(s, t);
/* Activate the hydro drift */
if (t->type == task_type_self && t->subtype == task_subtype_density) {
cell_activate_drift_part(ci, s);
}
/* Activate the gravity drift */
else if (t->type == task_type_self && t->subtype == task_subtype_grav) {
cell_activate_subcell_grav_tasks(t->ci, NULL, s);
}
/* Store current values of dx_max and h_max. */ /* Store current values of dx_max and h_max. */
if (t->type == task_type_sub_self && t->subtype == task_subtype_density) { else if (t->type == task_type_sub_self &&
cell_activate_subcell_tasks(t->ci, NULL, s); t->subtype == task_subtype_density) {
cell_activate_subcell_tasks(ci, NULL, s);
} else if (t->type == task_type_sub_self &&
t->subtype == task_subtype_grav) {
error("Invalid task sub-type encountered");
} }
} }
...@@ -2673,34 +2689,42 @@ void engine_marktasks_mapper(void *map_data, int num_elements, ...@@ -2673,34 +2689,42 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
struct cell *ci = t->ci; struct cell *ci = t->ci;
struct cell *cj = t->cj; struct cell *cj = t->cj;
/* If this task does not involve any active cells, skip it. */
if (!cell_is_active(t->ci, e) && !cell_is_active(t->cj, e)) continue;
/* Only activate tasks that involve a local active cell. */ /* Only activate tasks that involve a local active cell. */
if ((cell_is_active(ci, e) && ci->nodeID == engine_rank) || if ((cell_is_active(ci, e) && ci->nodeID == engine_rank) ||
(cj != NULL && cell_is_active(cj, e) && cj->nodeID == engine_rank)) { (cell_is_active(cj, e) && cj->nodeID == engine_rank)) {
scheduler_activate(s, t); scheduler_activate(s, t);
/* Set the correct sorting flags */ /* Set the correct sorting flags */
if (t->type == task_type_pair && t->subtype == task_subtype_density) { if (t->type == task_type_pair && t->subtype == task_subtype_density) {
/* Store some values. */ /* Store some values. */
atomic_or(&ci->requires_sorts, 1 << t->flags); atomic_or(&ci->requires_sorts, 1 << t->flags);
atomic_or(&cj->requires_sorts, 1 << t->flags); atomic_or(&cj->requires_sorts, 1 << t->flags);
ci->dx_max_sort_old = ci->dx_max_sort; ci->dx_max_sort_old = ci->dx_max_sort;
cj->dx_max_sort_old = cj->dx_max_sort; cj->dx_max_sort_old = cj->dx_max_sort;
/* Activate the drift tasks. */ /* Activate the hydro drift tasks. */
if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s); if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s);
if (cj->nodeID == engine_rank) cell_activate_drift_part(cj, s); if (cj->nodeID == engine_rank) cell_activate_drift_part(cj, s);
/* Check the sorts and activate them if needed. */ /* Check the sorts and activate them if needed. */
cell_activate_sorts(ci, t->flags, s); cell_activate_sorts(ci, t->flags, s);
cell_activate_sorts(cj, t->flags, s); cell_activate_sorts(cj, t->flags, s);
} else if (t->type == task_type_pair &&
t->subtype == task_subtype_grav) {
/* Activate the gravity drift */
cell_activate_subcell_grav_tasks(t->ci, t->cj, s);
} }
/* Store current values of dx_max and h_max. */ /* Store current values of dx_max and h_max. */
else if (t->type == task_type_sub_pair && else if (t->type == task_type_sub_pair &&
t->subtype == task_subtype_density) { t->subtype == task_subtype_density) {
cell_activate_subcell_tasks(t->ci, t->cj, s); cell_activate_subcell_tasks(t->ci, t->cj, s);
} else if (t->type == task_type_sub_pair &&
t->subtype == task_subtype_grav) {
error("Invalid task sub-type encountered");
} }
} }
...@@ -2833,20 +2857,24 @@ void engine_marktasks_mapper(void *map_data, int num_elements, ...@@ -2833,20 +2857,24 @@ void engine_marktasks_mapper(void *map_data, int num_elements,
} }
} }
/* Kick/Drift/init ? */ /* Kick/init ? */
if (t->type == task_type_kick1 || t->type == task_type_kick2 || else if (t->type == task_type_kick1 || t->type == task_type_kick2 ||
t->type == task_type_drift_part || t->type == task_type_drift_gpart ||
t->type == task_type_init_grav) { t->type == task_type_init_grav) {
if (cell_is_active(t->ci, e)) scheduler_activate(s, t); if (cell_is_active(t->ci, e)) scheduler_activate(s, t);
} }
/* Gravity ? */ /* Hydro ghost tasks ? */
else if (t->type == task_type_ghost || t->type == task_type_extra_ghost) {
if (cell_is_active(t->ci, e)) scheduler_activate(s, t);
}