diff --git a/src/cell.c b/src/cell.c index 2c4afe81a060103bb3dc239e23233c75c0458ec0..799c3333567653376412f04a6867f2e13a0599a3 100644 --- a/src/cell.c +++ b/src/cell.c @@ -2028,20 +2028,31 @@ void cell_activate_grav_mm_task(struct cell *ci, struct cell *cj, struct scheduler *s) { /* Some constants */ const struct engine *e = s->space->e; + const integertime_t ti_current = e->ti_current; /* Anything to do here? */ if (!cell_is_active_gravity_mm(ci, e) && !cell_is_active_gravity_mm(cj, e)) error("Inactive MM task being activated"); - /* Atomically drift the multipole in ci */ - lock_lock(&ci->mlock); - if (ci->ti_old_multipole < e->ti_current) cell_drift_multipole(ci, e); - if (lock_unlock(&ci->mlock) != 0) error("Impossible to unlock m-pole"); + /* Atomically drift the multipoles in the progenies of ci */ + for (int i = 0; i < 8; i++) { + struct cell *cpi = ci->progeny[i]; + if (cpi != NULL) { + lock_lock(&cpi->mlock); + if (cpi->ti_old_multipole < ti_current) cell_drift_multipole(cpi, e); + if (lock_unlock(&cpi->mlock) != 0) error("Impossible to unlock m-pole"); + } + } - /* Atomically drift the multipole in cj */ - lock_lock(&cj->mlock); - if (cj->ti_old_multipole < e->ti_current) cell_drift_multipole(cj, e); - if (lock_unlock(&cj->mlock) != 0) error("Impossible to unlock m-pole"); + /* Atomically drift the multipoles in the progenies of cj */ + for (int j = 0; j < 8; j++) { + struct cell *cpj = cj->progeny[j]; + if (cpj != NULL) { + lock_lock(&cpj->mlock); + if (cpj->ti_old_multipole < ti_current) cell_drift_multipole(cpj, e); + if (lock_unlock(&cpj->mlock) != 0) error("Impossible to unlock m-pole"); + } + } } /** @@ -2490,7 +2501,7 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { struct cell *ci = t->ci; struct cell *cj = t->cj; const int ci_active = cell_is_active_gravity_mm(ci, e); - const int cj_active = (cj != NULL) ? cell_is_active_gravity_mm(cj, e) : 0; + const int cj_active = cell_is_active_gravity_mm(cj, e); #ifdef WITH_MPI const int ci_nodeID = ci->nodeID; const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; diff --git a/src/engine.c b/src/engine.c index 0b15cc9765b6b59ca82b2bd2c7a8d6c1e9ceebed..148d915cad263fcee1fa5bb12386c61343d1f17d 100644 --- a/src/engine.c +++ b/src/engine.c @@ -2674,9 +2674,29 @@ void engine_count_and_link_tasks_mapper(void *map_data, int num_elements, } #endif - /* Note that we do not need to link the M-M tasks */ - /* since we already did so when splitting the gravity */ - /* tasks. */ + /* Multipole-multipole interaction of progenies */ + } else if (t_type == task_type_grav_mm) { + + atomic_inc(&ci->nr_mm_tasks); + atomic_inc(&cj->nr_mm_tasks); + engine_addlink(e, &ci->grav_mm, t); + engine_addlink(e, &cj->grav_mm, t); + + /* for (int i = 0; i < 8; i++) { */ + /* struct cell *cpi = ci->progeny[i]; */ + /* if (cpi != NULL) { */ + /* atomic_inc(&cpi->nr_mm_tasks); */ + /* engine_addlink(e, &cpi->grav_mm, t); */ + /* } */ + /* } */ + + /* for (int j = 0; j < 8; j++) { */ + /* struct cell *cpj = cj->progeny[j]; */ + /* if (cpj != NULL) { */ + /* atomic_inc(&cpj->nr_mm_tasks); */ + /* engine_addlink(e, &cpj->grav_mm, t); */ + /* } */ + /* } */ } } } diff --git a/src/runner.c b/src/runner.c index 0be6288cbcc0b77fbe9ba3128d820b82a8943480..fc22bd8014edc49612a50fc4ee84d948eaff2205 100644 --- a/src/runner.c +++ b/src/runner.c @@ -2273,7 +2273,7 @@ void *runner_main(void *data) { runner_do_grav_long_range(r, t->ci, 1); break; case task_type_grav_mm: - runner_dopair_grav_mm(r, t->ci, t->cj); + runner_dopair_grav_mm_progenies(r, t->ci, t->cj); break; case task_type_cooling: runner_do_cooling(r, t->ci, 1); diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h index f9d1f833e65f7e6dde6085696dfbcd0719ae2a87..2a9e78a3ede3a16994eb79ddd6bec47ad032e866 100644 --- a/src/runner_doiact_grav.h +++ b/src/runner_doiact_grav.h @@ -1300,8 +1300,35 @@ static INLINE void runner_dopair_grav_mm(struct runner *r, runner_dopair_grav_mm_nonsym(r, ci, cj); else if (do_j) runner_dopair_grav_mm_nonsym(r, cj, ci); - else - error("Running M-M task with two inactive cells."); + /* else */ + /* error("Running M-M task with two inactive cells."); */ +} + +static INLINE void runner_dopair_grav_mm_progenies(struct runner *r, + struct cell *restrict ci, + struct cell *restrict cj) { + + const struct engine *e = r->e; + const struct space *s = e->s; + + /* Loop over all pairs of progenies */ + for (int i = 0; i < 8; i++) { + if (ci->progeny[i] != NULL) { + for (int j = 0; j < 8; j++) { + if (cj->progeny[j] != NULL) { + + struct cell *cpi = ci->progeny[i]; + struct cell *cpj = cj->progeny[j]; + + /* Did we agree to use an M-M interaction here at the last rebuild? */ + if (cell_can_use_pair_mm_rebuild(cpi, cpj, e, s)) { + + runner_dopair_grav_mm(r, cpi, cpj); + } + } + } + } + } } static INLINE void runner_dopair_recursive_grav_pm(struct runner *r, @@ -1631,13 +1658,13 @@ static INLINE void runner_do_grav_long_range(struct runner *r, struct cell *ci, if (ci->ti_old_multipole != e->ti_current) error("Interacting un-drifted multipole"); + /* Get this cell's multipole information */ + struct gravity_tensors *const multi_i = ci->multipole; + /* Find this cell's top-level (great-)parent */ struct cell *top = ci; while (top->parent != NULL) top = top->parent; - /* Flag that contributions will be recieved */ - struct gravity_tensors *const multi_i = ci->multipole; - /* Recover the top-level multipole (for distance checks) */ struct gravity_tensors *const multi_top = top->multipole; const double CoM_rebuild_top[3] = {multi_top->CoM_rebuild[0], diff --git a/src/scheduler.c b/src/scheduler.c index abfa6c549818a0e3c2b85a3cdd65e199557cf6e4..a5da777f45f8075c7c577988eaa5dfbd7d1ca5ed 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -888,20 +888,6 @@ static void scheduler_splittask_gravity(struct task *t, struct scheduler *s) { break; } - /* Should we replace it with an M-M task? */ - if (cell_can_use_pair_mm_rebuild(ci, cj, e, sp)) { - - t->type = task_type_grav_mm; - t->subtype = task_subtype_none; - - /* Since this task will not be split, we can already link it */ - atomic_inc(&ci->nr_mm_tasks); - atomic_inc(&cj->nr_mm_tasks); - engine_addlink(e, &ci->grav_mm, t); - engine_addlink(e, &cj->grav_mm, t); - break; - } - /* Should this task be split-up? */ if (cell_can_split_pair_gravity_task(ci) && cell_can_split_pair_gravity_task(cj)) { @@ -910,37 +896,33 @@ static void scheduler_splittask_gravity(struct task *t, struct scheduler *s) { const long long gcount_j = cj->gcount; /* Replace by a single sub-task? */ - if (scheduler_dosub && /* Use division to avoid integer overflow. */ + if (scheduler_dosub && gcount_i * gcount_j < ((long long)space_subsize_pair_grav)) { /* Otherwise, split it. */ } else { - /* Take a step back (we're going to recycle the current task)... */ - redo = 1; - - /* Find the first non-empty childrens of the cells */ - int first_ci_child = 0, first_cj_child = 0; - while (ci->progeny[first_ci_child] == NULL) first_ci_child++; - while (cj->progeny[first_cj_child] == NULL) first_cj_child++; - - /* Recycle the current pair */ - t->ci = ci->progeny[first_ci_child]; - t->cj = cj->progeny[first_cj_child]; + /* Turn the task into a M-M task that will take care of all the + * progeny pairs */ + t->type = task_type_grav_mm; + t->subtype = task_subtype_none; /* Make a task for every other pair of progeny */ - for (int i = first_ci_child; i < 8; i++) { + for (int i = 0; i < 8; i++) { if (ci->progeny[i] != NULL) { - for (int j = first_cj_child; j < 8; j++) { + for (int j = 0; j < 8; j++) { if (cj->progeny[j] != NULL) { - /* Skip the recycled pair */ - if (i == first_ci_child && j == first_cj_child) continue; + /* But only for pairs that cannot be replaced by a M-M + * interaction */ + if (!cell_can_use_pair_mm_rebuild(ci->progeny[i], + cj->progeny[j], e, sp)) { - scheduler_splittask_gravity( - scheduler_addtask(s, task_type_pair, t->subtype, 0, 0, - ci->progeny[i], cj->progeny[j]), - s); + scheduler_splittask_gravity( + scheduler_addtask(s, task_type_pair, task_subtype_grav, + 0, 0, ci->progeny[i], cj->progeny[j]), + s); + } } } }