diff --git a/include/openmc/bank.h b/include/openmc/bank.h index 303c1e8be..7c74125c3 100644 --- a/include/openmc/bank.h +++ b/include/openmc/bank.h @@ -4,6 +4,7 @@ #include #include +#include "openmc/shared_array.h" #include "openmc/particle.h" #include "openmc/position.h" @@ -17,9 +18,8 @@ namespace simulation { extern std::vector source_bank; -extern std::unique_ptr fission_bank; -extern int64_t fission_bank_length; -extern int64_t fission_bank_max; +extern SharedArray fission_bank; + extern std::vector progeny_per_particle; } // namespace simulation diff --git a/include/openmc/shared_array.h b/include/openmc/shared_array.h index e45568ceb..926597f9a 100644 --- a/include/openmc/shared_array.h +++ b/include/openmc/shared_array.h @@ -4,6 +4,9 @@ //! \file shared_array.h //! \brief Shared array data structure +#include + + namespace openmc { //============================================================================== diff --git a/src/bank.cpp b/src/bank.cpp index e91a1c1b9..9ee1f8c8d 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -17,15 +17,11 @@ namespace simulation { std::vector source_bank; -// The fission bank is allocated as a pointer, rather than a vector, as it will +// The fission bank is allocated as a SharedArray, rather than a vector, as it will // be shared by all threads in the simulation. It will be allocated to a fixed // maximum capacity in the init_fission_bank() function. Then, Elements will be -// added to it by performing atomic incrementing captures on the fission_bank_length -// variable. A vector is not appropriate, as use of push_back() and size() -// functions would cause undefined or unintended behavior. -std::unique_ptr fission_bank; -int64_t fission_bank_length {0}; -int64_t fission_bank_max; +// added to it by using SharedArray's special thread_safe_append() function. +SharedArray fission_bank; // Each entry in this vector corresponds to the number of progeny produced // this generation for the particle located at that index. This vector is @@ -41,16 +37,13 @@ std::vector progeny_per_particle; void free_memory_bank() { simulation::source_bank.clear(); - simulation::fission_bank.reset(); - simulation::fission_bank_length = 0; + simulation::fission_bank.clear(); simulation::progeny_per_particle.clear(); } void init_fission_bank(int64_t max) { - simulation::fission_bank_max = max; - simulation::fission_bank = std::make_unique(max); - simulation::fission_bank_length = 0; + simulation::fission_bank.reserve(max); simulation::progeny_per_particle.resize(simulation::work_per_rank); } @@ -87,15 +80,15 @@ void sort_fission_bank() std::vector sorted_bank_holder; // If there is not enough space, allocate a temporary vector and point to it - if (simulation::fission_bank_length > simulation::fission_bank_max / 2) { - sorted_bank_holder.resize(simulation::fission_bank_length); + if (simulation::fission_bank.size() > simulation::fission_bank.capacity() / 2) { + sorted_bank_holder.resize(simulation::fission_bank.size()); sorted_bank = sorted_bank_holder.data(); } else { // otherwise, point sorted_bank to unused portion of the fission bank - sorted_bank = &simulation::fission_bank[simulation::fission_bank_length]; + sorted_bank = &simulation::fission_bank[simulation::fission_bank.size()]; } // Use parent and progeny indices to sort fission bank - for (int64_t i = 0; i < simulation::fission_bank_length; i++) { + for (int64_t i = 0; i < simulation::fission_bank.size(); i++) { const auto& site = simulation::fission_bank[i]; int64_t offset = site.parent_id - 1 - simulation::work_index[mpi::rank]; int64_t idx = simulation::progeny_per_particle[offset] + site.progeny_id; @@ -103,8 +96,8 @@ void sort_fission_bank() } // Copy sorted bank into the fission bank - std::copy(sorted_bank, sorted_bank + simulation::fission_bank_length, - simulation::fission_bank.get()); + std::copy(sorted_bank, sorted_bank + simulation::fission_bank.size(), + simulation::fission_bank.data()); } //============================================================================== @@ -125,12 +118,12 @@ extern "C" int openmc_source_bank(void** ptr, int64_t* n) extern "C" int openmc_fission_bank(void** ptr, int64_t* n) { - if (simulation::fission_bank_length == 0) { + if (simulation::fission_bank.size() == 0) { set_errmsg("Fission bank has not been allocated."); return OPENMC_E_ALLOCATE; } else { - *ptr = simulation::fission_bank.get(); - *n = simulation::fission_bank_length; + *ptr = simulation::fission_bank.data(); + *n = simulation::fission_bank.size(); return 0; } } diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index 35d42ba1d..f02a96e7a 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -83,7 +83,7 @@ void synchronize_bank() #ifdef OPENMC_MPI int64_t start = 0; - int64_t n_bank = simulation::fission_bank_length; + int64_t n_bank = simulation::fission_bank.size(); MPI_Exscan(&n_bank, &start, 1, MPI_INT64_T, MPI_SUM, mpi::intracomm); // While we would expect the value of start on rank 0 to be 0, the MPI @@ -91,13 +91,13 @@ void synchronize_bank() // significant if (mpi::rank == 0) start = 0; - int64_t finish = start + simulation::fission_bank_length; + int64_t finish = start + simulation::fission_bank.size(); int64_t total = finish; MPI_Bcast(&total, 1, MPI_INT64_T, mpi::n_procs - 1, mpi::intracomm); #else int64_t start = 0; - int64_t finish = simulation::fission_bank_length; + int64_t finish = simulation::fission_bank.size(); int64_t total = finish; #endif @@ -106,7 +106,7 @@ void synchronize_bank() // extra logic to treat this circumstance, we really want to ensure the user // runs enough particles to avoid this in the first place. - if (simulation::fission_bank_length == 0) { + if (simulation::fission_bank.size() == 0) { fatal_error("No fission sites banked on MPI rank " + std::to_string(mpi::rank)); } @@ -138,7 +138,7 @@ void synchronize_bank() int64_t index_temp = 0; std::vector temp_sites(3*simulation::work_per_rank); - for (int64_t i = 0; i < simulation::fission_bank_length; i++ ) { + for (int64_t i = 0; i < simulation::fission_bank.size(); i++ ) { const auto& site = simulation::fission_bank[i]; // If there are less than n_particles particles banked, automatically add @@ -195,7 +195,7 @@ void synchronize_bank() // fission bank sites_needed = settings::n_particles - finish; for (int i = 0; i < sites_needed; ++i) { - int i_bank = simulation::fission_bank_length - sites_needed + i; + int i_bank = simulation::fission_bank.size() - sites_needed + i; temp_sites[index_temp] = simulation::fission_bank[i_bank]; ++index_temp; } @@ -506,7 +506,7 @@ void shannon_entropy() // Get source weight in each mesh bin bool sites_outside; xt::xtensor p = simulation::entropy_mesh->count_sites( - simulation::fission_bank.get(), simulation::fission_bank_length, + simulation::fission_bank.data(), simulation::fission_bank.size(), &sites_outside); // display warning message if there were sites outside entropy box diff --git a/src/physics.cpp b/src/physics.cpp index ca7dd8701..e40125ebd 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -16,7 +16,6 @@ #include "openmc/secondary_uncorrelated.h" #include "openmc/search.h" #include "openmc/settings.h" -#include "openmc/shared_array.h" #include "openmc/simulation.h" #include "openmc/string_utils.h" #include "openmc/thermal.h" @@ -182,14 +181,10 @@ create_fission_sites(Particle* p, int i_nuclide, const Reaction* rx) for (int i = 0; i < nu; ++i) { Particle::Bank* site; if (use_fission_bank) { - int64_t idx; - #pragma omp atomic capture - idx = simulation::fission_bank_length++; - if (idx >= simulation::fission_bank_max) { + int64_t idx = simulation::fission_bank.thread_safe_append(); + if (idx == -1) { warning("The shared fission bank is full. Additional fission sites created " "in this generation will not be banked."); - #pragma omp atomic write - simulation::fission_bank_length = simulation::fission_bank_max; skipped++; break; } diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index ed9d9f180..7cd65724d 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -127,14 +127,10 @@ create_fission_sites(Particle* p) for (int i = 0; i < nu; ++i) { Particle::Bank* site; if (use_fission_bank) { - int64_t idx; - #pragma omp atomic capture - idx = simulation::fission_bank_length++; - if (idx >= simulation::fission_bank_max) { + int64_t idx = simulation::fission_bank.thread_safe_append(); + if (idx == -1) { warning("The shared fission bank is full. Additional fission sites created " "in this generation will not be banked."); - #pragma omp atomic write - simulation::fission_bank_length = simulation::fission_bank_max; skipped++; break; } diff --git a/src/simulation.cpp b/src/simulation.cpp index b23f1d2e2..6d21b1efc 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -375,7 +375,7 @@ void initialize_generation() { if (settings::run_mode == RunMode::EIGENVALUE) { // Clear out the fission bank - simulation::fission_bank_length = 0; + simulation::fission_bank.resize(0); // Count source sites if using uniform fission source weighting if (settings::ufs_on) ufs_count_sites();