diff --git a/src/cell.c b/src/cell.c index 2e49e57d1f3e3c6566d37222adcd2273be0c33c5..23a444030dbbc71b34f060e9ca098b0e854b3652 100644 --- a/src/cell.c +++ b/src/cell.c @@ -1882,6 +1882,8 @@ void cell_clean_links(struct cell *c, void *data) { c->grav.mm = NULL; c->stars.density = NULL; c->stars.feedback = NULL; + c->black_holes.density = NULL; + c->black_holes.feedback = NULL; } /** @@ -2407,6 +2409,44 @@ void cell_activate_drift_spart(struct cell *c, struct scheduler *s) { } } +/** + * @brief Activate the #bpart drifts on the given cell. + */ +void cell_activate_drift_bpart(struct cell *c, struct scheduler *s) { + + /* If this cell is already marked for drift, quit early. */ + if (cell_get_flag(c, cell_flag_do_bh_drift)) return; + + /* Mark this cell for drifting. */ + cell_set_flag(c, cell_flag_do_bh_drift); + + /* Set the do_black_holes_sub_drifts all the way up and activate the super + drift if this has not yet been done. */ + if (c == c->hydro.super) { +#ifdef SWIFT_DEBUG_CHECKS + if (c->black_holes.drift == NULL) + error("Trying to activate un-existing c->black_holes.drift"); +#endif + scheduler_activate(s, c->black_holes.drift); + } else { + for (struct cell *parent = c->parent; + parent != NULL && !cell_get_flag(parent, cell_flag_do_bh_sub_drift); + parent = parent->parent) { + /* Mark this cell for drifting */ + cell_set_flag(parent, cell_flag_do_bh_sub_drift); + + if (parent == c->hydro.super) { +#ifdef SWIFT_DEBUG_CHECKS + if (parent->black_holes.drift == NULL) + error("Trying to activate un-existing parent->black_holes.drift"); +#endif + scheduler_activate(s, parent->black_holes.drift); + break; + } + } + } +} + /** * @brief Activate the drifts on the given cell. */ @@ -2508,7 +2548,6 @@ void cell_activate_stars_sorts_up(struct cell *c, struct scheduler *s) { #endif scheduler_activate(s, c->stars.sorts); if (c->nodeID == engine_rank) { - // MATTHIEU: to do: do we actually need both drifts here? cell_activate_drift_spart(c, s); } } else { @@ -2758,6 +2797,100 @@ void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, } /* Otherwise, pair interation */ } +/** + * @brief Traverse a sub-cell task and activate the black_holes drift tasks that + * are required by a black_holes task + * + * @param ci The first #cell we recurse in. + * @param cj The second #cell we recurse in. + * @param s The task #scheduler. + */ +void cell_activate_subcell_black_holes_tasks(struct cell *ci, struct cell *cj, + struct scheduler *s) { + const struct engine *e = s->space->e; + + /* Store the current dx_max and h_max values. */ + ci->black_holes.dx_max_part_old = ci->black_holes.dx_max_part; + ci->black_holes.h_max_old = ci->black_holes.h_max; + ci->hydro.dx_max_part_old = ci->hydro.dx_max_part; + ci->hydro.h_max_old = ci->hydro.h_max; + + if (cj != NULL) { + cj->black_holes.dx_max_part_old = cj->black_holes.dx_max_part; + cj->black_holes.h_max_old = cj->black_holes.h_max; + cj->hydro.dx_max_part_old = cj->hydro.dx_max_part; + cj->hydro.h_max_old = cj->hydro.h_max; + } + + /* Self interaction? */ + if (cj == NULL) { + /* Do anything? */ + if (!cell_is_active_black_holes(ci, e) || ci->hydro.count == 0 || + ci->black_holes.count == 0) + return; + + /* Recurse? */ + if (cell_can_recurse_in_self_black_holes_task(ci)) { + /* Loop over all progenies and pairs of progenies */ + for (int j = 0; j < 8; j++) { + if (ci->progeny[j] != NULL) { + cell_activate_subcell_black_holes_tasks(ci->progeny[j], NULL, s); + for (int k = j + 1; k < 8; k++) + if (ci->progeny[k] != NULL) + cell_activate_subcell_black_holes_tasks(ci->progeny[j], + ci->progeny[k], s); + } + } + } else { + /* We have reached the bottom of the tree: activate drift */ + cell_activate_drift_bpart(ci, s); + cell_activate_drift_part(ci, s); + } + } + + /* Otherwise, pair interation */ + else { + /* Should we even bother? */ + if (!cell_is_active_black_holes(ci, e) && + !cell_is_active_black_holes(cj, e)) + return; + + /* Get the orientation of the pair. */ + double shift[3]; + int sid = space_getsid(s->space, &ci, &cj, shift); + + /* recurse? */ + if (cell_can_recurse_in_pair_black_holes_task(ci, cj) && + cell_can_recurse_in_pair_black_holes_task(cj, ci)) { + struct cell_split_pair *csp = &cell_split_pairs[sid]; + for (int k = 0; k < csp->count; k++) { + const int pid = csp->pairs[k].pid; + const int pjd = csp->pairs[k].pjd; + if (ci->progeny[pid] != NULL && cj->progeny[pjd] != NULL) + cell_activate_subcell_black_holes_tasks(ci->progeny[pid], + cj->progeny[pjd], s); + } + } + + /* Otherwise, activate the sorts and drifts. */ + else { + if (cell_is_active_black_holes(ci, e)) { + + /* Activate the drifts if the cells are local. */ + if (ci->nodeID == engine_rank) cell_activate_drift_bpart(ci, s); + if (cj->nodeID == engine_rank) cell_activate_drift_part(cj, s); + } + + if (cell_is_active_black_holes(cj, e)) { + + /* Activate the drifts if the cells are local. */ + if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s); + if (cj->nodeID == engine_rank) cell_activate_drift_bpart(cj, s); + } + } + } /* Otherwise, pair interation */ +} + /** * @brief Traverse a sub-cell task and activate the gravity drift tasks that * are required by a self gravity task. @@ -2917,9 +3050,13 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { struct engine *e = s->space->e; const int nodeID = e->nodeID; const int with_limiter = (e->policy & engine_policy_limiter); + #ifdef WITH_MPI + const int with_star_formation = e->policy & engine_policy_star_formation; + const int with_feedback = e->policy & engine_policy_feedback; + #endif int rebuild = 0; @@ -2986,27 +3123,30 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { if (ci_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ if (cj_active) { - scheduler_activate(s, ci->mpi.hydro.recv_xv); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_xv); if (ci_active) { - scheduler_activate(s, ci->mpi.hydro.recv_rho); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_rho); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate(s, ci->mpi.hydro.recv_gradient); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_gradient); #endif } } /* If the foreign cell is active, we want its ti_end values. */ if (ci_active || with_limiter) - scheduler_activate(s, ci->mpi.hydro.recv_ti); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_part); - if (with_limiter) scheduler_activate(s, ci->mpi.limiter.recv); if (with_limiter) - scheduler_activate_send(s, cj->mpi.limiter.send, ci->nodeID); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_limiter); + if (with_limiter) + scheduler_activate_send(s, cj->mpi.send, task_subtype_limiter, + ci->nodeID); /* Is the foreign cell active and will need stuff from us? */ if (ci_active) { - scheduler_activate_send(s, cj->mpi.hydro.send_xv, ci_nodeID); + + scheduler_activate_send(s, cj->mpi.send, task_subtype_xv, ci_nodeID); /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ @@ -3015,54 +3155,69 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* If the local cell is also active, more stuff will be needed. */ if (cj_active) { - scheduler_activate_send(s, cj->mpi.hydro.send_rho, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_rho, + ci_nodeID); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate_send(s, cj->mpi.hydro.send_gradient, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_gradient, + ci_nodeID); #endif } } /* If the local cell is active, send its ti_end values. */ if (cj_active || with_limiter) - scheduler_activate_send(s, cj->mpi.hydro.send_ti, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_part, + ci_nodeID); /* Propagating new star counts? */ + if (with_star_formation && with_feedback) { + if (ci_active && ci->hydro.count > 0) { + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_sf_counts); - scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart); + + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart); } + if (cj_active && cj->hydro.count > 0) { - scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts, ci_nodeID); - scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart, ci_nodeID); + + scheduler_activate_send(s, cj->mpi.send, task_subtype_sf_counts, + ci_nodeID); + + scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart, + ci_nodeID); } } } else if (cj_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ if (ci_active) { - scheduler_activate(s, cj->mpi.hydro.recv_xv); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_xv); if (cj_active) { - scheduler_activate(s, cj->mpi.hydro.recv_rho); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_rho); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate(s, cj->mpi.hydro.recv_gradient); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_gradient); #endif } } /* If the foreign cell is active, we want its ti_end values. */ if (cj_active || with_limiter) - scheduler_activate(s, cj->mpi.hydro.recv_ti); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_part); - if (with_limiter) scheduler_activate(s, cj->mpi.limiter.recv); if (with_limiter) - scheduler_activate_send(s, ci->mpi.limiter.send, cj->nodeID); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_limiter); + if (with_limiter) + scheduler_activate_send(s, ci->mpi.send, task_subtype_limiter, + cj->nodeID); /* Is the foreign cell active and will need stuff from us? */ if (cj_active) { - scheduler_activate_send(s, ci->mpi.hydro.send_xv, cj_nodeID); + + scheduler_activate_send(s, ci->mpi.send, task_subtype_xv, cj_nodeID); /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ @@ -3071,27 +3226,40 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* If the local cell is also active, more stuff will be needed. */ if (ci_active) { - scheduler_activate_send(s, ci->mpi.hydro.send_rho, cj_nodeID); + + scheduler_activate_send(s, ci->mpi.send, task_subtype_rho, + cj_nodeID); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate_send(s, ci->mpi.hydro.send_gradient, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_gradient, + cj_nodeID); #endif } } /* If the local cell is active, send its ti_end values. */ if (ci_active || with_limiter) - scheduler_activate_send(s, ci->mpi.hydro.send_ti, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_part, + cj_nodeID); /* Propagating new star counts? */ + if (with_star_formation && with_feedback) { + if (cj_active && cj->hydro.count > 0) { + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_sf_counts); - scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart); + + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart); } + if (ci_active && ci->hydro.count > 0) { - scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts, cj_nodeID); - scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart, cj_nodeID); + + scheduler_activate_send(s, ci->mpi.send, task_subtype_sf_counts, + cj_nodeID); + + scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart, + cj_nodeID); } } } @@ -3183,14 +3351,18 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { /* Activate the send/recv tasks. */ if (ci_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ - if (cj_active) scheduler_activate(s, ci->mpi.grav.recv); + if (cj_active) + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_gpart); /* If the foreign cell is active, we want its ti_end values. */ - if (ci_active) scheduler_activate(s, ci->mpi.grav.recv_ti); + if (ci_active) + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_gpart); /* Is the foreign cell active and will need stuff from us? */ if (ci_active) { - scheduler_activate_send(s, cj->mpi.grav.send, ci_nodeID); + + scheduler_activate_send(s, cj->mpi.send, task_subtype_gpart, + ci_nodeID); /* Drift the cell which will be sent at the level at which it is sent, i.e. drift the cell specified in the send task (l->t) @@ -3200,18 +3372,23 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { /* If the local cell is active, send its ti_end values. */ if (cj_active) - scheduler_activate_send(s, cj->mpi.grav.send_ti, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_gpart, + ci_nodeID); } else if (cj_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ - if (ci_active) scheduler_activate(s, cj->mpi.grav.recv); + if (ci_active) + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_gpart); /* If the foreign cell is active, we want its ti_end values. */ - if (cj_active) scheduler_activate(s, cj->mpi.grav.recv_ti); + if (cj_active) + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_gpart); /* Is the foreign cell active and will need stuff from us? */ if (cj_active) { - scheduler_activate_send(s, ci->mpi.grav.send, cj_nodeID); + + scheduler_activate_send(s, ci->mpi.send, task_subtype_gpart, + cj_nodeID); /* Drift the cell which will be sent at the level at which it is sent, i.e. drift the cell specified in the send task (l->t) @@ -3221,7 +3398,8 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { /* If the local cell is active, send its ti_end values. */ if (ci_active) - scheduler_activate_send(s, ci->mpi.grav.send_ti, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_gpart, + cj_nodeID); } #endif } @@ -3377,26 +3555,28 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { /* Activate the send/recv tasks. */ if (ci_nodeID != nodeID) { if (cj_active) { - scheduler_activate(s, ci->mpi.hydro.recv_xv); - scheduler_activate(s, ci->mpi.hydro.recv_rho); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_xv); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_rho); /* If the local cell is active, more stuff will be needed. */ - scheduler_activate_send(s, cj->mpi.stars.send, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_spart, + ci_nodeID); cell_activate_drift_spart(cj, s); /* If the local cell is active, send its ti_end values. */ - scheduler_activate_send(s, cj->mpi.stars.send_ti, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_spart, + ci_nodeID); } if (ci_active) { - scheduler_activate(s, ci->mpi.stars.recv); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_spart); /* If the foreign cell is active, we want its ti_end values. */ - scheduler_activate(s, ci->mpi.stars.recv_ti); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_spart); /* Is the foreign cell active and will need stuff from us? */ - scheduler_activate_send(s, cj->mpi.hydro.send_xv, ci_nodeID); - scheduler_activate_send(s, cj->mpi.hydro.send_rho, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_xv, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_rho, ci_nodeID); /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ @@ -3406,26 +3586,28 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { } else if (cj_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ if (ci_active) { - scheduler_activate(s, cj->mpi.hydro.recv_xv); - scheduler_activate(s, cj->mpi.hydro.recv_rho); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_xv); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_rho); /* If the local cell is active, more stuff will be needed. */ - scheduler_activate_send(s, ci->mpi.stars.send, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_spart, + cj_nodeID); cell_activate_drift_spart(ci, s); /* If the local cell is active, send its ti_end values. */ - scheduler_activate_send(s, ci->mpi.stars.send_ti, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_spart, + cj_nodeID); } if (cj_active) { - scheduler_activate(s, cj->mpi.stars.recv); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_spart); /* If the foreign cell is active, we want its ti_end values. */ - scheduler_activate(s, cj->mpi.stars.recv_ti); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_spart); /* Is the foreign cell active and will need stuff from us? */ - scheduler_activate_send(s, ci->mpi.hydro.send_xv, cj_nodeID); - scheduler_activate_send(s, ci->mpi.hydro.send_rho, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_xv, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_rho, cj_nodeID); /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ @@ -3491,6 +3673,205 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { return rebuild; } +/** + * @brief Un-skips all the black hole tasks associated with a given cell and + * checks if the space needs to be rebuilt. + * + * @param c the #cell. + * @param s the #scheduler. + * + * @return 1 If the space needs rebuilding. 0 otherwise. + */ +int cell_unskip_black_holes_tasks(struct cell *c, struct scheduler *s) { + struct engine *e = s->space->e; + const int nodeID = e->nodeID; + int rebuild = 0; + + if (c->black_holes.drift != NULL && cell_is_active_black_holes(c, e)) { + cell_activate_drift_bpart(c, s); + } + + /* Un-skip the density tasks involved with this cell. */ + for (struct link *l = c->black_holes.density; l != NULL; l = l->next) { + struct task *t = l->t; + struct cell *ci = t->ci; + struct cell *cj = t->cj; + const int ci_active = cell_is_active_black_holes(ci, e); + const int cj_active = (cj != NULL) ? cell_is_active_black_holes(cj, e) : 0; +#ifdef WITH_MPI + const int ci_nodeID = ci->nodeID; + const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; +#else + const int ci_nodeID = nodeID; + const int cj_nodeID = nodeID; +#endif + + /* Activate the drifts */ + if (t->type == task_type_self && ci_active) { + cell_activate_drift_part(ci, s); + cell_activate_drift_bpart(ci, s); + } + + /* Only activate tasks that involve a local active cell. */ + if ((ci_active || cj_active) && + (ci_nodeID == nodeID || cj_nodeID == nodeID)) { + scheduler_activate(s, t); + + if (t->type == task_type_pair) { + /* Do ci */ + if (ci_active) { + + /* Activate the drift tasks. */ + if (ci_nodeID == nodeID) cell_activate_drift_bpart(ci, s); + if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); + } + + /* Do cj */ + if (cj_active) { + + /* Activate the drift tasks. */ + if (cj_nodeID == nodeID) cell_activate_drift_bpart(cj, s); + if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); + } + } + + else if (t->type == task_type_sub_pair || t->type == task_type_sub_self) { + cell_activate_subcell_black_holes_tasks(ci, cj, s); + } + } + + /* Only interested in pair interactions as of here. */ + if (t->type == task_type_pair || t->type == task_type_sub_pair) { + /* Check whether there was too much particle motion, i.e. the + cell neighbour conditions were violated. */ + if (cell_need_rebuild_for_black_holes_pair(ci, cj)) rebuild = 1; + if (cell_need_rebuild_for_black_holes_pair(cj, ci)) rebuild = 1; + +#ifdef WITH_MPI + /* Activate the send/recv tasks. */ + if (ci_nodeID != nodeID) { + if (cj_active) { + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_xv); + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_rho); + + /* If the local cell is active, more stuff will be needed. */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_bpart, + ci_nodeID); + cell_activate_drift_bpart(cj, s); + + /* If the local cell is active, send its ti_end values. */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_tend_bpart, + ci_nodeID); + } + + if (ci_active) { + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_bpart); + + /* If the foreign cell is active, we want its ti_end values. */ + scheduler_activate_recv(s, ci->mpi.recv, task_subtype_tend_bpart); + + /* Is the foreign cell active and will need stuff from us? */ + scheduler_activate_send(s, cj->mpi.send, task_subtype_xv, ci_nodeID); + scheduler_activate_send(s, cj->mpi.send, task_subtype_rho, ci_nodeID); + + /* Drift the cell which will be sent; note that not all sent + particles will be drifted, only those that are needed. */ + cell_activate_drift_part(cj, s); + } + + } else if (cj_nodeID != nodeID) { + /* If the local cell is active, receive data from the foreign cell. */ + if (ci_active) { + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_xv); + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_rho); + + /* If the local cell is active, more stuff will be needed. */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_bpart, + cj_nodeID); + cell_activate_drift_bpart(ci, s); + + /* If the local cell is active, send its ti_end values. */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_tend_bpart, + cj_nodeID); + } + + if (cj_active) { + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_bpart); + + /* If the foreign cell is active, we want its ti_end values. */ + scheduler_activate_recv(s, cj->mpi.recv, task_subtype_tend_bpart); + + /* Is the foreign cell active and will need stuff from us? */ + scheduler_activate_send(s, ci->mpi.send, task_subtype_xv, cj_nodeID); + scheduler_activate_send(s, ci->mpi.send, task_subtype_rho, cj_nodeID); + + /* Drift the cell which will be sent; note that not all sent + particles will be drifted, only those that are needed. */ + cell_activate_drift_part(ci, s); + } + } +#endif + } + } + + /* Un-skip the feedback tasks involved with this cell. */ + for (struct link *l = c->black_holes.feedback; l != NULL; l = l->next) { + struct task *t = l->t; + struct cell *ci = t->ci; + struct cell *cj = t->cj; + const int ci_active = cell_is_active_black_holes(ci, e); + const int cj_active = (cj != NULL) ? cell_is_active_black_holes(cj, e) : 0; +#ifdef WITH_MPI + const int ci_nodeID = ci->nodeID; + const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; +#else + const int ci_nodeID = nodeID; + const int cj_nodeID = nodeID; +#endif + + if (t->type == task_type_self && ci_active) { + scheduler_activate(s, t); + } + + else if (t->type == task_type_sub_self && ci_active) { + scheduler_activate(s, t); + } + + else if (t->type == task_type_pair || t->type == task_type_sub_pair) { + /* We only want to activate the task if the cell is active and is + going to update some gas on the *local* node */ + if ((ci_nodeID == nodeID && cj_nodeID == nodeID) && + (ci_active || cj_active)) { + scheduler_activate(s, t); + + } else if ((ci_nodeID == nodeID && cj_nodeID != nodeID) && (cj_active)) { + scheduler_activate(s, t); + + } else if ((ci_nodeID != nodeID && cj_nodeID == nodeID) && (ci_active)) { + scheduler_activate(s, t); + } + } + + /* Nothing more to do here, all drifts and sorts activated above */ + } + + /* Unskip all the other task types. */ + if (c->nodeID == nodeID && cell_is_active_black_holes(c, e)) { + if (c->black_holes.ghost != NULL) + scheduler_activate(s, c->black_holes.ghost); + if (c->black_holes.black_holes_in != NULL) + scheduler_activate(s, c->black_holes.black_holes_in); + if (c->black_holes.black_holes_out != NULL) + scheduler_activate(s, c->black_holes.black_holes_out); + if (c->kick1 != NULL) scheduler_activate(s, c->kick1); + if (c->kick2 != NULL) scheduler_activate(s, c->kick2); + if (c->timestep != NULL) scheduler_activate(s, c->timestep); + if (c->logger != NULL) scheduler_activate(s, c->logger); + } + + return rebuild; +} + /** * @brief Set the super-cell pointers for all cells in a hierarchy. * @@ -3602,9 +3983,7 @@ void cell_set_super_mapper(void *map_data, int num_elements, void *extra_data) { */ int cell_has_tasks(struct cell *c) { #ifdef WITH_MPI - if (c->timestep != NULL || c->mpi.hydro.recv_ti != NULL || - c->mpi.grav.recv_ti != NULL || c->mpi.stars.recv_ti != NULL) - return 1; + if (c->timestep != NULL || c->mpi.recv != NULL) return 1; #else if (c->timestep != NULL) return 1; #endif @@ -4335,7 +4714,8 @@ void cell_check_timesteps(struct cell *c) { #ifdef SWIFT_DEBUG_CHECKS if (c->hydro.ti_end_min == 0 && c->grav.ti_end_min == 0 && - c->stars.ti_end_min == 0 && c->nr_tasks > 0) + c->stars.ti_end_min == 0 && c->black_holes.ti_end_min == 0 && + c->nr_tasks > 0) error("Cell without assigned time-step"); if (c->split) { diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c index dcc694b2f6cd2777e5c71469f784d12befe47ed6..8c928a763a0b09c34c4be0bacccd815b4df9065d 100644 --- a/src/engine_maketasks.c +++ b/src/engine_maketasks.c @@ -287,10 +287,11 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci, scheduler_addunlock(s, ci->top->hydro.star_formation, t_sf_counts); } - engine_addlink(e, &ci->mpi.send, t_feedback); - engine_addlink(e, &ci->mpi.send, t_ti); - if (with_star_formation) { - engine_addlink(e, &ci->mpi.send, t_sf_counts); + engine_addlink(e, &ci->mpi.send, t_feedback); + engine_addlink(e, &ci->mpi.send, t_ti); + if (with_star_formation) { + engine_addlink(e, &ci->mpi.send, t_sf_counts); + } } } @@ -298,7 +299,7 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci, if (ci->split) for (int k = 0; k < 8; k++) if (ci->progeny[k] != NULL) - engine_addtasks_send_stars(e, ci->progeny[k], cj, t_feedback, + engine_addtasks_send_stars(e, ci->progeny[k], cj, t_feedback, t_sf_counts, t_ti, with_star_formation); #else @@ -512,9 +513,9 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c, if (t_feedback != NULL) { engine_addlink(e, &c->mpi.recv, t_feedback); engine_addlink(e, &c->mpi.recv, t_ti); - if (with_star_formation && c->hydro.count > 0) { - engine_addlink(e, &c->mpi.recv, t_sf_counts); - } + if (with_star_formation && c->hydro.count > 0) { + engine_addlink(e, &c->mpi.recv, t_sf_counts); + } #ifdef SWIFT_DEBUG_CHECKS if (c->nodeID == e->nodeID) error("Local cell!"); @@ -536,7 +537,7 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c, if (c->split) for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) - engine_addtasks_recv_stars(e, c->progeny[k], t_feedback, t_sf_counts, + engine_addtasks_recv_stars(e, c->progeny[k], t_feedback, t_sf_counts, t_ti, with_star_formation); #else @@ -2464,6 +2465,13 @@ void engine_addtasks_send_mapper(void *map_data, int num_elements, /*t_sf_counts=*/NULL, /*t_ti=*/NULL, with_star_formation); + /* Add the send tasks for the cells in the proxy that have a black holes + * connection. */ + if ((e->policy & engine_policy_black_holes) && + (type & proxy_cell_type_hydro)) + engine_addtasks_send_black_holes(e, ci, cj, /*t_feedback=*/NULL, + /*t_ti=*/NULL); + /* Add the send tasks for the cells in the proxy that have a gravity * connection. */ if ((e->policy & engine_policy_self_gravity) && @@ -2496,6 +2504,11 @@ void engine_addtasks_recv_mapper(void *map_data, int num_elements, /*t_sf_counts=*/NULL, /*t_ti=*/NULL, with_star_formation); + /* Add the recv tasks for the cells in the proxy that have a black holes + * connection. */ + if ((e->policy & engine_policy_feedback) && (type & proxy_cell_type_hydro)) + engine_addtasks_recv_black_holes(e, ci, NULL, NULL); + /* Add the recv tasks for the cells in the proxy that have a gravity * connection. */ if ((e->policy & engine_policy_self_gravity) && diff --git a/src/space.c b/src/space.c index e58b302d8171d6328a12762a6b7811c12e2ac8e9..9574bdbe57f0c07062dc892a7ae3630a77c975e0 100644 --- a/src/space.c +++ b/src/space.c @@ -4245,6 +4245,7 @@ void space_first_init_bparts_mapper(void *restrict map_data, int count, struct bpart *restrict bp = (struct bpart *)map_data; const struct space *restrict s = (struct space *)extra_data; const struct engine *e = s->e; + const struct black_holes_props *props = e->black_holes_properties; #ifdef SWIFT_DEBUG_CHECKS const ptrdiff_t delta = bp - s->bparts; @@ -4278,10 +4279,17 @@ void space_first_init_bparts_mapper(void *restrict map_data, int count, #endif } + /* Check that the smoothing lengths are non-zero */ + for (int k = 0; k < count; k++) { + if (bp[k].h <= 0.) + error("Invalid value of smoothing length for bpart %lld h=%e", bp[k].id, + bp[k].h); + } + /* Initialise the rest */ for (int k = 0; k < count; k++) { - black_holes_first_init_bpart(&bp[k]); + black_holes_first_init_bpart(&bp[k], props); #ifdef SWIFT_DEBUG_CHECKS if (bp[k].gpart && bp[k].gpart->id_or_neg_offset != -(k + delta)) diff --git a/src/task.c b/src/task.c index 84a60036a8889d54bcc64c2e18fd435c2a04231a..1f45c2e17bc83cae3fd56fa3fe7b3f2cbcda0564 100644 --- a/src/task.c +++ b/src/task.c @@ -99,8 +99,8 @@ const char *subtaskID_names[task_subtype_count] = { "limiter", "grav", "external_grav", "tend_part", "tend_gpart", "tend_spart", "tend_bpart", "xv", "rho", "gpart", "multipole", "spart", - "stars_density", "stars_feedback", "sf_count", "bpart", "bh_density", - "bh_feedback"}; + "stars_density", "stars_feedback", "sf_count", "bpart", + "bh_density", "bh_feedback"}; #ifdef WITH_MPI /* MPI communicators for the subtypes. */