Commit 81a132f0 authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

Added neighbour finding loops for the black holes and infrastrcture to create the tasks.

parent e21885b1
......@@ -500,6 +500,7 @@ int main(int argc, char *argv[]) {
if (with_star_formation && with_feedback)
error("Can't run with star formation and feedback over MPI (yet)");
if (with_limiter) error("Can't run with time-step limiter over MPI (yet)");
if (with_black_holes) error("Can't run with black holes over MPI (yet)");
#endif
/* Temporary early aborts for modes not supported with hand-vec. */
......
......@@ -25,6 +25,7 @@
/* Select the correct star model */
#if defined(BLACK_HOLES_NONE)
#include "./black_holes/Default/black_holes.h"
#include "./black_holes/Default/black_holes_iact.h"
#else
#error "Invalid choice of star model"
#endif
......
/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.ac.uk)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#ifndef SWIFT_DEFAULT_BH_IACT_H
#define SWIFT_DEFAULT_BH_IACT_H
/**
* @brief Density interaction between two particles (non-symmetric).
*
* @param r2 Comoving square distance between the two particles.
* @param dx Comoving vector separating both particles (pi - pj).
* @param hi Comoving smoothing-length of particle i.
* @param hj Comoving smoothing-length of particle j.
* @param bi First bparticle.
* @param pj Second particle (not updated).
* @param a Current scale factor.
* @param H Current Hubble parameter.
*/
__attribute__((always_inline)) INLINE static void
runner_iact_nonsym_bh_density(const float r2, const float *dx,
const float hi, const float hj,
struct bpart *restrict bi,
const struct part *restrict pj, const float a,
const float H) {
float wi, wi_dx;
/* Get r and 1/r. */
const float r_inv = 1.0f / sqrtf(r2);
const float r = r2 * r_inv;
/* Compute the kernel function */
const float hi_inv = 1.0f / hi;
const float ui = r * hi_inv;
kernel_deval(ui, &wi, &wi_dx);
/* Compute contribution to the number of neighbours */
bi->density.wcount += wi;
bi->density.wcount_dh -= (hydro_dimension * wi + ui * wi_dx);
#ifdef DEBUG_INTERACTIONS_BH
/* Update ngb counters */
if (si->num_ngb_density < MAX_NUM_OF_NEIGHBOURS_BH)
bi->ids_ngbs_density[si->num_ngb_density] = pj->id;
/* Update ngb counters */
++si->num_ngb_density;
#endif
}
/**
* @brief Feedback interaction between two particles (non-symmetric).
*
* @param r2 Comoving square distance between the two particles.
* @param dx Comoving vector separating both particles (pi - pj).
* @param hi Comoving smoothing-length of particle i.
* @param hj Comoving smoothing-length of particle j.
* @param bi First bparticle.
* @param pj Second particle (not updated).
* @param a Current scale factor.
* @param H Current Hubble parameter.
*/
__attribute__((always_inline)) INLINE static void
runner_iact_nonsym_bh_feedback(const float r2, const float *dx,
const float hi, const float hj,
struct bpart *restrict bi,
struct part *restrict pj, const float a,
const float H) {
#ifdef DEBUG_INTERACTIONS_BH
/* Update ngb counters */
if (si->num_ngb_force < MAX_NUM_OF_NEIGHBOURS_BH)
bi->ids_ngbs_force[si->num_ngb_force] = pj->id;
/* Update ngb counters */
++si->num_ngb_force;
#endif
}
#endif
......@@ -1786,6 +1786,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;
}
/**
......
......@@ -606,6 +606,15 @@ struct cell {
/*! The drift task for bparts */
struct task *drift;
/*! The star ghost task itself */
struct task *ghost;
/*! Linked list of the tasks computing this cell's star density. */
struct link *density;
/*! Linked list of the tasks computing this cell's star feedback. */
struct link *feedback;
/*! Max smoothing length in this cell. */
double h_max;
......@@ -627,6 +636,9 @@ struct cell {
/*! Maximum part movement in this cell since last construction. */
float dx_max_part;
/*! Values of dx_max before the drifts, used for sub-cell tasks. */
float dx_max_part_old;
/*! Maximum end of (integer) time step in this cell for black tasks. */
integertime_t ti_end_min;
......@@ -969,6 +981,43 @@ cell_can_recurse_in_self_stars_task(const struct cell *c) {
(kernel_gamma * c->hydro.h_max_old < 0.5f * c->dmin);
}
/**
* @brief Can a sub-pair star task recurse to a lower level based
* on the status of the particles in the cell.
*
* @param ci The #cell with black holes.
* @param cj The #cell with hydro parts.
*/
__attribute__((always_inline)) INLINE static int
cell_can_recurse_in_pair_black_holes_task(const struct cell *ci,
const struct cell *cj) {
/* Is the cell split ? */
/* If so, is the cut-off radius plus the max distance the parts have moved */
/* smaller than the sub-cell sizes ? */
/* Note: We use the _old values as these might have been updated by a drift */
return ci->split && cj->split &&
((kernel_gamma * ci->black_holes.h_max_old +
ci->black_holes.dx_max_part_old) < 0.5f * ci->dmin) &&
((kernel_gamma * cj->hydro.h_max_old + cj->hydro.dx_max_part_old) <
0.5f * cj->dmin);
}
/**
* @brief Can a sub-self black_holes task recurse to a lower level based
* on the status of the particles in the cell.
*
* @param c The #cell.
*/
__attribute__((always_inline)) INLINE static int
cell_can_recurse_in_self_black_holes_task(const struct cell *c) {
/* Is the cell split and not smaller than the smoothing length? */
return c->split &&
(kernel_gamma * c->black_holes.h_max_old < 0.5f * c->dmin) &&
(kernel_gamma * c->hydro.h_max_old < 0.5f * c->dmin);
}
/**
* @brief Can a pair hydro task associated with a cell be split into smaller
* sub-tasks.
......
......@@ -41,6 +41,7 @@
#include "active.h"
#include "approx_math.h"
#include "atomic.h"
#include "black_holes.h"
#include "cell.h"
#include "chemistry.h"
#include "const.h"
......@@ -126,6 +127,20 @@
#undef FUNCTION_TASK_LOOP
#undef FUNCTION
/* Import the black hole density loop functions. */
#define FUNCTION density
#define FUNCTION_TASK_LOOP TASK_LOOP_DENSITY
#include "runner_doiact_black_holes.h"
#undef FUNCTION_TASK_LOOP
#undef FUNCTION
/* Import the black hole feedback loop functions. */
#define FUNCTION feedback
#define FUNCTION_TASK_LOOP TASK_LOOP_FEEDBACK
#include "runner_doiact_black_holes.h"
#undef FUNCTION_TASK_LOOP
#undef FUNCTION
/**
* @brief Intermediate task after the density to check that the smoothing
* lengths are correct.
......@@ -3532,6 +3547,10 @@ void *runner_main(void *data) {
runner_doself_branch_stars_density(r, ci);
else if (t->subtype == task_subtype_stars_feedback)
runner_doself_branch_stars_feedback(r, ci);
else if (t->subtype == task_subtype_bh_density)
runner_doself_branch_bh_density(r, ci);
else if (t->subtype == task_subtype_bh_feedback)
runner_doself_branch_bh_feedback(r, ci);
else
error("Unknown/invalid task subtype (%d).", t->subtype);
break;
......@@ -3553,6 +3572,10 @@ void *runner_main(void *data) {
runner_dopair_branch_stars_density(r, ci, cj);
else if (t->subtype == task_subtype_stars_feedback)
runner_dopair_branch_stars_feedback(r, ci, cj);
else if (t->subtype == task_subtype_bh_density)
runner_dopair_branch_bh_density(r, ci, cj);
else if (t->subtype == task_subtype_bh_feedback)
runner_dopair_branch_bh_feedback(r, ci, cj);
else
error("Unknown/invalid task subtype (%d).", t->subtype);
break;
......@@ -3572,6 +3595,10 @@ void *runner_main(void *data) {
runner_dosub_self_stars_density(r, ci, 1);
else if (t->subtype == task_subtype_stars_feedback)
runner_dosub_self_stars_feedback(r, ci, 1);
else if (t->subtype == task_subtype_bh_density)
runner_dosub_self_bh_density(r, ci, 1);
else if (t->subtype == task_subtype_bh_feedback)
runner_dosub_self_bh_feedback(r, ci, 1);
else
error("Unknown/invalid task subtype (%d).", t->subtype);
break;
......@@ -3591,6 +3618,10 @@ void *runner_main(void *data) {
runner_dosub_pair_stars_density(r, ci, cj, 1);
else if (t->subtype == task_subtype_stars_feedback)
runner_dosub_pair_stars_feedback(r, ci, cj, 1);
else if (t->subtype == task_subtype_bh_density)
runner_dosub_pair_bh_density(r, ci, cj, 1);
else if (t->subtype == task_subtype_bh_feedback)
runner_dosub_pair_bh_feedback(r, ci, cj, 1);
else
error("Unknown/invalid task subtype (%d).", t->subtype);
break;
......
/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk)
* 2018 Loic Hausammann (loic.hausammann@epfl.ch)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
/* Before including this file, define FUNCTION, which is the
name of the interaction function. This creates the interaction functions
runner_dopair_FUNCTION, runner_doself_FUNCTION and runner_dosub_FUNCTION
calling the pairwise interaction function runner_iact_FUNCTION. */
#define PASTE(x, y) x##_##y
#define _DOSELF1_BH(f) PASTE(runner_doself_bh, f)
#define DOSELF1_BH _DOSELF1_BH(FUNCTION)
#define _DO_SYM_PAIR1_BH(f) PASTE(runner_do_sym_pair_bh, f)
#define DO_SYM_PAIR1_BH _DO_SYM_PAIR1_BH(FUNCTION)
#define _DO_NONSYM_PAIR1_BH_NAIVE(f) \
PASTE(runner_do_nonsym_pair_bh_naive, f)
#define DO_NONSYM_PAIR1_BH_NAIVE _DO_NONSYM_PAIR1_BH_NAIVE(FUNCTION)
#define _DOPAIR1_BH_NAIVE(f) PASTE(runner_dopair_bh_naive, f)
#define DOPAIR1_BH_NAIVE _DOPAIR1_BH_NAIVE(FUNCTION)
#define _DOPAIR1_SUBSET_BH(f) PASTE(runner_dopair_subset_bh, f)
#define DOPAIR1_SUBSET_BH _DOPAIR1_SUBSET_BH(FUNCTION)
#define _DOPAIR1_SUBSET_BH_NAIVE(f) \
PASTE(runner_dopair_subset_bh_naive, f)
#define DOPAIR1_SUBSET_BH_NAIVE _DOPAIR1_SUBSET_BH_NAIVE(FUNCTION)
#define _DOSELF1_SUBSET_BH(f) PASTE(runner_doself_subset_bh, f)
#define DOSELF1_SUBSET_BH _DOSELF1_SUBSET_BH(FUNCTION)
#define _DOSELF1_SUBSET_BRANCH_BH(f) \
PASTE(runner_doself_subset_branch_bh, f)
#define DOSELF1_SUBSET_BRANCH_BH _DOSELF1_SUBSET_BRANCH_BH(FUNCTION)
#define _DOPAIR1_SUBSET_BRANCH_BH(f) \
PASTE(runner_dopair_subset_branch_bh, f)
#define DOPAIR1_SUBSET_BRANCH_BH _DOPAIR1_SUBSET_BRANCH_BH(FUNCTION)
#define _DOSUB_SUBSET_BH(f) PASTE(runner_dosub_subset_bh, f)
#define DOSUB_SUBSET_BH _DOSUB_SUBSET_BH(FUNCTION)
#define _DOSELF1_BRANCH_BH(f) PASTE(runner_doself_branch_bh, f)
#define DOSELF1_BRANCH_BH _DOSELF1_BRANCH_BH(FUNCTION)
#define _DOPAIR1_BRANCH_BH(f) PASTE(runner_dopair_branch_bh, f)
#define DOPAIR1_BRANCH_BH _DOPAIR1_BRANCH_BH(FUNCTION)
#define _DOSUB_PAIR1_BH(f) PASTE(runner_dosub_pair_bh, f)
#define DOSUB_PAIR1_BH _DOSUB_PAIR1_BH(FUNCTION)
#define _DOSUB_SELF1_BH(f) PASTE(runner_dosub_self_bh, f)
#define DOSUB_SELF1_BH _DOSUB_SELF1_BH(FUNCTION)
#define _TIMER_DOSELF_BH(f) PASTE(timer_doself_bh, f)
#define TIMER_DOSELF_BH _TIMER_DOSELF_BH(FUNCTION)
#define _TIMER_DOPAIR_BH(f) PASTE(timer_dopair_bh, f)
#define TIMER_DOPAIR_BH _TIMER_DOPAIR_BH(FUNCTION)
#define _TIMER_DOSUB_SELF_BH(f) PASTE(timer_dosub_self_bh, f)
#define TIMER_DOSUB_SELF_BH _TIMER_DOSUB_SELF_BH(FUNCTION)
#define _TIMER_DOSUB_PAIR_BH(f) PASTE(timer_dosub_pair_bh, f)
#define TIMER_DOSUB_PAIR_BH _TIMER_DOSUB_PAIR_BH(FUNCTION)
#define _IACT_BH(f) PASTE(runner_iact_nonsym_bh, f)
#define IACT_BH _IACT_BH(FUNCTION)
/**
* @brief Calculate the number density of #part around the #spart
*
* @param r runner task
* @param c cell
* @param timer 1 if the time is to be recorded.
*/
void DOSELF1_BH(struct runner *r, struct cell *c, int timer) {
#ifdef SWIFT_DEBUG_CHECKS
if (c->nodeID != engine_rank) error("Should be run on a different node");
#endif
TIMER_TIC;
const struct engine *e = r->e;
//const int with_cosmology = e->policy & engine_policy_cosmology;
//const integertime_t ti_current = e->ti_current;
const struct cosmology *cosmo = e->cosmology;
/* Anything to do here? */
if (c->hydro.count == 0 || c->black_holes.count == 0) return;
if (!cell_is_active_black_holes(c, e)) return;
/* Cosmological terms */
const float a = cosmo->a;
const float H = cosmo->H;
const int bcount = c->black_holes.count;
const int count = c->hydro.count;
struct bpart *restrict bparts = c->black_holes.parts;
struct part *restrict parts = c->hydro.parts;
//struct xpart *restrict xparts = c->hydro.xparts;
/* Loop over the bparts in ci. */
for (int sid = 0; sid < bcount; sid++) {
/* Get a hold of the ith bpart in ci. */
struct bpart *restrict si = &bparts[sid];
/* Skip inactive particles */
if (!bpart_is_active(si, e)) continue;
const float hi = si->h;
const float hig2 = hi * hi * kernel_gamma2;
const float six[3] = {(float)(si->x[0] - c->loc[0]),
(float)(si->x[1] - c->loc[1]),
(float)(si->x[2] - c->loc[2])};
/* Loop over the parts in cj. */
for (int pjd = 0; pjd < count; pjd++) {
/* Get a pointer to the jth particle. */
struct part *restrict pj = &parts[pjd];
//struct xpart *restrict xpj = &xparts[pjd];
const float hj = pj->h;
/* Early abort? */
if (part_is_inhibited(pj, e)) continue;
/* Compute the pairwise distance. */
const float pjx[3] = {(float)(pj->x[0] - c->loc[0]),
(float)(pj->x[1] - c->loc[1]),
(float)(pj->x[2] - c->loc[2])};
float dx[3] = {six[0] - pjx[0], six[1] - pjx[1], six[2] - pjx[2]};
const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
#ifdef SWIFT_DEBUG_CHECKS
/* Check that particles have been drifted to the current time */
if (pj->ti_drift != e->ti_current)
error("Particle pj not drifted to current time");
#endif
if (r2 < hig2) {
IACT_BH(r2, dx, hi, hj, si, pj, a, H);
}
} /* loop over the parts in ci. */
} /* loop over the bparts in ci. */
TIMER_TOC(TIMER_DOSELF_BH);
}
/**
* @brief Calculate the number density of cj #part around the ci #spart
*
* @param r runner task
* @param ci The first #cell
* @param cj The second #cell
*/
void DO_NONSYM_PAIR1_BH_NAIVE(struct runner *r, struct cell *restrict ci,
struct cell *restrict cj) {
#ifdef SWIFT_DEBUG_CHECKS
#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
if (ci->nodeID != engine_rank) error("Should be run on a different node");
#else
if (cj->nodeID != engine_rank) error("Should be run on a different node");
#endif
#endif
const struct engine *e = r->e;
//const int with_cosmology = e->policy & engine_policy_cosmology;
//const integertime_t ti_current = e->ti_current;
const struct cosmology *cosmo = e->cosmology;
/* Anything to do here? */
if (cj->hydro.count == 0 || ci->black_holes.count == 0) return;
if (!cell_is_active_black_holes(ci, e)) return;
/* Cosmological terms */
const float a = cosmo->a;
const float H = cosmo->H;
const int bcount_i = ci->black_holes.count;
const int count_j = cj->hydro.count;
struct bpart *restrict bparts_i = ci->black_holes.parts;
struct part *restrict parts_j = cj->hydro.parts;
//struct xpart *restrict xparts_j = cj->hydro.xparts;
/* Get the relative distance between the pairs, wrapping. */
double shift[3] = {0.0, 0.0, 0.0};
for (int k = 0; k < 3; k++) {
if (cj->loc[k] - ci->loc[k] < -e->s->dim[k] / 2)
shift[k] = e->s->dim[k];
else if (cj->loc[k] - ci->loc[k] > e->s->dim[k] / 2)
shift[k] = -e->s->dim[k];
}
/* Loop over the bparts in ci. */
for (int sid = 0; sid < bcount_i; sid++) {
/* Get a hold of the ith bpart in ci. */
struct bpart *restrict si = &bparts_i[sid];
/* Skip inactive particles */
if (!bpart_is_active(si, e)) continue;
const float hi = si->h;
const float hig2 = hi * hi * kernel_gamma2;
const float six[3] = {(float)(si->x[0] - (cj->loc[0] + shift[0])),
(float)(si->x[1] - (cj->loc[1] + shift[1])),
(float)(si->x[2] - (cj->loc[2] + shift[2]))};
/* Loop over the parts in cj. */
for (int pjd = 0; pjd < count_j; pjd++) {
/* Get a pointer to the jth particle. */
struct part *restrict pj = &parts_j[pjd];
//struct xpart *restrict xpj = &xparts_j[pjd];
const float hj = pj->h;
/* Skip inhibited particles. */
if (part_is_inhibited(pj, e)) continue;
/* Compute the pairwise distance. */
const float pjx[3] = {(float)(pj->x[0] - cj->loc[0]),
(float)(pj->x[1] - cj->loc[1]),
(float)(pj->x[2] - cj->loc[2])};
float dx[3] = {six[0] - pjx[0], six[1] - pjx[1], six[2] - pjx[2]};
const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
#ifdef SWIFT_DEBUG_CHECKS
/* Check that particles have been drifted to the current time */
if (pj->ti_drift != e->ti_current)
error("Particle pj not drifted to current time");
#endif
if (r2 < hig2) {
IACT_BH(r2, dx, hi, hj, si, pj, a, H);
}
} /* loop over the parts in cj. */
} /* loop over the parts in ci. */
}
void DOPAIR1_BH_NAIVE(struct runner *r, struct cell *restrict ci,
struct cell *restrict cj, int timer) {
TIMER_TIC;
#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
const int do_ci_bh = ci->nodeID == r->e->nodeID;
const int do_cj_bh = cj->nodeID == r->e->nodeID;
#else
/* here we are updating the hydro -> switch ci, cj */
const int do_ci_bh = cj->nodeID == r->e->nodeID;
const int do_cj_bh = ci->nodeID == r->e->nodeID;
#endif
if (do_ci_bh && ci->black_holes.count != 0 && cj->hydro.count != 0)
DO_NONSYM_PAIR1_BH_NAIVE(r, ci, cj);
if (do_cj_bh && cj->black_holes.count != 0 && ci->hydro.count != 0)
DO_NONSYM_PAIR1_BH_NAIVE(r, cj, ci);
TIMER_TOC(TIMER_DOPAIR_BH);
}
/**
* @brief Compute the interactions between a cell pair, but only for the
* given indices in ci.
*
* Version using a brute-force algorithm.
*
* @param r The #runner.
* @param ci The first #cell.
* @param sparts_i The #part to interact with @c cj.
* @param ind The list of indices of particles in @c ci to interact with.
* @param scount The number of particles in @c ind.
* @param cj The second #cell.
* @param shift The shift vector to apply to the particles in ci.
*/
void DOPAIR1_SUBSET_BH_NAIVE(struct runner *r, struct cell *restrict ci,
struct bpart *restrict bparts_i,
int *restrict ind, int bcount,
struct cell *restrict cj, const double *shift) {
#ifdef SWIFT_DEBUG_CHECKS
if (ci->nodeID != engine_rank) error("Should be run on a different node");
#endif
const struct engine *e = r->e;
//const integertime_t ti_current = e->ti_current;
const struct cosmology *cosmo = e->cosmology;
/* Cosmological terms */
const float a = cosmo->a;
const float H = cosmo->H;
const int count_j = cj->hydro.count;
struct part *restrict parts_j = cj->hydro.parts;
//struct xpart *restrict xparts_j = cj->hydro.xparts;
/* Early abort? */
if (count_j == 0) return;
/* Loop over the parts_i. */
for (int pid = 0; pid < bcount; pid++) {
/* Get a hold of the ith part in ci. */
struct bpart *restrict bpi = &bparts_i[ind[pid]];
const double pix = bpi->x[0] - (shift[0]);
const double piy = bpi->x[1] - (shift[1]);
const double piz = bpi->x[2] - (shift[2]);
const float hi = bpi->h;
const float hig2 = hi * hi * kernel_gamma2;
#ifdef SWIFT_DEBUG_CHECKS
if (!bpart_is_active(bpi, e))
error("Trying to correct smoothing length of inactive particle !");
#endif
/* Loop over the parts in cj. */
for (int pjd = 0; pjd < count_j; pjd++) {
/* Get a pointer to the jth particle. */
struct part *restrict pj = &parts_j[pjd];
//struct xpart *restrict xpj = &xparts_j[pjd];
/* Skip inhibited particles */
if (part_is_inhibited(pj, e)) continue;
const double pjx = pj->x[0];
const double pjy = pj->x[1];
const double pjz = pj->x[2];