/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) * Matthieu Schaller (schaller@strw.leidenuniv.nl) * 2015 Peter W. Draper (p.w.draper@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 . * ******************************************************************************/ /* Config parameters. */ #include /* This object's header. */ #include "space.h" /* Local headers. */ #include "active.h" #include "cell.h" #include "debug.h" #include "engine.h" #include "multipole.h" #include "star_formation_logger.h" #include "threadpool.h" /** * @brief Recursively split a cell. * * @param s The #space in which the cell lives. * @param c The #cell to split recursively. * @param buff A buffer for particle sorting, should be of size at least * c->hydro.count or @c NULL. * @param sbuff A buffer for particle sorting, should be of size at least * c->stars.count or @c NULL. * @param bbuff A buffer for particle sorting, should be of size at least * c->black_holes.count or @c NULL. * @param gbuff A buffer for particle sorting, should be of size at least * c->grav.count or @c NULL. * @param sink_buff A buffer for particle sorting, should be of size at least * c->sinks.count or @c NULL. */ void space_split_recursive(struct space *s, struct cell *c, struct cell_buff *restrict buff, struct cell_buff *restrict sbuff, struct cell_buff *restrict bbuff, struct cell_buff *restrict gbuff, struct cell_buff *restrict sink_buff, const short int tpid) { const int count = c->hydro.count; const int gcount = c->grav.count; const int scount = c->stars.count; const int bcount = c->black_holes.count; const int sink_count = c->sinks.count; const int with_self_gravity = s->with_self_gravity; const int depth = c->depth; int maxdepth = 0; float h_max = 0.0f; float h_max_active = 0.0f; float stars_h_max = 0.f; float stars_h_max_active = 0.f; float black_holes_h_max = 0.f; float black_holes_h_max_active = 0.f; float sinks_h_max = 0.f; float sinks_h_max_active = 0.f; integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_beg_max = 0; integertime_t ti_rt_end_min = max_nr_timesteps, ti_rt_beg_max = 0; integertime_t ti_rt_min_step_size = max_nr_timesteps; integertime_t ti_gravity_end_min = max_nr_timesteps, ti_gravity_beg_max = 0; integertime_t ti_stars_end_min = max_nr_timesteps, ti_stars_beg_max = 0; integertime_t ti_sinks_end_min = max_nr_timesteps, ti_sinks_beg_max = 0; integertime_t ti_black_holes_end_min = max_nr_timesteps, ti_black_holes_beg_max = 0; struct part *parts = c->hydro.parts; struct gpart *gparts = c->grav.parts; struct spart *sparts = c->stars.parts; struct bpart *bparts = c->black_holes.parts; struct xpart *xparts = c->hydro.xparts; struct sink *sinks = c->sinks.parts; struct engine *e = s->e; const integertime_t ti_current = e->ti_current; const int with_rt = e->policy & engine_policy_rt; /* Set the top level cell tpid. Doing it here ensures top level cells * have the same tpid as their progeny. */ if (depth == 0) c->tpid = tpid; /* If the buff is NULL, allocate it, and remember to free it. */ const int allocate_buffer = (buff == NULL && gbuff == NULL && sbuff == NULL && bbuff == NULL && sink_buff == NULL); if (allocate_buffer) { if (count > 0) { if (swift_memalign("tempbuff", (void **)&buff, SWIFT_STRUCT_ALIGNMENT, sizeof(struct cell_buff) * count) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < count; k++) { #ifdef SWIFT_DEBUG_CHECKS if (parts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); if (parts[k].time_bin == time_bin_not_created) error("Extra particle present in space_split()"); #endif buff[k].x[0] = parts[k].x[0]; buff[k].x[1] = parts[k].x[1]; buff[k].x[2] = parts[k].x[2]; } } if (gcount > 0) { if (swift_memalign("tempgbuff", (void **)&gbuff, SWIFT_STRUCT_ALIGNMENT, sizeof(struct cell_buff) * gcount) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < gcount; k++) { #ifdef SWIFT_DEBUG_CHECKS if (gparts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); if (gparts[k].time_bin == time_bin_not_created) error("Extra particle present in space_split()"); #endif gbuff[k].x[0] = gparts[k].x[0]; gbuff[k].x[1] = gparts[k].x[1]; gbuff[k].x[2] = gparts[k].x[2]; } } if (scount > 0) { if (swift_memalign("tempsbuff", (void **)&sbuff, SWIFT_STRUCT_ALIGNMENT, sizeof(struct cell_buff) * scount) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < scount; k++) { #ifdef SWIFT_DEBUG_CHECKS if (sparts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); if (sparts[k].time_bin == time_bin_not_created) error("Extra particle present in space_split()"); #endif sbuff[k].x[0] = sparts[k].x[0]; sbuff[k].x[1] = sparts[k].x[1]; sbuff[k].x[2] = sparts[k].x[2]; } } if (bcount > 0) { if (swift_memalign("tempbbuff", (void **)&bbuff, SWIFT_STRUCT_ALIGNMENT, sizeof(struct cell_buff) * bcount) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < bcount; k++) { #ifdef SWIFT_DEBUG_CHECKS if (bparts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); if (bparts[k].time_bin == time_bin_not_created) error("Extra particle present in space_split()"); #endif bbuff[k].x[0] = bparts[k].x[0]; bbuff[k].x[1] = bparts[k].x[1]; bbuff[k].x[2] = bparts[k].x[2]; } } if (sink_count > 0) { if (swift_memalign("temp_sink_buff", (void **)&sink_buff, SWIFT_STRUCT_ALIGNMENT, sizeof(struct cell_buff) * sink_count) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < sink_count; k++) { #ifdef SWIFT_DEBUG_CHECKS if (sinks[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); if (sinks[k].time_bin == time_bin_not_created) error("Extra particle present in space_split()"); #endif sink_buff[k].x[0] = sinks[k].x[0]; sink_buff[k].x[1] = sinks[k].x[1]; sink_buff[k].x[2] = sinks[k].x[2]; } } } /* If the depth is too large, we have a problem and should stop. */ if (depth > space_cell_maxdepth) { error( "Exceeded maximum depth (%d) when splitting cells, aborting. This is " "most likely due to having too many particles at the exact same " "position, making the construction of a tree impossible.", space_cell_maxdepth); } /* Split or let it be? */ if ((with_self_gravity && gcount > space_splitsize) || (!with_self_gravity && (count > space_splitsize || scount > space_splitsize))) { /* No longer just a leaf. */ c->split = 1; /* Create the cell's progeny. */ space_getcells(s, 8, c->progeny, tpid); for (int k = 0; k < 8; k++) { struct cell *cp = c->progeny[k]; cp->hydro.count = 0; cp->grav.count = 0; cp->stars.count = 0; cp->sinks.count = 0; cp->black_holes.count = 0; cp->hydro.count_total = 0; cp->grav.count_total = 0; cp->sinks.count_total = 0; cp->stars.count_total = 0; cp->black_holes.count_total = 0; cp->hydro.ti_old_part = c->hydro.ti_old_part; cp->grav.ti_old_part = c->grav.ti_old_part; cp->grav.ti_old_multipole = c->grav.ti_old_multipole; cp->stars.ti_old_part = c->stars.ti_old_part; cp->sinks.ti_old_part = c->sinks.ti_old_part; cp->black_holes.ti_old_part = c->black_holes.ti_old_part; cp->loc[0] = c->loc[0]; cp->loc[1] = c->loc[1]; cp->loc[2] = c->loc[2]; cp->width[0] = c->width[0] / 2; cp->width[1] = c->width[1] / 2; cp->width[2] = c->width[2] / 2; cp->dmin = c->dmin / 2; cp->h_min_allowed = cp->dmin * 0.5 * (1. / kernel_gamma); cp->h_max_allowed = cp->dmin * (1. / kernel_gamma); if (k & 4) cp->loc[0] += cp->width[0]; if (k & 2) cp->loc[1] += cp->width[1]; if (k & 1) cp->loc[2] += cp->width[2]; cp->depth = c->depth + 1; cp->split = 0; cp->hydro.h_max = 0.f; cp->hydro.h_max_active = 0.f; cp->hydro.dx_max_part = 0.f; cp->hydro.dx_max_sort = 0.f; cp->stars.h_max = 0.f; cp->stars.h_max_active = 0.f; cp->stars.dx_max_part = 0.f; cp->stars.dx_max_sort = 0.f; cp->sinks.h_max = 0.f; cp->sinks.h_max_active = 0.f; cp->sinks.dx_max_part = 0.f; cp->black_holes.h_max = 0.f; cp->black_holes.h_max_active = 0.f; cp->black_holes.dx_max_part = 0.f; cp->nodeID = c->nodeID; cp->parent = c; cp->top = c->top; cp->super = NULL; cp->hydro.super = NULL; cp->grav.super = NULL; cp->flags = 0; star_formation_logger_init(&cp->stars.sfh); #ifdef WITH_MPI cp->mpi.tag = -1; #endif // WITH_MPI #if defined(SWIFT_DEBUG_CHECKS) || defined(SWIFT_CELL_GRAPH) cell_assign_cell_index(cp, c); #endif } /* Split the cell's particle data. */ cell_split(c, c->hydro.parts - s->parts, c->stars.parts - s->sparts, c->black_holes.parts - s->bparts, c->sinks.parts - s->sinks, buff, sbuff, bbuff, gbuff, sink_buff); /* Buffers for the progenitors */ struct cell_buff *progeny_buff = buff, *progeny_gbuff = gbuff, *progeny_sbuff = sbuff, *progeny_bbuff = bbuff, *progeny_sink_buff = sink_buff; for (int k = 0; k < 8; k++) { /* Get the progenitor */ struct cell *cp = c->progeny[k]; /* Remove any progeny with zero particles. */ if (cp->hydro.count == 0 && cp->grav.count == 0 && cp->stars.count == 0 && cp->black_holes.count == 0 && cp->sinks.count == 0) { space_recycle(s, cp); c->progeny[k] = NULL; } else { /* Recurse */ space_split_recursive(s, cp, progeny_buff, progeny_sbuff, progeny_bbuff, progeny_gbuff, progeny_sink_buff, tpid); /* Update the pointers in the buffers */ progeny_buff += cp->hydro.count; progeny_gbuff += cp->grav.count; progeny_sbuff += cp->stars.count; progeny_bbuff += cp->black_holes.count; progeny_sink_buff += cp->sinks.count; /* Update the cell-wide properties */ h_max = max(h_max, cp->hydro.h_max); h_max_active = max(h_max_active, cp->hydro.h_max_active); stars_h_max = max(stars_h_max, cp->stars.h_max); stars_h_max_active = max(stars_h_max_active, cp->stars.h_max_active); black_holes_h_max = max(black_holes_h_max, cp->black_holes.h_max); black_holes_h_max_active = max(black_holes_h_max_active, cp->black_holes.h_max_active); sinks_h_max = max(sinks_h_max, cp->sinks.h_max); sinks_h_max_active = max(sinks_h_max_active, cp->sinks.h_max_active); ti_hydro_end_min = min(ti_hydro_end_min, cp->hydro.ti_end_min); ti_hydro_beg_max = max(ti_hydro_beg_max, cp->hydro.ti_beg_max); ti_rt_end_min = min(ti_rt_end_min, cp->rt.ti_rt_end_min); ti_rt_beg_max = max(ti_rt_beg_max, cp->rt.ti_rt_beg_max); ti_rt_min_step_size = min(ti_rt_min_step_size, cp->rt.ti_rt_min_step_size); ti_gravity_end_min = min(ti_gravity_end_min, cp->grav.ti_end_min); ti_gravity_beg_max = max(ti_gravity_beg_max, cp->grav.ti_beg_max); ti_stars_end_min = min(ti_stars_end_min, cp->stars.ti_end_min); ti_stars_beg_max = max(ti_stars_beg_max, cp->stars.ti_beg_max); ti_sinks_end_min = min(ti_sinks_end_min, cp->sinks.ti_end_min); ti_sinks_beg_max = max(ti_sinks_beg_max, cp->sinks.ti_beg_max); ti_black_holes_end_min = min(ti_black_holes_end_min, cp->black_holes.ti_end_min); ti_black_holes_beg_max = max(ti_black_holes_beg_max, cp->black_holes.ti_beg_max); star_formation_logger_add(&c->stars.sfh, &cp->stars.sfh); /* Increase the depth */ maxdepth = max(maxdepth, cp->maxdepth); } } /* Deal with the multipole */ if (s->with_self_gravity) { /* Reset everything */ gravity_reset(c->grav.multipole); /* Compute CoM and bulk velocity from all progenies */ double CoM[3] = {0., 0., 0.}; double vel[3] = {0., 0., 0.}; float max_delta_vel[3] = {0.f, 0.f, 0.f}; float min_delta_vel[3] = {0.f, 0.f, 0.f}; double mass = 0.; for (int k = 0; k < 8; ++k) { if (c->progeny[k] != NULL) { const struct gravity_tensors *m = c->progeny[k]->grav.multipole; mass += m->m_pole.M_000; CoM[0] += m->CoM[0] * m->m_pole.M_000; CoM[1] += m->CoM[1] * m->m_pole.M_000; CoM[2] += m->CoM[2] * m->m_pole.M_000; vel[0] += m->m_pole.vel[0] * m->m_pole.M_000; vel[1] += m->m_pole.vel[1] * m->m_pole.M_000; vel[2] += m->m_pole.vel[2] * m->m_pole.M_000; max_delta_vel[0] = max(m->m_pole.max_delta_vel[0], max_delta_vel[0]); max_delta_vel[1] = max(m->m_pole.max_delta_vel[1], max_delta_vel[1]); max_delta_vel[2] = max(m->m_pole.max_delta_vel[2], max_delta_vel[2]); min_delta_vel[0] = min(m->m_pole.min_delta_vel[0], min_delta_vel[0]); min_delta_vel[1] = min(m->m_pole.min_delta_vel[1], min_delta_vel[1]); min_delta_vel[2] = min(m->m_pole.min_delta_vel[2], min_delta_vel[2]); } } /* Final operation on the CoM and bulk velocity */ const double inv_mass = 1. / mass; c->grav.multipole->CoM[0] = CoM[0] * inv_mass; c->grav.multipole->CoM[1] = CoM[1] * inv_mass; c->grav.multipole->CoM[2] = CoM[2] * inv_mass; c->grav.multipole->m_pole.vel[0] = vel[0] * inv_mass; c->grav.multipole->m_pole.vel[1] = vel[1] * inv_mass; c->grav.multipole->m_pole.vel[2] = vel[2] * inv_mass; /* Min max velocity along each axis */ c->grav.multipole->m_pole.max_delta_vel[0] = max_delta_vel[0]; c->grav.multipole->m_pole.max_delta_vel[1] = max_delta_vel[1]; c->grav.multipole->m_pole.max_delta_vel[2] = max_delta_vel[2]; c->grav.multipole->m_pole.min_delta_vel[0] = min_delta_vel[0]; c->grav.multipole->m_pole.min_delta_vel[1] = min_delta_vel[1]; c->grav.multipole->m_pole.min_delta_vel[2] = min_delta_vel[2]; /* Now shift progeny multipoles and add them up */ struct multipole temp; double r_max = 0.; for (int k = 0; k < 8; ++k) { if (c->progeny[k] != NULL) { const struct cell *cp = c->progeny[k]; const struct multipole *m = &cp->grav.multipole->m_pole; /* Contribution to multipole */ gravity_M2M(&temp, m, c->grav.multipole->CoM, cp->grav.multipole->CoM); gravity_multipole_add(&c->grav.multipole->m_pole, &temp); /* Upper limit of max CoM<->gpart distance */ const double dx = c->grav.multipole->CoM[0] - cp->grav.multipole->CoM[0]; const double dy = c->grav.multipole->CoM[1] - cp->grav.multipole->CoM[1]; const double dz = c->grav.multipole->CoM[2] - cp->grav.multipole->CoM[2]; const double r2 = dx * dx + dy * dy + dz * dz; r_max = max(r_max, cp->grav.multipole->r_max + sqrt(r2)); } } /* Alternative upper limit of max CoM<->gpart distance */ const double dx = c->grav.multipole->CoM[0] > c->loc[0] + c->width[0] / 2. ? c->grav.multipole->CoM[0] - c->loc[0] : c->loc[0] + c->width[0] - c->grav.multipole->CoM[0]; const double dy = c->grav.multipole->CoM[1] > c->loc[1] + c->width[1] / 2. ? c->grav.multipole->CoM[1] - c->loc[1] : c->loc[1] + c->width[1] - c->grav.multipole->CoM[1]; const double dz = c->grav.multipole->CoM[2] > c->loc[2] + c->width[2] / 2. ? c->grav.multipole->CoM[2] - c->loc[2] : c->loc[2] + c->width[2] - c->grav.multipole->CoM[2]; /* Take minimum of both limits */ c->grav.multipole->r_max = min(r_max, sqrt(dx * dx + dy * dy + dz * dz)); /* Store the value at rebuild time */ c->grav.multipole->r_max_rebuild = c->grav.multipole->r_max; c->grav.multipole->CoM_rebuild[0] = c->grav.multipole->CoM[0]; c->grav.multipole->CoM_rebuild[1] = c->grav.multipole->CoM[1]; c->grav.multipole->CoM_rebuild[2] = c->grav.multipole->CoM[2]; /* Compute the multipole power */ gravity_multipole_compute_power(&c->grav.multipole->m_pole); } /* Deal with gravity */ } /* Split or let it be? */ /* Otherwise, collect the data from the particles this cell. */ else { /* Clear the progeny. */ bzero(c->progeny, sizeof(struct cell *) * 8); c->split = 0; maxdepth = c->depth; ti_hydro_end_min = max_nr_timesteps; ti_hydro_beg_max = 0; ti_gravity_end_min = max_nr_timesteps; ti_gravity_beg_max = 0; ti_stars_end_min = max_nr_timesteps; ti_stars_beg_max = 0; ti_black_holes_end_min = max_nr_timesteps; ti_black_holes_beg_max = 0; ti_rt_end_min = max_nr_timesteps; ti_rt_beg_max = 0; ti_rt_min_step_size = max_nr_timesteps; /* parts: Get dt_min/dt_max and h_max. */ for (int k = 0; k < count; k++) { #ifdef SWIFT_DEBUG_CHECKS if (parts[k].time_bin == time_bin_not_created) error("Extra particle present in space_split()"); if (parts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); #endif /* When does this particle's time-step start and end? */ const timebin_t time_bin = parts[k].time_bin; const timebin_t time_bin_rt = parts[k].rt_time_data.time_bin; const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); ti_hydro_end_min = min(ti_hydro_end_min, ti_end); ti_hydro_beg_max = max(ti_hydro_beg_max, ti_beg); if (with_rt) { /* Contrary to other physics, RT doesn't have its own particle type. * So collect time step data from particles only when we're running * with RT. Otherwise, we may find cells which are active or in * impossible timezones. Skipping this check results in cells having * RT times = max_nr_timesteps or zero, respecively. */ const integertime_t ti_rt_end = get_integer_time_end(ti_current, time_bin_rt); const integertime_t ti_rt_beg = get_integer_time_begin(ti_current, time_bin_rt); const integertime_t ti_rt_step = get_integer_timestep(time_bin_rt); ti_rt_end_min = min(ti_rt_end_min, ti_rt_end); ti_rt_beg_max = max(ti_rt_beg_max, ti_rt_beg); ti_rt_min_step_size = min(ti_rt_min_step_size, ti_rt_step); } h_max = max(h_max, parts[k].h); if (part_is_active(&parts[k], e)) h_max_active = max(h_max_active, parts[k].h); cell_set_part_h_depth(&parts[k], c); /* Collect SFR from the particles after rebuilt */ star_formation_logger_log_inactive_part(&parts[k], &xparts[k], &c->stars.sfh); } /* xparts: Reset x_diff */ for (int k = 0; k < count; k++) { xparts[k].x_diff[0] = 0.f; xparts[k].x_diff[1] = 0.f; xparts[k].x_diff[2] = 0.f; } /* gparts: Get dt_min/dt_max. */ for (int k = 0; k < gcount; k++) { #ifdef SWIFT_DEBUG_CHECKS if (gparts[k].time_bin == time_bin_not_created) error("Extra g-particle present in space_split()"); if (gparts[k].time_bin == time_bin_inhibited) error("Inhibited g-particle present in space_split()"); #endif /* When does this particle's time-step start and end? */ const timebin_t time_bin = gparts[k].time_bin; const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); ti_gravity_end_min = min(ti_gravity_end_min, ti_end); ti_gravity_beg_max = max(ti_gravity_beg_max, ti_beg); } /* sparts: Get dt_min/dt_max */ for (int k = 0; k < scount; k++) { #ifdef SWIFT_DEBUG_CHECKS if (sparts[k].time_bin == time_bin_not_created) error("Extra s-particle present in space_split()"); if (sparts[k].time_bin == time_bin_inhibited) error("Inhibited s-particle present in space_split()"); #endif /* When does this particle's time-step start and end? */ const timebin_t time_bin = sparts[k].time_bin; const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); ti_stars_end_min = min(ti_stars_end_min, ti_end); ti_stars_beg_max = max(ti_stars_beg_max, ti_beg); stars_h_max = max(stars_h_max, sparts[k].h); if (spart_is_active(&sparts[k], e)) stars_h_max_active = max(stars_h_max_active, sparts[k].h); cell_set_spart_h_depth(&sparts[k], c); /* Reset x_diff */ sparts[k].x_diff[0] = 0.f; sparts[k].x_diff[1] = 0.f; sparts[k].x_diff[2] = 0.f; } /* sinks: Get dt_min/dt_max */ for (int k = 0; k < sink_count; k++) { #ifdef SWIFT_DEBUG_CHECKS if (sinks[k].time_bin == time_bin_not_created) error("Extra sink-particle present in space_split()"); if (sinks[k].time_bin == time_bin_inhibited) error("Inhibited sink-particle present in space_split()"); #endif /* When does this particle's time-step start and end? */ const timebin_t time_bin = sinks[k].time_bin; const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); ti_sinks_end_min = min(ti_sinks_end_min, ti_end); ti_sinks_beg_max = max(ti_sinks_beg_max, ti_beg); sinks_h_max = max(sinks_h_max, sinks[k].h); if (sink_is_active(&sinks[k], e)) sinks_h_max_active = max(sinks_h_max_active, sinks[k].h); cell_set_sink_h_depth(&sinks[k], c); /* Reset x_diff */ sinks[k].x_diff[0] = 0.f; sinks[k].x_diff[1] = 0.f; sinks[k].x_diff[2] = 0.f; } /* bparts: Get dt_min/dt_max */ for (int k = 0; k < bcount; k++) { #ifdef SWIFT_DEBUG_CHECKS if (bparts[k].time_bin == time_bin_not_created) error("Extra b-particle present in space_split()"); if (bparts[k].time_bin == time_bin_inhibited) error("Inhibited b-particle present in space_split()"); #endif /* When does this particle's time-step start and end? */ const timebin_t time_bin = bparts[k].time_bin; const integertime_t ti_end = get_integer_time_end(ti_current, time_bin); const integertime_t ti_beg = get_integer_time_begin(ti_current, time_bin); ti_black_holes_end_min = min(ti_black_holes_end_min, ti_end); ti_black_holes_beg_max = max(ti_black_holes_beg_max, ti_beg); black_holes_h_max = max(black_holes_h_max, bparts[k].h); if (bpart_is_active(&bparts[k], e)) black_holes_h_max_active = max(black_holes_h_max_active, bparts[k].h); cell_set_bpart_h_depth(&bparts[k], c); /* Reset x_diff */ bparts[k].x_diff[0] = 0.f; bparts[k].x_diff[1] = 0.f; bparts[k].x_diff[2] = 0.f; } /* Construct the multipole and the centre of mass*/ if (s->with_self_gravity) { if (gcount > 0) { gravity_P2M(c->grav.multipole, c->grav.parts, c->grav.count, e->gravity_properties); /* Compute the multipole power */ gravity_multipole_compute_power(&c->grav.multipole->m_pole); } else { /* No gparts in that leaf cell */ /* Set the values to something sensible */ gravity_multipole_init(&c->grav.multipole->m_pole); if (c->nodeID == engine_rank) { c->grav.multipole->CoM[0] = c->loc[0] + c->width[0] / 2.; c->grav.multipole->CoM[1] = c->loc[1] + c->width[1] / 2.; c->grav.multipole->CoM[2] = c->loc[2] + c->width[2] / 2.; c->grav.multipole->r_max = 0.; } } /* Store the value at rebuild time */ c->grav.multipole->r_max_rebuild = c->grav.multipole->r_max; c->grav.multipole->CoM_rebuild[0] = c->grav.multipole->CoM[0]; c->grav.multipole->CoM_rebuild[1] = c->grav.multipole->CoM[1]; c->grav.multipole->CoM_rebuild[2] = c->grav.multipole->CoM[2]; } } /* Set the values for this cell. */ c->hydro.h_max = h_max; c->hydro.h_max_active = h_max_active; c->hydro.ti_end_min = ti_hydro_end_min; c->hydro.ti_beg_max = ti_hydro_beg_max; c->rt.ti_rt_end_min = ti_rt_end_min; c->rt.ti_rt_beg_max = ti_rt_beg_max; c->rt.ti_rt_min_step_size = ti_rt_min_step_size; c->grav.ti_end_min = ti_gravity_end_min; c->grav.ti_beg_max = ti_gravity_beg_max; c->stars.ti_end_min = ti_stars_end_min; c->stars.ti_beg_max = ti_stars_beg_max; c->stars.h_max = stars_h_max; c->stars.h_max_active = stars_h_max_active; c->sinks.ti_end_min = ti_sinks_end_min; c->sinks.ti_beg_max = ti_sinks_beg_max; c->sinks.h_max = sinks_h_max; c->sinks.h_max_active = sinks_h_max_active; c->black_holes.ti_end_min = ti_black_holes_end_min; c->black_holes.ti_beg_max = ti_black_holes_beg_max; c->black_holes.h_max = black_holes_h_max; c->black_holes.h_max_active = black_holes_h_max_active; c->maxdepth = maxdepth; /* No runner owns this cell yet. We assign those during scheduling. */ c->owner = -1; /* Store the global max depth */ if (c->depth == 0) atomic_max(&s->maxdepth, maxdepth); /* Clean up. */ if (allocate_buffer) { if (buff != NULL) swift_free("tempbuff", buff); if (gbuff != NULL) swift_free("tempgbuff", gbuff); if (sbuff != NULL) swift_free("tempsbuff", sbuff); if (bbuff != NULL) swift_free("tempbbuff", bbuff); if (sink_buff != NULL) swift_free("temp_sink_buff", sink_buff); } } /** * @brief #threadpool mapper function to split cells if they contain * too many particles. * * @param map_data Pointer towards the top-cells. * @param num_cells The number of cells to treat. * @param extra_data Pointers to the #space. */ void space_split_mapper(void *map_data, int num_cells, void *extra_data) { /* Unpack the inputs. */ struct space *s = (struct space *)extra_data; struct cell *cells_top = s->cells_top; int *local_cells_with_particles = (int *)map_data; /* Collect some global information about the top-level m-poles */ float min_a_grav = FLT_MAX; float max_softening = 0.f; float max_mpole_power[SELF_GRAVITY_MULTIPOLE_ORDER + 1] = {0.f}; /* Threadpool id of current thread. */ short int tpid = threadpool_gettid(); /* Loop over the non-empty cells */ for (int ind = 0; ind < num_cells; ind++) { struct cell *c = &cells_top[local_cells_with_particles[ind]]; space_split_recursive(s, c, NULL, NULL, NULL, NULL, NULL, tpid); if (s->with_self_gravity) { min_a_grav = min(min_a_grav, c->grav.multipole->m_pole.min_old_a_grav_norm); max_softening = max(max_softening, c->grav.multipole->m_pole.max_softening); for (int n = 0; n < SELF_GRAVITY_MULTIPOLE_ORDER + 1; ++n) max_mpole_power[n] = max(max_mpole_power[n], c->grav.multipole->m_pole.power[n]); } } #ifdef SWIFT_DEBUG_CHECKS /* All cells and particles should have consistent h_max values. */ for (int ind = 0; ind < num_cells; ind++) { int depth = 0; const struct cell *c = &cells_top[local_cells_with_particles[ind]]; if (!checkCellhdxmax(c, &depth)) message(" at cell depth %d", depth); } #endif atomic_min_f(&s->min_a_grav, min_a_grav); atomic_max_f(&s->max_softening, max_softening); for (int n = 0; n < SELF_GRAVITY_MULTIPOLE_ORDER + 1; ++n) atomic_max_f(&s->max_mpole_power[n], max_mpole_power[n]); } /** * @brief Split particles between cells of a hierarchy. * * This is done in parallel using threads in the #threadpool. * Only do this for the local non-empty top-level cells. * * @param s The #space. * @param verbose Are we talkative ? */ void space_split(struct space *s, int verbose) { const ticks tic = getticks(); s->min_a_grav = FLT_MAX; s->max_softening = 0.f; bzero(s->max_mpole_power, (SELF_GRAVITY_MULTIPOLE_ORDER + 1) * sizeof(float)); threadpool_map(&s->e->threadpool, space_split_mapper, s->local_cells_with_particles_top, s->nr_local_cells_with_particles, sizeof(int), threadpool_auto_chunk_size, s); if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); }