/******************************************************************************* * 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 "cell.h" #include "engine.h" /* Some standard headers. */ #include /** * @brief Allocate memory for the extra particles used for on-the-fly creation. * * This rarely actually allocates memory. Most of the time, we convert * pre-allocated memory inot extra particles. * * This function also sets the extra particles' location to their top-level * cells. They can then be sorted into their correct memory position later on. * * @param s The current #space. * @param verbose Are we talkative? */ void space_allocate_extras(struct space *s, int verbose) { const int local_nodeID = s->e->nodeID; /* Anything to do here? (Abort if we don't want extras)*/ if (space_extra_parts == 0 && space_extra_gparts == 0 && space_extra_sparts == 0 && space_extra_bparts == 0 && space_extra_sinks == 0) return; /* The top-level cells */ const struct cell *cells = s->cells_top; const double half_cell_width[3] = {0.5 * cells[0].width[0], 0.5 * cells[0].width[1], 0.5 * cells[0].width[2]}; /* The current number of particles (including spare ones) */ size_t nr_parts = s->nr_parts; size_t nr_gparts = s->nr_gparts; size_t nr_sparts = s->nr_sparts; size_t nr_bparts = s->nr_bparts; size_t nr_sinks = s->nr_sinks; /* The current number of actual particles */ size_t nr_actual_parts = nr_parts - s->nr_extra_parts; size_t nr_actual_gparts = nr_gparts - s->nr_extra_gparts; size_t nr_actual_sparts = nr_sparts - s->nr_extra_sparts; size_t nr_actual_bparts = nr_bparts - s->nr_extra_bparts; size_t nr_actual_sinks = nr_sinks - s->nr_extra_sinks; /* The number of particles we allocated memory for (MPI overhead) */ size_t size_parts = s->size_parts; size_t size_gparts = s->size_gparts; size_t size_sparts = s->size_sparts; size_t size_bparts = s->size_bparts; size_t size_sinks = s->size_sinks; int *local_cells = (int *)malloc(sizeof(int) * s->nr_cells); if (local_cells == NULL) error("Failed to allocate list of local top-level cells"); /* List the local cells */ size_t nr_local_cells = 0; for (int i = 0; i < s->nr_cells; ++i) { if (s->cells_top[i].nodeID == local_nodeID) { local_cells[nr_local_cells] = i; ++nr_local_cells; } } /* Number of extra particles we want for each type */ const size_t expected_num_extra_parts = nr_local_cells * space_extra_parts; const size_t expected_num_extra_gparts = nr_local_cells * space_extra_gparts; const size_t expected_num_extra_sparts = nr_local_cells * space_extra_sparts; const size_t expected_num_extra_bparts = nr_local_cells * space_extra_bparts; const size_t expected_num_extra_sinks = nr_local_cells * space_extra_sinks; if (verbose) { message("Currently have %zd/%zd/%zd/%zd/%zd real particles.", nr_actual_parts, nr_actual_gparts, nr_actual_sinks, nr_actual_sparts, nr_actual_bparts); message("Currently have %zd/%zd/%zd/%zd/%zd spaces for extra particles.", s->nr_extra_parts, s->nr_extra_gparts, s->nr_extra_sinks, s->nr_extra_sparts, s->nr_extra_bparts); message( "Requesting space for future %zd/%zd/%zd/%zd/%zd " "part/gpart/sinks/sparts/bparts.", expected_num_extra_parts, expected_num_extra_gparts, expected_num_extra_sinks, expected_num_extra_sparts, expected_num_extra_bparts); } if (expected_num_extra_parts < s->nr_extra_parts) error( "Reduction in top-level cells number not handled. Please set a lower " "h_max or reduce the number of top level cells."); if (expected_num_extra_gparts < s->nr_extra_gparts) error( "Reduction in top-level cells number not handled. Please set a lower " "h_max or reduce the number of top level cells."); if (expected_num_extra_sparts < s->nr_extra_sparts) error( "Reduction in top-level cells number not handled. Please set a lower " "h_max or reduce the number of top level cells."); if (expected_num_extra_bparts < s->nr_extra_bparts) error( "Reduction in top-level cells number not handled. Please set a lower " "h_max or reduce the number of top level cells."); if (expected_num_extra_sinks < s->nr_extra_sinks) error( "Reduction in top-level cells number not handled. Please set a lower " "h_max or reduce the number of top level cells."); /* Do we have enough space for the extra gparts (i.e. we haven't used up any) * ? */ if (nr_actual_gparts + expected_num_extra_gparts > nr_gparts) { /* Ok... need to put some more in the game */ /* Do we need to reallocate? */ if (nr_actual_gparts + expected_num_extra_gparts > size_gparts) { size_gparts = (nr_actual_gparts + expected_num_extra_gparts) * engine_redistribute_alloc_margin; if (verbose) message("Re-allocating gparts array from %zd to %zd", s->size_gparts, size_gparts); /* Create more space for parts */ struct gpart *gparts_new = NULL; if (swift_memalign("gparts", (void **)&gparts_new, gpart_align, sizeof(struct gpart) * size_gparts) != 0) error("Failed to allocate new gpart data"); memcpy(gparts_new, s->gparts, sizeof(struct gpart) * s->size_gparts); swift_free("gparts", s->gparts); s->gparts = gparts_new; /* Update the counter */ s->size_gparts = size_gparts; /* We now need to correct all the pointers of the other particle arrays */ part_relink_all_parts_to_gparts(gparts_new, s->nr_gparts, s->parts, s->sinks, s->sparts, s->bparts, &s->e->threadpool); } /* Turn some of the allocated spares into particles we can use */ for (size_t i = nr_gparts; i < nr_actual_gparts + expected_num_extra_gparts; ++i) { bzero(&s->gparts[i], sizeof(struct gpart)); s->gparts[i].time_bin = time_bin_not_created; s->gparts[i].type = swift_type_dark_matter; s->gparts[i].id_or_neg_offset = -1; } /* Put the spare particles in their correct cell */ size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; #ifdef SWIFT_DEBUG_CHECKS size_t count_extra_gparts = 0; #endif for (size_t i = 0; i < nr_actual_gparts + expected_num_extra_gparts; ++i) { #ifdef SWIFT_DEBUG_CHECKS if (current_cell == s->nr_cells) error("Cell counter beyond the maximal nr. cells."); #endif if (s->gparts[i].time_bin == time_bin_not_created) { /* We want the extra particles to be at the centre of their cell */ s->gparts[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; s->gparts[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; s->gparts[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; ++count_in_cell; #ifdef SWIFT_DEBUG_CHECKS count_extra_gparts++; #endif } /* Once we have reached the number of extra gpart per cell, we move to the * next */ if (count_in_cell == space_extra_gparts) { ++local_cell_id; if (local_cell_id == nr_local_cells) break; current_cell = local_cells[local_cell_id]; count_in_cell = 0; } } #ifdef SWIFT_DEBUG_CHECKS if (count_extra_gparts != expected_num_extra_gparts) error("Constructed the wrong number of extra gparts (%zd vs. %zd)", count_extra_gparts, expected_num_extra_gparts); #endif /* Update the counters */ s->nr_gparts = nr_actual_gparts + expected_num_extra_gparts; s->nr_extra_gparts = expected_num_extra_gparts; } /* Do we have enough space for the extra parts (i.e. we haven't used up any) ? */ if (nr_actual_parts + expected_num_extra_parts > nr_parts) { /* Ok... need to put some more in the game */ /* Do we need to reallocate? */ if (nr_actual_parts + expected_num_extra_parts > size_parts) { size_parts = (nr_actual_parts + expected_num_extra_parts) * engine_redistribute_alloc_margin; if (verbose) message("Re-allocating parts array from %zd to %zd", s->size_parts, size_parts); /* Create more space for parts */ struct part *parts_new = NULL; if (swift_memalign("parts", (void **)&parts_new, part_align, sizeof(struct part) * size_parts) != 0) error("Failed to allocate new part data"); memcpy(parts_new, s->parts, sizeof(struct part) * s->size_parts); swift_free("parts", s->parts); s->parts = parts_new; /* Same for xparts */ struct xpart *xparts_new = NULL; if (swift_memalign("xparts", (void **)&xparts_new, xpart_align, sizeof(struct xpart) * size_parts) != 0) error("Failed to allocate new xpart data"); memcpy(xparts_new, s->xparts, sizeof(struct xpart) * s->size_parts); swift_free("xparts", s->xparts); s->xparts = xparts_new; /* Update the counter */ s->size_parts = size_parts; } /* Turn some of the allocated spares into particles we can use */ for (size_t i = nr_parts; i < nr_actual_parts + expected_num_extra_parts; ++i) { bzero(&s->parts[i], sizeof(struct part)); bzero(&s->xparts[i], sizeof(struct xpart)); s->parts[i].time_bin = time_bin_not_created; s->parts[i].id = -42; } /* Put the spare particles in their correct cell */ size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; #ifdef SWIFT_DEBUG_CHECKS size_t count_extra_parts = 0; #endif for (size_t i = 0; i < nr_actual_parts + expected_num_extra_parts; ++i) { #ifdef SWIFT_DEBUG_CHECKS if (current_cell == s->nr_cells) error("Cell counter beyond the maximal nr. cells."); #endif if (s->parts[i].time_bin == time_bin_not_created) { /* We want the extra particles to be at the centre of their cell */ s->parts[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; s->parts[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; s->parts[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; ++count_in_cell; #ifdef SWIFT_DEBUG_CHECKS count_extra_parts++; #endif } /* Once we have reached the number of extra part per cell, we move to the * next */ if (count_in_cell == space_extra_parts) { ++local_cell_id; if (local_cell_id == nr_local_cells) break; current_cell = local_cells[local_cell_id]; count_in_cell = 0; } } #ifdef SWIFT_DEBUG_CHECKS if (count_extra_parts != expected_num_extra_parts) error("Constructed the wrong number of extra parts (%zd vs. %zd)", count_extra_parts, expected_num_extra_parts); #endif /* Update the counters */ s->nr_parts = nr_actual_parts + expected_num_extra_parts; s->nr_extra_parts = expected_num_extra_parts; } /* Do we have enough space for the extra sinks (i.e. we haven't used up any) * ? */ if (nr_actual_sinks + expected_num_extra_sinks > nr_sinks) { /* Ok... need to put some more in the game */ /* Do we need to reallocate? */ if (nr_actual_sinks + expected_num_extra_sinks > size_sinks) { size_sinks = (nr_actual_sinks + expected_num_extra_sinks) * engine_redistribute_alloc_margin; if (verbose) message("Re-allocating sinks array from %zd to %zd", s->size_sinks, size_sinks); /* Create more space for parts */ struct sink *sinks_new = NULL; if (swift_memalign("sinks", (void **)&sinks_new, sink_align, sizeof(struct sink) * size_sinks) != 0) error("Failed to allocate new sink data"); memcpy(sinks_new, s->sinks, sizeof(struct sink) * s->size_sinks); swift_free("sinks", s->sinks); s->sinks = sinks_new; /* Update the counter */ s->size_sinks = size_sinks; } /* Turn some of the allocated spares into particles we can use */ for (size_t i = nr_sinks; i < nr_actual_sinks + expected_num_extra_sinks; ++i) { bzero(&s->sinks[i], sizeof(struct sink)); s->sinks[i].time_bin = time_bin_not_created; s->sinks[i].id = -42; sink_mark_sink_as_not_swallowed(&s->sinks[i].merger_data); } /* Put the spare particles in their correct cell */ size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; #ifdef SWIFT_DEBUG_CHECKS size_t count_extra_sinks = 0; #endif for (size_t i = 0; i < nr_actual_sinks + expected_num_extra_sinks; ++i) { #ifdef SWIFT_DEBUG_CHECKS if (current_cell == s->nr_cells) error("Cell counter beyond the maximal nr. cells."); #endif if (s->sinks[i].time_bin == time_bin_not_created) { /* We want the extra particles to be at the centre of their cell */ s->sinks[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; s->sinks[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; s->sinks[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; ++count_in_cell; #ifdef SWIFT_DEBUG_CHECKS count_extra_sinks++; #endif } /* Once we have reached the number of extra sink per cell, we move to the * next */ if (count_in_cell == space_extra_sinks) { ++local_cell_id; if (local_cell_id == nr_local_cells) break; current_cell = local_cells[local_cell_id]; count_in_cell = 0; } } #ifdef SWIFT_DEBUG_CHECKS if (count_extra_sinks != expected_num_extra_sinks) error("Constructed the wrong number of extra sinks (%zd vs. %zd)", count_extra_sinks, expected_num_extra_sinks); #endif /* Update the counters */ s->nr_sinks = nr_actual_sinks + expected_num_extra_sinks; s->nr_extra_sinks = expected_num_extra_sinks; } /* Do we have enough space for the extra sparts (i.e. we haven't used up any) * ? */ if (nr_actual_sparts + expected_num_extra_sparts > nr_sparts) { /* Ok... need to put some more in the game */ /* Do we need to reallocate? */ if (nr_actual_sparts + expected_num_extra_sparts > size_sparts) { size_sparts = (nr_actual_sparts + expected_num_extra_sparts) * engine_redistribute_alloc_margin; if (verbose) message("Re-allocating sparts array from %zd to %zd", s->size_sparts, size_sparts); /* Create more space for parts */ struct spart *sparts_new = NULL; if (swift_memalign("sparts", (void **)&sparts_new, spart_align, sizeof(struct spart) * size_sparts) != 0) error("Failed to allocate new spart data"); memcpy(sparts_new, s->sparts, sizeof(struct spart) * s->size_sparts); swift_free("sparts", s->sparts); s->sparts = sparts_new; /* Update the counter */ s->size_sparts = size_sparts; } /* Turn some of the allocated spares into particles we can use */ for (size_t i = nr_sparts; i < nr_actual_sparts + expected_num_extra_sparts; ++i) { bzero(&s->sparts[i], sizeof(struct spart)); s->sparts[i].time_bin = time_bin_not_created; s->sparts[i].id = -42; } /* Put the spare particles in their correct cell */ size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; #ifdef SWIFT_DEBUG_CHECKS size_t count_extra_sparts = 0; #endif for (size_t i = 0; i < nr_actual_sparts + expected_num_extra_sparts; ++i) { #ifdef SWIFT_DEBUG_CHECKS if (current_cell == s->nr_cells) error("Cell counter beyond the maximal nr. cells."); #endif if (s->sparts[i].time_bin == time_bin_not_created) { /* We want the extra particles to be at the centre of their cell */ s->sparts[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; s->sparts[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; s->sparts[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; ++count_in_cell; #ifdef SWIFT_DEBUG_CHECKS count_extra_sparts++; #endif } /* Once we have reached the number of extra spart per cell, we move to the * next */ if (count_in_cell == space_extra_sparts) { ++local_cell_id; if (local_cell_id == nr_local_cells) break; current_cell = local_cells[local_cell_id]; count_in_cell = 0; } } #ifdef SWIFT_DEBUG_CHECKS if (count_extra_sparts != expected_num_extra_sparts) error("Constructed the wrong number of extra sparts (%zd vs. %zd)", count_extra_sparts, expected_num_extra_sparts); #endif /* Update the counters */ s->nr_sparts = nr_actual_sparts + expected_num_extra_sparts; s->nr_extra_sparts = expected_num_extra_sparts; } /* Do we have enough space for the extra bparts (i.e. we haven't used up any) * ? */ if (nr_actual_bparts + expected_num_extra_bparts > nr_bparts) { /* Ok... need to put some more in the game */ /* Do we need to reallocate? */ if (nr_actual_bparts + expected_num_extra_bparts > size_bparts) { size_bparts = (nr_actual_bparts + expected_num_extra_bparts) * engine_redistribute_alloc_margin; if (verbose) message("Re-allocating bparts array from %zd to %zd", s->size_bparts, size_bparts); /* Create more space for parts */ struct bpart *bparts_new = NULL; if (swift_memalign("bparts", (void **)&bparts_new, bpart_align, sizeof(struct bpart) * size_bparts) != 0) error("Failed to allocate new bpart data"); memcpy(bparts_new, s->bparts, sizeof(struct bpart) * s->size_bparts); swift_free("bparts", s->bparts); s->bparts = bparts_new; /* Update the counter */ s->size_bparts = size_bparts; } /* Turn some of the allocated spares into particles we can use */ for (size_t i = nr_bparts; i < nr_actual_bparts + expected_num_extra_bparts; ++i) { bzero(&s->bparts[i], sizeof(struct bpart)); s->bparts[i].time_bin = time_bin_not_created; s->bparts[i].id = -42; } /* Put the spare particles in their correct cell */ size_t local_cell_id = 0; int current_cell = local_cells[local_cell_id]; int count_in_cell = 0; #ifdef SWIFT_DEBUG_CHECKS size_t count_extra_bparts = 0; #endif for (size_t i = 0; i < nr_actual_bparts + expected_num_extra_bparts; ++i) { #ifdef SWIFT_DEBUG_CHECKS if (current_cell == s->nr_cells) error("Cell counter beyond the maximal nr. cells."); #endif if (s->bparts[i].time_bin == time_bin_not_created) { /* We want the extra particles to be at the centre of their cell */ s->bparts[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; s->bparts[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; s->bparts[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; ++count_in_cell; #ifdef SWIFT_DEBUG_CHECKS count_extra_bparts++; #endif } /* Once we have reached the number of extra bpart per cell, we move to the * next */ if (count_in_cell == space_extra_bparts) { ++local_cell_id; if (local_cell_id == nr_local_cells) break; current_cell = local_cells[local_cell_id]; count_in_cell = 0; } } #ifdef SWIFT_DEBUG_CHECKS if (count_extra_bparts != expected_num_extra_bparts) error("Constructed the wrong number of extra bparts (%zd vs. %zd)", count_extra_bparts, expected_num_extra_bparts); #endif /* Update the counters */ s->nr_bparts = nr_actual_bparts + expected_num_extra_bparts; s->nr_extra_bparts = expected_num_extra_bparts; } #ifdef SWIFT_DEBUG_CHECKS /* Verify that the links are correct */ if ((nr_gparts > 0 && nr_parts > 0) || (nr_gparts > 0 && nr_sparts > 0) || (nr_gparts > 0 && nr_bparts > 0) || (nr_gparts > 0 && nr_sinks > 0)) part_verify_links(s->parts, s->gparts, s->sinks, s->sparts, s->bparts, nr_parts, nr_gparts, nr_sinks, nr_sparts, nr_bparts, verbose); #endif /* Free the list of local cells */ free(local_cells); }