Commit ce5d0537 authored by Peter W. Draper's avatar Peter W. Draper
Browse files

Merge branch 'fix_super_pointer' into 'master'

Fix super pointer

Updated the logic setting the `super` pointer and creating the "hierarchical" tasks (i.e. init, kick, ghost, etc.). Changes involve:

 - Getting rid of the `g_super` pointer. We have only one `super` cell per hierarchy.
 - Set the `super` pointer in a new routine.
 - Have only one routine to construct the hierarchical task to avoid overwriting things.
 - Moved the external gravity task to be a self with a new kind of sub-type.

The last item is necessary for the following reason. If we want to run with only external gravity (no hydro, no normal gravity), which is useful to test this aspect individually, we need to create the tasks. Now, we only create the init/kick tasks for super cells, i.e. cells that have at least one self or pair. So I promoted the external_gravity task to be a self with a new sub_type. 

IMO that's more clean now. What do you think ?

Fix #215.

See merge request !259
parents f15c30bb 8ebc446c
......@@ -7,4 +7,4 @@ then
python makeIC.py 10000
fi
../swift -g -t 2 externalPointMass.yml 2>&1 | tee output.log
../swift -g -t 1 externalPointMass.yml 2>&1 | tee output.log
......@@ -892,3 +892,23 @@ int cell_is_drift_needed(struct cell *c, int ti_current) {
/* No neighbouring cell has active particles. Drift not necessary */
return 0;
}
/**
* @brief Set the super-cell pointers for all cells in a hierarchy.
*
* @param c The top-level #cell to play with.
* @param super Pointer to the deepest cell with tasks in this part of the tree.
*/
void cell_set_super(struct cell *c, struct cell *super) {
/* Are we in a cell with some kind of self/pair task ? */
if (super == NULL && c->nr_tasks > 0) super = c;
/* Set the super-cell */
c->super = super;
/* Recurse */
if (c->split)
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) cell_set_super(c->progeny[k], super);
}
......@@ -130,14 +130,9 @@ struct cell {
/* Parent cell. */
struct cell *parent;
/* Super cell, i.e. the highest-level supercell that has hydro interactions.
*/
/* Super cell, i.e. the highest-level supercell that has pair/self tasks */
struct cell *super;
/* Super cell, i.e. the highest-level supercell that has gravity interactions.
*/
struct cell *gsuper;
/* The task computing this cell's sorts. */
struct task *sorts;
int sortsize;
......@@ -240,5 +235,6 @@ int cell_are_neighbours(const struct cell *restrict ci,
void cell_check_multipole(struct cell *c, void *data);
void cell_clean(struct cell *c);
int cell_is_drift_needed(struct cell *c, int ti_current);
void cell_set_super(struct cell *c, struct cell *super);
#endif /* SWIFT_CELL_H */
......@@ -111,119 +111,57 @@ void engine_addlink(struct engine *e, struct link **l, struct task *t) {
res->next = atomic_swap(l, res);
}
/**
* @brief Generate the gravity hierarchical tasks for a hierarchy of cells -
* i.e. all the O(Npart) tasks.
*
* Tasks are only created here. The dependencies will be added later on.
*
* @param e The #engine.
* @param c The #cell.
* @param gsuper The gsuper #cell.
*/
void engine_make_gravity_hierarchical_tasks(struct engine *e, struct cell *c,
struct cell *gsuper) {
struct scheduler *s = &e->sched;
const int is_with_external_gravity =
(e->policy & engine_policy_external_gravity) ==
engine_policy_external_gravity;
const int is_fixdt = (e->policy & engine_policy_fixdt) == engine_policy_fixdt;
/* Is this the super-cell? */
if (gsuper == NULL && (c->grav != NULL || (!c->split && c->gcount > 0))) {
/* This is the super cell, i.e. the first with gravity tasks attached. */
gsuper = c;
/* Local tasks only... */
if (c->nodeID == e->nodeID) {
/* Add the init task. */
if (c->init == NULL)
c->init = scheduler_addtask(s, task_type_init, task_subtype_none, 0, 0,
c, NULL, 0);
/* Add the kick task that matches the policy. */
if (is_fixdt) {
if (c->kick == NULL)
c->kick = scheduler_addtask(s, task_type_kick_fixdt,
task_subtype_none, 0, 0, c, NULL, 0);
} else {
if (c->kick == NULL)
c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0,
0, c, NULL, 0);
}
if (is_with_external_gravity)
c->grav_external = scheduler_addtask(
s, task_type_grav_external, task_subtype_none, 0, 0, c, NULL, 0);
}
}
/* Set the super-cell. */
c->gsuper = gsuper;
/* Recurse. */
if (c->split)
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL)
engine_make_gravity_hierarchical_tasks(e, c->progeny[k], gsuper);
}
/**
* @brief Generate the hydro hierarchical tasks for a hierarchy of cells -
* i.e. all the O(Npart) tasks.
*
* Tasks are only created here. The dependencies will be added later on.
*
* Note that there is no need to recurse below the super-cell.
*
* @param e The #engine.
* @param c The #cell.
* @param super The super #cell.
*/
void engine_make_hydro_hierarchical_tasks(struct engine *e, struct cell *c,
struct cell *super) {
void engine_make_hierarchical_tasks(struct engine *e, struct cell *c) {
struct scheduler *s = &e->sched;
const int is_fixdt = (e->policy & engine_policy_fixdt) == engine_policy_fixdt;
const int is_with_cooling =
(e->policy & engine_policy_cooling) == engine_policy_cooling;
const int is_with_sourceterms =
(e->policy & engine_policy_sourceterms) == engine_policy_sourceterms;
const int is_fixdt = (e->policy & engine_policy_fixdt);
const int is_hydro = (e->policy & engine_policy_hydro);
const int is_with_cooling = (e->policy & engine_policy_cooling);
const int is_with_sourceterms = (e->policy & engine_policy_sourceterms);
/* Is this the super-cell? */
if (super == NULL && (c->density != NULL || (c->count > 0 && !c->split))) {
/* This is the super cell, i.e. the first with density tasks attached. */
super = c;
/* Are we in a super-cell ? */
if (c->super == c) {
/* Local tasks only... */
if (c->nodeID == e->nodeID) {
/* Add the init task. */
if (c->init == NULL)
c->init = scheduler_addtask(s, task_type_init, task_subtype_none, 0, 0,
c, NULL, 0);
c->init = scheduler_addtask(s, task_type_init, task_subtype_none, 0, 0, c,
NULL, 0);
/* Add the kick task that matches the policy. */
if (is_fixdt) {
if (c->kick == NULL)
c->kick = scheduler_addtask(s, task_type_kick_fixdt,
task_subtype_none, 0, 0, c, NULL, 0);
c->kick = scheduler_addtask(s, task_type_kick_fixdt, task_subtype_none,
0, 0, c, NULL, 0);
} else {
if (c->kick == NULL)
c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0,
0, c, NULL, 0);
c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0, 0,
c, NULL, 0);
}
/* Generate the ghost task. */
c->ghost = scheduler_addtask(s, task_type_ghost, task_subtype_none, 0, 0,
c, NULL, 0);
if (is_hydro)
c->ghost = scheduler_addtask(s, task_type_ghost, task_subtype_none, 0,
0, c, NULL, 0);
#ifdef EXTRA_HYDRO_LOOP
/* Generate the extra ghost task. */
if (is_hydro)
c->extra_ghost = scheduler_addtask(s, task_type_extra_ghost,
task_subtype_none, 0, 0, c, NULL, 0);
#endif
/* Cooling task */
if (is_with_cooling)
c->cooling = scheduler_addtask(s, task_type_cooling, task_subtype_none,
0, 0, c, NULL, 0);
......@@ -232,16 +170,19 @@ void engine_make_hydro_hierarchical_tasks(struct engine *e, struct cell *c,
c->sourceterms = scheduler_addtask(s, task_type_sourceterms,
task_subtype_none, 0, 0, c, NULL, 0);
}
}
/* Set the super-cell. */
c->super = super;
} else { /* We are above the super-cell so need to go deeper */
#ifdef SWIFT_DEBUG_CHECKS
if (c->super != NULL) error("Incorrectly set super pointer");
#endif
/* Recurse. */
if (c->split)
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL)
engine_make_hydro_hierarchical_tasks(e, c->progeny[k], super);
engine_make_hierarchical_tasks(e, c->progeny[k]);
}
}
/**
......@@ -1289,6 +1230,30 @@ void engine_make_gravity_tasks(struct engine *e) {
}
}
void engine_make_external_gravity_tasks(struct engine *e) {
struct space *s = e->s;
struct scheduler *sched = &e->sched;
const int nodeID = e->nodeID;
struct cell *cells = s->cells_top;
const int nr_cells = s->nr_cells;
for (int cid = 0; cid < nr_cells; ++cid) {
struct cell *ci = &cells[cid];
/* Skip cells without gravity particles */
if (ci->gcount == 0) continue;
/* Is that neighbour local ? */
if (ci->nodeID != nodeID) continue;
/* If the cells is local build a self-interaction */
scheduler_addtask(sched, task_type_self, task_subtype_external_grav, 0, 0,
ci, NULL, 0);
}
}
/**
* @brief Constructs the top-level pair tasks for the first hydro loop over
* neighbours
......@@ -1434,11 +1399,27 @@ static inline void engine_make_gravity_dependencies(struct scheduler *sched,
struct cell *c) {
/* init --> gravity --> kick */
scheduler_addunlock(sched, c->gsuper->init, gravity);
scheduler_addunlock(sched, gravity, c->gsuper->kick);
scheduler_addunlock(sched, c->super->init, gravity);
scheduler_addunlock(sched, gravity, c->super->kick);
/* grav_up --> gravity ( --> kick) */
scheduler_addunlock(sched, c->gsuper->grav_up, gravity);
scheduler_addunlock(sched, c->super->grav_up, gravity);
}
/**
* @brief Creates the dependency network for the external gravity tasks of a
* given cell.
*
* @param sched The #scheduler.
* @param gravity The gravity task to link.
* @param c The cell.
*/
static inline void engine_make_external_gravity_dependencies(
struct scheduler *sched, struct task *gravity, struct cell *c) {
/* init --> external gravity --> kick */
scheduler_addunlock(sched, c->super->init, gravity);
scheduler_addunlock(sched, gravity, c->super->kick);
}
/**
......@@ -1480,19 +1461,27 @@ void engine_link_gravity_tasks(struct engine *e) {
/* Gather the multipoles --> mm interaction --> kick */
scheduler_addunlock(sched, gather, t);
scheduler_addunlock(sched, t, t->ci->gsuper->kick);
scheduler_addunlock(sched, t, t->ci->super->kick);
/* init --> mm interaction */
scheduler_addunlock(sched, t->ci->gsuper->init, t);
scheduler_addunlock(sched, t->ci->super->init, t);
}
/* Self-interaction? */
/* Self-interaction for self-gravity? */
if (t->type == task_type_self && t->subtype == task_subtype_grav) {
engine_make_gravity_dependencies(sched, t, t->ci);
}
/* Self-interaction for external gravity ? */
else if (t->type == task_type_self &&
t->subtype == task_subtype_external_grav) {
engine_make_external_gravity_dependencies(sched, t, t->ci);
}
/* Otherwise, pair interaction? */
else if (t->type == task_type_pair && t->subtype == task_subtype_grav) {
......@@ -1501,7 +1490,7 @@ void engine_link_gravity_tasks(struct engine *e) {
engine_make_gravity_dependencies(sched, t, t->ci);
}
if (t->cj->nodeID == nodeID && t->ci->gsuper != t->cj->gsuper) {
if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) {
engine_make_gravity_dependencies(sched, t, t->cj);
}
......@@ -1516,6 +1505,15 @@ void engine_link_gravity_tasks(struct engine *e) {
}
}
/* Sub-self-interaction for external gravity ? */
else if (t->type == task_type_sub_self &&
t->subtype == task_subtype_external_grav) {
if (t->ci->nodeID == nodeID) {
engine_make_external_gravity_dependencies(sched, t, t->ci);
}
}
/* Otherwise, sub-pair interaction? */
else if (t->type == task_type_sub_pair && t->subtype == task_subtype_grav) {
......@@ -1523,7 +1521,7 @@ void engine_link_gravity_tasks(struct engine *e) {
engine_make_gravity_dependencies(sched, t, t->ci);
}
if (t->cj->nodeID == nodeID && t->ci->gsuper != t->cj->gsuper) {
if (t->cj->nodeID == nodeID && t->ci->super != t->cj->super) {
engine_make_gravity_dependencies(sched, t, t->cj);
}
......@@ -1790,12 +1788,6 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) {
}
#endif
}
/* External gravity tasks should depend on init and unlock the kick */
else if (t->type == task_type_grav_external) {
scheduler_addunlock(sched, t->ci->init, t);
scheduler_addunlock(sched, t, t->ci->kick);
}
/* Cooling tasks should depend on kick and unlock sourceterms */
else if (t->type == task_type_cooling) {
scheduler_addunlock(sched, t->ci->kick, t);
......@@ -1871,6 +1863,13 @@ void engine_maketasks(struct engine *e) {
/* Add the gravity mm tasks. */
if (e->policy & engine_policy_self_gravity) engine_make_gravity_tasks(e);
/* Add the external gravity tasks. */
if (e->policy & engine_policy_external_gravity)
engine_make_external_gravity_tasks(e);
if (e->sched.nr_tasks == 0 && (s->nr_gparts > 0 || s->nr_parts > 0))
error("We have particles but no hydro or gravity tasks were created.");
/* Split the tasks. */
scheduler_splittasks(sched);
......@@ -1894,25 +1893,24 @@ void engine_maketasks(struct engine *e) {
/* Count the number of tasks associated with each cell and
store the density tasks in each cell, and make each sort
depend on the sorts of its progeny. */
if (e->policy & engine_policy_hydro) engine_count_and_link_tasks(e);
engine_count_and_link_tasks(e);
/* Append hierarchical tasks to each cells */
if (e->policy & engine_policy_hydro)
for (int k = 0; k < nr_cells; k++)
engine_make_hydro_hierarchical_tasks(e, &cells[k], NULL);
/* Now that the self/pair tasks are at the right level, set the super
* pointers. */
for (int k = 0; k < nr_cells; k++) cell_set_super(&cells[k], NULL);
if ((e->policy & engine_policy_self_gravity) ||
(e->policy & engine_policy_external_gravity))
/* Append hierarchical tasks to each cells */
for (int k = 0; k < nr_cells; k++)
engine_make_gravity_hierarchical_tasks(e, &cells[k], NULL);
engine_make_hierarchical_tasks(e, &cells[k]);
/* Run through the tasks and make force tasks for each density task.
Each force task depends on the cell ghosts and unlocks the kick task
of its super-cell. */
if (e->policy & engine_policy_hydro) engine_make_extra_hydroloop_tasks(e);
/* Add the dependencies for the self-gravity stuff */
if (e->policy & engine_policy_self_gravity) engine_link_gravity_tasks(e);
/* Add the dependencies for the gravity stuff */
if (e->policy & (engine_policy_self_gravity | engine_policy_external_gravity))
engine_link_gravity_tasks(e);
#ifdef WITH_MPI
......@@ -2654,7 +2652,10 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs) {
/* Add the tasks corresponding to external gravity to the masks */
if (e->policy & engine_policy_external_gravity) {
mask |= 1 << task_type_grav_external;
mask |= 1 << task_type_self;
mask |= 1 << task_type_sub_self;
submask |= 1 << task_subtype_external_grav;
}
/* Add MPI tasks if need be */
......@@ -2823,7 +2824,11 @@ void engine_step(struct engine *e) {
/* Add the tasks corresponding to external gravity to the masks */
if (e->policy & engine_policy_external_gravity) {
mask |= 1 << task_type_grav_external;
mask |= 1 << task_type_self;
mask |= 1 << task_type_sub_self;
submask |= 1 << task_subtype_external_grav;
}
/* Add the tasks corresponding to cooling to the masks */
......
......@@ -184,12 +184,12 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) {
for (int i = 0; i < gcount; i++) {
/* Get a direct pointer on the part. */
struct gpart *restrict g = &gparts[i];
struct gpart *restrict gp = &gparts[i];
/* Is this part within the time step? */
if (g->ti_end <= ti_current) {
if (gp->ti_end <= ti_current) {
external_gravity_acceleration(time, potential, constants, g);
external_gravity_acceleration(time, potential, constants, gp);
}
}
......@@ -1280,9 +1280,12 @@ void *runner_main(void *data) {
runner_doself2_force(r, ci);
else if (t->subtype == task_subtype_grav)
runner_doself_grav(r, ci, 1);
else if (t->subtype == task_subtype_external_grav)
runner_do_grav_external(r, ci, 1);
else
error("Unknown task subtype.");
break;
case task_type_pair:
if (t->subtype == task_subtype_density)
runner_dopair1_density(r, ci, cj);
......@@ -1297,9 +1300,7 @@ void *runner_main(void *data) {
else
error("Unknown task subtype.");
break;
case task_type_sort:
runner_do_sort(r, ci, t->flags, 1);
break;
case task_type_sub_self:
if (t->subtype == task_subtype_density)
runner_dosub_self1_density(r, ci, 1);
......@@ -1311,9 +1312,12 @@ void *runner_main(void *data) {
runner_dosub_self2_force(r, ci, 1);
else if (t->subtype == task_subtype_grav)
runner_dosub_grav(r, ci, cj, 1);
else if (t->subtype == task_subtype_external_grav)
runner_do_grav_external(r, ci, 1);
else
error("Unknown task subtype.");
break;
case task_type_sub_pair:
if (t->subtype == task_subtype_density)
runner_dosub_pair1_density(r, ci, cj, t->flags, 1);
......@@ -1328,6 +1332,10 @@ void *runner_main(void *data) {
else
error("Unknown task subtype.");
break;
case task_type_sort:
runner_do_sort(r, ci, t->flags, 1);
break;
case task_type_init:
runner_do_init(r, ci, 1);
break;
......@@ -1371,9 +1379,6 @@ void *runner_main(void *data) {
case task_type_grav_fft:
runner_do_grav_fft(r);
break;
case task_type_grav_external:
runner_do_grav_external(r, t->ci, 1);
break;
case task_type_cooling:
runner_do_cooling(r, t->ci, 1);
break;
......
......@@ -1110,20 +1110,10 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) {
break;
case task_type_pair:
case task_type_sub_pair:
if (t->subtype == task_subtype_grav) {
qid = t->ci->gsuper->owner;
if (qid < 0 ||
s->queues[qid].count > s->queues[t->cj->gsuper->owner].count)
qid = t->cj->gsuper->owner;
} else {
qid = t->ci->super->owner;
if (qid < 0 ||
s->queues[qid].count > s->queues[t->cj->super->owner].count)
qid = t->cj->super->owner;
}
break;
case task_type_recv:
#ifdef WITH_MPI
......
......@@ -335,7 +335,6 @@ void space_regrid(struct space *s, double cell_max, int verbose) {
c->count = 0;
c->gcount = 0;
c->super = c;
c->gsuper = c;
c->ti_old = ti_current;
lock_init(&c->lock);
}
......@@ -408,7 +407,6 @@ void space_regrid(struct space *s, double cell_max, int verbose) {
s->cells_top[k].ghost = NULL;
s->cells_top[k].kick = NULL;
s->cells_top[k].super = &s->cells_top[k];
s->cells_top[k].gsuper = &s->cells_top[k];
}
s->maxdepth = 0;
}
......@@ -1480,7 +1478,6 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) {
temp->nodeID = c->nodeID;
temp->parent = c;
temp->super = NULL;
temp->gsuper = NULL;
c->progeny[k] = temp;
}
......
......@@ -51,10 +51,10 @@ const char *taskID_names[task_type_count] = {
"none", "sort", "self", "pair", "sub_self",
"sub_pair", "init", "ghost", "extra_ghost", "kick",
"kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft",
"grav_mm", "grav_up", "grav_external", "cooling", "sourceterms"};
"grav_mm", "grav_up", "cooling", "sourceterms"};
const char *subtaskID_names[task_subtype_count] = {
"none", "density", "gradient", "force", "grav", "tend"};
"none", "density", "gradient", "force", "grav", "external_grav", "tend"};
/**
* @brief Computes the overlap between the parts array of two given cells.
......@@ -135,6 +135,7 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
break;
case task_subtype_grav:
case task_subtype_external_grav:
return task_action_gpart;
break;
......@@ -150,7 +151,14 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
case task_type_kick_fixdt:
case task_type_send:
case task_type_recv:
if (t->ci->count > 0 && t->ci->gcount > 0)
return task_action_all;
else if (t->ci->count > 0)
return task_action_part;
else if (t->ci->gcount > 0)
return task_action_gpart;
else
error("Task without particles");
break;
case task_type_grav_gather_m:
......@@ -160,10 +168,6 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
return task_action_multipole;
break;
case task_type_grav_external:
return task_action_gpart;
break;
default:
error("Unknown task_action for task");
return task_action_none;
......@@ -393,3 +397,15 @@ void task_print_submask(unsigned int submask) {
printf(" %s=%s", subtaskID_names[k], (submask & (1 << k)) ? "yes" : "no");
printf(" ]\n");
}
/**
* @brief Print basic information about a task.
*
* @param t The #task.
*/
void task_print(const struct task *t) {
message("Type:'%s' sub_type:'%s' wait=%d nr_unlocks=%d skip=%d",
taskID_names[t->type], subtaskID_names[t->subtype], t->wait,
t->nr_unlock_tasks, t->skip);
}
......@@ -53,7 +53,6 @@ enum task_types {
task_type_grav_fft,
task_type_grav_mm,
task_type_grav_up,
task_type_grav_external,
task_type_cooling,
task_type_sourceterms,
task_type_count
......@@ -68,6 +67,7 @@ enum task_subtypes {
task_subtype_gradient,
task_subtype_force,
task_subtype_grav,
task_subtype_external_grav,
task_subtype_tend,
task_subtype_count
} __attribute__((packed));
......@@ -160,5 +160,6 @@ int task_lock(struct task *t);
void task_print_mask(unsigned int mask);