From e9c26ad641f06f7ba8dfd7a9b11ac1fbba61c498 Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 19 Mar 2020 08:56:13 +0100 Subject: [PATCH 01/13] Unique ID: start implementation --- src/space.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/space.h | 30 ++++++++++++++ 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/src/space.c b/src/space.c index 9b20f33e9..2520233cb 100644 --- a/src/space.c +++ b/src/space.c @@ -4765,6 +4765,85 @@ void space_convert_quantities(struct space *s, int verbose) { clocks_getunit()); } + +/** + * @brief Initialize the computation of unique IDs. + * + * @param s The #space. + */ +void space_init_unique_id(struct space *s) { + /* Set the counter to 0. */ + s->unique_id.global_next_id = 0; + + /* Check the parts for the max id. */ + for(size_t i = 0; i < s->nr_parts; i++) { + if (s->parts[i].id > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->parts[i].id; + } + } + + /* Check the gparts for the max id. */ + for(size_t i = 0; i < s->nr_gparts; i++) { + if (s->gparts[i].id_or_neg_offset > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->gparts[i].id_or_neg_offset; + } + } + + /* Check the sparts for the max id. */ + for(size_t i = 0; i < s->nr_sparts; i++) { + if (s->sparts[i].id > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->sparts[i].id; + } + } + + /* Check the bparts for the max id. */ + for(size_t i = 0; i < s->nr_bparts; i++) { + if (s->bparts[i].id > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->bparts[i].id; + } + } + +#ifdef WITH_MPI + /* Find the global max. */ + MPI_Allreduce(MPI_IN_PLACE, &s->unique_id.global_next_id, 1, + MPI_LONGLONG, MPI_MAX, MPI_COMM_WORLD); +#endf + + /* Get the first unique id. */ + if (s->unique_id.global_next_id == LLONG_MAX) { + error("Overflow for the unique id."); + } + s->unique_id.global_next_id++; + + /* Compute the size of the each slice. */ + s->unique_id.slice_size = space_extra_parts + space_extra_sparts + + space_extra_gparts + space_extra_bparts; + + /* Compute the initial slices. */ + if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * s->unique_id.slice_size) { + error("Overflow for the unique id."); + } + long long init = s->unique_id.global_next_id + 2 * engine_rank * s->unique_id.slice_size; + + /* Set the slices and check for overflows. */ + s->unique_id.current.current = init; + + if (init > LLONG_MAX - s->unique_id.slice_size) { + error("Overflow for the unique id."); + } + s->unique_id.current.max = init + s->unique_id.slice_size; + s->unique_id.next.current = s->unique_id.current.max; + + if (s->unique_id.next.current > LLONG_MAX - s->unique_id.slice_size) { + error("Overflow for the unique id."); + } + s->unique_id.next.max = s->unique_id.next.current + s->unique_id.slice_size; + + /* Initialize the lock. */ + if (lock_init(&s->unique_id.lock) != 0) + error("Failed to init spinlock for the unique ids."); +} + /** * @brief Split the space into cells given the array of particles. * @@ -5082,8 +5161,14 @@ void space_init(struct space *s, struct swift_params *params, #endif /* Do we want any spare particles for on the fly creation? */ - if (!star_formation || !swift_star_formation_model_creates_stars) + if (!star_formation || !swift_star_formation_model_creates_stars) { space_extra_sparts = 0; + } + + /* Compute the max id for the generation of unique id. */ + if (star_formation && swift_star_formation_model_creates_stars) { + space_init_unique_id(s); + } /* Build the cells recursively. */ if (!dry_run) space_regrid(s, verbose); @@ -5735,12 +5820,15 @@ void space_clean(struct space *s) { swift_free("gparts_foreign", s->gparts_foreign); swift_free("bparts_foreign", s->bparts_foreign); #endif + + if (lock_destroy(&s->unique_id.lock) != 0) + error("Failed to destroy spinlocks."); } /** * @brief Write the space struct and its contents to the given FILE as a * stream of bytes. - * +< * * @param s the space * @param stream the file stream */ @@ -6030,3 +6118,22 @@ void space_write_cell_hierarchy(const struct space *s, int j) { fclose(f); #endif } + + +/** + * @brief Get a new unique ID. + * + * @param s the #space. + * + * @return The new unique ID + */ +long long space_get_new_unique_id(struct space *s) { + /* Get the lock */ + lock_lock(&s->unique_id.lock); + + + /* Release the lock */ + if (lock_unlock(s->unique_id.lock) != 0) { + error("Impossible to unlock the unique id."); + } +} diff --git a/src/space.h b/src/space.h index acb55bd26..cd7edd98a 100644 --- a/src/space.h +++ b/src/space.h @@ -81,6 +81,18 @@ extern int space_extra_gparts; extern int space_extra_sparts; extern int space_extra_bparts; + +/** + * @brief Slice of unique IDs for particle creation. + */ +struct unique_ids { + /*! Current free unique id */ + long long current; + + /*! Maximal unique id in this slice (not included) */ + long long max; +} + /** * @brief The space in which the cells and particles reside. */ @@ -277,6 +289,24 @@ struct space { /*! The group information returned by VELOCIraptor for each #gpart. */ struct velociraptor_gpart_data *gpart_group_data; + /*! Structure dealing with the computation of a unique ID */ + struct { + /*! Current slice of unique ids */ + struct unique_ids current; + + /*! Next slice of unique ids */ + struct unique_ids next; + + /* Global next slot available */ + long long global_next_id; + + /* Size of the slices */ + size_t slice_size; + + /* Lock for the unique ids */ + swift_lock_type lock; + } unique_id; + #ifdef WITH_MPI /*! Buffers for parts that we will receive from foreign cells. */ -- GitLab From 70e6cac96aec95194e18fa7508b49ca5b43dafce Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 19 Mar 2020 09:08:48 +0100 Subject: [PATCH 02/13] Unique ID: seems to be working --- src/cell.c | 4 +- src/space.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++------ src/space.h | 13 +++--- 3 files changed, 110 insertions(+), 22 deletions(-) diff --git a/src/cell.c b/src/cell.c index c4a4ecc18..0e0a65f23 100644 --- a/src/cell.c +++ b/src/cell.c @@ -6149,8 +6149,8 @@ struct spart *cell_spawn_new_spart_from_part(struct engine *e, struct cell *c, /* Copy the gpart */ *gp = *p->gpart; - /* Assign the ID back */ - sp->id = p->id; + /* Assign the ID. */ + sp->id = space_get_new_unique_id(e->s); gp->type = swift_type_stars; /* Re-link things */ diff --git a/src/space.c b/src/space.c index 2520233cb..8d0e3046f 100644 --- a/src/space.c +++ b/src/space.c @@ -2000,6 +2000,9 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Clean up any stray sort indices in the cell buffer. */ space_free_buff_sort_indices(s); + /* Update the slice of unique IDs. */ + space_update_unique_id(s); + if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); @@ -4806,8 +4809,8 @@ void space_init_unique_id(struct space *s) { #ifdef WITH_MPI /* Find the global max. */ MPI_Allreduce(MPI_IN_PLACE, &s->unique_id.global_next_id, 1, - MPI_LONGLONG, MPI_MAX, MPI_COMM_WORLD); -#endf + MPI_LONG_LONG, MPI_MAX, MPI_COMM_WORLD); +#endif // WITH_MPI /* Get the first unique id. */ if (s->unique_id.global_next_id == LLONG_MAX) { @@ -4816,28 +4819,29 @@ void space_init_unique_id(struct space *s) { s->unique_id.global_next_id++; /* Compute the size of the each slice. */ - s->unique_id.slice_size = space_extra_parts + space_extra_sparts + - space_extra_gparts + space_extra_bparts; + const long long slice_size = + (space_extra_parts + space_extra_sparts + + space_extra_gparts + space_extra_bparts) * s->nr_cells; /* Compute the initial slices. */ - if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * s->unique_id.slice_size) { + if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * slice_size) { error("Overflow for the unique id."); } - long long init = s->unique_id.global_next_id + 2 * engine_rank * s->unique_id.slice_size; + long long init = s->unique_id.global_next_id + 2 * engine_rank * slice_size; /* Set the slices and check for overflows. */ s->unique_id.current.current = init; - if (init > LLONG_MAX - s->unique_id.slice_size) { + if (init > LLONG_MAX - slice_size) { error("Overflow for the unique id."); } - s->unique_id.current.max = init + s->unique_id.slice_size; + s->unique_id.current.max = init + slice_size; s->unique_id.next.current = s->unique_id.current.max; - if (s->unique_id.next.current > LLONG_MAX - s->unique_id.slice_size) { + if (s->unique_id.next.current > LLONG_MAX - slice_size) { error("Overflow for the unique id."); } - s->unique_id.next.max = s->unique_id.next.current + s->unique_id.slice_size; + s->unique_id.next.max = s->unique_id.next.current + slice_size; /* Initialize the lock. */ if (lock_init(&s->unique_id.lock) != 0) @@ -6119,6 +6123,71 @@ void space_write_cell_hierarchy(const struct space *s, int j) { #endif } +/** + * @brief Update the unique id structure by requesting a + * new slice if required. + * + * @param s The #space. + */ +void space_update_unique_id(struct space *s) { + const int require_new_slice = s->unique_id.next.current == 0; + +#ifdef WITH_MPI + const struct engine *e = s->e; + + /* Check if the other ranks need a slices */ + int *all_requires = (int *) malloc(sizeof(int) * e->nr_nodes); + + /* Do the communication */ + MPI_Allgather(&require_new_slice, 1, MPI_INT, all_requires, 1, + MPI_INT, MPI_COMM_WORLD); + + /* Compute the position of this rank slice and the position of + the next free slice. */ + int local_index = 0; + int total_shift = 0; + for(int i = 0; i < e->nr_nodes; i++) { + total_shift += 1; + if (i < engine_rank) { + local_index += 1; + } + } + + /* Free the allocated resources. */ + free(all_requires); + +#else + + int local_index = 0; + int total_shift = require_new_slice; + +#endif // WITH_MPI + + /* Compute the size of the each slice. */ + const long long slice_size = + (space_extra_parts + space_extra_sparts + + space_extra_gparts + space_extra_bparts) * s->nr_cells; + + /* Get a new slice. */ + if (require_new_slice) { + /* First check against an overflow. */ + const long long local_shift = local_index * slice_size; + if (s->unique_id.global_next_id > LLONG_MAX - (local_shift + slice_size)) { + error("Overflow for the unique IDs."); + } + /* Now assign it. */ + s->unique_id.next.current = s->unique_id.global_next_id + local_shift; + s->unique_id.next.max = s->unique_id.global_next_id + local_shift + slice_size; + } + + /* Shift the position of the next available slice. */ + const long long shift = total_shift * slice_size; + if (s->unique_id.global_next_id > LLONG_MAX - shift) { + error("Overflow for the unique IDs."); + } + s->unique_id.global_next_id += shift; + +} /** * @brief Get a new unique ID. @@ -6128,12 +6197,32 @@ void space_write_cell_hierarchy(const struct space *s, int j) { * @return The new unique ID */ long long space_get_new_unique_id(struct space *s) { - /* Get the lock */ + /* Get the lock. */ lock_lock(&s->unique_id.lock); + /* Get the current available id. */ + const long long id = s->unique_id.current.current; + + /* Update the counter. */ + s->unique_id.current.current++; + + /* Check if need to move to the next slice. */ + if (s->unique_id.current.current == s->unique_id.current.max) { + /* Check if the next slice is already used */ + if (s->unique_id.next.current == 0) { + error("Failed to obtain a new unique ID."); + } + s->unique_id.current = s->unique_id.next; - /* Release the lock */ - if (lock_unlock(s->unique_id.lock) != 0) { + /* Reset the next slice. */ + s->unique_id.next.current = 0; + s->unique_id.next.max = 0; + } + + /* Release the lock. */ + if (lock_unlock(&s->unique_id.lock) != 0) { error("Impossible to unlock the unique id."); } + + return id; } diff --git a/src/space.h b/src/space.h index cd7edd98a..8336dd37d 100644 --- a/src/space.h +++ b/src/space.h @@ -85,13 +85,13 @@ extern int space_extra_bparts; /** * @brief Slice of unique IDs for particle creation. */ -struct unique_ids { +struct slice { /*! Current free unique id */ long long current; /*! Maximal unique id in this slice (not included) */ long long max; -} +}; /** * @brief The space in which the cells and particles reside. @@ -292,17 +292,14 @@ struct space { /*! Structure dealing with the computation of a unique ID */ struct { /*! Current slice of unique ids */ - struct unique_ids current; + struct slice current; /*! Next slice of unique ids */ - struct unique_ids next; + struct slice next; /* Global next slot available */ long long global_next_id; - /* Size of the slices */ - size_t slice_size; - /* Lock for the unique ids */ swift_lock_type lock; } unique_id; @@ -417,4 +414,6 @@ void space_struct_restore(struct space *s, FILE *stream); void space_write_cell_hierarchy(const struct space *s, int j); void space_compute_star_formation_stats(const struct space *s, struct star_formation *star_form); +void space_update_unique_id(struct space *s); +long long space_get_new_unique_id(struct space *s); #endif /* SWIFT_SPACE_H */ -- GitLab From f8f9edeff806ef925f6ec1cb98f2a6e0fdb019d3 Mon Sep 17 00:00:00 2001 From: loikki Date: Mon, 23 Mar 2020 11:28:26 +0100 Subject: [PATCH 03/13] Unique ID is working --- src/space.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/space.c b/src/space.c index 8d0e3046f..7f0e96a13 100644 --- a/src/space.c +++ b/src/space.c @@ -1817,6 +1817,9 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { swift_free("b_index", b_index); swift_free("cell_bpart_counts", cell_bpart_counts); + /* Update the slice of unique IDs. */ + space_update_unique_id(s); + #ifdef WITH_MPI /* Re-allocate the index array for the gparts if needed.. */ @@ -2000,9 +2003,6 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Clean up any stray sort indices in the cell buffer. */ space_free_buff_sort_indices(s); - /* Update the slice of unique IDs. */ - space_update_unique_id(s); - if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); @@ -5169,13 +5169,14 @@ void space_init(struct space *s, struct swift_params *params, space_extra_sparts = 0; } + /* Build the cells recursively. */ + if (!dry_run) space_regrid(s, verbose); + + /* Compute the max id for the generation of unique id. */ if (star_formation && swift_star_formation_model_creates_stars) { space_init_unique_id(s); } - - /* Build the cells recursively. */ - if (!dry_run) space_regrid(s, verbose); } /** @@ -6206,8 +6207,14 @@ long long space_get_new_unique_id(struct space *s) { /* Update the counter. */ s->unique_id.current.current++; + /* Check if everything is fine */ + if (s->unique_id.current.current > s->unique_id.current.max) { + error("Failed to get a new ID"); + } + /* Check if need to move to the next slice. */ if (s->unique_id.current.current == s->unique_id.current.max) { + /* Check if the next slice is already used */ if (s->unique_id.next.current == 0) { error("Failed to obtain a new unique ID."); -- GitLab From a8030447d0586997812032c10ef873abc4d0d4ae Mon Sep 17 00:00:00 2001 From: loikki Date: Mon, 23 Mar 2020 11:39:45 +0100 Subject: [PATCH 04/13] Update comment --- src/space.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/space.c b/src/space.c index 7f0e96a13..08747d9b4 100644 --- a/src/space.c +++ b/src/space.c @@ -4818,7 +4818,7 @@ void space_init_unique_id(struct space *s) { } s->unique_id.global_next_id++; - /* Compute the size of the each slice. */ + /* Compute the size of each slice. */ const long long slice_size = (space_extra_parts + space_extra_sparts + space_extra_gparts + space_extra_bparts) * s->nr_cells; -- GitLab From 3103bb779283d065ac612249fa662ca6d20c0f1f Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 26 Mar 2020 09:40:33 +0100 Subject: [PATCH 05/13] Unique ID: remove unwanted character --- src/space.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/space.c b/src/space.c index 08747d9b4..787d200dc 100644 --- a/src/space.c +++ b/src/space.c @@ -5833,7 +5833,7 @@ void space_clean(struct space *s) { /** * @brief Write the space struct and its contents to the given FILE as a * stream of bytes. -< * + * * @param s the space * @param stream the file stream */ -- GitLab From 7a597ccd70f4ab825d92766220d47cd06ef0f868 Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 26 Mar 2020 16:06:44 +0100 Subject: [PATCH 06/13] Split space and space_unique_id --- src/Makefile.am | 5 +- src/space.c | 133 ++++--------------------------------- src/space.h | 13 +--- src/space_unique_id.c | 149 ++++++++++++++++++++++++++++++++++++++++++ src/space_unique_id.h | 43 ++++++++++++ 5 files changed, 207 insertions(+), 136 deletions(-) create mode 100644 src/space_unique_id.c create mode 100644 src/space_unique_id.h diff --git a/src/Makefile.am b/src/Makefile.am index f1f9157b1..2f73608f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,7 +57,8 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ pressure_floor.h pressure_floor_struct.h pressure_floor_iact.h \ velociraptor_struct.h velociraptor_io.h random.h memuse.h mpiuse.h memuse_rnodes.h \ black_holes.h black_holes_io.h black_holes_properties.h black_holes_struct.h \ - feedback.h feedback_struct.h feedback_properties.h task_order.h + feedback.h feedback_struct.h feedback_properties.h task_order.h \ + space_unique_id.h # source files for EAGLE cooling QLA_COOLING_SOURCES = @@ -107,7 +108,7 @@ AM_SOURCES = space.c runner_main.c runner_doiact_hydro.c runner_doiact_limiter.c collectgroup.c hydro_space.c equation_of_state.c \ chemistry.c cosmology.c restart.c mesh_gravity.c velociraptor_interface.c \ outputlist.c velociraptor_dummy.c logger_io.c memuse.c mpiuse.c memuse_rnodes.c fof.c \ - hashmap.c pressure_floor.c \ + hashmap.c pressure_floor.c space_unique_id.c \ $(QLA_COOLING_SOURCES) \ $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES) \ $(GRACKLE_COOLING_SOURCES) $(GEAR_FEEDBACK_SOURCES) diff --git a/src/space.c b/src/space.c index 787d200dc..16d8654e8 100644 --- a/src/space.c +++ b/src/space.c @@ -60,6 +60,7 @@ #include "proxy.h" #include "restart.h" #include "sort_part.h" +#include "space_unique_id.h" #include "star_formation.h" #include "star_formation_logger.h" #include "stars.h" @@ -4768,7 +4769,6 @@ void space_convert_quantities(struct space *s, int verbose) { clocks_getunit()); } - /** * @brief Initialize the computation of unique IDs. * @@ -4779,28 +4779,28 @@ void space_init_unique_id(struct space *s) { s->unique_id.global_next_id = 0; /* Check the parts for the max id. */ - for(size_t i = 0; i < s->nr_parts; i++) { + for (size_t i = 0; i < s->nr_parts; i++) { if (s->parts[i].id > s->unique_id.global_next_id) { s->unique_id.global_next_id = s->parts[i].id; } } /* Check the gparts for the max id. */ - for(size_t i = 0; i < s->nr_gparts; i++) { + for (size_t i = 0; i < s->nr_gparts; i++) { if (s->gparts[i].id_or_neg_offset > s->unique_id.global_next_id) { s->unique_id.global_next_id = s->gparts[i].id_or_neg_offset; } } /* Check the sparts for the max id. */ - for(size_t i = 0; i < s->nr_sparts; i++) { + for (size_t i = 0; i < s->nr_sparts; i++) { if (s->sparts[i].id > s->unique_id.global_next_id) { s->unique_id.global_next_id = s->sparts[i].id; } } /* Check the bparts for the max id. */ - for(size_t i = 0; i < s->nr_bparts; i++) { + for (size_t i = 0; i < s->nr_bparts; i++) { if (s->bparts[i].id > s->unique_id.global_next_id) { s->unique_id.global_next_id = s->bparts[i].id; } @@ -4808,9 +4808,9 @@ void space_init_unique_id(struct space *s) { #ifdef WITH_MPI /* Find the global max. */ - MPI_Allreduce(MPI_IN_PLACE, &s->unique_id.global_next_id, 1, - MPI_LONG_LONG, MPI_MAX, MPI_COMM_WORLD); -#endif // WITH_MPI + MPI_Allreduce(MPI_IN_PLACE, &s->unique_id.global_next_id, 1, MPI_LONG_LONG, + MPI_MAX, MPI_COMM_WORLD); +#endif // WITH_MPI /* Get the first unique id. */ if (s->unique_id.global_next_id == LLONG_MAX) { @@ -4819,9 +4819,9 @@ void space_init_unique_id(struct space *s) { s->unique_id.global_next_id++; /* Compute the size of each slice. */ - const long long slice_size = - (space_extra_parts + space_extra_sparts + - space_extra_gparts + space_extra_bparts) * s->nr_cells; + const long long slice_size = (space_extra_parts + space_extra_sparts + + space_extra_gparts + space_extra_bparts) * + s->nr_cells; /* Compute the initial slices. */ if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * slice_size) { @@ -5172,7 +5172,6 @@ void space_init(struct space *s, struct swift_params *params, /* Build the cells recursively. */ if (!dry_run) space_regrid(s, verbose); - /* Compute the max id for the generation of unique id. */ if (star_formation && swift_star_formation_model_creates_stars) { space_init_unique_id(s); @@ -6123,113 +6122,3 @@ void space_write_cell_hierarchy(const struct space *s, int j) { fclose(f); #endif } - -/** - * @brief Update the unique id structure by requesting a - * new slice if required. - * - * @param s The #space. - */ -void space_update_unique_id(struct space *s) { - const int require_new_slice = s->unique_id.next.current == 0; - -#ifdef WITH_MPI - const struct engine *e = s->e; - - /* Check if the other ranks need a slices */ - int *all_requires = (int *) malloc(sizeof(int) * e->nr_nodes); - - /* Do the communication */ - MPI_Allgather(&require_new_slice, 1, MPI_INT, all_requires, 1, - MPI_INT, MPI_COMM_WORLD); - - /* Compute the position of this rank slice and the position of - the next free slice. */ - int local_index = 0; - int total_shift = 0; - for(int i = 0; i < e->nr_nodes; i++) { - total_shift += 1; - if (i < engine_rank) { - local_index += 1; - } - } - - /* Free the allocated resources. */ - free(all_requires); - -#else - - int local_index = 0; - int total_shift = require_new_slice; - -#endif // WITH_MPI - - /* Compute the size of the each slice. */ - const long long slice_size = - (space_extra_parts + space_extra_sparts + - space_extra_gparts + space_extra_bparts) * s->nr_cells; - - /* Get a new slice. */ - if (require_new_slice) { - /* First check against an overflow. */ - const long long local_shift = local_index * slice_size; - if (s->unique_id.global_next_id > LLONG_MAX - (local_shift + slice_size)) { - error("Overflow for the unique IDs."); - } - /* Now assign it. */ - s->unique_id.next.current = s->unique_id.global_next_id + local_shift; - s->unique_id.next.max = s->unique_id.global_next_id + local_shift + slice_size; - } - - /* Shift the position of the next available slice. */ - const long long shift = total_shift * slice_size; - if (s->unique_id.global_next_id > LLONG_MAX - shift) { - error("Overflow for the unique IDs."); - } - s->unique_id.global_next_id += shift; - -} - -/** - * @brief Get a new unique ID. - * - * @param s the #space. - * - * @return The new unique ID - */ -long long space_get_new_unique_id(struct space *s) { - /* Get the lock. */ - lock_lock(&s->unique_id.lock); - - /* Get the current available id. */ - const long long id = s->unique_id.current.current; - - /* Update the counter. */ - s->unique_id.current.current++; - - /* Check if everything is fine */ - if (s->unique_id.current.current > s->unique_id.current.max) { - error("Failed to get a new ID"); - } - - /* Check if need to move to the next slice. */ - if (s->unique_id.current.current == s->unique_id.current.max) { - - /* Check if the next slice is already used */ - if (s->unique_id.next.current == 0) { - error("Failed to obtain a new unique ID."); - } - s->unique_id.current = s->unique_id.next; - - /* Reset the next slice. */ - s->unique_id.next.current = 0; - s->unique_id.next.max = 0; - } - - /* Release the lock. */ - if (lock_unlock(&s->unique_id.lock) != 0) { - error("Impossible to unlock the unique id."); - } - - return id; -} diff --git a/src/space.h b/src/space.h index 8336dd37d..c0706ae0b 100644 --- a/src/space.h +++ b/src/space.h @@ -34,6 +34,7 @@ #include "lock.h" #include "parser.h" #include "part.h" +#include "space_unique_id.h" #include "velociraptor_struct.h" /* Avoid cyclic inclusions */ @@ -81,18 +82,6 @@ extern int space_extra_gparts; extern int space_extra_sparts; extern int space_extra_bparts; - -/** - * @brief Slice of unique IDs for particle creation. - */ -struct slice { - /*! Current free unique id */ - long long current; - - /*! Maximal unique id in this slice (not included) */ - long long max; -}; - /** * @brief The space in which the cells and particles reside. */ diff --git a/src/space_unique_id.c b/src/space_unique_id.c new file mode 100644 index 000000000..5e1cbb1f5 --- /dev/null +++ b/src/space_unique_id.c @@ -0,0 +1,149 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2020 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 . + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include +#include +#include + +/* MPI headers. */ +#ifdef WITH_MPI +#include +#endif + +/* This object's header. */ +#include "space_unique_id.h" + +/* Local headers. */ +#include "engine.h" +#include "lock.h" +#include "space.h" + +/** + * @brief Update the unique id structure by requesting a + * new slice if required. + * + * @param s The #space. + */ +void space_update_unique_id(struct space *s) { + const int require_new_slice = s->unique_id.next.current == 0; + +#ifdef WITH_MPI + const struct engine *e = s->e; + + /* Check if the other ranks need a slices */ + int *all_requires = (int *)malloc(sizeof(int) * e->nr_nodes); + + /* Do the communication */ + MPI_Allgather(&require_new_slice, 1, MPI_INT, all_requires, 1, MPI_INT, + MPI_COMM_WORLD); + + /* Compute the position of this rank slice and the position of + the next free slice. */ + int local_index = 0; + int total_shift = 0; + for (int i = 0; i < e->nr_nodes; i++) { + total_shift += 1; + if (i < engine_rank) { + local_index += 1; + } + } + + /* Free the allocated resources. */ + free(all_requires); + +#else + + int local_index = 0; + int total_shift = require_new_slice; + +#endif // WITH_MPI + + /* Compute the size of the each slice. */ + const long long slice_size = (space_extra_parts + space_extra_sparts + + space_extra_gparts + space_extra_bparts) * + s->nr_cells; + + /* Get a new slice. */ + if (require_new_slice) { + /* First check against an overflow. */ + const long long local_shift = local_index * slice_size; + if (s->unique_id.global_next_id > LLONG_MAX - (local_shift + slice_size)) { + error("Overflow for the unique IDs."); + } + /* Now assign it. */ + s->unique_id.next.current = s->unique_id.global_next_id + local_shift; + s->unique_id.next.max = + s->unique_id.global_next_id + local_shift + slice_size; + } + + /* Shift the position of the next available slice. */ + const long long shift = total_shift * slice_size; + if (s->unique_id.global_next_id > LLONG_MAX - shift) { + error("Overflow for the unique IDs."); + } + s->unique_id.global_next_id += shift; +} + +/** + * @brief Get a new unique ID. + * + * @param s the #space. + * + * @return The new unique ID + */ +long long space_get_new_unique_id(struct space *s) { + /* Get the lock. */ + lock_lock(&s->unique_id.lock); + + /* Get the current available id. */ + const long long id = s->unique_id.current.current; + + /* Update the counter. */ + s->unique_id.current.current++; + + /* Check if everything is fine */ + if (s->unique_id.current.current > s->unique_id.current.max) { + error("Failed to get a new ID"); + } + + /* Check if need to move to the next slice. */ + if (s->unique_id.current.current == s->unique_id.current.max) { + + /* Check if the next slice is already used */ + if (s->unique_id.next.current == 0) { + error("Failed to obtain a new unique ID."); + } + s->unique_id.current = s->unique_id.next; + + /* Reset the next slice. */ + s->unique_id.next.current = 0; + s->unique_id.next.max = 0; + } + + /* Release the lock. */ + if (lock_unlock(&s->unique_id.lock) != 0) { + error("Impossible to unlock the unique id."); + } + + return id; +} diff --git a/src/space_unique_id.h b/src/space_unique_id.h new file mode 100644 index 000000000..d6e1ad62f --- /dev/null +++ b/src/space_unique_id.h @@ -0,0 +1,43 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2020 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 . + * + ******************************************************************************/ + +#ifndef SWIFT_SPACE_UNIQUE_ID_H +#define SWIFT_SPACE_UNIQUE_ID_H + +/* Config parameters. */ +#include "../config.h" + +/* Predefine the space structure */ +struct space; + +/** + * @brief Slice of unique IDs for particle creation. + */ +struct slice { + /*! Current free unique id */ + long long current; + + /*! Maximal unique id in this slice (not included) */ + long long max; +}; + +void space_update_unique_id(struct space *s); +long long space_get_new_unique_id(struct space *s); + +#endif // SWIFT_SPACE_UNIQUE_ID_H -- GitLab From 7a69096d6c07b937d06240ed31d0c4014a33c0b4 Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 26 Mar 2020 16:19:59 +0100 Subject: [PATCH 07/13] Move some functions --- src/space.c | 79 ------------------------------------------- src/space.h | 2 -- src/space_unique_id.c | 79 +++++++++++++++++++++++++++++++++++++++++++ src/space_unique_id.h | 1 + 4 files changed, 80 insertions(+), 81 deletions(-) diff --git a/src/space.c b/src/space.c index 16d8654e8..ce4c6ff85 100644 --- a/src/space.c +++ b/src/space.c @@ -4769,85 +4769,6 @@ void space_convert_quantities(struct space *s, int verbose) { clocks_getunit()); } -/** - * @brief Initialize the computation of unique IDs. - * - * @param s The #space. - */ -void space_init_unique_id(struct space *s) { - /* Set the counter to 0. */ - s->unique_id.global_next_id = 0; - - /* Check the parts for the max id. */ - for (size_t i = 0; i < s->nr_parts; i++) { - if (s->parts[i].id > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->parts[i].id; - } - } - - /* Check the gparts for the max id. */ - for (size_t i = 0; i < s->nr_gparts; i++) { - if (s->gparts[i].id_or_neg_offset > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->gparts[i].id_or_neg_offset; - } - } - - /* Check the sparts for the max id. */ - for (size_t i = 0; i < s->nr_sparts; i++) { - if (s->sparts[i].id > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->sparts[i].id; - } - } - - /* Check the bparts for the max id. */ - for (size_t i = 0; i < s->nr_bparts; i++) { - if (s->bparts[i].id > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->bparts[i].id; - } - } - -#ifdef WITH_MPI - /* Find the global max. */ - MPI_Allreduce(MPI_IN_PLACE, &s->unique_id.global_next_id, 1, MPI_LONG_LONG, - MPI_MAX, MPI_COMM_WORLD); -#endif // WITH_MPI - - /* Get the first unique id. */ - if (s->unique_id.global_next_id == LLONG_MAX) { - error("Overflow for the unique id."); - } - s->unique_id.global_next_id++; - - /* Compute the size of each slice. */ - const long long slice_size = (space_extra_parts + space_extra_sparts + - space_extra_gparts + space_extra_bparts) * - s->nr_cells; - - /* Compute the initial slices. */ - if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * slice_size) { - error("Overflow for the unique id."); - } - long long init = s->unique_id.global_next_id + 2 * engine_rank * slice_size; - - /* Set the slices and check for overflows. */ - s->unique_id.current.current = init; - - if (init > LLONG_MAX - slice_size) { - error("Overflow for the unique id."); - } - s->unique_id.current.max = init + slice_size; - s->unique_id.next.current = s->unique_id.current.max; - - if (s->unique_id.next.current > LLONG_MAX - slice_size) { - error("Overflow for the unique id."); - } - s->unique_id.next.max = s->unique_id.next.current + slice_size; - - /* Initialize the lock. */ - if (lock_init(&s->unique_id.lock) != 0) - error("Failed to init spinlock for the unique ids."); -} - /** * @brief Split the space into cells given the array of particles. * diff --git a/src/space.h b/src/space.h index c0706ae0b..1e1a91f06 100644 --- a/src/space.h +++ b/src/space.h @@ -403,6 +403,4 @@ void space_struct_restore(struct space *s, FILE *stream); void space_write_cell_hierarchy(const struct space *s, int j); void space_compute_star_formation_stats(const struct space *s, struct star_formation *star_form); -void space_update_unique_id(struct space *s); -long long space_get_new_unique_id(struct space *s); #endif /* SWIFT_SPACE_H */ diff --git a/src/space_unique_id.c b/src/space_unique_id.c index 5e1cbb1f5..66edc99fa 100644 --- a/src/space_unique_id.c +++ b/src/space_unique_id.c @@ -147,3 +147,82 @@ long long space_get_new_unique_id(struct space *s) { return id; } + +/** + * @brief Initialize the computation of unique IDs. + * + * @param s The #space. + */ +void space_init_unique_id(struct space *s) { + /* Set the counter to 0. */ + s->unique_id.global_next_id = 0; + + /* Check the parts for the max id. */ + for (size_t i = 0; i < s->nr_parts; i++) { + if (s->parts[i].id > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->parts[i].id; + } + } + + /* Check the gparts for the max id. */ + for (size_t i = 0; i < s->nr_gparts; i++) { + if (s->gparts[i].id_or_neg_offset > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->gparts[i].id_or_neg_offset; + } + } + + /* Check the sparts for the max id. */ + for (size_t i = 0; i < s->nr_sparts; i++) { + if (s->sparts[i].id > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->sparts[i].id; + } + } + + /* Check the bparts for the max id. */ + for (size_t i = 0; i < s->nr_bparts; i++) { + if (s->bparts[i].id > s->unique_id.global_next_id) { + s->unique_id.global_next_id = s->bparts[i].id; + } + } + +#ifdef WITH_MPI + /* Find the global max. */ + MPI_Allreduce(MPI_IN_PLACE, &s->unique_id.global_next_id, 1, MPI_LONG_LONG, + MPI_MAX, MPI_COMM_WORLD); +#endif // WITH_MPI + + /* Get the first unique id. */ + if (s->unique_id.global_next_id == LLONG_MAX) { + error("Overflow for the unique id."); + } + s->unique_id.global_next_id++; + + /* Compute the size of each slice. */ + const long long slice_size = (space_extra_parts + space_extra_sparts + + space_extra_gparts + space_extra_bparts) * + s->nr_cells; + + /* Compute the initial slices. */ + if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * slice_size) { + error("Overflow for the unique id."); + } + long long init = s->unique_id.global_next_id + 2 * engine_rank * slice_size; + + /* Set the slices and check for overflows. */ + s->unique_id.current.current = init; + + if (init > LLONG_MAX - slice_size) { + error("Overflow for the unique id."); + } + s->unique_id.current.max = init + slice_size; + s->unique_id.next.current = s->unique_id.current.max; + + if (s->unique_id.next.current > LLONG_MAX - slice_size) { + error("Overflow for the unique id."); + } + s->unique_id.next.max = s->unique_id.next.current + slice_size; + + /* Initialize the lock. */ + if (lock_init(&s->unique_id.lock) != 0) + error("Failed to init spinlock for the unique ids."); +} diff --git a/src/space_unique_id.h b/src/space_unique_id.h index d6e1ad62f..6411a8cb7 100644 --- a/src/space_unique_id.h +++ b/src/space_unique_id.h @@ -39,5 +39,6 @@ struct slice { void space_update_unique_id(struct space *s); long long space_get_new_unique_id(struct space *s); +void space_init_unique_id(struct space *s); #endif // SWIFT_SPACE_UNIQUE_ID_H -- GitLab From c1d74a269ffca978cfb73675ba6b668cf6fdd419 Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 9 Apr 2020 08:57:35 +0200 Subject: [PATCH 08/13] Unique ID: increase the number of available slices --- examples/main.c | 2 +- src/space.c | 7 ++++--- src/space.h | 4 ++-- src/space_unique_id.c | 40 ++++++++++++++++++++++------------------ src/space_unique_id.h | 2 +- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/examples/main.c b/examples/main.c index 2528ce589..e19783045 100644 --- a/examples/main.c +++ b/examples/main.c @@ -1058,7 +1058,7 @@ int main(int argc, char *argv[]) { space_init(&s, params, &cosmo, dim, parts, gparts, sparts, bparts, Ngas, Ngpart, Nspart, Nbpart, periodic, replicate, generate_gas_in_ics, with_hydro, with_self_gravity, with_star_formation, - with_DM_background_particles, talking, dry_run); + with_DM_background_particles, talking, dry_run, nr_nodes); if (myrank == 0) { clocks_gettime(&toc); diff --git a/src/space.c b/src/space.c index ce4c6ff85..f336e88e1 100644 --- a/src/space.c +++ b/src/space.c @@ -4793,6 +4793,7 @@ void space_convert_quantities(struct space *s, int verbose) { * @param DM_background Are we running with some DM background particles? * @param verbose Print messages to stdout or not. * @param dry_run If 1, just initialise stuff, don't do anything with the parts. + * @param nr_nodes The number of MPI rank. * * Makes a grid of edge length > r_max and fills the particles * into the respective cells. Cells containing more than #space_splitsize @@ -4805,8 +4806,8 @@ void space_init(struct space *s, struct swift_params *params, struct bpart *bparts, size_t Npart, size_t Ngpart, size_t Nspart, size_t Nbpart, int periodic, int replicate, int generate_gas_in_ics, int hydro, int self_gravity, - int star_formation, int DM_background, int verbose, - int dry_run) { + int star_formation, int DM_background, int verbose, int dry_run, + int nr_nodes) { /* Clean-up everything */ bzero(s, sizeof(struct space)); @@ -5095,7 +5096,7 @@ void space_init(struct space *s, struct swift_params *params, /* Compute the max id for the generation of unique id. */ if (star_formation && swift_star_formation_model_creates_stars) { - space_init_unique_id(s); + space_init_unique_id(s, nr_nodes); } } diff --git a/src/space.h b/src/space.h index 1e1a91f06..b7afc6c83 100644 --- a/src/space.h +++ b/src/space.h @@ -332,8 +332,8 @@ void space_init(struct space *s, struct swift_params *params, struct bpart *bparts, size_t Npart, size_t Ngpart, size_t Nspart, size_t Nbpart, int periodic, int replicate, int generate_gas_in_ics, int hydro, int gravity, - int star_formation, int DM_background, int verbose, - int dry_run); + int star_formation, int DM_background, int verbose, int dry_run, + int nr_nodes); void space_sanitize(struct space *s); void space_map_cells_pre(struct space *s, int full, void (*fun)(struct cell *c, void *data), void *data); diff --git a/src/space_unique_id.c b/src/space_unique_id.c index 66edc99fa..7ef2571d4 100644 --- a/src/space_unique_id.c +++ b/src/space_unique_id.c @@ -50,7 +50,7 @@ void space_update_unique_id(struct space *s) { #ifdef WITH_MPI const struct engine *e = s->e; - /* Check if the other ranks need a slices */ + /* Check if the other ranks need a slice. */ int *all_requires = (int *)malloc(sizeof(int) * e->nr_nodes); /* Do the communication */ @@ -62,9 +62,9 @@ void space_update_unique_id(struct space *s) { int local_index = 0; int total_shift = 0; for (int i = 0; i < e->nr_nodes; i++) { - total_shift += 1; + total_shift += all_requires[i]; if (i < engine_rank) { - local_index += 1; + local_index += all_requires[i]; } } @@ -78,7 +78,7 @@ void space_update_unique_id(struct space *s) { #endif // WITH_MPI - /* Compute the size of the each slice. */ + /* Compute the size of each slice. */ const long long slice_size = (space_extra_parts + space_extra_sparts + space_extra_gparts + space_extra_bparts) * s->nr_cells; @@ -133,6 +133,7 @@ long long space_get_new_unique_id(struct space *s) { if (s->unique_id.next.current == 0) { error("Failed to obtain a new unique ID."); } + s->unique_id.current = s->unique_id.next; /* Reset the next slice. */ @@ -152,37 +153,34 @@ long long space_get_new_unique_id(struct space *s) { * @brief Initialize the computation of unique IDs. * * @param s The #space. + * @param nr_nodes The number of MPI ranks. */ -void space_init_unique_id(struct space *s) { +void space_init_unique_id(struct space *s, int nr_nodes) { /* Set the counter to 0. */ s->unique_id.global_next_id = 0; /* Check the parts for the max id. */ for (size_t i = 0; i < s->nr_parts; i++) { - if (s->parts[i].id > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->parts[i].id; - } + s->unique_id.global_next_id = + max(s->unique_id.global_next_id, s->parts[i].id); } /* Check the gparts for the max id. */ for (size_t i = 0; i < s->nr_gparts; i++) { - if (s->gparts[i].id_or_neg_offset > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->gparts[i].id_or_neg_offset; - } + s->unique_id.global_next_id = + max(s->unique_id.global_next_id, s->gparts[i].id_or_neg_offset); } /* Check the sparts for the max id. */ for (size_t i = 0; i < s->nr_sparts; i++) { - if (s->sparts[i].id > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->sparts[i].id; - } + s->unique_id.global_next_id = + max(s->unique_id.global_next_id, s->sparts[i].id); } /* Check the bparts for the max id. */ for (size_t i = 0; i < s->nr_bparts; i++) { - if (s->bparts[i].id > s->unique_id.global_next_id) { - s->unique_id.global_next_id = s->bparts[i].id; - } + s->unique_id.global_next_id = + max(s->unique_id.global_next_id, s->bparts[i].id); } #ifdef WITH_MPI @@ -202,7 +200,7 @@ void space_init_unique_id(struct space *s) { space_extra_gparts + space_extra_bparts) * s->nr_cells; - /* Compute the initial slices. */ + /* Compute the initial slices (each rank has 2 slices). */ if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * slice_size) { error("Overflow for the unique id."); } @@ -222,6 +220,12 @@ void space_init_unique_id(struct space *s) { } s->unique_id.next.max = s->unique_id.next.current + slice_size; + /* Update the next available id */ + if (s->unique_id.global_next_id > LLONG_MAX - 2 * slice_size * nr_nodes) { + error("Overflow for the unique id."); + } + s->unique_id.global_next_id += 2 * slice_size * nr_nodes; + /* Initialize the lock. */ if (lock_init(&s->unique_id.lock) != 0) error("Failed to init spinlock for the unique ids."); diff --git a/src/space_unique_id.h b/src/space_unique_id.h index 6411a8cb7..95dd273a1 100644 --- a/src/space_unique_id.h +++ b/src/space_unique_id.h @@ -39,6 +39,6 @@ struct slice { void space_update_unique_id(struct space *s); long long space_get_new_unique_id(struct space *s); -void space_init_unique_id(struct space *s); +void space_init_unique_id(struct space *s, int nr_nodes); #endif // SWIFT_SPACE_UNIQUE_ID_H -- GitLab From 04739ea2ade1b73b2a285ad29a56531ae07dc019 Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 9 Apr 2020 10:17:31 +0200 Subject: [PATCH 09/13] Format --- src/space.h | 14 +-- src/space_unique_id.c | 107 ++++++++++-------- src/space_unique_id.h | 24 +++- .../EAGLE/star_formation_struct.h | 4 + .../GEAR/star_formation_struct.h | 4 + src/star_formation/QLA/star_formation.h | 4 + .../QLA/star_formation_struct.h | 4 + .../none/star_formation_struct.h | 4 + 8 files changed, 103 insertions(+), 62 deletions(-) diff --git a/src/space.h b/src/space.h index b7afc6c83..b7ba58948 100644 --- a/src/space.h +++ b/src/space.h @@ -279,19 +279,7 @@ struct space { struct velociraptor_gpart_data *gpart_group_data; /*! Structure dealing with the computation of a unique ID */ - struct { - /*! Current slice of unique ids */ - struct slice current; - - /*! Next slice of unique ids */ - struct slice next; - - /* Global next slot available */ - long long global_next_id; - - /* Lock for the unique ids */ - swift_lock_type lock; - } unique_id; + struct unique_id unique_id; #ifdef WITH_MPI diff --git a/src/space_unique_id.c b/src/space_unique_id.c index 7ef2571d4..3a6f0c48f 100644 --- a/src/space_unique_id.c +++ b/src/space_unique_id.c @@ -21,9 +21,7 @@ #include "../config.h" /* Some standard headers. */ -#include #include -#include /* MPI headers. */ #ifdef WITH_MPI @@ -40,30 +38,35 @@ /** * @brief Update the unique id structure by requesting a - * new slice if required. + * new batch if required. * * @param s The #space. */ void space_update_unique_id(struct space *s) { - const int require_new_slice = s->unique_id.next.current == 0; + /* Do we need unique IDs? */ + if (!star_formation_need_unique_id) { + return; + } + + const int require_new_batch = s->unique_id.next_batch.current == 0; #ifdef WITH_MPI const struct engine *e = s->e; - /* Check if the other ranks need a slice. */ + /* Check if the other ranks need a batch. */ int *all_requires = (int *)malloc(sizeof(int) * e->nr_nodes); /* Do the communication */ - MPI_Allgather(&require_new_slice, 1, MPI_INT, all_requires, 1, MPI_INT, + MPI_Allgather(&require_new_batch, 1, MPI_INT, all_requires, 1, MPI_INT, MPI_COMM_WORLD); - /* Compute the position of this rank slice and the position of - the next free slice. */ + /* Compute the position of this rank batch and the position of + the next free batch. */ int local_index = 0; int total_shift = 0; for (int i = 0; i < e->nr_nodes; i++) { total_shift += all_requires[i]; - if (i < engine_rank) { + if (i < e->nodeID) { local_index += all_requires[i]; } } @@ -74,30 +77,30 @@ void space_update_unique_id(struct space *s) { #else int local_index = 0; - int total_shift = require_new_slice; + int total_shift = require_new_batch; #endif // WITH_MPI - /* Compute the size of each slice. */ - const long long slice_size = (space_extra_parts + space_extra_sparts + + /* Compute the size of each batch. */ + const long long batch_size = (space_extra_parts + space_extra_sparts + space_extra_gparts + space_extra_bparts) * s->nr_cells; - /* Get a new slice. */ - if (require_new_slice) { + /* Get a new batch. */ + if (require_new_batch) { /* First check against an overflow. */ - const long long local_shift = local_index * slice_size; - if (s->unique_id.global_next_id > LLONG_MAX - (local_shift + slice_size)) { + const long long local_shift = local_index * batch_size; + if (s->unique_id.global_next_id > LLONG_MAX - (local_shift + batch_size)) { error("Overflow for the unique IDs."); } /* Now assign it. */ - s->unique_id.next.current = s->unique_id.global_next_id + local_shift; - s->unique_id.next.max = - s->unique_id.global_next_id + local_shift + slice_size; + s->unique_id.next_batch.current = s->unique_id.global_next_id + local_shift; + s->unique_id.next_batch.max = + s->unique_id.global_next_id + local_shift + batch_size; } - /* Shift the position of the next available slice. */ - const long long shift = total_shift * slice_size; + /* Shift the position of the next available batch. */ + const long long shift = total_shift * batch_size; if (s->unique_id.global_next_id > LLONG_MAX - shift) { error("Overflow for the unique IDs."); } @@ -112,33 +115,39 @@ void space_update_unique_id(struct space *s) { * @return The new unique ID */ long long space_get_new_unique_id(struct space *s) { + /* Do we need unique IDs? */ + if (!star_formation_need_unique_id) { + error("The scheme selected does not seem to use unique ID."); + } + /* Get the lock. */ lock_lock(&s->unique_id.lock); /* Get the current available id. */ - const long long id = s->unique_id.current.current; + const long long id = s->unique_id.current_batch.current; /* Update the counter. */ - s->unique_id.current.current++; + s->unique_id.current_batch.current++; /* Check if everything is fine */ - if (s->unique_id.current.current > s->unique_id.current.max) { + if (s->unique_id.current_batch.current > s->unique_id.current_batch.max) { error("Failed to get a new ID"); } - /* Check if need to move to the next slice. */ - if (s->unique_id.current.current == s->unique_id.current.max) { + /* Check if need to move to the next batch. */ + else if (s->unique_id.current_batch.current == + s->unique_id.current_batch.max) { - /* Check if the next slice is already used */ - if (s->unique_id.next.current == 0) { + /* Check if the next batch is already used */ + if (s->unique_id.next_batch.current == 0) { error("Failed to obtain a new unique ID."); } - s->unique_id.current = s->unique_id.next; + s->unique_id.current_batch = s->unique_id.next_batch; - /* Reset the next slice. */ - s->unique_id.next.current = 0; - s->unique_id.next.max = 0; + /* Reset the next batch. */ + s->unique_id.next_batch.current = 0; + s->unique_id.next_batch.max = 0; } /* Release the lock. */ @@ -156,6 +165,11 @@ long long space_get_new_unique_id(struct space *s) { * @param nr_nodes The number of MPI ranks. */ void space_init_unique_id(struct space *s, int nr_nodes) { + /* Do we need unique IDs? */ + if (!star_formation_need_unique_id) { + return; + } + /* Set the counter to 0. */ s->unique_id.global_next_id = 0; @@ -195,36 +209,37 @@ void space_init_unique_id(struct space *s, int nr_nodes) { } s->unique_id.global_next_id++; - /* Compute the size of each slice. */ - const long long slice_size = (space_extra_parts + space_extra_sparts + + /* Compute the size of each batch. */ + const long long batch_size = (space_extra_parts + space_extra_sparts + space_extra_gparts + space_extra_bparts) * s->nr_cells; - /* Compute the initial slices (each rank has 2 slices). */ - if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * slice_size) { + /* Compute the initial batchs (each rank has 2 batchs). */ + if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * batch_size) { error("Overflow for the unique id."); } - long long init = s->unique_id.global_next_id + 2 * engine_rank * slice_size; + const long long init = + s->unique_id.global_next_id + 2 * engine_rank * batch_size; - /* Set the slices and check for overflows. */ - s->unique_id.current.current = init; + /* Set the batchs and check for overflows. */ + s->unique_id.current_batch.current = init; - if (init > LLONG_MAX - slice_size) { + if (init > LLONG_MAX - batch_size) { error("Overflow for the unique id."); } - s->unique_id.current.max = init + slice_size; - s->unique_id.next.current = s->unique_id.current.max; + s->unique_id.current_batch.max = init + batch_size; + s->unique_id.next_batch.current = s->unique_id.current_batch.max; - if (s->unique_id.next.current > LLONG_MAX - slice_size) { + if (s->unique_id.next_batch.current > LLONG_MAX - batch_size) { error("Overflow for the unique id."); } - s->unique_id.next.max = s->unique_id.next.current + slice_size; + s->unique_id.next_batch.max = s->unique_id.next_batch.current + batch_size; /* Update the next available id */ - if (s->unique_id.global_next_id > LLONG_MAX - 2 * slice_size * nr_nodes) { + if (s->unique_id.global_next_id > LLONG_MAX - 2 * batch_size * nr_nodes) { error("Overflow for the unique id."); } - s->unique_id.global_next_id += 2 * slice_size * nr_nodes; + s->unique_id.global_next_id += 2 * batch_size * nr_nodes; /* Initialize the lock. */ if (lock_init(&s->unique_id.lock) != 0) diff --git a/src/space_unique_id.h b/src/space_unique_id.h index 95dd273a1..49ec49d2b 100644 --- a/src/space_unique_id.h +++ b/src/space_unique_id.h @@ -23,20 +23,38 @@ /* Config parameters. */ #include "../config.h" +/* Local includes */ +#include "lock.h" + /* Predefine the space structure */ struct space; /** - * @brief Slice of unique IDs for particle creation. + * @brief Batch of unique IDs for particle creation. */ -struct slice { +struct batch { /*! Current free unique id */ long long current; - /*! Maximal unique id in this slice (not included) */ + /*! Maximal unique id in this batch (not included) */ long long max; }; +/*! Structure dealing with the computation of a unique ID */ +struct unique_id { + /*! Current batch of unique ids */ + struct batch current_batch; + + /*! Next batch of unique ids */ + struct batch next_batch; + + /* Global next slot available */ + long long global_next_id; + + /* Lock for the unique ids */ + swift_lock_type lock; +}; + void space_update_unique_id(struct space *s); long long space_get_new_unique_id(struct space *s); void space_init_unique_id(struct space *s, int nr_nodes); diff --git a/src/star_formation/EAGLE/star_formation_struct.h b/src/star_formation/EAGLE/star_formation_struct.h index f5f0f76e8..556d7bea6 100644 --- a/src/star_formation/EAGLE/star_formation_struct.h +++ b/src/star_formation/EAGLE/star_formation_struct.h @@ -19,6 +19,10 @@ #ifndef SWIFT_EAGLE_STAR_FORMATION_STRUCT_H #define SWIFT_EAGLE_STAR_FORMATION_STRUCT_H +/* Do we need unique IDs (only useful when spawning + new particles, conversion gas->stars does not need unique IDs) */ +#define star_formation_need_unique_id 0 + /** * @brief Star-formation-related properties stored in the extended particle * data. diff --git a/src/star_formation/GEAR/star_formation_struct.h b/src/star_formation/GEAR/star_formation_struct.h index c03a8ae0a..372a9ea82 100644 --- a/src/star_formation/GEAR/star_formation_struct.h +++ b/src/star_formation/GEAR/star_formation_struct.h @@ -19,6 +19,10 @@ #ifndef SWIFT_GEAR_STAR_FORMATION_STRUCT_H #define SWIFT_GEAR_STAR_FORMATION_STRUCT_H +/* Do we need unique IDs (only useful when spawning + new particles, conversion gas->stars does not need unique IDs) */ +#define star_formation_need_unique_id 1 + /** * @brief Star-formation-related properties stored in the extended particle * data. diff --git a/src/star_formation/QLA/star_formation.h b/src/star_formation/QLA/star_formation.h index aa9421220..b446b9314 100644 --- a/src/star_formation/QLA/star_formation.h +++ b/src/star_formation/QLA/star_formation.h @@ -29,6 +29,10 @@ #include "stars.h" #include "units.h" +/* Do we need unique IDs (only useful when spawning + new particles, conversion gas->stars does not need unique IDs) */ +#define star_formation_need_unique_id 0 + /** * @file src/star_formation/EAGLE/star_formation.h * @brief Star formation model used in the EAGLE model diff --git a/src/star_formation/QLA/star_formation_struct.h b/src/star_formation/QLA/star_formation_struct.h index 872577e0f..cb93f014f 100644 --- a/src/star_formation/QLA/star_formation_struct.h +++ b/src/star_formation/QLA/star_formation_struct.h @@ -19,6 +19,10 @@ #ifndef SWIFT_QLA_STAR_FORMATION_STRUCT_H #define SWIFT_QLA_STAR_FORMATION_STRUCT_H +/* Can the star formation spawn new star + (in opposition to simply convert gas particles)? */ +#define star_formation_can_spawn_stars 0 + /** * @brief Star-formation-related properties stored in the extended particle * data. diff --git a/src/star_formation/none/star_formation_struct.h b/src/star_formation/none/star_formation_struct.h index 27a2adaf8..c1596c1d4 100644 --- a/src/star_formation/none/star_formation_struct.h +++ b/src/star_formation/none/star_formation_struct.h @@ -19,6 +19,10 @@ #ifndef SWIFT_NONE_STAR_FORMATION_STRUCT_H #define SWIFT_NONE_STAR_FORMATION_STRUCT_H +/* Do we need unique IDs (only useful when spawning + new particles, conversion gas->stars does not need unique IDs) */ +#define star_formation_need_unique_id 0 + /** * @brief Star-formation-related properties stored in the extended particle * data. -- GitLab From ac64cbfc3637b5698dd03b43e3238a5ccfaf156b Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 9 Apr 2020 10:29:25 +0200 Subject: [PATCH 10/13] Unique ID: add doc --- doc/RTD/source/SpecialBehavior/index.rst | 23 +++++++++++++++++++++++ doc/RTD/source/index.rst | 1 + 2 files changed, 24 insertions(+) create mode 100644 doc/RTD/source/SpecialBehavior/index.rst diff --git a/doc/RTD/source/SpecialBehavior/index.rst b/doc/RTD/source/SpecialBehavior/index.rst new file mode 100644 index 000000000..1f6f61049 --- /dev/null +++ b/doc/RTD/source/SpecialBehavior/index.rst @@ -0,0 +1,23 @@ +.. Special Behavior + Loic Hausammann, 2020 + +.. _special_behavior: + +Special Behavior +================ + +Generating new unique IDs +------------------------- + +When generating new particles (not transforming them), the code needs to provide new unique IDs. +This is implemented in the file ``space_unique_id.c`` and can be turn on/off in the star formation file ``star_formation_struct.h`` +with the variable ``star_formation_need_unique_id``. + +The generation of new IDs is done by computing the maximal ID in the initial condition and then attributing two batchs of ID to each rank. +The size of each batch is computed in the same way than the extra particles in order to ensure that we will have enough ID. +Every time that a new ID is requested, the next available ID in the first batch is used. +If the last available ID in the first batch is requested, the first one is replaced by the second one and the second one is flagged as being used. +If the second batch is also fully used, the code will exit with an error message. Due to the size of the slices, the code should run out of extra particles +before reaching this point. + +At each rebuild, the ranks will request a new batch if required and communicate about it. diff --git a/doc/RTD/source/index.rst b/doc/RTD/source/index.rst index d0493e69d..82c5c2dde 100644 --- a/doc/RTD/source/index.rst +++ b/doc/RTD/source/index.rst @@ -32,3 +32,4 @@ difference is the parameter file that will need to be adapted for SWIFT. VELOCIraptorInterface/index AnalysisTools/index Logger/index + SpecialBehavior/index -- GitLab From 27ed02e4c173e709b0e16a1f5b018e819f0b7d2b Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 9 Apr 2020 10:37:30 +0200 Subject: [PATCH 11/13] Unique ID: add comment about overflow --- doc/RTD/source/SpecialBehavior/index.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/RTD/source/SpecialBehavior/index.rst b/doc/RTD/source/SpecialBehavior/index.rst index 1f6f61049..d78f1216a 100644 --- a/doc/RTD/source/SpecialBehavior/index.rst +++ b/doc/RTD/source/SpecialBehavior/index.rst @@ -13,11 +13,13 @@ When generating new particles (not transforming them), the code needs to provide This is implemented in the file ``space_unique_id.c`` and can be turn on/off in the star formation file ``star_formation_struct.h`` with the variable ``star_formation_need_unique_id``. -The generation of new IDs is done by computing the maximal ID in the initial condition and then attributing two batchs of ID to each rank. +The generation of new IDs is done by computing the maximal ID in the initial condition (IC) and then attributing two batchs of ID to each rank. The size of each batch is computed in the same way than the extra particles in order to ensure that we will have enough ID. Every time that a new ID is requested, the next available ID in the first batch is used. If the last available ID in the first batch is requested, the first one is replaced by the second one and the second one is flagged as being used. If the second batch is also fully used, the code will exit with an error message. Due to the size of the slices, the code should run out of extra particles -before reaching this point. +before reaching this point. At each rebuild, the ranks will request a new batch if required and communicate about it. -At each rebuild, the ranks will request a new batch if required and communicate about it. +As we are using the maximal ID from the IC, nothing can be done against the user providing the maximal integer possible as an ID +(that is the case in the EAGLE IC as the ID are set according to a Peano-Hilbert curve). +Therefore the code is checking against overflow and will exit if it happens. -- GitLab From 666ec47d4b0c033976fd7e0c3093008529e7a3d0 Mon Sep 17 00:00:00 2001 From: loikki Date: Thu, 9 Apr 2020 13:03:30 +0200 Subject: [PATCH 12/13] Unique ID: fix QLA --- src/star_formation/QLA/star_formation.h | 4 ---- src/star_formation/QLA/star_formation_struct.h | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/star_formation/QLA/star_formation.h b/src/star_formation/QLA/star_formation.h index b446b9314..aa9421220 100644 --- a/src/star_formation/QLA/star_formation.h +++ b/src/star_formation/QLA/star_formation.h @@ -29,10 +29,6 @@ #include "stars.h" #include "units.h" -/* Do we need unique IDs (only useful when spawning - new particles, conversion gas->stars does not need unique IDs) */ -#define star_formation_need_unique_id 0 - /** * @file src/star_formation/EAGLE/star_formation.h * @brief Star formation model used in the EAGLE model diff --git a/src/star_formation/QLA/star_formation_struct.h b/src/star_formation/QLA/star_formation_struct.h index cb93f014f..034885726 100644 --- a/src/star_formation/QLA/star_formation_struct.h +++ b/src/star_formation/QLA/star_formation_struct.h @@ -19,9 +19,9 @@ #ifndef SWIFT_QLA_STAR_FORMATION_STRUCT_H #define SWIFT_QLA_STAR_FORMATION_STRUCT_H -/* Can the star formation spawn new star - (in opposition to simply convert gas particles)? */ -#define star_formation_can_spawn_stars 0 +/* Do we need unique IDs (only useful when spawning + new particles, conversion gas->stars does not need unique IDs) */ +#define star_formation_need_unique_id 1 /** * @brief Star-formation-related properties stored in the extended particle -- GitLab From 075c0478317149977e83f8481fa4cd965abaa8a2 Mon Sep 17 00:00:00 2001 From: Matthieu Schaller Date: Fri, 10 Apr 2020 14:32:58 +0200 Subject: [PATCH 13/13] Stylistic changes to the new documentation --- .../source/ImplementationDetails/index.rst | 41 +++++++++++++++++++ doc/RTD/source/SpecialBehavior/index.rst | 25 ----------- doc/RTD/source/index.rst | 2 +- 3 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 doc/RTD/source/ImplementationDetails/index.rst delete mode 100644 doc/RTD/source/SpecialBehavior/index.rst diff --git a/doc/RTD/source/ImplementationDetails/index.rst b/doc/RTD/source/ImplementationDetails/index.rst new file mode 100644 index 000000000..dda984293 --- /dev/null +++ b/doc/RTD/source/ImplementationDetails/index.rst @@ -0,0 +1,41 @@ +.. Implementation details + Loic Hausammann, 2020 + Matthieu Schaller, 2020 + +.. _implementation_details: + +Implementation details +====================== + +Generating new unique IDs +------------------------- + +When spawning new particles (not converting them) for star formation or other +similar processes, the code needs to create new unique particle IDs. This is +implemented in the file ``space_unique_id.c`` and can be switched on/off in the +star formation file ``star_formation_struct.h`` by setting the variable +``star_formation_need_unique_id`` to 1 or 0. + +The generation of new IDs is done by computing the maximal ID present in the +initial condition (across all particle types) and then attributing two batches +of new, unused IDs to each MPI rank. The size of each batch is computed in the +same way as the count of extra particles in order to ensure that we will have +enough available IDs between two tree rebuilds (where the extra particles are +regenerated). + +When a new ID is requested, the next available ID in the first batch is +returned. If the last available ID in the first batch is requested, we switch to +the next batch of IDs and flag it for regeneration at the next rebuild time. If +the second batch is also fully used, the code will exit with an error message +[#f1]_. At each tree-rebuild steps, the ranks will request a new batch if +required and make sure the batches are unique across all MPI ranks. + +As we are using the maximal ID from the ICs, nothing can be done against the user +providing the maximal integer possible as an ID (that can for instance be the +case in some of the EAGLE ICs as the ID encode their Lagrangian position on a +Peano-Hilbert curve). + + +.. [#f1] Thanks to the size of the fresh ID batches, the code should run out of + extra particles before reaching this point and triggered a new rebuild + if this is allowed by the star formation scheme. diff --git a/doc/RTD/source/SpecialBehavior/index.rst b/doc/RTD/source/SpecialBehavior/index.rst deleted file mode 100644 index d78f1216a..000000000 --- a/doc/RTD/source/SpecialBehavior/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. Special Behavior - Loic Hausammann, 2020 - -.. _special_behavior: - -Special Behavior -================ - -Generating new unique IDs -------------------------- - -When generating new particles (not transforming them), the code needs to provide new unique IDs. -This is implemented in the file ``space_unique_id.c`` and can be turn on/off in the star formation file ``star_formation_struct.h`` -with the variable ``star_formation_need_unique_id``. - -The generation of new IDs is done by computing the maximal ID in the initial condition (IC) and then attributing two batchs of ID to each rank. -The size of each batch is computed in the same way than the extra particles in order to ensure that we will have enough ID. -Every time that a new ID is requested, the next available ID in the first batch is used. -If the last available ID in the first batch is requested, the first one is replaced by the second one and the second one is flagged as being used. -If the second batch is also fully used, the code will exit with an error message. Due to the size of the slices, the code should run out of extra particles -before reaching this point. At each rebuild, the ranks will request a new batch if required and communicate about it. - -As we are using the maximal ID from the IC, nothing can be done against the user providing the maximal integer possible as an ID -(that is the case in the EAGLE IC as the ID are set according to a Peano-Hilbert curve). -Therefore the code is checking against overflow and will exit if it happens. diff --git a/doc/RTD/source/index.rst b/doc/RTD/source/index.rst index 82c5c2dde..2f5a56745 100644 --- a/doc/RTD/source/index.rst +++ b/doc/RTD/source/index.rst @@ -32,4 +32,4 @@ difference is the parameter file that will need to be adapted for SWIFT. VELOCIraptorInterface/index AnalysisTools/index Logger/index - SpecialBehavior/index + ImplementationDetails/index -- GitLab