/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) * 2016 Matthieu Schaller (schaller@strw.leidenuniv.nl) * * 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 . * ******************************************************************************/ /* Before including this file, define FUNCTION, which is the name of the interaction function. This creates the interaction functions runner_dopair_FUNCTION, runner_dopair_FUNCTION_naive, runner_doself_FUNCTION, and runner_dosub_FUNCTION calling the pairwise interaction function runner_iact_FUNCTION. */ #include "runner_doiact_limiter.h" /** * @brief Compute the interactions between a cell pair (non-symmetric case). * * Inefficient version using a brute-force algorithm. * * @param r The #runner. * @param ci The first #cell. * @param cj The second #cell. */ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, struct cell *restrict cj) { const struct engine *e = r->e; const struct cosmology *cosmo = e->cosmology; TIMER_TIC; /* Anything to do here? */ if (!cell_is_starting_hydro(ci, e) && !cell_is_starting_hydro(cj, e)) return; const int count_i = ci->hydro.count; const int count_j = cj->hydro.count; struct part *restrict parts_i = ci->hydro.parts; struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; const float H = cosmo->H; /* 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 parts in ci. */ for (int pid = 0; pid < count_i; pid++) { /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts_i[pid]; /* Skip inhibited particles. */ if (part_is_inhibited(pi, e)) continue; const int pi_active = part_is_starting(pi, e); const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; const float pix[3] = {(float)(pi->x[0] - (cj->loc[0] + shift[0])), (float)(pi->x[1] - (cj->loc[1] + shift[1])), (float)(pi->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]; /* Skip inhibited particles. */ if (part_is_inhibited(pj, e)) continue; const float hj = pj->h; const float hjg2 = hj * hj * kernel_gamma2; const int pj_active = part_is_starting(pj, e); /* 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] = {pix[0] - pjx[0], pix[1] - pjx[1], pix[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 (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ if (r2 < hig2 && pi_active) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); } if (r2 < hjg2 && pj_active) { dx[0] = -dx[0]; dx[1] = -dx[1]; dx[2] = -dx[2]; IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); } } /* loop over the parts in cj. */ } /* loop over the parts in ci. */ TIMER_TOC(TIMER_DOPAIR); } /** * @brief Compute the interactions within a cell (non-symmetric case). * * Inefficient version using a brute-force algorithm. * * @param r The #runner. * @param c The #cell. */ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { const struct engine *e = r->e; const struct cosmology *cosmo = e->cosmology; TIMER_TIC; /* Anything to do here? */ if (!cell_is_starting_hydro(c, e)) return; /* Cosmological terms */ const float a = cosmo->a; const float H = cosmo->H; const int count = c->hydro.count; struct part *restrict parts = c->hydro.parts; /* Loop over the parts in ci. */ for (int pid = 0; pid < count; pid++) { /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts[pid]; /* Skip inhibited particles. */ if (part_is_inhibited(pi, e)) continue; const int pi_active = part_is_starting(pi, e); const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; const float pix[3] = {(float)(pi->x[0] - c->loc[0]), (float)(pi->x[1] - c->loc[1]), (float)(pi->x[2] - c->loc[2])}; /* Loop over the parts in cj. */ for (int pjd = pid + 1; pjd < count; pjd++) { /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts[pjd]; /* Skip inhibited particles. */ if (part_is_inhibited(pj, e)) continue; const float hj = pj->h; const float hjg2 = hj * hj * kernel_gamma2; const int pj_active = part_is_starting(pj, e); /* 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] = {pix[0] - pjx[0], pix[1] - pjx[1], pix[2] - pjx[2]}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; const int doi = pi_active && (r2 < hig2); const int doj = pj_active && (r2 < hjg2); #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ if (doi && doj) { IACT(r2, dx, hi, hj, pi, pj, a, H); } else if (doi) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); } else if (doj) { dx[0] = -dx[0]; dx[1] = -dx[1]; dx[2] = -dx[2]; IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); } } /* loop over the parts in cj. */ } /* loop over the parts in ci. */ TIMER_TOC(TIMER_DOSELF); } /** * @brief Compute the interactions between a cell pair (non-symmetric). * * @param r The #runner. * @param ci The first #cell. * @param cj The second #cell. * @param sid The direction of the pair. * @param shift The shift vector to apply to the particles in ci. */ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const double *shift) { const struct engine *restrict e = r->e; const struct cosmology *restrict cosmo = e->cosmology; TIMER_TIC; /* Get the cutoff shift. */ double rshift = 0.0; for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k]; /* Pick-out the sorted lists. */ const struct sort_entry *restrict sort_i = cell_get_hydro_sorts(ci, sid); const struct sort_entry *restrict sort_j = cell_get_hydro_sorts(cj, sid); #ifdef SWIFT_DEBUG_CHECKS /* Some constants used to checks that the parts are in the right frame */ const float shift_threshold_x = 2. * ci->width[0] + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_y = 2. * ci->width[1] + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_z = 2. * ci->width[2] + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); #endif /* SWIFT_DEBUG_CHECKS */ /* Get some other useful values. */ const double hi_max = ci->hydro.h_max * kernel_gamma - rshift; const double hj_max = cj->hydro.h_max * kernel_gamma; const int count_i = ci->hydro.count; const int count_j = cj->hydro.count; struct part *restrict parts_i = ci->hydro.parts; struct part *restrict parts_j = cj->hydro.parts; const double di_max = sort_i[count_i - 1].d - rshift; const double dj_min = sort_j[0].d; const float dx_max = (ci->hydro.dx_max_sort + cj->hydro.dx_max_sort); /* Cosmological terms */ const float a = cosmo->a; const float H = cosmo->H; if (cell_is_starting_hydro(ci, e)) { /* Loop over the parts in ci. */ for (int pid = count_i - 1; pid >= 0 && sort_i[pid].d + hi_max + dx_max > dj_min; pid--) { /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts_i[sort_i[pid].i]; const float hi = pi->h; /* Skip inactive particles */ if (!part_is_starting(pi, e)) continue; /* Is there anything we need to interact with ? */ const double di = sort_i[pid].d + hi * kernel_gamma + dx_max - rshift; if (di < dj_min) continue; /* Get some additional information about pi */ const float hig2 = hi * hi * kernel_gamma2; const float pix = pi->x[0] - (cj->loc[0] + shift[0]); const float piy = pi->x[1] - (cj->loc[1] + shift[1]); const float piz = pi->x[2] - (cj->loc[2] + shift[2]); /* Loop over the parts in cj. */ for (int pjd = 0; pjd < count_j && sort_j[pjd].d < di; pjd++) { /* Recover pj */ struct part *pj = &parts_j[sort_j[pjd].i]; /* Skip inhibited particles. */ if (part_is_inhibited(pj, e)) continue; const float hj = pj->h; const float pjx = pj->x[0] - cj->loc[0]; const float pjy = pj->x[1] - cj->loc[1]; const float pjz = pj->x[2] - cj->loc[2]; /* Compute the pairwise distance. */ float dx[3] = {pix - pjx, piy - pjy, piz - pjz}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS /* Check that particles are in the correct frame after the shifts */ if (pix > shift_threshold_x || pix < -shift_threshold_x) error( "Invalid particle position in X for pi (pix=%e ci->width[0]=%e)", pix, ci->width[0]); if (piy > shift_threshold_y || piy < -shift_threshold_y) error( "Invalid particle position in Y for pi (piy=%e ci->width[1]=%e)", piy, ci->width[1]); if (piz > shift_threshold_z || piz < -shift_threshold_z) error( "Invalid particle position in Z for pi (piz=%e ci->width[2]=%e)", piz, ci->width[2]); if (pjx > shift_threshold_x || pjx < -shift_threshold_x) error( "Invalid particle position in X for pj (pjx=%e ci->width[0]=%e)", pjx, ci->width[0]); if (pjy > shift_threshold_y || pjy < -shift_threshold_y) error( "Invalid particle position in Y for pj (pjy=%e ci->width[1]=%e)", pjy, ci->width[1]); if (pjz > shift_threshold_z || pjz < -shift_threshold_z) error( "Invalid particle position in Z for pj (pjz=%e ci->width[2]=%e)", pjz, ci->width[2]); /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ if (r2 < hig2) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); } } /* loop over the parts in cj. */ } /* loop over the parts in ci. */ } /* Cell ci is active */ if (cell_is_starting_hydro(cj, e)) { /* Loop over the parts in cj. */ for (int pjd = 0; pjd < count_j && sort_j[pjd].d - hj_max - dx_max < di_max; pjd++) { /* Get a hold of the jth part in cj. */ struct part *pj = &parts_j[sort_j[pjd].i]; const float hj = pj->h; /* Skip inactive particles */ if (!part_is_starting(pj, e)) continue; /* Is there anything we need to interact with ? */ const double dj = sort_j[pjd].d - hj * kernel_gamma - dx_max + rshift; if (dj - rshift > di_max) continue; /* Get some additional information about pj */ const float hjg2 = hj * hj * kernel_gamma2; const float pjx = pj->x[0] - cj->loc[0]; const float pjy = pj->x[1] - cj->loc[1]; const float pjz = pj->x[2] - cj->loc[2]; /* Loop over the parts in ci. */ for (int pid = count_i - 1; pid >= 0 && sort_i[pid].d > dj; pid--) { /* Recover pi */ struct part *pi = &parts_i[sort_i[pid].i]; /* Skip inhibited particles. */ if (part_is_inhibited(pi, e)) continue; const float hi = pi->h; const float pix = pi->x[0] - (cj->loc[0] + shift[0]); const float piy = pi->x[1] - (cj->loc[1] + shift[1]); const float piz = pi->x[2] - (cj->loc[2] + shift[2]); /* Compute the pairwise distance. */ float dx[3] = {pjx - pix, pjy - piy, pjz - piz}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS /* Check that particles are in the correct frame after the shifts */ if (pix > shift_threshold_x || pix < -shift_threshold_x) error( "Invalid particle position in X for pi (pix=%e ci->width[0]=%e)", pix, ci->width[0]); if (piy > shift_threshold_y || piy < -shift_threshold_y) error( "Invalid particle position in Y for pi (piy=%e ci->width[1]=%e)", piy, ci->width[1]); if (piz > shift_threshold_z || piz < -shift_threshold_z) error( "Invalid particle position in Z for pi (piz=%e ci->width[2]=%e)", piz, ci->width[2]); if (pjx > shift_threshold_x || pjx < -shift_threshold_x) error( "Invalid particle position in X for pj (pjx=%e ci->width[0]=%e)", pjx, ci->width[0]); if (pjy > shift_threshold_y || pjy < -shift_threshold_y) error( "Invalid particle position in Y for pj (pjy=%e ci->width[1]=%e)", pjy, ci->width[1]); if (pjz > shift_threshold_z || pjz < -shift_threshold_z) error( "Invalid particle position in Z for pj (pjz=%e ci->width[2]=%e)", pjz, ci->width[2]); /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ if (r2 < hjg2) { IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); } } /* loop over the parts in ci. */ } /* loop over the parts in cj. */ } /* Cell cj is active */ TIMER_TOC(TIMER_DOPAIR); } /** * @brief Determine which version of DOPAIR1 needs to be called depending on the * orientation of the cells or whether DOPAIR1 needs to be called at all. * * @param r #runner * @param ci #cell ci * @param cj #cell cj * */ void DOPAIR1_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) { const struct engine *restrict e = r->e; /* Anything to do here? */ if (ci->hydro.count == 0 || cj->hydro.count == 0) return; /* Anything to do here? */ if (!cell_is_starting_hydro(ci, e) && !cell_is_starting_hydro(cj, e)) return; /* Check that cells are drifted. */ if (!cell_are_part_drifted(ci, e) || !cell_are_part_drifted(cj, e)) error("Interacting undrifted cells."); /* Get the sort ID. */ double shift[3] = {0.0, 0.0, 0.0}; const int sid = space_getsid(e->s, &ci, &cj, shift); /* Have the cells been sorted? */ if (!(ci->hydro.sorted & (1 << sid)) || ci->hydro.dx_max_sort_old > space_maxreldx * ci->dmin) error("Interacting unsorted cells."); if (!(cj->hydro.sorted & (1 << sid)) || cj->hydro.dx_max_sort_old > space_maxreldx * cj->dmin) error("Interacting unsorted cells."); #ifdef SWIFT_DEBUG_CHECKS /* Pick-out the sorted lists. */ const struct sort_entry *restrict sort_i = cell_get_hydro_sorts(ci, sid); const struct sort_entry *restrict sort_j = cell_get_hydro_sorts(cj, sid); /* Check that the dx_max_sort values in the cell are indeed an upper bound on particle movement. */ for (int pid = 0; pid < ci->hydro.count; pid++) { const struct part *p = &ci->hydro.parts[sort_i[pid].i]; if (part_is_inhibited(p, e)) continue; const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; if (fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > 1.0e-4 * max(fabsf(d), ci->hydro.dx_max_sort_old) && fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > ci->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell ci. ci->nodeID=%d " "cj->nodeID=%d d=%e sort_i[pid].d=%e ci->hydro.dx_max_sort=%e " "ci->hydro.dx_max_sort_old=%e", ci->nodeID, cj->nodeID, d, sort_i[pid].d, ci->hydro.dx_max_sort, ci->hydro.dx_max_sort_old); } for (int pjd = 0; pjd < cj->hydro.count; pjd++) { const struct part *p = &cj->hydro.parts[sort_j[pjd].i]; if (part_is_inhibited(p, e)) continue; const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; if ((fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort) > 1.0e-4 * max(fabsf(d), cj->hydro.dx_max_sort_old) && (fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort) > cj->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell cj. cj->nodeID=%d " "ci->nodeID=%d d=%e sort_j[pjd].d=%e cj->hydro.dx_max_sort=%e " "cj->hydro.dx_max_sort_old=%e", cj->nodeID, ci->nodeID, d, sort_j[pjd].d, cj->hydro.dx_max_sort, cj->hydro.dx_max_sort_old); } #endif /* SWIFT_DEBUG_CHECKS */ #if defined(SWIFT_USE_NAIVE_INTERACTIONS) DOPAIR1_NAIVE(r, ci, cj); #else DOPAIR1(r, ci, cj, sid, shift); #endif } /** * @brief Compute the cell self-interaction (non-symmetric). * * @param r The #runner. * @param c The #cell. */ void DOSELF1(struct runner *r, struct cell *restrict c) { const struct engine *e = r->e; const struct cosmology *cosmo = e->cosmology; TIMER_TIC; struct part *restrict parts = c->hydro.parts; const int count = c->hydro.count; /* Set up indt. */ int *indt = NULL; int countdt = 0, firstdt = 0; if (posix_memalign((void **)&indt, VEC_SIZE * sizeof(int), count * sizeof(int)) != 0) error("Failed to allocate indt."); for (int k = 0; k < count; k++) if (part_is_starting(&parts[k], e)) { indt[countdt] = k; countdt += 1; } /* Cosmological terms */ const float a = cosmo->a; const float H = cosmo->H; /* Loop over the particles in the cell. */ for (int pid = 0; pid < count; pid++) { /* Get a pointer to the ith particle. */ struct part *restrict pi = &parts[pid]; /* Skip inhibited particles. */ if (part_is_inhibited(pi, e)) continue; /* Get the particle position and radius. */ double pix[3]; for (int k = 0; k < 3; k++) pix[k] = pi->x[k]; const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; /* Is the ith particle inactive? */ if (!part_is_starting(pi, e)) { /* Loop over the other particles .*/ for (int pjd = firstdt; pjd < countdt; pjd++) { /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts[indt[pjd]]; const float hj = pj->h; #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Compute the pairwise distance. */ float r2 = 0.0f; float dx[3]; for (int k = 0; k < 3; k++) { dx[k] = pj->x[k] - pix[k]; r2 += dx[k] * dx[k]; } /* Hit or miss? */ if (r2 < hj * hj * kernel_gamma2) { IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); } } /* loop over all other particles. */ } /* Otherwise, interact with all candidates. */ else { /* We caught a live one! */ firstdt += 1; /* Loop over the other particles .*/ for (int pjd = pid + 1; pjd < count; pjd++) { /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts[pjd]; /* Skip inhibited particles. */ if (part_is_inhibited(pj, e)) continue; const float hj = pj->h; /* Compute the pairwise distance. */ float r2 = 0.0f; float dx[3]; for (int k = 0; k < 3; k++) { dx[k] = pix[k] - pj->x[k]; r2 += dx[k] * dx[k]; } const int doj = (part_is_starting(pj, e)) && (r2 < hj * hj * kernel_gamma2); const int doi = (r2 < hig2); #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ if (doi || doj) { /* Which parts need to be updated? */ if (doi && doj) { IACT(r2, dx, hi, hj, pi, pj, a, H); } else if (doi) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); } else if (doj) { dx[0] = -dx[0]; dx[1] = -dx[1]; dx[2] = -dx[2]; IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); } } } /* loop over all other particles. */ } } /* loop over all particles. */ free(indt); TIMER_TOC(TIMER_DOSELF); } /** * @brief Determine which version of DOSELF1 needs to be called depending on the * optimisation level. * * @param r #runner * @param c #cell c * */ void DOSELF1_BRANCH(struct runner *r, struct cell *c) { const struct engine *restrict e = r->e; /* Anything to do here? */ if (c->hydro.count == 0) return; /* Anything to do here? */ if (!cell_is_starting_hydro(c, e)) return; /* Did we mess up the recursion? */ if (c->hydro.h_max_old * kernel_gamma > c->dmin) error("Cell smaller than smoothing length"); /* Check that cells are drifted. */ if (!cell_are_part_drifted(c, e)) error("Interacting undrifted cell."); #if defined(SWIFT_USE_NAIVE_INTERACTIONS) DOSELF1_NAIVE(r, c); #else DOSELF1(r, c); #endif } /** * @brief Compute grouped sub-cell interactions for pairs * * @param r The #runner. * @param ci The first #cell. * @param cj The second #cell. * @param gettimer Do we have a timer ? * * @todo Hard-code the sid on the recursive calls to avoid the * redundant computations to find the sid on-the-fly. */ void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, int gettimer) { struct space *s = r->e->s; const struct engine *e = r->e; TIMER_TIC; /* Get the type of pair and flip ci/cj if needed. */ double shift[3]; const int sid = space_getsid(s, &ci, &cj, shift); /* Should we even bother? */ const int do_i = cell_get_flag(ci, cell_flag_do_hydro_limiter); const int do_j = cell_get_flag(cj, cell_flag_do_hydro_limiter); const int do_sub_i = cell_get_flag(ci, cell_flag_do_hydro_sub_limiter); const int do_sub_j = cell_get_flag(cj, cell_flag_do_hydro_sub_limiter); if (!do_i && !do_j && !do_sub_i && !do_sub_j) return; if (!cell_is_starting_hydro(ci, e) && !cell_is_starting_hydro(cj, e)) return; if (ci->hydro.count == 0 || cj->hydro.count == 0) return; /* Recurse? */ if (cell_can_recurse_in_pair_hydro_task(ci) && cell_can_recurse_in_pair_hydro_task(cj)) { 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) DOSUB_PAIR1(r, ci->progeny[pid], cj->progeny[pjd], 0); } } /* Otherwise, compute the pair directly. */ else if ((cell_is_starting_hydro(ci, e) && (do_i || do_sub_i)) || (cell_is_starting_hydro(cj, e) && (do_j || do_sub_j))) { /* Make sure both cells are drifted to the current timestep. */ if (!cell_are_part_drifted(ci, e) || !cell_are_part_drifted(cj, e)) error("Interacting undrifted cells."); /* Do any of the cells need to be sorted first? */ if (!(ci->hydro.sorted & (1 << sid)) || ci->hydro.dx_max_sort_old > ci->dmin * space_maxreldx) error( "Interacting unsorted cell. ci->hydro.dx_max_sort_old=%e ci->dmin=%e " "ci->sorted=%d sid=%d", ci->hydro.dx_max_sort_old, ci->dmin, ci->hydro.sorted, sid); if (!(cj->hydro.sorted & (1 << sid)) || cj->hydro.dx_max_sort_old > cj->dmin * space_maxreldx) error( "Interacting unsorted cell. cj->hydro.dx_max_sort_old=%e cj->dmin=%e " "cj->sorted=%d sid=%d", cj->hydro.dx_max_sort_old, cj->dmin, cj->hydro.sorted, sid); /* Compute the interactions. */ DOPAIR1_BRANCH(r, ci, cj); } if (gettimer) TIMER_TOC(TIMER_DOSUB_PAIR); } /** * @brief Compute grouped sub-cell interactions for self tasks * * @param r The #runner. * @param ci The first #cell. * @param gettimer Do we have a timer ? */ void DOSUB_SELF1(struct runner *r, struct cell *ci, int gettimer) { TIMER_TIC; /* Should we even bother? */ const int do_i = cell_get_flag(ci, cell_flag_do_hydro_limiter); const int do_sub_i = cell_get_flag(ci, cell_flag_do_hydro_sub_limiter); if (!do_i && !do_sub_i) return; if (!cell_is_starting_hydro(ci, r->e)) return; if (ci->hydro.count == 0) return; /* Recurse? */ if (cell_can_recurse_in_self_hydro_task(ci)) { /* Loop over all progeny. */ for (int k = 0; k < 8; k++) if (ci->progeny[k] != NULL) { DOSUB_SELF1(r, ci->progeny[k], 0); for (int j = k + 1; j < 8; j++) if (ci->progeny[j] != NULL) DOSUB_PAIR1(r, ci->progeny[k], ci->progeny[j], 0); } } /* Otherwise, compute self-interaction. */ else { /* Drift the cell to the current timestep if needed. */ if (!cell_are_part_drifted(ci, r->e)) error("Interacting undrifted cell."); DOSELF1_BRANCH(r, ci); } if (gettimer) TIMER_TOC(TIMER_DOSUB_SELF); }