diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 029bc2c4d..f9f7a9488 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -62,6 +62,9 @@ extern "C" void initialize_batch(); //! Initialize a fission generation extern "C" void initialize_generation(); +//! Finalize a fission generation +extern "C" void finalize_generation(); + //! Determine overall generation number extern "C" int overall_generation(); diff --git a/include/openmc/source.h b/include/openmc/source.h index 2e8c9491a..efc6f12a6 100644 --- a/include/openmc/source.h +++ b/include/openmc/source.h @@ -58,6 +58,9 @@ extern "C" void initialize_source(); //! \return Sampled source site extern "C" Bank sample_external_source(); +//! Fill source bank at end of generation for fixed source simulations +void fill_source_bank_fixedsource(); + } // namespace openmc #endif // OPENMC_SOURCE_H diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index c323d3bac..05b5d141f 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -14,9 +14,12 @@ namespace openmc { extern "C" double total_weight; // Threadprivate variables - extern "C" double global_tally_absorption; -#pragma omp threadprivate(global_tally_absorption) +extern "C" double global_tally_collision; +extern "C" double global_tally_tracklength; +extern "C" double global_tally_leakage; +#pragma omp threadprivate(global_tally_absorption, global_tally_collision, \ + global_tally_tracklength, global_tally_leakage) //============================================================================== // Non-member functions diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index fbf4c65ae..552339829 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -32,7 +32,7 @@ contains ! to preserve the order of the bank when using varying numbers of threads. !=============================================================================== - subroutine join_bank_from_threads() + subroutine join_bank_from_threads() bind(C) integer(8) :: total ! total number of fission bank sites integer :: i ! loop index for threads diff --git a/src/output.F90 b/src/output.F90 index a54b099ec..58965456b 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -323,7 +323,7 @@ contains ! PRINT_GENERATION displays information for a generation of neutrons. !=============================================================================== - subroutine print_generation() + subroutine print_generation() bind(C) integer :: i ! overall generation integer :: n ! number of active generations diff --git a/src/simulation.F90 b/src/simulation.F90 index 46b2eda5b..d8a6e2d98 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -57,6 +57,9 @@ module simulation subroutine initialize_generation() bind(C) end subroutine + subroutine finalize_generation() bind(C) + end subroutine finalize_generation + function sample_external_source() result(site) bind(C) import Bank type(Bank) :: site @@ -182,77 +185,6 @@ contains end subroutine initialize_history -!=============================================================================== -! FINALIZE_GENERATION -!=============================================================================== - - subroutine finalize_generation() - - interface - subroutine fill_source_bank_fixedsource() bind(C) - end subroutine - - subroutine shannon_entropy() bind(C) - end subroutine - - subroutine synchronize_bank() bind(C) - end subroutine - end interface - - ! Update global tallies with the omp private accumulation variables -!$omp parallel -!$omp critical - if (run_mode == MODE_EIGENVALUE) then - global_tallies(RESULT_VALUE, K_COLLISION) = & - global_tallies(RESULT_VALUE, K_COLLISION) + global_tally_collision - global_tallies(RESULT_VALUE, K_ABSORPTION) = & - global_tallies(RESULT_VALUE, K_ABSORPTION) + global_tally_absorption - global_tallies(RESULT_VALUE, K_TRACKLENGTH) = & - global_tallies(RESULT_VALUE, K_TRACKLENGTH) + global_tally_tracklength - end if - global_tallies(RESULT_VALUE, LEAKAGE) = & - global_tallies(RESULT_VALUE, LEAKAGE) + global_tally_leakage -!$omp end critical - - ! reset private tallies - if (run_mode == MODE_EIGENVALUE) then - global_tally_collision = ZERO - global_tally_absorption = ZERO - global_tally_tracklength = ZERO - end if - global_tally_leakage = ZERO -!$omp end parallel - - if (run_mode == MODE_EIGENVALUE) then -#ifdef _OPENMP - ! Join the fission bank from each thread into one global fission bank - call join_bank_from_threads() -#endif - - ! Distribute fission bank across processors evenly - call synchronize_bank() - - ! Calculate shannon entropy - if (entropy_on) call shannon_entropy() - - ! Collect results and statistics - call calculate_generation_keff() - call calculate_average_keff() - - ! Write generation output - if (master .and. verbosity >= 7) then - if (current_gen /= gen_per_batch) then - call print_generation() - end if - end if - - elseif (run_mode == MODE_FIXEDSOURCE) then - ! For fixed-source mode, we need to sample the external source - call fill_source_bank_fixedsource() - end if - - end subroutine finalize_generation - !=============================================================================== ! FINALIZE_BATCH handles synchronization and accumulation of tallies, ! calculation of Shannon entropy, getting single-batch estimate of keff, and diff --git a/src/simulation.cpp b/src/simulation.cpp index 5fd9532b4..39cb31361 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -1,4 +1,4 @@ - #include "openmc/simulation.h" +#include "openmc/simulation.h" #include "openmc/capi.h" #include "openmc/eigenvalue.h" @@ -6,6 +6,7 @@ #include "openmc/message_passing.h" #include "openmc/output.h" #include "openmc/settings.h" +#include "openmc/source.h" #include "openmc/timer.h" #include "openmc/tallies/tally.h" @@ -14,6 +15,8 @@ // data/functions from Fortran side extern "C" void cmfd_init_batch(); +extern "C" void join_bank_from_threads(); +extern "C" void print_generation(); extern "C" void print_results(); extern "C" void print_runtime(); extern "C" void setup_active_tallies(); @@ -182,6 +185,62 @@ void initialize_generation() } } +void finalize_generation() +{ + auto gt = global_tallies(); + + // Update global tallies with the omp private accumulation variables +#pragma omp parallel + { +#pragma omp critical(increment_global_tallies) + { + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + gt(K_COLLISION, RESULT_VALUE) += global_tally_collision; + gt(K_ABSORPTION, RESULT_VALUE) += global_tally_absorption; + gt(K_TRACKLENGTH, RESULT_VALUE) += global_tally_tracklength; + } + gt(LEAKAGE, RESULT_VALUE) += global_tally_leakage; + } + + // reset threadprivate tallies + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + global_tally_collision = 0.0; + global_tally_absorption = 0.0; + global_tally_tracklength = 0.0; + } + global_tally_leakage = 0.0; + } + + + if (settings::run_mode == RUN_MODE_EIGENVALUE) { +#ifdef _OPENMP + // Join the fission bank from each thread into one global fission bank + join_bank_from_threads(); +#endif + + // Distribute fission bank across processors evenly + synchronize_bank(); + + // Calculate shannon entropy + if (settings::entropy_on) shannon_entropy(); + + // Collect results and statistics + calculate_generation_keff(); + calculate_average_keff(); + + // Write generation output + if (mpi::master && settings::verbosity >= 7) { + if (simulation::current_gen != settings::gen_per_batch) { + print_generation(); + } + } + + } else if (settings::run_mode == RUN_MODE_FIXEDSOURCE) { + // For fixed-source mode, we need to sample the external source + fill_source_bank_fixedsource(); + } +} + int overall_generation() { using namespace simulation; diff --git a/src/source.cpp b/src/source.cpp index 3427579ee..bfed41b6a 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -352,11 +352,7 @@ extern "C" double total_source_strength() return strength; } -// Needed in fill_source_bank_fixedsource -extern "C" int overall_generation(); - -//! Fill source bank at end of generation for fixed source simulations -extern "C" void fill_source_bank_fixedsource() +void fill_source_bank_fixedsource() { if (settings::path_source.empty()) { // Get pointer to source bank diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 481f05edc..7f64832ec 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -13,6 +13,15 @@ namespace openmc { +//============================================================================== +// Global variable definitions +//============================================================================== + +double global_tally_absorption; +double global_tally_collision; +double global_tally_tracklength; +double global_tally_leakage; + //============================================================================== // Non-member functions //============================================================================== diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 06eb6d2a2..8a5f9b550 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -136,10 +136,10 @@ module tally_header ! global tally, it can cause a higher cache miss rate due to ! invalidation. Thus, we use threadprivate variables to accumulate global ! tallies and then reduce at the end of a generation. - real(C_DOUBLE), public :: global_tally_collision = ZERO - real(C_DOUBLE), public, bind(C) :: global_tally_absorption = ZERO - real(C_DOUBLE), public :: global_tally_tracklength = ZERO - real(C_DOUBLE), public :: global_tally_leakage = ZERO + real(C_DOUBLE), public, bind(C) :: global_tally_collision + real(C_DOUBLE), public, bind(C) :: global_tally_absorption + real(C_DOUBLE), public, bind(C) :: global_tally_tracklength + real(C_DOUBLE), public, bind(C) :: global_tally_leakage !$omp threadprivate(global_tally_collision, global_tally_absorption, & !$omp& global_tally_tracklength, global_tally_leakage)